📝 SELF-UPDATING DOCUMENT: Verify against the actual codebase and update this file when it drifts.
Overview
The SDK reference sections under frontend/docs/content/docs/reference/{python,typescript,go,ruby} are generated from SDK source — doc comments and docstrings are the source of truth. Never hand-edit generated .mdx; the next regeneration overwrites it. To change reference content, edit the doc comment/docstring in the SDK and regenerate.
Commands
task generate-sdk-docs # all four languages (also part of `task generate`)
task generate-sdk-docs-python # sdks/python/docs/generate.sh
task generate-sdk-docs-typescript # sdks/typescript/docs/generate.sh
task generate-sdk-docs-go # (cd sdks/go && go run ./docs/generator)
task generate-sdk-docs-ruby # sdks/ruby/docs/generate.sh
All four pipelines are fully deterministic; no AI/LLM is involved anywhere and no API keys are needed.
CI: .github/workflows/gen-sdk-docs.yml runs on pushes to main touching sdks/** or pkg/worker/** (the Go generator also reads pkg/worker for the Context interfaces). It detects which SDKs changed, regenerates only those, opens a PR labeled autogenerated-sdk-docs, and requests auto-squash-merge. workflow_dispatch only runs from main. Optional SDK_DOCS_PR_TOKEN secret (PAT/App token) makes generated PRs trigger normal CI.
Per-language pipelines
| Language |
Pipeline |
Notes |
| Python |
mkdocs (mkdocstrings, markdown-export plugin) → deterministic converter → mdx |
Feature-client md stubs are auto-created from Hatchet client introspection. Doc prose lives in docstrings; the converter is verbatim-faithful. |
| TypeScript |
typedoc (custom theme docs/markdown-theme.mjs) → docs/generate.ts |
entryPoints derived by globbing src/v1/client/features/*.ts — new feature clients need zero config. |
| Go |
sdks/go/docs/generator (stdlib go/doc) |
Feature clients auto-discovered from Client methods returning *features.X. Also parses pkg/worker. |
| Ruby |
sdks/ruby/docs/generate.rb (YARD registry + RBS sigs) |
Static parse — no SDK gem install needed. New public methods on core classes auto-append. |
Ownership rules
- Generators own: every
.mdx in their section + feature-clients/meta.json.
- Section
meta.json (e.g. python/meta.json) is merged, not overwritten: existing order and separator strings (e.g. ---Python Specifics---) are preserved; new pages auto-append; dead entries are removed.
- Hand-authored pages exist only in Python (asyncio, pydantic, lifespans, dependency-injection, dataclasses) — generators never touch them.
reference/meta.json (top-level) is hand-maintained. Nothing generates it. So is reference/index.mdx.
- Generators hard-fail if an emitted page is unreachable from a meta.json.
- Each generator also emits
<lang>/index.mdx (the section overview) from the shared hand-maintained mapping frontend/docs/reference-map.json, which pairs each canonical feature-client concept with per-language page slugs and its user-guide page. Generators hard-fail on an emitted feature-client page with no mapping entry, a mapping slug matching no emitted page, or a guide path that does not exist. Adding a feature client to any SDK therefore requires adding (or extending) its reference-map.json entry.
Gotchas (learned the hard way)
- fumadocs dropdown: a
root: true folder only appears in the section dropdown if it has an index page or a direct page child. The Reference folder now has a hand-maintained index.mdx, and app/(docs)/layout.tsx still adds a fallback tab bound with $folder (for active-state detection), deduped by URL, pointing at /reference. The per-language sections also have generated index pages, so /reference/<lang> serves an overview rather than redirecting to the client page.
- Never put
{/* */} JSX comments in this repo's MDX — the prettier pass rewrites * to _ inside them, producing invalid MDX that 500s the whole docs site.
- Determinism is a requirement: every generator must produce byte-identical output across runs (sorted iteration everywhere), or CI churns endless PRs. Verify with a double run + checksum diff. Output must not depend on optional tooling: the Go generator hard-fails if frontend/docs prettier is missing (a silent skip once shipped unformatted pages via CI while local runs looked clean).
- golangci-lint: repo uses v2 config;
os.WriteFile in generators must use 0o600.
- Don't edit
frontend/docs/pages/** — that's the dead pre-fumadocs tree.
- No em dashes in docs content (
.cursor/rules/docs-writing-style.mdc): use commas, parentheses, or separate sentences. Generated pages inherit them from SDK doc comments, so fix them at the source.
Adding a new SDK language
- Build a generator under
sdks/<lang>/docs/ with a generate.sh entry point (or go run ./docs/generator style) that emits the standard layout: client.mdx, context.mdx, runnables.mdx, feature-clients/*.mdx + feature-clients/meta.json, into frontend/docs/content/docs/reference/<lang>/. Use content/docs/reference/python/ as the style template. Auto-discover feature clients from source; no hand-lists.
- Hand-write the initial
<lang>/meta.json (client, context, feature-clients, runnables); the generator merges it afterward.
- Add a
generate-sdk-docs-<lang> task to the root Taskfile and wire it into generate-sdk-docs.
- Add the language to
.github/workflows/gen-sdk-docs.yml: the for lang in ... loop in the detect step, a toolchain setup step if needed, and a conditional generate step.
- Add
"<lang>" to frontend/docs/content/docs/reference/meta.json.
1---2name: sdk-reference-docs3description: How the SDK reference docs pipeline works — regenerating references for the Python/TypeScript/Go/Ruby SDKs, adding a new SDK language, and known gotchas. Use when working on docs generation, sdks/*/docs generators, or content/docs/reference.4---56**📝 SELF-UPDATING DOCUMENT**: Verify against the actual codebase and update this file when it drifts.78## Overview910The SDK reference sections under `frontend/docs/content/docs/reference/{python,typescript,go,ruby}` are **generated from SDK source** — doc comments and docstrings are the source of truth. Never hand-edit generated `.mdx`; the next regeneration overwrites it. To change reference content, edit the doc comment/docstring in the SDK and regenerate.1112## Commands1314```bash15task generate-sdk-docs # all four languages (also part of `task generate`)16task generate-sdk-docs-python # sdks/python/docs/generate.sh17task generate-sdk-docs-typescript # sdks/typescript/docs/generate.sh18task generate-sdk-docs-go # (cd sdks/go && go run ./docs/generator)19task generate-sdk-docs-ruby # sdks/ruby/docs/generate.sh20```2122All four pipelines are fully deterministic; no AI/LLM is involved anywhere and no API keys are needed.2324CI: `.github/workflows/gen-sdk-docs.yml` runs on pushes to main touching `sdks/**` or `pkg/worker/**` (the Go generator also reads `pkg/worker` for the Context interfaces). It detects which SDKs changed, regenerates only those, opens a PR labeled `autogenerated-sdk-docs`, and requests auto-squash-merge. `workflow_dispatch` only runs from main. Optional `SDK_DOCS_PR_TOKEN` secret (PAT/App token) makes generated PRs trigger normal CI.2526## Per-language pipelines2728| Language | Pipeline | Notes |29|------------|----------|-------|30| Python | mkdocs (mkdocstrings, `markdown-export` plugin) → deterministic converter → mdx | Feature-client md stubs are auto-created from `Hatchet` client introspection. Doc prose lives in docstrings; the converter is verbatim-faithful. |31| TypeScript | typedoc (custom theme `docs/markdown-theme.mjs`) → `docs/generate.ts` | entryPoints derived by globbing `src/v1/client/features/*.ts` — new feature clients need zero config. |32| Go | `sdks/go/docs/generator` (stdlib `go/doc`) | Feature clients auto-discovered from `Client` methods returning `*features.X`. Also parses `pkg/worker`. |33| Ruby | `sdks/ruby/docs/generate.rb` (YARD registry + RBS sigs) | Static parse — no SDK gem install needed. New public methods on core classes auto-append. |3435## Ownership rules3637- Generators own: every `.mdx` in their section + `feature-clients/meta.json`.38- Section `meta.json` (e.g. `python/meta.json`) is **merged**, not overwritten: existing order and separator strings (e.g. `---Python Specifics---`) are preserved; new pages auto-append; dead entries are removed.39- Hand-authored pages exist only in Python (asyncio, pydantic, lifespans, dependency-injection, dataclasses) — generators never touch them.40- `reference/meta.json` (top-level) is hand-maintained. Nothing generates it. So is `reference/index.mdx`.41- Generators hard-fail if an emitted page is unreachable from a meta.json.42- Each generator also emits `<lang>/index.mdx` (the section overview) from the shared hand-maintained mapping `frontend/docs/reference-map.json`, which pairs each canonical feature-client concept with per-language page slugs and its user-guide page. Generators hard-fail on an emitted feature-client page with no mapping entry, a mapping slug matching no emitted page, or a guide path that does not exist. Adding a feature client to any SDK therefore requires adding (or extending) its `reference-map.json` entry.4344## Gotchas (learned the hard way)45461. **fumadocs dropdown**: a `root: true` folder only appears in the section dropdown if it has an index page or a direct page child. The Reference folder now has a hand-maintained `index.mdx`, and `app/(docs)/layout.tsx` still adds a fallback tab bound with `$folder` (for active-state detection), deduped by URL, pointing at `/reference`. The per-language sections also have generated index pages, so `/reference/<lang>` serves an overview rather than redirecting to the client page.472. **Never put `{/* */}` JSX comments in this repo's MDX** — the prettier pass rewrites `*` to `_` inside them, producing invalid MDX that 500s the whole docs site.483. **Determinism is a requirement**: every generator must produce byte-identical output across runs (sorted iteration everywhere), or CI churns endless PRs. Verify with a double run + checksum diff. Output must not depend on optional tooling: the Go generator hard-fails if frontend/docs prettier is missing (a silent skip once shipped unformatted pages via CI while local runs looked clean).494. **golangci-lint**: repo uses v2 config; `os.WriteFile` in generators must use `0o600`.505. Don't edit `frontend/docs/pages/**` — that's the dead pre-fumadocs tree.516. **No em dashes in docs content** (`.cursor/rules/docs-writing-style.mdc`): use commas, parentheses, or separate sentences. Generated pages inherit them from SDK doc comments, so fix them at the source.5253## Adding a new SDK language54551. Build a generator under `sdks/<lang>/docs/` with a `generate.sh` entry point (or `go run ./docs/generator` style) that emits the standard layout: `client.mdx`, `context.mdx`, `runnables.mdx`, `feature-clients/*.mdx` + `feature-clients/meta.json`, into `frontend/docs/content/docs/reference/<lang>/`. Use `content/docs/reference/python/` as the style template. Auto-discover feature clients from source; no hand-lists.562. Hand-write the initial `<lang>/meta.json` (`client`, `context`, `feature-clients`, `runnables`); the generator merges it afterward.573. Add a `generate-sdk-docs-<lang>` task to the root Taskfile and wire it into `generate-sdk-docs`.584. Add the language to `.github/workflows/gen-sdk-docs.yml`: the `for lang in ...` loop in the detect step, a toolchain setup step if needed, and a conditional generate step.595. Add `"<lang>"` to `frontend/docs/content/docs/reference/meta.json`.