@erclx/canon 4.122.0 → 4.124.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.
Files changed (124) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +7 -8
  3. package/claude/skills/auto-ship/references/tier-failures.md +7 -4
  4. package/claude/skills/backlog-triage/SKILL.md +1 -1
  5. package/claude/skills/codebase-layout/REQUIREMENT.md +1 -1
  6. package/claude/skills/codebase-layout/SKILL.md +1 -1
  7. package/claude/skills/create-rule/SKILL.md +5 -2
  8. package/claude/skills/design-taste/SKILL.md +1 -1
  9. package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
  10. package/claude/skills/draft-ready/SKILL.md +1 -1
  11. package/claude/skills/git-ship/SKILL.md +4 -3
  12. package/claude/skills/memory-capture/SKILL.md +14 -4
  13. package/claude/skills/memory-review/REQUIREMENT.md +4 -2
  14. package/claude/skills/memory-review/SKILL.md +18 -7
  15. package/claude/skills/memory-review/references/later-phases.md +7 -4
  16. package/claude/skills/memory-review/references/receipt-format.md +19 -3
  17. package/claude/skills/role-orchestrator/SKILL.md +2 -2
  18. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
  19. package/claude/skills/session-resume/SKILL.md +4 -3
  20. package/claude/skills/task-board/SKILL.md +1 -1
  21. package/claude/skills/task-board/references/archive.md +1 -1
  22. package/claude/skills/task-board/references/decline.md +1 -1
  23. package/claude/skills/test-first/REQUIREMENT.md +1 -1
  24. package/docs/agents/counts.md +3 -3
  25. package/docs/agents/drift-surfaces.md +2 -2
  26. package/docs/agents/rule-citations.md +4 -4
  27. package/docs/agents/tasks-archive.md +3 -3
  28. package/docs/agents/tasks-plans.md +5 -3
  29. package/docs/agents/tasks-validate.md +1 -1
  30. package/docs/agents/tasks.md +1 -1
  31. package/docs/agents/test-order.md +1 -1
  32. package/docs/index.md +3 -0
  33. package/docs/target-migrations.md +93 -0
  34. package/docs/target-projects.md +4 -216
  35. package/docs/target-scenarios.md +56 -0
  36. package/docs/target-sync.md +93 -0
  37. package/docs/workflow/ai-workflow.md +4 -203
  38. package/docs/workflow/index.md +2 -0
  39. package/docs/workflow/operating-model.md +18 -47
  40. package/docs/workflow/parallel-features.md +77 -0
  41. package/docs/workflow/skill-map.md +148 -0
  42. package/governance/renames.toml +34 -0
  43. package/governance/rules/{claude/555-tasks.md → canon/655-tasks.md} +2 -1
  44. package/governance/rules/{claude/560-diagrams.md → canon/660-diagrams.md} +1 -1
  45. package/governance/rules/{claude/562-session.md → canon/662-session.md} +1 -1
  46. package/governance/rules/code/000-code.md +21 -0
  47. package/governance/rules/lib/300-testing-ts.md +0 -4
  48. package/governance/rules/lib/330-testing-py.md +0 -4
  49. package/governance/rules/{claude/500-prose.md → writing/800-prose.md} +1 -1
  50. package/governance/rules/{claude/501-markdown.md → writing/801-markdown.md} +1 -1
  51. package/governance/rules/{claude/502-mermaid.md → writing/802-mermaid.md} +1 -1
  52. package/governance/stacks/base.toml +7 -6
  53. package/governance/stacks/node.toml +1 -1
  54. package/governance/stacks/python.toml +1 -1
  55. package/package.json +1 -1
  56. package/scripts/core/install-check.sh +3 -5
  57. package/src/claude/routing.ts +1 -1
  58. package/src/commands/gov.ts +1 -1
  59. package/src/commands/tasks.ts +39 -29
  60. package/src/gate/measures.ts +1 -6
  61. package/src/gate/stages.ts +1 -0
  62. package/src/gov/citations.ts +1 -1
  63. package/src/gov/list.ts +1 -1
  64. package/src/gov/restated.ts +2 -2
  65. package/src/init/steps.ts +1 -1
  66. package/src/labels/spelling.ts +1 -1
  67. package/src/records/prune.ts +1 -1
  68. package/src/shipped/references.ts +1 -1
  69. package/src/tasks/archive.ts +212 -105
  70. package/src/tasks/reach.ts +1 -1
  71. package/src/tasks/record.ts +59 -16
  72. package/src/tasks/validate.ts +1 -1
  73. package/standards/board.md +136 -0
  74. package/standards/commit.md +5 -0
  75. package/standards/groundwork.md +25 -36
  76. package/standards/index.md +2 -1
  77. package/standards/plan.md +20 -34
  78. package/standards/readme.md +8 -77
  79. package/standards/requirements.md +2 -2
  80. package/standards/rule.md +4 -6
  81. package/standards/tasks.md +18 -125
  82. package/standards/versioning.md +1 -1
  83. package/tooling/base/configs/commitlint.config.js +27 -1
  84. package/tooling/base/reference.md +2 -2
  85. package/tooling/claude/seeds/.claude/hooks/path-form.sh +1 -1
  86. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +1 -1
  87. package/tooling/web/reference.md +1 -1
  88. package/governance/rules/core/000-constitution.md +0 -30
  89. package/governance/rules/core/020-concurrency.md +0 -22
  90. package/governance/rules/core/030-error-handling.md +0 -31
  91. package/governance/rules/core/040-performance.md +0 -20
  92. package/governance/rules/core/050-logging.md +0 -20
  93. package/governance/rules/core/060-naming.md +0 -19
  94. package/governance/rules/snippets/600-at-references.md +0 -9
  95. /package/governance/rules/{core/025-indexes.md → canon/601-indexes.md} +0 -0
  96. /package/governance/rules/{core/035-tasks.md → canon/602-tasks.md} +0 -0
  97. /package/governance/rules/{core/045-memory.md → canon/603-memory.md} +0 -0
  98. /package/governance/rules/{core/055-scratch.md → canon/604-scratch.md} +0 -0
  99. /package/governance/rules/{core/085-worktrees.md → canon/605-worktrees.md} +0 -0
  100. /package/governance/rules/{core/087-git.md → canon/606-git.md} +0 -0
  101. /package/governance/rules/{claude/510-context.md → canon/610-context.md} +0 -0
  102. /package/governance/rules/{claude/511-indexes.md → canon/611-indexes.md} +0 -0
  103. /package/governance/rules/{claude/520-wireframes.md → canon/620-wireframes.md} +0 -0
  104. /package/governance/rules/{claude/530-requirements.md → canon/630-requirements.md} +0 -0
  105. /package/governance/rules/{claude/540-architecture.md → canon/640-architecture.md} +0 -0
  106. /package/governance/rules/{claude/545-decisions.md → canon/645-decisions.md} +0 -0
  107. /package/governance/rules/{claude/550-design.md → canon/650-design.md} +0 -0
  108. /package/governance/rules/{claude/556-groundwork.md → canon/656-groundwork.md} +0 -0
  109. /package/governance/rules/{claude/557-intake.md → canon/657-intake.md} +0 -0
  110. /package/governance/rules/{claude/558-plan.md → canon/658-plan.md} +0 -0
  111. /package/governance/rules/{claude/559-memory.md → canon/659-memory.md} +0 -0
  112. /package/governance/rules/{claude/561-teach.md → canon/661-teach.md} +0 -0
  113. /package/governance/rules/{claude/563-ready.md → canon/663-ready.md} +0 -0
  114. /package/governance/rules/{core/005-behavior.md → claude/565-behavior.md} +0 -0
  115. /package/governance/rules/{core/015-output.md → claude/566-output.md} +0 -0
  116. /package/governance/rules/{core/070-planning.md → claude/567-planning.md} +0 -0
  117. /package/governance/rules/{core → code}/010-testing.md +0 -0
  118. /package/governance/rules/{ci → tooling}/700-ci-workflow.md +0 -0
  119. /package/governance/rules/{core/065-spelling.md → tooling/765-spelling.md} +0 -0
  120. /package/governance/rules/{core/075-dependencies.md → tooling/775-dependencies.md} +0 -0
  121. /package/governance/rules/{core/080-config-comments.md → tooling/780-config-comments.md} +0 -0
  122. /package/governance/rules/{core/090-code-comments.md → tooling/790-code-comments.md} +0 -0
  123. /package/governance/rules/{claude/580-readme.md → writing/880-readme.md} +0 -0
  124. /package/governance/rules/{claude/591-standard-authoring.md → writing/891-standard-authoring.md} +0 -0
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: Skill map
3
+ description: When to reach for each plugin skill, grouped by the moment a project meets it
4
+ category: Workflow
5
+ ---
6
+
7
+ # Skill map
8
+
9
+ Groups run in the order a project meets them, so a reader at a known point scans to that group and reads across. The set reconciles the scenarios in [AI workflow](ai-workflow.md) with the lifecycle [target projects](../target-projects.md) describes, rather than inventing a third vocabulary beside those two, so a group name matches neither source exactly and every moment either one names has a group. Each row says when to reach for the skill. What it does is the skill's own description.
10
+
11
+ This page is the corpus the coverage claim is measured against: every name `canon claude skills list --names` reports takes exactly one row here. A skill serving two moments sits at the earlier one, and a mention on any other page is prose rather than routing.
12
+
13
+ ## Set up a project
14
+
15
+ | Skill | When to use |
16
+ | ---------------------- | ------------------------------------------------------------------------------------------------------ |
17
+ | `canon:target-setup` | On a fresh scaffold, to detect the stack and run the install chain, or to reach one phase of it alone |
18
+ | `canon:canon-operator` | On a project that already exists, to read what it carries before an install is picked |
19
+ | `canon:sketch-design` | Before `design-extract`'s greenfield path, to trace a design direction from reference images or URLs |
20
+ | `canon:design-extract` | Before the first UI feature, to draft `canon/DESIGN.md` |
21
+ | `canon:draft-diagram` | Once the architecture is written, to draft per-kind entries under `.canon/diagrams/` |
22
+ | `canon:repo-metadata` | When the GitHub About text, homepage, or topics may have drifted, to reconcile them against the README |
23
+
24
+ ## Decide what to build
25
+
26
+ | Skill | When to use |
27
+ | -------------------------- | --------------------------------------------------------------------------------- |
28
+ | `canon:plan-intake` | When the input is a pile of findings rather than one feature |
29
+ | `canon:plan-intake-answer` | When an intake folder holds unread slots waiting on your decision |
30
+ | `canon:backlog-triage` | When the backlog needs pruning, to file a verdict per row and apply approved ones |
31
+ | `canon:plan-groundwork` | When the state is unmeasured and more than one approach is live |
32
+ | `canon:decision-escalate` | When open decisions turn on your preference and want batching into one set |
33
+ | `canon:draft-and-pick` | When the call is taste and wants several candidates rendered side by side |
34
+ | `canon:task-board` | When a decided item needs a file on the board, or a shipped one needs archiving |
35
+ | `canon:plan-feature` | When the approach is settled and the next step is a plan |
36
+ | `canon:codebase-layout` | When a plan or change adds a file and you need to decide which folder holds it |
37
+
38
+ ## Build the feature
39
+
40
+ | Skill | When to use |
41
+ | ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
42
+ | `canon:session-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch, or to route a refused main-root write |
43
+ | `canon:auto-ship` | After plan approval, to chain implement, verify, review, draft PR |
44
+ | `canon:project-commands` | When the project's own command needs running |
45
+ | `canon:test-first` | Before implementing a planned change, to run its test red, green, then refactor |
46
+ | `canon:test-craft` | When writing or changing any test, to pick its layer and filter what it asserts |
47
+ | `canon:review-craft` | When reviewing a change, for what to look for and how much evidence a finding needs |
48
+ | `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first |
49
+ | `canon:ui-checklist` | After a UI change, to write what to look at and name what ships untested |
50
+
51
+ ## Check the work before it leaves the branch
52
+
53
+ | Skill | When to use |
54
+ | ------------------------ | --------------------------------------------------------------------------------------- |
55
+ | `canon:review-branch` | On the local branch diff, before anything is pushed |
56
+ | `canon:standards-audit` | When changed markdown has to answer to the authoring standards |
57
+ | `canon:document-health` | When the documents themselves have to answer for length, placement, and staleness |
58
+ | `canon:markdown-propose` | When a markdown claim needs rewriting and the change should wait for an answer per file |
59
+ | `canon:ux-audit` | To read UI source for missing states, edge cases, and inconsistencies |
60
+ | `canon:ux-measure` | To start the interface and measure paint, processor, and layout cost |
61
+ | `canon:ux-walkthrough` | To run a multi-finding inspection pass over a running app with the operator |
62
+
63
+ ## Ship it
64
+
65
+ | Skill | When to use |
66
+ | ---------------------- | ------------------------------------------------------------------------------------------------- |
67
+ | `canon:git-ship` | To run the whole post-feature chain from the verify gate through open PR |
68
+ | `canon:memory-capture` | First skill in that chain, to route what the session learned to the surface owning it |
69
+ | `canon:context-fold` | When decisions diverged from the plan, or a shipped task needs its outcomes marked |
70
+ | `canon:docs-fold` | Never on purpose. A pointer at the old name that names `context-fold` <!-- canon-keep-retired --> |
71
+ | `canon:docs-sync` | When a change since main left `README.md` or `docs/` stale |
72
+ | `canon:git-stage` | When the staged set spans several concerns and wants one commit each |
73
+ | `canon:git-commit` | When the staged set is one concern, or was staged hunk by hand |
74
+ | `canon:git-branch` | When a branch name needs generating or renaming to conventional form |
75
+ | `canon:git-pr` | When a pull request needs a title and body written from the diff |
76
+ | `canon:memory-review` | When the pen has grown, to propose where each entry belongs |
77
+
78
+ ## After the pull request opens
79
+
80
+ | Skill | When to use |
81
+ | ---------------------- | -------------------------------------------------------------------- |
82
+ | `canon:review-pr` | From an independent session, to post findings on the PR itself |
83
+ | `canon:review-address` | On the worker's side, to fix posted findings and push a follow-up |
84
+ | `canon:git-followup` | For a small self-review edit on a branch whose PR is already open |
85
+ | `canon:git-split` | When a branch turns out to carry unrelated commits |
86
+ | `canon:git-issue` | When something surfaced that belongs on the tracker rather than here |
87
+ | `canon:git-worktree` | After a PR merges, to list worktrees and reclaim the slot |
88
+
89
+ ## Run several tracks at once
90
+
91
+ | Skill | When to use |
92
+ | ------------------------- | ----------------------------------------------------------------------------------------------------------- |
93
+ | `canon:role-orchestrator` | To assert the control session that owns the queue and reviews each worker's PR |
94
+ | `canon:role-planner` | To assert the thinking role for a cold session writing a plan, a groundwork track, or an intake pass |
95
+ | `canon:role-worker` | To assert the worker role for a cold session building one branch under one plan |
96
+ | `canon:session-relay` | When this session owes another session a message, with or without a role |
97
+ | `canon:session-resume` | At the start of a session, to pick up what a previous one left |
98
+ | `canon:session-compact` | Before a compaction or a move to another machine, to write a plain session's handoff note outside the board |
99
+ | `canon:session-map` | At the close of an orchestrating session, to write its board-side handoff |
100
+
101
+ ## Keep the project current with the toolkit
102
+
103
+ | Skill | When to use |
104
+ | ----------------------------- | -------------------------------------------------------------------------------------- |
105
+ | `canon:target-check` | In a target project, to report per domain what it holds against what the toolkit ships |
106
+ | `canon:seed-sync` | After a toolkit update, to reconcile installed seeds without losing customizations |
107
+ | `canon:canon-feedback` | When something in the toolkit is broken, missing, or off, to open an issue on it |
108
+ | `canon:canon-feedback-triage` | In the toolkit repo, to work through the open feedback issues |
109
+ | `canon:canon-rollout` | In the toolkit repo, to take one change out to every consuming project at once |
110
+
111
+ ## Generate an artifact on demand
112
+
113
+ | Skill | When to use |
114
+ | ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
115
+ | `canon:create-rule` | For a project-specific governance rule the toolkit does not ship |
116
+ | `canon:create-skill` | For a new `SKILL.md` |
117
+ | `canon:create-snippet` | For a reusable prompt |
118
+ | `canon:create-standard` | For a new authoring convention |
119
+ | `canon:draft-docs` | For a brand-new `docs/*.md` page, drafted against `standards/docs.md` |
120
+ | `canon:draft-ready` | For finished files a worker should copy, written as a ready folder with its overview, thin plan, and task |
121
+ | `canon:draft-context` | For a brand-new `canon/context/<domain>.md` entry, drafted against `standards/context.md` |
122
+ | `canon:draft-wireframes` | For a brand-new `canon/wireframes/<surface>.md` file, drafted against `standards/wireframes.md` |
123
+ | `canon:draft-wiki` | For a brand-new wiki reference page on a subject owned outside the project, drafted against `standards/wiki.md` |
124
+ | `canon:draft-figure` | For a hand-drawn figure inside an existing doc, drafted against `standards/figures.md` in Mermaid or freehand SVG |
125
+ | `canon:draft-readme` | For a project's `README.md`, drafted against `standards/readme.md` |
126
+ | `canon:bash-script` | For an interactive, human-facing shell tool |
127
+ | `canon:bash-cli-script` | For a non-interactive automation, CI, or pipeline script |
128
+ | `canon:ci-workflow` | For a GitHub Actions workflow file |
129
+ | `canon:draft-slides` | For a deck, drafted as `.claude/SLIDES.md` and rendered to PowerPoint |
130
+ | `canon:draft-screencast` | For a recording script with beats and defaults already seeded |
131
+ | `canon:record-screencast` | For compiling and running a screencast draft into a recording and a still |
132
+ | `canon:draft-identity` | For a project's logo mark and its social card, drafted through `draft-and-pick`'s pick loop |
133
+
134
+ ## Answer a question at any point
135
+
136
+ | Skill | When to use |
137
+ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
138
+ | `canon:canon-cli` | Before running an unfamiliar verb, a sync, or an install, to learn which command to run, which reference doc covers it, or what it overwrites, merges, or leaves alone |
139
+ | `canon:index-lookup` | To find where a topic is documented across the tracked `index.md` catalogs |
140
+ | `canon:youtube-transcripts` | When a video transcript is wanted in the repo as context |
141
+ | `canon:read-frames` | To read a recorded demo back frame by frame and report what each one shows, with no verdict on whether the recording looks right |
142
+ | `canon:teach-workspace` | To learn a subject across sessions, in a workspace that holds the progress |
143
+ | `canon:write-human` | Before drafting or revising prose, for voice, rhythm, and density |
144
+ | `canon:restate-plainly` | When an answer or a document has to be read again in plain words |
145
+
146
+ Every row answers a question rather than marking a point in a project's life, so a phase above would send a reader to the wrong group.
147
+
148
+ A learning workspace produces two halves and only one of them leaves. A lesson is worked through once and stays in the workspace, and a reference page or a glossary carries no learner, so it belongs wherever the project already keeps prose on that subject. Asking `canon:teach-workspace` to promote sorts each durable page by who owns its subject, sending an Anthropic-owned subject to the wiki, an internal one to the matching context entry, and everything else, subject-neutral material included, to the public docs. It proposes and waits, because a promoted page is public prose that needs a line naming who owns the subject, and it writes nothing to a destination: each page the operator confirms goes to a handoff file that `canon:context-fold` folds in from a branch. A project with no wiki folder gets a refusal naming `canon wiki init` rather than a folder it never asked for.
@@ -11,3 +11,37 @@
11
11
  # stay. A key must name no live rule and every chain must end on one, which
