@erclx/canon 5.30.0 → 5.31.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 (84) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/build-in-slices/REQUIREMENT.md +1 -1
  3. package/claude/skills/build-in-slices/references/adopted.md +1 -1
  4. package/claude/skills/canon-feedback-triage/SKILL.md +2 -0
  5. package/claude/skills/context-fold/SKILL.md +1 -1
  6. package/claude/skills/create-skill/SKILL.md +1 -1
  7. package/claude/skills/create-standard/SKILL.md +1 -1
  8. package/claude/skills/design-extract/SKILL.md +2 -2
  9. package/claude/skills/design-taste/SKILL.md +1 -1
  10. package/claude/skills/docs-sync/SKILL.md +1 -1
  11. package/claude/skills/draft-doc/SKILL.md +1 -1
  12. package/claude/skills/draft-figure/SKILL.md +1 -1
  13. package/claude/skills/draft-figure/references/mermaid.md +1 -1
  14. package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
  15. package/claude/skills/git-issue/SKILL.md +1 -1
  16. package/claude/skills/git-pr/SKILL.md +1 -1
  17. package/claude/skills/git-stage/SKILL.md +1 -1
  18. package/claude/skills/markdown-craft/REQUIREMENT.md +23 -0
  19. package/claude/skills/markdown-craft/SKILL.md +17 -0
  20. package/{standards → claude/skills/markdown-craft/references}/markdown.md +14 -7
  21. package/claude/skills/memory-capture/SKILL.md +1 -1
  22. package/claude/skills/memory-review/SKILL.md +1 -1
  23. package/claude/skills/plan-feature/REQUIREMENT.md +2 -1
  24. package/claude/skills/plan-feature/SKILL.md +12 -2
  25. package/claude/skills/review-address/SKILL.md +1 -1
  26. package/claude/skills/review-address/references/post-review-findings.md +1 -1
  27. package/claude/skills/review-pr/references/post.md +2 -2
  28. package/claude/skills/review-ui/references/post.md +1 -1
  29. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -0
  30. package/claude/skills/target-setup/references/indexes.md +1 -1
  31. package/claude/skills/test-first/REQUIREMENT.md +1 -1
  32. package/claude/skills/write-human/SKILL.md +1 -1
  33. package/docs/agents/commands.md +5 -4
  34. package/docs/agents/context-audit-checks.md +1 -1
  35. package/docs/agents/counts.md +3 -3
  36. package/docs/agents/index.md +1 -0
  37. package/docs/agents/install-and-sync.md +3 -3
  38. package/docs/agents/markdown-audit.md +1 -1
  39. package/docs/agents/routing.md +1 -1
  40. package/docs/agents/tasks-plans.md +1 -1
  41. package/docs/agents/test-order.md +1 -1
  42. package/docs/agents/upstream.md +70 -0
  43. package/docs/workflow/skill-map-on-request.md +1 -1
  44. package/governance/renames.toml +0 -4
  45. package/governance/rules/standards/plan.md +1 -0
  46. package/governance/rules/writing/markdown.md +23 -0
  47. package/package.json +1 -1
  48. package/scripts/core/install-check.sh +1 -1
  49. package/src/claude/cases/authoring.ts +5 -0
  50. package/src/claude/cases/misc.ts +0 -4
  51. package/src/claude/skills-reach.ts +1 -1
  52. package/src/cli/help.ts +2 -0
  53. package/src/cli.ts +2 -0
  54. package/src/commands/claude.ts +1 -1
  55. package/src/commands/gov.ts +2 -2
  56. package/src/commands/records.ts +19 -1
  57. package/src/commands/upstream.ts +295 -0
  58. package/src/context/audit.ts +1 -1
  59. package/src/gate/stages.ts +0 -1
  60. package/src/markdown/structure.ts +1 -1
  61. package/src/records/backup.ts +1 -0
  62. package/src/records/validate.ts +55 -0
  63. package/src/roots/record.ts +1 -0
  64. package/src/standards/read.ts +21 -1
  65. package/src/tasks/answers.ts +14 -1
  66. package/src/tasks/stack.ts +176 -0
  67. package/src/upstream/catalog.ts +112 -0
  68. package/src/upstream/cursor.ts +120 -0
  69. package/src/upstream/digest.ts +75 -0
  70. package/src/upstream/releases.ts +169 -0
  71. package/standards/index.md +0 -1
  72. package/standards/plan.md +25 -12
  73. package/standards/rule.md +1 -1
  74. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +1 -1
  75. package/claude/skills/index-lookup/REQUIREMENT.md +0 -35
  76. package/claude/skills/index-lookup/SKILL.md +0 -44
  77. package/governance/rules/canon/601-indexes.md +0 -9
  78. package/governance/rules/claude/565-behavior.md +0 -27
  79. package/governance/rules/claude/567-planning.md +0 -16
  80. package/governance/rules/claude/575-hooks.md +0 -16
  81. package/governance/rules/claude/576-settings.md +0 -13
  82. package/governance/rules/claude/592-claude-md.md +0 -19
  83. package/governance/rules/standards/markdown.md +0 -16
  84. package/governance/rules/writing/800-prose.md +0 -15
