@erclx/canon 5.38.0 → 5.39.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 (149) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +12 -9
  4. package/claude/skills/auto-ship/SKILL.md +43 -23
  5. package/claude/skills/backlog-triage/SKILL.md +62 -53
  6. package/claude/skills/backlog-triage/references/apply.md +69 -0
  7. package/claude/skills/build-in-slices/SKILL.md +8 -4
  8. package/claude/skills/canon-cli/SKILL.md +5 -1
  9. package/claude/skills/canon-feedback/SKILL.md +18 -8
  10. package/claude/skills/canon-feedback-triage/SKILL.md +10 -3
  11. package/claude/skills/canvas-board/SKILL.md +36 -17
  12. package/claude/skills/ci-workflow/SKILL.md +5 -4
  13. package/claude/skills/code-craft/SKILL.md +10 -6
  14. package/claude/skills/codebase-layout/SKILL.md +3 -5
  15. package/claude/skills/context-fold/REQUIREMENT.md +4 -4
  16. package/claude/skills/context-fold/SKILL.md +42 -23
  17. package/claude/skills/context-fold/references/context-refresh.md +4 -3
  18. package/claude/skills/context-fold/references/context.md +79 -64
  19. package/claude/skills/create-rule/SKILL.md +7 -3
  20. package/claude/skills/create-skill/SKILL.md +27 -7
  21. package/claude/skills/create-skill/references/skill-reference.md +41 -17
  22. package/claude/skills/decision-escalate/SKILL.md +8 -5
  23. package/claude/skills/deploy-app/SKILL.md +1 -1
  24. package/claude/skills/deprecation-migration/SKILL.md +12 -4
  25. package/claude/skills/design-taste/SKILL.md +17 -11
  26. package/claude/skills/docs-sync/REQUIREMENT.md +1 -0
  27. package/claude/skills/docs-sync/SKILL.md +17 -6
  28. package/claude/skills/docs-sync/references/docs.md +54 -21
  29. package/claude/skills/docs-sync/references/readme.md +32 -8
  30. package/claude/skills/document-health/SKILL.md +3 -4
  31. package/claude/skills/draft-and-pick/SKILL.md +73 -47
  32. package/claude/skills/draft-doc/SKILL.md +9 -4
  33. package/claude/skills/draft-doc/references/context.md +4 -4
  34. package/claude/skills/draft-doc/references/docs.md +1 -0
  35. package/claude/skills/draft-doc/references/wiki.md +3 -2
  36. package/claude/skills/draft-figure/SKILL.md +9 -7
  37. package/claude/skills/draft-identity/SKILL.md +24 -52
  38. package/claude/skills/draft-identity/references/card-route.md +46 -0
  39. package/claude/skills/draft-ready/SKILL.md +19 -7
  40. package/claude/skills/draft-screencast/SKILL.md +6 -112
  41. package/claude/skills/draft-screencast/references/beats-template.md +119 -0
  42. package/claude/skills/draft-slides/SKILL.md +7 -4
  43. package/claude/skills/git-branch/SKILL.md +3 -3
  44. package/claude/skills/git-commit/SKILL.md +5 -3
  45. package/claude/skills/git-followup/SKILL.md +16 -9
  46. package/claude/skills/git-issue/SKILL.md +6 -5
  47. package/claude/skills/git-pr/SKILL.md +56 -44
  48. package/claude/skills/git-ship/SKILL.md +43 -34
  49. package/claude/skills/git-ship/references/ci-watch.md +31 -0
  50. package/claude/skills/git-split/SKILL.md +28 -100
  51. package/claude/skills/git-split/references/independent.md +40 -0
  52. package/claude/skills/git-split/references/stacked.md +73 -0
  53. package/claude/skills/git-stage/SKILL.md +9 -7
  54. package/claude/skills/git-worktree/SKILL.md +27 -49
  55. package/claude/skills/git-worktree/references/cleanup.md +55 -0
  56. package/claude/skills/markdown-craft/SKILL.md +2 -2
  57. package/claude/skills/markdown-craft/references/markdown.md +82 -53
  58. package/claude/skills/plan-feature/SKILL.md +52 -46
  59. package/claude/skills/plan-feature/references/batches.md +46 -0
  60. package/claude/skills/plan-groundwork/SKILL.md +60 -74
  61. package/claude/skills/plan-groundwork/references/output.md +48 -0
  62. package/claude/skills/plan-intake/SKILL.md +28 -21
  63. package/claude/skills/plan-intake-answer/SKILL.md +14 -13
  64. package/claude/skills/read-frames/SKILL.md +2 -0
  65. package/claude/skills/record-screencast/SKILL.md +31 -11
  66. package/claude/skills/review-address/SKILL.md +76 -158
  67. package/claude/skills/review-address/references/rebase-only.md +34 -0
  68. package/claude/skills/review-craft/SKILL.md +27 -11
  69. package/claude/skills/review-pr/SKILL.md +91 -40
  70. package/claude/skills/review-ui/SKILL.md +62 -37
  71. package/claude/skills/review-ui/references/hosted-preview.md +30 -0
  72. package/claude/skills/role-orchestrator/SKILL.md +105 -74
  73. package/claude/skills/role-orchestrator/references/orchestrator-filing.md +26 -0
  74. package/claude/skills/role-planner/SKILL.md +66 -64
  75. package/claude/skills/role-reviewer/SKILL.md +57 -46
  76. package/claude/skills/role-worker/SKILL.md +68 -63
  77. package/claude/skills/search-craft/SKILL.md +7 -5
  78. package/claude/skills/session-compact/SKILL.md +16 -11
  79. package/claude/skills/session-map/SKILL.md +31 -10
  80. package/claude/skills/session-relay/SKILL.md +32 -65
  81. package/claude/skills/session-resume/SKILL.md +18 -13
  82. package/claude/skills/session-worktree/SKILL.md +70 -42
  83. package/claude/skills/systematic-debugging/SKILL.md +6 -1
  84. package/claude/skills/target-check/SKILL.md +13 -6
  85. package/claude/skills/target-setup/SKILL.md +39 -27
  86. package/claude/skills/task-board/SKILL.md +68 -60
  87. package/claude/skills/task-board/references/create-report.md +36 -0
  88. package/claude/skills/task-complete/SKILL.md +20 -18
  89. package/claude/skills/teach-workspace/SKILL.md +61 -33
  90. package/claude/skills/test-craft/SKILL.md +2 -1
  91. package/claude/skills/test-first/SKILL.md +15 -9
  92. package/claude/skills/ui-checklist/SKILL.md +18 -16
  93. package/claude/skills/ux-audit/SKILL.md +9 -10
  94. package/claude/skills/ux-measure/SKILL.md +22 -18
  95. package/claude/skills/video-craft/SKILL.md +15 -7
  96. package/claude/skills/write-human/SKILL.md +9 -1
  97. package/claude/skills/youtube-transcripts/SKILL.md +2 -1
  98. package/docs/agents/context-audit-checks.md +19 -1
  99. package/docs/agents/context-audit.md +2 -2
  100. package/docs/agents/driver.md +1 -1
  101. package/docs/agents/hooks.md +21 -1
  102. package/docs/agents/index.md +10 -14
  103. package/docs/agents/indexes.md +25 -29
  104. package/docs/agents/install-and-sync.md +124 -235
  105. package/docs/agents/markdown-audit-density.md +39 -0
  106. package/docs/agents/markdown-audit-weight.md +9 -7
  107. package/docs/agents/markdown-audit.md +18 -14
  108. package/docs/agents/migrate.md +41 -16
  109. package/docs/agents/output-shape.md +60 -45
  110. package/docs/agents/overview.md +36 -12
  111. package/docs/agents/routing.md +1 -1
  112. package/docs/agents/rule-citations.md +1 -1
  113. package/docs/agents/skills-reach.md +1 -1
  114. package/docs/agents/targets.md +25 -77
  115. package/docs/target/migrations.md +1 -1
  116. package/docs/target/projects.md +2 -2
  117. package/docs/workflow/ai-workflow.md +2 -2
  118. package/docs/workflow/parallel-features.md +2 -2
  119. package/docs/workflow/skill-map.md +1 -1
  120. package/docs/workflow/visual-design-workflow.md +1 -1
  121. package/package.json +1 -1
  122. package/src/commands/claude.ts +1 -1
  123. package/src/commands/context.ts +106 -7
  124. package/src/commands/hooks.ts +63 -0
  125. package/src/commands/markdown.ts +169 -32
  126. package/src/context/audit.ts +256 -5
  127. package/src/context/classify/prompts.ts +1 -1
  128. package/src/context/gate.ts +23 -7
  129. package/src/context/shape-gated.ts +28 -0
  130. package/src/design/document.ts +1 -1
  131. package/src/design/tokens.ts +1 -1
  132. package/src/gate/measures.ts +15 -190
  133. package/src/gate/stages.ts +7 -23
  134. package/src/hooks/reply-links.ts +110 -0
  135. package/src/markdown/density.ts +258 -0
  136. package/src/markdown/gate.ts +57 -18
  137. package/src/markdown/reference-shape.ts +103 -0
  138. package/src/markdown/scope.ts +174 -0
  139. package/src/markdown/structure.ts +9 -59
  140. package/src/shipped/references.ts +1 -1
  141. package/tooling/claude/seeds/.claude/hooks/reply-links.sh +72 -0
  142. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +22 -1
  143. package/tooling/claude/seeds/.claude/settings.json +4 -0
  144. package/docs/agents/commands.md +0 -154
  145. package/docs/agents/docs.md +0 -27
  146. package/docs/agents/drift-surfaces.md +0 -201
  147. package/docs/agents/gov-detect.md +0 -47
  148. package/docs/agents/scripting.md +0 -142
  149. package/src/markdown/growth.ts +0 -43