12
12
  # `src/gov/renames.test.ts` checks against this file.
13
13
  [renamed]
14
+ "005-behavior" = "565-behavior"
15
+ "015-output" = "566-output"
16
+ "070-planning" = "567-planning"
17
+ "025-indexes" = "601-indexes"
18
+ "035-tasks" = "602-tasks"
19
+ "045-memory" = "603-memory"
20
+ "055-scratch" = "604-scratch"
21
+ "085-worktrees" = "605-worktrees"
22
+ "087-git" = "606-git"
23
+ "510-context" = "610-context"
24
+ "511-indexes" = "611-indexes"
25
+ "520-wireframes" = "620-wireframes"
26
+ "530-requirements" = "630-requirements"
27
+ "540-architecture" = "640-architecture"
28
+ "545-decisions" = "645-decisions"
29
+ "550-design" = "650-design"
30
+ "555-tasks" = "655-tasks"
31
+ "556-groundwork" = "656-groundwork"
32
+ "557-intake" = "657-intake"
33
+ "558-plan" = "658-plan"
34
+ "559-memory" = "659-memory"
35
+ "560-diagrams" = "660-diagrams"
36
+ "561-teach" = "661-teach"
37
+ "562-session" = "662-session"
38
+ "563-ready" = "663-ready"
39
+ "500-prose" = "800-prose"
40
+ "501-markdown" = "801-markdown"
41
+ "502-mermaid" = "802-mermaid"
42
+ "580-readme" = "880-readme"
43
+ "591-standard-authoring" = "891-standard-authoring"
44
+ "065-spelling" = "765-spelling"
45
+ "075-dependencies" = "775-dependencies"
46
+ "080-config-comments" = "780-config-comments"
47
+ "090-code-comments" = "790-code-comments"
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Route .canon/tasks/ edits to the tasks standard for filenames, frontmatter, and task file format
2
+ description: Route .canon/tasks/ edits to the tasks standard for task files and the board standard for priority.md and backlog.md
3
3
  paths:
