docsync — track and fix doc drift
Caution
Docs go stale the moment code moves on. Nobody remembers to re-read SKILL.md after a refactor, and a forgotten README.md means the next session starts from wrong assumptions. Manual checks don’t scale across dozens of files.
Tip
Frontmatter is the source of truth — no separate ledger. Docsync installs three project-local hooks that quietly record which .md files you read or edit. At the end of a turn, if any touched doc is stale by its own last_updated date, it nags once and asks whether to sync. Replaces brewdoc:auto-sync.
Quick reference
| Field | Value |
|---|---|
| Command | /brewdoc:docsync [mode] |
| Arguments | init · status · sync [--all] · reread · frontmatter · uninstall · free text (RU/EN) |
| Model | sonnet |
| Tools | Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion |
When to use
| Scenario | Command |
|---|---|
| First time in a project — set up staleness tracking | /brewdoc:docsync (empty + not installed → init) |
| Check what’s tracked and what’s stale, no changes | /brewdoc:docsync status |
| Refresh stale docs after confirming which ones | /brewdoc:docsync sync |
| Force a full resync of every in-scope doc | /brewdoc:docsync sync --all |
| Reload tracked docs into context without editing | /brewdoc:docsync reread |
| Retro-add tracking frontmatter to existing docs | /brewdoc:docsync frontmatter |
| Remove the tracker without touching foreign hooks | /brewdoc:docsync uninstall |
Examples
# First run in a project — asks threshold + excludes, installs 3 hooks
/brewdoc:docsync
# Natural language also works, RU or EN
"что устарело в документации"
"track doc staleness in this project"
"docsync status"
status prints an age table per tracked doc:
## Status
| Doc | doc_type | last_updated | age | state |
|-----|----------|--------------|-----|-------|
| README.md | user | 2026-07-01 | 18d | stale |
| SKILL.md | llm | 2026-07-17 | 2d | fresh |
| CHANGELOG.md | skip | — | — | excluded |
Flow
- Resolve mode
Free text in RU or EN maps to a mode (
init,status,sync,reread,frontmatter,uninstall). Empty input picksinitwhen hooks aren’t installed yet, otherwisestatus. - Install (once)
initasks for a staleness threshold (default 7 days) and exclude globs, copies the 3 hooks into.claude/hooks/, writes.claude/docsync/config.json, and idempotently merges.claude/settings.json— always backed up to.bakfirst. It never adds frontmatter to your docs. - Track silently
From the next session on,
docsync-track.mjs(PostToolUse onWrite|Edit|MultiEdit) anddocsync-watch.mjs(PostToolUse onRead) record every.mdfile touched during a session — no output, no interruption. - Nag once
At
Stop,docsync-gate.mjschecks touched docs against their ownlast_updatedfrontmatter. If any is older thanthreshold_days, it blocks the turn once and tells Claude to ask about syncing. - Sync on confirmation
/brewdoc:docsync synclists the stale set, asks viaAskUserQuestion, then refreshes each confirmed doc per its ownsync_procedureand bumpslast_updatedto today. Compression depth followsdoc_type:llm= deep,user= light.
Internals
Frontmatter schema — every tracked .md carries its own state, no separate registry:
---
doc_type: llm # optional; absent => user. values: llm | user | skip
last_updated: 2026-07-19 # sole staleness input (YYYY-MM-DD, LOCAL time)
sync_procedure: "what to check / where to look when syncing" # optional, prose
---Staleness is DATE ONLY: today - last_updated > threshold_days. No hashing, no depends_on graph. doc_type: skip excludes a file entirely.
The three hooks
| File | Event | Matcher | Action |
|---|---|---|---|
docsync-track.mjs | PostToolUse | Write|Edit|MultiEdit | Records touched .md; nudges to add last_updated when missing |
docsync-watch.mjs | PostToolUse | Read | Records touched .md (silent) |
docsync-gate.mjs | Stop | — | Blocks once if a touched doc is stale; tells Claude to ask about syncing |
Hooks are self-contained ESM (Node built-ins only), read state from .claude/docsync/ at runtime, and take effect starting the next session.
State / config — .claude/docsync/:
config.json—{ "threshold_days": 7, "exclude": ["node_modules/**", ...] }state.json—{ "session_id": "...", "touched": [], "asked": false }(hook-managed, resets per session)
Scope — all *.md in the project minus exclude globs and any file marked doc_type: skip. Only docs actually read or edited in a session are candidates for the end-of-turn nag; untouched docs are never nagged.
Uninstall removes only the 3 docsync hook entries from settings.json (foreign entries preserved), deletes the 3 hook files, and asks separately whether to drop .claude/docsync/.
Memory
Interactively compact and optimize memory files — pairs well with keeping docs fresh.
GitHub source
Source code, hook assets, and full SKILL.md for docsync.
Brewdoc overview
All brewdoc skills in one place.
Updating plugins
/brewtools:plugin-update to check and update the brewcode plugin suite in one command.
See the FAQ for details.