doc-canon
v0.10.0
Published
Deterministic canon CLI for agent documentation
Maintainers
Readme
doc-canon
Deterministic CLI for agent documentation canon: scaffold, validate, report, index, and search structured docs under docs/canon with managed skills for Cursor and Claude Code.
Why
Ad-hoc agent docs drift from code, contradict each other, and diverge in shape when different LLMs edit them. Teams need a durable canon: what docs exist, how they are shaped, how they stay current, and how docs↔code conflicts are resolved with a human in the loop.
Goals
- Keep agent-facing project docs accurate, consistent, and non-contradictory.
- Treat
docs/canon/as the source of truth for agent context; when docs and code disagree, the user decides which is stale. - Let skills edit documentation automatically; never patch application code — emit tasks for coding agents instead.
- Keep document structure stable across LLMs via in-repo templates and a per-project contract.
- Ship Cursor and Claude Code overlays by default; keep the CLI IDE-agnostic so additional agents can plug in later.
MVP does not include IDE UIs, automatic code patches, or CI/git hooks as the everyday sync trigger. Details: docs/canon/OVERVIEW.md.
Install
npm install -g doc-canon
# or one-shot:
npx doc-canon --helpRequires Node.js ≥ 22.16 (the built-in node:sqlite store used by code-index).
From this repository (development):
npm install
npm link # optional: put doc-canon on PATH for local developmentQuick start flows
Short recipes. Full walkthroughs: docs/guides/usage-flows.md.
Empty project
- Install and ensure
doc-canonis onPATH doc-canon init --yes(or interactivedoc-canon init)- In Cursor or Claude Code, run skill
canon-bootstrap(purpose/scope interview, fill canon) doc-canon validate(must pass)
Existing project
doc-canon initat the repo root (does not overwrite existing canon document content)- Run
canon-bootstrap— extract-then-freeze; legacy docs are import sources only; application code is not edited - Confirm any proposed extra sections / contract changes when prompted
doc-canon validate
Day-to-day
- After meaningful code or canon edits, run
canon-writeto sync affected sections (skills reindex withdoc-canon indexafter substantive canon writes) doc-canon check— inventory +.doc-canon/report.json- On docs↔code drift, run
canon-audit(docs_staleorcode_stale) - Optionally
doc-canon reportto print the last report; agents/skills usedoc-canon searchfor a bounded working set
Usage
All commands accept --root <path> (default: current directory) to target a repo root. Behavior SoT: docs/canon/CLI.md.
init
Scaffold docs/canon/, mandatory templates, default contract, and managed harness overlays — Cursor, Claude Code, and DSH (.cursor/skills, .claude/skills, .dsh/skills, .cursor/rules/doc-canon.mdc, short AGENTS.md block, full-body CLAUDE.md). On a TTY init asks which harnesses to install (checkbox, all checked by default); --harnesses cursor,claude,dsh picks an exact set; --yes / non-TTY installs all three.
doc-canon init
doc-canon init --root /path/to/repo
doc-canon init --force-skills # refresh managed assets on re-init
doc-canon init --yes # install all harnesses, ask nothing
doc-canon init --harnesses dsh # install only the DSH skill tree
doc-canon init --harnesses cursor,dsh # comma-separated selectionvalidate
Schema and structure validation only (exit non-zero on errors).
doc-canon validate
doc-canon validate --root /path/to/repo
doc-canon validate --json # machine-readable issue report--json prints a structured issue report: {schema_version: 1, ok, issues: [{message, kind, paths, severity}]} — no English-message parsing needed.
check
Validate, build a language-agnostic inventory, and write .doc-canon/report.json.
doc-canon check
doc-canon check --root /path/to/reporeport
Print the last .doc-canon/report.json to stdout.
doc-canon report
doc-canon report --root /path/to/repodiscipline
Report probe discipline: reads .doc-canon/probe-log.jsonl (last doc/code probe age, probe count) plus the index manifests (files changed since each probe). Exits ≠0 when an index exists and relevant files changed after the last probe of that kind (un-probed state). Missing index or never-probed fresh clone → not-applicable, exit 0.
doc-canon discipline
doc-canon discipline --root /path/to/repo
doc-canon discipline --jsonupgrade-skills
Refresh managed skills, Cursor rule, AGENTS.md, and CLAUDE.md overlays without touching canon content. Refreshes the skill trees of the harnesses already present in the repo (.cursor/skills, .claude/skills, .dsh/skills); on a TTY it additionally offers the missing harnesses. --harnesses cursor,claude,dsh overrides the detected set; --yes / non-TTY never prompts. Also migrates existing repos onto the required future_plans/INDEX.md skeleton when missing.
doc-canon upgrade-skills
doc-canon upgrade-skills --root /path/to/repo
doc-canon upgrade-skills --harnesses dshmigrate
Bring an existing canon up to this CLI: create missing required files/templates listed in that repo’s CANON_CONTRACT.md, add missing INDEX Sections rows, then run upgrade-skills. Does not rewrite section prose and does not add default sections the contract omitted. Empty repos should use init, not migrate. Harness handling follows upgrade-skills (refresh present harnesses, offer missing ones on a TTY, --harnesses to override).
# global install (doc-canon on PATH):
doc-canon migrate
doc-canon migrate --root /path/to/repo
doc-canon migrate --harnesses cursor,claude
# one-shot npx (no global install):
npx doc-canon migrate --root .When to use upgrade-skills vs migrate
- After
npm install -g doc-canon@…: rundoc-canon migrateon each target repo. - After a one-shot
npx doc-canon@…: runnpx doc-canon migrate --root .(baredoc-canonis not on PATH). - If the contract is already
schema_version: 1and you only need managed overlays /skills_stamp:upgrade-skillsis enough. schema_versionother than1fails closed; this CLI does not rewrite contract YAML.
Soft coupling: changes to managed skills/rules bump both npm version and skills_stamp. A CLI-only bugfix may bump npm patch without a stamp bump. Validate still fails closed on a too-old stamp (upgrade-skills / migrate to refresh).
index
Build or refresh the local BM25 index over docs/canon/**/*.md (writes .doc-canon/index-manifest.json and .doc-canon/bm25-index.json). One-shot exits non-zero if a watch process is already running.
doc-canon index
doc-canon index --root /path/to/repo
doc-canon index --watch # poll and keep the index in sync (default 2000 ms)
doc-canon index --watch --interval 500 # custom poll interval (ms, min 200)
doc-canon index --stop # stop a running --watch processsearch
Search the existing BM25 index and print a bounded context pack (ranked paths, scores, live-file snippets). A stale index is self-healed at the CLI layer when no watch owns it (rebuild then serve, auto_reindexed warning); with a live watch, stale is served with exit 0 and an index_stale warning. Missing/corrupt index → exit ≠0 with a hint to run doc-canon index. Every successful search appends a line to .doc-canon/probe-log.jsonl.
doc-canon search "CLI commands"
doc-canon search "working set" --json
doc-canon search "BM25" --max-hits 5 --snippet-lines 6
doc-canon search "topic" --root /path/to/repocode-index build
Build or refresh the local AST index over the project's discovered source roots (writes .doc-canon/code-index-manifest.json and .doc-canon/code-ast-index.sqlite). Covers TypeScript/JavaScript, Go, C#, Rust, and Python via pinned tree-sitter WASM grammars. One-shot exits non-zero if a watch process is already running. Same --watch / --interval / --stop discipline as index, with a separate watch pid.
doc-canon code-index build
doc-canon code-index build --root /path/to/repo
doc-canon code-index build --watch # poll and keep the index in sync (default 2000 ms)
doc-canon code-index build --watch --interval 500 # custom poll interval (ms, min 200)
doc-canon code-index build --stop # stop a running watch processcode-index search
Search the code AST index and print a bounded code pack (symbol or syntactic-reference hits with live-file snippets). A stale index is self-healed at the CLI layer when no watch owns it (rebuild then serve, auto_reindexed warning); with a live watch, stale is served with exit 0 and a code_index_stale warning. Missing/corrupt index → exit ≠0 with a hint to run doc-canon code-index build. Every successful search appends a line to .doc-canon/probe-log.jsonl.
Symbol mode (positional query): every query token must be a case-insensitive substring of the symbol name (or, falling back, the signature). Ordering: exact name > name prefix > name tokens > signature tokens, tie-break file then line. Filters --kind <type> and --file <glob> narrow the scan; --body widens the snippet window to the symbol's endLine (symbol mode only).
Refs mode (--refs <name>): exact, case-sensitive match over syntactic references — anchor (same-file usage), import (cross-file edges, incl. call-site edges and Class.method member-access edges for new Type()-initialized bindings), and binding (in-scope locals).
doc-canon code-index search "searchCanon" # symbol mode: find the declaration
doc-canon code-index search "search code index" # multi-token: every token matches name/signature
doc-canon code-index search --refs "searchCanon" # refs mode: import + call-site edges
doc-canon code-index search --refs "Reader.score" # member-access edge (Class.method)
doc-canon code-index search "Reader" --kind class # filter by symbol kind
doc-canon code-index search "search" --file "src/**" # filter by file glob
doc-canon code-index search "searchCanon" --body # widen symbol-mode window to endLine
doc-canon code-index search --refs "searchCanon" --json # machine-readable pack
doc-canon code-index search "Reader" --max-hits 5 --snippet-lines 6
doc-canon code-index search "topic" --root /path/to/repoAgent skills
Managed skills (canon-bootstrap, canon-write, canon-audit, canon-contract, canon-future-plan) invoke doc-canon subprocesses. doc-canon must be on PATH (e.g. via npm link, global install, or CI npm install -g .).
init / upgrade-skills install identical skill trees under the selected harnesses' skill roots — .cursor/skills/, .claude/skills/, and .dsh/skills/ (DSH — the DeepSeek Harness — discovers skills under .dsh/skills/). Cursor always-on guidance is .cursor/rules/doc-canon.mdc plus the short AGENTS.md block; Claude Code uses full pointer-rule body in CLAUDE.md and does not load .cursor/rules/; DSH loads the same always-on guidance from both AGENTS.md and CLAUDE.md and needs no dedicated rule file. Selection: interactive checkbox on a TTY, --harnesses cursor,claude,dsh, or installed-harness detection on upgrade-skills / migrate.
Adopter CI
Recommended gate is doc-canon validate (structure only). check is optional. Do not fail CI on open DISCREPANCIES.md entries.
# example for an adopter repository — not used in the doc-canon repo itself
name: canon
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- run: npm install -g doc-canon
- run: doc-canon validateSpec and acceptance
- Design spec:
docs/superpowers/specs/2026-08-07-doc-first-canon-design.md - Skill acceptance scenarios:
docs/acceptance/skill-scenarios.md
Development
npm run build
npm test
node bin/doc-canon.js --help
DRY_RUN=1 npm run release # test, build, validate, pack-check; no publish
# a real `npm run release` also creates and pushes a `v<version>` git tagdoc-canon (RU)
Детерминированный CLI для канона агентской документации: создание каркаса, валидация, отчёты, индекс и поиск по структурированным документам в docs/canon с управляемыми skills для Cursor и Claude Code.
Зачем
Ad-hoc документация для агентов устаревает относительно кода, противоречит сама себе и расходится по форме, когда её правят разные LLM. Командам нужен устойчивый канон: какие документы есть, какой у них shape, как они остаются актуальными и как конфликты docs↔code разрешаются с человеком в контуре.
Цели
- Держать проектную документацию для агентов точной, согласованной и без внутренних противоречий.
- Считать
docs/canon/источником истины для агентского контекста; при расхождении docs и кода пользователь решает, что устарело. - Дать skills автоматически править документацию; никогда не патчить код приложения — вместо этого писать задачи для coding-агентов.
- Держать структуру документов стабильной между разными LLM через шаблоны в репозитории и per-project контракт.
- Поставлять оверлеи Cursor и Claude Code по умолчанию; CLI оставить IDE-agnostic, чтобы позже подключать других агентов.
В MVP нет IDE UI, автоматических патчей кода и CI/git hooks как повседневного триггера синхронизации. Подробности: docs/canon/OVERVIEW.md.
Установка
npm install -g doc-canon
# или одноразово:
npx doc-canon --helpТребуется Node.js ≥ 22.16 (встроенный node:sqlite для хранения code-index).
Из этого репозитория (разработка):
npm install
npm link # опционально: добавить doc-canon в PATH для локальной разработкиБыстрый старт по флоу
Короткие рецепты. Подробные walkthrough: docs/guides/usage-flows.md.
Пустой проект
- Установите и убедитесь, что
doc-canonесть вPATH doc-canon init --yes(или интерактивныйdoc-canon init)- В Cursor или Claude Code запустите skill
canon-bootstrap(интервью purpose/scope, заполнение канона) doc-canon validate(должно пройти)
Существующий проект
doc-canon initв корне репозитория (не перезаписывает уже существующее содержимое канона)- Запустите
canon-bootstrap— extract-then-freeze; legacy docs только как import sources; код приложения не редактируется - Подтвердите предложенные extra sections / изменения контракта, если спросят
doc-canon validate
Повседневный цикл
- После заметных правок кода или канона запустите
canon-write, чтобы синхронизировать затронутые секции (после substantive-правок канона skills делаютdoc-canon index) doc-canon check— inventory +.doc-canon/report.json- При drift docs↔code запустите
canon-audit(docs_staleилиcode_stale) - Опционально
doc-canon report, чтобы напечатать последний отчёт; агенты/skills используютdoc-canon searchдля ограниченного working set
Использование
Все команды принимают --root <path> (по умолчанию: текущая директория) для указания корня репозитория. SoT по поведению: docs/canon/CLI.md.
init
Создаёт каркас docs/canon/, обязательные шаблоны, контракт по умолчанию и управляемые оверлеи для харнессов — Cursor, Claude Code и DSH (.cursor/skills, .claude/skills, .dsh/skills, .cursor/rules/doc-canon.mdc, короткий блок AGENTS.md, полный body в CLAUDE.md). На TTY init спрашивает, какие харнессы установить (чекбокс, все отмечены по умолчанию); --harnesses cursor,claude,dsh задаёт точный набор; --yes / не-TTY ставит все три.
doc-canon init
doc-canon init --root /path/to/repo
doc-canon init --force-skills # обновить управляемые ассеты при повторном init
doc-canon init --yes # установить все харнессы, без вопросов
doc-canon init --harnesses dsh # установить только дерево скиллов DSH
doc-canon init --harnesses cursor,dsh # выбор через запятуюvalidate
Только валидация схемы и структуры (ненулевой код выхода при ошибках).
doc-canon validate
doc-canon validate --root /path/to/repo
doc-canon validate --json # machine-readable отчёт об ошибках--json печатает структурированный отчёт об ошибках: {schema_version: 1, ok, issues: [{message, kind, paths, severity}]} — парсинг английских сообщений не нужен.
check
Валидация, построение языконезависимого инвентаря и запись .doc-canon/report.json.
doc-canon check
doc-canon check --root /path/to/reporeport
Печать последнего .doc-canon/report.json в stdout.
doc-canon report
doc-canon report --root /path/to/repodiscipline
Отчёт о дисциплине поиска (probe discipline): читает .doc-canon/probe-log.jsonl (возраст последнего doc/code probe, число probe) плюс манифесты индексов (файлы, изменённые после каждого probe). Завершается с кодом ≠0, когда индекс существует и релевантные файлы изменились после последнего probe этого вида (un-probed состояние). Нет индекса или свежий клон без probe → not-applicable, exit 0.
doc-canon discipline
doc-canon discipline --root /path/to/repo
doc-canon discipline --jsonupgrade-skills
Обновление управляемых skills, Cursor rule, AGENTS.md и CLAUDE.md без изменения содержимого канона. Обновляет деревья скиллов тех харнессов, которые уже есть в репозитории (.cursor/skills, .claude/skills, .dsh/skills); на TTY дополнительно предлагает отсутствующие. --harnesses cursor,claude,dsh перекрывает обнаруженный набор; --yes / не-TTY никогда не спрашивает. Также мигрирует существующие репозитории на обязательный каркас future_plans/INDEX.md, если его ещё нет.
doc-canon upgrade-skills
doc-canon upgrade-skills --root /path/to/repo
doc-canon upgrade-skills --harnesses dshmigrate
Подтянуть существующий канон до этого CLI: создать отсутствующие обязательные файлы/шаблоны, перечисленные в CANON_CONTRACT.md целевого репозитория, добавить отсутствующие строки Sections в INDEX, затем выполнить upgrade-skills. Не переписывает прозу секций и не добавляет секции по умолчанию, которых нет в контракте. Пустые репозитории должны использовать init, а не migrate. Харнессы обрабатываются как в upgrade-skills (обновить присутствующие, предложить отсутствующие на TTY, --harnesses для переопределения).
# глобальная установка (doc-canon в PATH):
doc-canon migrate
doc-canon migrate --root /path/to/repo
doc-canon migrate --harnesses cursor,claude
# one-shot npx (без глобальной установки):
npx doc-canon migrate --root .Когда использовать upgrade-skills vs migrate
- После
npm install -g doc-canon@…: запускайтеdoc-canon migrateв каждом целевом репозитории. - После one-shot
npx doc-canon@…: запускайтеnpx doc-canon migrate --root .(голыйdoc-canonне в PATH). - Если контракт уже
schema_version: 1и нужны только управляемые оверлеи /skills_stamp: достаточноupgrade-skills. schema_versionотличный от1завершается fail-closed; этот CLI не переписывает YAML контракта.
Мягкая связка: изменения управляемых skills/rules поднимают и npm-версию, и skills_stamp. Багфикс только CLI может поднять npm patch без bump stamp. Validate по-прежнему fail-closed на слишком старом stamp (upgrade-skills / migrate, чтобы обновить).
index
Сборка или обновление локального BM25-индекса по docs/canon/**/*.md (пишет .doc-canon/index-manifest.json и .doc-canon/bm25-index.json). One-shot завершается с ненулевым кодом, если уже запущен watch.
doc-canon index
doc-canon index --root /path/to/repo
doc-canon index --watch # опрос и поддержание индекса (по умолчанию 2000 мс)
doc-canon index --watch --interval 500 # свой интервал опроса (мс, мин. 200)
doc-canon index --stop # остановить запущенный --watchsearch
Поиск по существующему BM25-индексу и печать ограниченного context pack (ранжированные пути, scores, сниппеты из живых файлов). Устаревший индекс самовосстанавливается на уровне CLI, когда его не держит watch (пересборка и выдача с предупреждением auto_reindexed); при живом watch устаревший индекс отдаётся с exit 0 и предупреждением index_stale. Нет/битый индекс → exit ≠0 с подсказкой doc-canon index. Каждый успешный поиск дописывает строку в .doc-canon/probe-log.jsonl.
doc-canon search "CLI commands"
doc-canon search "working set" --json
doc-canon search "BM25" --max-hits 5 --snippet-lines 6
doc-canon search "topic" --root /path/to/repocode-index build
Сборка или обновление локального AST-индекса по обнаруженным source-roots проекта (пишет .doc-canon/code-index-manifest.json и .doc-canon/code-ast-index.sqlite). Покрывает TypeScript/JavaScript, Go, C#, Rust и Python через закреплённые tree-sitter WASM-грамматики. One-shot завершается с ненулевым кодом, если уже запущен watch. Та же дисциплина --watch / --interval / --stop, что и у index, но с отдельным watch-pid.
doc-canon code-index build
doc-canon code-index build --root /path/to/repo
doc-canon code-index build --watch # опрос и поддержание индекса (по умолчанию 2000 мс)
doc-canon code-index build --watch --interval 500 # свой интервал опроса (мс, мин. 200)
doc-canon code-index build --stop # остановить запущенный watchcode-index search
Поиск по кодовому AST-индексу и печать ограниченного code pack (хиты по символам или синтаксическим ссылкам со сниппетами из живых файлов). Устаревший индекс самовосстанавливается на уровне CLI, когда его не держит watch (пересборка и выдача с предупреждением auto_reindexed); при живом watch устаревший индекс отдаётся с exit 0 и предупреждением code_index_stale. Нет/битый индекс → exit ≠0 с подсказкой doc-canon code-index build. Каждый успешный поиск дописывает строку в .doc-canon/probe-log.jsonl.
Symbol-режим (позиционный запрос): каждый токен запроса должен быть case-insensitive подстрокой имени символа name (или, как запасной вариант, signature). Ранжирование: точное имя > префикс имени > токены в имени > токены в сигнатуре, tie-break по файлу, затем строке. Фильтры --kind <type> и --file <glob> сужают сканирование; --body расширяет сниппет-окно до endLine символа (только symbol-режим).
Refs-режим (--refs <name>): точное, case-sensitive совпадение по синтаксическим ссылкам — anchor (использование в том же файле), import (межфайловые эджи, включая call-site эджи и member-access эджи Class.method для привязок из new Type()), и binding (локальные переменные в области видимости).
doc-canon code-index search "searchCanon" # symbol-режим: найти объявление
doc-canon code-index search "search code index" # мультитокенный: каждый токен матчится в name/signature
doc-canon code-index search --refs "searchCanon" # refs-режим: import + call-site эджи
doc-canon code-index search --refs "Reader.score" # member-access эдж (Class.method)
doc-canon code-index search "Reader" --kind class # фильтр по виду символа
doc-canon code-index search "search" --file "src/**" # фильтр по glob файла
doc-canon code-index search "searchCanon" --body # расширить окно symbol-режима до endLine
doc-canon code-index search --refs "searchCanon" --json # машиночитаемый pack
doc-canon code-index search "Reader" --max-hits 5 --snippet-lines 6
doc-canon code-index search "topic" --root /path/to/repoAgent skills
Управляемые skills (canon-bootstrap, canon-write, canon-audit, canon-contract, canon-future-plan) вызывают subprocess doc-canon. doc-canon должен быть в PATH (например, через npm link, глобальную установку или npm install -g . в CI).
init / upgrade-skills ставят одинаковые деревья skills в корни скиллов выбранных харнессов — .cursor/skills/, .claude/skills/ и .dsh/skills/ (DSH — DeepSeek Harness — находит скиллы в .dsh/skills/). Always-on для Cursor — .cursor/rules/doc-canon.mdc и короткий блок AGENTS.md; Claude Code читает полный body pointer-rule из CLAUDE.md и не загружает .cursor/rules/; DSH читает тот же always-on гайденс из AGENTS.md и CLAUDE.md — отдельный rule-файл ему не нужен. Выбор: интерактивный чекбокс на TTY, --harnesses cursor,claude,dsh или обнаружение установленных харнессов в upgrade-skills / migrate.
CI для adopter-репозитория
Рекомендуемый gate — doc-canon validate (только структура). check опционален. Не валите CI из-за открытых записей в DISCREPANCIES.md.
# пример для adopter-репозитория — в самом репозитории doc-canon не используется
name: canon
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- run: npm install -g doc-canon
- run: doc-canon validateСпецификация и acceptance
- Спецификация дизайна:
docs/superpowers/specs/2026-08-07-doc-first-canon-design.md - Acceptance-сценарии skills:
docs/acceptance/skill-scenarios.md
Разработка
npm run build
npm test
node bin/doc-canon.js --help
DRY_RUN=1 npm run release # test, build, validate, pack-check; без publish
# реальный `npm run release` также создаёт и пушит git-тег `v<version>`