4
4
  - '.canon/tasks/**'
5
5
  ---
@@ -9,4 +9,5 @@ paths:
9
9
  ## Authority
10
10
 
11
11
  - Follow the tasks standard for filenames, frontmatter, what belongs, and the task file format. It is the single source. Read it with `canon standards tasks`.
12
+ - Follow the board standard for `priority.md` and `backlog.md`, their readiness groups, and row order. Read it with `canon standards board`.
12
13
  - Never hand-edit `.canon/tasks/index.md`. A hook regenerates it from sibling frontmatter.
@@ -10,7 +10,7 @@ paths:
10
10
  ## Authority
11
11
 
12
12
  - Follow the diagrams standard for which question an entry answers, the entry kinds and their source signals, the frontmatter, and the explanation prose beneath the fence. It is the single source. Read it with `canon standards diagrams`.
13
- - Layout, budgets, accessibility, labels, and render verification inside the fence are a separate topic. `502-mermaid` routes them to `mermaid.md`.
13
+ - Layout, budgets, accessibility, labels, and render verification inside the fence are a separate topic. `802-mermaid` routes them to `mermaid.md`.
14
14
  - A diagram entry carries structure and flow, not implementation. Read the standard before adding or revising a kind.
15
15
 
16
16
  ## Scope
@@ -8,7 +8,7 @@ paths:
8
8
 
