@erclx/canon 5.39.0 → 5.41.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 +39 -22
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/REQUIREMENT.md +1 -0
- package/claude/skills/auto-ship/SKILL.md +6 -0
- package/claude/skills/auto-ship/references/fan-in.md +59 -0
- package/claude/skills/canvas-board/SKILL.md +1 -1
- package/claude/skills/create-skill/references/skill.md +1 -1
- package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
- package/claude/skills/decision-escalate/SKILL.md +1 -2
- package/claude/skills/draft-slides/SKILL.md +2 -3
- package/claude/skills/draft-slides/references/deck.md +183 -0
- package/claude/skills/git-branch/REQUIREMENT.md +17 -6
- package/claude/skills/git-branch/SKILL.md +63 -7
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +1 -1
- package/claude/skills/git-pr/references/labels.md +1 -1
- package/claude/skills/git-pr/references/publish.md +1 -1
- package/claude/skills/plan-feature/references/batches.md +48 -1
- package/claude/skills/plan-feature/references/plan.md +2 -0
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
- package/claude/skills/plan-intake-answer/SKILL.md +1 -2
- package/claude/skills/review-address/references/rebase-conflicts.md +7 -0
- package/claude/skills/review-ui/SKILL.md +3 -0
- package/claude/skills/review-ui/references/close-out.md +47 -0
- package/claude/skills/review-ui/references/post.md +3 -1
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
- package/claude/skills/role-worker/REQUIREMENT.md +1 -0
- package/claude/skills/role-worker/SKILL.md +9 -0
- package/claude/skills/task-board/references/board.md +1 -1
- package/claude/skills/task-board/references/tasks.md +1 -1
- package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
- package/claude/skills/teach-workspace/SKILL.md +1 -2
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/docs/agents/audits.md +61 -60
- package/docs/agents/context-audit.md +40 -58
- package/docs/agents/index.md +5 -51
- package/docs/agents/install-and-sync.md +1 -0
- package/docs/agents/markdown-audit.md +53 -99
- package/docs/agents/records.md +37 -79
- package/docs/agents/sessions-transfer.md +26 -70
- package/docs/target/index.md +0 -1
- package/docs/target/migrations.md +57 -66
- package/docs/target/projects.md +36 -78
- package/docs/target/scenarios.md +9 -19
- package/docs/target/sync.md +27 -68
- package/docs/workflow/ai-workflow.md +22 -68
- package/docs/workflow/operating-model.md +32 -186
- package/docs/workflow/parallel-features.md +30 -66
- package/docs/workflow/skill-map-on-request.md +22 -24
- package/docs/workflow/skill-map.md +72 -76
- package/docs/workflow/visual-design-workflow.md +25 -118
- package/docs/workflow/zshrc-aliases.md +18 -37
- package/package.json +1 -1
- package/src/canvas/client/inspector/fields.css +4 -0
- package/src/canvas/index.html +6 -0
- package/src/claude/cases/git.ts +4 -0
- package/src/claude/skills-reach.ts +2 -2
- package/src/cli/ui.ts +3 -1
- package/src/commands/canvas.ts +23 -0
- package/src/commands/capture.ts +14 -0
- package/src/commands/claude.ts +13 -0
- package/src/commands/demo.ts +22 -0
- package/src/commands/deps.ts +6 -0
- package/src/commands/driver.ts +28 -2
- package/src/commands/gov.ts +52 -18
- package/src/commands/intake.ts +17 -0
- package/src/commands/labels.ts +38 -5
- package/src/commands/pr.ts +192 -52
- package/src/commands/records.ts +19 -3
- package/src/commands/secrets.ts +6 -0
- package/src/commands/sessions.ts +8 -0
- package/src/commands/tasks.ts +52 -0
- package/src/commands/teach.ts +13 -0
- package/src/commands/upstream.ts +25 -1
- package/src/commands/worktrees.ts +5 -0
- package/src/context/audit.ts +22 -4
- package/src/context/folders.ts +1 -1
- package/src/context/shape-gated.ts +5 -2
- package/src/counts/scan.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/design/document.ts +1 -1
- package/src/design/tokens.ts +1 -1
- package/src/gate/boundaries.ts +4 -1
- package/src/gate/measures.ts +1 -1
- package/src/gate/stages.ts +7 -7
- package/src/git/env.ts +6 -0
- package/src/markdown/scope.ts +11 -19
- package/src/pr/frames.ts +53 -9
- package/src/pr/lift.ts +153 -19
- package/src/pr/painted.ts +87 -0
- package/src/records/validate.ts +1 -0
- package/src/roots/record.ts +18 -1
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/headless/run.ts +3 -2
- package/src/sandbox/headless/watch.ts +3 -4
- package/src/slides/convert/master.ts +3 -0
- package/src/sync/format.ts +46 -0
- package/src/sync/stamp.ts +6 -0
- package/src/tasks/answers.ts +79 -2
- package/src/tasks/fan-in.ts +176 -0
- package/src/tasks/stack.ts +1 -1
- package/tooling/astro/reference.md +80 -39
- package/tooling/base/reference.md +63 -32
- package/tooling/base/seeds/canon/context/ci.md +7 -15
- package/tooling/base/seeds/canon/context/development.md +14 -14
- package/tooling/claude/reference.md +40 -22
- package/tooling/cloudflare/reference.md +31 -12
- package/tooling/go/reference.md +47 -23
- package/tooling/nextjs/reference.md +52 -19
- package/tooling/php/reference.md +35 -16
- package/tooling/python/reference.md +47 -30
- package/tooling/shell/reference.md +6 -5
- package/tooling/vite-react/reference.md +49 -21
- package/tooling/web/reference.md +131 -71
- package/docs/agents/canvas.md +0 -86
- package/docs/agents/capture.md +0 -65
- package/docs/agents/census.md +0 -23
- package/docs/agents/comments.md +0 -34
- package/docs/agents/context-audit-checks.md +0 -108
- package/docs/agents/context-classify.md +0 -101
- package/docs/agents/counts.md +0 -74
- package/docs/agents/demo.md +0 -140
- package/docs/agents/driver.md +0 -103
- package/docs/agents/gate.md +0 -90
- package/docs/agents/hooks.md +0 -78
- package/docs/agents/intake.md +0 -81
- package/docs/agents/key-changes.md +0 -116
- package/docs/agents/label-coverage.md +0 -86
- package/docs/agents/markdown-audit-density.md +0 -39
- package/docs/agents/markdown-audit-weight.md +0 -83
- package/docs/agents/pr-evidence-layout.md +0 -70
- package/docs/agents/pr-evidence.md +0 -273
- package/docs/agents/pr-frames.md +0 -131
- package/docs/agents/pr-lift.md +0 -132
- package/docs/agents/pr-local.md +0 -111
- package/docs/agents/pr-preview.md +0 -155
- package/docs/agents/pr-reads.md +0 -111
- package/docs/agents/pr-tick.md +0 -72
- package/docs/agents/records-push.md +0 -61
- package/docs/agents/records-stale.md +0 -40
- package/docs/agents/records-validate.md +0 -57
- package/docs/agents/restated.md +0 -83
- package/docs/agents/routing.md +0 -61
- package/docs/agents/rule-citations.md +0 -90
- package/docs/agents/sandbox.md +0 -126
- package/docs/agents/sessions.md +0 -128
- package/docs/agents/skills-audit.md +0 -120
- package/docs/agents/skills-reach.md +0 -64
- package/docs/agents/slides.md +0 -176
- package/docs/agents/state-scoped-risk.md +0 -105
- package/docs/agents/superseded.md +0 -85
- package/docs/agents/tasks-archive.md +0 -83
- package/docs/agents/tasks-plans.md +0 -152
- package/docs/agents/tasks-validate.md +0 -133
- package/docs/agents/tasks.md +0 -123
- package/docs/agents/teach-authoring.md +0 -118
- package/docs/agents/teach.md +0 -157
- package/docs/agents/test-order.md +0 -58
- package/docs/agents/upstream.md +0 -94
- package/docs/agents/worktrees.md +0 -118
- package/docs/target/standards-moved.md +0 -34
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Teach authoring
|
|
3
|
-
description: Resolving what the next lesson needs before it is written, rendering a lesson body's blocks to HTML, and rewriting the root listing, a contents page, and each lesson's chrome and quiz stepper from its marker regions
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Teach authoring
|
|
7
|
-
|
|
8
|
-
The verbs a session runs while writing a lesson. Workspace resolution, the verbs that open and record into a workspace, and the refusal reasons they share are in `teach.md`.
|
|
9
|
-
|
|
10
|
-
## Lesson
|
|
11
|
-
|
|
12
|
-
`canon teach lesson` resolves what the next lesson needs before it is written. It reads and never writes.
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
canon teach lesson regular-expressions \
|
|
16
|
-
--slug capture-groups \
|
|
17
|
-
--questions 3 \
|
|
18
|
-
--options 4
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
| Option | Behavior |
|
|
22
|
-
| ----------------- | --------------------------------------------------------- |
|
|
23
|
-
| `--slug <kebab>` | The lesson's own topic, required |
|
|
24
|
-
| `--questions <n>` | How many questions the quiz carries, required |
|
|
25
|
-
| `--options <n>` | How many options each question carries, defaulting to `4` |
|
|
26
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
27
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
28
|
-
|
|
29
|
-
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.
|
|
30
|
-
|
|
31
|
-
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.
|
|
32
|
-
|
|
33
|
-
`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, so a change to the shared chrome reaches a workspace that already exists. `canon teach nav` and `canon teach up` rewrite it too. `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.
|
|
34
|
-
|
|
35
|
-
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.
|
|
36
|
-
|
|
37
|
-
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.
|
|
38
|
-
|
|
39
|
-
## Render
|
|
40
|
-
|
|
41
|
-
`canon teach render` renders a lesson body's structural blocks to HTML, through the five lesson components. It takes no topic and no `--root`, since the verb is a stateless transform reading nothing off a workspace on disk.
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
echo '[{"type":"heading","level":1,"text":"Compass bearings"}]' | canon teach render --json
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
| Option | Behavior |
|
|
48
|
-
| -------- | ---------------------------------------- |
|
|
49
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
50
|
-
|
|
51
|
-
It reads a JSON array of blocks from stdin, each a `heading`, `paragraph`, `list`, `refs`, `code`, 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.
|
|
52
|
-
|
|
53
|
-
A `code` block carries `text` and an optional `lang`, a highlight.js name or alias. The source is highlighted at render time into `hljs-*` class spans the workspace stylesheet colors in both themes, so the page carries no script. A `lang` the renderer does not register renders as plain escaped code, and one that does not match `^[a-z0-9+#-]+$` is refused. A workspace seeded before the syntax colors existed shows the spans uncolored until `canon teach nav`, `canon teach up`, or `canon teach stylesheet <topic>` rewrites its base stylesheet.
|
|
54
|
-
|
|
55
|
-
```json
|
|
56
|
-
[{ "type": "code", "lang": "ts", "text": "const a: number = 1" }]
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
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.
|
|
60
|
-
|
|
61
|
-
```json
|
|
62
|
-
[
|
|
63
|
-
{ "type": "paragraph", "text": "North is fixed.", "cites": [1] },
|
|
64
|
-
{
|
|
65
|
-
"type": "refs",
|
|
66
|
-
"items": [{ "title": "Compass manual", "url": "https://example.com" }]
|
|
67
|
-
}
|
|
68
|
-
]
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
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`.
|
|
72
|
-
|
|
73
|
-
## Nav
|
|
74
|
-
|
|
75
|
-
`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.
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
canon teach nav
|
|
79
|
-
canon teach nav regular-expressions --json
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
| Option | Behavior |
|
|
83
|
-
| --------------- | ------------------------------------------------- |
|
|
84
|
-
| `[topic]` | Workspace folder or topic, scoping the run to one |
|
|
85
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
86
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
87
|
-
|
|
88
|
-
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.
|
|
89
|
-
|
|
90
|
-
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.
|
|
91
|
-
|
|
92
|
-
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.
|
|
93
|
-
|
|
94
|
-
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.
|
|
95
|
-
|
|
96
|
-
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.
|
|
97
|
-
|
|
98
|
-
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.
|
|
99
|
-
|
|
100
|
-
Every run also rewrites `assets/base.css` wherever the workspace already holds one, so a change to the shared chrome reaches an existing workspace through this verb as well as through `canon teach stylesheet <topic>`. `course.css` is still never rewritten. A legacy workspace holding only a `course.css` is not handed a `base.css`, since its lessons were written without the link. `canon teach up` runs this pass before serving, which is the route that keeps a viewed workspace current.
|
|
101
|
-
|
|
102
|
-
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.
|
|
103
|
-
|
|
104
|
-
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.
|
|
105
|
-
|
|
106
|
-
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.
|
|
107
|
-
|
|
108
|
-
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.
|
|
109
|
-
|
|
110
|
-
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.
|
|
111
|
-
|
|
112
|
-
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.
|
|
113
|
-
|
|
114
|
-
### Reference pages
|
|
115
|
-
|
|
116
|
-
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 fenced code block in a language the highlighter registers is highlighted the same way a `code` block is, and one in any other language stays plain. A hand-written code block in a lesson body is never highlighted. 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.
|
|
117
|
-
|
|
118
|
-
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.
|
package/docs/agents/teach.md
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
---
|
|
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, viewing one with its chrome refreshed, where the lesson authoring verbs are described, the refusal reasons, and why every write here runs through a verb
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Teach
|
|
7
|
-
|
|
8
|
-
Learning workspaces sit under `.canon/teach/<nn>-<topic>/`, and `claude/skills/teach-workspace/references/teach.md` fixes their layout, naming, and file formats, apart from the glossary, whose shape `claude/skills/teach-workspace/references/glossary.md` fixes, cited from the `teach-workspace` skill, so it travels with the file wherever a promotion lands it. Every verb here resolves that folder against the main worktree root rather than against the working directory, so a session standing in a linked worktree reaches the one workspace the learner has rather than opening a second.
|
|
9
|
-
|
|
10
|
-
Passing `--root` a path already named `teach` reaches that folder directly rather than wrapping it in the `.canon/`-or-`.claude/` record-root lookup, which is what lets a workspace committed outside the record root, such as a worked example kept in version control on purpose, take every verb below the same as one under `.canon/teach/`.
|
|
11
|
-
|
|
12
|
-
That root resolution is also why the writing verbs exist at all. The file-editing tools refuse a main-root path from a linked worktree and offer a worktree copy instead, and a caller naming only the destination reports a success that did not happen. A whole-file create still goes out as a shell heredoc. Changing a line inside a file that already exists has no shell route, because the stream editors are banned, so `resource` and `glossary` are the route for the two files a running workspace edits.
|
|
13
|
-
|
|
14
|
-
## List
|
|
15
|
-
|
|
16
|
-
`canon teach list` reports the workspaces under `.canon/teach/`, or what one workspace holds. It reads and never writes.
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
canon teach list
|
|
20
|
-
canon teach list regular-expressions --json
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
| Option | Behavior |
|
|
24
|
-
| --------------- | ------------------------------------------- |
|
|
25
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
26
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
27
|
-
|
|
28
|
-
With no topic it reports one line per workspace, carrying the lesson, learning-record, reference-page, and glossary-term counts, plus `next`, the ordinal an open would take. With one it reports the filenames behind each count and the glossary entries themselves.
|
|
29
|
-
|
|
30
|
-
A folder not named `NN-<topic>` is not a workspace, so the listing, `nav`, and every selector skip it and it moves no ordinal. That is what lets a teach root carry a sibling folder such as `evidence/` without it drawing as a stub row and receiving a contents page.
|
|
31
|
-
|
|
32
|
-
The listing also names the required files a workspace does not carry, which is `MISSION.md`, `RESOURCES.md`, and `GLOSSARY.md`. That is a report rather than a refusal, because a workspace missing one is still a workspace a session can resume.
|
|
33
|
-
|
|
34
|
-
Every record carries `due`, read from the `## Revisit` sections of the workspace's learning records and sorted soonest first. Each entry names the `item`, its `date`, the `rung` it has reached on the spacing ladder, `overdue` once that date has arrived or passed, and the `record` the surviving entry was written in. A later record supersedes an earlier entry for the same item, matched without regard to case, since the schedule is the state of one topic rather than a log of every time it was set.
|
|
35
|
-
|
|
36
|
-
Each entry also carries `hit` and `miss`, the two dates the next record could write. The ladder is 1, 3, 7, 16, and 35 days, a retrieval the learner passed unaided moving up a rung and a miss dropping back one, both held inside the ladder at either end. Reporting both dates is what lets a session copy one rather than compute it, on the same reasoning that put quiz option order in `canon teach lesson`.
|
|
37
|
-
|
|
38
|
-
The field rides on the listing rather than on `canon teach lesson`, because a session needs the schedule before it has chosen what to teach and that verb takes a `--slug` naming a choice already made. An entry not written in the shape the standard fixes is skipped rather than reported, since a note carrying no date has no date to schedule.
|
|
39
|
-
|
|
40
|
-
## Open
|
|
41
|
-
|
|
42
|
-
`canon teach open` creates a workspace at the next ordinal and writes all three required files.
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
canon teach open regular-expressions \
|
|
46
|
-
--subject "Reading and writing regular expressions" \
|
|
47
|
-
--starting-point "Comfortable with the shell, has never written a group" \
|
|
48
|
-
--success "Write a pattern matching a date" \
|
|
49
|
-
--success "Explain what a backreference does"
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
| Option | Behavior |
|
|
53
|
-
| ------------------------- | ----------------------------------------------------------- |
|
|
54
|
-
| `--subject <line>` | One line stating what the workspace covers, required |
|
|
55
|
-
| `--starting-point <text>` | What the learner already knows, required |
|
|
56
|
-
| `--success <line>` | Observable thing the learner will be able to do, repeatable |
|
|
57
|
-
| `--out-of-scope <line>` | What the workspace does not cover, repeatable |
|
|
58
|
-
| `--title <text>` | Title, defaulting to the topic in sentence case |
|
|
59
|
-
| `--date <YYYY-MM-DD>` | Opening date, defaulting to today |
|
|
60
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
61
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
62
|
-
|
|
63
|
-
The ordinal comes from the highest already present, incremented, so the caller derives no name and composes no path. A topic another workspace already covers is refused rather than opened beside it, since two workspaces on one subject fork the learning records the folder exists to keep whole.
|
|
64
|
-
|
|
65
|
-
`--starting-point` is required rather than defaulted because difficulty with no floor under it teaches nobody, and a mission written without one cannot say what the lessons sit above. At least one `--success` line is required for the same reason in the other direction: a mission nothing can test is a mission nothing can call finished.
|
|
66
|
-
|
|
67
|
-
## Resource
|
|
68
|
-
|
|
69
|
-
`canon teach resource` records sources in a workspace `RESOURCES.md`, keeping what was read apart from what was only found.
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
canon teach resource regular-expressions \
|
|
73
|
-
--read "MDN regular expressions=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions" \
|
|
74
|
-
--lead "RE2 syntax=https://github.com/google/re2/wiki/Syntax"
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
| Option | Behavior |
|
|
78
|
-
| -------------------- | -------------------------------------------------- |
|
|
79
|
-
| `--read <title=url>` | Source that stands behind the material, repeatable |
|
|
80
|
-
| `--lead <title=url>` | Source found and not opened, repeatable |
|
|
81
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
82
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
83
|
-
|
|
84
|
-
The pair splits on the first `=`, so a URL carrying its own separator survives intact. Say in the title which claims rest on the source, since the entry is the only place a later session reads that from. Which sources qualify is the source ladder in `claude/skills/teach-workspace/references/teach.md`, and a source below its first two rungs also names why no higher one covers the claim.
|
|
85
|
-
|
|
86
|
-
A URL either heading already lists is refused rather than written twice. Two entries for one source split what rests on it across two lines, and a reader checking a claim then finds half of the answer. The exception is a `--read` URL already under `## Leads`, which moves to `## Read` under the title the call carries, since opening a lead is how it becomes read. A `--read` URL already under `## Read`, and any `--lead` URL already listed, stays refused, and a refusal leaves the whole batch unwritten.
|
|
87
|
-
|
|
88
|
-
A URL a file displays inside a fence does not count as listed, which is how a workspace quoting the entry format in its own prose is read as the sample it is.
|
|
89
|
-
|
|
90
|
-
## Glossary
|
|
91
|
-
|
|
92
|
-
`canon teach glossary` adds terms to a workspace `GLOSSARY.md`, alphabetically.
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
canon teach glossary regular-expressions \
|
|
96
|
-
--term "capture group=A parenthesised part of a pattern whose match is kept" \
|
|
97
|
-
--first-seen 0002-groups.html
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
| Option | Behavior |
|
|
101
|
-
| -------------------------- | --------------------------------------------------------- |
|
|
102
|
-
| `--term <term=definition>` | Term the subject defines, repeatable |
|
|
103
|
-
| `--first-seen <file>` | Lesson or reference page the batch first defines these in |
|
|
104
|
-
| `--json` | Emit a machine-readable record on stdout |
|
|
105
|
-
| `--root <path>` | Teach root, defaulting to the main worktree |
|
|
106
|
-
|
|
107
|
-
One call writes one file, which keeps a batch of terms from racing on the glossary every one of them shares. `--first-seen` names one page for the whole batch rather than one per term, because a batch comes from one lesson.
|
|
108
|
-
|
|
109
|
-
A term already defined is refused rather than replaced. A definition the subject has moved under is a revision of the entry that exists, and nothing on the command line tells that apart from a second definition arriving by mistake.
|
|
110
|
-
|
|
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
|
-
|
|
113
|
-
## Lesson, render, and nav
|
|
114
|
-
|
|
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`.
|
|
116
|
-
|
|
117
|
-
## Opening a workspace
|
|
118
|
-
|
|
119
|
-
`canon teach up` runs the `nav` pass and then serves the teach root, so the page a reader opens carries the chrome the installed CLI generates:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
canon teach up 03-fde-system-design --json
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
The link opens the named workspace's contents page, or the root listing when no topic is named. The verb serves the teach folder at its absolute path, so a run from a linked worktree still reaches the main worktree root. `--port` sets the first port tried and `--root` the teach root, as on every other verb. It runs until interrupted, so a session starts it in the background and reads the record off stdout.
|
|
126
|
-
|
|
127
|
-
The JSON record is one line carrying the `nav` fields, then `served`, the absolute folder, and the server's `host`, `port`, `entry`, `url`, and `entryExists`. A lesson `nav` skips lands in `skipped` and the server still starts, since a partial refresh is still worth viewing. A `nav` refusal starts no server.
|
|
128
|
-
|
|
129
|
-
While it runs, `up` watches the teach root. A change there, such as a lesson, a workspace, a glossary term, or a reference page added by hand or by another `teach` verb, runs the `nav` pass again, and every open page reloads once that pass changes what is served. Passes run one at a time, so a burst of saves costs one more pass rather than several at once. A pass `nav` refuses, such as one over a workspace deleted while it was served, is reported on stderr, the server keeps running, and no page reloads.
|
|
130
|
-
|
|
131
|
-
Each refresh is logged to stderr, so stdout stays the one record line. Dotfiles and editor backups ending in `~` start no pass.
|
|
132
|
-
|
|
133
|
-
The reload script is added to each page as the server sends it and never written to disk, so a page saved from the browser, a promoted lesson, and a committed fixture carry no trace of it. The script listens on `/__live`, which answers only a request naming the server by its loopback address or `localhost`.
|
|
134
|
-
|
|
135
|
-
Viewing writes. Every page and generated stylesheet `nav` owns is rewritten first, which on a committed fixture shows as a diff. To serve without rewriting anything, `canon teach list <topic>` ends its human output with a `canon serve` line for that workspace, with the teach folder written relative to the cwd, or absolute when it sits outside it. The JSON record of `list` carries no such field.
|
|
136
|
-
|
|
137
|
-
`canon serve` itself stays general, since nothing about serving a directory is specific to a learning workspace and the same verb carries a slide render and a design preview. What `up` adds in front of it is the refresh and the watch that repeats it, both teach-specific, and it serves through the same server rather than a second one.
|
|
138
|
-
|
|
139
|
-
Read `url` off the record rather than building one from the port that was asked for. The verb walks forward past a port already in use, which is routine when a second workspace is already open, and the port it took is the one thing a composed URL gets wrong.
|
|
140
|
-
|
|
141
|
-
## Refusal reasons
|
|
142
|
-
|
|
143
|
-
| Reason | Raised when |
|
|
144
|
-
| -------------- | --------------------------------------------------------------- |
|
|
145
|
-
| `no-teach` | The root carries no `.canon/teach/` folder |
|
|
146
|
-
| `no-workspace` | No workspace matches the topic, with the folder names as detail |
|
|
147
|
-
| `ambiguous` | Two workspaces claim one topic, with both names as detail |
|
|
148
|
-
| `exists` | A workspace already covers the topic an open names |
|
|
149
|
-
| `no-file` | The workspace carries no file the verb writes into |
|
|
150
|
-
| `no-section` | `RESOURCES.md` carries no heading the entries belong under |
|
|
151
|
-
| `listed` | A URL is already read, or a lead is offered as listed |
|
|
152
|
-
| `defined` | A term already carries a glossary entry |
|
|
153
|
-
| `bad-input` | The command line is malformed, before any folder is read |
|
|
154
|
-
|
|
155
|
-
`up` also passes through the refusals `canon serve` raises once `nav` has run, `no-port` when every port in reach is taken and `bind-failed` for any other bind error, such as a privileged port, in the same record shape with the server's detail as `message`.
|
|
156
|
-
|
|
157
|
-
A `bad-input` refusal reports the working directory as its root rather than the resolved one, since the command line is rejected before the root is worth resolving. `lesson` raises it for a slug that is not kebab-case, for a quiz carrying no question, and for a question carrying fewer than two options, since a question with one option has nothing to confuse the right answer with.
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Test order
|
|
3
|
-
description: Reading where an implementation reached history ahead of its test, how a pair is decided, the three verdicts, the coverage the pairing cannot reach, and why the check reports rather than gates
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Test order
|
|
7
|
-
|
|
8
|
-
`canon gov test-order` reports where an implementation reached a commit ahead of the test covering the same behavior. It measures the test-first order that the `test-first` skill and `auto-ship` hold, which until this verb existed was prose with nothing measuring it.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
canon gov test-order
|
|
12
|
-
canon gov test-order --base origin/main --json
|
|
13
|
-
canon gov test-order --root ../my-app
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
| Option | Behavior |
|
|
17
|
-
| --------------- | ---------------------------------------------------------- |
|
|
18
|
-
| `--base <ref>` | Ref the range runs back to, defaulting to the trunk |
|
|
19
|
-
| `--root <path>` | Repository to read, defaulting to the current directory |
|
|
20
|
-
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
21
|
-
|
|
22
|
-
Under `--json` the record holds stdout alone and the frame still renders on stderr, refusals included, which is the split `output-shape.md` fixes for every mode. A consumer reading stdout sees pure data, and an operator reading the terminal sees why a run refused rather than a command that appeared to do nothing.
|
|
23
|
-
|
|
24
|
-
## The range it reads
|
|
25
|
-
|
|
26
|
-
The default range is the branch against the trunk, resolved as the merge base against `origin/main` and then local `main`. A repository carrying neither falls back to the root commit, so a fresh checkout still answers rather than refusing.
|
|
27
|
-
|
|
28
|
-
Reading all history on every run measures work nobody is reviewing and buries the finding that matters under the ones already merged. `--base` widens or narrows it when a reader wants a different window.
|
|
29
|
-
|
|
30
|
-
A ref passed there is resolved the same way, through its merge base with `HEAD`, so it names the far side of the range and not the commit the range starts from. `--base origin/main` therefore reports the same window whether the trunk has moved since the branch left or not. Naming a commit the branch already carries still measures from that commit, since the merge base of `HEAD` and an ancestor is the ancestor, and a ref sharing no history with `HEAD` refuses as `bad-base`.
|
|
31
|
-
|
|
32
|
-
Only history is read. A file sitting in the working tree and in no commit is invisible here, which is the point: the verification run sees a tree at one moment, and the ordering exists nowhere but history.
|
|
33
|
-
|
|
34
|
-
## How a pair is decided
|
|
35
|
-
|
|
36
|
-
A test is paired to an implementation by the module path with the test suffix removed, so `src/parser.test.ts` covers `src/parser.ts`. Every record is keyed on the implementation path, which is what a reader goes looking for.
|
|
37
|
-
|
|
38
|
-
Pairing is the whole difficulty. A test and its implementation are related by behavior rather than by filename, so a behavior split across two modules pairs wrongly or not at all. That is what the unclassified verdict exists to catch rather than hide.
|
|
39
|
-
|
|
40
|
-
## The three verdicts
|
|
41
|
-
|
|
42
|
-
- **Satisfied.** The implementation was added in the range and its test reached history no later. A test that predates the range counts, and so does one commit carrying both sides, since the rule asks that the test not come after and a single commit is the shape a small change takes.
|
|
43
|
-
- **Implementation-first.** The implementation was added in the range and its test was added in a later commit of the same range. This is the only verdict that moves the exit code.
|
|
44
|
-
- **Unclassified.** Everything the pairing cannot read, each carrying its own reason. A module the range modified rather than added lands here, because a refactor and a new behavior cannot be told apart from history. So does an implementation no test names, and a test whose implementation the range never introduced.
|
|
45
|
-
|
|
46
|
-
## What it reads past
|
|
47
|
-
|
|
48
|
-
Only `.ts` and `.tsx` are paired, since a test sits beside its subject under one name across that corpus and a bash script has no such partner. Declaration files carry no behavior to test. Every other changed path is counted under `Read past` rather than dropped silently.
|
|
49
|
-
|
|
50
|
-
Coverage is narrower than the rule the check answers to. The rule speaks to every behavior, and the verb speaks to the behaviors it can identify, so the report states its own scope on every run rather than implying it looked at everything.
|
|
51
|
-
|
|
52
|
-
## Exit codes
|
|
53
|
-
|
|
54
|
-
Exit codes are `0` when nothing reached history ahead of its test, `1` for a refusal, and `2` for at least one implementation-first finding. Unclassified rows move no exit code.
|
|
55
|
-
|
|
56
|
-
Nothing wires this into `bun run check` or into a hook. The unclassified class is large and known, and gating a measure carrying a known false-positive class is what teaches contributors to route around the stage. `canon tasks validate` is the precedent: it exits `2` on findings and is called where the claim is made rather than on every push.
|
|
57
|
-
|
|
58
|
-
An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the JSON record's `findings` array rather than the exit when a skill consumes this.
|
package/docs/agents/upstream.md
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Upstream
|
|
3
|
-
description: The fetch, catalog, due, and advance verbs that read Claude Code releases against the toolkit, the cursor record, and each refusal reason
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Upstream
|
|
7
|
-
|
|
8
|
-
`canon upstream` reads the Claude Code release feed from a stored cursor and lists canon's own mechanisms beside it, so a triage can match a release line to something canon does. The verbs ship in the published CLI as `canon gate` and `canon sandbox` do, and only this repository has the skill that drives them. A target has no use for them.
|
|
9
|
-
|
|
10
|
-
Run them as `bun src/cli.ts upstream ...` from this repository's root. The global `canon` resolves to the installed package, which lacks the verbs until a release ships them.
|
|
11
|
-
|
|
12
|
-
## Verbs
|
|
13
|
-
|
|
14
|
-
| Verb | Behavior |
|
|
15
|
-
| ----------------------------------- | ---------------------------------------------------------------------------- |
|
|
16
|
-
| `fetch [--since <version>]` | List the release lines since the cursor, with the mechanical noise dropped |
|
|
17
|
-
| `catalog` | List the skills, verbs, hooks, and gate stages the tree holds, one line each |
|
|
18
|
-
| `due` | Say whether a digest is due, from the cursor and the installed version |
|
|
19
|
-
| `advance <version> --intake <slug>` | Move the cursor to a version, and store the current `llms.txt` beside it |
|
|
20
|
-
|
|
21
|
-
Every verb takes `--root <path>` for the repository to read and `--json` for a record on stdout. `fetch` and `catalog` write nothing, and `due` writes only its day cache. `advance` is the only writer of the cursor, and the digest skill runs it after the findings are filed, so a run that dies midway reads the same range next time.
|
|
22
|
-
|
|
23
|
-
## fetch
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
bun src/cli.ts upstream fetch --json
|
|
27
|
-
bun src/cli.ts upstream fetch --since 2.1.256 --json
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The range runs from the cursor, or from `--since` when given, to the newest release. The walk stops at the first release whose version is not newer than the cursor, so a cursor naming a version the feed never carried still bounds the range, and a range crossing a page boundary is read whole.
|
|
31
|
-
|
|
32
|
-
A line survives when it opens with `Added`, `Changed`, `Removed`, `Improved`, or `Deprecated` and carries none of the dropped surfaces: `[VSCode]`, `[Claude Tag]`, `[Code Review]`, `Windows:`, `Self-hosted`, the apps gateway, managed settings, OpenTelemetry, Bedrock, Vertex, and screen reader. A nested bullet and a `*` bullet are read as well as a `-` one.
|
|
33
|
-
|
|
34
|
-
Without `--json`, stdout carries one `version<TAB>text` row per line. With it, stdout carries one record:
|
|
35
|
-
|
|
36
|
-
| Field | Holds |
|
|
37
|
-
| ---------- | -------------------------------------------------------------------------- |
|
|
38
|
-
| `from` | The cursor version the range starts after |
|
|
39
|
-
| `to` | The newest release version, or `from` when nothing is newer |
|
|
40
|
-
| `releases` | How many releases the range spans |
|
|
41
|
-
| `lines` | Each kept line as `version`, `date`, `text`, and `identifiers` |
|
|
42
|
-
| `llms` | `added` and `removed` lines of `llms.txt` against the stored copy, or null |
|
|
43
|
-
|
|
44
|
-
An identifier is a backticked name on a `Changed`, `Removed`, or `Deprecated` line that holds a dash, a slash, a dot, or a capital. It carries up to three tracked files naming it, and one with no hit is left out. `llms` is null when the page could not be fetched, and every line reads as added until `advance` has stored a first copy.
|
|
45
|
-
|
|
46
|
-
The request sends `GH_TOKEN` or `GITHUB_TOKEN` when either is set. Unauthenticated, GitHub allows 60 requests an hour, and a range takes about three.
|
|
47
|
-
|
|
48
|
-
## catalog
|
|
49
|
-
|
|
50
|
-
Prints a heading per section and a line per entry. With `--json` it prints one record whose fields are `skills`, `internalSkills`, `verbs`, `hooks`, `gate`, and `gaps`, each entry as `name` and `text`. A skill folder with no `SKILL.md` or no description appears in `gaps` rather than dropping out. A hook's text is the first comment line after its shebang.
|
|
51
|
-
|
|
52
|
-
## due
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
bun src/cli.ts upstream due --json
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Answers whether a digest is worth running now. It exits 0 whether or not one is due, so branch on the record rather than the exit. The installed version comes from `claude --version`, and the cursor from the main worktree root.
|
|
59
|
-
|
|
60
|
-
| Reason | `due` | Meaning |
|
|
61
|
-
| ----------------- | ------- | -------------------------------------------------------------------------- |
|
|
62
|
-
| `no-cursor` | `true` | No digest has been run, so a first run is prompted |
|
|
63
|
-
| `week` | `true` | The cursor is seven or more days old and the install is ahead of it |
|
|
64
|
-
| `vocabulary` | `true` | An `Added` line in the gap names a plugin, skill, hook, worktree, or so on |
|
|
65
|
-
| `current` | `false` | The install is at or below the cursor, as after a downgrade |
|
|
66
|
-
| `recent` | `false` | The cursor is under a week old and no line in the gap matches |
|
|
67
|
-
| `unknown-version` | `false` | `claude --version` could not be read |
|
|
68
|
-
|
|
69
|
-
The record is `due`, `reason`, `releases`, `installed`, and `cursor`. `releases` counts the releases in the gap and is `null` when the feed was not read, so a `week` result can arrive without a count.
|
|
70
|
-
|
|
71
|
-
The gap is read from GitHub only when the install is ahead of the cursor, and the result is cached for a day under the scratch folder at `.canon/tmp/upstream-due/check.json`. A failed read is cached too, so a rate limit hit by one session is not retried by the next. Nothing here moves the cursor.
|
|
72
|
-
|
|
73
|
-
The `.claude/hooks/upstream-due.sh` hook runs the verb at an attended session start and shows the operator one line when it is due. It stays silent in a background session, on a resume, a clear, or a compaction, and on any failure.
|
|
74
|
-
|
|
75
|
-
## advance
|
|
76
|
-
|
|
77
|
-
Writes `cursor.json` and the fetched `llms.txt` under the upstream record folder at the main worktree root, each through a temp file and a rename. `--no-llms` keeps the stored `llms.txt` and fetches nothing. The record is `version`, `intake`, `advanced`, and `llms`, which reads `stored` when a fresh copy was written and `kept` when the stored one stayed, whether by `--no-llms` or because the fetch failed.
|
|
78
|
-
|
|
79
|
-
The cursor file holds `version`, `date`, and `intake`. The folder is a backed record folder, so `canon records push` carries it.
|
|
80
|
-
|
|
81
|
-
## Refusals
|
|
82
|
-
|
|
83
|
-
A refusal exits 1, prints the reason on stderr, and with `--json` adds `reason` and `message` to stdout. Branch on `reason`.
|
|
84
|
-
|
|
85
|
-
| Reason | Verb | Meaning |
|
|
86
|
-
| ------------------- | --------- | ------------------------------------------------------------------- |
|
|
87
|
-
| `no-cursor` | `fetch` | No cursor is stored and no `--since` was given. Pass the flag. |
|
|
88
|
-
| `bad-since` | `fetch` | `--since` is not a dotted version |
|
|
89
|
-
| `cursor-missing` | `fetch` | Every release the feed returned is newer than the cursor |
|
|
90
|
-
| `rate-limited` | `fetch` | GitHub refused the request. Set `GH_TOKEN` or `GITHUB_TOKEN`. |
|
|
91
|
-
| `network` | `fetch` | The feed could not be reached |
|
|
92
|
-
| `http` | `fetch` | GitHub answered with an error status |
|
|
93
|
-
| `invalid-version` | `advance` | The version is not a dotted number |
|
|
94
|
-
| `older-than-cursor` | `advance` | The version is older than the stored cursor, which never moves back |
|
package/docs/agents/worktrees.md
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Worktrees
|
|
3
|
-
description: Reporting which worktrees are reclaimable, removing the ones that are, the hidden verb that clears a stranded bare flag, the record a hook reads back, why the reading keys on the pull request rather than on git ancestry, the refusals it names, and the two removal shapes
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Worktrees
|
|
7
|
-
|
|
8
|
-
## List
|
|
9
|
-
|
|
10
|
-
`canon worktrees list` reports every worktree of the current repository with a reclaim verdict and the reason behind it.
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
canon worktrees list
|
|
14
|
-
canon worktrees list --json
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
| Option | Behavior |
|
|
18
|
-
| -------- | --------------------------------------- |
|
|
19
|
-
| `--json` | Add a machine-readable record on stdout |
|
|
20
|
-
|
|
21
|
-
It reads and removes nothing. The question it answers is which worktrees the work has finished with, which nothing in the loop asks: a worktree is created per feature and removed by nobody, so directories left by shipped work accumulate for the life of the checkout.
|
|
22
|
-
|
|
23
|
-
Exit codes: `0` every worktree was read, `1` refused. The refusal carries a `reason` of `gh-missing`, `gh-failed`, or `sessions-unreadable`.
|
|
24
|
-
|
|
25
|
-
An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the record's `reason` rather than the exit when a skill consumes this.
|
|
26
|
-
|
|
27
|
-
## Repair the bare flag
|
|
28
|
-
|
|
29
|
-
`canon worktrees repair-bare-flag` clears a `core.bare` flag that Claude Code's worktree entry left set in the shared config. It is hidden, so no help listing shows it, because its one caller is a hook rather than a person.
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
canon worktrees repair-bare-flag --root <path> --json
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
| Option | Behavior |
|
|
36
|
-
| --------------- | ------------------------------------- |
|
|
37
|
-
| `--root <path>` | Repository to repair, default the cwd |
|
|
38
|
-
| `--json` | Print the record on stdout |
|
|
39
|
-
|
|
40
|
-
`--json` writes `{repaired, reason, message}` on stdout, once, whether or not anything was written. `reason` is `flag-unset`, `common-dir-unreadable`, `genuinely-bare`, or `write-failed` when `repaired` is false. `message` carries text when the flag is repaired and when the write failed, and is null on the three quiet skips. A `write-failed` record means the flag is still set, which a lock file or a read-only config causes. A repository whose common dir is not named `.git` keeps its flag. The exit code is always `0`, so a hook never fails a tool call. Without `--json`, a record carrying a message prints it on stderr and any other prints nothing.
|
|
41
|
-
|
|
42
|
-
## Reclaim
|
|
43
|
-
|
|
44
|
-
`canon worktrees reclaim` removes every worktree the reading above called reclaimable, and the branch behind each one.
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
canon worktrees reclaim --dry-run
|
|
48
|
-
canon worktrees reclaim
|
|
49
|
-
canon worktrees reclaim --json
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
| Option | Behavior |
|
|
53
|
-
| ----------- | ------------------------------------------- |
|
|
54
|
-
| `--dry-run` | Report what would be removed without acting |
|
|
55
|
-
| `--json` | Add a machine-readable record on stdout |
|
|
56
|
-
|
|
57
|
-
Removal sits on the default path rather than behind an apply flag. Report-only is what the `list` verb already did, and what it produced was a hand cleanup: eight directories deleted outside git in one afternoon, each leaving the registration and the branch that `git worktree remove` would have taken with it. A flag a reader has to remember is one nobody passes the first time, and the first time is when the directories are still there.
|
|
58
|
-
|
|
59
|
-
Each entry unlocks, removes, then deletes its branch, and the sequence is the same whether the directory still stands or is already gone. A run carrying a directory that is gone sweeps stale registrations once between the removals and the branch deletes, since a branch git still reads as held by a worktree cannot be deleted. That sweep is the one step reaching past the reclaimable set, because git takes no path to scope it: it clears the bookkeeping for every directory already gone, refused entries included, and deletes no branch and no directory of its own.
|
|
60
|
-
|
|
61
|
-
Exit codes: `0` every reclaimable worktree was removed or there were none, `1` refused or a removal failed. A reading that could not reach the merge state refuses every entry rather than falling back to a default, since that state is the one input deciding whether a branch is safe to delete.
|
|
62
|
-
|
|
63
|
-
### The record
|
|
64
|
-
|
|
65
|
-
`--json` writes `{reason, detail, dryRun, reclaimable, removed, failed, pruned, outcomes}` on stdout. `reason` is null unless the whole reading refused, `reclaimable` counts what the verdicts named, `removed` and `failed` split the outcomes, and `pruned` says whether the stale-registration sweep ran. A dry run and a reading that found nothing both report `removed` as 0 and differ on `reclaimable`, which separates a quiet repository from a run asked not to act.
|
|
66
|
-
|
|
67
|
-
Field order is part of the contract. A shell reads this record with a pattern rather than a parser, so `reason` sits ahead of the free-text `detail`, and the scalar counts sit ahead of `outcomes`, whose per-entry `failedAt` and boolean `removed` match neither digit pattern. Read the record's fields rather than the exit when a skill or a hook consumes this, for the reason the `list` section above gives.
|
|
68
|
-
|
|
69
|
-
## What calls it
|
|
70
|
-
|
|
71
|
-
`canon hooks post-merge`, which `.husky/post-merge` calls, runs `canon worktrees reclaim --json` on every merge, between the records push and the upgrade, so a merged branch's worktree goes without a person remembering. `CANON_SKIP_RECLAIM=1` turns that step off. `hooks.md` covers the verb.
|
|
72
|
-
|
|
73
|
-
That call carries no `--root` and runs from the hook's own working directory, unlike the two steps before it. Git runs a hook from the top level of the worktree the pull happened in, and the verb reads its own working directory to refuse that worktree as `current-worktree`, so a root argument would turn the running worktree into an ordinary candidate and let a pull inside a linked worktree delete the ground under itself.
|
|
74
|
-
|
|
75
|
-
## What makes a worktree reclaimable
|
|
76
|
-
|
|
77
|
-
All three hold: its branch has a merged pull request, its working tree is clean, and no live session holds the directory. Each alone has a case where removal loses something, so `refusals` names every failing condition rather than the first.
|
|
78
|
-
|
|
79
|
-
| Refusal | What it means |
|
|
80
|
-
| ------------------------ | ------------------------------------------------------- |
|
|
81
|
-
| `main-worktree` | The main worktree, which is never reclaimable |
|
|
82
|
-
| `current-worktree` | The worktree the command is running in |
|
|
83
|
-
| `detached-head` | No branch, so nothing names a pull request |
|
|
84
|
-
| `no-merged-pull-request` | Its branch has no merged pull request |
|
|
85
|
-
| `uncommitted-changes` | Work no history stands behind, untracked files included |
|
|
86
|
-
| `unreadable-worktree` | The working tree status could not be read |
|
|
87
|
-
| `held-by-session` | A live session still holds the directory |
|
|
88
|
-
|
|
89
|
-
Uncommitted work is the condition that gates rather than warns. A worktree is gitignored scratch with no history behind it, so a directory removed with unstaged changes takes them somewhere nothing recovers.
|
|
90
|
-
|
|
91
|
-
A directory already deleted by hand is clean rather than unreadable, so the merged and session checks decide it like any other worktree. Reading the two together is what reported eight reclaimable worktrees as unreadable, since `git status` exits the same way for a path that is gone and one it could not read.
|
|
92
|
-
|
|
93
|
-
The worktree the command runs in refuses on position rather than on state. Git removes the directory a caller is standing in without complaint, and every later call scoped to that directory then fails, so a run that took it would leave the branches after it undeleted and report the failures against the worktrees rather than the cause.
|
|
94
|
-
|
|
95
|
-
## Why the pull request rather than git ancestry
|
|
96
|
-
|
|
97
|
-
Ancestry is the reading anyone reaches for and it fails in both directions on a repository that squash merges. A merged branch is never an ancestor of the trunk there, so `git merge-base --is-ancestor` calls shipped work unmerged. Measured against nine worktrees, it named five of six lingering branches unmerged, each of which had a merged pull request, reporting them 2 to 6 commits ahead.
|
|
98
|
-
|
|
99
|
-
The one branch it did call merged was the one that had to stay. That branch had no pull request at all, sat at a release commit, and its worktree held finished work outside any commit. So the cheap test kept every directory safe to remove and offered the only one that was not.
|
|
100
|
-
|
|
101
|
-
The read is one `gh pr list --state merged` for the whole repository rather than one call per worktree, which would be a network round trip inside a loop. It covers the most recent 200 merges, so a worktree older than that reads as having none and is refused, which fails in the direction that keeps a directory.
|
|
102
|
-
|
|
103
|
-
## Two removal shapes
|
|
104
|
-
|
|
105
|
-
`route` names which one applies rather than choosing it, since picking wrong strands state.
|
|
106
|
-
|
|
107
|
-
- `session`: a live session holds the directory, and the `sessions` field carries `{name, kind, id}` per holder rather than a bare name, since `claude rm <id>` takes the id and never the name. `kind` reads `bg` or `interactive` off this repository's session registry.
|
|
108
|
-
- A resolved background holder: `id` carries the value `claude agents --json` reports, so `claude rm <id>` is the command to run. Its own report is not reliable: two runs under matched conditions on 2026-09-03 both printed `kept`, and one of them had already removed the worktree, so read `canon worktrees list` again afterward rather than trust what the command printed.
|
|
109
|
-
- An unresolved background holder: `id` is `null` because the binary is missing, fails, or has not reported that pid yet, so its id has to come from a manual read of `claude agents --json` instead.
|
|
110
|
-
- An interactive holder: `id` is always `null`, since no id exists for one at all, and nothing removes it until a person closes its terminal.
|
|
111
|
-
- `worktree`: the session has ended, and `canon worktrees reclaim` is what runs the remove and the branch delete.
|
|
112
|
-
- `null`: the main worktree, which no removal shape reaches.
|
|
113
|
-
|
|
114
|
-
A held worktree is refused rather than reported reclaimable, and its route is reported for whoever decides to act on it. Deleting a directory underneath a live session is the case that has to refuse, and an interactive holder is the one shape inside that refusal with no removal route at all.
|
|
115
|
-
|
|
116
|
-
## What an unreadable input does
|
|
117
|
-
|
|
118
|
-
It refuses the whole report rather than producing verdicts around the gap. An absent merge state and a branch with no merged pull request return the same empty answer, and so do an absent session roster and a worktree nobody holds. Reporting the second when it was the first is a false clean, and here that ends in a removal rather than in a warning.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Target standards moved
|
|
3
|
-
description: Which skill owns each standard the retired standards verb used to serve, for a project that still calls it
|
|
4
|
-
category: Agent surface
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Target standards moved
|
|
8
|
-
|
|
9
|
-
`canon standards <name>` is gone, and with it the name map that sent an old call to a new home. A rule, skill, or `CLAUDE.md` of your own that still runs it now gets commander's too-many-arguments error and no content, so search the project for the call and replace it. The surrounding step is in [target migrations](migrations.md). <!-- canon-allow-reference: says the verb is gone -->
|
|
10
|
-
|
|
11
|
-
Each standard now lives at `references/<name>.md` in the skill that owns it. Load that skill and read the reference it names:
|
|
12
|
-
|
|
13
|
-
| Skill | Standards |
|
|
14
|
-
| ----------------- | ------------------------------------------------------------- |
|
|
15
|
-
| `task-board` | `board`, `tasks`, `tasks-decline` |
|
|
16
|
-
| `context-fold` | `context` |
|
|
17
|
-
| `canvas-board` | `canvas`, `design` |
|
|
18
|
-
| `docs-sync` | `docs`, `readme` |
|
|
19
|
-
| `draft-figure` | `figures`, `mermaid` |
|
|
20
|
-
| `create-rule` | `rule` |
|
|
21
|
-
| `create-skill` | `skill`, `skill-paths`, `skill-practice`, `skill-requirement` |
|
|
22
|
-
| `git-branch` | `branch`, `slug` |
|
|
23
|
-
| `git-commit` | `commit`, `versioning` |
|
|
24
|
-
| `git-pr` | `pr`, `publish` |
|
|
25
|
-
| `markdown-craft` | `markdown` |
|
|
26
|
-
| `teach-workspace` | `glossary`, `teach` |
|
|
27
|
-
| `plan-groundwork` | `groundwork`, `groundwork-spikes` |
|
|
28
|
-
| `plan-intake` | `intake` |
|
|
29
|
-
| `plan-feature` | `plan`, `plan-lifecycle` |
|
|
30
|
-
| `draft-ready` | `ready` |
|
|
31
|
-
| `draft-doc` | `requirements`, `wiki` |
|
|
32
|
-
| `session-map` | `session` |
|
|
33
|
-
|
|
34
|
-
One name moved under a new filename. `standard`, the shape of a standard itself, became `skill-reference.md` in `create-skill`, since the toolkit no longer ships a standards folder to hold one.
|