Skip to content

Authoring conventions

These docs are Astro Starlight MDX. This page is the style contract every page follows: which components to reach for, how to escape the characters MDX chokes on, how to mark deploy-honesty with badges, and the one rule that fails the build if you break it — env-var names only, never values.

The single best reference is a finished page. Read Add a new generation tool worker — it is the quality bar, and it uses almost everything below.

Every page is an .mdx file under src/content/docs/<slug>.mdx. Keep the frontmatter the page manifest already generated — title, description, and sidebar.order — and replace the body. Import any component you use on the line right after the frontmatter:

src/content/docs/how-to/example.mdx
---
title: "My page"
description: "One sentence, sentence case."
sidebar:
order: 3
---
Lead with the point. …

Import only what you use — an unused import is harmless, but a used-but-unimported component is a hard build error.

Callouts are how you surface the gotchas this fleet is full of. Prefer the directive form — it needs no import and reads cleanly in the source. The component form exists for when you need to nest block content or set attributes dynamically; the two render identically.

:::caution[Restart core-mcp after a schema change]
core-mcp caches tool schemas in memory. Redeploying the worker updates the DB row,
but the changed schema is not picked up until core-mcp restarts.
:::

The title in brackets — :::caution[Custom title] — is optional; omit it for the default label. Pick the type by severity:

Directive Component type Use it for
:::note note neutral context the reader needs
:::tip tip a shortcut or a recommended path
:::caution caution a gotcha that will bite (this fleet has many)
:::danger danger data loss, security, or money

Wrap any ordered, do-this-then-that recipe in <Steps> around a numbered list. It renders the connected-number rail you see in the how-to guides.

<Steps>
1. **Scaffold.** Copy the template repo.
2. **Write the three parts** — input model, output model, `process()`.
3. **Declare pricing** so the tool is billable.
</Steps>

Bold the first clause of each step (the imperative) — it becomes the scannable spine of the recipe. Keep prose and code inside the list item so the rail stays unbroken.

Code blocks render through Starlight’s built-in Expressive Code. Always give a language, and add a title="…" when the block is a real file — the title renders as a filename tab:

```python title="app/tools/my_tool.py"
class MyTool(BaseTool[MyInput, MyOutput]):
def process(self, input: MyInput, ctx: TaskContext) -> MyOutput:
...
```

Reach for a fenced block whenever text is $- or brace-heavy — shell, SQL, a ${env}:${namespace}:rest Redis key, a $1/$N placeholder. Those characters are safe inside a code fence and break the build in bare prose (see below).

<Badge> is an inline pill. Use it two ways: to tag a language or shape, and — more importantly — to state a feature’s deploy status.

variant Use it for
note neutral / Planned
tip flagship or highlight
caution In code, not deployed
success Deployed
danger broken / removed

Much of this backend is built but not live. Whenever a page or section’s deploy state matters, say so — an accurate “not deployed yet” is worth more than a confident lie. Use exactly these three:

<Badge text="Deployed" variant="success" />
<Badge text="In code, not deployed" variant="caution" />
<Badge text="Planned" variant="note" />

Rendered inline: Deployed, In code, not deployed, and Planned.

To stamp a badge on the whole page (it appears next to the title and in the sidebar), add it to the frontmatter instead:

sidebar:
order: 4
badge:
text: In code, not deployed
variant: caution

MDX parses your Markdown as JSX, so a few plain-text patterns silently break the build.

  • Braces and dollars in prose. Bare { } and $ feed MDX’s expression parser and fail. Anything like {env}:{ns}, a JSON { "key": … }, or a $N placeholder must live inside backticks or a fenced block. ${…} inside a code block is fine.
  • No HTML comments. {/* … */} is the MDX comment form; the HTML <!-- --> style is rejected. Usually you just want a blank line or a :::note.
  • Angle brackets in tables. A raw <Badge … /> in a table cell renders the component. To show the literal source, wrap it in backticks: `<Badge text="Deployed" variant="success" />`.

Two hard rules keep the site’s link graph honest.

  1. Internal links are absolute, lower-case slugs with a trailing slash/how-to/add-a-tool-worker/, not add-a-tool-worker.md or a relative path. Link only to slugs that already exist in scripts/pages.manifest.mjs. The post-build check:links gate walks every generated page and fails on any internal href that doesn’t resolve.

  2. Every code/file reference must be a real path, and the best form is a GitHub deep link into the soundversegit org: https://github.com/soundversegit/<repo>/blob/staging/<path>. A bare filename in backticks is acceptable when the surrounding prose makes the repo obvious.

The secret rule build-enforced

Section titled “The secret rule ”

Write the name and its purpose, and let the deploy plumbing supply the value:

Good — names + placeholders only
# INTERNAL_RPC_SECRET — shared secret every internal RPC presents; injected by the
# deploy engine from the STAGING_/PROD_-prefixed org secret.
INTERNAL_RPC_SECRET=${INTERNAL_RPC_SECRET}
CORE_DATABASE_GRPC=<core-database-fqdn>:<port>

The secret gate enforces this two ways:

  • Deny-list. High-signal credential shapes are rejected outright — PEM PRIVATE KEY blocks, AWS access keys (AKIA…), Anthropic keys (sk-ant-…), OpenAI-style keys (sk-…), GitHub tokens (ghp_…), Slack tokens (xoxb-…), Google keys (AIza…), the prod Postgres host, an Azure SAS sig= signature, and JWTs (eyJ…).
  • Assignment check. Any identifier ending in a secret keyword — …SECRET, …PASSWORD, …TOKEN, …API_KEY, …PRIVATE_KEY, …CONNECTION_STRING, …SAS — assigned with = to a concrete string is flagged. Assigning it a placeholder passes: <…>, ${…}, , xxx, your-…, changeme, placeholder, redacted.

The keyword must be a suffix and the operator must be =, so ordinary prose is safe: the table name token_ledger, a Mermaid edge label A: token, and the phrase “the INTERNAL_RPC_SECRET name” never trip it. Only a real …SECRET=<real-value> does.

Architecture pages carry Mermaid. Author each as a fenced ```mermaid block; it renders client-side and re-themes on the light/dark toggle, so keep it theme-neutral and apply the shared five-tier colour legend. The mechanics live on their own page.

Before you consider a page done:

  1. Frontmatter title / description / sidebar.order preserved; components imported.

  2. No bare <word>, { }, or $ in prose; no <!-- --> comments.

  3. Every internal link is a /slug/ that exists in the manifest; every file reference is a real path (prefer a soundversegit GitHub deep link).

  4. Deploy-sensitive claims carry the right status badge; facts verified against current code: sources.

  5. npm run check:secrets is clean. npm run verify (secrets → build → links) is the full gate — see Running & deploying the docs.