+ A brokerless, Rust-powered task queue with first-class Python and
+ Node.js SDKs over one core and store. No Redis, no RabbitMQ — just a
+ file and a worker.
+
+
+ );
+}
diff --git a/docs/app/components/landing/index.ts b/docs/app/components/landing/index.ts
new file mode 100644
index 00000000..d7bd79f3
--- /dev/null
+++ b/docs/app/components/landing/index.ts
@@ -0,0 +1,10 @@
+export { Hero } from "./hero";
+export { useReveal } from "./reveal";
+export {
+ Comparison,
+ CTA,
+ Features,
+ HowItWorks,
+ Integrations,
+ UseCases,
+} from "./sections";
diff --git a/docs/app/components/landing/reveal.ts b/docs/app/components/landing/reveal.ts
new file mode 100644
index 00000000..4d95b0fb
--- /dev/null
+++ b/docs/app/components/landing/reveal.ts
@@ -0,0 +1,30 @@
+import { useEffect } from "react";
+
+/** Scroll-reveal: add `.in` to `.reveal` elements as they enter the viewport. */
+export function useReveal(): void {
+ useEffect(() => {
+ const els = document.querySelectorAll(".reveal:not(.in)");
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
+ for (const el of els) {
+ el.classList.add("in");
+ }
+ return;
+ }
+ const io = new IntersectionObserver(
+ (entries) => {
+ for (const e of entries) {
+ if (e.isIntersecting) {
+ e.target.classList.add("in");
+ io.unobserve(e.target);
+ }
+ }
+ },
+ { threshold: 0.12, rootMargin: "0px 0px -8% 0px" },
+ );
+ els.forEach((el, i) => {
+ el.style.transitionDelay = `${Math.min(i % 6, 5) * 0.04}s`;
+ io.observe(el);
+ });
+ return () => io.disconnect();
+ }, []);
+}
diff --git a/docs/app/components/landing/sections.tsx b/docs/app/components/landing/sections.tsx
new file mode 100644
index 00000000..213bc835
--- /dev/null
+++ b/docs/app/components/landing/sections.tsx
@@ -0,0 +1,289 @@
+import { useState } from "react";
+import { Link } from "react-router";
+import { RawHtml } from "@/components/ui";
+import { highlightPython } from "@/lib/highlight-lite";
+import {
+ CODE_CELERY,
+ CODE_TASKITO,
+ DELTA,
+ FEATURES,
+ type IconCard,
+ INTEGRATIONS,
+ USE_CASES,
+} from "@/lib/landing-content";
+
+function Icon({ d, rect }: { d: string; rect?: boolean }) {
+ return (
+
+ );
+}
+
+const STATIONS = [
+ { label: "YOUR CODE", title: "enqueue", hint: ".delay()" },
+ { label: "QUEUE", title: "store", hint: "SQLite · PG" },
+ { label: "SCHEDULER", title: "dispatch", hint: "Rust · Tokio", accent: true },
+ {
+ label: "WORKERS",
+ title: "execute",
+ hint: "6 · pool",
+ accent: true,
+ pool: true,
+ },
+];
+
+export function HowItWorks() {
+ return (
+
+
+
+ How it works
+
Enqueue here, execute there.
+
+ The Rust scheduler polls the store, dispatches to a worker pool, and
+ writes results back — the same loop whether you enqueue from Python
+ or Node.
+
- A brokerless, Rust-powered task queue with first-class Python and
- Node.js SDKs over one core and store. No Redis, no RabbitMQ — just a
- file and a worker.
+ A Rust-powered task queue with first-class Python and{" "}
+ Node.js SDKs over one core and one store — no broker. Start on{" "}
+ SQLite, scale to Postgres.
- The Rust scheduler polls the store, dispatches to a worker pool, and
- writes results back — the same loop whether you enqueue from Python
- or Node.
-
-
-
- {STATIONS.map((s, i) => (
-
- ))}
-
-
-
- result written back to the store
+
+
+
+ {STATIONS.map((s, i) => (
+
+ ))}
+
+
+
+ result written back to the store
+
@@ -90,7 +106,7 @@ function Station({
{station.pool ? (
+ The quickstart walks you through defining a task, enqueuing it, and
+ watching the worker run it — in Python or Node, no Redis, no broker,
+ no config.
+
-
- Get started →
+
+ Start the quickstart →
-
- Node.js SDK
+
+ See the full comparison
+ );
+}
diff --git a/docs/app/components/diagrams/worker-fork.tsx b/docs/app/components/diagrams/worker-fork.tsx
index 6b832af4..1820d8f0 100644
--- a/docs/app/components/diagrams/worker-fork.tsx
+++ b/docs/app/components/diagrams/worker-fork.tsx
@@ -1,26 +1,25 @@
-// Worker pool — ports the prototype's `.archstack` + `.archfork` (sync OS-thread
-// pool vs async pool, converging at the result channel). `architecture/worker-pool.mdx`.
+// Worker pool — exact port of the prototype's `.archstack` + `.fork-route` +
+// `.archfork` (scheduler routes by task type; sync OS-thread pool vs async pool).
+// `architecture/worker-pool.mdx`.
export function WorkerDispatch() {
return (
-
- Scheduler
+
+ Rust
-
Dispatch
+
Scheduler
- The Rust scheduler claims a job and routes it by task kind — sync
- tasks to the thread pool, async def tasks to the native
- async pool.
+ Dequeues a job, applies rate limits, then routes it{" "}
+ by task type — sync functions to the thread pool,{" "}
+ async def functions to the async runtime.
+ routes by task type
-
- ↓route by task kind
- ↓
-
+
sync def · async def
-
bounded mpsc · workers × N
+
bounded mpsc · workers × 2
Sync pool
@@ -40,29 +39,14 @@ export function WorkerDispatch() {
NativeAsyncPool
- async def tasks run on a dedicated event loop with
- bounded concurrency — no thread per task, no GIL contention for
- I/O-bound work.
+ async def tasks are dispatched to an{" "}
+ AsyncTaskExecutor on a Python daemon thread;{" "}
+ PyResultSender bridges results back.
-
- ↓result channel
- ↓
-
-
- Store
-
-
Result handler → SQLite
-
- Both pools hand results to a single result channel; the handler
- commits them (and decides retry / dead-letter) before the outcome
- surfaces.
-
-
-
);
}
diff --git a/docs/content/docs/architecture/mesh.mdx b/docs/content/docs/architecture/mesh.mdx
index 542e06e8..9a131517 100644
--- a/docs/content/docs/architecture/mesh.mdx
+++ b/docs/content/docs/architecture/mesh.mdx
@@ -12,22 +12,25 @@ network that reduces DB contention and enables sub-millisecond load awareness.
For usage and configuration, see the
[Mesh Scheduling guide](/guides/operations/mesh).
-
+
+
+## Live demonstration
+
+Five workers run in different regions, linked into one mesh over HTTP. Jobs
+hash-route into the cluster — but enqueues are deliberately skewed toward
+`us-east-1`/`us-west-2`, so their queues build up. Watch idle regions steal
+batches from the busiest peer across the network (cyan, with real inter-region
+latency), SWIM gossip flicker along the mesh links, and the counters track
+throughput. Hover a region to see its links and latencies; hit **Add burst** to
+flood the queue.
- mesh --> durability
- `}
-/>
+
## Crate structure
@@ -48,13 +51,12 @@ cluster size.
Every 500ms (configurable via `protocol_period_ms` in `MeshConfig`), a node:
-1. Picks a random alive peer and sends a **Ping** (with sequence number)
-2. If no **Ack** within `protocol_period / 2` → sends **PingReq** to
- `indirect_ping_count` (3) random intermediaries asking them to probe the
- target on its behalf
-3. If still no response → marks the target as **Suspect**
-4. After `suspicion_multiplier × ln(N+1) × protocol_period` → declares
- **Dead** and removes from the hash ring
+
+
Picks a random alive peer and sends a Ping (with sequence number).
+
If no Ack within protocol_period / 2 → sends PingReq to indirect_ping_count (3) random intermediaries to probe the target on its behalf.
+
If still no response → marks the target as Suspect.
+
After suspicion_multiplier × ln(N+1) × protocol_period → declares Dead and removes from the hash ring.
+
### Message types
@@ -145,15 +147,12 @@ The ring recalculates on every membership change (join, leave, death). The
Each worker maintains a `Mutex>` as a local job buffer with
a configurable capacity (`local_buffer_capacity`, default 64):
- j1
- j5 -.-> pop["pop() LIFO"]
- `}
+
- **Prefetch**: the
@@ -187,17 +186,14 @@ payload, metadata, and scheduling info.
### Sequence diagram
->V: TCP connect (500ms timeout)
- T->>V: StealRequest{id, max_count}
- V->>V: rate-limit check
- V->>V: deque.steal(max)
- V->>T: StealResponse{jobs}
- T->>V: close
- `}
+
Timeouts: 500ms connect, 2s response read. On any failure, returns empty
@@ -257,22 +253,14 @@ Instead, `run_worker` (in `crates/taskito-python/src/py_queue/worker.rs`)
spawns a **mesh bridge** — an intermediate `tokio::sync::mpsc` channel
between the scheduler and dispatcher:
-|job_tx| MB[mesh_bridge]
- MB -->|dispatch_tx| D[Dispatcher]
- MB --- DQ[Local deque]
- MB --- SC[Steal client TCP to peers]
- `}
-/>
-
The `run_mesh_bridge()` function:
-1. `recv` from `job_rx` (scheduler channel) — push into local deque
-2. `pop` from local deque — send to `dispatch_tx` (dispatcher channel)
-3. On idle (no jobs from scheduler, deque low) → `try_steal()` from
- busiest peer
-4. Loop until shutdown
+
+
recv from job_rx (scheduler channel) — push into the local deque.
+
pop from the local deque — send to dispatch_tx (dispatcher channel).
+
On idle (no jobs from scheduler, deque low) → try_steal() from the busiest peer.
+
Loop until shutdown.
+
This keeps the scheduler and dispatcher completely unaware of mesh logic.
Without the `mesh` feature flag, the scheduler sends directly to the
diff --git a/docs/content/docs/architecture/scheduler.mdx b/docs/content/docs/architecture/scheduler.mdx
index 6cde5c85..19167906 100644
--- a/docs/content/docs/architecture/scheduler.mdx
+++ b/docs/content/docs/architecture/scheduler.mdx
@@ -32,17 +32,20 @@ loop {
## Polling cycle
+The loop wakes every 50 ms. `try_dispatch()` runs on every tick; the three
+maintenance tasks fire on coprime intervals so they rarely collide on the same wake.
+
## Dispatch flow
-1. `dequeue_from()` — atomically `SELECT` + `UPDATE` (pending → running) within a transaction.
-2. Check rate limit — if over limit, reschedule 1s in the future.
-3. Send job to worker pool via `tokio::sync::mpsc` channel.
-4. Worker executes task, sends result back.
-5. `handle_result()` — mark complete, schedule retry, or move to DLQ.
-
-
+
+
dequeue_from() — atomically SELECT + UPDATE (pending → running) within a transaction.
+
Check rate limit — if over limit, reschedule 1s in the future.
+
Send job to worker pool via tokio::sync::mpsc channel.
+
Worker executes task, sends result back.
+
handle_result() — mark complete, schedule retry, or move to DLQ.
+
With [mesh scheduling](/architecture/mesh) enabled, a mesh bridge sits
diff --git a/docs/content/docs/architecture/storage.mdx b/docs/content/docs/architecture/storage.mdx
index a577487a..e242c734 100644
--- a/docs/content/docs/architecture/storage.mdx
+++ b/docs/content/docs/architecture/storage.mdx
@@ -14,133 +14,15 @@ description: "SQLite pragmas, schema, indexes, connection pooling, and Postgres
## Database schema
-Six tables in the SQLite backend. Use the arrows or click a dot to flip between tables; the last slide shows their relationships.
+Six tables back the SQLite store — jobs and their error history, the dead letter
+queue, rate limits, periodic tasks, and worker heartbeats.
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ **Relationships:** `jobs` → `job_errors` (1 ─ \*, error history) and `jobs` →
+ `dead_letter` (1 ─ 0..1, DLQ on retry exhaustion).
+
## Key indexes
From aee414cfd4b793fb92e2428ff46c2ad2ff9d1e60 Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:16 +0530
Subject: [PATCH 21/48] fix(docs): rebuild on-this-page TOC when lazy content
mounts
---
docs/app/components/docs/toc.tsx | 90 ++++++++++++++++++--------------
1 file changed, 52 insertions(+), 38 deletions(-)
diff --git a/docs/app/components/docs/toc.tsx b/docs/app/components/docs/toc.tsx
index a6e91ffb..5c9f0f77 100644
--- a/docs/app/components/docs/toc.tsx
+++ b/docs/app/components/docs/toc.tsx
@@ -7,56 +7,70 @@ interface Heading {
level: number;
}
+function readHeadings(article: Element): Heading[] {
+ return [...article.querySelectorAll("h2[id], h3[id]")].map(
+ (el) => ({
+ id: el.id,
+ text: el.textContent ?? "",
+ level: el.tagName === "H3" ? 3 : 2,
+ }),
+ );
+}
+
/** On-this-page TOC, built from the rendered article headings with scroll-spy. */
export function Toc() {
const { pathname } = useLocation();
const [headings, setHeadings] = useState([]);
const [active, setActive] = useState("");
- // Rebuild from the DOM after each page renders (headings carry ids from rehype-slug).
- useEffect(() => {
- const nodes = document.querySelectorAll(
- ".article h2[id], .article h3[id]",
- );
- setHeadings(
- [...nodes].map((el) => ({
- id: el.id,
- text: el.textContent ?? "",
- level: el.tagName === "H3" ? 3 : 2,
- })),
- );
- }, []);
-
+ // The article is a lazily-loaded MDX chunk, so its headings are NOT in the DOM
+ // when this effect first runs after a client-side navigation. Re-scan on every
+ // article mutation (via MutationObserver) so the TOC fills in once the page
+ // content actually mounts, and re-arm scroll-spy whenever the heading set changes.
// biome-ignore lint/correctness/useExhaustiveDependencies: re-scan when the path changes
useEffect(() => {
- const nodes = document.querySelectorAll(
- ".article h2[id], .article h3[id]",
- );
- if (!nodes.length) {
+ const article = document.querySelector(".article");
+ if (!article) {
setHeadings([]);
return;
}
- setHeadings(
- [...nodes].map((el) => ({
- id: el.id,
- text: el.textContent ?? "",
- level: el.tagName === "H3" ? 3 : 2,
- })),
- );
- const observer = new IntersectionObserver(
- (entries) => {
- for (const entry of entries) {
- if (entry.isIntersecting) {
- setActive(entry.target.id);
+ let spy: IntersectionObserver | null = null;
+ let lastKey = "";
+
+ const scan = () => {
+ const next = readHeadings(article);
+ const key = next.map((h) => h.id).join("|");
+ if (key === lastKey) {
+ return;
+ }
+ lastKey = key;
+ setHeadings(next);
+ spy?.disconnect();
+ if (!next.length) {
+ return;
+ }
+ spy = new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries) {
+ if (entry.isIntersecting) {
+ setActive(entry.target.id);
+ }
}
- }
- },
- { rootMargin: "-80px 0px -70% 0px" },
- );
- for (const node of nodes) {
- observer.observe(node);
- }
- return () => observer.disconnect();
+ },
+ { rootMargin: "-80px 0px -70% 0px" },
+ );
+ for (const el of article.querySelectorAll("h2[id], h3[id]")) {
+ spy.observe(el);
+ }
+ };
+
+ scan();
+ const content = new MutationObserver(scan);
+ content.observe(article, { childList: true, subtree: true });
+ return () => {
+ content.disconnect();
+ spy?.disconnect();
+ };
}, [pathname]);
if (headings.length === 0) {
From c16435f70fd0b1ca97bd8f7c029b09110c7707a9 Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:16 +0530
Subject: [PATCH 22/48] feat(docs): grouped command palette with browse-on-open
---
docs/app/components/docs/search-modal.tsx | 177 ++++++++++++++++++----
docs/app/lib/search.ts | 42 ++++-
2 files changed, 185 insertions(+), 34 deletions(-)
diff --git a/docs/app/components/docs/search-modal.tsx b/docs/app/components/docs/search-modal.tsx
index 910cc594..54086b4a 100644
--- a/docs/app/components/docs/search-modal.tsx
+++ b/docs/app/components/docs/search-modal.tsx
@@ -1,8 +1,69 @@
-import { useEffect, useMemo, useState } from "react";
+import { Fragment, useEffect, useMemo, useRef, useState } from "react";
import { useNavigate } from "react-router";
-import { searchDocs } from "@/lib/search";
+import { type SearchHit, searchDocs } from "@/lib/search";
-/** ⌘K command palette: client-side search over the build-time MDX index. */
+// Section glyphs mirror the prototype's command-palette icons.
+const SECTION_ICON: { match: string; path: string }[] = [
+ { match: "getting", path: "M13 2L3 14h7l-1 8 10-12h-7l1-8z" },
+ {
+ match: "guide",
+ path: "M4 19.5A2.5 2.5 0 0 1 6.5 17H20M4 19.5A2.5 2.5 0 0 0 6.5 22H20V2H6.5A2.5 2.5 0 0 0 4 4.5v15z",
+ },
+ {
+ match: "architecture",
+ path: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5",
+ },
+ { match: "api", path: "M16 18l6-6-6-6M8 6l-6 6 6 6" },
+ { match: "node", path: "M12 2l8.5 5v10L12 22 3.5 17V7z" },
+ { match: "reference", path: "M16 18l6-6-6-6M8 6l-6 6 6 6" },
+];
+
+function sectionIconPath(section: string): string {
+ const key = section.toLowerCase();
+ return (
+ SECTION_ICON.find((s) => key.includes(s.match))?.path ??
+ "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20z"
+ );
+}
+
+function SectionIcon({ section }: { section: string }) {
+ return (
+
+ );
+}
+
+interface Group {
+ section: string;
+ items: SearchHit[];
+}
+
+/** Group ranked hits by section, preserving first-appearance order. */
+function groupBySection(hits: SearchHit[]): Group[] {
+ const groups: Group[] = [];
+ const byName = new Map();
+ for (const hit of hits) {
+ let group = byName.get(hit.section);
+ if (!group) {
+ group = { section: hit.section, items: [] };
+ byName.set(hit.section, group);
+ groups.push(group);
+ }
+ group.items.push(hit);
+ }
+ return groups;
+}
+
+/** ⌘K command palette: browse-by-section on open, ranked search as you type. */
export function SearchModal({
open,
onClose,
@@ -13,7 +74,10 @@ export function SearchModal({
const navigate = useNavigate();
const [query, setQuery] = useState("");
const [active, setActive] = useState(0);
- const results = useMemo(() => searchDocs(query), [query]);
+ const listRef = useRef(null);
+
+ const groups = useMemo(() => groupBySection(searchDocs(query)), [query]);
+ const flat = useMemo(() => groups.flatMap((g) => g.items), [groups]);
// biome-ignore lint/correctness/useExhaustiveDependencies: reset selection as results change
useEffect(() => {
@@ -26,6 +90,13 @@ export function SearchModal({
}
}, [open]);
+ // Keep the active row in view during keyboard navigation.
+ useEffect(() => {
+ listRef.current
+ ?.querySelector(`[data-idx="${active}"]`)
+ ?.scrollIntoView({ block: "nearest" });
+ }, [active]);
+
if (!open) {
return null;
}
@@ -40,15 +111,16 @@ export function SearchModal({
onClose();
} else if (e.key === "ArrowDown") {
e.preventDefault();
- setActive((i) => Math.min(i + 1, results.length - 1));
+ setActive((i) => Math.min(i + 1, flat.length - 1));
} else if (e.key === "ArrowUp") {
e.preventDefault();
setActive((i) => Math.max(i - 1, 0));
- } else if (e.key === "Enter" && results[active]) {
- go(results[active].id);
+ } else if (e.key === "Enter" && flat[active]) {
+ go(flat[active].id);
}
};
+ let idx = -1;
return (
{/* biome-ignore lint/a11y/noStaticElementInteractions: key handling for the palette */}
` in the prototype's `.md-table` shell so
+ * tables across the docs get the rounded surface, header band, and row rules
+ * from `docs.css`. Mapped onto the `table` element in `mdxComponents`, so it
+ * applies everywhere without touching individual pages.
+ */
+export function MdxTable(props: ComponentProps<"table">) {
+ return (
+
+
+
+ );
+}
From 3aeed5d5014c4b41363fb1a5c4dcc5a48cb40281 Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:16 +0530
Subject: [PATCH 25/48] feat(docs): make landing hero Python-focused
---
docs/app/components/landing/hero.tsx | 20 +++++++---------
docs/app/lib/landing-content.ts | 34 +---------------------------
2 files changed, 9 insertions(+), 45 deletions(-)
diff --git a/docs/app/components/landing/hero.tsx b/docs/app/components/landing/hero.tsx
index 687acdfc..043b6460 100644
--- a/docs/app/components/landing/hero.tsx
+++ b/docs/app/components/landing/hero.tsx
@@ -1,10 +1,10 @@
import { useState } from "react";
import { Link } from "react-router";
import { RawHtml } from "@/components/ui";
-import { highlightPython, highlightTs } from "@/lib/highlight-lite";
+import { highlightPython } from "@/lib/highlight-lite";
import { HERO_PANES, SOON_PANES, type SoonLang } from "@/lib/landing-content";
-type Lang = "py" | "ts" | "go" | "java";
+type Lang = "py" | "go" | "java";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
@@ -37,23 +37,19 @@ function SoonBox({ pane }: { pane: SoonLang }) {
export function Hero() {
const [lang, setLang] = useState("py");
const pane = HERO_PANES.find((p) => p.id === lang);
- const codeHtml = pane
- ? lang === "py"
- ? highlightPython(pane.code)
- : highlightTs(pane.code)
- : "";
+ const codeHtml = pane ? highlightPython(pane.code) : "";
const active = pane ?? HERO_PANES[0];
return (
- One queue.Python and Node.
+ One queue.Built for Python.
- A Rust-powered task queue with first-class Python and{" "}
- Node.js SDKs over one core and one store — no broker. Start on{" "}
- SQLite, scale to Postgres.
+ A Rust-powered task queue with a first-class Python SDK over
+ one core and one store — no broker. Start on SQLite,
+ scale to Postgres.
-
+
Start the quickstart →
-
+
See the full comparison
diff --git a/docs/app/components/ui/site-nav.tsx b/docs/app/components/ui/site-nav.tsx
index f66df0c2..0f8c4969 100644
--- a/docs/app/components/ui/site-nav.tsx
+++ b/docs/app/components/ui/site-nav.tsx
@@ -18,11 +18,11 @@ function GithubMark() {
}
const LINKS = [
- { label: "Getting Started", href: "/getting-started/installation" },
- { label: "Guides", href: "/guides" },
- { label: "Architecture", href: "/architecture" },
- { label: "API", href: "/api-reference" },
- { label: "Changelog", href: "/more/changelog" },
+ { label: "Getting Started", href: "/python/getting-started/installation" },
+ { label: "Guides", href: "/python/guides" },
+ { label: "Architecture", href: "/python/architecture" },
+ { label: "API", href: "/python/api-reference" },
+ { label: "Changelog", href: "/python/more/changelog" },
];
/** Sticky top navigation, shared by the landing and docs shells. */
diff --git a/docs/app/lib/landing-content.ts b/docs/app/lib/landing-content.ts
index 8ddfd96f..cde6b80d 100644
--- a/docs/app/lib/landing-content.ts
+++ b/docs/app/lib/landing-content.ts
@@ -51,7 +51,7 @@ print(job.result()) # → 5`,
timing: "12 ms",
},
],
- docHref: "/getting-started/quickstart",
+ docHref: "/python/getting-started/quickstart",
docLabel: "Read the Python quickstart",
},
];
diff --git a/docs/app/lib/nav.ts b/docs/app/lib/nav.ts
index bc2e9ad2..69f50d79 100644
--- a/docs/app/lib/nav.ts
+++ b/docs/app/lib/nav.ts
@@ -83,16 +83,17 @@ function buildTree(sections: string[]): NavNode[] {
}
export const PYTHON_SECTIONS = [
- "getting-started",
- "guides",
- "architecture",
- "api-reference",
- "more",
+ "python/getting-started",
+ "python/guides",
+ "python/architecture",
+ "python/api-reference",
+ "python/more",
];
export const NODE_SECTIONS = [
"node/getting-started",
"node/guides",
- "architecture",
+ // The engine is identical across SDKs — Node reuses the shared architecture pages.
+ "python/architecture",
"node/api-reference",
];
diff --git a/docs/content/docs/api-reference/overview.mdx b/docs/content/docs/api-reference/overview.mdx
deleted file mode 100644
index d2039028..00000000
--- a/docs/content/docs/api-reference/overview.mdx
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: Overview
-description: "Complete Python API reference for all public classes and methods."
----
-
-Complete Python API reference for all public classes and methods.
-
-| Class | Description |
-|-------|-------------|
-| [Queue](/api-reference/queue) | Central orchestrator — task registration, enqueue, workers, and all queue operations |
-| [TaskWrapper](/api-reference/task) | Handle returned by `@queue.task()` — `delay()`, `apply_async()`, `map()`, signatures |
-| [JobResult](/api-reference/result) | Handle for an enqueued job — status polling, result retrieval, dependencies |
-| [JobContext](/api-reference/context) | Runtime context inside a running task — job ID, retry count, progress updates |
-| [Canvas](/api-reference/canvas) | Workflow primitives — `Signature`, `chain`, `group`, `chord` |
-| [Workflows](/api-reference/workflows) | DAG workflow builder, `WorkflowRun`, gates, sub-workflows |
-| [Testing](/api-reference/testing) | Test mode, `TestResult`, `MockResource` for unit testing tasks |
-| [CLI](/api-reference/cli) | `taskito` command-line interface — `worker`, `info`, `scaler` |
diff --git a/docs/content/docs/architecture/overview.mdx b/docs/content/docs/architecture/overview.mdx
deleted file mode 100644
index b82c4ac4..00000000
--- a/docs/content/docs/architecture/overview.mdx
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Overview
-description: "Hybrid Python/Rust architecture: Python API on top, Rust engine underneath."
----
-
-taskito is a hybrid Python/Rust system. Python provides the user-facing API. Rust
-handles all the heavy lifting: storage, scheduling, dispatch, rate limiting, and
-worker management.
-
-
-
-## Section overview
-
-| Page | What it covers |
-|---|---|
-| [Job Lifecycle](/architecture/job-lifecycle) | State machine, status codes, transitions |
-| [Worker Pool](/architecture/worker-pool) | Thread architecture, async dispatch, GIL management |
-| [Storage Layer](/architecture/storage) | SQLite pragmas, schema, indexes, Postgres differences |
-| [Scheduler](/architecture/scheduler) | Poll loop, dispatch flow, periodic tasks |
-| [Resource System](/architecture/resources) | Argument interception, DI, proxy reconstruction |
-| [Failure Model](/architecture/failure-model) | Crash recovery, duplicate execution, partial writes |
-| [Serialization](/architecture/serialization) | Pluggable serializers, format details |
diff --git a/docs/content/docs/guides/advanced-execution/index.mdx b/docs/content/docs/guides/advanced-execution/index.mdx
deleted file mode 100644
index eefb7a8c..00000000
--- a/docs/content/docs/guides/advanced-execution/index.mdx
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Advanced execution
-description: "Patterns for scaling and optimizing task execution."
----
-
-Patterns for scaling and optimizing task execution.
-
-| Guide | Description |
-|---|---|
-| [Prefork Pool](/guides/advanced-execution/prefork) | Process-based isolation for CPU-bound or memory-leaking tasks |
-| [Native Async Tasks](/guides/advanced-execution/async-tasks) | `async def` tasks with native event loop integration |
-| [Result Streaming](/guides/advanced-execution/streaming) | Stream partial results and progress updates in real time |
-| [Dependencies](/guides/advanced-execution/dependencies) | DAG-based job dependencies — run tasks in order |
-| [Batch Enqueue](/guides/advanced-execution/batch-enqueue) | Enqueue many jobs efficiently with `task.map()` and `enqueue_many()` |
-| [Unique Tasks](/guides/advanced-execution/unique-tasks) | Deduplicate active jobs with unique keys |
diff --git a/docs/content/docs/guides/core/index.mdx b/docs/content/docs/guides/core/index.mdx
deleted file mode 100644
index 5a17059e..00000000
--- a/docs/content/docs/guides/core/index.mdx
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Core
-description: "The building blocks of every taskito application."
----
-
-The building blocks of every taskito application.
-
-| Guide | Description |
-|---|---|
-| [Tasks](/guides/core/tasks) | Define tasks with `@queue.task()`, configure retries, timeouts, and options |
-| [Workers](/guides/core/workers) | Start workers, control concurrency, graceful shutdown |
-| [Execution Models](/guides/core/execution-model) | How tasks move from enqueue to completion |
-| [Queues & Priority](/guides/core/queues) | Named queues, priority levels, and routing |
-| [Scheduling](/guides/core/scheduling) | Periodic tasks with cron expressions |
-| [Workflows](/guides/core/workflows) | Chains, groups, and chords for multi-step pipelines |
diff --git a/docs/content/docs/guides/extensibility/index.mdx b/docs/content/docs/guides/extensibility/index.mdx
deleted file mode 100644
index 47a97bec..00000000
--- a/docs/content/docs/guides/extensibility/index.mdx
+++ /dev/null
@@ -1,12 +0,0 @@
----
-title: Extensibility
-description: "Extend taskito at every stage of the task lifecycle."
----
-
-Extend taskito with custom behavior at every stage of the task lifecycle.
-
-| Guide | Description |
-|---|---|
-| [Middleware](/guides/extensibility/middleware) | Hook into task execution with `before`, `after`, `on_retry`, and more |
-| [Serializers](/guides/extensibility/serializers) | Custom payload serialization — msgpack, orjson, encryption |
-| [Events & Webhooks](/guides/extensibility/events-webhooks) | React to queue events and push notifications to external services |
diff --git a/docs/content/docs/guides/observability/index.mdx b/docs/content/docs/guides/observability/index.mdx
deleted file mode 100644
index 7b2b5074..00000000
--- a/docs/content/docs/guides/observability/index.mdx
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: Observability
-description: "Monitor, log, and inspect your task queue in real time."
----
-
-Monitor, log, and inspect your task queue in real time.
-
-| Guide | Description |
-|---|---|
-| [Monitoring & Hooks](/guides/observability/monitoring) | Queue stats, progress tracking, worker heartbeat, and alerting hooks |
-| [Structured Logging](/guides/observability/logging) | Per-task structured logs with automatic context |
-| [Structured Notes](/guides/observability/notes) | Operator-visible metadata attached to individual jobs |
-
-For the built-in web UI, see the [Dashboard](/guides/dashboard) section —
-it covers the browser app, password and SSO login, runtime task/queue
-overrides, and the underlying REST API.
diff --git a/docs/content/docs/guides/operations/index.mdx b/docs/content/docs/guides/operations/index.mdx
deleted file mode 100644
index e3c2b15c..00000000
--- a/docs/content/docs/guides/operations/index.mdx
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: Operations
-description: "Run taskito reliably in production — testing, deployment, scaling, migration."
----
-
-Run taskito reliably in production.
-
-| Guide | Description |
-|---|---|
-| [Testing](/guides/operations/testing) | Test mode, fixtures, mocking resources, and workflow testing |
-| [Job Management](/guides/operations/job-management) | Cancel, pause, archive, revoke, replay, and clean up jobs |
-| [Troubleshooting](/guides/operations/troubleshooting) | Diagnose stuck jobs, lock contention, and worker issues |
-| [Deployment](/guides/operations/deployment) | systemd, Docker, WAL mode, Postgres, and production checklists |
-| [Bare-Metal Autoscaler](/guides/operations/autoscaler) | Automatically scale worker processes without Kubernetes |
-| [KEDA Autoscaling](/guides/operations/keda) | Kubernetes event-driven autoscaling for workers |
-| [Postgres Backend](/guides/operations/postgres) | Set up and run taskito with PostgreSQL |
-| [Migrating from Celery](/guides/operations/migration) | Side-by-side comparison and step-by-step migration guide |
diff --git a/docs/content/docs/guides/reliability/index.mdx b/docs/content/docs/guides/reliability/index.mdx
deleted file mode 100644
index be234498..00000000
--- a/docs/content/docs/guides/reliability/index.mdx
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Reliability
-description: "Harden your task queue for production workloads."
----
-
-Harden your task queue for production workloads.
-
-| Guide | Description |
-|---|---|
-| [Retries & Dead Letters](/guides/reliability/retries) | Automatic retries with exponential backoff, dead letter queue |
-| [Error Handling](/guides/reliability/error-handling) | Task failure lifecycle, error inspection, debugging patterns |
-| [Delivery Guarantees](/guides/reliability/guarantees) | At-least-once delivery, idempotency, and exactly-once patterns |
-| [Rate Limiting](/guides/reliability/rate-limiting) | Throttle task execution with token bucket rate limits |
-| [Circuit Breakers](/guides/reliability/circuit-breakers) | Protect downstream services from cascading failures |
-| [Distributed Locking](/guides/reliability/locking) | Mutual exclusion across workers with database-backed locks |
diff --git a/docs/content/docs/meta.json b/docs/content/docs/meta.json
index 69c58e0d..f828d01d 100644
--- a/docs/content/docs/meta.json
+++ b/docs/content/docs/meta.json
@@ -1,12 +1,4 @@
{
"title": "Taskito",
- "pages": [
- "capabilities",
- "getting-started",
- "node",
- "guides",
- "architecture",
- "api-reference",
- "more"
- ]
+ "pages": ["python", "node"]
}
diff --git a/docs/content/docs/more/examples/index.mdx b/docs/content/docs/more/examples/index.mdx
deleted file mode 100644
index 0ebfe6ab..00000000
--- a/docs/content/docs/more/examples/index.mdx
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: Examples
-description: "End-to-end examples demonstrating common taskito patterns."
----
-
-End-to-end examples demonstrating common taskito patterns.
-
-| Example | Description |
-|---------|-------------|
-| [FastAPI Service](/more/examples/fastapi-service) | REST API that enqueues tasks and streams progress via SSE |
-| [Notification Service](/more/examples/notifications) | Multi-channel notifications with retries and rate limiting |
-| [Web Scraper Pipeline](/more/examples/web-scraper) | Distributed scraping with chains and error handling |
-| [Data Pipeline](/more/examples/data-pipeline) | ETL pipeline with dependencies, groups, and chords |
-| [DAG Workflows](/more/examples/workflows) | Fan-out, conditions, gates, sub-workflows, incremental runs |
-| [Predicate-Gated Jobs](/more/examples/predicate-gated-jobs) | Business-hours windows, load-shedding, feature flags, per-tenant quotas |
-| [Benchmark](/more/examples/benchmark) | Performance benchmarks comparing taskito to alternatives |
diff --git a/docs/content/docs/node/getting-started/concepts.mdx b/docs/content/docs/node/getting-started/concepts.mdx
index cff9e94b..efbd016d 100644
--- a/docs/content/docs/node/getting-started/concepts.mdx
+++ b/docs/content/docs/node/getting-started/concepts.mdx
@@ -59,6 +59,6 @@ process sharing the storage can await them.
The architecture is engine-level and shared across SDKs — see
- [Architecture](/architecture/overview) for the job lifecycle, scheduler,
+ [Architecture](/python/architecture/overview) for the job lifecycle, scheduler,
storage schema, and mesh internals.
diff --git a/docs/content/docs/node/guides/operations/deployment.mdx b/docs/content/docs/node/guides/operations/deployment.mdx
index 26d920f4..9b92d950 100644
--- a/docs/content/docs/node/guides/operations/deployment.mdx
+++ b/docs/content/docs/node/guides/operations/deployment.mdx
@@ -36,5 +36,5 @@ process.on("SIGTERM", () => worker.stop());
Always set a [timeout](/node/guides/reliability/timeouts) on production tasks —
a crashed worker's `running` jobs are reaped and retried once their timeout
- elapses. See the [failure model](/architecture/failure-model).
+ elapses. See the [failure model](/python/architecture/failure-model).
diff --git a/docs/content/docs/node/guides/operations/mesh.mdx b/docs/content/docs/node/guides/operations/mesh.mdx
index 857d6db8..7320b3fb 100644
--- a/docs/content/docs/node/guides/operations/mesh.mdx
+++ b/docs/content/docs/node/guides/operations/mesh.mdx
@@ -29,6 +29,6 @@ it; published prebuilts include it).
Mesh is an optimization, never a correctness dependency — atomic claims in
storage still guarantee exactly-once dispatch. See
- [Mesh Scheduling](/architecture/mesh) for the SWIM/ring/work-stealing
+ [Mesh Scheduling](/python/architecture/mesh) for the SWIM/ring/work-stealing
internals (shared engine).
diff --git a/docs/content/docs/node/guides/reliability/idempotency.mdx b/docs/content/docs/node/guides/reliability/idempotency.mdx
index ffd7d74a..216eed4d 100644
--- a/docs/content/docs/node/guides/reliability/idempotency.mdx
+++ b/docs/content/docs/node/guides/reliability/idempotency.mdx
@@ -36,5 +36,5 @@ queue.task("charge", async (order: Order) => {
Use the provider's idempotency key (Stripe, etc.), an upsert, or a "already
done?" check at the top of the task. See the
- [failure model](/architecture/failure-model) for the exact re-run windows.
+ [failure model](/python/architecture/failure-model) for the exact re-run windows.
diff --git a/docs/content/docs/api-reference/batching.mdx b/docs/content/docs/python/api-reference/batching.mdx
similarity index 100%
rename from docs/content/docs/api-reference/batching.mdx
rename to docs/content/docs/python/api-reference/batching.mdx
diff --git a/docs/content/docs/api-reference/canvas.mdx b/docs/content/docs/python/api-reference/canvas.mdx
similarity index 97%
rename from docs/content/docs/api-reference/canvas.mdx
rename to docs/content/docs/python/api-reference/canvas.mdx
index b5e91f9e..1297d88c 100644
--- a/docs/content/docs/api-reference/canvas.mdx
+++ b/docs/content/docs/python/api-reference/canvas.mdx
@@ -94,7 +94,7 @@ chain.apply(queue: Queue | None = None) -> JobResult
```
Execute the chain by enqueuing and waiting for each step sequentially. Returns
-the [`JobResult`](/api-reference/result) of the **last** step.
+the [`JobResult`](/python/api-reference/result) of the **last** step.
Each step's return value is prepended to the next mutable signature's args.
Immutable signatures (`task.si()`) receive their args as-is.
@@ -154,7 +154,7 @@ group.apply(queue: Queue | None = None) -> list[JobResult]
```
Enqueue all signatures and return a list of
-[`JobResult`](/api-reference/result) handles. Jobs run concurrently
+[`JobResult`](/python/api-reference/result) handles. Jobs run concurrently
across available workers.
```python
@@ -209,7 +209,7 @@ chord.apply(queue: Queue | None = None) -> JobResult
Execute the group, wait for all results, then run the callback with the list
of results prepended to its args (unless immutable). Returns the
-[`JobResult`](/api-reference/result) of the callback.
+[`JobResult`](/python/api-reference/result) of the callback.
```python
@queue.task()
diff --git a/docs/content/docs/api-reference/cli.mdx b/docs/content/docs/python/api-reference/cli.mdx
similarity index 97%
rename from docs/content/docs/api-reference/cli.mdx
rename to docs/content/docs/python/api-reference/cli.mdx
index 03f7cb7a..9b146700 100644
--- a/docs/content/docs/api-reference/cli.mdx
+++ b/docs/content/docs/python/api-reference/cli.mdx
@@ -162,7 +162,7 @@ The server exposes three routes:
taskito scaler --app myapp:queue --port 9091 --target-queue-depth 5
```
-See the [KEDA Integration guide](/guides/operations) for Kubernetes deploy
+See the [KEDA Integration guide](/python/guides/operations) for Kubernetes deploy
templates.
### `taskito autoscale`
@@ -194,7 +194,7 @@ taskito autoscale --app [options]
taskito autoscale --app myapp.tasks:queue --min-workers 2 --max-workers 20
```
-See the [Autoscaler guide](/guides/operations/autoscaler) for deployment
+See the [Autoscaler guide](/python/guides/operations/autoscaler) for deployment
patterns and tuning advice.
## Error messages
diff --git a/docs/content/docs/api-reference/context.mdx b/docs/content/docs/python/api-reference/context.mdx
similarity index 94%
rename from docs/content/docs/api-reference/context.mdx
rename to docs/content/docs/python/api-reference/context.mdx
index 0a4487dd..541d2029 100644
--- a/docs/content/docs/api-reference/context.mdx
+++ b/docs/content/docs/python/api-reference/context.mdx
@@ -86,8 +86,8 @@ current_job.update_progress(progress: int) -> None
```
Update the job's progress percentage (0–100). The value is written directly to
-the database and can be read via [`job.progress`](/api-reference/result)
-or [`queue.get_job()`](/api-reference/queue/jobs).
+the database and can be read via [`job.progress`](/python/api-reference/result)
+or [`queue.get_job()`](/python/api-reference/queue/jobs).
```python
@queue.task()
@@ -116,7 +116,7 @@ current_job.publish(data: Any) -> None
```
Publish a partial result visible to
-[`job.stream()`](/api-reference/result) consumers. Use this to stream
+[`job.stream()`](/python/api-reference/result) consumers. Use this to stream
intermediate data from long-running tasks.
`data` must be JSON-serializable. It is stored as a task log entry with
diff --git a/docs/content/docs/api-reference/index.mdx b/docs/content/docs/python/api-reference/index.mdx
similarity index 82%
rename from docs/content/docs/api-reference/index.mdx
rename to docs/content/docs/python/api-reference/index.mdx
index 7ee5a0a7..db9be548 100644
--- a/docs/content/docs/api-reference/index.mdx
+++ b/docs/content/docs/python/api-reference/index.mdx
@@ -23,55 +23,55 @@ signature, parameters, return values, and a short example.
}
title="Overview"
- href="/api-reference/overview"
+ href="/python/api-reference/overview"
description="The shape of the public API — what's stable, what's experimental."
/>
}
title="Queue"
- href="/api-reference/queue"
+ href="/python/api-reference/queue"
description="Construct queues, enqueue jobs, manage workers, inspect state."
/>
}
title="Task"
- href="/api-reference/task"
+ href="/python/api-reference/task"
description="The @queue.task decorator — options, methods, async variants."
/>
}
title="Result"
- href="/api-reference/result"
+ href="/python/api-reference/result"
description="JobResult, polling, awaiting, timeouts, sync and async APIs."
/>
}
title="Context"
- href="/api-reference/context"
+ href="/python/api-reference/context"
description="current_job — progress, logging, cancellation, timeouts inside a task."
/>
}
title="Canvas"
- href="/api-reference/canvas"
+ href="/python/api-reference/canvas"
description="chain, group, chord — the Celery-compatible composition primitives."
/>
}
title="Workflows"
- href="/api-reference/workflows"
+ href="/python/api-reference/workflows"
description="The DAG builder — fan-out, fan-in, gates, conditions, sub-workflows."
/>
}
title="Testing"
- href="/api-reference/testing"
+ href="/python/api-reference/testing"
description="test_mode, MockResource, fixtures for synchronous in-process verification."
/>
}
title="CLI"
- href="/api-reference/cli"
+ href="/python/api-reference/cli"
description="taskito worker, dashboard, info — every flag and subcommand."
/>
diff --git a/docs/content/docs/api-reference/meta.json b/docs/content/docs/python/api-reference/meta.json
similarity index 100%
rename from docs/content/docs/api-reference/meta.json
rename to docs/content/docs/python/api-reference/meta.json
diff --git a/docs/content/docs/python/api-reference/overview.mdx b/docs/content/docs/python/api-reference/overview.mdx
new file mode 100644
index 00000000..a3283418
--- /dev/null
+++ b/docs/content/docs/python/api-reference/overview.mdx
@@ -0,0 +1,17 @@
+---
+title: Overview
+description: "Complete Python API reference for all public classes and methods."
+---
+
+Complete Python API reference for all public classes and methods.
+
+| Class | Description |
+|-------|-------------|
+| [Queue](/python/api-reference/queue) | Central orchestrator — task registration, enqueue, workers, and all queue operations |
+| [TaskWrapper](/python/api-reference/task) | Handle returned by `@queue.task()` — `delay()`, `apply_async()`, `map()`, signatures |
+| [JobResult](/python/api-reference/result) | Handle for an enqueued job — status polling, result retrieval, dependencies |
+| [JobContext](/python/api-reference/context) | Runtime context inside a running task — job ID, retry count, progress updates |
+| [Canvas](/python/api-reference/canvas) | Workflow primitives — `Signature`, `chain`, `group`, `chord` |
+| [Workflows](/python/api-reference/workflows) | DAG workflow builder, `WorkflowRun`, gates, sub-workflows |
+| [Testing](/python/api-reference/testing) | Test mode, `TestResult`, `MockResource` for unit testing tasks |
+| [CLI](/python/api-reference/cli) | `taskito` command-line interface — `worker`, `info`, `scaler` |
diff --git a/docs/content/docs/api-reference/queue/events.mdx b/docs/content/docs/python/api-reference/queue/events.mdx
similarity index 100%
rename from docs/content/docs/api-reference/queue/events.mdx
rename to docs/content/docs/python/api-reference/queue/events.mdx
diff --git a/docs/content/docs/api-reference/queue/index.mdx b/docs/content/docs/python/api-reference/queue/index.mdx
similarity index 89%
rename from docs/content/docs/api-reference/queue/index.mdx
rename to docs/content/docs/python/api-reference/queue/index.mdx
index f737637c..01b0cda3 100644
--- a/docs/content/docs/api-reference/queue/index.mdx
+++ b/docs/content/docs/python/api-reference/queue/index.mdx
@@ -10,11 +10,11 @@ The central class for creating and managing a task queue.
The Queue API is split across several pages for readability:
- - **[Job Management](/api-reference/queue/jobs)** — get, list, cancel, archive, replay jobs
- - **[Queue & Stats](/api-reference/queue/queues)** — rate limits, concurrency, pause/resume, statistics, dead letters
- - **[Workers & Hooks](/api-reference/queue/workers)** — run workers, lifecycle hooks, circuit breakers, async methods
- - **[Resources & Locking](/api-reference/queue/resources)** — resource system, distributed locks
- - **[Events & Logs](/api-reference/queue/events)** — event callbacks, webhooks, structured logs
+ - **[Job Management](/python/api-reference/queue/jobs)** — get, list, cancel, archive, replay jobs
+ - **[Queue & Stats](/python/api-reference/queue/queues)** — rate limits, concurrency, pause/resume, statistics, dead letters
+ - **[Workers & Hooks](/python/api-reference/queue/workers)** — run workers, lifecycle hooks, circuit breakers, async methods
+ - **[Resources & Locking](/python/api-reference/queue/resources)** — resource system, distributed locks
+ - **[Events & Logs](/python/api-reference/queue/events)** — event callbacks, webhooks, structured logs
## Constructor
@@ -54,7 +54,7 @@ Queue(
| `result_ttl` | `int \| None` | `None` | Auto-cleanup completed/dead jobs older than this many seconds. `None` disables. |
| `middleware` | `list[TaskMiddleware] \| None` | `None` | Queue-level middleware applied to all tasks. |
| `drain_timeout` | `int` | `30` | Seconds to wait for in-flight tasks during graceful shutdown. |
-| `interception` | `str` | `"off"` | Argument interception mode: `"strict"`, `"lenient"`, or `"off"`. See [Resource System](/guides/resources). |
+| `interception` | `str` | `"off"` | Argument interception mode: `"strict"`, `"lenient"`, or `"off"`. See [Resource System](/python/guides/resources). |
| `max_intercept_depth` | `int` | `10` | Max recursion depth for argument walking. |
| `recipe_signing_key` | `str \| None` | `None` | HMAC-SHA256 key for proxy recipe integrity. Falls back to `TASKITO_RECIPE_SECRET` env var. |
| `max_reconstruction_timeout` | `int` | `10` | Max seconds allowed for proxy reconstruction. |
@@ -92,7 +92,7 @@ Queue(
) -> TaskWrapper
```
-Register a function as a background task. Returns a [`TaskWrapper`](/api-reference/task).
+Register a function as a background task. Returns a [`TaskWrapper`](/python/api-reference/task).
| Parameter | Type | Default | Description |
|---|---|---|---|
@@ -109,7 +109,7 @@ Register a function as a background task. Returns a [`TaskWrapper`](/api-referen
| `circuit_breaker` | `dict \| None` | `None` | Circuit breaker config: `{"threshold": 5, "window": 60, "cooldown": 120}`. |
| `middleware` | `list[TaskMiddleware] \| None` | `None` | Per-task middleware, applied in addition to queue-level middleware. |
| `expires` | `float \| None` | `None` | Seconds until the job expires if not started. |
-| `inject` | `list[str] \| None` | `None` | Resource names to inject as keyword arguments. See [Resource System](/guides/resources). |
+| `inject` | `list[str] \| None` | `None` | Resource names to inject as keyword arguments. See [Resource System](/python/guides/resources). |
| `serializer` | `Serializer \| None` | `None` | Per-task serializer override. Falls back to queue-level serializer. |
| `max_concurrent` | `int \| None` | `None` | Max concurrent running instances. `None` = no limit. |
@@ -158,13 +158,13 @@ queue.enqueue(
) -> JobResult
```
-Enqueue a task for execution. Returns a [`JobResult`](/api-reference/result) handle.
+Enqueue a task for execution. Returns a [`JobResult`](/python/api-reference/result) handle.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `metadata` | `str \| None` | `None` | Free-form JSON string blob. No size or shape constraint. |
-| `notes` | `dict \| None` | `None` | Structured annotations, max **15** top-level keys. See [Structured notes](/guides/observability/notes). |
-| `depends_on` | `str \| list[str] \| None` | `None` | Job ID(s) this job depends on. See [Dependencies](/guides/advanced-execution). |
+| `notes` | `dict \| None` | `None` | Structured annotations, max **15** top-level keys. See [Structured notes](/python/guides/observability/notes). |
+| `depends_on` | `str \| list[str] \| None` | `None` | Job ID(s) this job depends on. See [Dependencies](/python/guides/advanced-execution). |
### `queue.enqueue_many()`
@@ -201,7 +201,7 @@ uniform parameters (applied to all jobs) and per-job lists.
| `unique_keys` | `list[str \| None] \| None` | `None` | Per-job deduplication keys |
| `metadata` | `str \| None` | `None` | Uniform metadata JSON for all jobs |
| `metadata_list` | `list[str \| None] \| None` | `None` | Per-job metadata JSON |
-| `notes` | `dict \| None` | `None` | Uniform [structured notes](/guides/observability/notes) for all jobs (≤ 15 keys) |
+| `notes` | `dict \| None` | `None` | Uniform [structured notes](/python/guides/observability/notes) for all jobs (≤ 15 keys) |
| `notes_list` | `list[dict \| None] \| None` | `None` | Per-job structured notes (takes precedence over `notes`) |
| `expires` | `float \| None` | `None` | Uniform expiry in seconds for all jobs |
| `expires_list` | `list[float \| None] \| None` | `None` | Per-job expiry in seconds |
diff --git a/docs/content/docs/api-reference/queue/jobs.mdx b/docs/content/docs/python/api-reference/queue/jobs.mdx
similarity index 100%
rename from docs/content/docs/api-reference/queue/jobs.mdx
rename to docs/content/docs/python/api-reference/queue/jobs.mdx
diff --git a/docs/content/docs/api-reference/queue/meta.json b/docs/content/docs/python/api-reference/queue/meta.json
similarity index 100%
rename from docs/content/docs/api-reference/queue/meta.json
rename to docs/content/docs/python/api-reference/queue/meta.json
diff --git a/docs/content/docs/api-reference/queue/queues.mdx b/docs/content/docs/python/api-reference/queue/queues.mdx
similarity index 100%
rename from docs/content/docs/api-reference/queue/queues.mdx
rename to docs/content/docs/python/api-reference/queue/queues.mdx
diff --git a/docs/content/docs/api-reference/queue/resources.mdx b/docs/content/docs/python/api-reference/queue/resources.mdx
similarity index 99%
rename from docs/content/docs/api-reference/queue/resources.mdx
rename to docs/content/docs/python/api-reference/queue/resources.mdx
index fd183b8f..3e86104e 100644
--- a/docs/content/docs/api-reference/queue/resources.mdx
+++ b/docs/content/docs/python/api-reference/queue/resources.mdx
@@ -63,7 +63,7 @@ queue.load_resources(toml_path: str) -> None
```
Load resource definitions from a TOML file. Must be called before `run_worker()`.
-See [TOML configuration](/guides/resources).
+See [TOML configuration](/python/guides/resources).
### `queue.health_check()`
diff --git a/docs/content/docs/api-reference/queue/workers.mdx b/docs/content/docs/python/api-reference/queue/workers.mdx
similarity index 100%
rename from docs/content/docs/api-reference/queue/workers.mdx
rename to docs/content/docs/python/api-reference/queue/workers.mdx
diff --git a/docs/content/docs/api-reference/result.mdx b/docs/content/docs/python/api-reference/result.mdx
similarity index 90%
rename from docs/content/docs/api-reference/result.mdx
rename to docs/content/docs/python/api-reference/result.mdx
index d5de9a15..83611fa9 100644
--- a/docs/content/docs/api-reference/result.mdx
+++ b/docs/content/docs/python/api-reference/result.mdx
@@ -6,9 +6,9 @@ description: "Handle for an enqueued job — status polling, result retrieval, d
Handle to an enqueued job. Provides methods to check status and retrieve
results, both synchronously and asynchronously.
-Returned by [`task.delay()`](/api-reference/task),
-[`task.apply_async()`](/api-reference/task),
-[`queue.enqueue()`](/api-reference/queue), and canvas operations.
+Returned by [`task.delay()`](/python/api-reference/task),
+[`task.apply_async()`](/python/api-reference/task),
+[`queue.enqueue()`](/python/api-reference/queue), and canvas operations.
## Properties
@@ -45,7 +45,7 @@ job.progress -> int | None
```
Current progress (0–100) if reported by the task via
-[`current_job.update_progress()`](/api-reference/context). Returns `None`
+[`current_job.update_progress()`](/python/api-reference/context). Returns `None`
if no progress has been reported. Refreshes from the database.
### `job.error`
@@ -88,7 +88,7 @@ job.dependencies -> list[str]
```
List of job IDs this job depends on. Returns an empty list if the job has no
-dependencies. See [Dependencies](/guides/advanced-execution).
+dependencies. See [Dependencies](/python/guides/advanced-execution).
### `job.dependents`
@@ -108,8 +108,8 @@ job.to_dict() -> dict
```
Return all job fields as a plain dictionary. Useful for JSON serialization
-(e.g. in the [dashboard](/guides/observability) or
-[FastAPI integration](/guides/integrations)).
+(e.g. in the [dashboard](/python/guides/observability) or
+[FastAPI integration](/python/guides/integrations)).
### `job.result()`
@@ -192,7 +192,7 @@ job.stream(
```
Iterate over partial results published by the task via
-[`current_job.publish()`](/api-reference/context). Yields each result as
+[`current_job.publish()`](/python/api-reference/context). Yields each result as
it arrives, stops when the job reaches a terminal state.
| Parameter | Type | Default | Description |
diff --git a/docs/content/docs/api-reference/saga.mdx b/docs/content/docs/python/api-reference/saga.mdx
similarity index 100%
rename from docs/content/docs/api-reference/saga.mdx
rename to docs/content/docs/python/api-reference/saga.mdx
diff --git a/docs/content/docs/api-reference/task.mdx b/docs/content/docs/python/api-reference/task.mdx
similarity index 89%
rename from docs/content/docs/api-reference/task.mdx
rename to docs/content/docs/python/api-reference/task.mdx
index 271bee60..724226f9 100644
--- a/docs/content/docs/api-reference/task.mdx
+++ b/docs/content/docs/python/api-reference/task.mdx
@@ -26,7 +26,7 @@ task.delay(*args, **kwargs) -> JobResult
```
Enqueue the task for background execution using the decorator's default options.
-Returns a [`JobResult`](/api-reference/result) handle.
+Returns a [`JobResult`](/python/api-reference/result) handle.
```python
@queue.task(priority=5)
@@ -68,7 +68,7 @@ falls back to the decorator's default.
| `timeout` | `int \| None` | `None` | Override timeout in seconds |
| `unique_key` | `str \| None` | `None` | Deduplicate active jobs with same key |
| `metadata` | `str \| None` | `None` | Arbitrary JSON metadata to attach |
-| `depends_on` | `str \| list[str] \| None` | `None` | Job ID(s) this job depends on. See [Dependencies](/guides/advanced-execution). |
+| `depends_on` | `str \| list[str] \| None` | `None` | Job ID(s) this job depends on. See [Dependencies](/python/guides/advanced-execution). |
```python
job = send_email.apply_async(
@@ -102,8 +102,8 @@ print(results) # [3, 7, 11]
task.s(*args, **kwargs) -> Signature
```
-Create a **mutable** [`Signature`](/api-reference/canvas). In a
-[`chain`](/api-reference/canvas), the previous task's return value is
+Create a **mutable** [`Signature`](/python/api-reference/canvas). In a
+[`chain`](/python/api-reference/canvas), the previous task's return value is
prepended to `args`.
```python
@@ -118,7 +118,7 @@ sig = add.s(10)
task.si(*args, **kwargs) -> Signature
```
-Create an **immutable** [`Signature`](/api-reference/canvas). Ignores the
+Create an **immutable** [`Signature`](/python/api-reference/canvas). Ignores the
previous task's result — arguments are used as-is.
```python
diff --git a/docs/content/docs/api-reference/testing.mdx b/docs/content/docs/python/api-reference/testing.mdx
similarity index 100%
rename from docs/content/docs/api-reference/testing.mdx
rename to docs/content/docs/python/api-reference/testing.mdx
diff --git a/docs/content/docs/api-reference/workflows.mdx b/docs/content/docs/python/api-reference/workflows.mdx
similarity index 100%
rename from docs/content/docs/api-reference/workflows.mdx
rename to docs/content/docs/python/api-reference/workflows.mdx
diff --git a/docs/content/docs/architecture/failure-model.mdx b/docs/content/docs/python/architecture/failure-model.mdx
similarity index 94%
rename from docs/content/docs/architecture/failure-model.mdx
rename to docs/content/docs/python/architecture/failure-model.mdx
index a04f18fa..cfa6a2a9 100644
--- a/docs/content/docs/architecture/failure-model.mdx
+++ b/docs/content/docs/python/architecture/failure-model.mdx
@@ -35,7 +35,7 @@ Same behavior as database unavailable. The scheduler retries on the next poll cy
`claim_execution` prevents two workers from picking up the same job simultaneously.
But if a worker crashes *after* starting execution, the job will be retried —
potentially executing the same task twice. Design tasks to be
-[idempotent](/guides/reliability) to handle this safely.
+[idempotent](/python/guides/reliability) to handle this safely.
## Recovery timeline
@@ -46,7 +46,7 @@ potentially executing the same task twice. Design tasks to be
If a task completes successfully but the result write to the database fails (e.g.,
database full, connection lost), the job stays in `running` status. The stale reaper
eventually marks it failed and retries it. The task will execute again — make sure
-it's [idempotent](/guides/reliability).
+it's [idempotent](/python/guides/reliability).
## Jobs without timeouts
diff --git a/docs/content/docs/architecture/index.mdx b/docs/content/docs/python/architecture/index.mdx
similarity index 83%
rename from docs/content/docs/architecture/index.mdx
rename to docs/content/docs/python/architecture/index.mdx
index cf1b7869..3a93df9d 100644
--- a/docs/content/docs/architecture/index.mdx
+++ b/docs/content/docs/python/architecture/index.mdx
@@ -22,49 +22,49 @@ high-level model, then drill into the layer that interests you.
}
title="Overview"
- href="/architecture/overview"
+ href="/python/architecture/overview"
description="The big picture — Python ↔ PyO3 ↔ Rust core, end to end."
/>
}
title="Job lifecycle"
- href="/architecture/job-lifecycle"
+ href="/python/architecture/job-lifecycle"
description="Every state a job moves through, from enqueue to result or dead letter."
/>
}
title="Worker pool"
- href="/architecture/worker-pool"
+ href="/python/architecture/worker-pool"
description="OS-thread pool, prefork children, async executor — how each model dispatches work."
/>
}
title="Scheduler"
- href="/architecture/scheduler"
+ href="/python/architecture/scheduler"
description="The Tokio polling loop — how jobs are picked, claimed, and routed to workers."
/>
}
title="Storage"
- href="/architecture/storage"
+ href="/python/architecture/storage"
description="The Storage trait, Diesel for SQLite/Postgres, Redis backend, table schemas."
/>
}
title="Resources"
- href="/architecture/resources"
+ href="/python/architecture/resources"
description="The 3-layer DI pipeline — argument interception, worker injection, proxy reconstruction."
/>
}
title="Failure model"
- href="/architecture/failure-model"
+ href="/python/architecture/failure-model"
description="Retries, dead letters, circuit breakers, cancellation — what happens when things go wrong."
/>
}
title="Serialization"
- href="/architecture/serialization"
+ href="/python/architecture/serialization"
description="Cloudpickle, JSON, MsgPack — how arguments and results cross the worker boundary."
/>
diff --git a/docs/content/docs/architecture/job-lifecycle.mdx b/docs/content/docs/python/architecture/job-lifecycle.mdx
similarity index 100%
rename from docs/content/docs/architecture/job-lifecycle.mdx
rename to docs/content/docs/python/architecture/job-lifecycle.mdx
diff --git a/docs/content/docs/architecture/mesh.mdx b/docs/content/docs/python/architecture/mesh.mdx
similarity index 90%
rename from docs/content/docs/architecture/mesh.mdx
rename to docs/content/docs/python/architecture/mesh.mdx
index 9a131517..6f974715 100644
--- a/docs/content/docs/architecture/mesh.mdx
+++ b/docs/content/docs/python/architecture/mesh.mdx
@@ -5,12 +5,12 @@ description: "SWIM gossip, consistent hashing, work-stealing deques, and adaptiv
import { Callout } from "fumadocs-ui/components/callout";
-The mesh layer sits between the [scheduler](/architecture/scheduler) and the
-[storage backend](/architecture/storage), forming a decentralized overlay
+The mesh layer sits between the [scheduler](/python/architecture/scheduler) and the
+[storage backend](/python/architecture/storage), forming a decentralized overlay
network that reduces DB contention and enables sub-millisecond load awareness.
For usage and configuration, see the
-[Mesh Scheduling guide](/guides/operations/mesh).
+[Mesh Scheduling guide](/python/guides/operations/mesh).
Dispatch
Enhanced poller
Local deque · affinity routing · work-stealing.
@@ -37,7 +37,7 @@ flood the queue.
The mesh is implemented as a standalone Rust crate (`crates/taskito-mesh/`)
with no PyO3 dependency. Feature-gated via `mesh` cargo feature on
`taskito-python`. Depends on `taskito-core` for the
-[`Job`](/architecture/job-lifecycle) type only.
+[`Job`](/python/architecture/job-lifecycle) type only.
## SWIM gossip protocol
@@ -108,7 +108,7 @@ failure detection from cascading across the cluster.
Optional XOR symmetric encryption with a shared key (base64-encoded).
Applied to every UDP datagram before send, reversed on receive. All
cluster nodes must share the same key. See
-[Gossip encryption](/guides/operations/mesh#gossip-encryption) for setup.
+[Gossip encryption](/python/guides/operations/mesh#gossip-encryption) for setup.
XOR encryption provides obfuscation, not cryptographic security. It
@@ -156,7 +156,7 @@ a configurable capacity (`local_buffer_capacity`, default 64):
/>
- **Prefetch**: the
- [scheduler](/architecture/scheduler) dequeues a batch from the DB and
+ [scheduler](/python/architecture/scheduler) dequeues a batch from the DB and
pushes into the deque via `push_sorted()`
- **Affinity sorting**: `push_sorted()` partitions the batch — non-owned
tasks go to the front (stealable), owned tasks to the back (hot)
@@ -247,8 +247,8 @@ after a period of queue emptiness.
## Integration with the scheduler
-The mesh does **not** modify the [`Scheduler`](/architecture/scheduler)
-struct or the [`WorkerDispatcher`](/architecture/worker-pool) trait.
+The mesh does **not** modify the [`Scheduler`](/python/architecture/scheduler)
+struct or the [`WorkerDispatcher`](/python/architecture/worker-pool) trait.
Instead, `run_worker` (in `crates/taskito-python/src/py_queue/worker.rs`)
spawns a **mesh bridge** — an intermediate `tokio::sync::mpsc` channel
between the scheduler and dispatcher:
@@ -288,7 +288,7 @@ values cloned atomically).
| Scenario | Behavior |
|---|---|
-| Gossip socket fails to bind | Warning logged, mesh disabled, [scheduler](/architecture/scheduler) runs normally |
+| Gossip socket fails to bind | Warning logged, mesh disabled, [scheduler](/python/architecture/scheduler) runs normally |
| Steal server fails to bind | Warning logged, stealing disabled, gossip + deque still work |
| All seeds unreachable | Worker operates standalone, retries on next protocol tick |
| Peer crashes | Detected in ~1.5s via SWIM, removed from ring |
@@ -299,12 +299,12 @@ values cloned atomically).
In every failure case, the database remains the source of truth. The worst
outcome is reduced performance (more DB polls), never data loss or
double-execution — those guarantees come from the
-[storage layer's](/architecture/storage) atomic claim mechanism.
+[storage layer's](/python/architecture/storage) atomic claim mechanism.
## See also
-- [Mesh Scheduling guide](/guides/operations/mesh) — configuration, cluster topology, Docker Compose example
-- [Scheduler](/architecture/scheduler) — the poll loop that feeds jobs into the mesh bridge
-- [Worker Pool](/architecture/worker-pool) — the dispatcher that receives jobs from the mesh bridge
-- [Storage](/architecture/storage) — atomic claim mechanism that guarantees exactly-once dispatch
-- [Failure Model](/architecture/failure-model) — how taskito handles crashes and timeouts
+- [Mesh Scheduling guide](/python/guides/operations/mesh) — configuration, cluster topology, Docker Compose example
+- [Scheduler](/python/architecture/scheduler) — the poll loop that feeds jobs into the mesh bridge
+- [Worker Pool](/python/architecture/worker-pool) — the dispatcher that receives jobs from the mesh bridge
+- [Storage](/python/architecture/storage) — atomic claim mechanism that guarantees exactly-once dispatch
+- [Failure Model](/python/architecture/failure-model) — how taskito handles crashes and timeouts
diff --git a/docs/content/docs/architecture/meta.json b/docs/content/docs/python/architecture/meta.json
similarity index 100%
rename from docs/content/docs/architecture/meta.json
rename to docs/content/docs/python/architecture/meta.json
diff --git a/docs/content/docs/python/architecture/overview.mdx b/docs/content/docs/python/architecture/overview.mdx
new file mode 100644
index 00000000..8f696711
--- /dev/null
+++ b/docs/content/docs/python/architecture/overview.mdx
@@ -0,0 +1,22 @@
+---
+title: Overview
+description: "Hybrid Python/Rust architecture: Python API on top, Rust engine underneath."
+---
+
+taskito is a hybrid Python/Rust system. Python provides the user-facing API. Rust
+handles all the heavy lifting: storage, scheduling, dispatch, rate limiting, and
+worker management.
+
+
+
+## Section overview
+
+| Page | What it covers |
+|---|---|
+| [Job Lifecycle](/python/architecture/job-lifecycle) | State machine, status codes, transitions |
+| [Worker Pool](/python/architecture/worker-pool) | Thread architecture, async dispatch, GIL management |
+| [Storage Layer](/python/architecture/storage) | SQLite pragmas, schema, indexes, Postgres differences |
+| [Scheduler](/python/architecture/scheduler) | Poll loop, dispatch flow, periodic tasks |
+| [Resource System](/python/architecture/resources) | Argument interception, DI, proxy reconstruction |
+| [Failure Model](/python/architecture/failure-model) | Crash recovery, duplicate execution, partial writes |
+| [Serialization](/python/architecture/serialization) | Pluggable serializers, format details |
diff --git a/docs/content/docs/architecture/resources.mdx b/docs/content/docs/python/architecture/resources.mdx
similarity index 100%
rename from docs/content/docs/architecture/resources.mdx
rename to docs/content/docs/python/architecture/resources.mdx
diff --git a/docs/content/docs/architecture/scheduler.mdx b/docs/content/docs/python/architecture/scheduler.mdx
similarity index 95%
rename from docs/content/docs/architecture/scheduler.mdx
rename to docs/content/docs/python/architecture/scheduler.mdx
index 19167906..c1dea2a3 100644
--- a/docs/content/docs/architecture/scheduler.mdx
+++ b/docs/content/docs/python/architecture/scheduler.mdx
@@ -48,7 +48,7 @@ maintenance tasks fire on coprime intervals so they rarely collide on the same w
- With [mesh scheduling](/architecture/mesh) enabled, a mesh bridge sits
+ With [mesh scheduling](/python/architecture/mesh) enabled, a mesh bridge sits
between the scheduler and the worker pool — buffering jobs in a local deque,
applying task affinity, and stealing from peers on idle ticks. The scheduler
itself is unchanged.
diff --git a/docs/content/docs/architecture/serialization.mdx b/docs/content/docs/python/architecture/serialization.mdx
similarity index 100%
rename from docs/content/docs/architecture/serialization.mdx
rename to docs/content/docs/python/architecture/serialization.mdx
diff --git a/docs/content/docs/architecture/storage.mdx b/docs/content/docs/python/architecture/storage.mdx
similarity index 96%
rename from docs/content/docs/architecture/storage.mdx
rename to docs/content/docs/python/architecture/storage.mdx
index e242c734..d585960c 100644
--- a/docs/content/docs/architecture/storage.mdx
+++ b/docs/content/docs/python/architecture/storage.mdx
@@ -40,7 +40,7 @@ per-connection).
## Postgres differences
taskito also supports PostgreSQL as an alternative storage backend. See the
-[Postgres backend guide](/guides/operations) for full details.
+[Postgres backend guide](/python/guides/operations) for full details.
- **Connection pooling**: `r2d2` pool with a default of 10 connections (vs. 8 for SQLite)
- **Schema isolation**: all tables are created inside a configurable PostgreSQL schema
diff --git a/docs/content/docs/architecture/worker-pool.mdx b/docs/content/docs/python/architecture/worker-pool.mdx
similarity index 100%
rename from docs/content/docs/architecture/worker-pool.mdx
rename to docs/content/docs/python/architecture/worker-pool.mdx
diff --git a/docs/content/docs/capabilities.mdx b/docs/content/docs/python/capabilities.mdx
similarity index 75%
rename from docs/content/docs/capabilities.mdx
rename to docs/content/docs/python/capabilities.mdx
index 4428da78..21ba0fd0 100644
--- a/docs/content/docs/capabilities.mdx
+++ b/docs/content/docs/python/capabilities.mdx
@@ -23,11 +23,11 @@ These are the capabilities most often assumed absent. They aren't.
| You might assume… | Reality |
| --- | --- |
-| No canvas / workflows — no chain, group, or chord | [`chain` / `group` / `chord`](/guides/workflows/canvas) are exported from the top-level package, backed by a full workflow DSL. |
-| No Flower-like dashboard | [`taskito dashboard --app myapp:queue`](/guides/dashboard) serves a built-in monitoring UI. |
-| No retry backoff or per-exception retries | [`max_retries`, `retry_backoff`, `retry_on`, `dont_retry_on`](/guides/reliability/retries) are arguments on every task. |
-| No soft timeouts | [`current_job.check_timeout()`](/guides/reliability/error-handling) gives cooperative soft timeouts. |
-| GIL bottleneck with no escape hatch | [`--pool prefork`](/guides/advanced-execution/prefork) runs child processes with independent GILs for true CPU parallelism. |
+| No canvas / workflows — no chain, group, or chord | [`chain` / `group` / `chord`](/python/guides/workflows/canvas) are exported from the top-level package, backed by a full workflow DSL. |
+| No Flower-like dashboard | [`taskito dashboard --app myapp:queue`](/python/guides/dashboard) serves a built-in monitoring UI. |
+| No retry backoff or per-exception retries | [`max_retries`, `retry_backoff`, `retry_on`, `dont_retry_on`](/python/guides/reliability/retries) are arguments on every task. |
+| No soft timeouts | [`current_job.check_timeout()`](/python/guides/reliability/error-handling) gives cooperative soft timeouts. |
+| GIL bottleneck with no escape hatch | [`--pool prefork`](/python/guides/advanced-execution/prefork) runs child processes with independent GILs for true CPU parallelism. |
## By capability
@@ -35,37 +35,37 @@ These are the capabilities most often assumed absent. They aren't.
}
title="Reliability"
- href="/guides/reliability"
+ href="/python/guides/reliability"
description="Retries with exponential backoff, per-exception rules, soft timeouts, dead-letter replay, circuit breakers, and idempotent enqueue."
/>
}
title="Workflows"
- href="/guides/workflows/canvas"
+ href="/python/guides/workflows/canvas"
description="Compose with chain, fan out with group, fan in with chord — plus dependency graphs with cascade cancel."
/>
}
title="Concurrency"
- href="/guides/advanced-execution/prefork"
+ href="/python/guides/advanced-execution/prefork"
description="A thread pool for I/O-bound work and a prefork pool for true CPU parallelism, with a native async API."
/>
}
title="Scheduling"
- href="/guides/core/scheduling"
+ href="/python/guides/core/scheduling"
description="Priorities, rate limiting, periodic (cron) tasks, delayed execution, and job expiration."
/>
}
title="Observability"
- href="/guides/dashboard"
+ href="/python/guides/dashboard"
description="A built-in dashboard, events, HMAC-signed webhooks, Prometheus, OpenTelemetry, and structured logging."
/>
}
title="Extensibility"
- href="/guides/extensibility"
+ href="/python/guides/extensibility"
description="Pluggable serializers, per-task middleware, a fully async API, and Postgres or Redis backends."
/>
diff --git a/docs/content/docs/getting-started/concepts.mdx b/docs/content/docs/python/getting-started/concepts.mdx
similarity index 93%
rename from docs/content/docs/getting-started/concepts.mdx
rename to docs/content/docs/python/getting-started/concepts.mdx
index 867bb046..77444fcd 100644
--- a/docs/content/docs/getting-started/concepts.mdx
+++ b/docs/content/docs/python/getting-started/concepts.mdx
@@ -10,12 +10,12 @@ Get taskito installed and running in under 5 minutes.
diff --git a/docs/content/docs/getting-started/installation.mdx b/docs/content/docs/python/getting-started/installation.mdx
similarity index 89%
rename from docs/content/docs/getting-started/installation.mdx
rename to docs/content/docs/python/getting-started/installation.mdx
index fe3611b5..22fd0fb4 100644
--- a/docs/content/docs/getting-started/installation.mdx
+++ b/docs/content/docs/python/getting-started/installation.mdx
@@ -6,7 +6,7 @@ description: "Install taskito and prepare your environment."
import { Callout } from "fumadocs-ui/components/callout";
- See [**Capabilities at a glance**](/capabilities) for everything taskito does —
+ See [**Capabilities at a glance**](/python/capabilities) for everything taskito does —
workflows, retries, the dashboard, prefork pools — each with a link to its guide.
@@ -33,7 +33,7 @@ To use PostgreSQL as the storage backend instead of SQLite:
pip install taskito[postgres]
```
-See the [Postgres backend guide](/guides/operations) for configuration details.
+See the [Postgres backend guide](/python/guides/operations) for configuration details.
## From source
diff --git a/docs/content/docs/getting-started/meta.json b/docs/content/docs/python/getting-started/meta.json
similarity index 100%
rename from docs/content/docs/getting-started/meta.json
rename to docs/content/docs/python/getting-started/meta.json
diff --git a/docs/content/docs/getting-started/quickstart.mdx b/docs/content/docs/python/getting-started/quickstart.mdx
similarity index 83%
rename from docs/content/docs/getting-started/quickstart.mdx
rename to docs/content/docs/python/getting-started/quickstart.mdx
index 766ea480..31041fb1 100644
--- a/docs/content/docs/getting-started/quickstart.mdx
+++ b/docs/content/docs/python/getting-started/quickstart.mdx
@@ -122,12 +122,12 @@ taskito dashboard --app tasks:queue
Open `http://localhost:8080` in your browser. The dashboard includes pages
covering every aspect of your task queue — no extra dependencies needed.
-[Dashboard guide →](/guides/observability)
+[Dashboard guide →](/python/guides/observability)
## Next steps
-- [Tasks](/guides/core) — decorator options, `.delay()` vs `.apply_async()`
-- [Workers](/guides/core) — CLI flags, graceful shutdown, worker count
-- [Retries](/guides/reliability) — exponential backoff, dead letter queue
-- [Workflows](/guides/workflows) — chain, group, chord
-- [Testing](/guides/operations) — run tasks synchronously in tests with `queue.test_mode()`
+- [Tasks](/python/guides/core) — decorator options, `.delay()` vs `.apply_async()`
+- [Workers](/python/guides/core) — CLI flags, graceful shutdown, worker count
+- [Retries](/python/guides/reliability) — exponential backoff, dead letter queue
+- [Workflows](/python/guides/workflows) — chain, group, chord
+- [Testing](/python/guides/operations) — run tasks synchronously in tests with `queue.test_mode()`
diff --git a/docs/content/docs/guides/advanced-execution/async-tasks.mdx b/docs/content/docs/python/guides/advanced-execution/async-tasks.mdx
similarity index 100%
rename from docs/content/docs/guides/advanced-execution/async-tasks.mdx
rename to docs/content/docs/python/guides/advanced-execution/async-tasks.mdx
diff --git a/docs/content/docs/guides/advanced-execution/batch-enqueue.mdx b/docs/content/docs/python/guides/advanced-execution/batch-enqueue.mdx
similarity index 98%
rename from docs/content/docs/guides/advanced-execution/batch-enqueue.mdx
rename to docs/content/docs/python/guides/advanced-execution/batch-enqueue.mdx
index 392388ef..6fd84c48 100644
--- a/docs/content/docs/guides/advanced-execution/batch-enqueue.mdx
+++ b/docs/content/docs/python/guides/advanced-execution/batch-enqueue.mdx
@@ -43,7 +43,7 @@ jobs = queue.enqueue_many(
Per-job lists (`delay_list`, `metadata_list`, `expires_list`,
`result_ttl_list`) override uniform values when both are provided. See the
-[API reference](/api-reference/queue) for the full parameter list.
+[API reference](/python/api-reference/queue) for the full parameter list.
## Per-item results for batched tasks
diff --git a/docs/content/docs/guides/advanced-execution/dependencies.mdx b/docs/content/docs/python/guides/advanced-execution/dependencies.mdx
similarity index 100%
rename from docs/content/docs/guides/advanced-execution/dependencies.mdx
rename to docs/content/docs/python/guides/advanced-execution/dependencies.mdx
diff --git a/docs/content/docs/python/guides/advanced-execution/index.mdx b/docs/content/docs/python/guides/advanced-execution/index.mdx
new file mode 100644
index 00000000..addfcaba
--- /dev/null
+++ b/docs/content/docs/python/guides/advanced-execution/index.mdx
@@ -0,0 +1,15 @@
+---
+title: Advanced execution
+description: "Patterns for scaling and optimizing task execution."
+---
+
+Patterns for scaling and optimizing task execution.
+
+| Guide | Description |
+|---|---|
+| [Prefork Pool](/python/guides/advanced-execution/prefork) | Process-based isolation for CPU-bound or memory-leaking tasks |
+| [Native Async Tasks](/python/guides/advanced-execution/async-tasks) | `async def` tasks with native event loop integration |
+| [Result Streaming](/python/guides/advanced-execution/streaming) | Stream partial results and progress updates in real time |
+| [Dependencies](/python/guides/advanced-execution/dependencies) | DAG-based job dependencies — run tasks in order |
+| [Batch Enqueue](/python/guides/advanced-execution/batch-enqueue) | Enqueue many jobs efficiently with `task.map()` and `enqueue_many()` |
+| [Unique Tasks](/python/guides/advanced-execution/unique-tasks) | Deduplicate active jobs with unique keys |
diff --git a/docs/content/docs/guides/advanced-execution/meta.json b/docs/content/docs/python/guides/advanced-execution/meta.json
similarity index 100%
rename from docs/content/docs/guides/advanced-execution/meta.json
rename to docs/content/docs/python/guides/advanced-execution/meta.json
diff --git a/docs/content/docs/guides/advanced-execution/prefork.mdx b/docs/content/docs/python/guides/advanced-execution/prefork.mdx
similarity index 100%
rename from docs/content/docs/guides/advanced-execution/prefork.mdx
rename to docs/content/docs/python/guides/advanced-execution/prefork.mdx
diff --git a/docs/content/docs/guides/advanced-execution/streaming.mdx b/docs/content/docs/python/guides/advanced-execution/streaming.mdx
similarity index 100%
rename from docs/content/docs/guides/advanced-execution/streaming.mdx
rename to docs/content/docs/python/guides/advanced-execution/streaming.mdx
diff --git a/docs/content/docs/guides/advanced-execution/unique-tasks.mdx b/docs/content/docs/python/guides/advanced-execution/unique-tasks.mdx
similarity index 100%
rename from docs/content/docs/guides/advanced-execution/unique-tasks.mdx
rename to docs/content/docs/python/guides/advanced-execution/unique-tasks.mdx
diff --git a/docs/content/docs/guides/core/batching.mdx b/docs/content/docs/python/guides/core/batching.mdx
similarity index 95%
rename from docs/content/docs/guides/core/batching.mdx
rename to docs/content/docs/python/guides/core/batching.mdx
index ca8c1a50..94aae586 100644
--- a/docs/content/docs/guides/core/batching.mdx
+++ b/docs/content/docs/python/guides/core/batching.mdx
@@ -90,4 +90,4 @@ When not to use it:
- Tasks where per-item retry matters.
- Heterogeneous work that doesn't share the same downstream code path.
-See also the [`canvas.chunks()`](/guides/workflows/canvas) primitive — it's a producer-side equivalent that creates `N` separate jobs each holding a sub-list, with full per-chunk retry semantics.
+See also the [`canvas.chunks()`](/python/guides/workflows/canvas) primitive — it's a producer-side equivalent that creates `N` separate jobs each holding a sub-list, with full per-chunk retry semantics.
diff --git a/docs/content/docs/guides/core/execution-model.mdx b/docs/content/docs/python/guides/core/execution-model.mdx
similarity index 95%
rename from docs/content/docs/guides/core/execution-model.mdx
rename to docs/content/docs/python/guides/core/execution-model.mdx
index dd0cef9b..64040d3a 100644
--- a/docs/content/docs/guides/core/execution-model.mdx
+++ b/docs/content/docs/python/guides/core/execution-model.mdx
@@ -66,7 +66,7 @@ instance. It must be a module-level name (`"module:attribute"` format) —
tasks defined inside functions or closures cannot be imported by child
processes.
-For more details, see the [Prefork Pool guide](/guides/advanced-execution).
+For more details, see the [Prefork Pool guide](/python/guides/advanced-execution).
## Native async
@@ -90,7 +90,7 @@ queue = Queue(
)
```
-For more details, see the [Native Async Tasks guide](/guides/advanced-execution).
+For more details, see the [Native Async Tasks guide](/python/guides/advanced-execution).
## Mixing sync and async
diff --git a/docs/content/docs/python/guides/core/index.mdx b/docs/content/docs/python/guides/core/index.mdx
new file mode 100644
index 00000000..f3b4463d
--- /dev/null
+++ b/docs/content/docs/python/guides/core/index.mdx
@@ -0,0 +1,15 @@
+---
+title: Core
+description: "The building blocks of every taskito application."
+---
+
+The building blocks of every taskito application.
+
+| Guide | Description |
+|---|---|
+| [Tasks](/python/guides/core/tasks) | Define tasks with `@queue.task()`, configure retries, timeouts, and options |
+| [Workers](/python/guides/core/workers) | Start workers, control concurrency, graceful shutdown |
+| [Execution Models](/python/guides/core/execution-model) | How tasks move from enqueue to completion |
+| [Queues & Priority](/python/guides/core/queues) | Named queues, priority levels, and routing |
+| [Scheduling](/python/guides/core/scheduling) | Periodic tasks with cron expressions |
+| [Workflows](/python/guides/core/workflows) | Chains, groups, and chords for multi-step pipelines |
diff --git a/docs/content/docs/guides/core/meta.json b/docs/content/docs/python/guides/core/meta.json
similarity index 100%
rename from docs/content/docs/guides/core/meta.json
rename to docs/content/docs/python/guides/core/meta.json
diff --git a/docs/content/docs/guides/core/predicates.mdx b/docs/content/docs/python/guides/core/predicates.mdx
similarity index 100%
rename from docs/content/docs/guides/core/predicates.mdx
rename to docs/content/docs/python/guides/core/predicates.mdx
diff --git a/docs/content/docs/guides/core/queues.mdx b/docs/content/docs/python/guides/core/queues.mdx
similarity index 100%
rename from docs/content/docs/guides/core/queues.mdx
rename to docs/content/docs/python/guides/core/queues.mdx
diff --git a/docs/content/docs/guides/core/scheduling.mdx b/docs/content/docs/python/guides/core/scheduling.mdx
similarity index 100%
rename from docs/content/docs/guides/core/scheduling.mdx
rename to docs/content/docs/python/guides/core/scheduling.mdx
diff --git a/docs/content/docs/guides/core/tasks.mdx b/docs/content/docs/python/guides/core/tasks.mdx
similarity index 98%
rename from docs/content/docs/guides/core/tasks.mdx
rename to docs/content/docs/python/guides/core/tasks.mdx
index 31c311d1..534861c4 100644
--- a/docs/content/docs/guides/core/tasks.mdx
+++ b/docs/content/docs/python/guides/core/tasks.mdx
@@ -35,7 +35,7 @@ def process_data(data: dict) -> str:
| `circuit_breaker` | `dict \| None` | `None` | Circuit breaker config: `{"threshold": 5, "window": 60, "cooldown": 120}`. |
| `middleware` | `list[TaskMiddleware] \| None` | `None` | Per-task middleware, applied in addition to queue-level middleware. |
| `expires` | `float \| None` | `None` | Seconds until the job expires if not started. |
-| `inject` | `list[str] \| None` | `None` | Worker resource names to inject as keyword arguments. See [Resource System](/guides/resources). |
+| `inject` | `list[str] \| None` | `None` | Worker resource names to inject as keyword arguments. See [Resource System](/python/guides/resources). |
| `serializer` | `Serializer \| None` | `None` | Per-task serializer override. Falls back to the queue-level serializer. |
| `max_concurrent` | `int \| None` | `None` | Max concurrent running instances of this task. `None` means no limit. |
diff --git a/docs/content/docs/guides/core/workers.mdx b/docs/content/docs/python/guides/core/workers.mdx
similarity index 98%
rename from docs/content/docs/guides/core/workers.mdx
rename to docs/content/docs/python/guides/core/workers.mdx
index c6dcecc9..7d640980 100644
--- a/docs/content/docs/guides/core/workers.mdx
+++ b/docs/content/docs/python/guides/core/workers.mdx
@@ -274,7 +274,7 @@ queue = Queue(
)
```
-See [Native Async Tasks](/guides/advanced-execution) for the full guide.
+See [Native Async Tasks](/python/guides/advanced-execution) for the full guide.
## How workers work
@@ -304,6 +304,6 @@ See [Native Async Tasks](/guides/advanced-execution) for the full guide.
4. Results from both pools flow back through a **result channel** to the main loop
5. The main loop updates job status in SQLite (complete, retry, or DLQ)
-For multi-worker deployments, [mesh scheduling](/guides/operations/mesh)
+For multi-worker deployments, [mesh scheduling](/python/guides/operations/mesh)
adds gossip-based discovery, task affinity, and work-stealing between
workers.
diff --git a/docs/content/docs/guides/core/workflows.mdx b/docs/content/docs/python/guides/core/workflows.mdx
similarity index 60%
rename from docs/content/docs/guides/core/workflows.mdx
rename to docs/content/docs/python/guides/core/workflows.mdx
index 866dbec4..2b87f29e 100644
--- a/docs/content/docs/guides/core/workflows.mdx
+++ b/docs/content/docs/python/guides/core/workflows.mdx
@@ -4,10 +4,10 @@ description: "DAG workflows for multi-step pipelines and Canvas primitives for s
---
taskito provides two workflow models. See the dedicated
-[Workflows section](/guides/workflows) for full documentation.
+[Workflows section](/python/guides/workflows) for full documentation.
-- **[DAG Workflows](/guides/workflows)** — Multi-step pipelines as
+- **[DAG Workflows](/python/guides/workflows)** — Multi-step pipelines as
directed acyclic graphs with fan-out, conditions, gates, sub-workflows,
incremental caching, and visualization.
-- **[Canvas Primitives](/api-reference/canvas)** — Lightweight chain,
+- **[Canvas Primitives](/python/api-reference/canvas)** — Lightweight chain,
group, and chord composition for simple pipelines.
diff --git a/docs/content/docs/guides/dashboard/authentication.mdx b/docs/content/docs/python/guides/dashboard/authentication.mdx
similarity index 98%
rename from docs/content/docs/guides/dashboard/authentication.mdx
rename to docs/content/docs/python/guides/dashboard/authentication.mdx
index 6aa16fd7..1e333a26 100644
--- a/docs/content/docs/guides/dashboard/authentication.mdx
+++ b/docs/content/docs/python/guides/dashboard/authentication.mdx
@@ -155,7 +155,7 @@ guard on.
Native sign-in with Google, GitHub, and any OIDC-compliant provider
(Okta, Auth0, Keycloak, Microsoft Entra) is available alongside
-password auth — see [SSO (OAuth & OIDC)](/guides/dashboard/sso).
+password auth — see [SSO (OAuth & OIDC)](/python/guides/dashboard/sso).
Operators can mix-and-match providers or run an OAuth-only deployment
by setting `TASKITO_DASHBOARD_PASSWORD_AUTH_ENABLED=false`.
diff --git a/docs/content/docs/guides/dashboard/index.mdx b/docs/content/docs/python/guides/dashboard/index.mdx
similarity index 94%
rename from docs/content/docs/guides/dashboard/index.mdx
rename to docs/content/docs/python/guides/dashboard/index.mdx
index 4e5333c0..0bf4266f 100644
--- a/docs/content/docs/guides/dashboard/index.mdx
+++ b/docs/content/docs/python/guides/dashboard/index.mdx
@@ -69,7 +69,7 @@ taskito dashboard --app myapp:queue --host 0.0.0.0 --port 9000
On a fresh database the dashboard refuses every API request with
``503 setup_required`` until you create the first admin. See
- [Authentication](/guides/dashboard/authentication) for the full
+ [Authentication](/python/guides/dashboard/authentication) for the full
flow, including the env-var bootstrap path useful for managed
deployments.
@@ -93,12 +93,12 @@ Configuration (how to change it):
| Reliability | **Dead Letters** | Failed jobs that exhausted retries — retry or purge |
| Reliability | **Circuit Breakers** | Automatic failure protection state, thresholds, cooldowns |
| Reliability | **System** | Proxy reconstruction and interception strategy metrics |
-| Configuration | **Tasks** | Decorator defaults + runtime overrides per task ([guide](/guides/dashboard/task-overrides)) |
-| Configuration | **Webhooks** | HTTP event subscriptions with delivery history + replay ([guide](/guides/extensibility/events-webhooks)) |
+| Configuration | **Tasks** | Decorator defaults + runtime overrides per task ([guide](/python/guides/dashboard/task-overrides)) |
+| Configuration | **Webhooks** | HTTP event subscriptions with delivery history + replay ([guide](/python/guides/extensibility/events-webhooks)) |
| Configuration | **Settings** | Dashboard branding, external links, integrations |
The full REST API surface is documented at
-[Dashboard REST API](/guides/dashboard/rest-api).
+[Dashboard REST API](/python/guides/dashboard/rest-api).
## Design
@@ -138,7 +138,7 @@ first admin, every subsequent visit shows the sign-in form.

-See [Authentication](/guides/dashboard/authentication) for the env
+See [Authentication](/python/guides/dashboard/authentication) for the env
var-based bootstrap (`TASKITO_DASHBOARD_ADMIN_USER` /
`TASKITO_DASHBOARD_ADMIN_PASSWORD`) and the CSRF model.
@@ -158,7 +158,7 @@ The **Webhooks** page lists every HTTP endpoint subscribed to job
events. Add new endpoints with the **+ New webhook** button. Each row
has a dropdown menu — send a test event, enable/disable, rotate the
signing secret, or view the delivery history. Full guide:
-[Events & Webhooks](/guides/extensibility/events-webhooks).
+[Events & Webhooks](/python/guides/extensibility/events-webhooks).

@@ -169,7 +169,7 @@ defaults and any active runtime override. Click **Edit** to open a
side sheet with two tabs: **Overrides** (rate limit, concurrency,
retries, timeout, priority, paused) and **Middleware** (toggle each
middleware on or off for the task). Full guide:
-[Task & Queue Overrides](/guides/dashboard/task-overrides).
+[Task & Queue Overrides](/python/guides/dashboard/task-overrides).

diff --git a/docs/content/docs/guides/dashboard/meta.json b/docs/content/docs/python/guides/dashboard/meta.json
similarity index 100%
rename from docs/content/docs/guides/dashboard/meta.json
rename to docs/content/docs/python/guides/dashboard/meta.json
diff --git a/docs/content/docs/guides/dashboard/rest-api.mdx b/docs/content/docs/python/guides/dashboard/rest-api.mdx
similarity index 98%
rename from docs/content/docs/guides/dashboard/rest-api.mdx
rename to docs/content/docs/python/guides/dashboard/rest-api.mdx
index 77afabd4..7c4fc687 100644
--- a/docs/content/docs/guides/dashboard/rest-api.mdx
+++ b/docs/content/docs/python/guides/dashboard/rest-api.mdx
@@ -14,7 +14,7 @@ as the dashboard itself.
`/api/auth/login`, `/api/auth/setup`) requires a valid session cookie
obtained from `POST /api/auth/login`. State-changing requests
(POST/PUT/DELETE) additionally require a CSRF header. See
- [Dashboard Authentication](/guides/dashboard/authentication) for
+ [Dashboard Authentication](/python/guides/dashboard/authentication) for
the login flow and headless usage examples.
@@ -135,7 +135,7 @@ Purge all dead letters.
## Webhooks
-Full guide: [Events & Webhooks](/guides/extensibility/events-webhooks).
+Full guide: [Events & Webhooks](/python/guides/extensibility/events-webhooks).
### `GET /api/webhooks`
@@ -273,7 +273,7 @@ fresh delivery on top of the original (audit trail preserved).
## Tasks and overrides
-Full guide: [Task & Queue Overrides](/guides/dashboard/task-overrides).
+Full guide: [Task & Queue Overrides](/python/guides/dashboard/task-overrides).
### `GET /api/tasks`
diff --git a/docs/content/docs/guides/dashboard/sso.mdx b/docs/content/docs/python/guides/dashboard/sso.mdx
similarity index 100%
rename from docs/content/docs/guides/dashboard/sso.mdx
rename to docs/content/docs/python/guides/dashboard/sso.mdx
diff --git a/docs/content/docs/guides/dashboard/task-overrides.mdx b/docs/content/docs/python/guides/dashboard/task-overrides.mdx
similarity index 97%
rename from docs/content/docs/guides/dashboard/task-overrides.mdx
rename to docs/content/docs/python/guides/dashboard/task-overrides.mdx
index 4fe33da1..6fb7c0c3 100644
--- a/docs/content/docs/guides/dashboard/task-overrides.mdx
+++ b/docs/content/docs/python/guides/dashboard/task-overrides.mdx
@@ -217,6 +217,6 @@ queue.disable_middleware_for_task("myapp.tasks.process_image", "debug.payload")
## Reference
-- [Dashboard REST API: Tasks & overrides](/guides/dashboard/rest-api#tasks-and-overrides)
-- [Dashboard REST API: Middleware](/guides/dashboard/rest-api#middleware)
-- [Tasks decorator reference](/api-reference/task)
+- [Dashboard REST API: Tasks & overrides](/python/guides/dashboard/rest-api#tasks-and-overrides)
+- [Dashboard REST API: Middleware](/python/guides/dashboard/rest-api#middleware)
+- [Tasks decorator reference](/python/api-reference/task)
diff --git a/docs/content/docs/guides/extensibility/events-webhooks.mdx b/docs/content/docs/python/guides/extensibility/events-webhooks.mdx
similarity index 98%
rename from docs/content/docs/guides/extensibility/events-webhooks.mdx
rename to docs/content/docs/python/guides/extensibility/events-webhooks.mdx
index 8922cadf..73fec418 100644
--- a/docs/content/docs/guides/extensibility/events-webhooks.mdx
+++ b/docs/content/docs/python/guides/extensibility/events-webhooks.mdx
@@ -352,5 +352,5 @@ Within a single job's lifecycle, events always fire in this order:
## Reference
-- [Dashboard REST API for webhooks and deliveries](/guides/dashboard/rest-api#webhooks)
-- [Dashboard auth — how to call these endpoints from a script](/guides/dashboard/authentication)
+- [Dashboard REST API for webhooks and deliveries](/python/guides/dashboard/rest-api#webhooks)
+- [Dashboard auth — how to call these endpoints from a script](/python/guides/dashboard/authentication)
diff --git a/docs/content/docs/python/guides/extensibility/index.mdx b/docs/content/docs/python/guides/extensibility/index.mdx
new file mode 100644
index 00000000..cb317909
--- /dev/null
+++ b/docs/content/docs/python/guides/extensibility/index.mdx
@@ -0,0 +1,12 @@
+---
+title: Extensibility
+description: "Extend taskito at every stage of the task lifecycle."
+---
+
+Extend taskito with custom behavior at every stage of the task lifecycle.
+
+| Guide | Description |
+|---|---|
+| [Middleware](/python/guides/extensibility/middleware) | Hook into task execution with `before`, `after`, `on_retry`, and more |
+| [Serializers](/python/guides/extensibility/serializers) | Custom payload serialization — msgpack, orjson, encryption |
+| [Events & Webhooks](/python/guides/extensibility/events-webhooks) | React to queue events and push notifications to external services |
diff --git a/docs/content/docs/guides/extensibility/meta.json b/docs/content/docs/python/guides/extensibility/meta.json
similarity index 100%
rename from docs/content/docs/guides/extensibility/meta.json
rename to docs/content/docs/python/guides/extensibility/meta.json
diff --git a/docs/content/docs/guides/extensibility/middleware.mdx b/docs/content/docs/python/guides/extensibility/middleware.mdx
similarity index 98%
rename from docs/content/docs/guides/extensibility/middleware.mdx
rename to docs/content/docs/python/guides/extensibility/middleware.mdx
index b156fe8b..ada55f11 100644
--- a/docs/content/docs/guides/extensibility/middleware.mdx
+++ b/docs/content/docs/python/guides/extensibility/middleware.mdx
@@ -222,4 +222,4 @@ queue = Queue(middleware=[
])
```
-See the [OpenTelemetry guide](/guides/integrations) for setup details.
+See the [OpenTelemetry guide](/python/guides/integrations) for setup details.
diff --git a/docs/content/docs/guides/extensibility/serializers.mdx b/docs/content/docs/python/guides/extensibility/serializers.mdx
similarity index 100%
rename from docs/content/docs/guides/extensibility/serializers.mdx
rename to docs/content/docs/python/guides/extensibility/serializers.mdx
diff --git a/docs/content/docs/guides/index.mdx b/docs/content/docs/python/guides/index.mdx
similarity index 81%
rename from docs/content/docs/guides/index.mdx
rename to docs/content/docs/python/guides/index.mdx
index 8a2374ae..d8a8377e 100644
--- a/docs/content/docs/guides/index.mdx
+++ b/docs/content/docs/python/guides/index.mdx
@@ -19,61 +19,61 @@ import {
Pick the topic you're working through. Each guide is self-contained, with code
samples, gotchas, and links to the relevant API reference. For a one-page
overview of everything taskito does, see
-[**Capabilities at a glance**](/capabilities).
+[**Capabilities at a glance**](/python/capabilities).
}
title="Core"
- href="/guides/core"
+ href="/python/guides/core"
description="Define tasks, route to queues, run workers, schedule periodics."
/>
}
title="Reliability"
- href="/guides/reliability"
+ href="/python/guides/reliability"
description="Retries, dead letters, circuit breakers, idempotency, error handling."
/>
}
title="Advanced execution"
- href="/guides/advanced-execution"
+ href="/python/guides/advanced-execution"
description="Prefork pools, native async, streaming, cancellation, soft timeouts."
/>
}
title="Operations"
- href="/guides/operations"
+ href="/python/guides/operations"
description="Deployment, scaling, namespaces, migration from Celery."
/>
}
title="Observability"
- href="/guides/observability"
+ href="/python/guides/observability"
description="Metrics, logs, dashboard, OpenTelemetry, Sentry, Prometheus."
/>
}
title="Resources"
- href="/guides/resources"
+ href="/python/guides/resources"
description="Inject DB clients, HTTP sessions, and cloud SDKs by name with hot reload."
/>
}
title="Workflows"
- href="/guides/workflows"
+ href="/python/guides/workflows"
description="DAGs, fan-out, fan-in, conditions, gates, sub-workflows, incremental re-runs."
/>
}
title="Integrations"
- href="/guides/integrations"
+ href="/python/guides/integrations"
description="Django, FastAPI, Flask — admin views, REST routers, management commands."
/>
}
title="Extensibility"
- href="/guides/extensibility"
+ href="/python/guides/extensibility"
description="Custom serializers, middleware, events, webhooks, proxies."
/>
diff --git a/docs/content/docs/guides/integrations/django.mdx b/docs/content/docs/python/guides/integrations/django.mdx
similarity index 100%
rename from docs/content/docs/guides/integrations/django.mdx
rename to docs/content/docs/python/guides/integrations/django.mdx
diff --git a/docs/content/docs/guides/integrations/fastapi.mdx b/docs/content/docs/python/guides/integrations/fastapi.mdx
similarity index 100%
rename from docs/content/docs/guides/integrations/fastapi.mdx
rename to docs/content/docs/python/guides/integrations/fastapi.mdx
diff --git a/docs/content/docs/guides/integrations/flask.mdx b/docs/content/docs/python/guides/integrations/flask.mdx
similarity index 100%
rename from docs/content/docs/guides/integrations/flask.mdx
rename to docs/content/docs/python/guides/integrations/flask.mdx
diff --git a/docs/content/docs/guides/integrations/index.mdx b/docs/content/docs/python/guides/integrations/index.mdx
similarity index 73%
rename from docs/content/docs/guides/integrations/index.mdx
rename to docs/content/docs/python/guides/integrations/index.mdx
index 9aa5be6d..f5d61d84 100644
--- a/docs/content/docs/guides/integrations/index.mdx
+++ b/docs/content/docs/python/guides/integrations/index.mdx
@@ -23,15 +23,15 @@ tools. Install only what you need.
## Framework integrations
-- **[Flask](/guides/integrations/flask)** — full Flask extension with app config, factory pattern, and CLI commands
-- **[FastAPI](/guides/integrations/fastapi)** — pre-built `APIRouter` with job status, SSE progress, and DLQ management
-- **[Django](/guides/integrations/django)** — admin views for browsing jobs, dead letters, and queue stats
+- **[Flask](/python/guides/integrations/flask)** — full Flask extension with app config, factory pattern, and CLI commands
+- **[FastAPI](/python/guides/integrations/fastapi)** — pre-built `APIRouter` with job status, SSE progress, and DLQ management
+- **[Django](/python/guides/integrations/django)** — admin views for browsing jobs, dead letters, and queue stats
## Observability integrations
-- **[OpenTelemetry](/guides/integrations/otel)** — distributed tracing with per-task spans
-- **[Prometheus](/guides/integrations/prometheus)** — counters, histograms, and gauges for task execution
-- **[Sentry](/guides/integrations/sentry)** — automatic error capture with task context
+- **[OpenTelemetry](/python/guides/integrations/otel)** — distributed tracing with per-task spans
+- **[Prometheus](/python/guides/integrations/prometheus)** — counters, histograms, and gauges for task execution
+- **[Sentry](/python/guides/integrations/sentry)** — automatic error capture with task context
## Combining integrations
diff --git a/docs/content/docs/guides/integrations/meta.json b/docs/content/docs/python/guides/integrations/meta.json
similarity index 100%
rename from docs/content/docs/guides/integrations/meta.json
rename to docs/content/docs/python/guides/integrations/meta.json
diff --git a/docs/content/docs/guides/integrations/otel.mdx b/docs/content/docs/python/guides/integrations/otel.mdx
similarity index 97%
rename from docs/content/docs/guides/integrations/otel.mdx
rename to docs/content/docs/python/guides/integrations/otel.mdx
index 9d5c1b00..e3c59509 100644
--- a/docs/content/docs/guides/integrations/otel.mdx
+++ b/docs/content/docs/python/guides/integrations/otel.mdx
@@ -106,5 +106,5 @@ queue = Queue(middleware=[
lock.
-See the [Middleware guide](/guides/extensibility/middleware) for more
+See the [Middleware guide](/python/guides/extensibility/middleware) for more
on combining middleware.
diff --git a/docs/content/docs/guides/integrations/prometheus.mdx b/docs/content/docs/python/guides/integrations/prometheus.mdx
similarity index 98%
rename from docs/content/docs/guides/integrations/prometheus.mdx
rename to docs/content/docs/python/guides/integrations/prometheus.mdx
index fac36c3e..f84dccc0 100644
--- a/docs/content/docs/guides/integrations/prometheus.mdx
+++ b/docs/content/docs/python/guides/integrations/prometheus.mdx
@@ -160,7 +160,7 @@ queue = Queue(
)
```
-See the [Middleware guide](/guides/extensibility/middleware) for more
+See the [Middleware guide](/python/guides/extensibility/middleware) for more
on combining middleware.
## Example: alert on high DLQ size
diff --git a/docs/content/docs/guides/integrations/sentry.mdx b/docs/content/docs/python/guides/integrations/sentry.mdx
similarity index 98%
rename from docs/content/docs/guides/integrations/sentry.mdx
rename to docs/content/docs/python/guides/integrations/sentry.mdx
index 211c03f6..0a01a86c 100644
--- a/docs/content/docs/guides/integrations/sentry.mdx
+++ b/docs/content/docs/python/guides/integrations/sentry.mdx
@@ -100,7 +100,7 @@ queue = Queue(
)
```
-See the [Middleware guide](/guides/extensibility/middleware) for more
+See the [Middleware guide](/python/guides/extensibility/middleware) for more
on combining middleware.
## Full example
diff --git a/docs/content/docs/guides/meta.json b/docs/content/docs/python/guides/meta.json
similarity index 100%
rename from docs/content/docs/guides/meta.json
rename to docs/content/docs/python/guides/meta.json
diff --git a/docs/content/docs/python/guides/observability/index.mdx b/docs/content/docs/python/guides/observability/index.mdx
new file mode 100644
index 00000000..5fb72fa6
--- /dev/null
+++ b/docs/content/docs/python/guides/observability/index.mdx
@@ -0,0 +1,16 @@
+---
+title: Observability
+description: "Monitor, log, and inspect your task queue in real time."
+---
+
+Monitor, log, and inspect your task queue in real time.
+
+| Guide | Description |
+|---|---|
+| [Monitoring & Hooks](/python/guides/observability/monitoring) | Queue stats, progress tracking, worker heartbeat, and alerting hooks |
+| [Structured Logging](/python/guides/observability/logging) | Per-task structured logs with automatic context |
+| [Structured Notes](/python/guides/observability/notes) | Operator-visible metadata attached to individual jobs |
+
+For the built-in web UI, see the [Dashboard](/python/guides/dashboard) section —
+it covers the browser app, password and SSO login, runtime task/queue
+overrides, and the underlying REST API.
diff --git a/docs/content/docs/guides/observability/logging.mdx b/docs/content/docs/python/guides/observability/logging.mdx
similarity index 100%
rename from docs/content/docs/guides/observability/logging.mdx
rename to docs/content/docs/python/guides/observability/logging.mdx
diff --git a/docs/content/docs/guides/observability/meta.json b/docs/content/docs/python/guides/observability/meta.json
similarity index 100%
rename from docs/content/docs/guides/observability/meta.json
rename to docs/content/docs/python/guides/observability/meta.json
diff --git a/docs/content/docs/guides/observability/monitoring.mdx b/docs/content/docs/python/guides/observability/monitoring.mdx
similarity index 96%
rename from docs/content/docs/guides/observability/monitoring.mdx
rename to docs/content/docs/python/guides/observability/monitoring.mdx
index c5e1d2ea..08b0d70c 100644
--- a/docs/content/docs/guides/observability/monitoring.mdx
+++ b/docs/content/docs/python/guides/observability/monitoring.mdx
@@ -120,7 +120,7 @@ workers = await queue.aworkers()
The worker heartbeat is also available via the dashboard REST API at
`GET /api/workers`. See the
-[Dashboard](/guides/dashboard) guide for details.
+[Dashboard](/python/guides/dashboard) guide for details.
## Events system
@@ -129,7 +129,7 @@ events (`JOB_ENQUEUED`, `JOB_COMPLETED`, `JOB_FAILED`, `JOB_RETRYING`,
`JOB_DEAD`, `JOB_CANCELLED`). Events can also be delivered as signed HTTP
webhooks to external systems.
-[Events & Webhooks guide →](/guides/extensibility)
+[Events & Webhooks guide →](/python/guides/extensibility)
## Prometheus metrics
@@ -140,7 +140,7 @@ counters, histograms, and gauges for task execution:
pip install taskito[prometheus]
```
-[Prometheus integration →](/guides/integrations)
+[Prometheus integration →](/python/guides/integrations)
## Hooks
diff --git a/docs/content/docs/guides/observability/notes.mdx b/docs/content/docs/python/guides/observability/notes.mdx
similarity index 100%
rename from docs/content/docs/guides/observability/notes.mdx
rename to docs/content/docs/python/guides/observability/notes.mdx
diff --git a/docs/content/docs/guides/operations/autoscaler.mdx b/docs/content/docs/python/guides/operations/autoscaler.mdx
similarity index 98%
rename from docs/content/docs/guides/operations/autoscaler.mdx
rename to docs/content/docs/python/guides/operations/autoscaler.mdx
index e8b17e28..ce3bc5bc 100644
--- a/docs/content/docs/guides/operations/autoscaler.mdx
+++ b/docs/content/docs/python/guides/operations/autoscaler.mdx
@@ -11,7 +11,7 @@ formula so the scaling behaviour is predictable if you're already familiar
with KEDA or the Horizontal Pod Autoscaler.
Use this when you're running on bare metal, Docker, or systemd and can't
-use [KEDA + Kubernetes](/guides/operations/keda).
+use [KEDA + Kubernetes](/python/guides/operations/keda).
## Quick start
@@ -286,4 +286,4 @@ volumes:
| Crash recovery | Auto-replaces crashed workers | Kubernetes restarts pods |
| Setup | Zero — no external components | KEDA operator + ScaledObject |
-For Kubernetes deployments, use [KEDA](/guides/operations/keda).
+For Kubernetes deployments, use [KEDA](/python/guides/operations/keda).
diff --git a/docs/content/docs/guides/operations/deployment.mdx b/docs/content/docs/python/guides/operations/deployment.mdx
similarity index 97%
rename from docs/content/docs/guides/operations/deployment.mdx
rename to docs/content/docs/python/guides/operations/deployment.mdx
index e74f887f..10e4e874 100644
--- a/docs/content/docs/guides/operations/deployment.mdx
+++ b/docs/content/docs/python/guides/operations/deployment.mdx
@@ -160,7 +160,7 @@ Both methods are safe while the worker is running.
## Postgres deployment
-If you're using the [Postgres backend](/guides/operations/postgres),
+If you're using the [Postgres backend](/python/guides/operations/postgres),
deployment is simpler in several ways:
- **No shared-file constraints** — workers connect over the network, no need for shared volumes or local storage
@@ -204,7 +204,7 @@ pg_dump -h localhost -U taskito -d myapp -n taskito > backup.sql
psql -h localhost -U taskito -d myapp < backup.sql
```
-See the [Postgres Backend guide](/guides/operations/postgres) for full
+See the [Postgres Backend guide](/python/guides/operations/postgres) for full
configuration details.
## Database maintenance
@@ -324,7 +324,7 @@ queue = Queue(
```
If you need distributed workers across multiple machines, use the
-[Postgres backend](/guides/operations/postgres) which removes the
+[Postgres backend](/python/guides/operations/postgres) which removes the
single-writer constraint and supports multi-machine deployments.
## SQLite scaling limits
@@ -349,7 +349,7 @@ are serialized. This is the primary throughput ceiling.
- Multiple processes contend heavily for writes (high lock wait times)
- You need sub-millisecond dequeue latency under high load
-taskito's [Postgres backend](/guides/operations/postgres) addresses all
+taskito's [Postgres backend](/python/guides/operations/postgres) addresses all
of these limitations while keeping the same API.
## Sizing your deployment
diff --git a/docs/content/docs/python/guides/operations/index.mdx b/docs/content/docs/python/guides/operations/index.mdx
new file mode 100644
index 00000000..0866b9e1
--- /dev/null
+++ b/docs/content/docs/python/guides/operations/index.mdx
@@ -0,0 +1,17 @@
+---
+title: Operations
+description: "Run taskito reliably in production — testing, deployment, scaling, migration."
+---
+
+Run taskito reliably in production.
+
+| Guide | Description |
+|---|---|
+| [Testing](/python/guides/operations/testing) | Test mode, fixtures, mocking resources, and workflow testing |
+| [Job Management](/python/guides/operations/job-management) | Cancel, pause, archive, revoke, replay, and clean up jobs |
+| [Troubleshooting](/python/guides/operations/troubleshooting) | Diagnose stuck jobs, lock contention, and worker issues |
+| [Deployment](/python/guides/operations/deployment) | systemd, Docker, WAL mode, Postgres, and production checklists |
+| [Bare-Metal Autoscaler](/python/guides/operations/autoscaler) | Automatically scale worker processes without Kubernetes |
+| [KEDA Autoscaling](/python/guides/operations/keda) | Kubernetes event-driven autoscaling for workers |
+| [Postgres Backend](/python/guides/operations/postgres) | Set up and run taskito with PostgreSQL |
+| [Migrating from Celery](/python/guides/operations/migration) | Side-by-side comparison and step-by-step migration guide |
diff --git a/docs/content/docs/guides/operations/job-management.mdx b/docs/content/docs/python/guides/operations/job-management.mdx
similarity index 100%
rename from docs/content/docs/guides/operations/job-management.mdx
rename to docs/content/docs/python/guides/operations/job-management.mdx
diff --git a/docs/content/docs/guides/operations/keda.mdx b/docs/content/docs/python/guides/operations/keda.mdx
similarity index 97%
rename from docs/content/docs/guides/operations/keda.mdx
rename to docs/content/docs/python/guides/operations/keda.mdx
index 34bee69c..e9702b83 100644
--- a/docs/content/docs/guides/operations/keda.mdx
+++ b/docs/content/docs/python/guides/operations/keda.mdx
@@ -193,7 +193,7 @@ spec:
threshold: "0.8"
```
-See the [Prometheus integration](/guides/integrations) for setting up
+See the [Prometheus integration](/python/guides/integrations) for setting up
the metrics collector.
## Deploy templates
@@ -210,6 +210,6 @@ Ready-to-use YAML templates are included in the repository under
When using SQLite, all worker replicas must share the same database
volume. For multi-replica Kubernetes deployments, use the
- [Postgres backend](/guides/operations/postgres) — workers connect
+ [Postgres backend](/python/guides/operations/postgres) — workers connect
over the network and there's no shared-file constraint.
diff --git a/docs/content/docs/guides/operations/mesh.mdx b/docs/content/docs/python/guides/operations/mesh.mdx
similarity index 91%
rename from docs/content/docs/guides/operations/mesh.mdx
rename to docs/content/docs/python/guides/operations/mesh.mdx
index 2f7af0e9..ba07004f 100644
--- a/docs/content/docs/guides/operations/mesh.mdx
+++ b/docs/content/docs/python/guides/operations/mesh.mdx
@@ -7,7 +7,7 @@ import { Callout } from "fumadocs-ui/components/callout";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
Mesh scheduling adds a decentralized overlay network on top of the
-[standard scheduler](/architecture/scheduler). Workers discover each other via
+[standard scheduler](/python/architecture/scheduler). Workers discover each other via
gossip, route tasks through a consistent-hashing ring, and steal work from
busy peers — all without a central coordinator.
@@ -56,18 +56,18 @@ Mesh scheduling composes five primitives that work together:
|---|---|
| **SWIM gossip** | UDP protocol for worker discovery and failure detection (~1.5s vs 30s DB heartbeat) |
| **Consistent hashing** | xxhash ring with virtual nodes maps tasks to preferred workers (soft affinity) |
-| **Local deque** | In-memory buffer between DB polls — workers drain the deque before hitting the [storage backend](/architecture/storage) |
+| **Local deque** | In-memory buffer between DB polls — workers drain the deque before hitting the [storage backend](/python/architecture/storage) |
| **Work-stealing** | TCP protocol lets idle workers steal jobs from busy peers |
| **Adaptive load balancing** | Prefetch size and poll timing auto-tune based on cluster state |
The database remains the source of truth. Gossip is an optimization layer —
if it fails, workers fall back to standard DB polling. See
-[Architecture: Mesh Scheduling](/architecture/mesh) for protocol-level details.
+[Architecture: Mesh Scheduling](/python/architecture/mesh) for protocol-level details.
## Configuration
All mesh settings live in `MeshWorker`, keeping the
-[`Queue`](/api-reference/queue) class clean:
+[`Queue`](/python/api-reference/queue) class clean:
```python
mesh = MeshWorker(
@@ -221,7 +221,7 @@ parameter controls how aggressively the ring biases dispatch. Set it to
This improves cache locality — if a task always runs on the same worker,
its imports, connections, and warm caches stay hot. Particularly useful with
-[worker resources](/guides/resources/overview) that have expensive
+[worker resources](/python/guides/resources/overview) that have expensive
initialization.
```python
@@ -325,15 +325,15 @@ queue.run_worker(mesh=mesh)
```
See also:
-- [Per-task concurrency](/guides/core/tasks#concurrency) for `max_concurrent`
-- [Rate limiting](/guides/core/tasks#rate-limiting) for `rate_limit`
-- [Worker resources](/guides/resources/overview) for DI into tasks
-- [Batch dequeue](/guides/core/scheduling#batch-dequeue) for `scheduler_batch_size`
+- [Per-task concurrency](/python/guides/core/tasks#concurrency) for `max_concurrent`
+- [Rate limiting](/python/guides/core/tasks#rate-limiting) for `rate_limit`
+- [Worker resources](/python/guides/resources/overview) for DI into tasks
+- [Batch dequeue](/python/guides/core/scheduling#batch-dequeue) for `scheduler_batch_size`
## Mixing mesh and non-mesh workers
-Mesh workers coexist safely with [standard workers](/guides/core/workers).
-Both use the same [storage backend](/architecture/storage) for atomic job
+Mesh workers coexist safely with [standard workers](/python/guides/core/workers).
+Both use the same [storage backend](/python/architecture/storage) for atomic job
claims — mesh just reduces how often workers hit the DB.
```python
@@ -372,13 +372,13 @@ Key log messages:
| `debug` | `giving N jobs to thief X` | Responded to steal request |
| `debug` | `ack from X resolved probe` | Healthy ping-ack cycle |
-If you use [Prometheus](/guides/integrations/prometheus), mesh metrics flow
+If you use [Prometheus](/python/guides/integrations/prometheus), mesh metrics flow
through the same worker observability pipeline.
## Graceful shutdown
When a mesh worker shuts down (via `SIGINT`, `SIGTERM`, or
-[`request_shutdown()`](/api-reference/queue#request_shutdown)), it broadcasts
+[`request_shutdown()`](/python/api-reference/queue#request_shutdown)), it broadcasts
a `Leave` message to all known peers. They remove it from the ring
immediately — no suspicion timeout needed.
@@ -402,6 +402,6 @@ With default settings (multiplier=4, period=500ms), a crashed worker in a
- Single worker setups
- Low throughput (< 100 jobs/second)
- Workers processing completely different queues (no overlap = no stealing)
-- Already using [bare-metal autoscaler](/guides/operations/autoscaler) or
- [KEDA](/guides/operations/keda) for process-level scaling (mesh is
+- Already using [bare-metal autoscaler](/python/guides/operations/autoscaler) or
+ [KEDA](/python/guides/operations/keda) for process-level scaling (mesh is
*within-process* optimization, not a replacement for autoscaling)
diff --git a/docs/content/docs/guides/operations/meta.json b/docs/content/docs/python/guides/operations/meta.json
similarity index 100%
rename from docs/content/docs/guides/operations/meta.json
rename to docs/content/docs/python/guides/operations/meta.json
diff --git a/docs/content/docs/guides/operations/migration.mdx b/docs/content/docs/python/guides/operations/migration.mdx
similarity index 100%
rename from docs/content/docs/guides/operations/migration.mdx
rename to docs/content/docs/python/guides/operations/migration.mdx
diff --git a/docs/content/docs/guides/operations/postgres.mdx b/docs/content/docs/python/guides/operations/postgres.mdx
similarity index 100%
rename from docs/content/docs/guides/operations/postgres.mdx
rename to docs/content/docs/python/guides/operations/postgres.mdx
diff --git a/docs/content/docs/guides/operations/security.mdx b/docs/content/docs/python/guides/operations/security.mdx
similarity index 100%
rename from docs/content/docs/guides/operations/security.mdx
rename to docs/content/docs/python/guides/operations/security.mdx
diff --git a/docs/content/docs/guides/operations/testing.mdx b/docs/content/docs/python/guides/operations/testing.mdx
similarity index 98%
rename from docs/content/docs/guides/operations/testing.mdx
rename to docs/content/docs/python/guides/operations/testing.mdx
index 4b696e98..7528e746 100644
--- a/docs/content/docs/guides/operations/testing.mdx
+++ b/docs/content/docs/python/guides/operations/testing.mdx
@@ -53,7 +53,7 @@ with queue.test_mode(propagate_errors=False, resources=None) as results:
| Parameter | Type | Default | Description |
|---|---|---|---|
| `propagate_errors` | `bool` | `False` | If `True`, task exceptions are re-raised immediately instead of being captured in `TestResult.error` |
-| `resources` | `dict[str, Any] \| None` | `None` | Map of resource name → mock instance or `MockResource` for injection. See [Resource System](/guides/resources). |
+| `resources` | `dict[str, Any] \| None` | `None` | Map of resource name → mock instance or `MockResource` for injection. See [Resource System](/python/guides/resources). |
The context manager yields a `TestResults` list that accumulates results as
tasks execute.
@@ -272,7 +272,7 @@ async def test_async_enqueue(task_results):
## Testing with worker resources
-If your tasks use [worker resources](/guides/resources) (injected via
+If your tasks use [worker resources](/python/guides/resources) (injected via
`inject=` or `Inject["name"]`), pass mock instances through `resources=`:
```python
diff --git a/docs/content/docs/guides/operations/troubleshooting.mdx b/docs/content/docs/python/guides/operations/troubleshooting.mdx
similarity index 100%
rename from docs/content/docs/guides/operations/troubleshooting.mdx
rename to docs/content/docs/python/guides/operations/troubleshooting.mdx
diff --git a/docs/content/docs/guides/operations/upgrading-0.15.mdx b/docs/content/docs/python/guides/operations/upgrading-0.15.mdx
similarity index 100%
rename from docs/content/docs/guides/operations/upgrading-0.15.mdx
rename to docs/content/docs/python/guides/operations/upgrading-0.15.mdx
diff --git a/docs/content/docs/guides/reliability/circuit-breakers.mdx b/docs/content/docs/python/guides/reliability/circuit-breakers.mdx
similarity index 100%
rename from docs/content/docs/guides/reliability/circuit-breakers.mdx
rename to docs/content/docs/python/guides/reliability/circuit-breakers.mdx
diff --git a/docs/content/docs/guides/reliability/error-handling.mdx b/docs/content/docs/python/guides/reliability/error-handling.mdx
similarity index 98%
rename from docs/content/docs/guides/reliability/error-handling.mdx
rename to docs/content/docs/python/guides/reliability/error-handling.mdx
index 82d5628f..2b48ae57 100644
--- a/docs/content/docs/guides/reliability/error-handling.mdx
+++ b/docs/content/docs/python/guides/reliability/error-handling.mdx
@@ -247,7 +247,7 @@ def on_task_failure(task_name, args, kwargs, error):
### Test mode for isolation
-Use [test mode](/guides/operations) to run tasks synchronously and inspect
+Use [test mode](/python/guides/operations) to run tasks synchronously and inspect
errors without a worker:
```python
@@ -287,7 +287,7 @@ def call_api(url):
return resp.json()
```
-See [Retries — Exception Filtering](/guides/reliability/retries) for details.
+See [Retries — Exception Filtering](/python/guides/reliability/retries) for details.
### Cancelling running tasks
diff --git a/docs/content/docs/guides/reliability/guarantees.mdx b/docs/content/docs/python/guides/reliability/guarantees.mdx
similarity index 98%
rename from docs/content/docs/guides/reliability/guarantees.mdx
rename to docs/content/docs/python/guides/reliability/guarantees.mdx
index 38040a75..f3523034 100644
--- a/docs/content/docs/guides/reliability/guarantees.mdx
+++ b/docs/content/docs/python/guides/reliability/guarantees.mdx
@@ -84,7 +84,7 @@ job = send_report.apply_async(
If a job with the same `unique_key` is already pending or running, the
duplicate is silently dropped. See
-[Unique Tasks](/guides/advanced-execution) for details.
+[Unique Tasks](/python/guides/advanced-execution) for details.
### Avoid side effects that can't be undone
diff --git a/docs/content/docs/guides/reliability/idempotency.mdx b/docs/content/docs/python/guides/reliability/idempotency.mdx
similarity index 100%
rename from docs/content/docs/guides/reliability/idempotency.mdx
rename to docs/content/docs/python/guides/reliability/idempotency.mdx
diff --git a/docs/content/docs/python/guides/reliability/index.mdx b/docs/content/docs/python/guides/reliability/index.mdx
new file mode 100644
index 00000000..70848e97
--- /dev/null
+++ b/docs/content/docs/python/guides/reliability/index.mdx
@@ -0,0 +1,15 @@
+---
+title: Reliability
+description: "Harden your task queue for production workloads."
+---
+
+Harden your task queue for production workloads.
+
+| Guide | Description |
+|---|---|
+| [Retries & Dead Letters](/python/guides/reliability/retries) | Automatic retries with exponential backoff, dead letter queue |
+| [Error Handling](/python/guides/reliability/error-handling) | Task failure lifecycle, error inspection, debugging patterns |
+| [Delivery Guarantees](/python/guides/reliability/guarantees) | At-least-once delivery, idempotency, and exactly-once patterns |
+| [Rate Limiting](/python/guides/reliability/rate-limiting) | Throttle task execution with token bucket rate limits |
+| [Circuit Breakers](/python/guides/reliability/circuit-breakers) | Protect downstream services from cascading failures |
+| [Distributed Locking](/python/guides/reliability/locking) | Mutual exclusion across workers with database-backed locks |
diff --git a/docs/content/docs/guides/reliability/locking.mdx b/docs/content/docs/python/guides/reliability/locking.mdx
similarity index 100%
rename from docs/content/docs/guides/reliability/locking.mdx
rename to docs/content/docs/python/guides/reliability/locking.mdx
diff --git a/docs/content/docs/guides/reliability/meta.json b/docs/content/docs/python/guides/reliability/meta.json
similarity index 100%
rename from docs/content/docs/guides/reliability/meta.json
rename to docs/content/docs/python/guides/reliability/meta.json
diff --git a/docs/content/docs/guides/reliability/rate-limiting.mdx b/docs/content/docs/python/guides/reliability/rate-limiting.mdx
similarity index 100%
rename from docs/content/docs/guides/reliability/rate-limiting.mdx
rename to docs/content/docs/python/guides/reliability/rate-limiting.mdx
diff --git a/docs/content/docs/guides/reliability/retries.mdx b/docs/content/docs/python/guides/reliability/retries.mdx
similarity index 100%
rename from docs/content/docs/guides/reliability/retries.mdx
rename to docs/content/docs/python/guides/reliability/retries.mdx
diff --git a/docs/content/docs/guides/resources/configuration.mdx b/docs/content/docs/python/guides/resources/configuration.mdx
similarity index 100%
rename from docs/content/docs/guides/resources/configuration.mdx
rename to docs/content/docs/python/guides/resources/configuration.mdx
diff --git a/docs/content/docs/guides/resources/dependency-injection.mdx b/docs/content/docs/python/guides/resources/dependency-injection.mdx
similarity index 98%
rename from docs/content/docs/guides/resources/dependency-injection.mdx
rename to docs/content/docs/python/guides/resources/dependency-injection.mdx
index 57304a70..c9f19003 100644
--- a/docs/content/docs/guides/resources/dependency-injection.mdx
+++ b/docs/content/docs/python/guides/resources/dependency-injection.mdx
@@ -115,7 +115,7 @@ def create_cache():
Pool configuration parameters (`pool_size`, `pool_min`, `acquire_timeout`,
`max_lifetime`, `idle_timeout`) only apply to task-scoped resources. See
-[Configuration](/guides/resources/configuration) for details.
+[Configuration](/python/guides/resources/configuration) for details.
## Dependencies
@@ -236,7 +236,7 @@ status = queue.resource_status()
```
Task-scoped resources include a `"pool"` key with pool statistics. See
-[Observability](/guides/resources/observability) for details.
+[Observability](/python/guides/resources/observability) for details.
## Full example
diff --git a/docs/content/docs/guides/resources/index.mdx b/docs/content/docs/python/guides/resources/index.mdx
similarity index 78%
rename from docs/content/docs/guides/resources/index.mdx
rename to docs/content/docs/python/guides/resources/index.mdx
index c3dc6a11..fc53e608 100644
--- a/docs/content/docs/guides/resources/index.mdx
+++ b/docs/content/docs/python/guides/resources/index.mdx
@@ -87,9 +87,9 @@ taskito worker --app myapp.tasks:queue
| Page | What it covers |
|---|---|
-| [Argument Interception](/guides/resources/interception) | Modes, strategies, custom types, `analyze()`, metrics |
-| [Dependency Injection](/guides/resources/dependency-injection) | `worker_resource()`, scopes, dependencies, teardown, health checks |
-| [Resource Proxies](/guides/resources/proxies) | Built-in handlers, HMAC signing, security, `NoProxy`, cloud handlers |
-| [Configuration](/guides/resources/configuration) | TOML config, pool tuning, frozen and reloadable resources, hot reload |
-| [Testing](/guides/resources/testing) | `test_mode(resources=)`, `MockResource`, pytest fixtures |
-| [Observability](/guides/resources/observability) | Prometheus metrics, dashboard endpoints, CLI commands |
+| [Argument Interception](/python/guides/resources/interception) | Modes, strategies, custom types, `analyze()`, metrics |
+| [Dependency Injection](/python/guides/resources/dependency-injection) | `worker_resource()`, scopes, dependencies, teardown, health checks |
+| [Resource Proxies](/python/guides/resources/proxies) | Built-in handlers, HMAC signing, security, `NoProxy`, cloud handlers |
+| [Configuration](/python/guides/resources/configuration) | TOML config, pool tuning, frozen and reloadable resources, hot reload |
+| [Testing](/python/guides/resources/testing) | `test_mode(resources=)`, `MockResource`, pytest fixtures |
+| [Observability](/python/guides/resources/observability) | Prometheus metrics, dashboard endpoints, CLI commands |
diff --git a/docs/content/docs/guides/resources/interception.mdx b/docs/content/docs/python/guides/resources/interception.mdx
similarity index 97%
rename from docs/content/docs/guides/resources/interception.mdx
rename to docs/content/docs/python/guides/resources/interception.mdx
index 05712dab..aa0b3a58 100644
--- a/docs/content/docs/guides/resources/interception.mdx
+++ b/docs/content/docs/python/guides/resources/interception.mdx
@@ -92,7 +92,7 @@ These objects are deconstructed to a recipe dict and rebuilt by the worker:
| boto3 clients (via `botocore.client.BaseClient`) | `"boto3_client"` |
| `google.cloud.storage.Client` / `Bucket` / `Blob` | `"gcs_client"` |
-See [Resource Proxies](/guides/resources/proxies) for security options
+See [Resource Proxies](/python/guides/resources/proxies) for security options
and handler details.
## Built-in REJECT types
@@ -192,5 +192,5 @@ stats = queue.interception_stats()
# }
```
-See [Observability](/guides/resources/observability) for Prometheus
+See [Observability](/python/guides/resources/observability) for Prometheus
metrics and dashboard endpoints.
diff --git a/docs/content/docs/guides/resources/meta.json b/docs/content/docs/python/guides/resources/meta.json
similarity index 100%
rename from docs/content/docs/guides/resources/meta.json
rename to docs/content/docs/python/guides/resources/meta.json
diff --git a/docs/content/docs/guides/resources/observability.mdx b/docs/content/docs/python/guides/resources/observability.mdx
similarity index 97%
rename from docs/content/docs/guides/resources/observability.mdx
rename to docs/content/docs/python/guides/resources/observability.mdx
index e9a25b76..d4a110b2 100644
--- a/docs/content/docs/guides/resources/observability.mdx
+++ b/docs/content/docs/python/guides/resources/observability.mdx
@@ -122,7 +122,7 @@ Start the dashboard:
taskito dashboard --app myapp.tasks:queue
```
-See the [Web Dashboard](/guides/dashboard) guide for
+See the [Web Dashboard](/python/guides/dashboard) guide for
full dashboard documentation.
## CLI commands
@@ -214,5 +214,5 @@ from taskito.contrib.prometheus import start_metrics_server
start_metrics_server(port=9090)
```
-See the [Prometheus integration](/guides/integrations) page for full
+See the [Prometheus integration](/python/guides/integrations) page for full
setup instructions.
diff --git a/docs/content/docs/guides/resources/proxies.mdx b/docs/content/docs/python/guides/resources/proxies.mdx
similarity index 98%
rename from docs/content/docs/guides/resources/proxies.mdx
rename to docs/content/docs/python/guides/resources/proxies.mdx
index 2863183c..15a04423 100644
--- a/docs/content/docs/guides/resources/proxies.mdx
+++ b/docs/content/docs/python/guides/resources/proxies.mdx
@@ -181,5 +181,5 @@ stats = queue.proxy_stats()
# ]
```
-See [Observability](/guides/resources/observability) for Prometheus
+See [Observability](/python/guides/resources/observability) for Prometheus
metrics and dashboard endpoints.
diff --git a/docs/content/docs/guides/resources/testing.mdx b/docs/content/docs/python/guides/resources/testing.mdx
similarity index 100%
rename from docs/content/docs/guides/resources/testing.mdx
rename to docs/content/docs/python/guides/resources/testing.mdx
diff --git a/docs/content/docs/guides/workflows/analysis.mdx b/docs/content/docs/python/guides/workflows/analysis.mdx
similarity index 100%
rename from docs/content/docs/guides/workflows/analysis.mdx
rename to docs/content/docs/python/guides/workflows/analysis.mdx
diff --git a/docs/content/docs/guides/workflows/building.mdx b/docs/content/docs/python/guides/workflows/building.mdx
similarity index 98%
rename from docs/content/docs/guides/workflows/building.mdx
rename to docs/content/docs/python/guides/workflows/building.mdx
index 3be147c1..7a54bf02 100644
--- a/docs/content/docs/guides/workflows/building.mdx
+++ b/docs/content/docs/python/guides/workflows/building.mdx
@@ -106,7 +106,7 @@ This creates a `WorkflowRun` handle. Under the hood:
| `name` | `str` | `"workflow"` | Workflow name |
| `version` | `int` | `1` | Version number |
| `on_failure` | `str` | `"fail_fast"` | Error strategy: `"fail_fast"` or `"continue"` |
-| `cache_ttl` | `float` | `None` | Cache TTL in seconds for [incremental runs](/guides/workflows/caching) |
+| `cache_ttl` | `float` | `None` | Cache TTL in seconds for [incremental runs](/python/guides/workflows/caching) |
## Node statuses
diff --git a/docs/content/docs/guides/workflows/caching.mdx b/docs/content/docs/python/guides/workflows/caching.mdx
similarity index 100%
rename from docs/content/docs/guides/workflows/caching.mdx
rename to docs/content/docs/python/guides/workflows/caching.mdx
diff --git a/docs/content/docs/guides/workflows/canvas.mdx b/docs/content/docs/python/guides/workflows/canvas.mdx
similarity index 99%
rename from docs/content/docs/guides/workflows/canvas.mdx
rename to docs/content/docs/python/guides/workflows/canvas.mdx
index 5f84b17a..05e45947 100644
--- a/docs/content/docs/guides/workflows/canvas.mdx
+++ b/docs/content/docs/python/guides/workflows/canvas.mdx
@@ -101,7 +101,7 @@ succeeded — no workflow engine required.
Canvas compensation is in-thread: compensators are enqueued synchronously
during the `apply()` call that raised. For DAG-level sagas with full
observability and sub-workflow propagation, see the
- [Sagas guide](/guides/workflows/sagas).
+ [Sagas guide](/python/guides/workflows/sagas).
### chain compensation
diff --git a/docs/content/docs/guides/workflows/composition.mdx b/docs/content/docs/python/guides/workflows/composition.mdx
similarity index 100%
rename from docs/content/docs/guides/workflows/composition.mdx
rename to docs/content/docs/python/guides/workflows/composition.mdx
diff --git a/docs/content/docs/guides/workflows/conditions.mdx b/docs/content/docs/python/guides/workflows/conditions.mdx
similarity index 100%
rename from docs/content/docs/guides/workflows/conditions.mdx
rename to docs/content/docs/python/guides/workflows/conditions.mdx
diff --git a/docs/content/docs/guides/workflows/fan-out.mdx b/docs/content/docs/python/guides/workflows/fan-out.mdx
similarity index 97%
rename from docs/content/docs/guides/workflows/fan-out.mdx
rename to docs/content/docs/python/guides/workflows/fan-out.mdx
index 85c35ed8..dbcd9007 100644
--- a/docs/content/docs/guides/workflows/fan-out.mdx
+++ b/docs/content/docs/python/guides/workflows/fan-out.mdx
@@ -109,7 +109,7 @@ By default (`on_failure="fail_fast"`), if any fan-out child fails:
- The fan-in and downstream steps are `SKIPPED`
- The workflow transitions to `FAILED`
-Combine with [conditions](/guides/workflows/conditions) for more
+Combine with [conditions](/python/guides/workflows/conditions) for more
control:
```python
diff --git a/docs/content/docs/guides/workflows/gates.mdx b/docs/content/docs/python/guides/workflows/gates.mdx
similarity index 100%
rename from docs/content/docs/guides/workflows/gates.mdx
rename to docs/content/docs/python/guides/workflows/gates.mdx
diff --git a/docs/content/docs/guides/workflows/index.mdx b/docs/content/docs/python/guides/workflows/index.mdx
similarity index 59%
rename from docs/content/docs/guides/workflows/index.mdx
rename to docs/content/docs/python/guides/workflows/index.mdx
index 661ec38b..9332cc90 100644
--- a/docs/content/docs/guides/workflows/index.mdx
+++ b/docs/content/docs/python/guides/workflows/index.mdx
@@ -50,11 +50,11 @@ print(result.state) # WorkflowState.COMPLETED
| Page | What it covers |
|---|---|
-| [Building Workflows](/guides/workflows/building) | `Workflow.step()`, decorator pattern, step configuration, DAG structure |
-| [Fan-Out & Fan-In](/guides/workflows/fan-out) | Splitting results into parallel jobs, collecting with aggregation |
-| [Conditions & Error Handling](/guides/workflows/conditions) | `on_success`, `on_failure`, `always`, callable conditions, `on_failure` modes |
-| [Approval Gates](/guides/workflows/gates) | Human-in-the-loop pause/resume, timeout, approve/reject API |
-| [Sub-Workflows & Scheduling](/guides/workflows/composition) | Nesting workflows, cron-scheduled runs |
-| [Incremental Runs](/guides/workflows/caching) | Result hashing, `CACHE_HIT`, dirty-set propagation, TTL |
-| [Analysis & Visualization](/guides/workflows/analysis) | Critical path, bottleneck analysis, Mermaid/DOT rendering |
-| [Canvas Primitives](/guides/workflows/canvas) | Chain, group, chord — simple composition without DAGs |
+| [Building Workflows](/python/guides/workflows/building) | `Workflow.step()`, decorator pattern, step configuration, DAG structure |
+| [Fan-Out & Fan-In](/python/guides/workflows/fan-out) | Splitting results into parallel jobs, collecting with aggregation |
+| [Conditions & Error Handling](/python/guides/workflows/conditions) | `on_success`, `on_failure`, `always`, callable conditions, `on_failure` modes |
+| [Approval Gates](/python/guides/workflows/gates) | Human-in-the-loop pause/resume, timeout, approve/reject API |
+| [Sub-Workflows & Scheduling](/python/guides/workflows/composition) | Nesting workflows, cron-scheduled runs |
+| [Incremental Runs](/python/guides/workflows/caching) | Result hashing, `CACHE_HIT`, dirty-set propagation, TTL |
+| [Analysis & Visualization](/python/guides/workflows/analysis) | Critical path, bottleneck analysis, Mermaid/DOT rendering |
+| [Canvas Primitives](/python/guides/workflows/canvas) | Chain, group, chord — simple composition without DAGs |
diff --git a/docs/content/docs/guides/workflows/meta.json b/docs/content/docs/python/guides/workflows/meta.json
similarity index 100%
rename from docs/content/docs/guides/workflows/meta.json
rename to docs/content/docs/python/guides/workflows/meta.json
diff --git a/docs/content/docs/guides/workflows/sagas.mdx b/docs/content/docs/python/guides/workflows/sagas.mdx
similarity index 100%
rename from docs/content/docs/guides/workflows/sagas.mdx
rename to docs/content/docs/python/guides/workflows/sagas.mdx
diff --git a/docs/content/docs/python/meta.json b/docs/content/docs/python/meta.json
new file mode 100644
index 00000000..937521e1
--- /dev/null
+++ b/docs/content/docs/python/meta.json
@@ -0,0 +1,5 @@
+{
+ "title": "Python",
+ "root": true,
+ "pages": ["capabilities", "getting-started", "guides", "architecture", "api-reference", "more"]
+}
diff --git a/docs/content/docs/more/changelog.mdx b/docs/content/docs/python/more/changelog.mdx
similarity index 99%
rename from docs/content/docs/more/changelog.mdx
rename to docs/content/docs/python/more/changelog.mdx
index 4b198d8b..7c41b4b6 100644
--- a/docs/content/docs/more/changelog.mdx
+++ b/docs/content/docs/python/more/changelog.mdx
@@ -183,7 +183,7 @@ Security-hardening release. No breaking changes.
## 0.15.0
-See the [Upgrading to 0.15](/guides/operations/upgrading-0.15) guide for
+See the [Upgrading to 0.15](/python/guides/operations/upgrading-0.15) guide for
migration steps, rolling-upgrade notes, and the downgrade floor.
### Breaking
@@ -245,7 +245,7 @@ migration steps, rolling-upgrade notes, and the downgrade floor.
### Added
-- **Bare-metal autoscaler.** `taskito.autoscale` provides an in-process HPA-style control loop that spawns and drains `taskito worker` subprocesses based on queue depth and utilisation. Mirrors the Kubernetes HPA dual-signal formula (`depth_desired` + `util_desired`). Configurable stabilisation windows (default: scale-up immediate, scale-down 5 minutes), tolerance band (10%), overload override, and crash recovery. Use `serve_autoscaler(queue, AutoscaleConfig(...))` as the entry point. See the [Bare-Metal Autoscaler guide](/guides/operations/autoscaler).
+- **Bare-metal autoscaler.** `taskito.autoscale` provides an in-process HPA-style control loop that spawns and drains `taskito worker` subprocesses based on queue depth and utilisation. Mirrors the Kubernetes HPA dual-signal formula (`depth_desired` + `util_desired`). Configurable stabilisation windows (default: scale-up immediate, scale-down 5 minutes), tolerance band (10%), overload override, and crash recovery. Use `serve_autoscaler(queue, AutoscaleConfig(...))` as the entry point. See the [Bare-Metal Autoscaler guide](/python/guides/operations/autoscaler).
- **Dashboard `/api/workflows` backend.** Four new REST endpoints expose workflow run data: `GET /api/workflows/runs` (paginated list, filterable by definition name and state), `GET /api/workflows/runs/{id}` (run header + per-node detail with compensation fields), `GET /api/workflows/runs/{id}/dag` (DAG JSON), and `GET /api/workflows/runs/{id}/children` (sub-workflow runs). All timestamps are Unix milliseconds.
- **Canvas saga compensation.** `chain`, `group`, and `chord` support `.with_compensation([...])`. On failure, compensators for completed steps are enqueued with a deterministic `canvas_compensation:{run_id}:{slot}` idempotency key. Dispatch order: chain → reverse-sequential, group → parallel, chord → callback compensator first then group members. `Signature.with_compensation(compensator)` lets individual signatures carry their own compensator.
- **Per-item batch results.** `@queue.task(batch={"per_item_results": True})` enables per-item tracking for batched tasks. The task returns `list[BatchItemResult]`; each caller's `BatchedJobResult.result()` returns **only that caller's value**. `BatchItemResult.success(item_index, result)` and `BatchItemResult.failure(item_index, error)` are the constructors. `partial_failures()` returns failed items after a successful batch. `BatchPartialFailureError` and `BatchResultTypeError` are the new exception types. Cannot be combined with `idempotent=True`.
diff --git a/docs/content/docs/more/comparison.mdx b/docs/content/docs/python/more/comparison.mdx
similarity index 98%
rename from docs/content/docs/more/comparison.mdx
rename to docs/content/docs/python/more/comparison.mdx
index d34610dc..b07dbcf9 100644
--- a/docs/content/docs/more/comparison.mdx
+++ b/docs/content/docs/python/more/comparison.mdx
@@ -77,7 +77,7 @@ widely adopted.
**Choose taskito** if you want zero-infrastructure simplicity on a single machine.
**Choose Celery** if you need distributed workers, complex routing, or enterprise features.
-Looking to switch? See the [Migrating from Celery](/guides/operations) guide for a
+Looking to switch? See the [Migrating from Celery](/python/guides/operations) guide for a
step-by-step walkthrough with side-by-side code examples.
### vs RQ (Redis Queue)
diff --git a/docs/content/docs/more/examples/batch-emails.mdx b/docs/content/docs/python/more/examples/batch-emails.mdx
similarity index 100%
rename from docs/content/docs/more/examples/batch-emails.mdx
rename to docs/content/docs/python/more/examples/batch-emails.mdx
diff --git a/docs/content/docs/more/examples/benchmark.mdx b/docs/content/docs/python/more/examples/benchmark.mdx
similarity index 100%
rename from docs/content/docs/more/examples/benchmark.mdx
rename to docs/content/docs/python/more/examples/benchmark.mdx
diff --git a/docs/content/docs/more/examples/data-pipeline.mdx b/docs/content/docs/python/more/examples/data-pipeline.mdx
similarity index 100%
rename from docs/content/docs/more/examples/data-pipeline.mdx
rename to docs/content/docs/python/more/examples/data-pipeline.mdx
diff --git a/docs/content/docs/more/examples/fastapi-service.mdx b/docs/content/docs/python/more/examples/fastapi-service.mdx
similarity index 100%
rename from docs/content/docs/more/examples/fastapi-service.mdx
rename to docs/content/docs/python/more/examples/fastapi-service.mdx
diff --git a/docs/content/docs/python/more/examples/index.mdx b/docs/content/docs/python/more/examples/index.mdx
new file mode 100644
index 00000000..6d1f43e6
--- /dev/null
+++ b/docs/content/docs/python/more/examples/index.mdx
@@ -0,0 +1,16 @@
+---
+title: Examples
+description: "End-to-end examples demonstrating common taskito patterns."
+---
+
+End-to-end examples demonstrating common taskito patterns.
+
+| Example | Description |
+|---------|-------------|
+| [FastAPI Service](/python/more/examples/fastapi-service) | REST API that enqueues tasks and streams progress via SSE |
+| [Notification Service](/python/more/examples/notifications) | Multi-channel notifications with retries and rate limiting |
+| [Web Scraper Pipeline](/python/more/examples/web-scraper) | Distributed scraping with chains and error handling |
+| [Data Pipeline](/python/more/examples/data-pipeline) | ETL pipeline with dependencies, groups, and chords |
+| [DAG Workflows](/python/more/examples/workflows) | Fan-out, conditions, gates, sub-workflows, incremental runs |
+| [Predicate-Gated Jobs](/python/more/examples/predicate-gated-jobs) | Business-hours windows, load-shedding, feature flags, per-tenant quotas |
+| [Benchmark](/python/more/examples/benchmark) | Performance benchmarks comparing taskito to alternatives |
diff --git a/docs/content/docs/more/examples/meta.json b/docs/content/docs/python/more/examples/meta.json
similarity index 100%
rename from docs/content/docs/more/examples/meta.json
rename to docs/content/docs/python/more/examples/meta.json
diff --git a/docs/content/docs/more/examples/notifications.mdx b/docs/content/docs/python/more/examples/notifications.mdx
similarity index 100%
rename from docs/content/docs/more/examples/notifications.mdx
rename to docs/content/docs/python/more/examples/notifications.mdx
diff --git a/docs/content/docs/more/examples/predicate-gated-jobs.mdx b/docs/content/docs/python/more/examples/predicate-gated-jobs.mdx
similarity index 100%
rename from docs/content/docs/more/examples/predicate-gated-jobs.mdx
rename to docs/content/docs/python/more/examples/predicate-gated-jobs.mdx
diff --git a/docs/content/docs/more/examples/saga-checkout.mdx b/docs/content/docs/python/more/examples/saga-checkout.mdx
similarity index 100%
rename from docs/content/docs/more/examples/saga-checkout.mdx
rename to docs/content/docs/python/more/examples/saga-checkout.mdx
diff --git a/docs/content/docs/more/examples/web-scraper.mdx b/docs/content/docs/python/more/examples/web-scraper.mdx
similarity index 100%
rename from docs/content/docs/more/examples/web-scraper.mdx
rename to docs/content/docs/python/more/examples/web-scraper.mdx
diff --git a/docs/content/docs/more/examples/workflows.mdx b/docs/content/docs/python/more/examples/workflows.mdx
similarity index 100%
rename from docs/content/docs/more/examples/workflows.mdx
rename to docs/content/docs/python/more/examples/workflows.mdx
diff --git a/docs/content/docs/more/faq.mdx b/docs/content/docs/python/more/faq.mdx
similarity index 90%
rename from docs/content/docs/more/faq.mdx
rename to docs/content/docs/python/more/faq.mdx
index 7a30b15f..7299d38b 100644
--- a/docs/content/docs/more/faq.mdx
+++ b/docs/content/docs/python/more/faq.mdx
@@ -96,7 +96,7 @@ Use the **Postgres backend** (`pip install taskito[postgres]`) when you need:
- **Existing Postgres infrastructure** — leverage your existing database and backups
For single-machine workloads, SQLite is simpler and requires zero setup. See
-the [Postgres backend guide](/guides/operations).
+the [Postgres backend guide](/python/guides/operations).
## Is taskito production-ready?
@@ -104,7 +104,7 @@ taskito is suitable for production workloads — background job processing,
periodic tasks, data pipelines, and similar use cases.
For single-machine deployments, use the default SQLite backend. For
-multi-server setups, use the [Postgres backend](/guides/operations).
+multi-server setups, use the [Postgres backend](/python/guides/operations).
## What observability options does taskito support?
@@ -112,9 +112,9 @@ taskito offers three observability integrations, each suited to different needs:
| Integration | Best for | Install |
|-------------|----------|---------|
-| **[OpenTelemetry](/guides/integrations)** | Distributed tracing, correlating tasks with HTTP requests | `pip install taskito[otel]` |
-| **[Prometheus](/guides/integrations)** | Metrics dashboards, alerting on queue depth/error rates | `pip install taskito[prometheus]` |
-| **[Sentry](/guides/integrations)** | Error tracking with rich context and breadcrumbs | `pip install taskito[sentry]` |
+| **[OpenTelemetry](/python/guides/integrations)** | Distributed tracing, correlating tasks with HTTP requests | `pip install taskito[otel]` |
+| **[Prometheus](/python/guides/integrations)** | Metrics dashboards, alerting on queue depth/error rates | `pip install taskito[prometheus]` |
+| **[Sentry](/python/guides/integrations)** | Error tracking with rich context and breadcrumbs | `pip install taskito[sentry]` |
All three are implemented as `TaskMiddleware` and can be combined together.
@@ -153,7 +153,7 @@ stats = await queue.astats()
Sync and async tasks can coexist in the same queue. The worker automatically
routes each job to the correct pool based on the task type. See the
-[Async Tasks guide](/guides/advanced-execution) for details including
+[Async Tasks guide](/python/guides/advanced-execution) for details including
`async_concurrency` tuning and `current_job` context in async tasks.
## What serialization format does taskito use?
diff --git a/docs/content/docs/more/meta.json b/docs/content/docs/python/more/meta.json
similarity index 100%
rename from docs/content/docs/more/meta.json
rename to docs/content/docs/python/more/meta.json
From 3bf7ea518efd496650c63a6b385b1347b19f6c9e Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:17 +0530
Subject: [PATCH 39/48] feat(docs): add TypeScript snippet + quickstart link to
hero
---
docs/app/components/landing/hero.tsx | 10 ++++++---
docs/app/lib/landing-content.ts | 33 +++++++++++++++++++++++++++-
2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/docs/app/components/landing/hero.tsx b/docs/app/components/landing/hero.tsx
index 4791eb7a..f3d16244 100644
--- a/docs/app/components/landing/hero.tsx
+++ b/docs/app/components/landing/hero.tsx
@@ -1,10 +1,10 @@
import { useState } from "react";
import { Link } from "react-router";
import { RawHtml } from "@/components/ui";
-import { highlightPython } from "@/lib/highlight-lite";
+import { highlightPython, highlightTs } from "@/lib/highlight-lite";
import { HERO_PANES, SOON_PANES, type SoonLang } from "@/lib/landing-content";
-type Lang = "py" | "go" | "java";
+type Lang = "py" | "ts" | "go" | "java";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
@@ -37,7 +37,11 @@ function SoonBox({ pane }: { pane: SoonLang }) {
export function Hero() {
const [lang, setLang] = useState("py");
const pane = HERO_PANES.find((p) => p.id === lang);
- const codeHtml = pane ? highlightPython(pane.code) : "";
+ const codeHtml = pane
+ ? lang === "ts"
+ ? highlightTs(pane.code)
+ : highlightPython(pane.code)
+ : "";
const active = pane ?? HERO_PANES[0];
return (
diff --git a/docs/app/lib/landing-content.ts b/docs/app/lib/landing-content.ts
index cde6b80d..d5a15e99 100644
--- a/docs/app/lib/landing-content.ts
+++ b/docs/app/lib/landing-content.ts
@@ -10,7 +10,7 @@ export interface OutLine {
}
export interface LangPane {
- id: "py";
+ id: "py" | "ts";
label: string;
filename: string;
install: string;
@@ -54,6 +54,37 @@ print(job.result()) # → 5`,
docHref: "/python/getting-started/quickstart",
docLabel: "Read the Python quickstart",
},
+ {
+ id: "ts",
+ label: "TypeScript",
+ filename: "tasks.ts",
+ install: "pnpm add taskito",
+ code: `import { Queue } from "taskito";
+
+const queue = new Queue({ dbPath: "taskito.db" });
+
+queue.task("add", (a: number, b: number) => a + b, {
+ maxRetries: 3,
+});
+
+const id = queue.enqueue("add", [2, 3]);
+queue.runWorker();
+
+console.log(await queue.result(id)); // → 5`,
+ output: [
+ { glyph: "$", glyphKind: "p", text: "taskito run ./tasks.js" },
+ { glyph: "→", glyphKind: "p", text: "runWorker() · Rust core attached" },
+ {
+ glyph: "✓",
+ glyphKind: "g",
+ text: "add(2, 3) =",
+ value: "5",
+ timing: "9 ms",
+ },
+ ],
+ docHref: "/node/getting-started/quickstart",
+ docLabel: "Read the TypeScript quickstart",
+ },
];
/** Roadmap languages: disabled tab + "coming soon" panel (no fabricated SDK). */
From 9dd6e2f191b84c15934b29b9a8649c50fe1d82d1 Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:17 +0530
Subject: [PATCH 40/48] feat(docs): show Python + TypeScript quickstart links
in hero
---
docs/app/components/landing/hero.tsx | 14 +++++++++++---
docs/app/styles/landing.css | 8 +++++++-
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/docs/app/components/landing/hero.tsx b/docs/app/components/landing/hero.tsx
index f3d16244..192c2602 100644
--- a/docs/app/components/landing/hero.tsx
+++ b/docs/app/components/landing/hero.tsx
@@ -141,9 +141,17 @@ export function Hero() {
) : null}
-
- {active.docLabel} →
-
+
+
+ Read the Python quickstart →
+
+
+ Read the TypeScript quickstart →
+
+
);
diff --git a/docs/app/styles/landing.css b/docs/app/styles/landing.css
index ad83bccb..b7e55e07 100644
--- a/docs/app/styles/landing.css
+++ b/docs/app/styles/landing.css
@@ -130,11 +130,17 @@ main {
background: var(--indigo);
opacity: 0.75;
}
+.hero-doclinks {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-top: 14px;
+ align-self: flex-start;
+}
.hero-doclink {
display: inline-flex;
align-items: center;
gap: 7px;
- margin-top: 14px;
align-self: flex-start;
font-family: var(--mono);
font-size: 13px;
From cae7d125a52b0cd68de356ecbc5648509198f365 Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:17 +0530
Subject: [PATCH 41/48] feat(docs): global SDK store + useSdk hook with
no-flash boot
---
docs/app/app.css | 1 +
docs/app/hooks/index.ts | 1 +
docs/app/hooks/use-sdk.ts | 28 ++++++
docs/app/lib/index.ts | 2 +
docs/app/lib/sdk-store.ts | 85 +++++++++++++++++++
docs/app/root.tsx | 13 ++-
docs/app/styles/sdk.css | 21 +++++
.../architecture/failure-model.mdx | 0
.../docs/{python => }/architecture/index.mdx | 0
.../architecture/job-lifecycle.mdx | 0
.../docs/{python => }/architecture/mesh.mdx | 0
.../docs/{python => }/architecture/meta.json | 0
.../{python => }/architecture/overview.mdx | 0
.../{python => }/architecture/resources.mdx | 0
.../{python => }/architecture/scheduler.mdx | 0
.../architecture/serialization.mdx | 0
.../{python => }/architecture/storage.mdx | 0
.../{python => }/architecture/worker-pool.mdx | 0
.../{python/more => resources}/changelog.mdx | 0
.../{python/more => resources}/comparison.mdx | 0
.../docs/{python/more => resources}/faq.mdx | 0
21 files changed, 150 insertions(+), 1 deletion(-)
create mode 100644 docs/app/hooks/index.ts
create mode 100644 docs/app/hooks/use-sdk.ts
create mode 100644 docs/app/lib/index.ts
create mode 100644 docs/app/lib/sdk-store.ts
create mode 100644 docs/app/styles/sdk.css
rename docs/content/docs/{python => }/architecture/failure-model.mdx (100%)
rename docs/content/docs/{python => }/architecture/index.mdx (100%)
rename docs/content/docs/{python => }/architecture/job-lifecycle.mdx (100%)
rename docs/content/docs/{python => }/architecture/mesh.mdx (100%)
rename docs/content/docs/{python => }/architecture/meta.json (100%)
rename docs/content/docs/{python => }/architecture/overview.mdx (100%)
rename docs/content/docs/{python => }/architecture/resources.mdx (100%)
rename docs/content/docs/{python => }/architecture/scheduler.mdx (100%)
rename docs/content/docs/{python => }/architecture/serialization.mdx (100%)
rename docs/content/docs/{python => }/architecture/storage.mdx (100%)
rename docs/content/docs/{python => }/architecture/worker-pool.mdx (100%)
rename docs/content/docs/{python/more => resources}/changelog.mdx (100%)
rename docs/content/docs/{python/more => resources}/comparison.mdx (100%)
rename docs/content/docs/{python/more => resources}/faq.mdx (100%)
diff --git a/docs/app/app.css b/docs/app/app.css
index 766ccd5a..c066aaee 100644
--- a/docs/app/app.css
+++ b/docs/app/app.css
@@ -9,3 +9,4 @@
@import "./styles/diagrams.css";
@import "./styles/landing.css";
@import "./styles/shiki.css";
+@import "./styles/sdk.css";
diff --git a/docs/app/hooks/index.ts b/docs/app/hooks/index.ts
new file mode 100644
index 00000000..73471711
--- /dev/null
+++ b/docs/app/hooks/index.ts
@@ -0,0 +1 @@
+export { type Sdk, useActiveSdk, useSdk } from "./use-sdk";
diff --git a/docs/app/hooks/use-sdk.ts b/docs/app/hooks/use-sdk.ts
new file mode 100644
index 00000000..2b9b9315
--- /dev/null
+++ b/docs/app/hooks/use-sdk.ts
@@ -0,0 +1,28 @@
+import { useSyncExternalStore } from "react";
+import { useLocation } from "react-router";
+import { forcedSdkForPath, type Sdk, sdkStore } from "@/lib";
+
+export type { Sdk };
+
+/** Reactive active SDK + setter, backed by the SSG-safe external store. The
+ * server snapshot is the default SDK, so prerendered HTML and the first client
+ * render agree; the boot script has already applied the real value to
+ * `` before paint. */
+export function useSdk(): { sdk: Sdk; setSdk: (sdk: Sdk) => void } {
+ const sdk = useSyncExternalStore(
+ sdkStore.subscribe,
+ sdkStore.getSnapshot,
+ sdkStore.getServerSnapshot,
+ );
+ return { sdk, setSdk: sdkStore.set };
+}
+
+/** The SDK to render for the current page: forced by the URL prefix on
+ * SDK-specific pages, otherwise the global store value (shared pages). Avoids a
+ * first-paint nav flash when a `/node/*` URL loads while the store still holds
+ * the default. */
+export function useActiveSdk(): Sdk {
+ const { sdk } = useSdk();
+ const { pathname } = useLocation();
+ return forcedSdkForPath(pathname.replace(/\/$/, "") || "/") ?? sdk;
+}
diff --git a/docs/app/lib/index.ts b/docs/app/lib/index.ts
new file mode 100644
index 00000000..6f6530c7
--- /dev/null
+++ b/docs/app/lib/index.ts
@@ -0,0 +1,2 @@
+export * from "./nav";
+export * from "./sdk-store";
diff --git a/docs/app/lib/sdk-store.ts b/docs/app/lib/sdk-store.ts
new file mode 100644
index 00000000..54a4d7f7
--- /dev/null
+++ b/docs/app/lib/sdk-store.ts
@@ -0,0 +1,85 @@
+// Global active-SDK store. Single source of truth shared by the no-flash boot
+// script (root.tsx), the sidebar switcher, inline ``, and ``.
+// Kept as a tiny external store so `useSyncExternalStore` can hand React an
+// explicit server snapshot — the SSG-safe way to read a browser-only value
+// without a hydration mismatch. The live value lives on ``; CSS
+// shows/hides each SDK's variants off that attribute.
+
+export type Sdk = "python" | "node";
+
+const KEY = "taskito-sdk";
+const DEFAULT: Sdk = "python";
+
+const listeners = new Set<() => void>();
+
+function isSdk(value: string | null | undefined): value is Sdk {
+ return value === "python" || value === "node";
+}
+
+/** Resolve the active SDK: `?sdk=` query > localStorage > default. Used by the
+ * no-flash bootstrap in root.tsx and as the first client read. */
+export function readSdk(): Sdk {
+ if (typeof document === "undefined") {
+ return DEFAULT;
+ }
+ try {
+ const param = new URLSearchParams(window.location.search).get("sdk");
+ if (isSdk(param)) {
+ return param;
+ }
+ const stored = localStorage.getItem(KEY);
+ if (isSdk(stored)) {
+ return stored;
+ }
+ } catch {
+ // ignore storage/URL access failures (private mode etc.)
+ }
+ return DEFAULT;
+}
+
+function currentSdk(): Sdk {
+ const attr = document.documentElement.dataset.sdk;
+ return isSdk(attr) ? attr : DEFAULT;
+}
+
+function notify(): void {
+ for (const listener of listeners) {
+ listener();
+ }
+}
+
+// Another tab changed the choice — mirror it onto this document, then notify.
+function onStorage(event: StorageEvent): void {
+ if (event.key !== KEY || !isSdk(event.newValue)) {
+ return;
+ }
+ document.documentElement.dataset.sdk = event.newValue;
+ notify();
+}
+
+export const sdkStore = {
+ subscribe(callback: () => void): () => void {
+ if (listeners.size === 0) {
+ window.addEventListener("storage", onStorage);
+ }
+ listeners.add(callback);
+ return () => {
+ listeners.delete(callback);
+ if (listeners.size === 0) {
+ window.removeEventListener("storage", onStorage);
+ }
+ };
+ },
+ getSnapshot: currentSdk,
+ getServerSnapshot: (): Sdk => DEFAULT,
+ /** Set + persist the active SDK; drives the CSS show/hide via ``. */
+ set(sdk: Sdk): void {
+ document.documentElement.dataset.sdk = sdk;
+ try {
+ localStorage.setItem(KEY, sdk);
+ } catch {
+ // ignore storage failures (private mode etc.)
+ }
+ notify();
+ },
+};
diff --git a/docs/app/root.tsx b/docs/app/root.tsx
index c2b0ba90..eaa60842 100644
--- a/docs/app/root.tsx
+++ b/docs/app/root.tsx
@@ -25,14 +25,25 @@ export const links: Route.LinksFunction = () => [
// Apply the persisted theme before paint to avoid a light/dark flash.
const THEME_INIT = `(function(){try{var t=localStorage.getItem('taskito-theme')||'dark';document.documentElement.setAttribute('data-theme',t);}catch(e){}})();`;
+// Apply the active SDK before paint (query > localStorage > default) so the
+// CSS show/hide picks the right variant with no flash. Mirrors readSdk().
+const SDK_INIT = `(function(){try{var u=new URLSearchParams(location.search).get('sdk');var s=(u==='python'||u==='node')?u:(localStorage.getItem('taskito-sdk')||'python');if(s!=='python'&&s!=='node'){s='python';}document.documentElement.setAttribute('data-sdk',s);}catch(e){document.documentElement.setAttribute('data-sdk','python');}})();`;
+
export function Layout({ children }: { children: React.ReactNode }) {
return (
-
+
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: tiny no-flash theme bootstrap */}
+ {/* biome-ignore lint/security/noDangerouslySetInnerHtml: tiny no-flash sdk bootstrap */}
+
diff --git a/docs/app/styles/sdk.css b/docs/app/styles/sdk.css
new file mode 100644
index 00000000..c06088b4
--- /dev/null
+++ b/docs/app/styles/sdk.css
@@ -0,0 +1,21 @@
+/* SDK-variant show/hide, driven by `` (set before paint by the
+ bootstrap in root.tsx). Every SDK's variant ships in the static HTML; only the
+ active SDK's blocks are visible — no flash, no hydration mismatch, all variants
+ stay indexable. Components mark variants with `data-sdk-variant="python|node"`. */
+
+[data-sdk="python"] [data-sdk-variant="node"],
+[data-sdk="node"] [data-sdk-variant="python"] {
+ display: none;
+}
+
+/* SDK code-tabs reuse the base `.tab`/`.tablist` styles. The active tab is keyed
+ off `` (not a reactive class) so the highlight never flashes
+ before hydration. Panels show/hide via the data-sdk-variant rule above. */
+.sdk-tabpanel {
+ margin-top: 14px;
+}
+[data-sdk="python"] .sdk-tab[data-sdk-variant="python"],
+[data-sdk="node"] .sdk-tab[data-sdk-variant="node"] {
+ color: var(--indigo-br);
+ border-bottom-color: var(--indigo);
+}
diff --git a/docs/content/docs/python/architecture/failure-model.mdx b/docs/content/docs/architecture/failure-model.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/failure-model.mdx
rename to docs/content/docs/architecture/failure-model.mdx
diff --git a/docs/content/docs/python/architecture/index.mdx b/docs/content/docs/architecture/index.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/index.mdx
rename to docs/content/docs/architecture/index.mdx
diff --git a/docs/content/docs/python/architecture/job-lifecycle.mdx b/docs/content/docs/architecture/job-lifecycle.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/job-lifecycle.mdx
rename to docs/content/docs/architecture/job-lifecycle.mdx
diff --git a/docs/content/docs/python/architecture/mesh.mdx b/docs/content/docs/architecture/mesh.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/mesh.mdx
rename to docs/content/docs/architecture/mesh.mdx
diff --git a/docs/content/docs/python/architecture/meta.json b/docs/content/docs/architecture/meta.json
similarity index 100%
rename from docs/content/docs/python/architecture/meta.json
rename to docs/content/docs/architecture/meta.json
diff --git a/docs/content/docs/python/architecture/overview.mdx b/docs/content/docs/architecture/overview.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/overview.mdx
rename to docs/content/docs/architecture/overview.mdx
diff --git a/docs/content/docs/python/architecture/resources.mdx b/docs/content/docs/architecture/resources.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/resources.mdx
rename to docs/content/docs/architecture/resources.mdx
diff --git a/docs/content/docs/python/architecture/scheduler.mdx b/docs/content/docs/architecture/scheduler.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/scheduler.mdx
rename to docs/content/docs/architecture/scheduler.mdx
diff --git a/docs/content/docs/python/architecture/serialization.mdx b/docs/content/docs/architecture/serialization.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/serialization.mdx
rename to docs/content/docs/architecture/serialization.mdx
diff --git a/docs/content/docs/python/architecture/storage.mdx b/docs/content/docs/architecture/storage.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/storage.mdx
rename to docs/content/docs/architecture/storage.mdx
diff --git a/docs/content/docs/python/architecture/worker-pool.mdx b/docs/content/docs/architecture/worker-pool.mdx
similarity index 100%
rename from docs/content/docs/python/architecture/worker-pool.mdx
rename to docs/content/docs/architecture/worker-pool.mdx
diff --git a/docs/content/docs/python/more/changelog.mdx b/docs/content/docs/resources/changelog.mdx
similarity index 100%
rename from docs/content/docs/python/more/changelog.mdx
rename to docs/content/docs/resources/changelog.mdx
diff --git a/docs/content/docs/python/more/comparison.mdx b/docs/content/docs/resources/comparison.mdx
similarity index 100%
rename from docs/content/docs/python/more/comparison.mdx
rename to docs/content/docs/resources/comparison.mdx
diff --git a/docs/content/docs/python/more/faq.mdx b/docs/content/docs/resources/faq.mdx
similarity index 100%
rename from docs/content/docs/python/more/faq.mdx
rename to docs/content/docs/resources/faq.mdx
From 3aa8df34e0ec3d1e3bc6233dc13c603dd5d41c46 Mon Sep 17 00:00:00 2001
From: Pratyush Sharma <56130065+pratyush618@users.noreply.github.com>
Date: Sun, 21 Jun 2026 11:19:17 +0530
Subject: [PATCH 42/48] feat(docs): SDK-aware MDX components (CodeTabs,
SdkOnly, SdkLink)
---
docs/app/components/mdx/index.tsx | 4 ++
docs/app/components/mdx/sdk.tsx | 109 ++++++++++++++++++++++++++++++
docs/app/components/mdx/tabs.tsx | 11 ++-
3 files changed, 122 insertions(+), 2 deletions(-)
create mode 100644 docs/app/components/mdx/sdk.tsx
diff --git a/docs/app/components/mdx/index.tsx b/docs/app/components/mdx/index.tsx
index a5f6de74..4f859a3f 100644
--- a/docs/app/components/mdx/index.tsx
+++ b/docs/app/components/mdx/index.tsx
@@ -5,6 +5,7 @@ import * as Diagrams from "@/components/diagrams";
import { Callout } from "./callout";
import { Card, Cards } from "./card";
import { CodeBlock } from "./code-block";
+import { CodeTabs, SdkLink, SdkOnly } from "./sdk";
import { MdxTable } from "./table";
import { Tab, Tabs } from "./tabs";
@@ -39,6 +40,9 @@ export const mdxComponents: MDXComponents = {
Callout,
Tabs,
Tab,
+ CodeTabs,
+ SdkOnly,
+ SdkLink,
Card,
Cards,
...Diagrams,
diff --git a/docs/app/components/mdx/sdk.tsx b/docs/app/components/mdx/sdk.tsx
new file mode 100644
index 00000000..5caa923e
--- /dev/null
+++ b/docs/app/components/mdx/sdk.tsx
@@ -0,0 +1,109 @@
+import {
+ Children,
+ type ComponentProps,
+ isValidElement,
+ type ReactElement,
+ type ReactNode,
+ useId,
+ useRef,
+} from "react";
+import { Link } from "react-router";
+import { type Sdk, useSdk } from "@/hooks";
+
+const LABELS: Record = { python: "Python", node: "Node.js" };
+
+/** Show children only under one SDK. All variants ship in the HTML; the inactive
+ * one is hidden by CSS off `` — no flash, no hydration mismatch. */
+export function SdkOnly({ sdk, children }: { sdk: Sdk; children: ReactNode }) {
+ return
{children}
;
+}
+
+/** Internal link from a shared page into an SDK-specific tree. `to="guides/x"`
+ * resolves to `/{activeSdk}/guides/x` and re-points when the SDK switches. */
+export function SdkLink({
+ to,
+ children,
+ ...rest
+}: { to: string; children: ReactNode } & Omit<
+ ComponentProps,
+ "to" | "children"
+>) {
+ const { sdk } = useSdk();
+ const path = to.startsWith("/") ? to : `/${to}`;
+ return (
+
+ {children}
+
+ );
+}
+
+type TabChild = ReactElement<{ sdk: Sdk; children: ReactNode }>;
+
+/** Synced code/prose tabs: one panel per ``. Selecting a tab sets
+ * the global SDK, so every CodeTabs on the page and the sidebar switch together.
+ * Visibility is CSS-driven (data-sdk-variant); the tablist is APG-compliant. */
+export function CodeTabs({ children }: { children: ReactNode }) {
+ const { sdk, setSdk } = useSdk();
+ const baseId = useId();
+ const panels = Children.toArray(children).filter(
+ isValidElement,
+ ) as TabChild[];
+ const order = panels.map((p) => p.props.sdk);
+ const tabs = useRef<(HTMLButtonElement | null)[]>([]);
+ const tabId = (variant: Sdk) => `${baseId}-tab-${variant}`;
+ const panelId = (variant: Sdk) => `${baseId}-panel-${variant}`;
+
+ function onKeyDown(event: React.KeyboardEvent, index: number) {
+ const delta =
+ event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
+ if (delta === 0) {
+ return;
+ }
+ event.preventDefault();
+ const next = (index + delta + order.length) % order.length;
+ setSdk(order[next]);
+ tabs.current[next]?.focus();
+ }
+
+ return (
+