Developer Documentation
DraftCapsule publishes one docs site. This doc owns how each developer surface becomes a page on it: which artifact describes the surface, which gate keeps that artifact current, and where the page lands. Which surfaces exist is API Surfaces; the layering rules server code obeys are API Practices.
Implemented in capsule-docs/ (Astro + Starlight); pages are generated from committed artifacts by
capsule-docs/scripts/gen-reference.mjs. A stale reference page is worse than a missing one — it is
confidently wrong — so no reference page is maintained by hand.
The CI docs job installs bun only (no Rust, uniffi, or wasm-bindgen) and runs when its path
filter matches. That forces the boundary:
- Artifacts cross the boundary, not toolchains. Each surface’s owning gate emits a small,
committed, machine-readable description artifact. The docs build reads committed artifacts
and never invokes cargo, uniffi, or wasm-bindgen. The CI
docspath filter MUST list every artifact the docs build reads, not justcapsule-docs/**. Large output (rendered rustdoc) is built by the Rust gate and deployed beside the site, never committed. - Reference pages are generated, never written. Under
/reference/, hand-written prose is one overview page per section. Everything else is emitted into gitignored build output; a wrong page is fixed in the source annotation (doc comment, clapabout, schema description), then regenerated. - Freshness is a gate. Every artifact has a
--checkmode that fails on drift, run in the owning toolchain’s gate, never the docs gate. - One chrome. Prefer a generator that emits Starlight pages over a renderer that mounts its own
app (an embedded OpenAPI SPA escapes search, the link validator, and the theme). The
Referencesidebar group is hand-curated inastro.config.mjs; generated pages never determine navigation order.
Surfaces
Section titled “Surfaces”| Surface | Artifact | Emitted by | Drift gate | Page | Status |
|---|---|---|---|---|---|
| REST | Kynos OpenAPI 3.2 document | gen_openapi | openapi-check-kynos | /reference/api/ | Implemented |
| CLI | command-tree JSON | gen_cli_surface | cli-surface-check | /reference/cli/ | Implemented |
| Rust SDK | rustdoc HTML (uncommitted) | cargo doc --workspace (doc-check-rust) | broken intra-doc links denied | /reference/sdk/rust/ → /reference/crates/ | Implemented; not yet hosted |
| Swift / Kotlin bindings | capsule-sdk/bindings-surface.json | xtask bindings-surface, run by mise-tasks/gen-bindings | gen-bindings --check (Rust gate) | /reference/sdk/swift/, /reference/sdk/kotlin/ | Implemented |
| Browser | capsule-wasm/wasm-surface.d.ts | mise run wasm-surface, after build-wasm | wasm-surface-check (web gate) | /reference/sdk/wasm/ | Implemented |
The binding outputs are gitignored, so each has a small committed dump beside its generation step. The binding dump’s format is this repository’s, not uniffi’s: uniffi offers no stable machine-readable description of a namespace, so the dump records the declarations the native clients consume as the generated sources spell them, and fails when one is missing. The browser digest is the caller-facing half of the declaration file wasm-bindgen emits, kept verbatim. Its check runs in the web gate because only the web job installs wasm-bindgen.
Rustdoc is the one exception to one chrome: the workspace is publish = false (no docs.rs) and
rustdoc emits a whole site, so it is linked out from /reference/crates/. /reference/sdk/rust/
stays a Starlight page (narrative, auth model, worked example) linking into rustdoc for item detail.
Not reference surfaces: the retired capsule.sync.v1 proto
(API Surfaces); capsule_sdk::rest (generated
internals — REST is documented once, as the OpenAPI page); legacy-review/.
Information Architecture
Section titled “Information Architecture”/reference/ index one card per surface: artifact, generator, drift gate api/ REST, from the Kynos OpenAPI document cli/ capsule(1) sdk/ rust/ capsule-sdk narrative; links into crates/ swift/ uniffi namespaces kotlin/ uniffi namespaces wasm/ capsule-wasm browser surface crates/ workspace rustdoc (linked out)No Playground
Section titled “No Playground”The server is key-free: writes are sealed client-side and the sync feed returns opaque envelopes, so an HTTP try-it panel would teach that the API accepts plaintext. Executable examples live where sealing happens: SDK doctests and CLI transcripts.
Deferred
Section titled “Deferred”- Per-endpoint lifecycle metadata (stability, permission, changelog) as spec vendor extensions.
- Docs versioning (
starlight-versionsis installed, commented out) until the REST contract stabilizes. - Reference internationalization (Internationalization).
- Deploy automation (publishing is a manual
bun run deploy); required before hosting rustdoc.
Validation
Section titled “Validation”mise run check-docs formats, lints, and builds the site; the link validator fails on a dead
cross-reference. Each artifact’s --check runs in its owning toolchain gate. Adding a reference
surface means reviewing the CI docs path filter.