Documentation Standards¶
Note
In-repo only. This page is for contributors writing or editing AutonomyOps
documentation from a git clone checkout. Operators following the install
flow (curl … install.sh | bash) should start at the Quickstart;
the contribution surface here is not part of the install footprint.
How to write, format, and maintain documentation in the AutonomyOps ADK.
Canonical Source¶
adk/docs/ is the canonical source for AutonomyOps product and technical truth:
what the software does, how it is configured, what it ships, what guarantees it
makes. All other AutonomyOps surfaces are derivative — they position, summarize,
and link, but they do not restate canonical content.
Surface |
Role |
Authoring rule |
|---|---|---|
|
Canonical product / technical docs |
Author here when the content states what the software does, how to configure it, what it ships, or what it guarantees. CLI reference, quickstart, architecture, runbooks, release notes. |
|
Engineering-internal source material |
Author here when the content is engineering context not ready for customer sharing (Go symbol details, threat-model internals, in-flight commercial materials). Not built into the public site. Migration mechanics: |
|
Lighter public messaging |
Position the product, summarize the value proposition, and link to canonical docs. Do not restate technical claims independently. Source repo for companion PRs: |
Drift policy¶
Drift between the website (autonomyops.ai) and
canonical docs is a website bug, not a canonical docs bug. When a change
in adk/docs/ invalidates website copy, the canonical change lands in adk
first; a companion PR in the website source repo
autonomyops/autonomyops.github.io
follows in the same review cycle and is referenced from the adk PR description.
Required website-companion PR¶
If your adk/docs/ change updates a claim that the marketing website
(autonomyops.ai) also makes, the PR description
must:
Name the affected website page(s).
Link the companion PR in the website source repo
autonomyops/autonomyops.github.io(or explicitly state that the companion PR is already merged / not yet required because the website has not yet stated the claim).
A reviewer who finds a adk/docs/ PR that changes user-visible claims without a
linked companion PR or an explicit not-required note must block on this rule.
Page Structure¶
Every documentation page must have YAML front matter:
---
title: "Page Title"
owner: "<team or person responsible for keeping this page current>"
last_verified: "YYYY-MM-DD"
source: "<relative path(s) in the repo where content originates>"
---
Required sections (adapt headings to page type):
Section |
Purpose |
|---|---|
Opening paragraph or |
One paragraph: what this page covers and why it exists |
Core content |
Interfaces, invariants, config keys, walkthrough steps, etc. |
|
Anti-patterns — explicit list of what NOT to do, and why |
|
Cross-links to related pages (bidirectional where applicable) |
Front Matter Fields¶
Field |
Required |
Notes |
|---|---|---|
|
Yes |
Shown in nav and browser tab |
|
Recommended |
Team or person responsible for keeping the page current |
|
Recommended |
ISO date when the content was last verified against code |
|
Recommended |
Relative repo path(s) where content originates |
|
Optional |
Used for |
File Naming¶
Rule |
Example |
|---|---|
Lowercase, hyphens only |
|
Match the nav slug |
Nav entry |
No spaces or underscores in new files |
|
Code Blocks¶
Always specify a language identifier:
```go
func Put(ctx context.Context, key string, val []byte) error { ... }
```
```bash
make build
```
```toml
[storage]
disk_ceiling_bytes = 10737418240
```
Fenced code blocks only — indented code blocks are forbidden (enforced by
MD046: style: fenced in .markdownlint.yml).
Smoke-Test Markers¶
The <!-- smoke-test --> HTML comment enables CI validation of documented shell commands.
A bash fenced block immediately following this marker (with at most blank lines between)
is extracted by scripts/ci/extract-smoke-commands.sh and executed during the tagged-release
command-smoke-test CI job (golang:1.22 container, no Docker, no external services).
Only mark commands that:
Are safe to run in a fresh Go container (
makeandgoare available)Do not require Docker, a running registry, or external services
Produce deterministic, non-destructive results
<!-- smoke-test -->
```bash
make build
**Do NOT mark commands that:**
- Start daemons or long-running processes
- Require Docker, a container registry, or network services
- Have side effects on shared infrastructure
- Depend on demo keys or pre-existing artifacts
If no annotated blocks are found across all docs, the smoke-test job passes with a
warning (soft pass). The first failed command in any annotated block is a release blocker.
## Audience Markers
Every Markdown page in `docs/` (excluding `_*` directories and `internal/`)
that contains a repo-checkout-only command pattern — `make demo-*`,
`make build`, `./bin/autonomy`, or any `demo/{policies,keys,agent_py,locks}`
reference — MUST declare its intended audience in an HTML comment within
the page preamble (before the first H2/H3, or within the first 30 lines
for pages with no H2/H3 at all).
Three valid markers:
| Marker | Meaning |
|---|---|
| `<!-- audience: in-repo+installed -->` | Operator-facing page that supports both audiences. Each section that mentions a flagged command must also pair it (see "Pair shapes" below). |
| `<!-- audience: in-repo-only -->` | Intentionally a developer / contributor surface (e.g. `contributing/*.md`, contributor-only runbooks). The marker is paired with a **visible banner** (see "Visible banner for `in-repo-only` pages" below) so install-mode operators landing here from search get a rendered signal — no per-section pairing required. |
| `<!-- audience: docs-only-no-commands -->` | Reference doc that mentions repo paths illustratively but never instructs the reader to run them (e.g. `docs/contracts.md` table cells). The lint sanity-checks that no fenced bash block contains a flagged pattern; prose and table-cell mentions are intentionally tolerated. |
Pages without any marker but containing flagged patterns: **lint fails**
with the file path and a suggested marker. The marker is what makes the
audience contract explicit per page; without it the lint cannot reason
about the page's intent.
### Pair shapes for `in-repo+installed` pages
Within an `in-repo+installed` page, each section — including the page
preamble (everything between the H1 and the first H2/H3, treated as a
pseudo-section named `(preamble)` for error messages) — that mentions
a flagged command in **any form** (fenced bash, inline code, plain
prose, or table cell) MUST also contain a paired installed-form
companion in the same section.
The pairing applies to all forms because every form reads as
instruction on operator-facing pages. The pairing applies to the
preamble because preamble text is where landing pages put their
headline pitch (e.g. `docs/demo/index.md` had no H2/H3 at all and
the entire `make demo-up` pitch lived in intro prose).
Two valid pair patterns:
**Pattern A — labeled fenced pair** (preferred for prose-heavy pages):
````markdown
**In-repo:**
```bash
make demo-up
Installed:
cd ~/.autonomyops/quickstart && bash demo/scripts/demo_up.sh
**Pattern B — Sphinx tab directive** (preferred for tutorial step-by-step):
````markdown
````{tab-set}
:::{tab-item} In-repo (`git clone`)
:sync: in-repo
```bash
make demo-up
```
:::
:::{tab-item} Installed (`curl install.sh`)
:sync: installed
```bash
bash demo/scripts/demo_up.sh
```
:::
**Pattern C — inline annotation in fenced bash** (preferred for command-list pages
where each command's installed equivalent is most readable next to its in-repo
form, established by `docs/runbooks/demo-runbook.md`'s post-#722 restructure):
````markdown
```
make demo-up # (installed: bash demo/scripts/demo_up.sh)
make demo-preflight # (installed: bash demo/scripts/preflight.sh)
make demo-clean # (installed: docker compose -f demo/docker-compose.yml down -v)
```
The lint accepts the substring (installed: as the pair marker. The
opening paren and the colon and the exact spelling installed together
make this restrictive enough to avoid false-positives from prose
mentions.
Deferral form (when no installed equivalent exists yet)¶
When the installed flow is not yet supported (because the underlying bundle work has not landed), the installed block uses an explicit deferral marker:
**Installed:** *not yet supported — tracked in #723.*
The lint accepts the deferral as a valid pair AND treats the page as eligible to be re-audited when the referenced issue closes (so the deferral text can upgrade to a real command).
Lint and CI¶
The lint lives at scripts/docgen/check-docs-audience.py and runs in
the docs CI workflow on every PR. Run locally with:
make docs-audience-lint
The lint operates on structure, not line proximity:
Page level — marker explicit and machine-checkable.
Section level — H2/H3 boundary defines the unit; pair must exist within the same section. No N-line guesswork.
Pattern allowlist —
**Installed:**label,:sync: installedtab attribute, or the explicit “tracked in #723” deferral. Any of the three counts; nothing else does.
Unit tests for the lint live at
scripts/docgen/test_check_docs_audience.py and cover all three
marker types plus the four edge cases (preamble-only pages, table
cells, prose mentions, frontmatter placement).
Admonitions¶
Use MkDocs Material admonitions for callouts. Available types:
!!! warning "Title"
Warning text here — use for non-obvious gotchas.
!!! info "Title"
Informational note — use for tips and clarifications.
!!! danger "Title"
Danger / non-negotiable constraint — use for invariant violations and
security non-negotiables.
Use !!! danger for statements like “never bypass X” or “always require Y” that trace
to a named invariant.
Internal Links¶
Always use relative paths:
[Invariants](../architecture/invariants.md) ✓ relative path
[Invariants](invariants.md) ✓ same directory
[Invariants](/architecture/invariants/) ✗ absolute — breaks offline
[Invariants](https://example.com/architecture/) ✗ external URL for internal page
Bidirectional cross-links are required where pages reference each other
(e.g., if disk-ceiling.md links to invariants.md#inv-04, then invariants.md
should link to disk-ceiling.md).
Tables¶
Prefer Markdown tables over HTML. Table cells and heading lines are exempt from the
200-character line length limit (configured in .markdownlint.yml).
| Symbol | Signature | Description |
|---|---|---|
| `Put` | `func Put(ctx, key, value) error` | Stores a value under the disk ceiling. |
Generated vs Hand-Edited Content¶
Location |
Status |
Rule |
|---|---|---|
|
Auto-generated |
Never hand-edit — regenerate with |
|
Hand-edited |
Always PR-reviewed; use |
All other |
Hand-edited |
May link to generated content; never embed it inline |
Adding a New Page¶
Create
docs/<section>/<page>.mdwith required front matter.Add the filename (without
.md) to the{toctree}indocs/<section>/index.md.If the page documents a Go package, add an entry to
docs/_meta/pkg-to-page.yaml.Run
make docsto verify the build succeeds, thenmake docs-freshnessandmake docs-coverage-gate.
Mermaid Diagrams¶
Pages containing Mermaid diagrams must include the air-gap warning admonition:
!!! warning "Mermaid diagrams require JavaScript"
Diagrams on this page use [Mermaid](https://mermaid.js.org/) rendered via
`sphinxcontrib-mermaid`. They require JavaScript to be enabled and, in
non-air-gapped environments, an outbound connection to `cdn.jsdelivr.net`
(pinned to mermaid.js 10.2.0 via `mermaid_version` in `docs/conf.py`).
In air-gapped deployments, host `mermaid.min.js` locally and update
`mermaid_version` to point to the local path.
Use the default Mermaid theme. Custom hex colours are reserved for trust-boundary
diagrams (e.g., style A fill:#e8f5e9).
Parameterization¶
This documentation was structured from the Edge Capability Workplan (v0.6). When adapting for a different capability, substitute these placeholders:
Placeholder (in docs) |
Replace with |
|---|---|
|
Your daemon binary name |
|
Your control CLI name |
|
Your capability slug |
|
|
|
|
|
Your capability name |
|
Your invariant set |
Linting Locally¶
# Markdown style check
npx markdownlint-cli2 --config .markdownlint.yml "docs/**/*.md"
# Full docs build (strict — promotes all warnings to errors)
make docs-lint
# Verify all mapped pages exist on disk
make docs-freshness
# Verify all packages are mapped
make docs-coverage-gate
Review Checklist for Doc PRs¶
Front matter complete:
title,owner,last_verified,sourceNo broken internal links (
make docs-lintpasses htmltest)If a new package was added:
pkg-to-page.yamlentry presentIf a new page was added:
{toctree}entry indocs/<section>/index.md<!-- smoke-test -->markers used only on safe, generic commands!!! dangerused for invariant violations and security non-negotiablesdocs/_generated/files not hand-editedCanonical-source rule: if the PR changes a user-visible claim the website also makes, PR description links the companion PR in the website source repo (or states none required).
Do Not Do¶
❌ Do NOT hand-edit
docs/_generated/— these files are regenerated bymake docs-gen❌ Do NOT use absolute URLs for internal links — they break offline and staged deployments
❌ Do NOT add indented code blocks — use fenced blocks (
MD046: style: fenced)❌ Do NOT put
<!-- smoke-test -->on commands that require Docker, a running service, or network access❌ Do NOT omit the Mermaid air-gap warning admonition on pages with Mermaid diagrams
❌ Do NOT restate canonical product/technical claims on marketing surfaces — link to the canonical
adk/docs/page instead
See Also¶
.markdownlint.yml— markdown linting configuration.htmltest.yml— link-checking configuration