@@ -22,7 +22,7 @@ Applies to per-domain narrative entries under `canon/context/`. Skip for `index.
22
22
 
23
23
  ## Scope
24
24
 
25
- Governs per-domain narrative entries under `canon/context/`: their structure, the decisions and gotchas they carry, and what they leave to the code.
25
+ Governs the structure of per-domain narrative entries under `canon/context/`, the folders and traps they carry, and what they leave to the code.
26
26
 
27
27
  Does not govern:
28
28
 
@@ -33,19 +33,20 @@ Does not govern:
33
33
 
34
34
  ## Organizing principle
35
35
 
36
- Weight the entry toward what cannot be re-derived from the repo. That single rule sorts every section below.
36
+ Weight the entry toward what a session cannot cheaply re-derive from the repo, and keep it true of the repository today. That single rule sorts every section below.
37
37
 
38
- - Folder structure is re-derivable with `ls`. Cheap to regenerate, expensive to maintain by hand. Cap it hard.
39
- - Command surfaces are re-derivable with `--help` and already live in the CLI reference under `docs/`. Duplicating flag lists creates a second source of truth that drifts.
40
- - Decisions and gotchas cannot be re-derived at any price. They are the reason the folder exists.
38
+ - A folder list is re-derivable with `ls`, so Layout spends its words on what each working folder does rather than on naming it
39
+ - Command surfaces are re-derivable with `--help` and already live in the CLI reference under `docs/`, so a copied flag list is a second source of truth that drifts
40
+ - How the domain reached its shape is in git and the pull request that changed it, so the entry carries no decisions and no history
41
+ - A trap the code does not self-document costs a session a failed run to find, so it earns a line
41
42
 
42
43
  ## What a working entry looks like
43
44
 
44
45
  An entry works when a session can read it and answer three questions without opening source:
45
46
 
46
- - Where do things live in this domain?
47
- - Why are they that way?
48
- - How do I add one more of what this domain holds?
47
+ - What does this domain own, and where does its boundary sit?
48
+ - What does each folder in it do now?
49
+ - Which trap would I hit working here?
49
50
 
50
51
  An entry that fails these is non-conforming regardless of whether it satisfies every section and ordering rule below. Shape is the means. These three questions are the test.
51
52
 
@@ -58,25 +59,32 @@ Both fields feed `canon/context/index.md` when regenerated.
58
59
 
59
60
  ## The closed set
60
61
 
61
- An entry carries four H2 sections and no other, in this order: `Overview`, `Layout`, `Decisions`, `Gotchas`. `canon context audit` reports any other H2 and `--gate` fails it. A topic of the domain's own, such as `Cache` or `Workflow`, is an H3 under one of the four, which is where a reader scanning the entry looks for it.
62
+ An entry carries three H2 sections and no other, being `Overview`, `Layout`, and `Gotchas` in that order. `canon context audit` reports any other H2 and `--gate` fails it.
62
63
 
63
- - `## Overview`: two to four lines. What the domain owns and where its boundary sits. Required.
64
- - `## Layout`: one line per folder in owns-X form, folders only and never files. Required, and omitted where the domain owns no paths in the repo, as with a domain covering external tools. Inventing a line to satisfy the heading is the padding banned below.
65
- - `## Decisions`: non-obvious choices and the reasoning behind them, each as an H3 or a bullet. The highest-value section in the folder and the one most often missing. A decision resting on how an outside tool, an installer, or the model behaves may close with one `Revisit when <finding>.` sentence naming the harm the decision prevents, and a decision resting on the project's own code takes none.
66
- - `## Gotchas`: workarounds, things tried and rejected, and invariants the code does not self-document, such as shape constraints, skip rules, and header semantics. Use `## Decisions` when the reader needs the reasoning rather than the invariant itself.
64
+ - `## Overview`: two to four lines on what the domain owns and where its boundary sits. Required.
65
+ - `## Layout`: the folders the domain owns, described below. Required unless the domain owns no paths, as with one covering external tools, since an invented line is padding.
66
+ - `## Gotchas`: at most five one-line bullets, each a trap true today. No H3, no paragraph, and no history. Omit the section when the domain has no trap.
67
67
 