9
9
  ## What a handoff carries
10
10
 
11
- - Follow this rule rather than `555-tasks.md` for a `session-` file. A handoff is not a task and carries neither `## Outcomes` nor `## Findings`.
11
+ - Follow this rule rather than `655-tasks.md` for a `session-` file. A handoff is not a task and carries neither `## Outcomes` nor `## Findings`.
12
12
 
13
13
  ## Authority
14
14
 
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: Code placement, dependency, error, and naming choices a model does not make by default
3
+ ---
4
+
5
+ # Code standards
6
+
7
+ ## Placement
8
+
9
+ - Load the `canon:codebase-layout` skill before placing a new file, and report it rather than proceeding silently when it does not resolve.
10
+ - Prioritize native platform capabilities over third-party libraries.
11
+ - Ensure data and configuration reside in designated Single Source of Truth locations.
12
+
13
+ ## Errors
14
+
15
+ - Return structured error types for recoverable failures.
16
+ - Never expose internal implementation details in error messages.
17
+
18
+ ## Naming
19
+
20
+ - Prefix booleans with `is`, `has`, `should`, or `can`: `isLoading`, `hasAccess`.
21
+ - Prefix event handlers with `handle`: `handleClick`, `handleSubmit`.
@@ -9,10 +9,6 @@ paths:
9
9
 