@@ -0,0 +1,169 @@
1
+ import { $ } from 'bun'
2
+ import { gitEnv } from '@/git/env'
3
+ import { compareVersions } from '@/upstream/cursor'
4
+
5
+ const RELEASES_URL =
6
+ 'https://api.github.com/repos/anthropics/claude-code/releases'
7
+ const PER_PAGE = 100
8
+ const MAX_PAGES = 10
9
+
10
+ /** The subset of a GitHub release the digest reads. */
11
+ export interface Release {
12
+ readonly tag_name: string
13
+ readonly published_at: string
14
+ readonly body: string | null
15
+ readonly draft?: boolean
16
+ }
17
+
18
+ export interface ReleaseLine {
19
+ readonly version: string
20
+ readonly date: string
21
+ readonly text: string
22
+ }
23
+
24
+ export type FetchFailure = 'rate-limited' | 'network' | 'http'
25
+
26
+ export type PageResult =
27
+ | { readonly ok: true; readonly releases: readonly Release[] }
28
+ | {
29
+ readonly ok: false
30
+ readonly reason: FetchFailure
31
+ readonly message: string
32
+ }
33
+
34
+ /** Page numbers start at 1. A page past the feed's end comes back empty. */
35
+ export type PageFetcher = (page: number) => Promise<PageResult>
36
+
37
+ export type Walk =
38
+ | { readonly kind: 'reached'; readonly releases: readonly Release[] }
39
+ | { readonly kind: 'cursor-missing'; readonly cursor: string }
40
+ | {
41
+ readonly kind: 'failed'
42
+ readonly reason: FetchFailure
43
+ readonly message: string
44
+ }
45
+
46
+ // Ported from the groundwork's mechanical-drop script. The first group anchors on the line
47
+ // start, the rest match anywhere because the surface they name can sit mid-line.
48
+ const DROP =
49
+ /^(Fixed|\[VSCode\]|\[Claude Tag\]|\[Code Review\]|Windows:|Self-hosted)|apps gateway|managed setting|OpenTelemetry|Bedrock|Vertex|screen reader/i
50
+ const KEEP = /^(Added|Changed|Removed|Improved|Deprecated)/
51
+ const BULLET = /^\s*[-*] (.*)$/gm
52
+ const DIFFERENCE_LINE = /^(\[[^\]]+\] )?(Changed|Removed|Deprecated)/
53
+ const BACKTICKED = /`([^`]{3,60})`/g
54
+ const DISTINCTIVE = /[-/.A-Z]/
55
+
56
+ export function versionOf(tag: string): string {
57
+ return tag.replace(/^v/, '')
58
+ }
59
+
60
+ export function keepLines(release: Release): ReleaseLine[] {
61
+ const version = versionOf(release.tag_name)
62
+ const date = release.published_at.slice(0, 10)
63
+
64
+ return [...(release.body ?? '').matchAll(BULLET)]
65
+ .map((match) => match[1] ?? '')
66
+ .filter((text) => KEEP.test(text) && !DROP.test(text))
67
+ .map((text) => ({ version, date, text }))
68
+ }
69
+
70
+ export function extractIdentifiers(text: string): string[] {
71
+ if (!DIFFERENCE_LINE.test(text)) return []
72
+
73
+ return [...text.matchAll(BACKTICKED)]
74
+ .map((match) => match[1] ?? '')
75
+ .filter((name) => DISTINCTIVE.test(name))
76
+ }
77
+
78
+ /**
79
+ * Collects the releases newer than the cursor, newest first.
80
+ *
81
+ * The walk stops at the first release whose version is not newer than the
82
+ * cursor, wherever it sits, so a range crossing a page boundary is read whole
83
+ * and a cursor naming a version the feed never carried, as 2.1.256 is not,
84
+ * still bounds the range. A feed that ends with every release newer than the
85
+ * cursor reports `cursor-missing` instead of returning all of it.
86
+ */
87
+ export async function walkReleases(
88
+ cursor: string,
89
+ fetchPage: PageFetcher,
90
+ perPage: number = PER_PAGE,
91
+ ): Promise<Walk> {
92
+ const collected: Release[] = []
93
+
94
+ for (let page = 1; page <= MAX_PAGES; page++) {
95
+ const result = await fetchPage(page)
96
+ if (!result.ok) {
97
+ return { kind: 'failed', reason: result.reason, message: result.message }
98
+ }
99
+
100
+ for (const release of result.releases) {
101
+ if (release.draft) continue
102
+ if (compareVersions(versionOf(release.tag_name), cursor) <= 0) {
103
+ return { kind: 'reached', releases: collected }
104
+ }
105
+ collected.push(release)
106
+ }
107
+
108
+ if (result.releases.length < perPage) break
109
+ }
110
+
111
+ return { kind: 'cursor-missing', cursor }
112
+ }
113
+
114
+ export function githubPageFetcher(
115
+ env: Record<string, string | undefined> = process.env,
116
+ ): PageFetcher {
117
+ const token = env.GH_TOKEN ?? env.GITHUB_TOKEN
118
+ const headers: Record<string, string> = {
119
+ Accept: 'application/vnd.github+json',
120
+ 'User-Agent': 'canon-upstream',
121
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
122
+ }
123
+
124
+ return async (page) => {
125
+ try {
126
+ const response = await fetch(
127
+ `${RELEASES_URL}?per_page=${PER_PAGE}&page=${page}`,
128
+ { headers },
129
+ )
130
+ if (response.status === 403 || response.status === 429) {
131
+ return {
132
+ ok: false,
133
+ reason: 'rate-limited',
134
+ message:
135
+ 'GitHub refused the request. Set GH_TOKEN or GITHUB_TOKEN to lift the hourly limit.',
136
+ }
137
+ }
138
+ if (!response.ok) {
139
+ return {
140
+ ok: false,
141
+ reason: 'http',
142
+ message: `GitHub answered ${response.status} for page ${page}.`,
143
+ }
144
+ }
145
+
146
+ return { ok: true, releases: (await response.json()) as Release[] }
147
+ } catch {
148
+ return {
149
+ ok: false,
150
+ reason: 'network',
151
+ message: 'The releases feed could not be reached.',
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ /** The tracked files naming an identifier, as a hint for where to look. */
158
+ export async function grepHint(
159
+ root: string,
160
+ identifier: string,
161
+ ): Promise<string[]> {
162
+ const result =
163
+ await $`git -C ${root} grep -l -F -e ${identifier} -- . ':!wiki'`
164
+ .env(gitEnv())
165
+ .quiet()
166
+ .nothrow()
167
+
168
+ return result.stdout.toString().split('\n').filter(Boolean)
169
+ }
@@ -20,7 +20,6 @@ Reference docs for consistent authoring across the toolkit and target projects.
20
20
  - [Groundwork spikes reference](groundwork-spikes.md): What each spike in a track's 08-spikes.md records, the sample rule, and the three folders that hold what a spike produced
21
21
  - [Groundwork reference](groundwork.md): Folder layout, ordinal naming, reserved numbering, frontmatter and dating, required file contents, and conventions for a measurement track
22
22
  - [Intake reference](intake.md): Folder layout, ordinal naming, reserved index number, frontmatter and dating, the item template, the answer contract, and retrieval
23
- - [Markdown reference](markdown.md): Headings, paragraph and list structure, code spans, the date form, punctuation, emphasis, file references, American spelling, and frontmatter wording
24
23
  - [Memory reference](memory.md): Filename and type prefix, frontmatter, the body shape per type, links between entries, and the lifecycle from write to retire
25
24
  - [Mermaid reference](mermaid.md): Direction and layout, node and edge budgets, accessibility fields, label punctuation, and render verification for a Mermaid diagram
26
25
  - [Plan lifecycle reference](plan-lifecycle.md): When a feature plan is written, where it lives, how it changes mid-flight, and its move to the archive
package/standards/plan.md CHANGED
@@ -7,6 +7,7 @@ rule:
7
7
  - 'Never fill an `- Answer:` slot on behalf of the person who owns it. A blank slot accepts the suggestion at execution time.'
8
8
  - 'Never ship a question without a `- Suggested:` line. Write `- Suggested: needs your call, <why>` where the answer turns on preference.'
9
9
  - "Rewrite the `- Suggested:` line as `overridden at execution to <pick>,` plus the measurement when execution deviates from an unanswered question, leaving the slot blank. Put the same deviation in one line under the open task's `## Findings`."
