Doc Gardening
Maintain {{REPO}}'s per-package documentation graph after code changes. This skill handles both generating docs for a new package and updating stale docs for an existing one.
$ARGUMENTS is a package name ({{PACKAGE_EXAMPLES}}) or all / empty
for a whole-repo sweep. Packages live at {{PACKAGE_DIRS}}.
{{SOURCE_LAYOUT}}
Accuracy beats coverage. These files are read by humans and by agents mid-task, so a wrong dependency edge or an invented invariant is worse than a missing section. Read the actual source; never infer from a file name.
Phase 1: Detect what needs attention
Scoped run — read the package's sources and its existing
CLAUDE.md, and decide new versus stale.
Full run (all or no argument):
# Packages with source but no CLAUDE.md
{{DETECT_MISSING}}
# Packages touched on this branch
{{DETECT_TOUCHED}}
Classify each package:
- New — has source but no
CLAUDE.md. - Stale — has
CLAUDE.md, but source has a newer last commit ({{GATE_COMMAND}}prints these as warnings; see Phase 7). - Scaffold — the directory exists but holds no source. Write nothing, or a two-line stub explicitly marked as scaffold. Do not describe a package from its manifest alone.
Phase 2: Read the package's sources
Reading source is primary. For each package gather:
{{SOURCE_INPUTS}}
A fast sweep that gets the doc comments, imports and public surface at once:
{{SWEEP_COMMAND}}
Then read whole modules for anything the sweep leaves unclear.
Dependency edges come from the imports. {{DEPENDENCY_SOURCE}} Report a divergence between declared and actual edges; do not silently "fix" it.
Phase 3: Trace the traffic
The template's traffic section is where a per-package doc earns its keep. {{REPO}} has these kinds, and each wants concrete type names, not prose:
{{TRAFFIC_KINDS}}
Name both ends of every edge: the sender and the receiver, the writer
and the reader, by qualified type or function name. "Sends commits to
the writer" is prose; runtime/writer.Commit(tx, reply) sent by
runtime/api is a fact.
Phase 4: Generate or update CLAUDE.md
Follow template.md.
- New package — write from scratch against the template.
- Stale package — read the existing file, diff it against current source, and change only what actually moved. Do not rewrite prose that is still true; the file's stability is what makes its history readable.
Never name an assistant, an AI, or an authoring tool in generated content. The file is documentation of the package, nothing else.
Phase 5: Mirror to AGENTS.md
Every CLAUDE.md has a byte-identical AGENTS.md beside it:
cp <package>/CLAUDE.md <package>/AGENTS.md
Copy, never hand-edit the mirror; {{GATE_COMMAND}} compares them byte
for byte.
Phase 6: Architecture roll-up
Check whether the change belongs in the as-built docs:
- {{ARCH_DOCS}} A new or renamed module belongs in the right one.
- {{DECISION_HOMES}} Never a silent edit to a per-package doc.
- Root
CLAUDE.mdkeeps only the one Per-package docs pointer; the detail lives in the graph.
Phase 7: Validate
{{GATE_COMMAND}}
scripts/doc_check.sh enforces four things:
- Coverage — every package with source has a
CLAUDE.md. Failure. - Mirror —
AGENTS.mdexists and is byte-identical. Failure. - Staleness — the last commit touching the package's source is
newer than the last commit touching
CLAUDE.md. Warning, not failure: source moves faster than prose by design, and the warning list is the queue this skill works from. Mtimes are meaningless in a fresh checkout, so the comparison usesgit log -1 --format=%ct. - Citations — every
file.ext:NNunderdocs/resolves to one file, is within its length, and still holds the backticked symbol named beside it. Decidable drift in a backticked citation outside the review directory fails; the rest warns.
The script runs no builds and needs no toolchain, so it stays usable while other work is compiling.
Fix every error before finishing, and report what was created, updated, and left warning.
Notes
- {{PRUNE_NOTE}}
- Prefer a doc comment's own words for an invariant; they were written to state one.
- Invariants are things that break if violated. "Every transaction opens
with
BEGIN IMMEDIATE" is an invariant. "UsesResultfor errors" is not. - For CI:
{{GATE_COMMAND}}is the check-mode gate; the staleness warnings are the work queue for a/doc-gardening allpass, which commits its updates under adocs:prefix.