10
10
  # TypeScript/JavaScript testing tooling
11
11
 
12
- ## Layer
13
-
14
- - Load the `canon:test-craft` skill to pick the layer a test belongs at before choosing the tooling below, and report it rather than proceeding silently when the skill does not resolve.
15
-
16
12
  ## Unit and integration
17
13
 
18
14
  - Use Vitest for unit and integration tests.
@@ -8,10 +8,6 @@ paths:
8
8
 
9
9
  # Python testing tooling
10
10
 
11
- ## Layer
12
-
13
- - Load the `canon:test-craft` skill to pick the layer a test belongs at before choosing the tooling below, and report it rather than proceeding silently when the skill does not resolve.
14
-
15
11
  ## Framework
16
12
 
17
13
  - Use `pytest` for all tests. Do not use `unittest.TestCase`.
@@ -12,4 +12,4 @@ paths:
12
12
  - Load it before drafting a passage, not after revising one.
13
13
  - Report it rather than proceeding silently when the skill does not resolve.
14
14
  - Do not work these rules from memory.
15
- - Punctuation, formatting, and file references are a separate topic. `501-markdown` routes them.
15
+ - Punctuation, formatting, and file references are a separate topic. `801-markdown` routes them.
@@ -11,4 +11,4 @@ paths:
11
11
  - Follow the markdown standard for headings, paragraph and list structure, code spans, punctuation, emphasis, file references, and the wording of a `title` or `description`. It is the single source. Read it with `canon standards markdown`.
12
12
  - Read it before a substantial markdown edit. Do not work the banned characters from memory.
13
13
  - Run `canon markdown audit <path>` after the edit, and rewrite the sentence carrying a hit rather than swapping the token for a near-synonym.
14
- - Voice, rhythm, and sentence construction are a separate topic. `500-prose` routes them.
14
+ - Voice, rhythm, and sentence construction are a separate topic. `800-prose` routes them.
@@ -11,4 +11,4 @@ paths:
11
11
  - Apply this rule only when the edit drafts or revises a Mermaid fence. Skip it on a markdown edit carrying no diagram.
12
12
  - Follow the mermaid standard for direction and layout, node and edge budgets, the accessibility fields, punctuation inside labels, and how a render is verified. It is the single source. Read it with `canon standards mermaid`.
13
13
  - Read it before drafting the fence. Do not work the layout or the budgets from memory.
14
- - Which diagram a document carries and what question it answers is a separate topic. `560-diagrams` routes it.
14
+ - Which diagram a document carries and what question it answers is a separate topic. `660-diagrams` routes it.
@@ -1,8 +1,9 @@
1
1
  extends = ""
2
- # All four folders whole. Every rule authored under them ships to a base
2
+ # Four audience groups whole. Every rule authored under them ships to a base
3
3
  # consumer, so adding one is a single edit rather than a file and a name here.