10
+ - 'Fetch the source a decision rests on and quote the passage under `**Sources:**`, or mark the entry `unverified`. Never cite an outside source from recall.'
10
11
  - 'Move a shipped plan to `.canon/plans/archive/`. Never delete one.'
11
12
  - 'Amend a plan in place when a decision changes. Do not append a second passage narrating the change.'
12
13
  - 'Follow the plan lifecycle standard for when a plan is written, how it is amended, and its move to the archive. Read it with `canon standards plan-lifecycle`.'
@@ -51,7 +52,7 @@ A plan failing these is non-conforming even when it satisfies every shape rule b
51
52
 
52
53
  - Name the file `feature-<slug>.md`, with `<slug>` two to four kebab-case words naming the concern.
53
54
  - Write one concern per file. A request spanning two independent concerns takes two plans rather than one bundling both, since a bundled plan cannot be executed by two sessions or abandoned by half.
54
- - A staged batch is a concern of its own and takes its own file rather than a `**Batch N**` sub-heading inside one plan's `**Files to touch:**`. One plan filename derives one branch, so batches sharing a file have nothing to open a pull request against once the first merges. State a batch's dependency on the ones before it in its own `**Constraints:**`.
55
+ - A staged batch is a concern of its own and takes its own file rather than a `**Batch N**` sub-heading inside one plan's `**Files to touch:**`. One plan filename derives one branch, so batches sharing a file have nothing to open a pull request against once the first merges. State a batch's dependency on the ones before it in its own `**Constraints:**`. A batch that stacks on another and shares most of its files with it folds into that batch as contiguous commits on one branch rather than taking a file, unless its constraints carry ``Judged apart from `feature-<parent>`: <reason>`` with a reason after the colon. `canon records validate plans` reports `stack-foldable` for a stacked batch that has neither.
55
56
  - Derive the slug from the concern rather than from a branch, because the plan is written before the branch exists.