68
- Include `Decisions` and `Gotchas` whenever the domain has content for them, and never pad an entry with an empty heading.
68
+ `## Decisions` is retired. The audit reports one everywhere and gates it under a folder rebuilt to this shape, alongside the Gotchas and Layout caps below.
69
69
 
70
- ### Where an extra topic goes
70
+ ### Layout
71
71
 
72
- - A command surface goes under `## Layout` as an H3, only when the domain has one, and only as a list of what each verb does. Flags and JSON shapes stay in the CLI reference under `docs/`, linked rather than restated.
73
- - The procedure for the domain's most common task goes under `## Layout` as an H3 such as `### Adding a <thing>`, since most sessions arrive asking how to add one more of the thing the domain holds.
74
- - Implementation detail that the one-line owns-X form cannot carry moves to `## Decisions` or `## Gotchas`.
72
+ Layout gives each folder doing real work its own H3, titled with the folder path in a code span, such as ``### `src/design/` ``.
73
+
74
+ - Open the H3 with a lead of one short paragraph stating what the folder does
75
+ - Follow it with at most five bullets on what the folder does now
76
+ - Put every trivial folder under `### Other folders` as a one-line bullet in owns-X form
77
+ - Name folders only, never files, and write no decisions and no history under any H3
78
+ - Write no heading below H3 under `## Layout`
79
+
80
+ The audit reports a Layout H3 titled neither a path nor `Other folders`, a folder H3 holding a second paragraph or a sixth bullet, and any H4 under Layout. Bullets count at any indent and across any paragraph, so a list split by a bold label still counts as one list.
75
81
 
76
82
  ### Ordering and headings
77
83
 
78
- - Name a heading for its subject as it stands (`### Cache`), never for the event that shaped it (`### The cache was the untested part, and the test moved it`). A heading is what a scan reads, so a narrating heading turns the table of contents into a changelog.
79
- - Entries get read top-down and often partially, so irreducible content sits above recoverable content.
84
+ Entries get read top-down and often partially, so the boundary sits above the folders and the folders above the traps.
85
+
86
+ - Name a heading for its subject as it stands, never for the event that shaped it, since a heading is what a scan reads
87
+ - A narrating heading such as `### The cache was the untested part, and the test moved it` turns the table of contents into a changelog
80
88
 
81
89
  ## The development entry
82
90
 
@@ -86,60 +94,77 @@ Only the `development` entry carries this section, as an H3 under `## Layout`. I
86
94
 
87
95
  ## What goes in
88
96
 
89
- - Per-domain narrative on how the code is structured and why
90
- - Decisions that constrain the domain, whether or not their reasoning touches another one. A decision lives in the entry of the domain it constrains.
91
- - Constraints, gotchas, things tried and rejected
92
- - Domain-specific conventions that do not fit a `paths:`-scoped rule
97
+ - What the domain owns and where its boundary sits
98
+ - What each working folder does now
99
+ - Traps a session would hit, being shape constraints, skip rules, header semantics, and invariants the code does not self-document
93
100
 
94
101
  ### Figures and references
95
102
 
96
- - A measured figure, closed with a trailing `Measured at <short-sha> on <YYYY-MM-DD>.` naming a commit rather than a pull request number or a branch. Carry one anchor per figure and rewrite it in place when the number is re-read, whether or not it moved. An absent anchor reads as unchecked.
97
- - A reference to another entry, spelled as the path that entry sits at rather than as its bare filename. A bare name resolves against whichever folder the reader is already in, so a domain that splits into subfolders strands every inbound reference and the break surfaces nowhere. A reference to a seed, a standard, or a file the project owns elsewhere keeps the form its own surface uses.
103
+ A measured figure and a reference to another entry each take a form that keeps them checkable.
104
+
105
+ - Close a measured figure with `Measured at <short-sha> on <YYYY-MM-DD>.`, naming a commit rather than a pull request number or a branch
106
+ - Carry one anchor per figure and rewrite it in place whenever the number is re-read, whether or not it moved, since an absent anchor reads as unchecked
107
+ - Spell a reference to another entry as the path that entry sits at, never as its bare filename
108
+ - A bare name resolves against whichever folder the reader is in, so a domain splitting into subfolders strands every inbound reference silently
109
+ - A reference to a seed, a standard, or a file the project owns elsewhere keeps the form its own surface uses
98
110
 
99
111
  ## What does not go in
100
112
 
101
- - Exhaustive file trees with a description per file. Name folders and their responsibility under `## Layout` instead.
113
+ - Exhaustive file trees with a description per file. Describe the folder under its Layout H3 instead.
102
114
  - Restated `--help` output, flag tables, or JSON shapes.
103
115
  - A catalog a `list` command already returns. Link the command instead, so the entry cannot drift from it.
104
- - Function-level documentation for implementation modules. Read the code. The exception is the public surface of a shared utility module, where the entry is how a session finds an existing helper instead of duplicating it.
116
+ - Function-level documentation for implementation modules. The exception is a shared utility module's public surface, where the entry is how a session finds a helper rather than duplicating it.
105
117
 
106
118
  ### Elsewhere
107
119
 
120
+ Some content belongs to another surface entirely.
121
+
108
122
  - Rules. Those go in `.claude/rules/<scope>.md` with a `paths:` glob.
109
- - Tutorials or human onboarding. Those go in `docs/` if a public audience exists.
123
+ - Tutorials or human onboarding, which go in `docs/` if a public audience exists
110
124
  - Generated content (API references). Generate, do not write by hand.
111
125
  - Anything already in `canon/REQUIREMENTS.md`.
112
126
 
113
- ### History and results
127
+ ### History and decisions
114
128
 
