@erclx/canon 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/claude/.claude-plugin/plugin.json +19 -0
- package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
- package/claude/skills/bash-cli-script/SKILL.md +48 -0
- package/claude/skills/bash-cli-script/references/template.md +43 -0
- package/claude/skills/bash-script/REQUIREMENT.md +36 -0
- package/claude/skills/bash-script/SKILL.md +100 -0
- package/claude/skills/bash-script/references/patterns.md +349 -0
- package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
- package/claude/skills/canon-cli/SKILL.md +103 -0
- package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-file/SKILL.md +80 -0
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
- package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
- package/claude/skills/canon-operator/SKILL.md +108 -0
- package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
- package/claude/skills/canon-rollout/SKILL.md +147 -0
- package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
- package/claude/skills/canon-screencast/SKILL.md +167 -0
- package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
- package/claude/skills/canon-slides-draft/SKILL.md +62 -0
- package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
- package/claude/skills/ci-workflow/SKILL.md +65 -0
- package/claude/skills/ci-workflow/references/workflows.md +98 -0
- package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
- package/claude/skills/claude-address-review/SKILL.md +212 -0
- package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
- package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
- package/claude/skills/claude-autoship/SKILL.md +207 -0
- package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
- package/claude/skills/claude-design-extract/SKILL.md +102 -0
- package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
- package/claude/skills/claude-diagram/SKILL.md +177 -0
- package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
- package/claude/skills/claude-docs/SKILL.md +287 -0
- package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
- package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
- package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
- package/claude/skills/claude-feature/SKILL.md +115 -0
- package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
- package/claude/skills/claude-groundwork/SKILL.md +142 -0
- package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
- package/claude/skills/claude-intake/SKILL.md +114 -0
- package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
- package/claude/skills/claude-intake-answer/SKILL.md +90 -0
- package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
- package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
- package/claude/skills/claude-markdown-propose/references/format.md +107 -0
- package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-capture/SKILL.md +101 -0
- package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-review/SKILL.md +210 -0
- package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
- package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
- package/claude/skills/claude-orchestrate/SKILL.md +241 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
- package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
- package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
- package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
- package/claude/skills/claude-pr-review/SKILL.md +295 -0
- package/claude/skills/claude-review/REQUIREMENT.md +39 -0
- package/claude/skills/claude-review/SKILL.md +142 -0
- package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
- package/claude/skills/claude-seed-sync/SKILL.md +156 -0
- package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
- package/claude/skills/claude-standards-audit/SKILL.md +99 -0
- package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
- package/claude/skills/claude-tasks/SKILL.md +161 -0
- package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
- package/claude/skills/claude-teach/SKILL.md +196 -0
- package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
- package/claude/skills/claude-teach/references/pedagogy.md +67 -0
- package/claude/skills/claude-teach/references/promotion.md +54 -0
- package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ui-test/SKILL.md +77 -0
- package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ux-audit/SKILL.md +79 -0
- package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
- package/claude/skills/claude-ux-measure/SKILL.md +122 -0
- package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
- package/claude/skills/claude-worker/SKILL.md +96 -0
- package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
- package/claude/skills/claude-worktree/SKILL.md +136 -0
- package/claude/skills/create-rule/REQUIREMENT.md +45 -0
- package/claude/skills/create-rule/SKILL.md +68 -0
- package/claude/skills/create-skill/REQUIREMENT.md +38 -0
- package/claude/skills/create-skill/SKILL.md +32 -0
- package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
- package/claude/skills/create-snippet/SKILL.md +30 -0
- package/claude/skills/create-standard/REQUIREMENT.md +35 -0
- package/claude/skills/create-standard/SKILL.md +29 -0
- package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
- package/claude/skills/decision-escalate/SKILL.md +79 -0
- package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
- package/claude/skills/docs-sync/SKILL.md +95 -0
- package/claude/skills/git-branch/REQUIREMENT.md +38 -0
- package/claude/skills/git-branch/SKILL.md +60 -0
- package/claude/skills/git-commit/REQUIREMENT.md +36 -0
- package/claude/skills/git-commit/SKILL.md +49 -0
- package/claude/skills/git-followup/REQUIREMENT.md +43 -0
- package/claude/skills/git-followup/SKILL.md +48 -0
- package/claude/skills/git-issue/REQUIREMENT.md +38 -0
- package/claude/skills/git-issue/SKILL.md +65 -0
- package/claude/skills/git-pr/REQUIREMENT.md +50 -0
- package/claude/skills/git-pr/SKILL.md +164 -0
- package/claude/skills/git-pr/references/labels.md +95 -0
- package/claude/skills/git-ship/REQUIREMENT.md +42 -0
- package/claude/skills/git-ship/SKILL.md +55 -0
- package/claude/skills/git-split/REQUIREMENT.md +39 -0
- package/claude/skills/git-split/SKILL.md +162 -0
- package/claude/skills/git-stage/REQUIREMENT.md +39 -0
- package/claude/skills/git-stage/SKILL.md +73 -0
- package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
- package/claude/skills/git-worktree/SKILL.md +130 -0
- package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
- package/claude/skills/migration-claude-md/SKILL.md +76 -0
- package/claude/skills/migration-context/REQUIREMENT.md +36 -0
- package/claude/skills/migration-context/SKILL.md +95 -0
- package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
- package/claude/skills/migration-standards-drop/SKILL.md +113 -0
- package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
- package/claude/skills/migration-superseded/SKILL.md +115 -0
- package/claude/skills/project-commands/REQUIREMENT.md +42 -0
- package/claude/skills/project-commands/SKILL.md +85 -0
- package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
- package/claude/skills/restate-plainly/SKILL.md +39 -0
- package/claude/skills/session-map/REQUIREMENT.md +57 -0
- package/claude/skills/session-map/SKILL.md +70 -0
- package/claude/skills/session-resume/REQUIREMENT.md +49 -0
- package/claude/skills/session-resume/SKILL.md +51 -0
- package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
- package/claude/skills/setup-gov/SKILL.md +77 -0
- package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
- package/claude/skills/setup-indexes/SKILL.md +153 -0
- package/claude/skills/setup-init/REQUIREMENT.md +45 -0
- package/claude/skills/setup-init/SKILL.md +127 -0
- package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
- package/claude/skills/setup-plugins/SKILL.md +81 -0
- package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
- package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
- package/claude/skills/setup-verify/SKILL.md +51 -0
- package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
- package/claude/skills/systematic-debugging/SKILL.md +70 -0
- package/claude/skills/write-human/REQUIREMENT.md +46 -0
- package/claude/skills/write-human/SKILL.md +68 -0
- package/claude/skills/write-human/references/density.md +38 -0
- package/claude/skills/write-human/references/machine-tells.md +107 -0
- package/claude/skills/write-human/references/source-material.md +37 -0
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
- package/claude/skills/youtube-transcripts/SKILL.md +34 -0
- package/docs/agents/audits.md +98 -0
- package/docs/agents/capture.md +37 -0
- package/docs/agents/census.md +23 -0
- package/docs/agents/commands.md +146 -0
- package/docs/agents/comments.md +34 -0
- package/docs/agents/context-audit-checks.md +120 -0
- package/docs/agents/context-audit.md +83 -0
- package/docs/agents/counts.md +76 -0
- package/docs/agents/demo.md +86 -0
- package/docs/agents/docs.md +17 -0
- package/docs/agents/gate.md +84 -0
- package/docs/agents/index.md +47 -0
- package/docs/agents/indexes.md +35 -0
- package/docs/agents/install-and-sync.md +385 -0
- package/docs/agents/intake.md +81 -0
- package/docs/agents/key-changes.md +103 -0
- package/docs/agents/label-coverage.md +73 -0
- package/docs/agents/markdown-audit.md +197 -0
- package/docs/agents/output-shape.md +70 -0
- package/docs/agents/overview.md +26 -0
- package/docs/agents/records.md +170 -0
- package/docs/agents/restated.md +81 -0
- package/docs/agents/review-classification.md +77 -0
- package/docs/agents/routing.md +61 -0
- package/docs/agents/rule-citations.md +98 -0
- package/docs/agents/sandbox.md +71 -0
- package/docs/agents/scripting.md +149 -0
- package/docs/agents/sessions.md +120 -0
- package/docs/agents/skills-audit.md +94 -0
- package/docs/agents/skills-reach.md +64 -0
- package/docs/agents/standards-audit.md +38 -0
- package/docs/agents/state-scoped-risk.md +105 -0
- package/docs/agents/superseded.md +85 -0
- package/docs/agents/targets.md +83 -0
- package/docs/agents/tasks.md +200 -0
- package/docs/agents/teach.md +158 -0
- package/docs/agents/test-order.md +56 -0
- package/docs/agents/worktrees.md +62 -0
- package/docs/ai-workflow.md +317 -0
- package/docs/index.md +23 -0
- package/docs/operating-model.md +223 -0
- package/docs/target-projects.md +258 -0
- package/docs/visual-design-workflow.md +151 -0
- package/docs/zshrc-aliases.md +65 -0
- package/governance/rules/ci/700-ci-workflow.md +44 -0
- package/governance/rules/claude/500-prose.md +15 -0
- package/governance/rules/claude/501-markdown.md +14 -0
- package/governance/rules/claude/510-context.md +28 -0
- package/governance/rules/claude/511-indexes.md +14 -0
- package/governance/rules/claude/520-wireframes.md +12 -0
- package/governance/rules/claude/530-requirements.md +11 -0
- package/governance/rules/claude/540-architecture.md +11 -0
- package/governance/rules/claude/550-design.md +11 -0
- package/governance/rules/claude/555-tasks.md +12 -0
- package/governance/rules/claude/556-groundwork.md +11 -0
- package/governance/rules/claude/557-intake.md +11 -0
- package/governance/rules/claude/558-plan.md +22 -0
- package/governance/rules/claude/559-memory.md +11 -0
- package/governance/rules/claude/560-diagrams.md +18 -0
- package/governance/rules/claude/561-teach.md +13 -0
- package/governance/rules/claude/562-session.md +15 -0
- package/governance/rules/claude/570-skill.md +24 -0
- package/governance/rules/claude/575-hooks.md +17 -0
- package/governance/rules/claude/576-settings.md +14 -0
- package/governance/rules/claude/580-readme.md +11 -0
- package/governance/rules/claude/590-rule-authoring.md +12 -0
- package/governance/rules/claude/591-standard-authoring.md +12 -0
- package/governance/rules/claude/592-claude-md.md +19 -0
- package/governance/rules/core/000-constitution.md +30 -0
- package/governance/rules/core/005-behavior.md +27 -0
- package/governance/rules/core/010-testing.md +35 -0
- package/governance/rules/core/015-output.md +20 -0
- package/governance/rules/core/020-concurrency.md +22 -0
- package/governance/rules/core/025-indexes.md +9 -0
- package/governance/rules/core/030-error-handling.md +31 -0
- package/governance/rules/core/035-tasks.md +13 -0
- package/governance/rules/core/040-performance.md +20 -0
- package/governance/rules/core/045-memory.md +12 -0
- package/governance/rules/core/050-logging.md +20 -0
- package/governance/rules/core/055-scratch.md +9 -0
- package/governance/rules/core/060-naming.md +19 -0
- package/governance/rules/core/065-spelling.md +19 -0
- package/governance/rules/core/070-planning.md +18 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/core/080-config-comments.md +22 -0
- package/governance/rules/core/085-worktrees.md +17 -0
- package/governance/rules/core/087-git.md +11 -0
- package/governance/rules/core/090-code-comments.md +39 -0
- package/governance/rules/framework/200-react.md +51 -0
- package/governance/rules/framework/210-astro.md +41 -0
- package/governance/rules/framework/220-fastapi.md +43 -0
- package/governance/rules/framework/230-nextjs.md +48 -0
- package/governance/rules/framework/250-tailwind.md +32 -0
- package/governance/rules/framework/260-shadcn.md +34 -0
- package/governance/rules/lang/100-typescript.md +40 -0
- package/governance/rules/lang/110-python.md +42 -0
- package/governance/rules/lang/120-bash.md +19 -0
- package/governance/rules/lib/300-testing-ts.md +39 -0
- package/governance/rules/lib/305-e2e-reliability.md +34 -0
- package/governance/rules/lib/306-test-scope.md +25 -0
- package/governance/rules/lib/310-zod.md +25 -0
- package/governance/rules/lib/320-tanstack-query.md +32 -0
- package/governance/rules/lib/330-testing-py.md +44 -0
- package/governance/rules/lib/340-pydantic.md +38 -0
- package/governance/rules/lib/350-security-web.md +32 -0
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/rules/snippets/505-at-references.md +9 -0
- package/governance/rules/ui/400-ui.md +36 -0
- package/governance/rules/ui/410-a11y.md +48 -0
- package/governance/rules/ui/420-forms.md +36 -0
- package/governance/rules/ui/430-ux-completeness.md +65 -0
- package/governance/rules/ui/440-surface-capture.md +34 -0
- package/governance/rules/ui/450-link-behavior.md +19 -0
- package/governance/stacks/astro.toml +2 -0
- package/governance/stacks/base.toml +8 -0
- package/governance/stacks/node-server.toml +2 -0
- package/governance/stacks/node.toml +2 -0
- package/governance/stacks/python-fastapi.toml +2 -0
- package/governance/stacks/python.toml +2 -0
- package/governance/stacks/react.toml +2 -0
- package/package.json +69 -0
- package/scripts/config.sh +11 -0
- package/scripts/core/bootstrap.sh +81 -0
- package/scripts/core/check-color-source.sh +41 -0
- package/scripts/core/check-ignore-parity.sh +162 -0
- package/scripts/core/check-plugin-boundary.sh +45 -0
- package/scripts/core/check-seed-independence.sh +59 -0
- package/scripts/core/check-skill-paths.sh +24 -0
- package/scripts/core/clean.sh +36 -0
- package/scripts/core/install-check.sh +101 -0
- package/scripts/core/list-seed-roots.sh +18 -0
- package/scripts/core/regen-claude-copies.sh +10 -0
- package/scripts/core/regen-hero.sh +217 -0
- package/scripts/core/regen-indexes.sh +10 -0
- package/scripts/core/regen-tooling-paths.sh +61 -0
- package/scripts/core/repair-bare-flag.sh +19 -0
- package/scripts/core/snapshot.sh +134 -0
- package/scripts/core/update.sh +35 -0
- package/scripts/docs/list.sh +165 -0
- package/scripts/lib/frontmatter.sh +30 -0
- package/scripts/lib/gov.sh +14 -0
- package/scripts/lib/sandbox-fixtures.sh +191 -0
- package/scripts/lib/sandbox-git.sh +125 -0
- package/scripts/lib/sandbox-path.sh +206 -0
- package/scripts/lib/tooling.sh +35 -0
- package/scripts/lib/ui.sh +266 -0
- package/scripts/lib/worktree.sh +20 -0
- package/scripts/manage-sandbox.sh +466 -0
- package/scripts/snippets/create.sh +156 -0
- package/scripts/standards/list.sh +115 -0
- package/scripts/tooling/create.sh +109 -0
- package/scripts/tooling/verify.sh +179 -0
- package/snippets/align.md +12 -0
- package/snippets/claude/decision-memo.md +39 -0
- package/snippets/claude/feature-recap.md +19 -0
- package/snippets/claude/figma-steps.md +24 -0
- package/snippets/compact-summary.md +5 -0
- package/snippets/decision-help.md +6 -0
- package/snippets/meta-prompt.md +14 -0
- package/snippets/research-prompt.md +7 -0
- package/snippets/session-notes.md +11 -0
- package/snippets/snippets.toml +5 -0
- package/snippets/step-by-step.md +10 -0
- package/snippets/web-research.md +21 -0
- package/src/audits/baseline.ts +201 -0
- package/src/audits/catalog.ts +876 -0
- package/src/audits/run.ts +204 -0
- package/src/autoship/classify.ts +75 -0
- package/src/autoship/paths.ts +51 -0
- package/src/binary.ts +16 -0
- package/src/browser/engine.ts +40 -0
- package/src/census/count.ts +113 -0
- package/src/claude/cases/all.ts +24 -0
- package/src/claude/cases/authoring.ts +53 -0
- package/src/claude/cases/claude-workflow.ts +158 -0
- package/src/claude/cases/git.ts +44 -0
- package/src/claude/cases/misc.ts +27 -0
- package/src/claude/cases/setup.ts +94 -0
- package/src/claude/gitignore.ts +51 -0
- package/src/claude/routing.ts +283 -0
- package/src/claude/seeds-list.ts +47 -0
- package/src/claude/seeds.ts +150 -0
- package/src/claude/settings.ts +151 -0
- package/src/claude/skills-audit.ts +228 -0
- package/src/claude/skills-drift.ts +156 -0
- package/src/claude/skills-list.ts +99 -0
- package/src/claude/skills-rank.ts +320 -0
- package/src/claude/skills-reach.ts +227 -0
- package/src/cli-run.ts +43 -0
- package/src/cli.ts +200 -0
- package/src/commands/audits.ts +350 -0
- package/src/commands/autoship.ts +129 -0
- package/src/commands/capture.ts +133 -0
- package/src/commands/census.ts +105 -0
- package/src/commands/claude.ts +1286 -0
- package/src/commands/comments.ts +240 -0
- package/src/commands/context.ts +857 -0
- package/src/commands/demo.ts +389 -0
- package/src/commands/deps.ts +173 -0
- package/src/commands/design.ts +36 -0
- package/src/commands/docs.ts +60 -0
- package/src/commands/feedback-format.ts +23 -0
- package/src/commands/feedback.ts +112 -0
- package/src/commands/gate.ts +189 -0
- package/src/commands/gov.ts +1265 -0
- package/src/commands/indexes.ts +184 -0
- package/src/commands/init.ts +113 -0
- package/src/commands/intake.ts +406 -0
- package/src/commands/inventory.ts +256 -0
- package/src/commands/labels.ts +361 -0
- package/src/commands/markdown.ts +544 -0
- package/src/commands/migrate.ts +175 -0
- package/src/commands/pass-through.ts +39 -0
- package/src/commands/pr.ts +411 -0
- package/src/commands/records.ts +728 -0
- package/src/commands/sandbox.ts +468 -0
- package/src/commands/secrets.ts +132 -0
- package/src/commands/serve.ts +159 -0
- package/src/commands/sessions.ts +408 -0
- package/src/commands/slides.ts +126 -0
- package/src/commands/snippets.ts +84 -0
- package/src/commands/standards.ts +247 -0
- package/src/commands/sync.ts +428 -0
- package/src/commands/targets.ts +319 -0
- package/src/commands/tasks.ts +743 -0
- package/src/commands/teach.ts +786 -0
- package/src/commands/tooling.ts +573 -0
- package/src/commands/transcripts.ts +44 -0
- package/src/commands/upgrade.ts +231 -0
- package/src/commands/wiki.ts +100 -0
- package/src/commands/worktrees.ts +191 -0
- package/src/comments/scan.ts +338 -0
- package/src/comments/trend.ts +207 -0
- package/src/comments/vocabulary.ts +85 -0
- package/src/context/architecture.ts +364 -0
- package/src/context/audit.ts +790 -0
- package/src/context/citations.ts +196 -0
- package/src/context/folders.ts +186 -0
- package/src/context/gate.ts +57 -0
- package/src/context/index-drift.ts +64 -0
- package/src/context/narration.ts +99 -0
- package/src/copy.ts +30 -0
- package/src/counts/catalogs.ts +96 -0
- package/src/counts/numbers.ts +79 -0
- package/src/counts/scan.ts +314 -0
- package/src/demo/beats.ts +135 -0
- package/src/demo/compile.ts +326 -0
- package/src/demo/container.ts +63 -0
- package/src/demo/cursors.ts +55 -0
- package/src/demo/drive.ts +357 -0
- package/src/demo/pointer.ts +178 -0
- package/src/demo/theme.ts +112 -0
- package/src/deps/audit.ts +153 -0
- package/src/design/parse.ts +116 -0
- package/src/design/render.ts +249 -0
- package/src/docs/read.ts +77 -0
- package/src/exec.ts +16 -0
- package/src/exempt-marker.ts +43 -0
- package/src/frontmatter.ts +13 -0
- package/src/gate/measures.ts +682 -0
- package/src/gate/sequencer.ts +386 -0
- package/src/gate/stages.ts +412 -0
- package/src/git-env.ts +36 -0
- package/src/git-files.ts +105 -0
- package/src/git-ignore.ts +46 -0
- package/src/github-format.ts +13 -0
- package/src/github.ts +24 -0
- package/src/gov/adapter.ts +103 -0
- package/src/gov/citations.ts +514 -0
- package/src/gov/consumed.ts +129 -0
- package/src/gov/install.ts +132 -0
- package/src/gov/list.ts +106 -0
- package/src/gov/payload.ts +39 -0
- package/src/gov/restated.ts +814 -0
- package/src/gov/stacks.ts +205 -0
- package/src/gov/superseded.ts +415 -0
- package/src/gov/test-order.ts +407 -0
- package/src/indexes/frontmatter.ts +46 -0
- package/src/indexes/regen.ts +84 -0
- package/src/indexes/render.ts +201 -0
- package/src/indexes/walk.ts +83 -0
- package/src/init/flags.ts +60 -0
- package/src/init/plan.ts +114 -0
- package/src/init/run.ts +46 -0
- package/src/init/steps.ts +77 -0
- package/src/intake/folder.ts +320 -0
- package/src/intake/items.ts +174 -0
- package/src/inventory/config.ts +117 -0
- package/src/inventory/group.ts +76 -0
- package/src/inventory/subjects.ts +114 -0
- package/src/inventory/walk.ts +129 -0
- package/src/labels/audit.ts +82 -0
- package/src/labels/coverage.ts +79 -0
- package/src/labels/map.ts +101 -0
- package/src/labels/phase.ts +95 -0
- package/src/markdown/bans.ts +94 -0
- package/src/markdown/files.ts +102 -0
- package/src/markdown/gate.ts +28 -0
- package/src/markdown/scan.ts +295 -0
- package/src/markdown/structure.ts +730 -0
- package/src/migrate/apply.ts +115 -0
- package/src/migrate/plan.ts +103 -0
- package/src/migrate/rename.ts +183 -0
- package/src/pr/bijection.ts +145 -0
- package/src/pr/paths.ts +335 -0
- package/src/process/harness.ts +167 -0
- package/src/project-root.ts +19 -0
- package/src/records/backup.ts +455 -0
- package/src/records/migrate.ts +78 -0
- package/src/records/size.ts +260 -0
- package/src/records/validate.ts +1162 -0
- package/src/sandbox/census.ts +228 -0
- package/src/sandbox/coverage.ts +115 -0
- package/src/sandbox/expect.ts +629 -0
- package/src/sandbox/tree.ts +47 -0
- package/src/secrets/marker.ts +30 -0
- package/src/secrets/patterns.ts +142 -0
- package/src/secrets/scan.ts +123 -0
- package/src/secrets/shipped.ts +111 -0
- package/src/seed-marker.ts +74 -0
- package/src/serve/static.ts +322 -0
- package/src/sessions/claim.ts +85 -0
- package/src/sessions/live.ts +79 -0
- package/src/sessions/registry.ts +137 -0
- package/src/sessions/resolve.ts +333 -0
- package/src/slides/layouts.ts +391 -0
- package/src/slides/open.ts +18 -0
- package/src/slides/parse.ts +84 -0
- package/src/slides/render.ts +88 -0
- package/src/slides/styles.ts +44 -0
- package/src/snippets/categories.ts +66 -0
- package/src/snippets/list.ts +32 -0
- package/src/snippets/presets.ts +50 -0
- package/src/standards/audit.ts +132 -0
- package/src/standards/read.ts +100 -0
- package/src/sync/check.ts +692 -0
- package/src/sync/engine.ts +576 -0
- package/src/sync/git.ts +225 -0
- package/src/sync/history.ts +123 -0
- package/src/sync/layout.ts +140 -0
- package/src/sync/reverse.ts +268 -0
- package/src/sync/seeds-report.ts +126 -0
- package/src/sync/stamp.ts +358 -0
- package/src/sync/target.ts +70 -0
- package/src/sync/workflow.ts +200 -0
- package/src/target.ts +43 -0
- package/src/targets/pulls.ts +250 -0
- package/src/targets/registry.ts +203 -0
- package/src/targets/resolve.ts +145 -0
- package/src/targets/sweep.ts +246 -0
- package/src/tasks/archive.ts +506 -0
- package/src/tasks/record.ts +311 -0
- package/src/tasks/trunk.ts +89 -0
- package/src/tasks/validate.ts +1001 -0
- package/src/teach/lesson.ts +180 -0
- package/src/teach/workspace.ts +842 -0
- package/src/tooling/gitignore.ts +122 -0
- package/src/tooling/inject.ts +193 -0
- package/src/tooling/list.ts +39 -0
- package/src/tooling/manifest.ts +176 -0
- package/src/tooling/package.ts +166 -0
- package/src/tooling/read.ts +65 -0
- package/src/tooling/scan.ts +147 -0
- package/src/tooling/stamp.ts +44 -0
- package/src/transcripts/fetch.ts +156 -0
- package/src/transcripts/metadata.ts +54 -0
- package/src/transcripts/vtt.ts +114 -0
- package/src/ui.ts +266 -0
- package/src/version/compare.ts +53 -0
- package/src/version/installed.ts +40 -0
- package/src/version/manager.ts +67 -0
- package/src/version/skew.ts +192 -0
- package/src/wiki/init.ts +85 -0
- package/src/worktree.ts +143 -0
- package/src/worktrees/reclaim.ts +306 -0
- package/standards/architecture.md +72 -0
- package/standards/branch.md +59 -0
- package/standards/commit.md +72 -0
- package/standards/context.md +151 -0
- package/standards/design.md +93 -0
- package/standards/diagrams.md +152 -0
- package/standards/glossary.md +75 -0
- package/standards/groundwork.md +211 -0
- package/standards/index.md +36 -0
- package/standards/intake.md +192 -0
- package/standards/issue.md +94 -0
- package/standards/markdown.md +137 -0
- package/standards/memory.md +144 -0
- package/standards/plan.md +172 -0
- package/standards/pr.md +139 -0
- package/standards/publish.md +51 -0
- package/standards/readme.md +208 -0
- package/standards/requirements.md +70 -0
- package/standards/rule.md +118 -0
- package/standards/session.md +109 -0
- package/standards/skill.md +300 -0
- package/standards/slug.md +39 -0
- package/standards/snippets.md +76 -0
- package/standards/standard.md +170 -0
- package/standards/tasks.md +254 -0
- package/standards/teach.md +153 -0
- package/standards/versioning.md +71 -0
- package/standards/wireframes.md +113 -0
- package/tooling/astro/configs/astro.config.mjs +31 -0
- package/tooling/astro/configs/eslint.config.js +79 -0
- package/tooling/astro/configs/playwright.config.ts +26 -0
- package/tooling/astro/configs/tsconfig.json +12 -0
- package/tooling/astro/configs/vitest.config.ts +22 -0
- package/tooling/astro/manifest.toml +34 -0
- package/tooling/astro/reference.md +60 -0
- package/tooling/base/configs/.editorconfig +5 -0
- package/tooling/base/configs/.github/pull_request_template.md +18 -0
- package/tooling/base/configs/.github/workflows/verify.yml +35 -0
- package/tooling/base/configs/.husky/commit-msg +1 -0
- package/tooling/base/configs/.husky/post-merge +61 -0
- package/tooling/base/configs/.husky/post-rewrite +21 -0
- package/tooling/base/configs/.husky/pre-commit +1 -0
- package/tooling/base/configs/.husky/pre-push +1 -0
- package/tooling/base/configs/.prettierrc +12 -0
- package/tooling/base/configs/.shellcheckrc +1 -0
- package/tooling/base/configs/.vscode/extensions.json +9 -0
- package/tooling/base/configs/.vscode/settings.json +3 -0
- package/tooling/base/configs/commitlint.config.js +11 -0
- package/tooling/base/configs/scripts/verify.sh +64 -0
- package/tooling/base/manifest.toml +30 -0
- package/tooling/base/reference.md +98 -0
- package/tooling/base/seeds/.claude/context/ci.md +33 -0
- package/tooling/base/seeds/.claude/context/development.md +37 -0
- package/tooling/base/seeds/.claude/context/index.md +11 -0
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/base/seeds/.lintstagedrc +8 -0
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/base/seeds/cspell.json +20 -0
- package/tooling/claude/manifest.toml +14 -0
- package/tooling/claude/reference.md +79 -0
- package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
- package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
- package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
- package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
- package/tooling/claude/seeds/.claude/memory/index.md +8 -0
- package/tooling/claude/seeds/.claude/settings.json +47 -0
- package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
- package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
- package/tooling/claude/seeds/CLAUDE.md +29 -0
- package/tooling/claude/user/settings.template.json +10 -0
- package/tooling/claude/user/statusline-command.sh +53 -0
- package/tooling/python/configs/.coveragerc +14 -0
- package/tooling/python/configs/.python-version +1 -0
- package/tooling/python/configs/mypy.ini +6 -0
- package/tooling/python/configs/pytest.ini +4 -0
- package/tooling/python/configs/ruff.toml +15 -0
- package/tooling/python/configs/scripts/verify.sh +77 -0
- package/tooling/python/manifest.toml +16 -0
- package/tooling/python/reference.md +66 -0
- package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/python/seeds/tests/test_smoke.py +2 -0
- package/tooling/vite-react/configs/playwright.config.ts +26 -0
- package/tooling/vite-react/configs/tsconfig.json +35 -0
- package/tooling/vite-react/configs/vite.config.ts +24 -0
- package/tooling/vite-react/configs/vitest.config.ts +26 -0
- package/tooling/vite-react/manifest.toml +23 -0
- package/tooling/vite-react/reference.md +55 -0
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
- package/tooling/web/configs/.github/workflows/verify.yml +134 -0
- package/tooling/web/configs/.vscode/extensions.json +13 -0
- package/tooling/web/configs/.vscode/settings.json +10 -0
- package/tooling/web/configs/e2e/home.spec.ts +6 -0
- package/tooling/web/configs/e2e/screenshot.ts +53 -0
- package/tooling/web/configs/eslint.config.js +82 -0
- package/tooling/web/configs/scripts/screenshot.sh +28 -0
- package/tooling/web/configs/scripts/verify.sh +80 -0
- package/tooling/web/configs/scripts/worktree-port.sh +74 -0
- package/tooling/web/configs/src/test/setup.ts +8 -0
- package/tooling/web/manifest.toml +58 -0
- package/tooling/web/reference.md +115 -0
- package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown audit
|
|
3
|
+
description: Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why the ban half gates while the structural half reports
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Markdown audit
|
|
7
|
+
|
|
8
|
+
`canon markdown audit [path...]` reports any markdown file against the attribute standard `markdown.md`. An attribute standard governs a file rather than a folder, so this resolves no folder and requires no `index.md`, which is what puts `.claude/rules/`, `governance/`, and `snippets/` in reach. Folder-shaped findings stay in `canon context audit`, described in `context-audit.md`.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
canon markdown audit
|
|
12
|
+
canon markdown audit --json
|
|
13
|
+
canon markdown audit .claude/rules governance
|
|
14
|
+
canon markdown audit docs/agents/commands.md
|
|
15
|
+
canon markdown audit 'snippets/**/*.md'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Option | Behavior |
|
|
19
|
+
| -------- | ---------------------------------------------------------- |
|
|
20
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
21
|
+
|
|
22
|
+
## Scope
|
|
23
|
+
|
|
24
|
+
An argument is a file, a directory, or a glob. A directory narrows to everything under it and a glob narrows by match, both against the corpus git lists, which is what keeps `node_modules/` and the gitignored session-scratch folders out without naming either. An explicit file path is taken as given, so a gitignored draft can be measured before it is committed. Quote a glob the shell would expand first.
|
|
25
|
+
|
|
26
|
+
A bare run measures every markdown file git lists, tracked plus untracked-and-not-ignored, so a file added on this branch is in scope on the branch that adds it. An argument matching no markdown file is named on the scope line rather than passed over, since a run measuring the paths that did resolve otherwise reads as a pass over one it never opened.
|
|
27
|
+
|
|
28
|
+
## Where the rules come from
|
|
29
|
+
|
|
30
|
+
The three ban sets and all nine checkpoints ship with the `canon` package as data, in `src/markdown/bans.ts` and `src/markdown/structure.ts`. Every project is measured against the same sets whether or not it installed any standards, and no file has to resolve for a run to mean something.
|
|
31
|
+
|
|
32
|
+
Six of the nine are stated in `markdown.md` and the three cadence numbers are stated in the `write-human` skill. That split is the content boundary rather than an accident: `markdown.md` carries the enforced rules a scan can decide, and the skill carries the rhythm rules a ban list cannot express. A cadence number moved in the skill and left in the code drifts the same way, so move both.
|
|
33
|
+
|
|
34
|
+
Reading them out of the standards per run was the original design. It put a parser contract on a document authored for people, and the standard had to carry a paragraph of its own warning an author that a one-word backticked example in a `- Do not use ` bullet would be lifted into a literal ban set and ban that word everywhere. A rule existing to protect a parser from the prose it parses is the argument for separating them.
|
|
35
|
+
|
|
36
|
+
`markdown.md` still states every ban and every checkpoint, and a reader follows it rather than the code. Nothing compares the two, so a number moved in one place and left in the other drifts silently. Move both in the same change.
|
|
37
|
+
|
|
38
|
+
The sets are closed rather than extensible, so a project cannot add a term by editing a file. What decides that is the measurement behind them: 21 terms across 483 markdown files report a clean exit, and every occurrence of a banned word in the corpus sits inside the ban list itself or inside an example demonstrating the ban. The set is a prior an author already knows rather than a filter that has caught anything, and enumeration cannot close the gap it aims at, since `just`, `allows`, and `very` carry honest uses no literal match separates.
|
|
39
|
+
|
|
40
|
+
Freezing the spellings gave up a property worth naming. They were derived by applying the standard's own suffix pairs to its own examples, so an example added there extended the check with no code edit. The set is now carried whole, and `analyse` stays out of it for the reason it was always out: the standard's example is `analyze`, which ends in `-yze` rather than the `-ize` its rule states.
|
|
41
|
+
|
|
42
|
+
A set shipped empty is reported rather than passed. It finds nothing and would exit clean, which reports a corpus nobody checked as a corpus carrying no violation, so the run names the empty set and exits `1`. The sets ship with the package, so a defect in the build is the only cause left.
|
|
43
|
+
|
|
44
|
+
`canon standards <name>` still resolves a standard at the authoring root, then the package corpus, and prints it, so the human catalog reads without a project copy on disk.
|
|
45
|
+
|
|
46
|
+
## What each check reports
|
|
47
|
+
|
|
48
|
+
### Bans
|
|
49
|
+
|
|
50
|
+
Three closed sets report a hit: the characters `markdown.md` bans under `## Punctuation`, the single lowercase words it bans under `## Language`, and the British spellings of the American examples that section lists.
|
|
51
|
+
|
|
52
|
+
Deriving the spellings rather than pattern-matching a suffix is what keeps `exercises`, `promises`, and `revised` out of the report. A suffix pattern over the same corpus produced 46 false positives from words of that shape, and a closed set of whole words reaches none of them.
|
|
53
|
+
|
|
54
|
+
Frontmatter, fenced blocks, inline code spans, and link destinations are excluded. Without the code-span exclusion each standard would report its own backticked examples, and without the link exclusion a semicolon in a query string would report as prose no rewrite can fix.
|
|
55
|
+
|
|
56
|
+
A banned word is bounded on a word character or a hyphen either side. A plain word boundary sits after a hyphen, so a banned word ending a hyphenated compound reported from inside one, and a compound is a single word to the reader who wrote it.
|
|
57
|
+
|
|
58
|
+
A banned spelling keeps the plain word boundary, hyphens included. The two bans target different things: a word ban targets the word, so reading a compound as one word is correct, while a spelling ban targets the orthography inside it, which sits in `behaviour-driven` as plainly as it sits alone.
|
|
59
|
+
|
|
60
|
+
Two ban shapes stay unmeasured and the report says so on every run. A multi-word ban escapes the harvest by width, whether it carries a placeholder standing in for the rest of the sentence or spells the phrase out in full, and every rule under `## Voice` is a judgment. The bans `## Language` states over what a sentence may claim sit in the first group by construction, since a literal match over a pattern reports the compliant text and reaches none of the violations. A report listing hits without naming those would read as a verdict on the whole standard.
|
|
61
|
+
|
|
62
|
+
### Bullets, paragraphs, and depth
|
|
63
|
+
|
|
64
|
+
Bullet weight and depth are the checks that moved off `canon context audit`, carrying what they measured at the time. A top-level bullet reports past roughly 400 characters with continuation lines folded in and nested items left out. A run reports past roughly 40 rendered lines, measured at 80 columns, where a heading breaks one and so does a bold section marker taking the whole line at column zero, either ending in a colon, or holding one whole code span at any width, or running to 20 characters or fewer, skipping fenced blocks and exempting a flat peer list averaging under 130 characters a bullet and a run that is entirely table rows. Each file reports its longest run alone, so a second run past the checkpoint in the same file is never named.
|
|
65
|
+
|
|
66
|
+
Every weight and depth measure counts the text a reader is shown. A link reduces to its anchor text and an autolink drops whole, since no reader is shown either destination. A backticked path stays counted, which is where these measures part from the ban scan above: that one blanks a code span so a standard quoting its own banned character does not report itself, and discounting the same span here would under-report a paragraph carrying several. One file holds both span sets and each answers its own question.
|
|
67
|
+
|
|
68
|
+
A code span is walked around rather than through, so a path quoting link or angle-bracket syntax keeps the width the page gives it. Masking inside one takes back the decision to count it, and the placeholders this toolkit writes are where that shows.
|
|
69
|
+
|
|
70
|
+
The paragraph check measures both halves of one rule. `markdown.md` caps a paragraph at four sentences, and a sentence cap on its own is satisfied by writing fewer and longer ones: 15 paragraphs in this corpus sit inside four sentences and past the weight checkpoint, and the heaviest of those runs 886 characters. The standard therefore states a weight beside the sentence cap, and the verb reads it as its own checkpoint.
|
|
71
|
+
|
|
72
|
+
A sentence boundary closes on terminal punctuation ahead of a capital or a code span. The capital is what keeps a version pin and a decimal from each reading as two sentences, and the code span is admitted beside it because a command name opening a sentence carries no capital to find.
|
|
73
|
+
|
|
74
|
+
The paragraph weight sits at 700 and the bullet weight at 400. Both shipped at 400, because the paragraph number was borrowed from the bullet rule when the two checks landed together, and each has since been read against a sample of its own. They are separate checkpoints in the standard and separate patterns in the parser, so a read that moves one leaves the other where it is.
|
|
75
|
+
|
|
76
|
+
#### The sample behind the paragraph number
|
|
77
|
+
|
|
78
|
+
The checkpoint shipped at 400 as a borrowed number and was decided against a read of the prose it reports. Thirty-six findings were sampled, six from each of six weight bands, drawn at even spacing through each band ordered by path and line, and each was classed as prose a reader wants split or prose the checkpoint should not have reported.
|
|
79
|
+
|
|
80
|
+
Every band below was measured before the scan stopped counting link syntax as prose, so a paragraph sitting in one of these bands is heavier than a paragraph reported at the same number today. The re-sample in the section below re-reads the same range against the corrected measure and reaches the opposite verdict on it, which is the measure moving rather than the reader.
|
|
81
|
+
|
|
82
|
+
| Band | Wants the split | Reads as written |
|
|
83
|
+
| --------- | --------------- | ---------------- |
|
|
84
|
+
| 400 - 425 | 1 | 5 |
|
|
85
|
+
| 425 - 450 | 2 | 4 |
|
|
86
|
+
| 450 - 500 | 2 | 4 |
|
|
87
|
+
| 500 - 600 | 2 | 4 |
|
|
88
|
+
| 600 - 750 | 6 | 0 |
|
|
89
|
+
| Past 750 | 6 | 0 |
|
|
90
|
+
|
|
91
|
+
Precision is what moved the number rather than the finding count. Below 600 the checkpoint was right about seven of twenty-four sampled paragraphs, and past 600 it was right about all twelve. A checkpoint is a prompt to look, and a prompt wrong three times in four teaches a reader to stop looking. The distribution offers no seam to place the number against, with a median of 487 and a seventy-fifth percentile of 563, so the read is the whole of the evidence.
|
|
92
|
+
|
|
93
|
+
Nothing inside the 500 to 600 band separated the two classes by length, which is the reason the number did not land there. The two paragraphs wanting a split ran 543 and 590 characters against four reading well at 515, 532, 555, and 569.
|
|
94
|
+
|
|
95
|
+
The sample is thirty-six paragraphs against a reported population in the hundreds, and one reader classed all of them. Treat a band's rate as the order of magnitude it is rather than as a measured precision, and re-sample before moving the number again.
|
|
96
|
+
|
|
97
|
+
#### The re-sample that moved the number to 700
|
|
98
|
+
|
|
99
|
+
That re-sample ran once the scan stopped counting link syntax as prose. Findings at 604, 633, and 677 characters each read as an ordinary four-sentence paragraph on one topic, density arrived around 760 and was plain by 860, and the move cut the weight half of the report roughly in half while leaving the sentence cap untouched.
|
|
100
|
+
|
|
101
|
+
A bullet, a heading, a table row, a blockquote, a blank line, and a fence each end a paragraph, so a heavy bullet is reported by the bullet check alone and never counted twice.
|
|
102
|
+
|
|
103
|
+
### Cadence
|
|
104
|
+
|
|
105
|
+
Uniform cadence is the failure a ban list cannot express. A ban set states negatives, and fragments, verbless clauses, and sentences that all run one length are each the absence of something, so no addition to the thirteen banned words reaches any of them. The shape layer already measured a bullet, a paragraph, and a run, and stopped one level above where that failure lives.
|
|
106
|
+
|
|
107
|
+
Cadence measures a paragraph on two numbers. The spread is the words between its longest and shortest sentence, and the opener count is the times one word opens a sentence in it. A spread of five words or under reads as one cadence, and a word opening more than two sentences is a pattern rather than a coincidence. Both come from `## Rhythm` in the `write-human` skill, which states them about prose a person reads, and this measures against that statement rather than setting a threshold of its own.
|
|
108
|
+
|
|
109
|
+
Words are counted off the text a reader is shown. A link contributes its anchor text, an autolink contributes nothing, and the sentence boundaries do not move under that masking, since the boundary pattern requires whitespace after the terminal punctuation and no destination carries any. An opening word is lowercased and stripped of punctuation, so a sentence opening on a backticked command name reports the command.
|
|
110
|
+
|
|
111
|
+
A paragraph carrying fewer than three sentences is skipped rather than scored. A two-sentence configuration note has no spread worth reading, and the opener rule is written about a third sentence turning a coincidence into a pattern, so neither number says anything before the floor. That is the cheap form of a wider exemption: a shape-aware one, exempting a short reference block by what it is rather than by how many sentences it holds, waits on a second case.
|
|
112
|
+
|
|
113
|
+
The unit is the paragraph and each file names its worst on each measure, which follows the depth check rather than setting a precedent. A file's flattest paragraph and its most repetitive one are named only when each crosses its checkpoint, so a file reading healthy names nothing rather than offering its least healthy paragraph as a finding.
|
|
114
|
+
|
|
115
|
+
Neither number gates and neither names a file wrong. This is a weaker claim than the one the weight checkpoints make, because a healthy range differs by surface: a catalog entry is several short sentences carrying one fact each, and a page arguing a decision is not, so one range applied across the corpus would report the surfaces that are correct. The run therefore states where the numbers came from beside them, and the counts are what a reader compares against.
|
|
116
|
+
|
|
117
|
+
Measured at `6c273324` across the corpus, 2119 paragraphs reached the floor, 165 sat at or under the spread checkpoint and 50 past the opener checkpoint. Over the 60 files carrying at least ten measured paragraphs the flat rate runs from zero to 21 percent with a median near 6, which is the spread that makes the measure worth reading. Two wiki pages sit at either end of it: a server catalog reports 19 percent, its flattest paragraph five sentences within four words of each other and three of them verbless, while a page arguing where the prose rules came from reports none.
|
|
118
|
+
|
|
119
|
+
That reading travels with the command rather than staying here. `BASELINE` in `src/markdown/structure.ts` carries the overall share, the per-file range, and the ten-paragraph floor beneath which a file's own rate says nothing, and the run prints all four in the legend beside the rate it measured. A count with no range beside it reads as a finding, and naming that a healthy range differs by surface states that a range exists rather than what it looks like. This page is toolkit-internal, so a reader running the command in a project that installed no standards would otherwise have two counts and nothing to place them against.
|
|
120
|
+
|
|
121
|
+
Two of the rules `write-human` states are deliberately not implemented. A sentence's grammatical shape and whether it carries a finite verb each need a parse rather than a match, and an imperative would read as a defect under a pattern that approximated either. The verbless share is the measure closest to the reported symptom, which is exactly why shipping it wrong would discredit the two that hold.
|
|
122
|
+
|
|
123
|
+
The condition on that was something identifying a finite verb rather than guessing at one, and two parsers have now been run against it over 11,389 paragraph sentences. They disagree by a factor of four. `compromise` reports 2 percent and reads a fronted past participle as a finite verb, so `Measured at <sha> on <date>.` counts as carrying one. `wink-pos-tagger` reports 9 percent, fixes that class, and is still wrong on roughly three in four, because an imperative's verb tags as a proper noun and a noun-ambiguous predicate tags as a noun, which makes `Each maps to a skill.` read verbless. Separating those needs to know which token is the predicate, and that is syntax rather than a tag. The measure stays unimplemented, now against a mechanism rather than against the idea of one.
|
|
124
|
+
|
|
125
|
+
## Exit codes
|
|
126
|
+
|
|
127
|
+
Exit codes are `0` for a completed run with no gating finding, `1` for a refusal, `2` for a ban hit, and `3` for a shipped ban set that arrived empty. A banned character, word, or spelling fails the run. Bullet, paragraph, and depth weight are judgments a reader settles, and cadence is a distribution whose healthy range moves with the surface, so all four report under every code.
|
|
128
|
+
|
|
129
|
+
`3` is separate from `1` because the two want different responses from a caller. A refusal means no corpus was built, and the `Markdown bans` stage in `canon gate run` is right to report it as unmeasured rather than as a pass. An empty set means the corpus was walked and nothing was looked for, so that stage fails the push on `3` rather than skipping.
|
|
130
|
+
|
|
131
|
+
`2` rather than `1` for the gate keeps a measurement that succeeded and found something distinct from the audit declining to measure at all. A caller reading one as the other sends a reader hunting a defect that does not exist, which is the distinction `canon context audit` and the gate's own seed stage already draw between the same two codes.
|
|
132
|
+
|
|
133
|
+
A banned character is a fact rather than a judgment, which is the test that admits it to a gate. What held it back was that gating on day one against a corpus never checked mechanically fails loudly on work nobody has had a chance to fix. The order was to land the verb reporting, measure the corpus once, fix what it finds, and turn the gate on as its own change, and the gate is the last of the four.
|
|
134
|
+
|
|
135
|
+
Measured at `4b7b13a2` across 444 files with the paragraph checkpoint at 600: 8 word hits, no character or spelling hits, 119 heavy bullets, 221 heavy paragraphs across 86 files, and 41 files carrying a run past the depth checkpoint. Of the paragraphs, 88 fire on weight alone. That is the baseline the corpus sweep started from, and the ban count is the only one of the five a gate should ever read.
|
|
136
|
+
|
|
137
|
+
The ban half reached zero, which was the precondition the gate waited on, and it was re-measured against the same corpus at the moment the gate landed. Three sweep slices then took the structural half, and the corpus reports 1 heavy bullet and 22 heavy paragraphs across 6 files on 2026-08-06, every one on a ground the triage record holds as exempt.
|
|
138
|
+
|
|
139
|
+
Depth is the one measure no slice triaged, so its figure moved with the sweep rather than with the corpus. The break rule widened to bold section markers on 2026-08-28 and again to the colon-less ones the same day, and each drop came with no edit to any file, so the 41 above reads against a rule the command no longer runs. Read all four structural counts from a run rather than from this paragraph.
|
|
140
|
+
|
|
141
|
+
### What a hit asks of an author
|
|
142
|
+
|
|
143
|
+
Rewrite the sentence rather than swapping the banned token for a near-synonym. The rule is about the sense the token carries, so a swap that keeps the sense clears the report without clearing the violation.
|
|
144
|
+
|
|
145
|
+
A code span clears the report too, since the ban scan walks around one, and it is the answer only where the token is genuinely an identifier under discussion. `## Code and identifiers` in `markdown.md` reserves the span for commands, API names, file paths, and identifiers, so backticking a quoted utterance spends one rule to satisfy another and leaves the corpus no cleaner.
|
|
146
|
+
|
|
147
|
+
A hit the closed set cannot separate from correct prose is the case with no third option. `markdown.md` bans vague qualifiers and lists the tokens those qualifiers happen to spell, so the temporal `just` reports as the vague one. The rule as written reaches neither, and rewriting the sentence is what the toolkit settled on over building an exemption path, for the reasons below.
|
|
148
|
+
|
|
149
|
+
### Where the rules are enforced
|
|
150
|
+
|
|
151
|
+
Four surfaces apply the ban sets and three of them go through this verb. `.claude/hooks/standards-audit.sh` runs it against a single file after each markdown edit, the seed copy a project installs does the same, and the `Markdown bans` stage in `canon gate run` runs it across the whole corpus before a push. Each hook parsed its own copy of the word bans in awk before that, which left a British spelling passing at edit time and failing the push with nothing in between explaining the difference.
|
|
152
|
+
|
|
153
|
+
The seed copy moved onto the verb when the sets became data, since its awk had nothing left to parse. It resolves one runner where the toolkit copy resolves two, looking for no checkout source, and a machine carrying no `canon` gets a report naming the binary to install rather than a silent pass. `scripts/core/check-seed-independence.sh` scopes its walk to markdown and leaves the seed hooks outside it, which its own comment records as deliberate.
|
|
154
|
+
|
|
155
|
+
The fourth surface reads the standards directly and is not a consolidation left half done. `claude/skills/claude-standards-audit/SKILL.md` greps the banned tokens agent-side, which is a session reading prose rather than a process it can shell out to, and it ships to every target. It is the likeliest place for the next drift, since nothing compares it against the verb.
|
|
156
|
+
|
|
157
|
+
The hook prefers a checkout's own `src/cli.ts` over a globally installed binary, so it and the push stage read one build. A published binary lags a branch by whatever has not been released, which would put a ban kind added on the branch into the push and not into the edit. It reads its findings out of the `--json` record rather than off the exit code, so an older binary still reports where the fallback applies. It reads `bans.emptySets` out of the same record, so a set the verb shipped empty reaches the author as a check narrowed to what it could measure rather than as a clean pass.
|
|
158
|
+
|
|
159
|
+
That field replaced `bans.missingStandards`, which answered a standard resolving under none of three roots. The sets ship with the package now, so the state it named cannot occur and the narrowed check has one cause left, a defect in the build. The hook keeps reading a field either way, since a reader cannot tell a narrowed check from a clean one without it.
|
|
160
|
+
|
|
161
|
+
Both hooks answer an absent record as well. A completed run always writes the record and a refusal writes none, so an empty one means the verb declined to measure rather than measured and found nothing. The verb needs a git repository to build its corpus and refuses without one, which is a project the seeded hook can be installed into, and reading the findings alone reported that as a clean file.
|
|
162
|
+
|
|
163
|
+
A machine with neither runner still blocks no edit, and it says so rather than exiting clean. The push stage holds either way. An edit nobody checked and an edit carrying no violation are one silence to a reader, so the enforcement a machine lacks is reported rather than inferred.
|
|
164
|
+
|
|
165
|
+
The stage measures the whole corpus rather than the changed files. A `Do not use` bullet added to a standard bans a token retroactively, and no file in the push that adds the bullet was edited.
|
|
166
|
+
|
|
167
|
+
### Why a recorded count goes stale
|
|
168
|
+
|
|
169
|
+
A count written into prose goes stale against the corpus it describes, and nothing compares the two. The paragraph figure recorded when the masking fix shipped was already wrong by twelve one release later, which is why the standard states the rule and this page carries the numbers.
|
|
170
|
+
|
|
171
|
+
A standard sits inside the corpus this verb measures, so rewriting a rule can breach the rule beside it. A rewrite of the paragraph weight bullet landed at 539 characters against the bullet checkpoint stated two lines below it, in the authoring copy and the consumed one alike. Neither the drift stage nor the test suite reads that, so run the verb over a standard after editing one.
|
|
172
|
+
|
|
173
|
+
Masking took 7 of the weight-only paragraphs the checkpoint reported at 400 and 4 of the 44 files under their checkpoints, and no bullet at all. The first corpus triage put those at 31 paragraphs and 2 bullets, and neither reproduces: a code span is walked around, so a backticked path holding an angle-bracket placeholder keeps the width the page gives it, and both bullets the triage counted were that shape.
|
|
174
|
+
|
|
175
|
+
### How the ban count reached zero
|
|
176
|
+
|
|
177
|
+
Eight word hits stood between the baseline and a gate, and only three carried the sense the standard bans. `leverage` sat in the requirements worldview, `allows` in the claude stack reference, and one `just` was the vague qualifier in a skill body. Those three lost the qualifier rather than the word.
|
|
178
|
+
|
|
179
|
+
The other five were correct prose the closed set cannot separate from a violation. Four were the temporal `just`, meaning a moment ago, in phrases like the implementation `just` completed and the field the user `just` edited. The fifth quoted an anti-pattern a skill exists to forbid. `markdown.md` bans vague qualifiers and lists the tokens those qualifiers happen to spell, so the rule as written reaches none of the five while the scan reaches all of them.
|
|
180
|
+
|
|
181
|
+
### Why they were rewritten rather than exempted
|
|
182
|
+
|
|
183
|
+
Rewriting all five is what settled them, over building an exemption path. An exemption has three consumers, `src/markdown/scan.ts` for the patterns, `src/markdown/bans.ts` for the sets, and `.claude/hooks/standards-audit.sh`, which held its own copy of the word bans in awk at that point. A mechanism landing in the verb and not the hook leaves an exempted line still failing on edit, which is the surface an author actually meets. Five sentences lost a small amount of naturalness and the count now means what it says.
|
|
184
|
+
|
|
185
|
+
A code span was the first answer for the quoted anti-pattern and it was the wrong one. The ban scan walks around a code span, so backticking a quotation clears the report, and `## Code and identifiers` reserves the span for commands, API names, file paths, and identifiers, which a quoted utterance is none of. Spending one rule to satisfy another leaves the corpus no cleaner than dropping the qualifier does.
|
|
186
|
+
|
|
187
|
+
The collision is structural rather than a property of five legacy sentences. Writing the task and the plan behind this change each reproduced it, because a fresh file discussing the ban quotes the tokens it discusses. A later author writing about vague qualifiers meets the same thing, and the answer is to name the token in a code span where it is genuinely an identifier being discussed, and to rewrite the sentence where it is not.
|
|
188
|
+
|
|
189
|
+
## What it does not cover
|
|
190
|
+
|
|
191
|
+
The verb reads the two attribute standards and nothing else. The five standards declaring `appliesTo: ["*"]` also include `publish.md`, `slug.md`, and `versioning.md`, none of which this implements.
|
|
192
|
+
|
|
193
|
+
`publish.md` describes a scan applying the same punctuation bans to finished text on its way out. No code implemented that scan before this command, so nothing is duplicated, and a later surface should call this verb rather than build a second one.
|
|
194
|
+
|
|
195
|
+
That standard's cross-reference rule is out of reach rather than merely unimplemented. It resolves by destination, bare where the destination auto-links a pull request or issue number and backticked where it does not, so this verb sees only the half where the backticked form is correct. A check here would report every compliant reference in the tree and reach none of the published text that goes wrong, which is why the rule holds on reading alone.
|
|
196
|
+
|
|
197
|
+
The list-density rule at `standards/markdown.md` is out of scope on purpose, since it carries no number and what a density figure should measure is still open.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Output shape
|
|
3
|
+
description: Two framed shapes every command renders into, how JSON and --names modes keep stdout clean, and the exit discipline that lets piped output drain
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Output shape
|
|
7
|
+
|
|
8
|
+
Every CLI command renders into one of two framed shapes. Data goes to stdout. UI and logs go to stderr.
|
|
9
|
+
|
|
10
|
+
Help output is the exception. It prints to stdout so it can be piped and grepped.
|
|
11
|
+
|
|
12
|
+
## Data shape (lists, runs, errors)
|
|
13
|
+
|
|
14
|
+
```plaintext
|
|
15
|
+
┌
|
|
16
|
+
│ canon <domain>
|
|
17
|
+
│
|
|
18
|
+
├ Section
|
|
19
|
+
│ ✓ item
|
|
20
|
+
│ ✓ item
|
|
21
|
+
└
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Rules:
|
|
25
|
+
|
|
26
|
+
- `┌` opens the frame on stderr
|
|
27
|
+
- `│ canon <domain>` is the command banner, one per invocation
|
|
28
|
+
- `├ Section` headers introduce groups of items. `log_step` produces the blank `│` spacer before each.
|
|
29
|
+
- `└` closes the frame on stderr, wired via `trap close_timeline EXIT`
|
|
30
|
+
- Errors render as `│ ✗ message` inside the same frame. Never emit a lone error line without a frame.
|
|
31
|
+
|
|
32
|
+
## Help shape
|
|
33
|
+
|
|
34
|
+
```plaintext
|
|
35
|
+
┌
|
|
36
|
+
├ Usage: canon <domain> [command]
|
|
37
|
+
│
|
|
38
|
+
│ Commands:
|
|
39
|
+
│ ...
|
|
40
|
+
└
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Help skips the banner. The `Usage:` line sits directly on `├`. Help writes to stdout because `--help` is documentation, not runtime UI.
|
|
44
|
+
|
|
45
|
+
## JSON and `--names` modes
|
|
46
|
+
|
|
47
|
+
`--json` and `--names` keep stdout clean and machine-readable. The frame still renders on stderr (open, banner, close) so the stream discipline is consistent across modes. Consumers that only read stdout see pure data.
|
|
48
|
+
|
|
49
|
+
## Color
|
|
50
|
+
|
|
51
|
+
Escape sequences reach a destination that renders them and nowhere else. The question is asked per stream rather than once for the process, so a run piping its data while keeping a terminal on stderr still gets color on the frame.
|
|
52
|
+
|
|
53
|
+
Either condition alone turns color off:
|
|
54
|
+
|
|
55
|
+
- `NO_COLOR` is set to any non-empty value, whatever that value says
|
|
56
|
+
- The destination is not a terminal, which covers a pipe, a file, and a captured session
|
|
57
|
+
|
|
58
|
+
The frame survives both. `┌`, `│`, `├`, `└`, and the `✓ ! + - ✗` marks are structure rather than color, and they are what lets a captured run still read as one block. A caller wanting neither the frame nor the color reads `--json` instead.
|
|
59
|
+
|
|
60
|
+
Terminal control is a separate question this section does not cover. The cursor and key sequences an interactive prompt writes run only where a terminal already exists.
|
|
61
|
+
|
|
62
|
+
## Process exit
|
|
63
|
+
|
|
64
|
+
A command action sets `process.exitCode` and returns. Calling `process.exit()` there ends the process before a stdout write drains, which truncates piped output at the 64K pipe buffer while still reporting the right exit code. Redirecting to a file hides the truncation, so it surfaces only through a pipe, which is what a check has to use to catch it.
|
|
65
|
+
|
|
66
|
+
The rule reaches an error path that writes to stderr alone, where the truncation has nothing to cut. Scoping it to the stdout writers was the alternative and it makes the floor depend on a detail that moves, since an action grows a stdout write long after its error branches are written. An action always has a return path, so the requirement costs it a line.
|
|
67
|
+
|
|
68
|
+
The exit belongs to a helper that has no caller to unwind through. A prompt inside a promise executor and a wrapper propagating a child process status both qualify, and neither can hand a value back to a caller expecting one. A validation helper called from an action does not: it throws from a `never` return, which keeps its caller exhaustive to the compiler while the action catches and owns the code.
|
|
69
|
+
|
|
70
|
+
Diagnostics reach stderr in every mode, including `--json`. Name the file and the field that failed, because a JSON record carries an action and a reason and an operator reading stderr alone sees neither.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Overview
|
|
3
|
+
description: What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Overview
|
|
7
|
+
|
|
8
|
+
CLI catalog and invocation rules for agents working in this repository.
|
|
9
|
+
|
|
10
|
+
This folder is an index of what an agent can run and how to run it cleanly from a script. It does not cover domain behavior. Read `CLAUDE.md` for project behaviors and load the matching `.claude/skills/internal-*` skill when working inside a domain.
|
|
11
|
+
|
|
12
|
+
## Invocation rules
|
|
13
|
+
|
|
14
|
+
See `CLAUDE.md` design principles. They apply to every command in this folder.
|
|
15
|
+
|
|
16
|
+
## Where to start
|
|
17
|
+
|
|
18
|
+
- `output-shape.md`: the stream contract every command renders into and the exit discipline behind it, which is what a caller parsing stdout depends on
|
|
19
|
+
- `commands.md`: the full command catalog, project-level and per-domain
|
|
20
|
+
- `scripting.md`: the runtime catalogs that replace hardcoded names, plus headless invocation examples
|
|
21
|
+
|
|
22
|
+
## Related
|
|
23
|
+
|
|
24
|
+
- `CLAUDE.md`: project behaviors and design principles
|
|
25
|
+
- `.claude/skills/internal-*`: domain-scoped guidance for editing work
|
|
26
|
+
- `docs/index.md`: full docs directory
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Records
|
|
3
|
+
description: Validating the session records under .claude/ and the standards corpus, the per-kind checks, the refusal reasons, migrating a record a frontmatter change orphaned, reading each folder's size and growth, backing the folders to a private remote, and which root each kind defaults to
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Records
|
|
7
|
+
|
|
8
|
+
## Validate
|
|
9
|
+
|
|
10
|
+
`canon records validate <kind>` reports where a file and the standard governing it disagree. Five kinds are gitignored folders under `.claude/`: `plans`, `groundwork`, `intake`, `memory`, and `teach`. The sixth is `standards`, the authoring corpus, which is tracked and installed rather than scratch.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
canon records validate plans
|
|
14
|
+
canon records validate memory
|
|
15
|
+
canon records validate standards
|
|
16
|
+
canon records validate intake --json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Option | Behavior |
|
|
20
|
+
| --------------- | ------------------------------------------------------------------- |
|
|
21
|
+
| `--json` | Add a machine-readable record on stdout |
|
|
22
|
+
| `--root <path>` | Project root, defaulting to the main worktree except on `standards` |
|
|
23
|
+
|
|
24
|
+
It reads and never writes, and the reason splits by kind. A session record is per-machine scratch with no history behind it, so a repair that guessed wrong could not be undone. A standard installs into every target and is cited by bare filename, so a rename the verb performed would reach further than the file it moved, which is why a finding naming one says so.
|
|
25
|
+
|
|
26
|
+
`standards` reads the authoring root at `standards/` where it exists and a copy at `.claude/standards/` otherwise. The authoring root wins because it is the only tree anyone authors in and the only one the resolver answers from, so a finding fixed anywhere else is fixed where nothing reads it. No repository generates the second candidate any more, which leaves it as a floor under a target holding a copy an older toolkit installed. The walk stays flat, matching the catalog.
|
|
27
|
+
|
|
28
|
+
Nothing fires it automatically. The five record folders are gitignored, so the standards-audit hook exits early on them and any check reading changed files from git never lists one. The corpus is tracked and still unreached, since the markdown audit reads content across the files git lists and rules on no filename. The verb runs at the moment a session claims the record is finished, which is the same placement `canon tasks validate` takes over the board.
|
|
29
|
+
|
|
30
|
+
### What each kind checks
|
|
31
|
+
|
|
32
|
+
| Kind | What it reports |
|
|
33
|
+
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| `plans` | A filename that is not `feature-<slug>.md`, a missing `# Feature:` heading, a missing required section, a files-to-touch entry naming no file or saying nothing about one, and a question carrying no suggestion or no answer slot |
|
|
35
|
+
| `groundwork` | A track with no `README.md` or no `01-current-state.md`, a file missing `title` or `description`, a `README.md` with no `date` as `YYYY-MM-DD`, an unnumbered file, and a track holding a decision without its handoff or the reverse |
|
|
36
|
+
| `intake` | A dump with no `00-overview.md`, the same frontmatter and numbering checks, an item missing any of `Problem`, `Fix`, `Worth it`, or `You`, and an item carrying `Open` with no `Suggested` |
|
|
37
|
+
| `memory` | A filename whose prefix names none of the four types, an entry missing `title`, `description`, or `category`, a `category` disagreeing with that prefix, a title repeating the filename, and a rule-bearing body missing a part |
|
|
38
|
+
| `standards` | A standard missing `title` or `description`, an absent `## Scope` section, a scope section carrying no `Does not govern:` list, a statement anchoring nothing, and a filename naming no part of the path the statement governs |
|
|
39
|
+
| `teach` | A workspace folder carrying no two-digit ordinal, an absent `MISSION.md`, `RESOURCES.md`, or `GLOSSARY.md`, a file missing `title` or `description`, a mission with no `date` as `YYYY-MM-DD` or no `## Success looks like` section, an unnumbered learning record, and a reference page opening with an ordinal |
|
|
40
|
+
|
|
41
|
+
The half-closed track is the groundwork check a reader cannot run by eye. A folder holding `06` without `07` reads as closed to anyone scanning filenames while the file a returning session actually opens is absent.
|
|
42
|
+
|
|
43
|
+
The item check skips `00-overview.md` and `99-next-session.md`, since neither holds items and running it over the handoff would report every heading it carries. The memory walk skips `index.md` for the same reason, since the catalog is generated from its siblings rather than authored as an entry.
|
|
44
|
+
|
|
45
|
+
A memory `category` is compared against the sentence-case form of the filename prefix rather than checked field by field, so one finding covers a prefix outside the four types, a field disagreeing with the prefix, and a casing drift that would open a second group in the catalog. The body check runs on `feedback` and `project` entries alone, because a `user` or `reference` entry is a single sentence by design and has no rule to apply.
|
|
46
|
+
|
|
47
|
+
The standards filename check derives a word from the governed path rather than counting words in the name. Every member of the corpus is named for the artifact its scope statement governs, and one word is what that produces rather than the rule itself, so a check keyed on word count would pass a conforming single word naming the wrong artifact. Each path segment offers its own word, a dotted container segment offers none, a hyphenated segment offers its parts, and the singular and the plural both match.
|
|
48
|
+
|
|
49
|
+
The scope statement is read exactly as `scripts/standards/list.sh` reads it for the catalog's `appliesTo` field: backticked spans in the first sentence alone, with an attribute standard resolving where that sentence backticks nothing and the statement says it governs an attribute. One sentence read two ways would let a standard pass the check while publishing a different jurisdiction to every consumer of the catalog. An attribute standard is exempt from the filename derivation because it governs no path to derive from, and a statement that anchors nothing and claims no attribute is reported as `scope-unanchored` rather than passed, since silence there would let the backticks be removed to disable the check.
|
|
50
|
+
|
|
51
|
+
An absent `## Scope` section suppresses the filename finding. The name derives from the statement, so a missing section leaves nothing to derive against, and reporting both would name one defect twice and point the fix at the wrong file. The walk skips `index.md`, which is generated from its siblings rather than authored.
|
|
52
|
+
|
|
53
|
+
A plan section opens as a bold label or as an H2 and the check counts both, naming the standard's spelling when it reports one missing. The corpus splits roughly four to one between the two forms, so failing the variant would report nearly every plan on a rule that costs a reader nothing.
|
|
54
|
+
|
|
55
|
+
A section runs to the next marker-shaped line whatever it names, so a plan carrying a label of its own closes the section above it rather than collecting into it. Fenced blocks are dropped before any of this, since a plan showing the shape it writes puts real-looking bullets and headings inside a fence.
|
|
56
|
+
|
|
57
|
+
### Exit codes and refusals
|
|
58
|
+
|
|
59
|
+
Exit codes: `0` every check passed, `1` refused, `2` at least one record carries a finding. A `reason` field carries which gate fired: `no-folder` when none of the kind's directories exist, and `unknown-kind` when the argument names no published kind. A `no-folder` message names every candidate, so the `standards` refusal names both roots.
|
|
60
|
+
|
|
61
|
+
An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the record's `findings` array and its `reason` rather than the exit when a skill consumes this.
|
|
62
|
+
|
|
63
|
+
The four record folders are shared scratch at the main worktree root, so `--root` defaults to the first entry of `git worktree list` rather than the working directory. A linked worktree validates the same records every other session reads.
|
|
64
|
+
|
|
65
|
+
`standards` takes the other default, the root of the checkout the caller stands in. The corpus is tracked, so a linked worktree holds its own edited copy, and resolving the main root there would report on a tree the session never touched while saying nothing about which one it read. A session that adds or renames a standard inside a worktree is the case, and it is the one the check exists for.
|
|
66
|
+
|
|
67
|
+
Skills branch on the findings rather than on the exit code:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
canon records validate plans --json | jq -r '.findings[] | "\(.kind): \(.subject)"'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For the shapes each check enforces, see `standards/plan.md`, `standards/groundwork.md`, `standards/intake.md`, `standards/memory.md`, and `standards/standard.md`.
|
|
74
|
+
|
|
75
|
+
## Migrate
|
|
76
|
+
|
|
77
|
+
`canon records migrate <kind>` rewrites the records a `validate` finding names a transform for. A standard that redefines its own required frontmatter breaks every record already written to the old shape, and this is the repair `validate` could only report until now.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
canon records migrate memory
|
|
81
|
+
canon records migrate memory --write
|
|
82
|
+
canon records migrate memory --json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Option | Behavior |
|
|
86
|
+
| --------------- | ------------------------------------------------------------------- |
|
|
87
|
+
| `--json` | Add a machine-readable record on stdout |
|
|
88
|
+
| `--write` | Rewrite every record a transform can repair |
|
|
89
|
+
| `--root <path>` | Project root, defaulting to the main worktree except on `standards` |
|
|
90
|
+
|
|
91
|
+
It writes nothing until `--write` is passed, matching the write-flag contract `canon tooling sync` carries: a session record has no history to undo a wrong repair from, so naming a kind is not consent to rewrite every record inside it. A dry run reports which records it would touch and exits non-zero either way, headless or not, since there is nothing to prompt for.
|
|
92
|
+
|
|
93
|
+
A transform runs only where the missing value is recoverable from the file itself. The one shipped today repairs a memory record missing `category` alone, deriving it from the same filename prefix `checkMemory` already reads it from. `title` and `description` are prose nobody wrote down, so a finding naming either carries no transform and stays for a session to fix by hand, and `validate` keeps reporting it. The transform re-reads the file rather than trusting a value captured at validate time, so a check and its repair cannot disagree about the same record.
|
|
94
|
+
|
|
95
|
+
Exit codes: `0` nothing carried a known transform, or `--write` repaired everything it found. `1` refused for a reason `validate` shares, every candidate it found failed to repair, or `--write` repaired only some of them. `2` a record carries a known transform and `--write` was not passed.
|
|
96
|
+
|
|
97
|
+
## Size
|
|
98
|
+
|
|
99
|
+
`canon records size` reports what each record folder holds and how much of it is recent. It reads the ten backed folders named under Push and pull, plus `.claude/.tmp`, and it gates nothing.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
canon records size
|
|
103
|
+
canon records size --json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Option | Behavior |
|
|
107
|
+
| --------------- | --------------------------------------------- |
|
|
108
|
+
| `--json` | Add a machine-readable record on stdout |
|
|
109
|
+
| `--root <path>` | Project root, defaulting to the main worktree |
|
|
110
|
+
|
|
111
|
+
The table carries one row per folder that exists, heaviest first, with the file count, the bytes, a count for each growth window, and the dates of the least and most recently written file. Those dates render in the machine's local time, which is the calendar day whoever wrote the file was living in, and the reading is per-machine already. Folders that do not exist are named on one line below it rather than printed as rows of zeros. The record a `--json` call emits carries every folder either way, each with a `present` flag, so a caller reading the record gets a stable set of keys and can tell an absent folder from one the reading skipped.
|
|
112
|
+
|
|
113
|
+
Ordering by weight is what makes the reading worth taking. A folder listed alphabetically hides behind its neighbors, and the row a reader came for is the one that grew.
|
|
114
|
+
|
|
115
|
+
The reading carries two windows rather than one, at 7 and 30 days. A single window cannot separate a folder growing steadily from one that took a single batch: a folder whose 7-day count is most of its 30-day count moved in one pass, and one where the two are proportional is growing at a rate.
|
|
116
|
+
|
|
117
|
+
Nothing fails on a number here. A record folder has no correct size, so the reading is a number to notice rather than a threshold to gate, and the point of the verb is that the next reading is taken by a command instead of by someone remembering to count the folder. The memory pen went from 44 entries to 236 between two readings taken by hand two weeks apart, which is the measurement this replaces.
|
|
118
|
+
|
|
119
|
+
`.claude/.tmp` is read here and skipped by a backup, because deletable without loss is not the same as empty. The routing handoffs and the memory archive both sit there and both accumulate. `.claude/.records.git` stays out because it is the backup history rather than a record, and `.claude/worktrees/` stays out because each entry is a checkout of the project with its own removal verb, and one of them outweighs every record folder combined.
|
|
120
|
+
|
|
121
|
+
The window counts read `mtime`, so what they report is a file written inside the window rather than one created there. An entry edited long after it landed reads as recent, which overstates growth and never understates it, and these folders are append-mostly so the two readings agree on nearly every file. The one reading that is wrong rather than early is a machine restored by `canon records pull`, which resets the work tree hard and re-dates every file it writes, so a window taken there counts the restore. Nothing on the filesystem separates the two, since a restored file is new by every stamp it carries.
|
|
122
|
+
|
|
123
|
+
Exit codes: `0` the reading completed, `1` refused. The one refusal is `no-folder`, raised when the root holds no `.claude` directory at all.
|
|
124
|
+
|
|
125
|
+
## Push and pull
|
|
126
|
+
|
|
127
|
+
`canon records push` commits the backed record folders to a private remote and pushes them. `canon records pull` fetches the other direction and writes them back. Both take `--json` and `--root` the way `validate` does, and both exit `0` on agreement and `1` on a refusal.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
canon records push
|
|
131
|
+
canon records push --json
|
|
132
|
+
canon records pull
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The backed folders are `diagrams`, `groundwork`, `intake`, `memory`, `plans`, `proposals`, `review`, `tasks`, and `teach`, all under `.claude/`. Eight of them are the Claude ignore group the claude manifest ships, minus three entries: `.claude/.tmp`, which is deletable without loss, `.claude/worktrees/`, whose contents belong to the project repository already, and `.claude/.records.git/`, which is the history the rest are pushed into. `diagrams` is the one that group does not carry at all, since a target still tracks its own copies, which is why the list is spelled out rather than derived. Each name is a top-level record folder and every archive sits inside the one it archives, so the list stays at one entry per surface however many archives appear. It is a constant rather than configuration, and it deliberately does not match the six record kinds `validate` hardcodes.
|
|
136
|
+
|
|
137
|
+
Records are gitignored by design, so the history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree. Every path stays where it is, which is what a separate checkout could not do. The verbs stage the nine folders by explicit pathspec with `--force`, so nothing outside them can enter the index however the ignore rules read, and the project working tree and its index are never touched. Each pathspec is a bare folder name and git reads it against the current directory rather than against the work tree the same call names, so the invocation carries `-C` at the work tree beside the other two flags. That is what lets either verb run from a linked worktree under `.claude/worktrees/`, which sits inside the records work tree and would otherwise prefix every name with its own path.
|
|
138
|
+
|
|
139
|
+
### Setup
|
|
140
|
+
|
|
141
|
+
A person creates the records repository once per machine, and the verbs refuse with the commands when it is absent:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
git --git-dir=.claude/.records.git init
|
|
145
|
+
git --git-dir=.claude/.records.git remote add origin <private-repo-url>
|
|
146
|
+
printf '.claude/.records.git/\n' >> .gitignore
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The ignore line is repeated here rather than left to the install, because the person running these commands is the one who creates the directory and the rule is worth reading beside the command that needs it. The claude manifest ships `.claude/.records.git/` as the first entry of its group, so a project that ran `canon claude sync` already carries it and this line is a no-op there. What the group buys is the project that never sets records up: it holds a rule for a directory it will never create, which costs nothing, and the backed-folder derivation above subtracts that entry from the group rather than from a list it does not sit in.
|
|
150
|
+
|
|
151
|
+
Point it at a private repository, and at one that is not a remote of the project. Records carry the memory pen, the review reports, and the groundwork trails, so a public project publishes all of it to anyone who fetches all refs. `push` compares the configured origin against every remote of the project and refuses on a match. A read of that list which fails refuses as well, since an empty list clears the comparison for every origin and a gate that passes on its own failure is no gate.
|
|
152
|
+
|
|
153
|
+
### Refusals
|
|
154
|
+
|
|
155
|
+
| Reason | What fired |
|
|
156
|
+
| ------------------- | ------------------------------------------------------------------------------------ |
|
|
157
|
+
| `no-repository` | No `.claude/.records.git`, answered with the two setup commands |
|
|
158
|
+
| `no-remote` | The records history has no `origin` |
|
|
159
|
+
| `remote-unreadable` | The project's own remotes could not be read, so the shared-origin gate could not run |
|
|
160
|
+
| `remote-shared` | The records origin is also a remote of the project |
|
|
161
|
+
| `no-remote-records` | `pull` found no branch on the records origin |
|
|
162
|
+
| `local-changes` | `pull` found records on disk that the history does not carry |
|
|
163
|
+
| `local-ahead` | `pull` found local commits that never reached the origin |
|
|
164
|
+
| `git-failed` | A git call failed, with its stderr in the message |
|
|
165
|
+
|
|
166
|
+
The two `pull` refusals exist because the directions are not symmetric. A push only adds, while a pull onto a machine holding work that never left it would discard that work. Resolve either by running `push` first, or by moving the local folders aside. A machine holding none of the ten has nothing to lose, so a restore onto a fresh checkout runs straight through.
|
|
167
|
+
|
|
168
|
+
### When it runs
|
|
169
|
+
|
|
170
|
+
`.husky/post-merge` runs `push` after the task archiving loop, on every merge rather than only on one that archived a task. A review report and a memory entry both land on runs that close nothing. The call sits inside an `if` and last in the file, so an unreachable remote neither aborts the hook nor delays the archiving above it, and a checkout that never ran the setup reports nothing. Anything the hook misses is covered by running the verb by hand.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Restated instructions
|
|
3
|
+
description: Counting the instructions the always-loaded file and every path-scoped rule share with the seed, the shipped skill bodies, and each other, how a match is decided, the three classes, which surface a later edit starts from, and why the sweep reports rather than gates
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Restated instructions
|
|
7
|
+
|
|
8
|
+
`canon gov restated` reports every instruction the always-loaded file or a path-scoped rule states that a further surface states too. It answers a question nothing else here could: one rule was found written in three places, and it was found by accident when a shipped skill deleted a file the rule said to keep.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
canon gov restated
|
|
12
|
+
canon gov restated --json
|
|
13
|
+
canon gov restated --root ../my-app
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
| Option | Behavior |
|
|
17
|
+
| --------------- | ---------------------------------------------------------- |
|
|
18
|
+
| `--root <path>` | Tree to read, defaulting to the current directory |
|
|
19
|
+
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
20
|
+
|
|
21
|
+
Under `--json` the record holds stdout alone and the frame still renders on stderr, refusals included, which is the split `output-shape.md` fixes for every mode.
|
|
22
|
+
|
|
23
|
+
## The corpus it reads
|
|
24
|
+
|
|
25
|
+
Four surfaces, and they are not read symmetrically. Every top-level bullet in `CLAUDE.md` and in every path-scoped rule is a subject, and every surface below is searched, rules included a second time:
|
|
26
|
+
|
|
27
|
+
- `tooling/claude/seeds/CLAUDE.md`, read as bullets, since the seed carries the same shape as the file it is authored from
|
|
28
|
+
- `claude/skills/*/SKILL.md`, read as every prose line and bullet, since the motivating case was stated in a body as a paragraph rather than a list item
|
|
29
|
+
- `governance/rules/**/*.md`, the authoring root rather than the consumed copy under `.claude/rules/`, read as bullets the same way the seed is
|
|
30
|
+
|
|
31
|
+
A rule reads as both a subject and a candidate, unlike the seed and the shipped bodies. A stack ships a whole rule folder, so a bullet duplicated between two rules reaches a target exactly as a bullet duplicated between the always-loaded file and a rule does, and neither shape is visible from one side alone. A candidate sharing its subject's file is skipped, since two bullets inside one rule sharing anchors are adjacent instructions on one topic rather than the same rule shipped twice, and a pair found from one direction is not reported again from the other.
|
|
32
|
+
|
|
33
|
+
Frontmatter, headings, tables, and fenced blocks are read past. A heading names a section instead of stating a rule, a fenced block is an example whose words belong to the prose around it, and a body's `description` restates that skill's own purpose, so sweeping it would match every subject naming its domain.
|
|
34
|
+
|
|
35
|
+
A rule stated in two skill bodies and never in `CLAUDE.md` or another rule is outside this reading. A body is searched but never read as a subject, and a subject is what the search runs from.
|
|
36
|
+
|
|
37
|
+
## How a match is decided
|
|
38
|
+
|
|
39
|
+
Matching is recall-first and keyed on shared distinctive tokens rather than on a phrase two surfaces spell the same way. The case this exists for was one rule written three different ways, so a near-exact matcher would ship a cheap report blind to the defect it was built for.
|
|
40
|
+
|
|
41
|
+
A token is distinctive when it appears in at most 20 of the corpus's statements, which is under one percent of them. `.claude/plans/` sits at 14 and is the anchor the motivating case turns on, while `file` sits at 371 and would match most of the tree.
|
|
42
|
+
|
|
43
|
+
A backticked token counts double. An author marking a span as code named an identifier rather than describing one, so `.claude/plans/archive/` says more about what a statement governs than any two prose words do. Two statements are one rule when their shared anchors reach a weight of 3.
|
|
44
|
+
|
|
45
|
+
Every record names the anchors its match rested on, so a reader can weigh a finding instead of taking it.
|
|
46
|
+
|
|
47
|
+
## The three classes
|
|
48
|
+
|
|
49
|
+
- **Mirror.** Both files sit on a declared path pair whose duplication is deliberate. `CLAUDE.md` and the seed are the one pair, since the seed is authored from it and `claude-seed-sync` exists to reconcile the two. Excluding by pair rather than by content is the point: the duplication is a location fact this repository already records, and a content test would rediscover it on every run.
|
|
50
|
+
- **Repetition.** Two surfaces state one rule and neither is declared a copy of the other.
|
|
51
|
+
- **Contradiction.** The prohibition falls on one surface alone, on a match strong enough to read that as a disagreement. This is a polarity reading rather than a judgment about meaning, so weigh each against the surfaces it names.
|
|
52
|
+
|
|
53
|
+
The contradiction floor sits above the match floor deliberately. A thin match says two statements touch the same subject, which is not enough to claim one forbids what the other prescribes, so a weak pair reports as a repetition and the loudest class is reserved for a pair sharing real identity.
|
|
54
|
+
|
|
55
|
+
Two further rules decide where a prohibition counts, and both came out of false positives rather than from reasoning ahead of the corpus.
|
|
56
|
+
|
|
57
|
+
Polarity is read off the clause the anchors landed in, and off the densest such clause rather than every one carrying an anchor. A statement states one rule across several clauses, so a union answers true whenever any clause anywhere carries a marker, which is the whole statement again under another name.
|
|
58
|
+
|
|
59
|
+
The marker also has to open its clause, because an instruction leads with its verb. `Never delete a task file` prohibits where `a fallback never fires` reports, and no test reading the marker anywhere in the clause tells those apart. What that costs is a prohibition written mid-clause, which now reads as description and lands the pair in the repetition class, so both surfaces still reach the report and only the label is weaker.
|
|
60
|
+
|
|
61
|
+
A mirror that disagrees stays a finding. The exclusion reaches a repetition alone, because the two files on a declared pair are meant to agree.
|
|
62
|
+
|
|
63
|
+
## Which surface is authoritative
|
|
64
|
+
|
|
65
|
+
Each restatement names where a later edit starts.
|
|
66
|
+
|
|
67
|
+
- `claude-md` for a seed match, since the always-loaded file is authored first and the seed carries it to a target
|
|
68
|
+
- `skill-body` where the subject names that skill, which is the content-ownership rule that behavior triggered only when editing one domain belongs to that domain's skill
|
|
69
|
+
- `unknown` everywhere else, a rule match included, which is a first-class answer rather than a gap
|
|
70
|
+
|
|
71
|
+
The ownership table assigns a cross-domain rule and a domain-triggered one, and reaches nothing stated in a skill body the always-loaded file never names. Guessing there would put a reader on a surface nobody decided.
|
|
72
|
+
|
|
73
|
+
## Exit codes
|
|
74
|
+
|
|
75
|
+
Exit codes are `0` when no instruction is restated outside a declared mirror, `1` for a refusal, and `2` for at least one restatement outside one. Mirrors move no exit code.
|
|
76
|
+
|
|
77
|
+
Nothing wires this into `bun run check` or into a hook. A restatement is legitimate more often than not, and gating a measure whose ordinary result is a finding is what teaches contributors to route around the stage. `canon gov test-order` and `canon labels audit` are the siblings.
|
|
78
|
+
|
|
79
|
+
Both refusals are absences rather than breaks. A target holds none of the seed, a shipped skills tree, or a rules tree, so `canon audits run` reads `no-instructions` and `no-surfaces` as a corpus that is not there rather than a verb that failed.
|
|
80
|
+
|
|
81
|
+
An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the record's `counts` rather than the exit when a skill consumes this.
|