56
57
  - Give the branch that executes the plan the same slug. A later surface finds the plan from the branch name and finds nothing when the two spellings differ.
57
58
 
@@ -61,17 +62,18 @@ A plan carries no frontmatter. Its filename is the whole of its identity, so a f
61
62
 
62
63
  The document opens with `# Feature: <short title>` and one paragraph stating what is being built and why now. The sections below follow in this order.
63
64
 
64
- | Section | Holds | Required |
65
- | --------------------- | ------------------------------------------------------------------------- | ------------- |
66
- | `## Summary` | three to five one-line bullets: the goal, the deliverables, the trade-off | Always |
67
- | `**Constraints:**` | durable rules the work must respect | When supplied |
68
- | `**Files to touch:**` | each file with a one-line reason | Always |
69
- | `**Verification:**` | the test or command that proves each outcome | Always |
70
- | `**Risks:**` | conflicts, coupling, and the tricky spots | Always |
71
- | `**Review focus:**` | the inputs or states that would break the change, for the reviewer | Always |
72
- | `**Questions:**` | numbered open decisions, each with a suggestion and an answer slot | Always |
73
-
74
- - Write each marker as the table gives it. `Summary` opens the prose a reader scans, so it takes an H2, and the six that follow are labels over lists rather than sections of prose.
65
+ | Section | Holds | Required |
66
+ | --------------------- | ------------------------------------------------------------------------- | ------------------------------------------ |
67
+ | `## Summary` | three to five one-line bullets: the goal, the deliverables, the trade-off | Always |
68
+ | `**Constraints:**` | durable rules the work must respect | When supplied |
69
+ | `**Files to touch:**` | each file with a one-line reason | Always |
70
+ | `**Verification:**` | the test or command that proves each outcome | Always |
71
+ | `**Risks:**` | conflicts, coupling, and the tricky spots | Always |
72
+ | `**Review focus:**` | the inputs or states that would break the change, for the reviewer | Always |
73
+ | `**Questions:**` | numbered open decisions, each with a suggestion and an answer slot | Always |
74
+ | `**Sources:**` | the outside sources a decision rests on, each with its quoted passage | When a decision rests on an outside source |
75
+
76
+ - Write each marker as the table gives it. `Summary` opens the prose a reader scans, so it takes an H2, and the others are labels over lists rather than sections of prose.
75
77
  - A section written in the other spelling is still that section, since `## Risks` and `**Risks:**` name one thing. Write the table's form in a new plan and leave an existing plan's spelling alone. Either spelling breaks a depth run.