115
- - The history of how the domain reached its current shape. An entry describes the repository as it stands, so a change number, release label, or date attached to a change goes wherever the project tracks work.
116
- - A rejected alternative's provenance, which is the same rule at the one place the section above admits history. Keep what was tried and why it lost. Cut who tried it and when.
117
- - The route to a decision: the rounds of candidates, the tuning steps a threshold passed through, the review pass that caught a miss. State the decision, what lost, and why, once and in the present tense. Cut the route. Git and the change that introduced it keep it.
118
- - Measured results a generated file already carries. Point at the file instead of copying the figure, so a re-run cannot leave the entry behind.
129
+ An entry describes the repository as it stands, so the route that reached it lives in git and the change that introduced it.
130
+
131
+ - A decision and its rejected alternative, which the pull request carrying the change records
132
+ - The history of how the domain reached its current shape. A change number, release label, or date attached to a change goes wherever the project tracks work.
133
+ - The route to a choice, being the rounds of candidates, the tuning steps a threshold passed through, and the review pass that caught a miss
134
+ - Measured results a generated file already carries. Point at the file instead, so a re-run cannot leave the entry behind.
119
135
 
120
136
  ## Length
121
137
 
122
- - Aim for one entry per domain. Length is a symptom, not the defect, and the one hard cap is the whole-document ceiling `markdown.md` states.
123
- - Past roughly 150 rendered lines, check three things before adding more: whether the entry still covers a single domain, whether it has filled with content `ls` or `--help` reproduces, and whether it has accumulated the history of its own changes. Fix whichever is true rather than trimming to hit a number. The 150 is a diagnostic checkpoint and never gates. Rendered lines count as `markdown.md` defines them.
124
- - Never cut a `## Decisions` or `## Gotchas` entry to shorten a file. Cut a `## Layout` section or an H3 under it instead.
138
+ - Aim for one entry per domain. The section shape and the density limits `markdown.md` states bound the size, and the one hard cap is the whole-document ceiling it states.
139
+ - Past roughly 150 rendered lines, check whether the entry still covers one domain, has filled with content `ls` or `--help` reproduces, or has accumulated its own history
140
+ - Fix whichever is true rather than trimming. The 150 is a diagnostic checkpoint that never gates, counted in rendered lines as `markdown.md` defines them.
125
141
 
126
142
  ### Retiring and rewriting
127
143
 
128
- - Retire a decision or gotcha once its subject is gone, rewriting the bullet to state the current design rather than leaving the narration of what it replaced beside it. A rejected alternative is not a retired one, so what was tried and why it lost stays whatever its age. The rule above protects content whose subject is live, and this one releases content whose subject is not.
129
- - Rewrite a decision a later one replaced rather than appending the replacement beside it. The subject is still live, so the rule above does not reach it, and two bullets on one subject leave a reader to work out which of them is current. State the design that stands and keep the superseded reasoning only where it is the alternative that lost.
144
+ An entry states the repository that stands, so a bullet changes when its subject does.
145
+
146
+ - Edit a bullet that went untrue in place, and never append the correction beside it, since two bullets on one subject leave a reader to work out which is current
147
+ - Retire a gotcha once its trap is gone, rather than narrating what fixed it
148
+ - Drop a folder's H3 when the folder is removed, and move it when the folder moves
130
149
 
131
150
  ### Splitting and naming
132
151
 
133
- - Split into a folder (`canon/context/<domain>/<sub-area>.md`) when a domain has three or more sub-areas that do not fit cleanly in one file. That split is the natural ceiling.
134
- - Group whole single-file entries of two or more small domains into one folder when they share a kind, such as small feature domains that each own a verb. Each entry still covers one domain, and the folder's generated `index.md` carries a `subtitle` naming the kind. It names an entry to start with only when that entry frames the others. A grouping folder is not a split, so no entry inside it is a sub-area of another.
135
- - Name an entry inside a split or grouping folder per the `codebase-layout` skill, which never repeats the folder's name as the entry's stem or prefix.
136
- - Keep a split domain's `index.md` generated. The catalog body is rewritten on every regen, so the domain's own overview and layout belong in a sibling file rather than in it, and the `subtitle` is what names the file to start with.
137
- - Author a catalog that grows a row per shipped thing as a bullet list, never a markdown table. A table pads its columns to a shared width, so one row outgrowing its column reflows every row and turns a one-line edit into a whole-file rewrite that conflicts with any sibling branch. This is what forced the split above.
152
+ A domain outgrowing the ceiling splits into a folder, and small domains of one kind group into one.
153
+
154
+ - Keep one entry per domain, and split into a folder (`canon/context/<domain>/<sub-area>.md`) only when the rebuilt entry passes the 300-line ceiling `markdown.md` states, never on a count of sub-areas
155
+ - Group the single-file entries of two or more small domains into one folder when they share a kind, such as small feature domains that each own a verb
156
+ - A grouping folder is not a split, so each entry in it covers one domain. Its generated `index.md` carries a `subtitle` naming the kind, and an entry to start with only when one frames the others.
157
+ - Name an entry inside either folder per the `codebase-layout` skill, which never repeats the folder's name as the entry's stem or prefix
158
+ - Keep a split domain's `index.md` generated, since regen rewrites its body. The domain's own overview and layout go in a sibling file, which the `subtitle` names.
159
+
160
+ Author a catalog that grows a row per shipped thing as a bullet list, never a markdown table. A table pads its columns to a shared width, so one row outgrowing its column reflows every row and conflicts with any sibling branch.
138
161
 
139
162
  ## Examples
140
163
 
141
164
  ### Template
142
165
 
166
+ Each working folder takes an H3 with a one-paragraph lead and at most five bullets, and the rest sit under `### Other folders`.
167
+
143
168
  ```markdown
144
169
  ---
145
170
  title: API
@@ -156,31 +181,21 @@ never the reverse.
156
181
 
157
182
  ## Layout
158
183
 
159
- - `src/routes/` owns the HTTP layer and request parsing
160
- - `src/services/` owns business logic with no HTTP concerns
161
- - `src/db/` owns persistence and schema migrations
162
-
163
- ## Decisions
184
+ ### `src/routes/`
164
185
 
165
- ### Validation at the route boundary
186
+ Parses each request, validates it against its schema, and calls one service.
166
187
 
167
- Validation happens at the route boundary using a schema library. Services trust their inputs.
188
+ - Validation runs at the route boundary, so a service trusts its inputs
189
+ - Every handler issuing a cursor uses the shared encoder
190
+ - A handler returns a plain object, and the serializer wraps it in `{ data, meta }`
168
191
 
169
- ### Opaque pagination cursors
192
+ ### Other folders
170
193
 
171
- Pagination uses opaque cursor tokens, never offset+limit. Cursor format stays opaque to clients, which is why any handler that issues a cursor uses the shared encoder.
194
+ - `src/services/` owns business logic with no HTTP concerns
195
+ - `src/db/` owns persistence and schema migrations
172
196
 
173
197
  ## Gotchas
174
198
 
175
- ### The health endpoint skips auth
176
-
177
- The `/health` endpoint skips auth middleware. Liveness probes from the orchestrator do not carry tokens.
178
-
179
- ### The connection pool caps at 50
180
-
181
- Concurrent requests over that block until a connection frees.
182
-
183
- ### Handlers never wrap their return
184
-
185
- Route handlers return a plain object, and the serializer wraps it in `{ data, meta }`.
199
+ - The `/health` endpoint skips auth, since liveness probes carry no token
200
+ - The connection pool caps at 50, and a request past it blocks until one frees
186
201
  ```