4
- # `snippets` carries the `@`-reference convention rule, which lost its only
5
- # other delivery path when `canon snippets install` retired. `ci` carries the
6
- # workflow rule, whose glob is the only inbound route to the `ci-workflow`
7
- # skill.
8
- rules = ["core", "claude", "snippets", "ci", "120-bash"]
4
+ # `canon` carries the toolkit workflow and canonical-doc rules, `claude` the
5
+ # session conduct and `.claude/` authoring rules, `tooling` the dev setup and
6
+ # CI workflow rules, and `writing` the prose and document-shape rules. The
7
+ # `code` group is left to the stacks that write code, so a docs or writing
8
+ # project loads no rule it can never apply.
9
+ rules = ["canon", "claude", "tooling", "writing", "120-bash"]
@@ -1,2 +1,2 @@
1
1
  extends = "base"
2
- rules = ["100-typescript"]
2
+ rules = ["code", "100-typescript"]
@@ -1,2 +1,2 @@
1
1
  extends = "base"
2
- rules = ["110-python", "340-pydantic", "330-testing-py", "360-security-server", "370-database"]
2
+ rules = ["code", "110-python", "340-pydantic", "330-testing-py", "360-security-server", "370-database"]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/canon",
3
3
  "type": "module",
4
- "version": "4.122.0",
4
+ "version": "4.124.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -91,13 +91,11 @@ log_step "Assert scaffold"
91
91
  # Standards and snippets name no path because neither corpus installs into a
92
92
  # target. A scaffold reads a standard through `canon standards <name>` and a
93
93
  # snippet through the plugin's live `claude/snippets` symlink, both resolving
94
- # against the toolkit rather than a copy this gate could assert on. The
95
- # `@`-reference convention rule is the one snippets-domain file that still
96
- # installs, since `base` carries `governance/rules/snippets/` as a
97
- # folder-whole entry the same way it does `core` and `claude`.
94
+ # against the toolkit rather than a copy this gate could assert on. The two
95
+ # rule paths stand for the `claude` and `canon` groups `base` takes whole.
98
96
  for path in "CLAUDE.md" ".claude/wiki/index.md" ".claude" "canon/context/index.md" "canon/wireframes/index.md" ".canon/diagrams/index.md" \
99
97
  ".prettierrc" ".editorconfig" ".lintstagedrc" ".husky/pre-commit" ".github/workflows/verify.yml" "scripts/verify.sh" \
100
- ".claude/rules/canon/core/000-constitution.md" ".claude/rules/canon/snippets/600-at-references.md"; do
98
+ ".claude/rules/canon/claude/565-behavior.md" ".claude/rules/canon/canon/604-scratch.md"; do
101
99
  if [ ! -e "$TARGET_DIR/$path" ]; then
102
100
  log_error "Missing after canon init: $path"
103
101
  fi
