doc-sync — keep docs and code converged
This repo treats doc lag as an unfinished bug (see AGENTS.md § Doc-sync discipline).
This skill is the executable procedure; the canonical mapping table (which change owes
which doc) lives in AGENTS.md — read it there, do not copy it here.
This file is canonical at .agents/skills/doc-sync/SKILL.md (.claude/skills/doc-sync
is a symlink). The skill itself iterates: when a run shows an instruction here is wrong
or misleading, fix it in the same pass, with the run's evidence in the commit message.
Mode 1 — per-change sync (run at the end of every change)
Determine the change surface.
git diff --stat origin/main...HEAD (or the staged diff for uncommitted work).
Map each changed path against the AGENTS.md doc-sync table. Produce the list of
docs owed by this change. The high-traffic rows:
src/db/schema.ts → docs/generated/db-schema.md (hand-maintained snapshot — no
generator script exists despite the generated/ dir name; update the table row
and any enum lists by hand; prod DB migrates via prod:up → db:push:prod).
- Routes / CLI subcommands / daemon protocol →
ARCHITECTURE.md §II codemap + §IV contracts.
- Module purpose / boundary / invariant changed →
ARCHITECTURE.md §II–IV.
- Feature completed or modified →
FEATURES.md checkbox (checkbox + a short note;
long verification narratives belong in the PR, not the checklist).
- TODO / known drift left behind →
docs/tech-debt-tracker.md new entry
(next free ID — check the archive too so IDs are never reused).
src/daemon/** shipped in the bundle → bump packages/daemon/package.json,
cut a GitHub Release, and add the version's CHANGELOG.md entry. Merged ≠ shipped.
Status single-source rule. Security/authorization item states (F*/C*/IDOR-B*) live
only in docs/authorization.md §6. Other docs (PLANS, tech-debt I44) may point
there but must never mirror per-item states — mirrored lists are how C10 stayed
"remaining" for weeks after it was fixed. Detect mechanically, don't trust prose:
grep -rnE '\b(C1[0-2]|C[1-9]|B[1-6]|F[0-9]|IDOR)\b' --include='*.md' docs/ *.md | grep -vE 'authorization\.md|docs/exec-plans/|docs/superpowers/'
(historical plan/spec records legitimately narrate the states they shipped — the rule
polices live docs). A hit naming an item's state (open/fixed/remaining) is a
violation; a bare pointer to authorization.md §6 is fine.
Staleness check on every doc you touched. For each edited doc: file paths it names
exist; tech-debt I<n> / D<n> references resolve (tracker or archive); counts/enums
match code (grep, wc -l — better: drop volatile numbers entirely, per
ARCHITECTURE.md's header rule).
Hygiene gates.
- No personal/machine refs in what this change adds (core belief #9). Grep the
added diff lines, not whole files:
git diff origin/main -- <files> | grep '^+' | grep -E '~/\.claude|/Users/'.
A personal absolute path (/Users/<name>/…) is a violation. Two known non-violations
that this grep still surfaces: a generic runtime path that is product behavior
(e.g. ~/.claude/skills as Claude CLI's global skills dir), and a tech-debt entry
quoting a personal path as the evidence of the debt it records. Judge, don't
blind-fail — but never add a new personal path outside those two shapes.
- Touched
src/daemon/prompt.ts? Grep for provider-specific tool names
(Read, cat, grep, vision hints) → expect zero hits (code-quality red line).
Fail loud. In the PR/summary, list: docs updated · docs checked-and-clean ·
drift found but deferred (with its new tech-debt entry ID).
Mode 2 — periodic full audit (on request / doc-gardening)
Cross-check the status documents against code and each other; they drift fastest:
FEATURES.md — sample every [ ] unchecked line: is the feature actually still
missing? (grep the endpoint / CLI verb / component). Unchecked-but-shipped is the
most common rot.
docs/PLANS.md — every referenced plan file exists; Active items are still active;
completed plans moved to docs/exec-plans/completed/ with their status line
updated (a moved plan still saying "merge pending " is half-finished rot).
docs/tech-debt-tracker.md — no duplicate IDs (incl. vs the archive); ⬜/🟡 entries
spot-checked against code; newly-✅ entries: move the full row to the archive.
The tracker keeps no stub — it holds open items only; cross-references resolve by
grepping both files.
docs/authorization.md §6 vs any doc that mentions security items — pointers only,
no mirrored states (run the Mode 1 step-3 grep).
ARCHITECTURE.md §II — new substantive modules (>50 lines) present in the codemap.
Recipe: git log --since=<last audit> --name-only --diff-filter=A --pretty=format: -- 'src/*' 'web/src/*',
then check each surviving non-test file's basename appears in the codemap. Named files
exist; CHANGELOG.md's newest version heading (the [Unreleased] section doesn't
count) matches packages/daemon/package.json.
- Size / density audit — docs must stay maps, not manuals. Line counts hide bloat
(long table rows); rank by bytes:
git ls-files '*.md' | xargs wc -c | sort -rn | head.
For each fat doc, check it against its own stated form rule (FEATURES' "checkbox +
short note" header, ARCHITECTURE's "write only what doesn't change often" header) —
self-rule violations are the strongest trim mandate. Cut change-history narrative
("the former X was removed…", "before this fix…") and verification evidence — git log
and PRs own those. Frozen plan/spec archives of shipped work are deletable (git
history retains them); before deleting, grep for inbound references incl. from src/.
README.zh-CN.md parity — diff section structure + bullet counts against
README.md; the zh mirror silently misses EN feature edits (drift is one-directional).
Small deltas: translate in the same pass. A backlog: open a tech-debt entry.
Report findings with file:line evidence; fix mechanically-safe drift in the same pass,
open tech-debt entries for anything needing a decision.
1---2name: doc-sync3description: doc-sync — keep docs and code converged4---56# doc-sync — keep docs and code converged78This repo treats doc lag as **an unfinished bug** (see AGENTS.md § Doc-sync discipline).9This skill is the executable procedure; the canonical *mapping table* (which change owes10which doc) lives in **AGENTS.md** — read it there, do not copy it here.1112> This file is canonical at `.agents/skills/doc-sync/SKILL.md` (`.claude/skills/doc-sync`13> is a symlink). The skill itself iterates: when a run shows an instruction here is wrong14> or misleading, fix it **in the same pass**, with the run's evidence in the commit message.1516## Mode 1 — per-change sync (run at the end of every change)17181. **Determine the change surface.**19 `git diff --stat origin/main...HEAD` (or the staged diff for uncommitted work).20212. **Map each changed path against the AGENTS.md doc-sync table.** Produce the list of22 docs owed by this change. The high-traffic rows:23 - `src/db/schema.ts` → `docs/generated/db-schema.md` (hand-maintained snapshot — **no24 generator script exists despite the `generated/` dir name**; update the table row25 *and* any enum lists by hand; prod DB migrates via `prod:up` → `db:push:prod`).26 - Routes / CLI subcommands / daemon protocol → `ARCHITECTURE.md` §II codemap + §IV contracts.27 - Module purpose / boundary / invariant changed → `ARCHITECTURE.md` §II–IV.28 - Feature completed or modified → `FEATURES.md` checkbox (**checkbox + a short note**;29 long verification narratives belong in the PR, not the checklist).30 - TODO / known drift left behind → `docs/tech-debt-tracker.md` new entry31 (next free ID — check the **archive** too so IDs are never reused).32 - `src/daemon/**` shipped in the bundle → bump `packages/daemon/package.json`,33 cut a GitHub Release, **and add the version's `CHANGELOG.md` entry**. Merged ≠ shipped.34353. **Status single-source rule.** Security/authorization item states (F*/C*/IDOR-B*) live36 **only** in `docs/authorization.md` §6. Other docs (PLANS, tech-debt I44) may point37 there but must never mirror per-item states — mirrored lists are how C10 stayed38 "remaining" for weeks after it was fixed. Detect mechanically, don't trust prose:39 `grep -rnE '\b(C1[0-2]|C[1-9]|B[1-6]|F[0-9]|IDOR)\b' --include='*.md' docs/ *.md | grep -vE 'authorization\.md|docs/exec-plans/|docs/superpowers/'`40 (historical plan/spec records legitimately narrate the states they shipped — the rule41 polices *live* docs). A hit naming an item's *state* (open/fixed/remaining) is a42 violation; a bare pointer to authorization.md §6 is fine.43444. **Staleness check on every doc you touched.** For each edited doc: file paths it names45 exist; `tech-debt I<n>` / `D<n>` references resolve (tracker or archive); counts/enums46 match code (`grep`, `wc -l` — better: drop volatile numbers entirely, per47 ARCHITECTURE.md's header rule).48495. **Hygiene gates.**50 - No personal/machine refs in what this change **adds** (core belief #9). Grep the51 *added diff lines*, not whole files:52 `git diff origin/main -- <files> | grep '^+' | grep -E '~/\.claude|/Users/'`.53 A personal absolute path (`/Users/<name>/…`) is a violation. Two known non-violations54 that this grep still surfaces: a generic runtime path that is product behavior55 (e.g. `~/.claude/skills` as Claude CLI's global skills dir), and a tech-debt entry56 *quoting* a personal path as the evidence of the debt it records. Judge, don't57 blind-fail — but never add a *new* personal path outside those two shapes.58 - Touched `src/daemon/prompt.ts`? Grep for provider-specific tool names59 (`Read`, `cat`, `grep`, vision hints) → expect zero hits (code-quality red line).60616. **Fail loud.** In the PR/summary, list: docs updated · docs checked-and-clean ·62 drift found but deferred (with its new tech-debt entry ID).6364## Mode 2 — periodic full audit (on request / doc-gardening)6566Cross-check the status documents against code and each other; they drift fastest:67681. `FEATURES.md` — sample every `[ ]` unchecked line: is the feature actually still69 missing? (grep the endpoint / CLI verb / component). Unchecked-but-shipped is the70 most common rot.712. `docs/PLANS.md` — every referenced plan file exists; Active items are still active;72 completed plans moved to `docs/exec-plans/completed/` **with their status line73 updated** (a moved plan still saying "merge pending <date>" is half-finished rot).743. `docs/tech-debt-tracker.md` — no duplicate IDs (incl. vs the archive); ⬜/🟡 entries75 spot-checked against code; newly-✅ entries: **move the full row** to the archive.76 The tracker keeps no stub — it holds open items only; cross-references resolve by77 grepping both files.784. `docs/authorization.md` §6 vs any doc that mentions security items — pointers only,79 no mirrored states (run the Mode 1 step-3 grep).805. `ARCHITECTURE.md` §II — new substantive modules (>50 lines) present in the codemap.81 Recipe: `git log --since=<last audit> --name-only --diff-filter=A --pretty=format: -- 'src/*' 'web/src/*'`,82 then check each surviving non-test file's basename appears in the codemap. Named files83 exist; `CHANGELOG.md`'s newest **version** heading (the `[Unreleased]` section doesn't84 count) matches `packages/daemon/package.json`.856. **Size / density audit — docs must stay maps, not manuals.** Line counts hide bloat86 (long table rows); rank by bytes: `git ls-files '*.md' | xargs wc -c | sort -rn | head`.87 For each fat doc, check it against **its own stated form rule** (FEATURES' "checkbox +88 short note" header, ARCHITECTURE's "write only what doesn't change often" header) —89 self-rule violations are the strongest trim mandate. Cut change-history narrative90 ("the former X was removed…", "before this fix…") and verification evidence — git log91 and PRs own those. Frozen plan/spec archives of shipped work are deletable (git92 history retains them); before deleting, grep for inbound references incl. from `src/`.937. **`README.zh-CN.md` parity** — diff section structure + bullet counts against94 `README.md`; the zh mirror silently misses EN feature edits (drift is one-directional).95 Small deltas: translate in the same pass. A backlog: open a tech-debt entry.9697Report findings with file:line evidence; fix mechanically-safe drift in the same pass,98open tech-debt entries for anything needing a decision.