@@ -7,7 +7,9 @@ metadata:
7
7
 
8
8
  # Create rule
9
9
 
10
- Author a project-local governance rule. The rule lives in the target project, not the toolkit, so `canon gov sync` never overwrites it: the sync engine orphans anything under `.claude/rules/project/` by location, before it ever checks the rule's name against the toolkit catalog. A rule written anywhere else under `.claude/rules/` survives the sync too, and the report offers it the path under the project subfolder it would take.
10
+ Author a project-local governance rule. The rule lives in the target project, not the toolkit, so `canon gov sync` never overwrites it.
11
+
12
+ The sync engine orphans anything under `.claude/rules/project/` by location, before checking its name against the toolkit catalog. A rule elsewhere under `.claude/rules/` survives too, and the report offers it the path under the project subfolder.
11
13
 
12
14
  ## Guards
13
15
 
@@ -49,9 +51,11 @@ A rule's filename is its slug alone, a one-to-three-word kebab topic with no num
49
51
 
50
52
  Read `${CLAUDE_SKILL_DIR}/references/rule.md` for frontmatter, body shape, and voice before writing the body. Do not work the shape from memory.
51
53
 
52
- Write `.claude/rules/project/<subdir>/<slug>.md`. Preview the resolved path, subdir, slug, and frontmatter, then write immediately. The tool permission dialog is the confirmation gate.
54
+ Write `.claude/rules/project/<subdir>/<slug>.md`. Preview the resolved path, subdir, slug, and frontmatter, then write immediately, since the tool permission dialog is the confirmation gate.
53
55
 
54
- Frontmatter carries the Claude shape. Path-scoped rules emit one `paths:` entry per glob. Always-on rules omit `paths:` entirely.
56
+ - Frontmatter carries the Claude shape
57
+ - Path-scoped rules emit one `paths:` entry per glob
58
+ - Always-on rules omit `paths:` entirely
55
59
 
56
60
  ```markdown
57
61
  ---
@@ -12,7 +12,7 @@ Read these files in parallel:
12
12
  - `${CLAUDE_SKILL_DIR}/references/skill.md`: skill structure, skill types, frontmatter fields, invocation rules
13
13
  - `${CLAUDE_SKILL_DIR}/references/skill-requirement.md`: what `REQUIREMENT.md` must answer, its sections, and its template
14
14
  - `${CLAUDE_SKILL_DIR}/references/skill-paths.md`: which root a path in the body resolves against, and how the body cites another skill's reference
15
- - `${CLAUDE_SKILL_DIR}/references/skill-disclosure.md`: the rules that bind a skill of any size, being where each reference is named, the contents block, the trigger and guard that stay in the body, and what moves to `references/`
15
+ - `${CLAUDE_SKILL_DIR}/references/skill-disclosure.md`: where each reference is named, the contents block, the trigger and guard that stay in the body, and what moves to `references/`
16
16
 
17
17
  ### Writing standards
18
18
 
@@ -32,17 +32,37 @@ Read these in the same pass:
32
32
 
33
33
  ## Steps
34
34
 
35
- 1. Answer three questions in writing before drafting anything. Tell the user and stop if a rule, a verb, or an existing skill already reaches this moment, or if the body carries no procedure a session would get wrong from first principles. A non-interactive run stops on both too, reporting which question failed and writing no folder:
35
+ 1. Answer three questions in writing before drafting anything.
36
36
  - Does a rule, a verb, or an existing skill already reach this moment? A folder that only wraps something already reachable duplicates it rather than adding to the catalog.
37
37
  - Does the body carry a procedure a session would get wrong from first principles? A one-line wrapper around a single command needs no skill.
38
38
  - Will anything invoke it other than the author typing its name? Carry this one into the drafted `REQUIREMENT.md`'s `Must not` section as a review criterion instead, since nothing can answer it before the skill has run.
39
+ - Tell the user and stop when the first answer is yes or the second is no. A non-interactive run stops on both too, reporting which question failed and writing no folder.
39
40
  2. Draft the full `SKILL.md` from the user's description, stating the current rule alone. An incident and the date it happened belong in the requirement's `Gap`, not in the body or a reference.
40
- 3. Draft the sibling `REQUIREMENT.md` from what the skill is for, in the shape the requirement standard states. Write the gaps from the user's description rather than from the drafted body, since a requirement derived from the body records whatever the draft overfitted to.
41
- 4. Confirm the skill name and both files with the user before writing, when a person can answer. Skip the confirmation when `CANON_NON_INTERACTIVE=1` is set or another skill's run invoked this one, such as `auto-ship` or a dispatched worker. Then put the three Step 1 answers and the two drafted paths in the output and continue to Step 5, since a question nobody reads parks the chain.
42
- 5. Resolve the root, then write `<root>/<name>/SKILL.md` and `<root>/<name>/REQUIREMENT.md`. The root is `.claude/skills/` in a target project. Where the project root holds `claude/.claude-plugin/plugin.json`, which is the toolkit's own checkout, the name decides: an `internal-*` skill goes under `.claude/skills/` and every other skill goes under `claude/skills/`, since the plugin ships that tree.
43
- 6. Run `canon claude skills audit --json` and read `findings.datedProvenance` for rows under `<root>/<name>/`. Move each row's incident into `REQUIREMENT.md` under `Gap`, cut the date from the file the row names, and re-run until no row names the folder.
41
+ 3. Draft the sibling `REQUIREMENT.md` from what the skill is for, in the shape the requirement standard states.
42
+ - Write the gaps from the user's description rather than from the drafted body, since a requirement derived from the body records whatever the draft overfitted to.
43
+ 4. Confirm the skill name and both files with the user before writing, when a person can answer.
44
+ - Skip the confirmation when `CANON_NON_INTERACTIVE=1` is set or another skill's run invoked this one, such as `auto-ship` or a dispatched worker.
45
+ - Then put the three Step 1 answers and the two drafted paths in the output and continue to Step 5, since a question nobody reads parks the chain.
46
+
47
+ ### Write and check
48
+
49
+ Steps 5 to 7 write the folder and check what landed before the run reports.
50
+
51
+ 5. Resolve the root, then write `<root>/<name>/SKILL.md` and `<root>/<name>/REQUIREMENT.md`.
52
+ - The root is `.claude/skills/` in a target project.
53
+ - Where the project root holds `claude/.claude-plugin/plugin.json`, which is the toolkit's own checkout, an `internal-*` skill goes under `.claude/skills/` and every other skill under `claude/skills/`, since the plugin ships that tree.
54
+ 6. Run `canon claude skills audit --json` and read `findings.datedProvenance` for rows under `<root>/<name>/`.
55
+ - Move each row's incident into `REQUIREMENT.md` under `Gap`, cut the date from the file the row names, and re-run until no row names the folder.
44
56
  - When `canon` does not resolve or its record carries no `datedProvenance` key, say the check did not run rather than reporting the skill clean.
57
+ 7. Run `canon markdown audit <root>/<name>/` over the new body and any references, and fix every ban and density finding it reports.
58
+ - Re-run it until it reports none, since every file in the folder is this run's draft.
59
+ - When `canon` does not resolve, say the audit did not run rather than reporting the folder clean.
45
60
 
46
61
  Every skill carries a requirement. A skill created without one is a gap someone closes in a later sweep, and the sweep has to reconstruct what the skill was for from the body it already shipped.
47
62
 
48
- The two-question check has a shipped precedent. A pull request dropped `git-stash` for wrapping a single git command that needed no skill body, and `release-changelog` for being low-frequency and invoked by no other skill. The first is question one, and the second is question three read back after the fact, which is why it stays a review criterion rather than something this skill can gate on.
63
+ The two-question check has a shipped precedent:
64
+
65
+ - A pull request dropped `git-stash` for wrapping a single git command that needed no skill body, which is question one
66
+ - It dropped `release-changelog` for being low-frequency and invoked by no other skill, which is question three read back after the fact
67
+
68
+ That is why the third question stays a review criterion rather than something this skill can gate on.
@@ -47,31 +47,44 @@ A reference failing these questions is non-conforming even when it satisfies eve
47
47
 
48
48
  ### Declaring scope
49
49
 
50
+ A reference that specifies shape exhaustively and jurisdiction nowhere cannot refuse a rule, so the rule with no obvious owner lands in whichever reference sits nearest.
51
+
50
52
  - Govern one document type per reference, or one attribute across every document. Split unrelated conventions into separate files.
51
- - Open with a `## Scope` section stating what the reference governs and what it does not, placed above the shape rules. A reference that specifies shape exhaustively and jurisdiction nowhere cannot refuse a rule, so the rule with no obvious owner lands in whichever reference sits nearest.
53
+ - Open with a `## Scope` section stating what the reference governs and what it does not, placed above the shape rules
52
54
  - Write it as one line naming the artifact or attribute and where it applies, then a `Does not govern:` list. Give each entry the excluded concern and the owner it goes to.