76
78
  - Write `None identified.` under a required section with nothing to report rather than dropping the marker. A dropped section and an unconsidered one read identically.
77
79
  - Aim `## Summary` at a person scanning the plan, not at the session executing it. The other sections carry what execution needs.
@@ -118,6 +120,13 @@ A constraint naming a `.canon/ready/` folder is a third shape beside the hold an
118
120
  - Write it for the reviewer rather than the builder, since this section is where the planner's understanding of the risk reaches the review pass.
119
121
  - Keep it apart from `**Risks:**`. A risk is something the work might collide with, and a focus item is something the finished diff must be shown to handle.
120
122
 
123
+ ### Sources
124
+
125
+ - Give each entry a link, the decision it backs, and the passage relied on in double quotes.
126
+ - Mark a source that could not be fetched `unverified` and never quote it. A quote for a page nobody opened is the failure this section exists to prevent.
127
+ - Cite no source that was found and not opened, following the lead rule in `groundwork.md`.
128
+ - Leave the section out when no decision rests on an outside practice or behavior. `canon records validate plans` checks that an entry is well formed, not that every outside claim got one.
129
+
121
130
  ## The suggested-and-answer contract
122
131
 
123
132
  Every question carries a `- Suggested:` line and an empty `- Answer:` slot below it.
@@ -191,4 +200,8 @@ This contract inverts the one an intake folder keeps, where an empty slot means
191
200
  1. <question>
192
201
  - Suggested: <pick>, <reason or tradeoff>
193
202
  - Answer:
