@erclx/canon 4.118.0 → 4.120.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canon-rollout/SKILL.md +2 -2
- package/claude/skills/create-skill/SKILL.md +2 -1
- package/claude/skills/design-extract/SKILL.md +1 -1
- package/claude/skills/docs-fold/SKILL.md +2 -2
- package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +1 -1
- package/claude/skills/draft-screencast/SKILL.md +1 -1
- package/claude/skills/git-pr/REQUIREMENT.md +1 -0
- package/claude/skills/git-pr/SKILL.md +39 -7
- package/claude/skills/memory-capture/SKILL.md +3 -3
- package/claude/skills/memory-review/SKILL.md +3 -3
- package/claude/skills/plan-feature/SKILL.md +1 -1
- package/claude/skills/review-branch/SKILL.md +1 -1
- package/claude/skills/review-pr/SKILL.md +13 -242
- package/claude/skills/review-pr/references/close-out.md +30 -0
- package/claude/skills/review-pr/references/post.md +145 -0
- package/claude/skills/review-pr/references/scope.md +82 -0
- package/claude/skills/role-orchestrator/REQUIREMENT.md +9 -16
- package/claude/skills/role-orchestrator/SKILL.md +9 -153
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +4 -193
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +22 -0
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +85 -0
- package/claude/skills/role-orchestrator/references/orchestrator-output.md +61 -0
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +56 -0
- package/claude/skills/role-orchestrator/references/orchestrator-review-fallback.md +18 -0
- package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +1 -1
- package/claude/skills/role-planner/REQUIREMENT.md +1 -1
- package/claude/skills/role-planner/SKILL.md +1 -1
- package/claude/skills/role-worker/REQUIREMENT.md +1 -1
- package/claude/skills/role-worker/SKILL.md +10 -41
- package/claude/skills/seed-sync/SKILL.md +1 -1
- package/claude/skills/session-compact/SKILL.md +1 -1
- package/claude/skills/session-map/SKILL.md +1 -1
- package/claude/skills/session-relay/REQUIREMENT.md +7 -1
- package/claude/skills/session-relay/SKILL.md +4 -7
- package/claude/skills/session-worktree/REQUIREMENT.md +5 -1
- package/claude/skills/session-worktree/SKILL.md +7 -1
- package/claude/skills/session-worktree/references/main-root-writes.md +24 -0
- package/claude/skills/task-board/SKILL.md +4 -3
- package/claude/skills/teach-workspace/SKILL.md +4 -4
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/ux-audit/SKILL.md +1 -1
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/claude/skills/ux-walkthrough/references/relay.md +1 -1
- package/docs/agents/commands.md +4 -3
- package/docs/agents/counts.md +1 -1
- package/docs/agents/index.md +8 -3
- package/docs/agents/install-and-sync.md +11 -6
- package/docs/agents/pr-evidence.md +19 -3
- package/docs/agents/pr-local.md +102 -0
- package/docs/agents/pr-preview.md +2 -2
- package/docs/agents/records-push.md +61 -0
- package/docs/agents/records-validate.md +73 -0
- package/docs/agents/records.md +3 -119
- package/docs/agents/sessions-transfer.md +91 -0
- package/docs/agents/sessions.md +3 -82
- package/docs/agents/skills-audit.md +2 -2
- package/docs/agents/tasks.md +4 -4
- package/docs/agents/teach-authoring.md +112 -0
- package/docs/agents/teach.md +3 -103
- package/docs/target-projects.md +2 -2
- package/docs/workflow/ai-workflow.md +10 -10
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/governance/renames.toml +13 -0
- package/governance/rules/claude/570-skill.md +2 -1
- package/governance/rules/core/085-worktrees.md +2 -8
- package/package.json +1 -1
- package/scripts/core/check-ignore-parity.sh +1 -1
- package/scripts/lib/sandbox-git.sh +1 -1
- package/src/claude/cases/workflow.ts +10 -0
- package/src/commands/pr.ts +324 -2
- package/src/commands/sync.ts +11 -3
- package/src/commands/tasks.ts +9 -8
- package/src/context/classify/extract.ts +2 -2
- package/src/counts/scan.ts +1 -1
- package/src/design/base.css +19 -19
- package/src/design/board.ts +18 -7
- package/src/design/neutral.ts +127 -0
- package/src/design/regen.ts +6 -4
- package/src/design/tokens.ts +6 -3
- package/src/gate/stages.ts +6 -6
- package/src/gov/adapter.ts +51 -1
- package/src/gov/install.ts +13 -3
- package/src/gov/renames.ts +76 -0
- package/src/gov/stacks.ts +5 -1
- package/src/pr/evidence.ts +42 -2
- package/src/pr/local.ts +125 -0
- package/src/sync/check.ts +19 -4
- package/src/sync/engine.ts +67 -3
- package/src/tasks/archive.ts +28 -7
- package/src/tasks/record.ts +16 -9
- package/src/tasks/validate.ts +3 -1
- package/standards/index.md +1 -0
- package/standards/skill-requirement.md +72 -0
- package/standards/skill.md +34 -152
- package/standards/tasks.md +5 -3
- package/tooling/astro/reference.md +1 -1
- package/tooling/base/configs/.github/workflows/pr-local-preview.yml +32 -0
- package/governance/rules/core/091-channel.md +0 -13
package/docs/agents/teach.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Teach
|
|
3
|
-
description: Listing learning workspaces with what their records schedule next, opening one with its required files, recording sources and glossary terms,
|
|
3
|
+
description: Listing learning workspaces with what their records schedule next, opening one with its required files, recording sources and glossary terms, where the lesson authoring verbs are described, the refusal reasons, and why every write here runs through a verb
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Teach
|
|
@@ -110,109 +110,9 @@ A term already defined is refused rather than replaced. A definition the subject
|
|
|
110
110
|
|
|
111
111
|
The entry lands as the standard's shape, leading with the term as a bolded span. A definition not ending in sentence punctuation is terminated before the citation is appended, so a bare phrase does not run into the sentence naming where the term first appears.
|
|
112
112
|
|
|
113
|
-
## Lesson
|
|
113
|
+
## Lesson, render, and nav
|
|
114
114
|
|
|
115
|
-
`canon teach lesson`
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
canon teach lesson regular-expressions \
|
|
119
|
-
--slug capture-groups \
|
|
120
|
-
--questions 3 \
|
|
121
|
-
--options 4
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
| Option | Behavior |
|
|
125
|
-
| ----------------- | --------------------------------------------------------- |
|
|
126
|
-
| `--slug <kebab>` | The lesson's own topic, required |
|
|
127
|
-
| `--questions <n>` | How many questions the quiz carries, required |
|
|
128
|
-
| `--options <n>` | How many options each question carries, defaulting to `4` |
|
|
129
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
130
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
131
|
-
|
|
132
|
-
It reports three things. `lesson` is the numbered path the lesson takes, derived from the highest ordinal already in `lessons/` the way an open derives a workspace ordinal. `success` carries the mission's success lines, so a session reports progress against the exit criteria without a second read of `MISSION.md`. `quiz` carries one entry per question.
|
|
133
|
-
|
|
134
|
-
A lesson written against this record carries its chrome as four empty marker pairs rather than hand-composed markup: `canon:teach:style`, `canon:teach:header`, `canon:teach:footnav`, and `canon:teach:scripts`. `canon teach nav`, below, fills them from what the workspace holds on disk.
|
|
135
|
-
|
|
136
|
-
`canon teach stylesheet <topic>` writes the pair every lesson in the workspace renders through, seeded from the design source so a workspace renders in the system every other surface does. The two halves are written on different terms. `assets/base.css` holds the generated design layer and is rewritten on every run, which is the only way a change to the shared chrome reaches a workspace that already exists. `assets/course.css` is the half a workspace owns, so it refuses to overwrite, reporting `written` as false where the workspace already carries one, and `--force` takes the seed back over it. Each workspace used to carry a hand-authored palette, which is how the course styling forked once per workspace, so a lesson adds its own rules under the seed and reaches a value through its custom property rather than restating the hex.
|
|
137
|
-
|
|
138
|
-
Each `quiz` entry carries `order`, the authored option indices in presentation order where index `0` is the correct answer, and `answer`, the one-based position that answer lands in. Both travel together because a caller deriving the position itself is a caller that can derive it wrongly.
|
|
139
|
-
|
|
140
|
-
The order is drawn here rather than instructed, and that is the point of the verb. An author told to vary the position still varies it by judgment, and the judgment settles on the first slot, which is the defect this design departs from. The draw is uniform over the options, so the position carries no information about which answer is correct.
|
|
141
|
-
|
|
142
|
-
## Render
|
|
143
|
-
|
|
144
|
-
`canon teach render` renders a lesson body's structural blocks to HTML, through the four lesson components. It takes no topic and no `--root`, since the verb is a stateless transform reading nothing off a workspace on disk.
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
echo '[{"type":"heading","level":1,"text":"Compass bearings"}]' | canon teach render --json
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
| Option | Behavior |
|
|
151
|
-
| -------- | ---------------------------------------- |
|
|
152
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
153
|
-
|
|
154
|
-
It reads a JSON array of blocks from stdin, each a `heading`, `paragraph`, `list`, `refs`, or `raw` block, and reports `{ ok: true, html }` on `--json` or the bare rendered HTML on stdout otherwise. Content none of the components can express takes a `raw` block, carrying its own HTML verbatim and unescaped, which is the shape the quiz and the teach-back block travel in.
|
|
155
|
-
|
|
156
|
-
A citation takes two shapes. A `paragraph` carries an optional `cites` array of reference numbers, rendered as `sup.cite` markers after its text. The one `refs` block carries `items` of `{ title, url?, note? }`, rendered as `ol.refs` and numbered from 1, so cite `1` links to the first item.
|
|
157
|
-
|
|
158
|
-
```json
|
|
159
|
-
[
|
|
160
|
-
{ "type": "paragraph", "text": "North is fixed.", "cites": [1] },
|
|
161
|
-
{
|
|
162
|
-
"type": "refs",
|
|
163
|
-
"items": [{ "title": "Compass manual", "url": "https://example.com" }]
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
It refuses `bad-input` on empty stdin, on malformed JSON, on stdin that does not parse to an array, and on a block carrying an unrecognized `type` or a field of the wrong shape for its type, naming the block's index in the message. Citations add four refusals, each naming the offending block: a cite that resolves to no reference, `cites` on a lede paragraph, a second `refs` block, and a reference `url` that is not `http` or `https`.
|
|
169
|
-
|
|
170
|
-
## Nav
|
|
171
|
-
|
|
172
|
-
`canon teach nav` rewrites the teach-root listing, a workspace's contents page, and each of its lessons' chrome, from what the workspace holds on disk.
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
canon teach nav
|
|
176
|
-
canon teach nav regular-expressions --json
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
| Option | Behavior |
|
|
180
|
-
| --------------- | ------------------------------------------------- |
|
|
181
|
-
| `[topic]` | Workspace folder or topic, scoping the run to one |
|
|
182
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
183
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
184
|
-
|
|
185
|
-
With no topic it rewrites every workspace. The teach-root listing is always rewritten regardless, since it reports on every workspace and a scoped run leaving it stale would be a second kind of drift this verb exists to end.
|
|
186
|
-
|
|
187
|
-
A lesson carries its chrome as four marker pairs the authoring skill writes empty: `canon:teach:style`, `canon:teach:header`, `canon:teach:footnav`, and `canon:teach:scripts`. This verb splices each one from the current workspace state, embedding the toolkit's favicon, the shared stylesheet, and the script that settles the course panel before the page paints, rebuilding the course sidebar, the breadcrumb and jump menus, the prev/next footer nav, and the behavior scripts. It leaves the authored `<h1>`, lede, body, and quiz between the header and the footnav as written, with two exceptions. It wraps them in `<main>` when the lesson holds none, since the column width hangs off that element, and a lesson that already carries a `<main>` keeps its own.
|
|
188
|
-
|
|
189
|
-
It also links each "lesson NNNN" mention in that region to the lesson file in the same workspace carrying that number, skipping text inside `a`, `code`, `pre`, `script`, `style`, `label`, `summary`, and comments. A link the verb writes carries `data-lesson-ref`, and it is the only kind the verb rewrites: every run points one at the current filename for its number, or unwraps it to plain text once that number names no lesson. A link an author wrote is never touched.
|
|
190
|
-
|
|
191
|
-
Every workspace label in that chrome, being the breadcrumb, the sidebar heading, the workspace switcher, and the root listing's row, reads the mission's `title` and falls back to the folder topic in sentence case where the mission names none.
|
|
192
|
-
|
|
193
|
-
It also deletes two links a session used to write by hand into a lesson's `<head>`, each matched as its exact string: the old icon link and `<link rel="stylesheet" href="../assets/course.css" />`. The page keeps only the icon and the stylesheets the `style` region carries. Any other link an author wrote stays.
|
|
194
|
-
|
|
195
|
-
A workspace carrying no `course.css` gets its stylesheet pair seeded first, so the contents page it links is never unstyled, and an existing `course.css` is never overwritten. The `style` region links `assets/base.css` ahead of an embedded copy of `course.css`, so the workspace's own rules still win the cascade. The embedded copy drops the seed's `@import` line, which resolved against the lesson's own folder and never loaded anything, and the link is what reaches the base sheet in its place. A workspace with no `assets/base.css`, one holding a hand-authored `course.css` from before the seed, gets no link rather than one pointing at a missing file.
|
|
196
|
-
|
|
197
|
-
That seeding fires on the absent file alone, so a workspace already holding a `course.css` has neither half rewritten here. A change to the shared chrome therefore takes `canon teach stylesheet <topic>` per workspace, which rewrites `assets/base.css`, and every lesson picks it up through its link with no run of this verb. Running this one alone leaves every lesson on the `base.css` the workspace already holds, and nothing reports it. Only an edit to a workspace's own `course.css` needs this verb, since that half is embedded.
|
|
198
|
-
|
|
199
|
-
A lesson missing one of the four marker pairs is refused by name rather than rewritten, and every other lesson in the run still rewrites. The record's `skipped` list carries the refused files and which marker each is missing.
|
|
200
|
-
|
|
201
|
-
A mention whose number names no lesson in its workspace stays plain text and lands in the record's `unresolved` list, one `{ file, lesson }` entry per distinct number per lesson, with `file` relative to the root the way a `skipped` entry is. The lesson still rewrites and counts toward `lessons`, and the exit stays 0. A mention of the lesson's own number stays plain and is not reported, and a refused lesson reports nothing.
|
|
202
|
-
|
|
203
|
-
The `style` region carries the quiz stepper after the workspace stylesheet, for every lesson but the one shape named three paragraphs down, so it wins the cascade at equal specificity and reaches a workspace seeded before it existed. The stepper is CSS over the radio inputs a quiz is written from: it hides every question that follows one holding no checked input, and hides a question's feedback until that question does. The general sibling combinator is what keeps that from depending on the markup contract holding, since it selects the same questions as the adjacent one for a quiz written correctly and goes on gating when anything sits between two of them, where the adjacent one matches nothing and shows them all at once. Gating there rather than in a script is what keeps a later stem from answering an earlier question with nothing to bind, and the whole block sits inside `@supports selector(:has(*))`, so an engine without `:has()` renders every question rather than a stepper showing nothing. Feedback there follows the workspace stylesheet, shown by one that says nothing about `.fb` and hidden by one grown under the retired script.
|
|
204
|
-
|
|
205
|
-
The block hides and shows and sets nothing else, which leaves a workspace's own layout for a question and its own appearance for an option and a feedback panel. The one value it names is `display: block` on revealed feedback, since every stylesheet grown under the retired script carries `.fb { display: none }` and nothing adds the class that used to reveal it.
|
|
206
|
-
|
|
207
|
-
One detector decides both regions. A lesson carrying `<button class="opt"`, the shape written before the stepper, takes the feedback script and no stepper, and every other lesson takes the stepper and no script. That is a detector rather than a mode, since a lesson has one shape or the other, and removing the script outright would leave the lessons already written showing no feedback at all.
|
|
208
|
-
|
|
209
|
-
Splicing the stepper into a lesson of either shape was measured against a browser and reverted. Its rules match a button question, which can never hold a checked radio, so a lesson given both hides every question past the first for good and outranks the class the script reveals feedback with. Nothing else caught that: the markup is valid, the splice succeeds, and the page renders.
|
|
210
|
-
|
|
211
|
-
### Reference pages
|
|
212
|
-
|
|
213
|
-
Each reference page is rendered to a `reference/<slug>.html` sibling carrying the same chrome, and the contents page links that sibling rather than the markdown, which `canon serve` hands over as plain text. The render drops the frontmatter, turns tables into `<table>` markup, and escapes raw HTML written in the markdown rather than passing it through. A body with no H1 gets one from the frontmatter `title`. A relative link to another reference page's markdown points at that page's `.html` sibling, and one to the workspace `GLOSSARY.md` points at the glossary on the contents page, `../index.html#gloss`. Every other link, such as `../RESOURCES.md`, stays as written. The markdown file is never touched.
|
|
214
|
-
|
|
215
|
-
Every rendered page carries a `<meta name="generator" content="canon teach nav">` tag. A `.html` file under `reference/` whose markdown is gone is deleted when it carries that tag, and a hand-written HTML file there, carrying none, is left alone. The record's `reference` field counts the pages rendered. On a Bun with no `Bun.markdown`, each reference page lands in `skipped` with `Bun.markdown` as what is missing, and the rest of the run goes on.
|
|
115
|
+
`canon teach lesson`, `canon teach render`, and `canon teach nav` build and splice a lesson rather than editing a workspace's records. They are in `teach-authoring.md`.
|
|
216
116
|
|
|
217
117
|
## Opening a workspace
|
|
218
118
|
|
package/docs/target-projects.md
CHANGED
|
@@ -225,7 +225,7 @@ The report opens by naming the binary running it. The installed version reads ag
|
|
|
225
225
|
|
|
226
226
|
#### Then the causes
|
|
227
227
|
|
|
228
|
-
A `stale` file still matches what the toolkit installed, so the update is mechanical. A `customized` file carries local edits, so taking the upstream version is a decision and `canon:seed-sync` is the tool for it. A `stranded` file sits where an older toolkit installed it and the toolkit has since moved, which is a relocation the report names but no command runs. A `retired` rule is one under `.claude/rules/canon/` the toolkit no longer ships, and the next `canon gov sync` deletes it.
|
|
228
|
+
A `stale` file still matches what the toolkit installed, so the update is mechanical. A `customized` file carries local edits, so taking the upstream version is a decision and `canon:seed-sync` is the tool for it. A `stranded` file sits where an older toolkit installed it and the toolkit has since moved, which is a relocation the report names but no command runs. A `retired` rule is one under `.claude/rules/canon/` the toolkit no longer ships, and the next `canon gov sync` deletes it. A `renamed` rule is one the toolkit now ships under a new name, and the next sync installs the new name and deletes the old file.
|
|
229
229
|
|
|
230
230
|
That attribution comes from `canon/config/config.json`, which every install and sync now writes, falling back to `.claude/canon/config.json` for a target stamped before that move. A target stamped before that path shipped is read from the retired `.claude/canon.json` instead, reported rather than migrated. Governance records a hash per installed file, plus the stack `canon gov install` was given, and tooling records the stack chain it resolved instead of any file hash, since its install runs no per-file walk to attribute.
|
|
231
231
|
|
|
@@ -350,5 +350,5 @@ Sync also refuses a target whose working tree is dirty, so commit or stash befor
|
|
|
350
350
|
|
|
351
351
|
- [agents](agents/index.md): CLI flags, exit codes, and JSON output shapes
|
|
352
352
|
- [AI workflow](workflow/ai-workflow.md): feature-development loop inside a toolkit-managed project
|
|
353
|
-
- [tooling](../canon/context/tooling.md), [governance](../canon/context/governance/index.md), [claude plugin](../canon/context/claude-plugin/index.md), [indexes](../canon/context/indexes.md), [snippets](../canon/context/snippets.md), [standards](../canon/context/standards/index.md): per-domain mechanics
|
|
353
|
+
- [tooling](../canon/context/tooling/index.md), [governance](../canon/context/governance/index.md), [claude plugin](../canon/context/claude-plugin/index.md), [indexes](../canon/context/indexes.md), [snippets](../canon/context/snippets.md), [standards](../canon/context/standards/index.md): per-domain mechanics
|
|
354
354
|
- [sandbox](../canon/context/sandbox/index.md): scenario catalog for verifying domain flows
|
|
@@ -109,7 +109,7 @@ An execution that picks other than the suggestion rewrites the `- Suggested:` li
|
|
|
109
109
|
|
|
110
110
|
`canon records push` carries these folders off the disk they live on, and `canon records pull` brings them back. Every top-level entry under `.canon/` is backed except `tmp`, `ordinal-locks`, and `.records.git`, so a folder added later enters the payload on its own rather than waiting on a name written into a list. Push names each folder it carries the first time it sees it, which is what keeps a stray folder visible instead of silently entering the payload. It refuses the whole push, naming each path, when a new or changed file is over 25 MB or carries a credential `canon secrets scan` would report. The history lives in a second git directory at `.canon/.records.git` with `.canon/` as its work tree, so every path a task file cites stays where it is.
|
|
111
111
|
|
|
112
|
-
A person points it at a private repository once and both verbs refuse until they have, and `push` refuses when that origin is also a remote of the project, since the payload is the memory pen and the groundwork trails. `.husky/post-merge` runs the push after its archive loop, on every merge rather than only on one that closed a task. See [records](../agents/records.md) for the refusal table.
|
|
112
|
+
A person points it at a private repository once and both verbs refuse until they have, and `push` refuses when that origin is also a remote of the project, since the payload is the memory pen and the groundwork trails. `.husky/post-merge` runs the push after its archive loop, on every merge rather than only on one that closed a task. See [records push](../agents/records-push.md) for the refusal table.
|
|
113
113
|
|
|
114
114
|
`canon records size` reports what each of these folders holds, heaviest first, along with `.canon/tmp`. Each row carries the file count, the bytes, how many files were written in the last 7 and 30 days, and the dates of the least and most recently written one. Nothing fails on a number, because a record folder has no correct size. What the verb replaces is a reading somebody had to remember to take: the memory pen went from 44 entries to 236 between two counts made by hand a fortnight apart, and nothing reported the rate in between.
|
|
115
115
|
|
|
@@ -224,15 +224,15 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
224
224
|
|
|
225
225
|
### Build the feature
|
|
226
226
|
|
|
227
|
-
| Skill | When to use
|
|
228
|
-
| ---------------------------- |
|
|
229
|
-
| `canon:session-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch
|
|
230
|
-
| `canon:auto-ship` | After plan approval, to chain implement, verify, review, draft PR
|
|
231
|
-
| `canon:project-commands` | When the project's own command needs running
|
|
232
|
-
| `canon:test-first` | Before implementing a planned change, to run its test red, green, then refactor
|
|
233
|
-
| `canon:test-craft` | When writing or changing any test, to pick its layer and filter what it asserts
|
|
234
|
-
| `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first
|
|
235
|
-
| `canon:ui-checklist` | After a UI change, to write what to look at and name what ships untested
|
|
227
|
+
| Skill | When to use |
|
|
228
|
+
| ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
229
|
+
| `canon:session-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch, or to route a refused main-root write |
|
|
230
|
+
| `canon:auto-ship` | After plan approval, to chain implement, verify, review, draft PR |
|
|
231
|
+
| `canon:project-commands` | When the project's own command needs running |
|
|
232
|
+
| `canon:test-first` | Before implementing a planned change, to run its test red, green, then refactor |
|
|
233
|
+
| `canon:test-craft` | When writing or changing any test, to pick its layer and filter what it asserts |
|
|
234
|
+
| `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first |
|
|
235
|
+
| `canon:ui-checklist` | After a UI change, to write what to look at and name what ships untested |
|
|
236
236
|
|
|
237
237
|
### Check the work before it leaves the branch
|
|
238
238
|
|
|
@@ -22,9 +22,9 @@ Claude Code reads both and writes the implementation. Works for CLI tools, inter
|
|
|
22
22
|
|
|
23
23
|
The toolkit seed in `tooling/claude/seeds/canon/DESIGN.md` ships a token-table template with a starting set of roles, and `standards/design.md` carries the same tables under `## Template` with placeholder rows. The column headers are what the renderer parses, so they stay verbatim in either, while the rows and values are the project's own.
|
|
24
24
|
|
|
25
|
-
The `canon:design-extract` skill drafts the file, sourcing tokens from a project's existing prose and CLI UI surfaces, or proposing them from `canon/REQUIREMENTS.md` and a `## Personality` paragraph when no UI code exists yet. `canon design render` writes an HTML plus CSS preview to `.canon/tmp/render/design/` for eyeballing the current system without leaving Claude Code. See `canon/context/design.md`.
|
|
25
|
+
The `canon:design-extract` skill drafts the file, sourcing tokens from a project's existing prose and CLI UI surfaces, or proposing them from `canon/REQUIREMENTS.md` and a `## Personality` paragraph when no UI code exists yet. `canon design render` writes an HTML plus CSS preview to `.canon/tmp/render/design/` for eyeballing the current system without leaving Claude Code. See `canon/context/design/index.md`.
|
|
26
26
|
|
|
27
|
-
A project wanting
|
|
27
|
+
A project wanting a neutral starting point to override runs `canon design install`, which copies one stylesheet to `.claude/design/base.css` carrying an achromatic token set as custom properties and two components built on them. Greys run from near-black to near-white and the accent is monochrome, so the only palette the project renders is one it writes itself. That file is toolkit-owned and `canon design sync` refreshes it, so a project overrides a value in `.claude/design/project/` instead, which sync never touches. Nothing arrives without that install, and the two channels are independent: a record drafted by the extract skill is the project's own, and the installed stylesheet is the toolkit's.
|
|
28
28
|
|
|
29
29
|
A cell no source anchors ends in `? verify`, and the preview shows that marker beside the value rather than folding it in, so a swatch and a font sample stay built from the value alone. A confidence line above the sections names how many cells are anchored against how many are tagged, which is what tells a reader whether they are looking at a record of the code or a proposal about it. It reads the columns a source could anchor and leaves out the row names, so the ratio is not diluted by cells no tag could ever reach. The proposal path tags nearly all of them, so that count reads low on day one by design.
|
|
30
30
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Rule renames a sync carries a target across. Each key under [renamed] is an
|
|
2
|
+
# old rule basename and its value the basename the same rule ships under now,
|
|
3
|
+
# so `canon gov sync` replaces a held old file with the rule under its new name
|
|
4
|
+
# rather than only deleting it.
|
|
5
|
+
#
|
|
6
|
+
# An entry declares one-to-one identity and nothing else. A fold of several
|
|
7
|
+
# rules into one, or a split of one into several, is a retirement plus an
|
|
8
|
+
# addition and takes no entry here. Add the entry in the same change as the
|
|
9
|
+
# rename or renumber, and never prune one: a target can sit any number of
|
|
10
|
+
# releases behind, and a chain A to B to C resolves A only while both links
|
|
11
|
+
# stay. A key must name no live rule and every chain must end on one, which
|
|
12
|
+
# `src/gov/renames.test.ts` checks against this file.
|
|
13
|
+
[renamed]
|
|
@@ -21,4 +21,5 @@ paths:
|
|
|
21
21
|
|
|
22
22
|
## Authority
|
|
23
23
|
|
|
24
|
-
- Follow the skill standard for skill structure, frontmatter fields, invocation rules
|
|
24
|
+
- Follow the skill standard for skill structure, frontmatter fields, and invocation rules. It is the single source. Read it with `canon standards skill`.
|
|
25
|
+
- Follow the skill requirement standard for the shape a `REQUIREMENT.md` states. Read it with `canon standards skill-requirement`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Enter a linked worktree for implementation, resolve shared session scratch at the main root, and route a refused main-root write through session-worktree
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Worktrees standards
|
|
@@ -11,10 +11,4 @@ description: Route tracked-file writes and shared session scratch correctly from
|
|
|
11
11
|
## Shared session scratch
|
|
12
12
|
|
|
13
13
|
- Shared session scratch (`.canon/plans/`, `.canon/review/`, `.canon/memory/`, `.canon/tasks/`) lives at the main worktree root, not inside a linked worktree. From a linked worktree, resolve these paths against the main root via `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`. Fall back to `pwd` if not a git repo.
|
|
14
|
-
-
|
|
15
|
-
- From a linked worktree, every `Edit` or `Write` to a tracked file (source, docs) must use a path starting with `pwd`.
|
|
16
|
-
- From a linked worktree, `Edit` and `Write` are refused for every main-root path, session scratch included. The refusal names session isolation and points at the worktree copy, which is a second gitignored file no later session reads, so never take that redirect.
|
|
17
|
-
- `Read` resolves against the main root normally from a linked worktree. A main-root write reaches it only through `Bash`, as one plain command rather than a compound one, which is refused for complexity.
|
|
18
|
-
- Route a main-root write by what it does to the file. Creating a whole file goes out as one plain `Bash` command carrying a heredoc. Changing a line inside a file that already exists goes through a command that resolves the main root in-process, because the shell route for that case is the stream editor this file bans.
|
|
19
|
-
- A background session that entered no worktree at all meets the identical refusal writing to the main root, since the guard gates on isolation rather than on sitting inside a linked worktree. A planner writing its plan file from no worktree takes the same heredoc route for that reason.
|
|
20
|
-
- The heredoc route costs nothing on `.canon/plans/` and `.canon/review/`, which no `PostToolUse` hook watches, and costs the index on `.canon/tasks/` and `.canon/memory/`, since a hook matching `Write|Edit|MultiEdit` never fires on `Bash`. Regenerate positionally: in-process where a verb such as `canon tasks archive` already calls it, elsewhere by an explicit `canon indexes regen` call.
|
|
14
|
+
- From a linked worktree, or from a background session that entered none, `Edit` and `Write` refuse a main-root path and redirect to a worktree copy no later session reads. Never take that redirect. Route the write the way the `session-worktree` skill states, and report it rather than proceeding silently when that skill does not resolve. It ships with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have it.
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@ SECTION="# Claude"
|
|
|
19
19
|
# The diagrams divergence is the one that cost something. A target used to track
|
|
20
20
|
# its diagrams and keep the context audit's default coverage of them, and it now
|
|
21
21
|
# ignores them with the rest of its records, so that coverage is gone unless the
|
|
22
|
-
# project names the folder itself. `canon/context/tooling.md` carries the
|
|
22
|
+
# project names the folder itself. `canon/context/tooling/manifests.md` carries the
|
|
23
23
|
# narrative.
|
|
24
24
|
#
|
|
25
25
|
# An exception mechanism is not kept against a future divergence, because an
|
|
@@ -95,7 +95,7 @@ ensure_sandbox_anchor_repo() {
|
|
|
95
95
|
# nine to a pass against something that is not the anchor. Refusing is the safe
|
|
96
96
|
# default and creating is the opt-in, the shape `canon tooling sync --write`
|
|
97
97
|
# already sets. `canon records push` refuses outright for the reason
|
|
98
|
-
# `canon/context/development/
|
|
98
|
+
# `canon/context/development/records.md` records, so the two still differ.
|
|
99
99
|
# The sibling SANDBOX_ flags are presence tests, so any non-empty value turns
|
|
100
100
|
# them on. This one allowlists instead, because a presence test would have
|
|
101
101
|
# SANDBOX_ANCHOR_CREATE=false provisioning a repository. Both spellings are
|
|
@@ -163,11 +163,21 @@ export const WORKFLOW_CASES: readonly SkillCase[] = [
|
|
|
163
163
|
prompt: 'Get me set up in a fresh Claude Code worktree for this branch.',
|
|
164
164
|
expect: 'session-worktree',
|
|
165
165
|
},
|
|
166
|
+
{
|
|
167
|
+
prompt:
|
|
168
|
+
'My Write to the plan file at the main root got refused for session isolation. How do I land it there?',
|
|
169
|
+
expect: 'session-worktree',
|
|
170
|
+
},
|
|
166
171
|
{
|
|
167
172
|
prompt:
|
|
168
173
|
'Relay this over to the session that dispatched me. It gave me a sessionId rather than a name, so work out who that is and send it.',
|
|
169
174
|
expect: 'session-relay',
|
|
170
175
|
},
|
|
176
|
+
{
|
|
177
|
+
prompt:
|
|
178
|
+
'I am stuck on a question only the operator can answer. Before I stop and ask it, tell the session that dispatched me, it gave me a sessionId.',
|
|
179
|
+
expect: 'session-relay',
|
|
180
|
+
},
|
|
171
181
|
|
|
172
182
|
// Negatives: pairs whose bodies already carry an explicit Do NOT boundary.
|
|
173
183
|
{
|