53
55
 
54
- #### The path and owners
56
+ ### The path and owners
57
+
58
+ The scope line names the governed path, and each exclusion names its owner.
59
+
60
+ - Name an owner in the same `references/` folder by bare filename, and one in another skill by its sibling path, `../<skill>/references/<name>.md`
61
+ - Name the surface instead where the owner is one, such as a coding rule, a project policy, or the code
62
+ - Put the governed path in backticks inside the first sentence of that line, anchored deep enough to resolve from a project root, since a bare folder name matches a same-named folder elsewhere
63
+ - A path held back until a later sentence sits beside every other path the statement mentions, including the ones it excludes
64
+ - Say in that same sentence when the reference governs an attribute, since an attribute has no path to name and the silence reads as an omission unless the sentence claims it
55
65
 
56
- - Name an owner in the same `references/` folder by bare filename and one in another skill by its sibling path, `../<skill>/references/<name>.md`. Name the surface instead where the owner is one, such as a coding rule, a project policy, or the code.
57
- - Put the governed path in backticks inside the first sentence of that line, anchored deep enough to resolve from a project root. A bare folder name matches a same-named folder elsewhere in the tree, and a path held back until a later sentence sits beside every other path the statement mentions, including the ones it excludes.
58
- - Say in that same sentence when the reference governs an attribute rather than a document type. An attribute is written across every document and has no path to name, so the silence reads as an omission unless the sentence claims it.
59
- - Cut an entry that names no owner at all. It is either excluding something nothing was going to claim, or it is a content exclusion, which the rule below sends to the shape rules instead.
66
+ Cut an entry that names no owner at all. It is either excluding something nothing was going to claim, or it is a content exclusion, which the rule below sends to the shape rules instead.
60
67
 
61
- #### Boundaries
68
+ ### Boundaries
62
69
 
63
- - Declare a boundary from both sides. A yield, an exemption, or a handoff stated in one reference alone is never checked against the reference on the other side of it, which is how two files come to claim the same rule or neither does.
64
- - Separate a jurisdiction exclusion from a content exclusion. The first names a concern another reference owns and belongs in `## Scope`. The second names what does not belong inside the document and stays with the shape rules. Merging them puts a boundary claim where no sibling will read it.
70
+ A yield, an exemption, or a handoff stated in one reference alone is never checked against the reference on the other side, which is how two files come to claim the same rule or neither does.
71
+
72
+ - Declare a boundary from both sides
73
+ - Separate a jurisdiction exclusion, naming a concern another reference owns, which belongs in `## Scope`, from a content exclusion, which stays with the shape rules
74
+ - Merging the two puts a boundary claim where no sibling will read it
65
75
  - Stay silent on a section the reference holds today but should not own. Claiming it makes the scope statement false the moment it moves, and the mismatch is the evidence that moves it.
66
76
 
67
77
  ### Naming the file
68
78
 
69
- - Name the file for the artifact the scope statement governs, taking the word from the deepest path segment that names the artifact rather than the folder holding it. `plan.md` over `.canon/plans/feature-<slug>.md` and `session.md` over `.canon/tasks/session-<slug>.md` both follow it.
79
+ Name the file for the artifact the scope statement governs, taking the word from the deepest path segment that names the artifact rather than the folder holding it. `plan.md` over `.canon/plans/feature-<slug>.md` and `session.md` over `.canon/tasks/session-<slug>.md` both follow it.
70
80
 
71
81
  ### Staying inside it
72
82
 
73
- - Name no path, filename, or folder outside the document type the reference governs. A reference reaches projects whose layout is their own, so a path borrowed from the authoring repository is wrong in a target and nothing reports it.
74
- - State the rule, never the mechanism enforcing it. Hooks, scripts, checks, and skill catalogs are facts about one repository. Name the condition the document must meet and let the enforcing surface name its own case.
83
+ A reference reaches projects whose layout is their own, so what it names holds in any of them.
84
+
85
+ - Name no path, filename, or folder outside the document type the reference governs, since a path borrowed from the authoring repository is wrong in a target and nothing reports it
86
+ - State the rule, never the mechanism enforcing it, since hooks, scripts, checks, and skill catalogs are facts about one repository
87
+ - Name the condition the document must meet, and let the enforcer name its own case
75
88
  - Invent inline examples rather than citing a real file elsewhere in the project. A cited file moves or is deleted and the reference goes stale in silence.