@@ -196,7 +196,7 @@ function frontmatter(text: string): string {
196
196
  *
197
197
  * A glob opening `**` reaches every folder in the tree, so it answers that a
198
198
  * file type is governed and never that a named path is. Counting one would
199
- * report every markdown path covered by `501-markdown` and leave the column
199
+ * report every markdown path covered by `801-markdown` and leave the column
200
200
  * saying nothing a reader could act on.
201
201
  */
202
202
  function isAnchored(glob: string): boolean {
@@ -234,7 +234,7 @@ export function register(program: Command): void {
234
234
  'after',
235
235
  [
236
236
  '',
237
- 'Measures the rule in .claude/rules/canon/core/070-planning.md that asks for',
237
+ 'Measures the rule in .claude/rules/canon/claude/567-planning.md that asks for',
238
238
  'the test before the code. It reports and never gates, because pairing',
239
239
  'a test to an implementation is a judgment.',
240
240
  '',
@@ -11,6 +11,7 @@ import {
11
11
  type DeclineOutcome,
12
12
  declineTask,
13
13
  type PlanCitations,
14
+ type PlanMove,
14
15
  planCitations,
15
16
  } from '@/tasks/archive'
16
17
  import {
@@ -154,9 +155,9 @@ export function register(program: Command): void {
154
155
  'after',
155
156
  [
156
157
  '',
157
- 'The task carries its plan with it when no other live task cites that',
158
- 'plan, and the archived task keeps a working Plan: pointer at the new',
159
- 'path. A plan several tasks share stays where it is.',
158
+ 'The task carries each plan its Plan: line links when no other live',
159
+ 'task cites that plan, and the archived task keeps a working pointer',
160
+ 'at each new path. A plan several tasks share stays where it is.',
160
161
  '',
161
162
  'The ready folder the task names moves to .canon/ready/archive/ with its',
162
163
  'plan, and the Ready: line and the plan path to it are retargeted. A',
@@ -260,6 +261,7 @@ export function register(program: Command): void {
260
261
  '',
261
262
  'Locations:',
262
263
  ' unstated the task carries no Plan: line',
264
+ ' several the Plan: line links more than one plan, named in targets',
263
265
  ' live the target resolves inside .canon/plans/',
264
266
  ' archived the target resolves inside .canon/plans/archive/',
265
267
  ' outside the target resolves somewhere else',
@@ -448,12 +450,14 @@ export function register(program: Command): void {
448
450
  '',
449
451
  'Exit codes:',
450
452
  ' 0 the line was added, corrected, or already correct',
451
- ' 1 refused, with the reason on stderr or in the JSON record',
453
+ ' 1 refused, including several-plans for a line linking more than one',
454
+ ' plan, with the reason on stderr or in the JSON record',
452
455
  '',
453
456
  'It writes Plan: [<label>](<target>) right after the H1, corrects the',
454
- 'target in place when the line exists, and resolves both a bare slug',
455
- 'and a board-relative path the way canon tasks plan-answers does. Safe',
456
- 'from a linked worktree, since it resolves the board root in-process.',
457
+ 'target in place when the line exists and names the one it replaced,',
458
+ 'and resolves both a bare slug and a board-relative path the way canon',
459
+ 'tasks plan-answers does. Safe from a linked worktree, since it',
460
+ 'resolves the board root in-process.',
457
461
  '',
458
462
  'Examples:',
459
463
  ' canon tasks plan-link v28.1-trigger-escalation dispatch-answer-gate',
@@ -793,6 +797,7 @@ function reportPlanLink(
793
797
  path: relative(root, outcome.path),
794
798
  plan: outcome.plan,
795
799
  action: outcome.action,
800
+ replaced: outcome.replaced,
796
801
  })}\n`,
797
802
  )
798
803
  return 0
@@ -801,6 +806,7 @@ function reportPlanLink(
801
806
  intro('canon tasks plan-link')
802
807
  logStep(outcome.action === 'unchanged' ? 'Already recorded' : 'Recorded')
803
808
  logInfo(`${outcome.stem} names plan ${outcome.plan}`)
809
+ if (outcome.replaced) logInfo(`replaced ${outcome.replaced}`)
804
810
  if (outcome.action !== 'unchanged') logAdd(relative(root, outcome.path))
805
811
  outro()
806
812
 
@@ -975,6 +981,10 @@ function reportCitations(
975
981
  function describeCitations(outcome: PlanCitations): string {
976
982
  if (outcome.location === 'unstated') return 'carries no Plan: line.'
977
983
 
984
+ if (outcome.location === 'several') {
985
+ return `links ${outcome.targets.length} plans (${outcome.targets.join(', ')}), so no single plan is the sweep's to settle.`
986
+ }
987
+
978
988
  if (outcome.location === 'archived') {
979
989
  return `points at ${outcome.target}, which an earlier sweep already archived.`
980
990
  }
@@ -1396,11 +1406,7 @@ function report(
1396
1406
  logStep('Archived')
1397
1407
  logRemove(relative(root, outcome.from))
1398
1408
  logAdd(relative(root, outcome.to))
1399
- if (outcome.plan) {
1400
- logRemove(relative(root, outcome.plan.from))
1401
- logAdd(relative(root, outcome.plan.to))
1402
- logInfo('retargeted the Plan: line')
1403
- }
1409
+ logPlanMoves(outcome.plans, root)
1404
1410
  if (outcome.ready) {
1405
1411
  logRemove(relative(root, outcome.ready.from))
1406
1412
  logAdd(relative(root, outcome.ready.to))
@@ -1414,6 +1420,24 @@ function report(
1414
1420
  return 0
1415
1421
  }
1416
1422
 
1423
+ function logPlanMoves(plans: readonly PlanMove[], root: string): void {
1424
+ for (const plan of plans) {
1425
+ logRemove(relative(root, plan.from))
1426
+ logAdd(relative(root, plan.to))
1427
+ }
1428
+ if (plans.length > 0) logInfo('retargeted the Plan: line')
1429
+ }
1430
+
1431
+ function planMovesFor(
1432
+ plans: readonly PlanMove[],
1433
+ root: string,
1434
+ ): readonly { readonly from: string; readonly to: string }[] {
1435
+ return plans.map((plan) => ({
1436
+ from: relative(root, plan.from),
1437
+ to: relative(root, plan.to),
1438
+ }))
1439
+ }
1440
+
1417
1441
  function recordFor(
1418
1442
  outcome: ArchiveOutcome,
1419
1443
  root: string,
@@ -1434,12 +1458,7 @@ function recordFor(
1434
1458
  to: relative(root, outcome.to),
1435
1459
  priorityRowRemoved: outcome.priorityRowRemoved,
1436
1460
  indexRegenerated: outcome.indexRegenerated,
1437
- plan: outcome.plan
1438
- ? {
1439
- from: relative(root, outcome.plan.from),
1440
- to: relative(root, outcome.plan.to),
1441
- }
1442
- : null,
1461
+ plans: planMovesFor(outcome.plans, root),
1443
1462
  ready: outcome.ready
1444
1463
  ? {
1445
1464
  from: relative(root, outcome.ready.from),
@@ -1537,11 +1556,7 @@ function reportDecline(
1537
1556
  logStep('Declined')
1538
1557
  logRemove(relative(root, outcome.from))
1539
1558
  logAdd(relative(root, outcome.to))
1540
- if (outcome.plan) {
1541
- logRemove(relative(root, outcome.plan.from))
1542
- logAdd(relative(root, outcome.plan.to))
1543
- logInfo('retargeted the Plan: line')
1544
- }
1559
+ logPlanMoves(outcome.plans, root)
1545
1560
  if (outcome.priorityRowRemoved) logInfo('cleared the ordering row')
1546
1561
  if (outcome.backlogRowRemoved) logInfo('cleared the backlog row')
1547
1562
  if (outcome.indexRegenerated) logInfo('regenerated index.md')
@@ -1571,11 +1586,6 @@ function declineRecordFor(
1571
1586
  priorityRowRemoved: outcome.priorityRowRemoved,
1572
1587
  backlogRowRemoved: outcome.backlogRowRemoved,
1573
1588
  indexRegenerated: outcome.indexRegenerated,
1574
- plan: outcome.plan
1575
- ? {
1576
- from: relative(root, outcome.plan.from),
1577
- to: relative(root, outcome.plan.to),
1578
- }
1579
- : null,
1589
+ plans: planMovesFor(outcome.plans, root),
1580
1590
  }
1581
1591
  }
@@ -101,12 +101,7 @@ const output = (text: string): Emission => ({ kind: 'output', text })
101
101
  /**
102
102
  * Rules no stack reaches, sorted the way `canon gov list` emits them.
103
103
  * `260-shadcn` and `320-tanstack-query` are opt-in libraries a project may not
104
- * want. `600-at-references` used to sit here too, shipping with no stack on
105
- * purpose since a rule under `claude/` would reach every base consumer through
106
- * the folder-whole entry there. Its own install channel, `canon snippets
107
- * install`, retired with nothing left to deliver it, so `base` now carries
108
- * `snippets` as a folder-whole entry of its own and the rule reaches every base
109
- * consumer through that instead.
104
+ * want.
110
105
  *
111
106
  * `130-go`, `140-php`, `335-testing-go`, and `336-testing-php` are opt-in by
112
107
  * `--add` until a Go or PHP stack ships, which `target-setup` reaches by
@@ -107,6 +107,7 @@ const TESTS_SCOPE = new RegExp(
107
107
  '^vitest\\.config\\.ts$',
108
108
  '^tsconfig\\.json$',
109
109
  '^package\\.json$',
110
+ '^commitlint\\.config\\.(js|test\\.ts)$',
110
111
  ...TEST_CORPORA_PATTERNS,
111
112
  ].join('|'),
112
113
  )
@@ -266,7 +266,7 @@ export function collectCitations(text: string): RawCitation[] {
266
266
  *
267
267
  * A rule spelling a whole path there is declaring that exact artifact, and a
268
268
  * body line naming it again is naming what the rule governs rather than
269
- * pointing a reader somewhere. `governance/rules/claude/560-diagrams.md` tells
269
+ * pointing a reader somewhere. `governance/rules/canon/660-diagrams.md` tells
270
270
  * its reader to convert a `.claude/DIAGRAMS.md` left by an older install, which
271
271
  * is correctly absent from this tree and correctly named in the rule.
272
272
  */
package/src/gov/list.ts CHANGED
@@ -31,7 +31,7 @@ export interface GovCatalog {
31
31
  /**
32
32
  * Reports each stack's own entries expanded, so a folder entry reaches a
33
33
  * consumer as the rules it stands for. the `setup` skill dedupes `--add` extras
34
- * against this list, and a stack answering `core` there would re-add every
34
+ * against this list, and a stack answering `canon` there would re-add every
35
35
  * rule that folder already carries.
36
36
  *
37
37
  * The `extends` chain is deliberately not resolved, which is what the bash
@@ -698,8 +698,8 @@ export function readRestated(root: string): RestatedReport {
698
698
 
699
699
  // Every candidate's rare set is invariant across the subject loop, so it is
700
700
  // built once here rather than per pair. The corpora multiply out to hundreds
701
- // of thousands of pairings, and rebuilding a set inside that is the shape
702
- // `.claude/rules/canon/core/040-performance.md` names.
701
+ // of thousands of pairings, and rebuilding a set inside that would dominate
702
+ // the run.
703
703
  const rareCandidates = candidates.map((candidate) => ({
704
704
  ...candidate,
705
705
  rare: distinctive(candidate.analysis),
package/src/init/steps.ts CHANGED
@@ -5,7 +5,7 @@ import type { DomainStep } from '@/init/run'
5
5
  export type RunFactory = (args: readonly string[]) => () => Promise<boolean>
6
6
 
7
7
  /**
8
- * States the same fact as `docs/target-projects.md`'s backup section in its
8
+ * States the same fact as `docs/target-migrations.md`'s backup section in its
9
9
  * own words. Keep the two in step by hand; nothing compares them.
10
10
  */
11
11
  const RECORDS_SETUP_NOTICE =
@@ -8,7 +8,7 @@ import { execa } from 'execa'
8
8
  *
9
9
  * `no-binary` is the binary being absent anywhere from the root upward.
10
10
  * `cspell` is a devDependency of this repository alone, per
11
- * `075-dependencies.md`'s ban on importing a transitive-only package, so a
11
+ * `775-dependencies.md`'s ban on importing a transitive-only package, so a
12
12
  * target project that never adopted it gets no coverage from this check
13
13
  * rather than a network fetch or a forced new dependency.
14
14
  *
@@ -35,7 +35,7 @@ const LEGACY_MOVES: ReadonlyMap<string, string> = new Map([
35
35
  * Scratch-root names a different migration moves out of scratch for good,
36
36
  * derived from that migration's own table rather than duplicated in a second
37
37
  * hand-kept list. `RECORD_LAYOUT_MOVES` names `memory-archive`, the
38
- * retired-entry archive `045-memory` says never to delete, and `PROMOTED_FOLDERS`
38
+ * retired-entry archive `603-memory` says never to delete, and `PROMOTED_FOLDERS`
39
39
  * names an evidence folder a durable record cites by name. A project that has
40
40
  * not run either migration still carries these at the scratch root, where an
41
41
  * ordinary slug's own age test would eventually offer them.
@@ -212,7 +212,7 @@ const PHASE_LABEL = /\bv\d+\.\d+(?!\.\d)\b/g
212
212
  * number, such as `create-rule`, `memory-review`, and `target-setup` already
213
213
  * write correctly, from matching. The segment group between `rules/` and the
214
214
  * numbered file admits both a governance-namespace path
215
- * (`canon/core/055-scratch.md`) and a project-namespace one
215
+ * (`canon/canon/604-scratch.md`) and a project-namespace one
216
216
  * (`project/<subdir>/<n>-<slug>.md`) without distinguishing them, since
217
217
  * either shape is the same broken citation.
218
218
  */