203
+
204
+ **Sources:**
205
+
206
+ - [<title>](url), backing <decision>: "<passage relied on>"
194
207
  ```
package/standards/rule.md CHANGED
@@ -57,7 +57,7 @@ The cost is that a project-authored rule's leading digit stops naming its domain
57
57
 
58
58
  The reservation above divides one pair, being a shipped set against the rules a project wrote for itself. A third source, a rule set held back from targets and installed only where it was authored, needs its own division too. This repository is the one place all three sources exist at once, and it divides the third pair two ways at once rather than one: `canon/` and `internal/` separate a shipped rule from an internal one by location, the same way `project/` separates a project-authored one, and within each subdirectory the numbering still divides by source as well, one source taking the top of the band and the other the gaps between the tens.
59
59
 
60
- The numbering half stays because location alone does not carry to a reader who only sees the number, such as one comparing `claude/567-planning.md` against a citation written before the rules moved into `canon/`.
60
+ The numbering half stays because location alone does not carry to a reader who only sees the number, such as one comparing `claude/566-output.md` against a citation written before the rules moved into `canon/`.
61
61
 
62
62
  The collision this prevents is silent. Two rules that resolve to the same `<n>-<slug>` path leave one file in the installed folder, and neither the install nor the session that reads it reports which source lost. Nothing checks a division outside the reserved bands, so it holds only while both sources follow it. Separating `canon/` from `internal/` by folder removes the filename-collision case specifically, since the two no longer install to the same directory, but the number still carries the source signal for a reader who has only the number in view.
63
63
 
@@ -53,5 +53,5 @@ marker="$marker_dir/$key"
53
53
  mkdir -p "$marker_dir"
54
54
  : >"$marker"
55
55
 
56
- msg=$(printf 'An index.md exists at %s. Read it before searching this folder, it catalogs the sibling files faster than a blind search. For a cross-folder answer, run canon indexes list --json or invoke the index-lookup skill.' "$index")
56
+ msg=$(printf 'An index.md exists at %s. Read it before searching this folder, it catalogs the sibling files faster than a blind search. For a cross-folder answer, run canon indexes list --json.' "$index")
57
57
  jq -nc --arg msg "$msg" '{hookSpecificOutput:{hookEventName:"PreToolUse",additionalContext:$msg}}'
@@ -1,35 +0,0 @@
1
- ---
2
- name: index-lookup
3
- description: Why a topic search over the tracked index catalog needs its own skill, and why a folder outside `list`'s walk gets a named pointer instead of a search hit
4
- ---
5
-
6
- # Index lookup requirement
7
-
8
- ## Gap
9
-
10
- Without this skill, `canon indexes list --json` exists as a verb with nobody wrapping it into a topic-search request. A session either greps the tree by hand, which misses everything the catalog already states in `title` and `description` rather than in file contents, or answers from whichever folder it happened to open, which reports a topic as undocumented when the topic only sits outside the walked corpus: a gitignored indexed folder such as `.canon/tasks/` or `.canon/memory/`, or a README-based record catalog such as `.canon/groundwork/`, neither of which `list` ever reaches.
11
-
12
- ## Must
13
-
14
- - Run `canon indexes list --json` and match the topic against every entry's `title`, `description`, and `path`
15
- - Check whether the project carries a gitignored indexed folder or a README-based record catalog outside `list`'s walk before naming any of them, since a folder absent from the project names nothing
16
- - Report zero hits inside the walked corpus as zero hits, never as "not documented," since a folder outside the walk can still hold the answer
17
-
18
- ## Must not
19
-
20
- - Search file contents. A miss against `title`, `description`, and `path` is the whole answer, and grepping the tree is a different request.
21
- - Extend `canon indexes list` to read a `README.md` catalog or to bypass the gitignore filter. Both are accepted trade-offs the verb already carries, and widening either is a CLI change, not a skill-body change.
22
- - Regenerate an index on its own initiative. Reporting a stale-looking entry is this skill's job, and writing the fix belongs to `canon indexes regen`.
23
- - Fire from a request to browse a file whose path is already known, or to search source code, both of which this skill answers nothing for
24
- - Assume this skill's own invocation frequency needs no check. The reminder hook names it beside `canon indexes list --json`, and a session recognizing a topic-lookup request can trigger it by description, but whether anything reaches for it beyond an operator typing its name has no answer at creation time, so a review pass some months in should read that back rather than take it on faith.
25
-
26
- ## Guards
27
-
28
- - `canon indexes list` does not resolve on an older install. Report that rather than falling back to a manual walk, since a hand-rolled walk here restates the CLI logic this skill exists to call.
29
- - A folder failing frontmatter validation drops out of `entries` and its message lands in `errors`, per the verb's own per-folder isolation. Report the error alongside the match rather than treating it as a reason to stop.
30
-
31
- ## Out of scope
32
-
33
- - Regenerating or scaffolding an index, which `canon indexes regen` and the `target-setup` skill's `indexes` phase own
34
- - Reading a folder's contents once a hit names it, which is an ordinary file read rather than part of the lookup
35
- - Chaining this skill into the `target-setup` skill's `indexes` phase as a verification step. Left independent: that phase already validates through `canon indexes regen --dry-run`, and a second skill call inside a bootstrap flow duplicates a check that already runs.
@@ -1,44 +0,0 @@
1
- ---
2
- name: index-lookup
3
- description: Answers a topic search over every tracked index.md catalog in the project by running `canon indexes list --json` and matching the topic against each entry's title, description, and path, then reports the hits or names why there are none. Names the gitignored task and memory catalogs and the groundwork and intake record folders as pointers outside its walked corpus, so it never claims a topic is undocumented when the topic only sits there. Use when asked "where is X documented", "is there a page about X", "search the docs for X", "find the index entry for X", or "what covers X". Do NOT use to grep source code, browse a file whose path is already known, or regenerate an index, which is `canon indexes regen`.
4
- metadata:
5
- family: answer
6
- ---
7
-
8
- # Index lookup
9
-
10
- Answers a topic search over the project's tracked `index.md` catalogs, not a text search over file contents. Matches a topic string against every entry's `title`, `description`, and `path`, drawn from wherever `canon indexes list --json` walks.
11
-
12
- ## Steps
13
-
14
- 1. Resolve the project root with `git rev-parse --show-toplevel`, falling back to the working directory when the read fails.
15
- 2. Run `canon indexes list --json` from that root.
16
- 3. Read `errors` first. A folder failing frontmatter validation drops out of `entries` and lands its message in `errors` instead, per the verb's own per-folder isolation, so report an error alongside the match rather than reading it as a reason to stop.
17
- 4. Match the topic case-insensitively as a substring against each entry's `title`, `description`, and `path`. Report every match. A lookup with no ranking is honest about what it found, and a single best guess is not.
18
- 5. Check whether the project carries a gitignored indexed folder or a README-based record catalog outside `list`'s walk: `.canon/tasks/`, `.canon/memory/`, `.canon/groundwork/`, `.canon/intake/`. Test each for existence and at least one file inside it before naming it. A folder absent from this project names nothing.
19
- 6. Report the hits, plus a pointer to any outside-the-walk folder found present, per Output below.
20
-
21
- ## Rules
22
-
23
- - Report zero hits as zero hits, never as "not documented." The topic can sit inside a folder step 5 found and named, so an empty walked corpus is a fact about the search, not about the project.
24
- - Never search file contents. A miss against `title`, `description`, and `path` is the whole answer, and a request that needs a text search calls for grepping the tree instead.
25
- - Never regenerate or edit an index. Report an entry that reads as stale rather than running `canon indexes regen` on this skill's own initiative.
26
- - Report an absent `canon indexes list` subcommand rather than falling back to a manual walk. It ships with the CLI, so a project on an older install meets a missing verb, and a hand-rolled walk here restates the CLI logic this skill exists to call instead.
27
-
28
- ## Output
29
-
30
- ```plaintext
31
- Index lookup: "<topic>"
32
-
33
- Hits:
34
- - <path>: <title> — <description>
35
-
36
- Outside the walked corpus (check by hand):
37
- - <folder>: <one-line reason it sits outside list's walk>
38
- ```
39
-
40
- Replace the "Hits" block with `No catalog entry matched "<topic>".` when nothing matched. Omit "Outside the walked corpus" when the project carries none of the five folders from step 5, or when every one it carries is empty.
41
-
42
- ## Reference
43
-
44
- Run `canon docs indexes` for the `canon indexes list` flags, exit codes, and JSON shape. It resolves from the toolkit rather than from the target's own tree.
@@ -1,9 +0,0 @@
1
- ---
2
- description: Check a folder's index before searching its contents
3
- ---
4
-
5
- # Indexes standards
6
-
7
- ## Before searching
8
-
9
- - Check a folder's `index.md` before grepping its source or reading its files, starting with `canon/context/` for a domain and `canon/wireframes/` for a UI surface. It orients faster than a blind search.
@@ -1,27 +0,0 @@
1
- ---
2
- description: Handle judgment calls, scope discipline, and file-editing mechanics during a session
3
- ---
4
-
5
- # Behavior standards
6
-
7
- ## Communication
8
-
9
- - Flag concerns or alternatives when a proposed change has tradeoffs worth discussing
10
-
11
- ## Judgment calls
12
-
13
- - When facing a judgment call with 2-3 reasonable options mid-flow, pick one and state the tradeoff in one sentence. Enumerate options only when the user's preference is the deciding factor.
14
- - Put a call the user's preference decides through the structured question surface, such as `AskUserQuestion` in Claude Code, and fall back to a numbered list in one message where none exists. Rank the recommendation first and mark it, order the rest behind it, and give each option its cost, since an option with no stated cost is picked blind.
15
- - Author the real choices only. A structured surface appends its own trailing escapes for a free-text answer and for reopening the question as conversation, so never write either as an option. On the numbered-list fallback, say that answering outside the list is fine.
16
- - Answer from the artifact when one already put the question in writing with a suggestion, rather than re-asking it.
17
-
18
- ## Scope discipline
19
-
20
- - Match edit scope to the request. Ship minimal v1 and queue extensions as follow-ups.
21
- - On simplification requests, edit only what the user named
22
- - Do not add features the user did not ask for
23
- - When rewriting a section, preserve existing code blocks, tables, and grouped examples unless the user asked to remove them
24
-
25
- ## Editing mechanics
26
-
27
- - Edit an existing file with the file-editing tool, never a shell stream editor. An unescaped `&` in a `sed` replacement expands to the whole match, and `sed -i` exits zero when its pattern matches nothing, so both fail silently while reporting success. This governs edits you make, not stream editors written into a project's own scripts.
@@ -1,16 +0,0 @@
1
- ---
2
- description: Enforce planning standards before implementation
3
- ---
4
-
5
- # Planning standards
6
-
7
- ## Planning
8
-
9
- - Confirm a numbered implementation plan before a change whose diff cannot be described in one sentence.
10
- - Challenge ambiguous or over-engineered requests before implementation.
11
- - Search the project, its dependencies, and the standard library for an existing implementation before writing new code.
12
- - State where the search ran and why each candidate was rejected. Do not assert a search without naming its results.
13
- - Propose the simplest solution that satisfies the requirement before implementing complex patterns.
14
- - Write or update tests as part of every implementation plan.
15
- - Write the test for a behavior before the code that implements it. Confirm visual output after implementing it, not before.
16
- - Run `canon gov test-order` before shipping a branch. Fix what it names as reaching history ahead of its test.
@@ -1,16 +0,0 @@
1
- ---
2
- description: State the hook stdin guard and the silencing rule for .claude/hooks scripts
3
- paths:
4
- - '.claude/hooks/**/*.sh'
5
- ---
6
-
7
- # Hook standards
8
-
9
- ## Reading a payload
10
-
11
- - Open a hook that reads a payload with a bounded `IFS= read -r -d '' -t 2 input`, exiting non-zero on an empty payload. An unbounded `cat` blocks forever against a hand run or an open socket, holding the session open with it.
12
-
13
- ## Silencing output
14
-
15
- - Before silencing a hook's output, name the stage that catches the same failure. A hook that is the only enforcer of a rule makes its documented guarantee false when it discards that output.
16
- - Where no other stage catches the failure, capture the output into a variable, exit 0 on success, and emit the error lines as `additionalContext`.
@@ -1,13 +0,0 @@
1
- ---
2
- description: State the autoContinueAtUsageLimit inversion and the autoCompactWindow cap for .claude/settings.json
3
- paths:
4
- - '.claude/settings.json'
5
- ---
6
-
7
- # Settings standards
8
-
9
- ## Session budget settings
10
-
11
- - Never set `autoContinueAtUsageLimit` in this file. Its scope is user or managed, and a repository file setting it while no user, `--settings`, or managed value does makes Claude Code read the setting as off, so writing `true` here turns the behavior off for every operator carrying no value of their own.
12
- - Treat `autoCompactWindow` as capped at the model's own context window. A value above that cap is inert on a session running a smaller window and bites only on one running the larger, so name the window a recorded value is meant for.
13
- - Record why a session budget setting is left unset in the project's own development notes rather than in this file. JSON carries no pointer, so a session reading the settings file alone concludes the setting is unconfigured and sets it again.
@@ -1,19 +0,0 @@
1
- ---
2
- description: Enforce the CLAUDE.md edit protocol and the test routing a fact into it rather than a rule
3
- paths:
4
- - 'CLAUDE.md'
5
- ---
6
-
7
- # CLAUDE.md standards
8
-
9
- ## Editing
10
-
11
- - Show the proposed change as a fenced `diff` block in chat first, then wait for approval before calling the file-editing tool.
12
-
13
- ## Routing
14
-
15
- - Keep a rule here when it applies every session regardless of what is being edited, on firing alone.
16
- - Move a rule into `.claude/rules/` when it fires only on a specific path being edited and violating it ships silently, the same firing axis judged the other way.
17
- - Route a rule failing either half to a context entry or a skill body rather than here. Firing is one axis of three. Conditional presence and updatability are the other two, and this rule states the first alone.
18
- - Name a rule's tier rather than a rule file. A path-scoped rule reaches the session on its own glob and needs no pointer from here.
19
- - Point at a skill by name where one applies. A skill loads only when invoked, so an unreferenced skill is one no session finds.
@@ -1,16 +0,0 @@
1
- ---
2
- # Generated by `canon gov regen` from standards/markdown.md. Edit that frontmatter, not this file.
3
- description: Headings, paragraph and list structure, code spans, the date form, punctuation, emphasis, file references, American spelling, and frontmatter wording
4
- paths:
5
- - '**/*.md'
6
- ---
7
-
8
- # Markdown standards
9
-
10
- ## Authority
11
-
12
- - Follow the markdown standard for headings, paragraph and list structure, code spans, the date form, punctuation, emphasis, file references, American spelling, and frontmatter wording. It is the single source. Read it with `canon standards markdown`.
13
- - Read it before a substantial markdown edit. Do not work the banned characters from memory.
14
- - Run `canon markdown audit <path>` after the edit, and rewrite the sentence carrying a hit rather than swapping the token for a near-synonym.
15
- - Voice, rhythm, and sentence construction are a separate topic. `800-prose` routes them.
16
- - Load the `canon:draft-figure` skill before drafting or revising a Mermaid fence or a figure, and report it rather than proceeding silently when it does not resolve.
@@ -1,15 +0,0 @@
1
- ---
2
- description: Route markdown edits to the write-human skill for voice, rhythm, sentence construction, and information density
3
- paths:
4
- - '**/*.md'
5
- ---
6
-
7
- # Markdown voice standards
8
-
9
- ## Authority
10
-
11
- - Load the `canon:write-human` skill for voice, rhythm, sentence construction, and information density. It is the single source for all four.
12
- - Load it before drafting a passage, not after revising one.
13
- - Report it rather than proceeding silently when the skill does not resolve.
14
- - Do not work these rules from memory.
15
- - Punctuation, formatting, and file references are a separate topic. The markdown rule routes them.