76
89
 
77
90
  ## Frontmatter
@@ -82,9 +95,10 @@ A reference failing these questions is non-conforming even when it satisfies eve
82
95
 
83
96
  ## Structure
84
97
 
85
- - Use sentence case for every heading
98
+ - Use sentence case for every heading, and stop at `###`, since `markdown.md` allows no deeper one
86
99
  - Flat `##` rule groups for a single-topic reference. Group `##` headers by concern for a multi-topic one.
87
- - When one `##` section covers more than one sub-concern, split its bullets into `###` subgroups, one subgroup per sub-concern. A flat bullet list under an `##` covers a single sub-concern. Roughly seven bullets is a signal to split, not a hard cap.
100
+ - When one `##` section covers more than one sub-concern, split its bullets into `###` subgroups, one per sub-concern, each opening with a lead sentence
101
+ - A flat bullet list under an `##` covers a single sub-concern, and a run past the bullet limit `markdown.md` states is the signal to split it
88
102
  - Order groups from the most-used rule down to the edge case
89
103
 
90
104
  ## Rules
@@ -93,7 +107,7 @@ A reference failing these questions is non-conforming even when it satisfies eve
93
107
  - State the forbidden shape rather than enumerating allowed options, so a rule survives new categories
94
108
  - Cut any rule that resists a crisp one-line phrasing
95
109
  - Do not pad with filler prose. Every line earns its place as a usable reference entry.
96
- - Close a ban asserting how the model or a tool behaves with one `Revisit when <finding>.` sentence, since that claim can stop holding while the ban reads the same. A style, safety, or consistency ban takes none, and filling one with a condition is padding.
110
+ - Close a ban asserting how the model or a tool behaves with one `Revisit when <finding>.` sentence, since that claim can stop holding. A style, safety, or consistency ban takes none.
97
111
 
98
112
  ## Success criterion
99
113
 
@@ -115,7 +129,8 @@ Answer all four before editing, and carry the answers into wherever the change i
115
129
 
116
130
  ### What justifies a change
117
131
 
118
- - Change a reference on a failure, not on a finding. A finding is that the docs say X or a paper suggests Y. A failure is a conforming artifact that satisfied every shape rule and still missed the success criterion.
132
+ Change a reference on a failure, not on a finding. A finding is that the docs say X or a paper suggests Y, and a failure is a conforming artifact that satisfied every shape rule and still missed the success criterion.
133
+
119
134
  - Park findings wherever the project tracks pending work, or in the reference's own backlog section when it tracks none. They are hypotheses to test, not instructions to apply.
120
135
  - Cite the failing artifact in the change that fixes it, so the next reader can tell which rules were paid for by evidence.
121
136
 
@@ -129,17 +144,22 @@ Answer all four before editing, and carry the answers into wherever the change i
129
144
  ## Template
130
145
 
131
146
  - Carry one fenced template of the document the reference governs, so an author copies a shape instead of reconstructing it from prose.
132
- - Bind this to a reference governing a document type. An attribute reference governs a scan, a string, or a label rather than a file, so it has no document to template and carries none. State that exemption in the sentence declaring it an attribute reference.
147
+ - Bind this to a reference governing a document type. An attribute reference governs a scan, a string, or a label rather than a file, so it carries none.
148
+ - State that exemption in the sentence declaring it an attribute reference
133
149
  - Place the template below the rules it satisfies, under a `## Template` heading or inside the section holding those rules.
134
150
 
135
151
  ### What the template shows
136
152
 
153
+ The template is a skeleton an author fills, never a document of its own.
154
+
137
155
  - Show the skeleton alone: every required section, one placeholder line for what each holds. A full worked document is a second document to maintain.
138
156
  - Write placeholders in angle brackets rather than copying a real document. A copied file goes stale, and its backticked filenames read as citations to anything parsing the reference.
139
157
  - Switch to a bare word where the fenced language reads `<` as syntax of its own, as Mermaid and HTML do, and say in the line above the fence that the names are placeholders.
140
158
 
141
159
  ### Load-bearing text
142
160
 
161
+ The template is the only place an author learns which strings a consuming tool parses.
162
+
143
163
  - Carry any header, key, or label a consuming tool parses verbatim. The template is the only place an author learns which strings are load-bearing.
144
164
  - Treat the template as authoritative where it and the prose disagree. An author copies the block, so a contradiction ships as the block.
145
165
 
@@ -178,6 +198,10 @@ A <document type> failing these is non-conforming even when it satisfies every s
178
198
 
179
199
  ## <Shape rule group>
180
200
 
201
+ ### <Sub-concern>
202
+
203
+ <A lead sentence naming what this sub-concern decides.>
204
+
181
205
  - <imperative rule, one concern per bullet>
182
206
 
183
207
  ## Template
@@ -15,7 +15,7 @@ One batch is the whole point. A session that asks one question, acts, then asks
15
15
  ## Guards
16
16
 
17
17
  - If nothing is open, stop: `❌ Nothing to escalate. Every open call is one this session can make.`
18
- - Escalate only a decision whose answer turns on the operator's preference. A judgment call with two or three reasonable options the session can weigh is a pick with the tradeoff stated in one sentence, taken without asking.
18
+ - Escalate only a decision whose answer turns on the operator's preference. A judgment call the session can weigh between two or three options is a pick taken without asking, its tradeoff in a sentence.
19
19
  - Escalate only what is open now. A decision already taken this session goes to the artifact that records it rather than back to the operator.
20
20
  - Do not act on any decision in the batch before it is answered. Continue the work that depends on none of them.
21
21
  - Do not escalate a question the session can answer by reading the repository. Read first, and escalate what the tree does not settle.
@@ -39,11 +39,11 @@ Cap the batch at four. A structured question tool takes four, and a batch past t
39
39
 
40
40
  ## Step 3: put the batch
41
41
 
42
- Put every question in one turn. Never split the batch across turns and never ask the first while the rest stay unstated.
42
+ Put every question in one turn, never splitting the batch across turns or asking the first while the rest stay unstated. Send the batch through a structured question tool wherever the session runs on one, and write the shape below where it does not. One call carries the whole set, one entry per decision, so the operator answers them together.
43
43
 
44
- Send the batch through a structured question tool wherever the session runs on one, and write the shape below where it does not. What a batch adds is that one call carries the whole set, with one entry per decision, so the operator answers them together instead of one per turn.
44
+ The test is the surface rather than the project's instruction file. A target scaffolded before the rule shipped still reaches the tool, and loses only the option shape `CLAUDE.md` states, which the example below carries.
45
45
 
