Repo Doc Governance
Purpose
This skill enforces documentation governance with low churn.
It answers three questions after a meaningful change:
- Does this change require documentation updates?
- Which document should be updated?
- What minimum report should be emitted at completion?
How Detection Works (read this before expecting more)
The skill grep-ea path-refs en backticks / fenced blocks de tus .md y los compara contra git diff --name-only. Es substring-matching sobre paths, no análisis semántico. Un doc que menciona apps/api/ en prosa se flagea cuando cambia CUALQUIER cosa bajo apps/api/. Consecuencias:
- Sobre-reporta por diseño. Un
docs_affected: 0 es señal fuerte ("nada relevante"); un warning requiere triage humano.
- No detecta prose/symbol drift. README que dice "usa
chart.js" no genera warning si borrás chart.js del package.json (el nombre no es un path). Ver ## Known Limitations para el complemento manual con grep.
- Ruido reducible con
.doc-governance/ignore. Globs por línea (sintaxis gitignore-lite). Excluye docs enteros (docs/plans/**, Task*.md) y sus code-refs asociados. Ejemplo commiteable: templates/doc-governance-ignore.example.
When To Use
Use this skill after a task that may affect maintainers, operators, contributors, or users.
Trigger examples:
- setup, installation, dependencies, or environment requirements changed
- scripts, commands, CI, build, deploy, or release flow changed
- architecture, module boundaries, data flow, trust boundaries, or contracts changed
- API behavior, request/response shape, or compatibility changed
- auth, authz, secret handling, permissions, exposure, or hardening changed
- contributor workflow, lint/test expectations, or PR policy changed
- troubleshooting, operations, rollback, or recovery workflow changed
When NOT To Use
Do not run this skill for behavior-neutral edits:
- formatting-only or comment-only changes
- typo-only fixes without semantic impact
- pure renames with no behavior change
- internal refactors with no user/developer/operator/security impact
- test-only edits that do not change contributor expectations
- temporary debugging changes removed before completion
Activation Signals
Common request patterns that should activate this skill.
Terminación de sesión (frases naturales, el 80% de los casos):
- "actualizá los docs" / "actualizá la documentación"
- "update docs" / "update the docs"
- "revisá docs" / "chequeá docs"
- "chequeá qué docs cambiaron"
- "cerrá esta task revisando docs"
- "docs impact?" / "doc impact after this?"
Después de un cambio específico (más contexto):
- "actualizá docs después de estos cambios"
- "update docs after changing CI pipeline"
- "we changed setup/install steps"
- "security/auth flow changed, what docs need updates?"
- "API contract changed, which docs should be updated?"
- "review doc impact before closing this task"
Invocación explícita del skill (bypass heuristics):
- "corré doc-governance-skill"
- "usá el skill de doc governance"
- Slash literal:
/doc-governance-skill:review (flujo completo) o /doc-governance-skill:update (solo drift check)
Non-Activation Signals
Common request patterns that should not activate this skill:
- "format this file"
- "fix typos only"
- "rename variable/class only"
- "internal refactor with no behavior change"
- "comment cleanup only"
Decision Flow
Run this sequence after completing implementation:
- Inspect changed files and task outcome.
- Determine whether any documentation impact exists.
- Map each impact to the correct document target.
- Update only impacted sections and avoid unrelated rewrites.
- Emit the required minimal completion report.
Update Rules
Update docs when at least one is true:
- Setup, dependencies, environment variables, or platform requirements changed.
- Command usage, scripts, CI/CD, build, deploy, or release behavior changed.
- Architecture, integrations, data flow, or API contracts changed.
- Security posture changed (auth/authz/secrets/permissions/exposure/disclosure).
- Agent workflow or repository automation behavior changed.
- Contribution process or quality gates changed.
- Operator runbooks, failure handling, or rollback/recovery changed.
- User-visible behavior changed enough to require release notes or usage docs.
Document Routing By Type
Use only the files that match the actual impact:
README.md: setup, usage, safe defaults, common operational commands
AGENTS.md: agent workflow rules and repository automation guidance
CLAUDE.md: Claude-agent-specific instructions and repository conventions (pairs with or replaces AGENTS.md in Claude-native repos)
CONTRIBUTING.md: contributor workflow, lint/test expectations, PR standards
SECURITY.md: disclosure process, support policy, hardening-relevant maintainer guidance
CHANGELOG.md: user-visible or operator-visible release-facing changes. Follow Keep a Changelog buckets (Added / Changed / Fixed / Removed / Security). Fixes pending release go under [Unreleased]; dated sections are cut on release.
ARCHITECTURE.md: system boundaries, component responsibilities, trust/data flow
OPERATIONS.md: deployment, maintenance, backup, rollback, incident handling
TROUBLESHOOTING.md: recurring failures, diagnostics, safe remediation
API.md or docs/api/**: API behavior or contract changes
docs/**: deep technical documentation not suitable for top-level docs
- dep add/remove (
package.json, requirements.txt, go.mod, Cargo.toml, etc.): CHANGELOG.md + README.md (si la dep aparece en setup/install) + el manifest propio
- script/comando renombrado (
next lint → eslint ., npm test → vitest, etc.): CHANGELOG.md + AGENTS.md / CONTRIBUTING.md si documentan comandos
Minimal Output Format
At completion, emit exactly this block:
Action Taken: [README.md | AGENTS.md | CLAUDE.md | CONTRIBUTING.md | SECURITY.md | CHANGELOG.md | ARCHITECTURE.md | OPERATIONS.md | TROUBLESHOOTING.md | API.md | docs/** | Multiple | None]
Justification: [one clear sentence]
Persisted Rule: [rule to append to CLAUDE.md or AGENTS.md if the change reveals a routing or update policy worth carrying forward; else "None"]
Persisted Rule defaults to None. Emit a non-None value only when the change reveals a durable policy — e.g. "New CI jobs always update OPERATIONS.md rollback section". The agent applies it by editing CLAUDE.md or AGENTS.md in the same task.
When to emit which format
- Agent-driven decision flow (manual routing): emit the
Action Taken / Justification / Persisted Rule block above.
- Update Mode tool (
bin/update.js): emits the DOC_GOVERNANCE_UPDATE: / SUMMARY: block automatically. The agent still emits the manual block after acting on the tool's findings.
Style Constraints
- Keep output concise and specific.
- Prefer precise, local edits over broad rewrites.
- Do not force documentation updates when impact is absent.
- If multiple documents are impacted, update all relevant ones.
Audit Mode
Invoke when the human asks for a documentation map, a repo audit, or uses phrases like "audita la documentación" / "map the docs" / "/audit". This mode is heavy and infrequent — run it once per baseline, not per change.
Command:
node .ai/skills/doc-governance-skill/bin/audit.js
Path note: the command assumes the skill installed at .ai/skills/doc-governance-skill/ (per-repo default from install.sh). Adjust to ~/.claude/skills/doc-governance-skill/bin/… for a global install, or wherever the skill lives in your setup.
Behavior:
- Scans every
*.md in the repo (skipping .git, node_modules, dist, build, .next, target, vendor, .venv, venv, .doc-governance, .ai, .agents, .claude, graphify-out), plus anything matched by .doc-governance/ignore.
- For each doc, records: title (first H1), heading tree (H1–H3), and detected code refs (paths in backticks + fenced blocks annotated with
path=).
- Writes
.doc-governance/map.md, sealed with the current git HEAD SHA, an ISO 8601 timestamp, and the tool_version: that sealed it.
- Records
sealed_dirty: — every path whose worktree content differs from HEAD at seal time, with its content hash. The scan reads the worktree while sealed_sha names HEAD, so without this the next run reports the reseal's own commit as drift.
- Exit 0 on success, 1 on I/O or git error.
The line above is generated from EXCLUDE_DIRS in bin/lib/scan.js by bin/lib/sync-exclude-dirs.js; CI runs it with --check. Edit the code, not the prose.
After running audit, commit .doc-governance/map.md. It is the shared baseline the update mode diffs against.
Update Mode
Invoke when the human asks for a doc-drift check, uses phrases like "update docs" / "actualizá la documentación" / "/update", or after finishing a meaningful change. This mode is lightweight — safe to run per task.
Command:
node .ai/skills/doc-governance-skill/bin/update.js
Path note: same as Audit Mode — adjust the path to your install location.
Optional overrides:
--since <ref> — diff against a specific git ref instead of the sealed SHA.
--files a,b,c — explicit file list, skip git diff entirely.
- stdin — accepts one path per line (e.g.
git diff --name-only | node .../update.js).
Behavior:
- If
.doc-governance/map.md is missing, auto-creates it by scanning the repo and sealing to current git HEAD (see ## First Run / No Baseline below).
- Reads
.doc-governance/map.md, extracts the sealed SHA, the tool_version: and the sealed_dirty: set.
- Compares the baseline's
tool_version: against its own. A mismatch that crosses a version where the scanned file set changed is a Warning — the baseline is not merely stale, it maps a different universe of files.
- Runs
git diff --name-only <sealed_sha> (working-tree comparison → catches committed + uncommitted).
- Drops any changed path whose content still matches
sealed_dirty: down to Info (carried_from_seal) — the baseline scan already saw those bytes. Skipped under --since / --files / stdin, where the baseline is a different ref.
- Cross-references the remaining changed paths against
code_refs in the map.
- Emits a
DOC_GOVERNANCE_UPDATE: block with three severity tiers (Critical / Warning / Info) and a SUMMARY: line.
- Exit 0 clean or Info-only, 1 with any Warning or Critical finding.
For each code_file: <path> in the emitted Warning list, use the routing table in ## Document Routing By Type above to decide whether the docs named in its affected_docs: are the right target — the audit tool detects references, not intent.
First Run / No Baseline
On the first invocation in a repo without .doc-governance/map.md:
- Update Mode auto-creates the map sealed to current
git HEAD and emits an Info: baseline_auto_sealed entry.
- Exit 0 is expected — nothing has changed against a baseline sealed a moment ago.
- Commit
.doc-governance/map.md. Subsequent runs diff against that SHA.
To seal a baseline explicitly (larger repos, CI-driven bootstrap), run audit.js first — behavior is identical.
Root Invocation Behavior
Este flujo aplica cuando el skill se activa — sea por slash (/doc-governance-skill:review) o por intent phrasing ("actualizá docs", "revisá qué docs cambiaron", etc.).
Cold-start guard — chequeá esto ANTES de nada
Verificá si existe .doc-governance/map.md en el repo actual:
test -f .doc-governance/map.md && echo "map exists" || echo "no map"
Si "no map" (primer uso en este repo): NO sigas con los pasos 1-4 de abajo. Hacé exactamente esto:
Ubicá el skill root — este bloque es la fuente canónica; los slash-commands apuntan acá, no lo dupliques:
ROOT=$(find ~/.claude/plugins/cache/*/doc-governance-skill -name 'SKILL.md' -not -path '*/node_modules/*' 2>/dev/null | head -1 | xargs -r dirname)
[ -n "$ROOT" ] || ROOT=~/.claude/skills/doc-governance-skill
SKILL_ROOT=$(node "$ROOT/bin/which.js" 2>/dev/null) || SKILL_ROOT=$ROOT
El primer paso es barato y deliberadamente tonto: sólo necesita encontrar alguna copia. La elección la hace bin/which.js, que enumera todas las instalaciones y devuelve la de versión más alta. Antes se usaba find … | head -1 a secas, que devuelve lo primero que lista el filesystem — con dos copias conviviendo eso es una moneda al aire, y es el mecanismo exacto del incidente que motivó 0.9.0. Si la copia hallada es anterior a 0.9.1 y no tiene which.js, el || preserva el comportamiento viejo.
Ante cualquier duda sobre qué copia está corriendo: node "$SKILL_ROOT/bin/which.js" --verbose lista todas con su versión y avisa si conviven varias.
Corré node "$SKILL_ROOT/bin/audit.js".
Emitir mensaje corto al user:
Baseline sellado en .doc-governance/map.md (SHA <sha>, N docs mapeados).
Commiteá: git add .doc-governance/map.md && git commit -m "chore: seal doc-governance baseline"
Después re-invocáme para el flujo completo.
STOP. No hay drift para reportar en un baseline recién sellado — ejecutar el flujo agentic completo acá sería caro y no aportaría valor.
Si "map exists": seguí con el flujo abajo.
Flujo steady-state
Corré el flujo manual completo: inspeccionar cambios, decidir routing usando ## Document Routing By Type, editar los docs impactados, emitir el bloque Action Taken / Justification / Persisted Rule.
Cross-check CHANGELOG "Unreleased" (previene drift-ahead — CHANGELOG que miente sobre el estado del working tree):
- Localizá la sección
[Unreleased] / [Sin publicar] en CHANGELOG.md.
- Bajo
### Removed / ### Removido, extraé cada backtick-token con extensión de archivo (X.tsx, path/Y.ts, lib/Z.js).
- Para cada token, verificá con
git ls-files -- <path>. Si devuelve el path (el archivo sigue tracked) pero el bullet dice "eliminado" → warning changelog_drift_ahead.
- Corregí el bullet (o restaurá el archivo, según la intent real) ANTES de emitir el bloque
Action Taken.
Este check compensa la limitación documentada en ## Known Limitations: el skill mide path-refs del diff, no valida coherencia interna del CHANGELOG.
Ofrecé re-sellar el baseline (una línea): emitir literal Reseleo baseline? [Y/n] y esperar respuesta.
- Enter /
y / yes / sí → correr node <skill-root>/bin/audit.js, avisar Baseline re-sellado (SHA <short>, N docs). Incluí .doc-governance/map.md en tu próximo commit.
n / no → cerrar sin acción.
Desde 0.9.0 el commit que lleva el map re-sellado no genera drift sobre sí mismo: audit.js registra en sealed_dirty: el contenido de todo lo que estaba sin commitear al momento del sello, y update.js lo baja a INFO (carried_from_seal) mientras siga idéntico. No hace falta commitear el map aparte ni en un orden particular.
Skip enteramente la pregunta si el flujo se disparó desde /doc-governance-skill:update (drift check puro, no toca baseline) o si el user pasó --no-seal / "no reseales" en el mensaje original.
Regla de oro: la skill empodera al user, no lo reemplaza. La pregunta es corta pero explícita — nunca correr audit sin confirmación.
Drift Categories Monitored
| Severity |
Trigger |
Suggested Action |
| Critical |
Reserved (future: semantic mismatch, anchor removed, deleted-file referenced) |
Not emitted yet. |
| Warning |
Code path referenced by a doc changed substantively since the sealed SHA. One entry per changed code file (not per doc), with affected_docs: and a 2-3 line diff_sample:. |
Review the doc sections listed in affected_docs: that mention the changed path; update or confirm still accurate. |
| Warning |
baseline_version_drift where the gap between the baseline's tool_version: and the running tool crosses a version that changed which files get scanned. |
Re-seal. Until then the report covers a different file set than the repo actually has, and two installed copies of the skill will disagree. |
| Info |
baseline_version_drift with no scan-universe change crossed, or baseline_version_unknown (header has no parseable version). |
Re-seal when convenient; results are still comparable. |
| Info |
carried_from_seal — a changed path whose content is byte-identical to what the baseline scan already saw. |
None. This is the reseal's own commit, already accounted for. |
| Info |
Trivial change (whitespace-only or comment-only) on a referenced path; rename detected (renamed: A -> B); .md files changed since sealed SHA (map may be stale); auto-bootstrapped baseline. |
Depends on subtype — see suggested_action: on each entry. |
Exit code: 1 only when there is at least one WARNING. INFO alone returns 0 — it is informational, not blocking.
The version guard is deliberately blocking. A baseline sealed across a scan-universe change is not "a bit old" — it reports on a different set of files, and which copy of the skill resolves first decides the answer. One re-seal clears it for good.
Trivial-Change Suppression
To keep the signal-to-noise ratio high, bin/update.js inspects each changed code file with git diff --unified=3 and classifies it before deciding severity:
whitespace-only — added and removed lines are identical after normalizing whitespace. Downgraded to INFO.
comment-only — every added and removed line matches a known comment pattern for the file's extension (e.g. // for .js/.ts/.prisma, # for .py/.yml, <!-- --> for .html, -- for .sql). Downgraded to INFO.
substantive — anything else, including any mix of code + comment changes. Emitted as WARNING.
Unknown extensions default to substantive (safer to over-warn than under-warn on a language the classifier does not know). If your repo uses a language not yet covered, add its comment regex to bin/lib/diff-classify.js (COMMENT_PATTERNS_BY_EXT).
The classifier only downgrades — it never upgrades. A missed classification is a WARNING, not silent suppression.
Known Limitations
bin/update.js mide referencias a paths en .md — no símbolos, ni scripts, ni prosa descriptiva. docs_affected: 0 significa "ningún doc menciona un path del diff", NO "docs al día". Casos no cubiertos:
- Símbolos borrados citados por nombre:
README.md dice "usa chart.js" y el diff elimina chart.js de package.json. El nombre no es un path; el skill no avisa.
- Scripts/comandos en prosa:
CONTRIBUTING.md dice pnpm lint. Si el script cambia (next lint → eslint .), el skill no lo detecta.
- Estado descrito en prosa:
DESIGN.md dice "el dashboard usa chart.js". Sigue prosaicamente válido, pero drift real si la lib desaparece.
- CHANGELOG drift-ahead: el bullet dice "eliminado
X.tsx" pero X.tsx sigue en git ls-files. Cross-check se hace como paso manual en ## Root Invocation Behavior > Flujo steady-state (ver abajo).
Complemento recomendado ante "docs al día" — grep de símbolos/scripts/deps borrados sobre todos los .md:
git diff --name-only <sealed-sha> \
| xargs -I{} basename {} \
| while read f; do grep -l "$f" $(git ls-files '*.md') 2>/dev/null; done \
| sort -u
Extensión opt-in de detección automática de símbolos (--symbols) está trackeada en ROADMAP.md ## Deferred Backlog. Por ahora, prosa y símbolos requieren revisión manual — el skill mide path-drift, no intent-drift.
1---2name: doc-governance-skill3description: Decide doc-impact after meaningful code, config, CI/CD, security, architecture, API, or workflow changes, route updates to the right files, and avoid activation for cosmetic-only or behavior-neutral edits.4---56# Repo Doc Governance78## Purpose9This skill enforces documentation governance with low churn.1011It answers three questions after a meaningful change:121. Does this change require documentation updates?132. Which document should be updated?143. What minimum report should be emitted at completion?1516## How Detection Works (read this before expecting more)1718The skill grep-ea path-refs en backticks / fenced blocks de tus `.md` y los compara contra `git diff --name-only`. Es **substring-matching sobre paths**, no análisis semántico. Un doc que menciona `apps/api/` en prosa se flagea cuando cambia CUALQUIER cosa bajo `apps/api/`. Consecuencias:1920- **Sobre-reporta por diseño.** Un `docs_affected: 0` es señal fuerte ("nada relevante"); un warning requiere triage humano.21- **No detecta prose/symbol drift.** README que dice "usa `chart.js`" no genera warning si borrás `chart.js` del `package.json` (el nombre no es un path). Ver `## Known Limitations` para el complemento manual con grep.22- **Ruido reducible con `.doc-governance/ignore`.** Globs por línea (sintaxis gitignore-lite). Excluye docs enteros (`docs/plans/**`, `Task*.md`) y sus code-refs asociados. Ejemplo commiteable: `templates/doc-governance-ignore.example`.2324## When To Use25Use this skill after a task that may affect maintainers, operators, contributors, or users.2627Trigger examples:28- setup, installation, dependencies, or environment requirements changed29- scripts, commands, CI, build, deploy, or release flow changed30- architecture, module boundaries, data flow, trust boundaries, or contracts changed31- API behavior, request/response shape, or compatibility changed32- auth, authz, secret handling, permissions, exposure, or hardening changed33- contributor workflow, lint/test expectations, or PR policy changed34- troubleshooting, operations, rollback, or recovery workflow changed3536## When NOT To Use37Do not run this skill for behavior-neutral edits:38- formatting-only or comment-only changes39- typo-only fixes without semantic impact40- pure renames with no behavior change41- internal refactors with no user/developer/operator/security impact42- test-only edits that do not change contributor expectations43- temporary debugging changes removed before completion4445## Activation Signals46Common request patterns that should activate this skill.4748**Terminación de sesión (frases naturales, el 80% de los casos):**49- "actualizá los docs" / "actualizá la documentación"50- "update docs" / "update the docs"51- "revisá docs" / "chequeá docs"52- "chequeá qué docs cambiaron"53- "cerrá esta task revisando docs"54- "docs impact?" / "doc impact after this?"5556**Después de un cambio específico (más contexto):**57- "actualizá docs después de estos cambios"58- "update docs after changing CI pipeline"59- "we changed setup/install steps"60- "security/auth flow changed, what docs need updates?"61- "API contract changed, which docs should be updated?"62- "review doc impact before closing this task"6364**Invocación explícita del skill (bypass heuristics):**65- "corré doc-governance-skill"66- "usá el skill de doc governance"67- Slash literal: `/doc-governance-skill:review` (flujo completo) o `/doc-governance-skill:update` (solo drift check)6869## Non-Activation Signals70Common request patterns that should not activate this skill:71- "format this file"72- "fix typos only"73- "rename variable/class only"74- "internal refactor with no behavior change"75- "comment cleanup only"7677## Decision Flow78Run this sequence after completing implementation:791. Inspect changed files and task outcome.802. Determine whether any documentation impact exists.813. Map each impact to the correct document target.824. Update only impacted sections and avoid unrelated rewrites.835. Emit the required minimal completion report.8485## Update Rules86Update docs when at least one is true:871. Setup, dependencies, environment variables, or platform requirements changed.882. Command usage, scripts, CI/CD, build, deploy, or release behavior changed.893. Architecture, integrations, data flow, or API contracts changed.904. Security posture changed (auth/authz/secrets/permissions/exposure/disclosure).915. Agent workflow or repository automation behavior changed.926. Contribution process or quality gates changed.937. Operator runbooks, failure handling, or rollback/recovery changed.948. User-visible behavior changed enough to require release notes or usage docs.9596## Document Routing By Type97Use only the files that match the actual impact:98- `README.md`: setup, usage, safe defaults, common operational commands99- `AGENTS.md`: agent workflow rules and repository automation guidance100- `CLAUDE.md`: Claude-agent-specific instructions and repository conventions (pairs with or replaces `AGENTS.md` in Claude-native repos)101- `CONTRIBUTING.md`: contributor workflow, lint/test expectations, PR standards102- `SECURITY.md`: disclosure process, support policy, hardening-relevant maintainer guidance103- `CHANGELOG.md`: user-visible or operator-visible release-facing changes. Follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) buckets (Added / Changed / Fixed / Removed / Security). Fixes pending release go under `[Unreleased]`; dated sections are cut on release.104- `ARCHITECTURE.md`: system boundaries, component responsibilities, trust/data flow105- `OPERATIONS.md`: deployment, maintenance, backup, rollback, incident handling106- `TROUBLESHOOTING.md`: recurring failures, diagnostics, safe remediation107- `API.md` or `docs/api/**`: API behavior or contract changes108- `docs/**`: deep technical documentation not suitable for top-level docs109- **dep add/remove** (`package.json`, `requirements.txt`, `go.mod`, `Cargo.toml`, etc.): `CHANGELOG.md` + `README.md` (si la dep aparece en setup/install) + el manifest propio110- **script/comando renombrado** (`next lint` → `eslint .`, `npm test` → `vitest`, etc.): `CHANGELOG.md` + `AGENTS.md` / `CONTRIBUTING.md` si documentan comandos111112## Minimal Output Format113At completion, emit exactly this block:114115Action Taken: [README.md | AGENTS.md | CLAUDE.md | CONTRIBUTING.md | SECURITY.md | CHANGELOG.md | ARCHITECTURE.md | OPERATIONS.md | TROUBLESHOOTING.md | API.md | docs/** | Multiple | None]116Justification: [one clear sentence]117Persisted Rule: [rule to append to CLAUDE.md or AGENTS.md if the change reveals a routing or update policy worth carrying forward; else "None"]118119`Persisted Rule` defaults to `None`. Emit a non-None value only when the change reveals a durable policy — e.g. "New CI jobs always update OPERATIONS.md rollback section". The agent applies it by editing `CLAUDE.md` or `AGENTS.md` in the same task.120121### When to emit which format122- **Agent-driven decision flow (manual routing)**: emit the `Action Taken` / `Justification` / `Persisted Rule` block above.123- **Update Mode tool (`bin/update.js`)**: emits the `DOC_GOVERNANCE_UPDATE:` / `SUMMARY:` block automatically. The agent still emits the manual block after acting on the tool's findings.124125## Style Constraints126- Keep output concise and specific.127- Prefer precise, local edits over broad rewrites.128- Do not force documentation updates when impact is absent.129- If multiple documents are impacted, update all relevant ones.130131## Audit Mode132Invoke when the human asks for a documentation map, a repo audit, or uses phrases like "audita la documentación" / "map the docs" / "/audit". This mode is heavy and infrequent — run it once per baseline, not per change.133134Command:135```bash136node .ai/skills/doc-governance-skill/bin/audit.js137```138139Path note: the command assumes the skill installed at `.ai/skills/doc-governance-skill/` (per-repo default from `install.sh`). Adjust to `~/.claude/skills/doc-governance-skill/bin/…` for a global install, or wherever the skill lives in your setup.140141Behavior:142<!-- exclude-dirs:start -->143- Scans every `*.md` in the repo (skipping `.git`, `node_modules`, `dist`, `build`, `.next`, `target`, `vendor`, `.venv`, `venv`, `.doc-governance`, `.ai`, `.agents`, `.claude`, `graphify-out`), plus anything matched by `.doc-governance/ignore`.144<!-- exclude-dirs:end -->145- For each doc, records: title (first H1), heading tree (H1–H3), and detected code refs (paths in backticks + fenced blocks annotated with `path=`).146- Writes `.doc-governance/map.md`, sealed with the current `git HEAD` SHA, an ISO 8601 timestamp, and the `tool_version:` that sealed it.147- Records `sealed_dirty:` — every path whose worktree content differs from `HEAD` at seal time, with its content hash. The scan reads the **worktree** while `sealed_sha` names **HEAD**, so without this the next run reports the reseal's own commit as drift.148- Exit 0 on success, 1 on I/O or git error.149150The line above is generated from `EXCLUDE_DIRS` in `bin/lib/scan.js` by `bin/lib/sync-exclude-dirs.js`; CI runs it with `--check`. Edit the code, not the prose.151152After running audit, commit `.doc-governance/map.md`. It is the shared baseline the update mode diffs against.153154## Update Mode155Invoke when the human asks for a doc-drift check, uses phrases like "update docs" / "actualizá la documentación" / "/update", or after finishing a meaningful change. This mode is lightweight — safe to run per task.156157Command:158```bash159node .ai/skills/doc-governance-skill/bin/update.js160```161162Path note: same as Audit Mode — adjust the path to your install location.163164Optional overrides:165- `--since <ref>` — diff against a specific git ref instead of the sealed SHA.166- `--files a,b,c` — explicit file list, skip git diff entirely.167- stdin — accepts one path per line (e.g. `git diff --name-only | node .../update.js`).168169Behavior:170- If `.doc-governance/map.md` is missing, auto-creates it by scanning the repo and sealing to current `git HEAD` (see `## First Run / No Baseline` below).171- Reads `.doc-governance/map.md`, extracts the sealed SHA, the `tool_version:` and the `sealed_dirty:` set.172- Compares the baseline's `tool_version:` against its own. A mismatch that crosses a version where the scanned file set changed is a **Warning** — the baseline is not merely stale, it maps a different universe of files.173- Runs `git diff --name-only <sealed_sha>` (working-tree comparison → catches committed + uncommitted).174- Drops any changed path whose content still matches `sealed_dirty:` down to Info (`carried_from_seal`) — the baseline scan already saw those bytes. Skipped under `--since` / `--files` / stdin, where the baseline is a different ref.175- Cross-references the remaining changed paths against `code_refs` in the map.176- Emits a `DOC_GOVERNANCE_UPDATE:` block with three severity tiers (Critical / Warning / Info) and a `SUMMARY:` line.177- Exit 0 clean or Info-only, 1 with any Warning or Critical finding.178179For each `code_file: <path>` in the emitted Warning list, use the routing table in `## Document Routing By Type` above to decide whether the docs named in its `affected_docs:` are the right target — the audit tool detects references, not intent.180181## First Run / No Baseline182On the first invocation in a repo without `.doc-governance/map.md`:183- Update Mode auto-creates the map sealed to current `git HEAD` and emits an `Info: baseline_auto_sealed` entry.184- Exit 0 is expected — nothing has changed against a baseline sealed a moment ago.185- Commit `.doc-governance/map.md`. Subsequent runs diff against that SHA.186187To seal a baseline explicitly (larger repos, CI-driven bootstrap), run `audit.js` first — behavior is identical.188189## Root Invocation Behavior190191Este flujo aplica cuando el skill se activa — sea por slash (`/doc-governance-skill:review`) o por intent phrasing ("actualizá docs", "revisá qué docs cambiaron", etc.).192193### Cold-start guard — chequeá esto ANTES de nada194195Verificá si existe `.doc-governance/map.md` en el repo actual:196197```bash198test -f .doc-governance/map.md && echo "map exists" || echo "no map"199```200201**Si "no map"** (primer uso en este repo): NO sigas con los pasos 1-4 de abajo. Hacé exactamente esto:2022031. Ubicá el skill root — **este bloque es la fuente canónica; los slash-commands apuntan acá, no lo dupliques**:204205 ```bash206 ROOT=$(find ~/.claude/plugins/cache/*/doc-governance-skill -name 'SKILL.md' -not -path '*/node_modules/*' 2>/dev/null | head -1 | xargs -r dirname)207 [ -n "$ROOT" ] || ROOT=~/.claude/skills/doc-governance-skill208 SKILL_ROOT=$(node "$ROOT/bin/which.js" 2>/dev/null) || SKILL_ROOT=$ROOT209 ```210211 El primer paso es barato y deliberadamente tonto: sólo necesita encontrar *alguna* copia. La elección la hace `bin/which.js`, que enumera todas las instalaciones y devuelve **la de versión más alta**. Antes se usaba `find … | head -1` a secas, que devuelve lo primero que lista el filesystem — con dos copias conviviendo eso es una moneda al aire, y es el mecanismo exacto del incidente que motivó 0.9.0. Si la copia hallada es anterior a 0.9.1 y no tiene `which.js`, el `||` preserva el comportamiento viejo.212213 Ante cualquier duda sobre qué copia está corriendo: `node "$SKILL_ROOT/bin/which.js" --verbose` lista todas con su versión y avisa si conviven varias.2142. Corré `node "$SKILL_ROOT/bin/audit.js"`.2153. Emitir mensaje corto al user:216 > Baseline sellado en `.doc-governance/map.md` (SHA `<sha>`, N docs mapeados).217 > Commiteá: `git add .doc-governance/map.md && git commit -m "chore: seal doc-governance baseline"`218 > Después re-invocáme para el flujo completo.2194. **STOP**. No hay drift para reportar en un baseline recién sellado — ejecutar el flujo agentic completo acá sería caro y no aportaría valor.220221**Si "map exists"**: seguí con el flujo abajo.222223### Flujo steady-state2242251. **Corré el flujo manual completo**: inspeccionar cambios, decidir routing usando `## Document Routing By Type`, editar los docs impactados, emitir el bloque `Action Taken` / `Justification` / `Persisted Rule`.2262272. **Cross-check CHANGELOG "Unreleased"** (previene drift-ahead — CHANGELOG que miente sobre el estado del working tree):228229 - Localizá la sección `[Unreleased]` / `[Sin publicar]` en `CHANGELOG.md`.230 - Bajo `### Removed` / `### Removido`, extraé cada backtick-token con extensión de archivo (`X.tsx`, `path/Y.ts`, `lib/Z.js`).231 - Para cada token, verificá con `git ls-files -- <path>`. Si devuelve el path (el archivo sigue tracked) pero el bullet dice "eliminado" → warning `changelog_drift_ahead`.232 - Corregí el bullet (o restaurá el archivo, según la intent real) ANTES de emitir el bloque `Action Taken`.233234 Este check compensa la limitación documentada en `## Known Limitations`: el skill mide path-refs del diff, no valida coherencia interna del CHANGELOG.2352363. **Ofrecé re-sellar el baseline (una línea)**: emitir literal `Reseleo baseline? [Y/n]` y esperar respuesta.237238 - Enter / `y` / `yes` / `sí` → correr `node <skill-root>/bin/audit.js`, avisar `Baseline re-sellado (SHA <short>, N docs). Incluí .doc-governance/map.md en tu próximo commit.`239 - `n` / `no` → cerrar sin acción.240241 Desde 0.9.0 el commit que lleva el map re-sellado **no** genera drift sobre sí mismo: `audit.js` registra en `sealed_dirty:` el contenido de todo lo que estaba sin commitear al momento del sello, y `update.js` lo baja a INFO (`carried_from_seal`) mientras siga idéntico. No hace falta commitear el map aparte ni en un orden particular.242243 Skip enteramente la pregunta si el flujo se disparó desde `/doc-governance-skill:update` (drift check puro, no toca baseline) o si el user pasó `--no-seal` / "no reseales" en el mensaje original.244245 Regla de oro: la skill empodera al user, no lo reemplaza. La pregunta es corta pero explícita — nunca correr audit sin confirmación.246247## Drift Categories Monitored248249| Severity | Trigger | Suggested Action |250|---|---|---|251| Critical | Reserved (future: semantic mismatch, anchor removed, deleted-file referenced) | Not emitted yet. |252| Warning | Code path referenced by a doc changed **substantively** since the sealed SHA. One entry per changed code file (not per doc), with `affected_docs:` and a 2-3 line `diff_sample:`. | Review the doc sections listed in `affected_docs:` that mention the changed path; update or confirm still accurate. |253| Warning | `baseline_version_drift` where the gap between the baseline's `tool_version:` and the running tool crosses a version that changed which files get scanned. | Re-seal. Until then the report covers a different file set than the repo actually has, and two installed copies of the skill will disagree. |254| Info | `baseline_version_drift` with no scan-universe change crossed, or `baseline_version_unknown` (header has no parseable version). | Re-seal when convenient; results are still comparable. |255| Info | `carried_from_seal` — a changed path whose content is byte-identical to what the baseline scan already saw. | None. This is the reseal's own commit, already accounted for. |256| Info | Trivial change (whitespace-only or comment-only) on a referenced path; rename detected (`renamed: A -> B`); `.md` files changed since sealed SHA (map may be stale); auto-bootstrapped baseline. | Depends on subtype — see `suggested_action:` on each entry. |257258Exit code: `1` only when there is at least one WARNING. INFO alone returns `0` — it is informational, not blocking.259260The version guard is deliberately blocking. A baseline sealed across a scan-universe change is not "a bit old" — it reports on a different set of files, and which copy of the skill resolves first decides the answer. One re-seal clears it for good.261262## Trivial-Change Suppression263264To keep the signal-to-noise ratio high, `bin/update.js` inspects each changed code file with `git diff --unified=3` and classifies it before deciding severity:265266- **`whitespace-only`** — added and removed lines are identical after normalizing whitespace. Downgraded to INFO.267- **`comment-only`** — every added and removed line matches a known comment pattern for the file's extension (e.g. `//` for `.js/.ts/.prisma`, `#` for `.py/.yml`, `<!-- -->` for `.html`, `--` for `.sql`). Downgraded to INFO.268- **`substantive`** — anything else, including any mix of code + comment changes. Emitted as WARNING.269270Unknown extensions default to `substantive` (safer to over-warn than under-warn on a language the classifier does not know). If your repo uses a language not yet covered, add its comment regex to `bin/lib/diff-classify.js` (`COMMENT_PATTERNS_BY_EXT`).271272The classifier only downgrades — it never upgrades. A missed classification is a WARNING, not silent suppression.273274## Known Limitations275276`bin/update.js` mide **referencias a paths** en `.md` — no símbolos, ni scripts, ni prosa descriptiva. `docs_affected: 0` significa "ningún doc menciona un path del diff", NO "docs al día". Casos no cubiertos:277278- **Símbolos borrados citados por nombre**: `README.md` dice "usa `chart.js`" y el diff elimina `chart.js` de `package.json`. El nombre no es un path; el skill no avisa.279- **Scripts/comandos en prosa**: `CONTRIBUTING.md` dice `pnpm lint`. Si el script cambia (`next lint` → `eslint .`), el skill no lo detecta.280- **Estado descrito en prosa**: `DESIGN.md` dice "el dashboard usa chart.js". Sigue prosaicamente válido, pero drift real si la lib desaparece.281- **CHANGELOG drift-ahead**: el bullet dice "eliminado `X.tsx`" pero `X.tsx` sigue en `git ls-files`. Cross-check se hace como paso manual en `## Root Invocation Behavior > Flujo steady-state` (ver abajo).282283**Complemento recomendado ante "docs al día"** — grep de símbolos/scripts/deps borrados sobre todos los `.md`:284285```bash286git diff --name-only <sealed-sha> \287 | xargs -I{} basename {} \288 | while read f; do grep -l "$f" $(git ls-files '*.md') 2>/dev/null; done \289 | sort -u290```291292Extensión opt-in de detección automática de símbolos (`--symbols`) está trackeada en `ROADMAP.md ## Deferred Backlog`. Por ahora, prosa y símbolos requieren revisión manual — el skill mide path-drift, no intent-drift.