46
- The test is the surface rather than the project's instruction file. A target scaffolded before the rule shipped still reaches the tool, and what it loses is the option shape `CLAUDE.md` states, which the example below carries instead.
46
+ ### The fallback shape
47
47
 
48
48
  Batch shape on the fallback surface:
49
49
 
@@ -69,7 +69,10 @@ An operator who answers some and not others has answered those. Continue on the
69
69
 
70
70
  Restate each pick in one line, then continue the work.
71
71
 
72
- A pick that changes a written artifact goes into that artifact under the rule its own standard sets. An answer to an open plan question rewrites that question's `- Suggested:` line to the pick and names the operator as its source, leaving the `- Answer:` slot blank, per `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`. The standard bars a session from filling that slot even when the operator supplied the pick, and the blank slot resolves to the rewritten suggestion, so the record carries the operator's decision either way. A pick that settles nothing written stays in the session.
72
+ A pick that changes a written artifact goes into it under the rule its own standard sets, and a pick that settles nothing written stays in the session.
73
+
74
+ - An answer to an open plan question rewrites its `- Suggested:` line to the pick, naming the operator as source, per `${CLAUDE_SKILL_DIR}/../plan-feature/references/plan.md`
75
+ - Leave the `- Answer:` slot blank, since the standard bars a session from filling it, and the blank resolves to the rewritten suggestion
73
76
 
74
77
  Output after the answers land:
75
78
 
@@ -14,7 +14,7 @@ Runs the one-time setup a deploy needs before the host can publish on push, stop
14
14
  - Never accept an API token as input, in a prompt, an argument, or a file. Verify a secret's presence with `gh secret list` rather than asking for or reading its content.
15
15
  - Read every account, org, or project ID from the host CLI's own session or files, never from the operator, and pipe it into `gh secret set` rather than reporting it first.
16
16
  - Never reimplement a host CLI call or `gh secret set` as a hand-built HTTP call. Call the tools directly.
17
- - If the project name is not supplied, derive it from the repository's own name (`basename` of `git remote get-url origin`, stripped of a trailing `.git`) and confirm it in the preview rather than asking first.
17
+ - If the project name is not supplied, derive it as the `basename` of `git remote get-url origin` without a trailing `.git`, and confirm it in the preview rather than asking first
18
18
 
19
19
  ## Step 1: pick the host
20
20
 
@@ -7,7 +7,11 @@ metadata:
7
7
 
8
8
  # Deprecation and migration
9
9
 
10
- A session asked to remove something tends to grep for its name, find nothing it recognizes, and delete it. What it misses calls the thing by a string, a config key, or a copy shipped somewhere the search never looked, and the first anyone hears of it is a break in a place the diff never touched. The reverse failure is as common: a replacement ships, the old path gets a deprecation note, and nobody ever moves the callers, so both live on with no owner. This skill carries the discipline that ends with the old surface gone and every caller working.
10
+ A session asked to remove something tends to grep for its name, find nothing it recognizes, and delete it. What it misses calls the thing by a string, a config key, or a copy the search never reached, and breaks somewhere the diff never touched.
11
+
12
+ The reverse failure is as common. A replacement ships, the old path gets a deprecation note, and nobody moves the callers, so both live on with no owner. This skill ends with the old surface gone and every caller working.
13
+
14
+ ## When to load
11
15
 
12
16
  Load it before deleting or replacing anything a caller outside the current change could reach. Skip it for code introduced on the same branch that nothing has shipped against yet.
13
17
 
@@ -32,7 +36,7 @@ Answer four questions before writing a deprecation notice, and keep the surface
32
36
  The owner of a surface moves its callers, the Churn Rule. Announcing a deprecation and waiting for callers to migrate pushes the work onto everyone downstream, and most of them never do it.
33
37
 
34
38
  - Migrate every caller you can reach in the repository you own, as part of the deprecation work rather than after it.
35
- - For a caller you cannot edit, such as another team's code or a published consumer, ship a backward-compatible path or migration notes they can apply, and track them as a caller still on the old surface.
39
+ - For a caller you cannot edit, such as another team's code or a published consumer, ship a compatible path or migration notes, and track it as a caller still on the old surface
36
40
  - Never add a feature to the deprecated surface. New behavior goes on the replacement, which gives callers a reason to move.
37
41
 
38
42
  ## Prove zero consumers before removal
@@ -43,13 +47,13 @@ A clean search for one spelling of the name proves only that this spelling is ab
43
47
  - **String references**, such as a handler looked up by name, a command dispatched from a table, a reflection call, or a test fixture naming it.
44
48
  - **Configuration**, including build files, CI workflows, environment defaults, and data files that name the surface.
45
49
  - **Documentation and examples**, which callers copy from long after the code moves.
46
- - **Copies outside the repository**, such as a published package, an installed copy in another project, a shipped binary, a script someone runs from their own machine, or a saved request in an API client.
50
+ - **Copies outside the repository**, such as a published package, an installed copy in another project, a shipped binary, a script run from someone's machine, or a saved API client request.
47
51
 
48
52
  Say which kinds your search could not reach and why, rather than reporting zero. "No callers in this repository, but a published release still exports it" is a finding a reader can act on, since it names where the remaining risk sits. A bare "no callers" is a guess.
49
53
 
50
54
  ## Bridge with an adapter or a strangler
51
55
 
52
- - **Adapter.** Keep the old interface as a thin layer over the new implementation, so callers keep working while the implementation moves underneath them. The adapter holds no logic of its own and goes once its last caller moves.
56
+ - **Adapter.** Keep the old interface as a thin layer over the new implementation, so callers keep working while it moves underneath. It holds no logic of its own and goes once its last caller moves.
53
57
  - **Strangler.** Route callers to the new path a group at a time, leaving the old path serving the rest. The old path is done when it serves nothing, and only then is it removed.
54
58
  - Prefer the adapter when the interface stays and the implementation changes. Prefer the strangler when callers have to change how they call.
55
59
 
@@ -96,6 +100,8 @@ Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidan
96
100
 
97
101
  ### Behavior and callers
98
102
 
103
+ Behavior and callers carry their own signs.
104
+
99
105
  - You are adding behavior to the surface being deprecated.
100
106
  - Your report says "no callers" without naming the caller kinds the search could not reach.
101
107
  - A caller outside the repository was found and the plan still deletes the original.
@@ -110,6 +116,8 @@ Check each line against what the change produced. A line answering no is fixed o
110
116
 
111
117
  ### Checks and fallbacks
112
118
 
119
+ Hold the checks and the fallbacks to the same test.
120
+
113
121
  - The zero-consumers check covered every caller kind, and the report names the kinds it could not reach.
114
122
  - No change both adds the replacement and removes the original.
115
123
  - Every fallback left in place states when it goes and who removes it.