@erclx/canon 4.6.1 → 4.8.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/canon-feedback-file/SKILL.md +3 -3
- package/claude/skills/canon-feedback-triage/SKILL.md +1 -1
- package/claude/skills/canon-rollout/SKILL.md +1 -1
- package/claude/skills/canon-screencast/SKILL.md +5 -5
- package/claude/skills/canon-slides-draft/SKILL.md +1 -1
- package/claude/skills/claude-address-review/SKILL.md +4 -4
- package/claude/skills/claude-autoship/SKILL.md +17 -17
- package/claude/skills/claude-design-extract/SKILL.md +2 -2
- package/claude/skills/claude-diagram/SKILL.md +13 -13
- package/claude/skills/claude-docs/SKILL.md +23 -23
- package/claude/skills/claude-feature/SKILL.md +6 -6
- package/claude/skills/claude-groundwork/SKILL.md +16 -16
- package/claude/skills/claude-intake/SKILL.md +8 -8
- package/claude/skills/claude-intake-answer/SKILL.md +1 -1
- package/claude/skills/claude-markdown-propose/REQUIREMENT.md +2 -2
- package/claude/skills/claude-markdown-propose/SKILL.md +8 -8
- package/claude/skills/claude-markdown-propose/references/format.md +3 -3
- package/claude/skills/claude-memory-capture/SKILL.md +13 -13
- package/claude/skills/claude-memory-review/SKILL.md +28 -28
- package/claude/skills/claude-memory-review/references/receipt-format.md +1 -1
- package/claude/skills/claude-orchestrate/SKILL.md +9 -9
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +1 -1
- package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +1 -1
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +1 -1
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +1 -1
- package/claude/skills/claude-orchestrate/scripts/poll.sh +1 -1
- package/claude/skills/claude-planner/REQUIREMENT.md +1 -1
- package/claude/skills/claude-planner/SKILL.md +6 -6
- package/claude/skills/claude-pr-review/SKILL.md +5 -5
- package/claude/skills/claude-review/SKILL.md +4 -4
- package/claude/skills/claude-seed-sync/SKILL.md +2 -2
- package/claude/skills/claude-tasks/SKILL.md +16 -16
- package/claude/skills/claude-teach/SKILL.md +9 -9
- package/claude/skills/claude-ui-test/SKILL.md +3 -3
- package/claude/skills/claude-ux-audit/SKILL.md +5 -5
- package/claude/skills/claude-ux-measure/SKILL.md +3 -3
- package/claude/skills/claude-worker/SKILL.md +2 -2
- package/claude/skills/claude-worktree/SKILL.md +3 -3
- package/claude/skills/git-issue/SKILL.md +4 -4
- package/claude/skills/git-pr/SKILL.md +6 -6
- package/claude/skills/git-ship/SKILL.md +3 -3
- package/claude/skills/git-split/REQUIREMENT.md +1 -1
- package/claude/skills/git-split/SKILL.md +20 -20
- package/claude/skills/migration-superseded/SKILL.md +4 -4
- package/claude/skills/session-map/SKILL.md +2 -2
- package/claude/skills/session-resume/SKILL.md +8 -8
- package/docs/agents/capture.md +17 -11
- package/docs/agents/commands.md +8 -5
- package/docs/agents/demo.md +2 -2
- package/docs/agents/driver.md +2 -2
- package/docs/agents/index.md +1 -1
- package/docs/agents/indexes.md +1 -1
- package/docs/agents/install-and-sync.md +1 -1
- package/docs/agents/intake.md +1 -1
- package/docs/agents/key-changes.md +1 -1
- package/docs/agents/records.md +12 -9
- package/docs/agents/restated.md +2 -2
- package/docs/agents/rule-citations.md +1 -1
- package/docs/agents/sandbox.md +1 -1
- package/docs/agents/state-scoped-risk.md +1 -1
- package/docs/agents/tasks.md +6 -6
- package/docs/agents/teach.md +4 -4
- package/docs/ai-workflow.md +26 -19
- package/docs/operating-model.md +3 -3
- package/docs/target-projects.md +22 -2
- package/docs/visual-design-workflow.md +1 -1
- package/governance/rules/claude/555-tasks.md +3 -3
- package/governance/rules/claude/556-groundwork.md +2 -2
- package/governance/rules/claude/557-intake.md +2 -2
- package/governance/rules/claude/558-plan.md +3 -3
- package/governance/rules/claude/559-memory.md +2 -2
- package/governance/rules/claude/560-diagrams.md +3 -3
- package/governance/rules/claude/561-teach.md +2 -2
- package/governance/rules/claude/562-session.md +2 -2
- package/governance/rules/core/035-tasks.md +2 -2
- package/governance/rules/core/045-memory.md +3 -3
- package/governance/rules/core/055-scratch.md +2 -1
- package/governance/rules/core/085-worktrees.md +1 -1
- package/package.json +1 -2
- package/scripts/core/check-ignore-parity.sh +24 -51
- package/scripts/core/install-check.sh +4 -4
- package/scripts/core/regen-hero.sh +6 -3
- package/scripts/core/snapshot.sh +1 -1
- package/scripts/manage-sandbox.sh +1 -1
- package/scripts/tooling/verify.sh +2 -2
- package/snippets/claude/decision-memo.md +1 -1
- package/snippets/claude/feature-recap.md +1 -1
- package/src/audits/catalog.ts +1 -1
- package/src/capture/render.ts +166 -0
- package/src/capture/sources.ts +42 -0
- package/src/capture/stamp.ts +52 -0
- package/src/claude/cases/all.ts +1 -1
- package/src/claude/seeds.ts +13 -2
- package/src/claude/skills-rank.ts +1 -1
- package/src/cli.ts +5 -5
- package/src/commands/capture.ts +52 -41
- package/src/commands/demo.ts +1 -1
- package/src/commands/design.ts +1 -1
- package/src/commands/feedback.ts +5 -5
- package/src/commands/gov.ts +17 -6
- package/src/commands/intake.ts +1 -1
- package/src/commands/migrate.ts +173 -2
- package/src/commands/pr.ts +1 -1
- package/src/commands/records.ts +1 -1
- package/src/commands/serve.ts +2 -2
- package/src/commands/slides.ts +1 -1
- package/src/commands/tasks.ts +5 -5
- package/src/commands/teach.ts +1 -1
- package/src/context/audit.ts +1 -1
- package/src/demo/compile.ts +1 -1
- package/src/demo/drive.ts +5 -8
- package/src/driver/drive.ts +7 -8
- package/src/gate/measures.ts +1 -1
- package/src/gate/stages.ts +1 -1
- package/src/gov/citations.ts +1 -1
- package/src/gov/restated.ts +3 -3
- package/src/inventory/walk.ts +3 -3
- package/src/migrate/apply.ts +67 -1
- package/src/migrate/records.ts +276 -0
- package/src/paths.ts +1 -1
- package/src/pr/paths.ts +1 -1
- package/src/record-root.ts +77 -27
- package/src/records/backup.ts +71 -17
- package/src/records/validate.ts +1 -1
- package/src/sync/layout.ts +11 -2
- package/src/tasks/answers.ts +1 -1
- package/src/tasks/archive.ts +20 -3
- package/standards/diagrams.md +4 -4
- package/standards/glossary.md +1 -1
- package/standards/groundwork.md +3 -3
- package/standards/index.md +2 -2
- package/standards/intake.md +3 -3
- package/standards/memory.md +2 -2
- package/standards/plan.md +3 -3
- package/standards/session.md +2 -2
- package/standards/standard.md +1 -1
- package/standards/tasks.md +9 -9
- package/standards/teach.md +2 -2
- package/standards/versioning.md +1 -1
- package/tooling/base/configs/.husky/post-merge +1 -1
- package/tooling/base/reference.md +1 -1
- package/tooling/claude/manifest.toml +13 -3
- package/tooling/claude/reference.md +28 -15
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +8 -8
|
@@ -25,10 +25,10 @@ session's review are different passes, and how a feature is sized.
|
|
|
25
25
|
|
|
26
26
|
Read the board in parallel, resolving the paths at the main worktree root per Worktrees in `CLAUDE.md`:
|
|
27
27
|
|
|
28
|
-
- `.
|
|
29
|
-
- `.
|
|
30
|
-
- `.
|
|
31
|
-
- `.
|
|
28
|
+
- `.canon/tasks/priority.md`: execution order and what each task is waiting on
|
|
29
|
+
- `.canon/tasks/backlog.md`: what is not being scheduled, when the file exists
|
|
30
|
+
- `.canon/tasks/index.md`: what is queued
|
|
31
|
+
- `.canon/plans/*.md`: features already planned and ready to hand off
|
|
32
32
|
- open PRs via `gh pr list --json number,title,headRefName,isDraft`
|
|
33
33
|
|
|
34
34
|
Then output the state of play so the human knows what to launch, review, and merge.
|
|
@@ -59,7 +59,7 @@ Orchestrator ready.
|
|
|
59
59
|
Ready to build (hand each to its own worker):
|
|
60
60
|
|
|
61
61
|
<feature>
|
|
62
|
-
plan: .
|
|
62
|
+
plan: .canon/plans/feature-<slug>.md
|
|
63
63
|
→ /claude-autoship
|
|
64
64
|
|
|
65
65
|
<feature>
|
|
@@ -85,7 +85,7 @@ Omit any section with nothing in it. Recommend a handoff only for a plan whose f
|
|
|
85
85
|
|
|
86
86
|
`In flight` covers the state between the other two, which lasts ten to thirty minutes and is most of what an operator sees once this session dispatches its own workers. Before it existed, a session holding running workers reported them under no section and invented a shape per report, which the block below forbids two paragraphs down while giving it no term to use. Read the progress figures off each worker's worktree rather than from the worker, since a busy status says a session is alive and nothing about whether it is moving, and name the model because a dispatcher now picks one per row.
|
|
87
87
|
|
|
88
|
-
Leave a plan out of `Ready to build` once a row in flight names it. The plan file stays in `.
|
|
88
|
+
Leave a plan out of `Ready to build` once a row in flight names it. The plan file stays in `.canon/plans/` for the whole build, so listing it there recommends handing off work already underway, and the disjointness rule below withdraws the recommendation only for a reader who already knows what is running.
|
|
89
89
|
|
|
90
90
|
The block opens on the board rather than on a version, because no committed file states one. Adding a version line here would restate what a reader can already see on the rows, dated by nothing, which is how the retired sequencing surface produced an unsourced claim on every run.
|
|
91
91
|
|
|
@@ -164,7 +164,7 @@ It counts unclaimed plans against workers rather than reading the reserve in ste
|
|
|
164
164
|
3. Archive what closed.
|
|
165
165
|
- A task whose outcomes are all `[x]` runs `claude-docs` for the plan sweep, then `claude-tasks` to archive
|
|
166
166
|
- A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which Boundaries forbids.
|
|
167
|
-
4. Read `.
|
|
167
|
+
4. Read `.canon/tasks/priority.md` and count entries under its `## Run now` heading that carry a written plan. Keep one in reserve beyond what is running.
|
|
168
168
|
5. Promote from the top of `## Needs a plan`, which is where the last sweep recorded what to plan next. Depart from that order when something has changed under it and say what changed, since a position nobody honors is the ordering going stale on the surface built to hold it. What sets the order in the first place is whether a task establishes functionality rather than how old it is, so prefer a task that adds or proves a mechanism over one that trims, tidies, or audits an existing surface.
|
|
169
169
|
- Re-take the board-or-backlog call while the file is open. A row that has stopped being near-term moves to `backlog.md`, and a backlogged task the last wave made near-term moves onto the board. Both are one line removed from one surface and written to the other, and the standard states the test.
|
|
170
170
|
6. Before promoting a candidate, list the files it touches against every task already running, per Parallelism below. Name the overlap and serialize when the sets are not disjoint.
|
|
@@ -191,7 +191,7 @@ Do not promote a task to fill the queue when nothing qualifies. A thin queue is
|
|
|
191
191
|
|
|
192
192
|
### Writing the board
|
|
193
193
|
|
|
194
|
-
Promoting, demoting, and archiving a row all write `.
|
|
194
|
+
Promoting, demoting, and archiving a row all write `.canon/tasks/priority.md`, and this session is the only writer apart from `canon tasks archive`. Moving a task between the board and `.canon/tasks/backlog.md` writes both files, and this session is that file's only writer.
|
|
195
195
|
|
|
196
196
|
- Edit the file with the file-editing tool. A shell stream editor and an inline string replace both exit clean on a non-match, so a promotion that matched nothing leaves the board wrong with nothing reporting it, and the file-editing tool errors instead.
|
|
197
197
|
- Write both halves of a move before reporting it. A row removed from one surface and not written to the other leaves a task file nothing names, and the folder is gitignored with no history to recover the row from. `canon tasks validate` reports that state, so run it after any move.
|
|
@@ -201,7 +201,7 @@ Promoting, demoting, and archiving a row all write `.claude/tasks/priority.md`,
|
|
|
201
201
|
- Re-resolve every Plan pointer after anything archives a plan
|
|
202
202
|
- Read the file back after writing it, since the row that lands is the row a worker acts on
|
|
203
203
|
|
|
204
|
-
A Plan pointer goes stale from a branch this board never sees. `claude-docs` moves a plan to `.
|
|
204
|
+
A Plan pointer goes stale from a branch this board never sees. `claude-docs` moves a plan to `.canon/plans/archive/` and rewrites the citation in the task file alone, so a row for a task still on the board keeps pointing into `.canon/plans/` at a file that has moved. Workers running the ship chain on their own branches archive plans this board still cites, and the board reads as correct until a pointer is followed.
|
|
205
205
|
|
|
206
206
|
## Parallelism
|
|
207
207
|
|
|
@@ -17,7 +17,7 @@ Run `canon tasks plan-answers <plan> --json` and read `launchable` off the recor
|
|
|
17
17
|
|
|
18
18
|
- `launchable: true`: the plan answers itself, so proceed to the branch check.
|
|
19
19
|
- `launchable: false`: the row is not dispatchable. Report every entry in `open`, each carrying the question label and the reason its suggestion gave for needing a person, and hand the row to the human-launch line below. Never fill the slot on the operator's behalf, which is the one move the plan standard forbids outright.
|
|
20
|
-
- `reason: archived`: the row's plan sits in `.
|
|
20
|
+
- `reason: archived`: the row's plan sits in `.canon/plans/archive/` and describes work that already shipped. Repoint the row at a live plan rather than dispatching, since `claude-autoship` Step 1 refuses the same file and the worker would meet that refusal after the launch spent.
|
|
21
21
|
- The command refuses for any other reason, or the record carries no `launchable` key: treat the row as unverified rather than clear, name what could not be read, and fall back to the human. A gate that reads nothing and proceeds is the gate not running.
|
|
22
22
|
|
|
23
23
|
Branch on `launchable` rather than on the exit code, which a shell function wrapping `canon` can flatten to zero and so read a held row as a clear one.
|
|
@@ -15,7 +15,7 @@ The sweep's own question stays distinct from this one. It asks which parked row
|
|
|
15
15
|
|
|
16
16
|
## Scope
|
|
17
17
|
|
|
18
|
-
Every row under `## Up next` and `## Needs a plan` in `.
|
|
18
|
+
Every row under `## Up next` and `## Needs a plan` in `.canon/tasks/priority.md`. A `## Run now` row carries no blocker by definition, so the pass skips it. Resolve the board and each task file at the main worktree root, per Worktrees in `CLAUDE.md`.
|
|
19
19
|
|
|
20
20
|
Take the rows in board order and finish one before opening the next. Clearing a row changes what the next row collides with, so a pass that measures every row first and writes afterwards writes against a board it has already invalidated.
|
|
21
21
|
|
|
@@ -54,7 +54,7 @@ Every classification line names a pull request and a state. A line starting `pol
|
|
|
54
54
|
|
|
55
55
|
The script exits non-zero and classifies nothing when the open pull request list itself fails to load. That case would otherwise report every tracked pull request as merged, so the baseline is left untouched and the run says so.
|
|
56
56
|
|
|
57
|
-
The baseline lives at `.
|
|
57
|
+
The baseline lives at `.canon/tmp/pr-poll/baseline.txt` under the main worktree root and is per-machine. A first run against a board already in flight reports each open pull request once before it settles.
|
|
58
58
|
|
|
59
59
|
The five review headings the script matches are written by `claude-pr-review` and `claude-address-review`, and the whole set is stated once in the first. A project that posts its reviews under different headings edits the jq filters in the script to match, or every pull request reads as never reviewed.
|
|
60
60
|
|
|
@@ -6,7 +6,7 @@ description: What to read back after a compaction, and how to treat a groundwork
|
|
|
6
6
|
Resume as orchestrator after a compaction. Read the board and the groundwork behind the live work before answering anything, because a compaction summary keeps conclusions and drops the reasoning that produced them.
|
|
7
7
|
|
|
8
8
|
1. Resolve the main worktree root with `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. Every path below resolves against it.
|
|
9
|
-
2. Read `.
|
|
9
|
+
2. Read `.canon/tasks/priority.md` for the ordering and what each task waits on. Read the newest `.canon/tasks/session-*.md` when one exists, per `${CLAUDE_SKILL_DIR}/../../standards/session.md`, and treat it as the previous session's scratch rather than a source.
|
|
10
10
|
3. Read the task file for every entry under `## Run now`, plus any entry a live pull request names.
|
|
11
11
|
4. Read the groundwork folder each of those tasks cites. Read `README.md` for the file map, then `06-decision.md` when the track is closed, or `07-next-session.md` and the numbered topic files when it is open. A task's Findings section is a lossy summary of its track, so planning against the summary re-derives what the folder already settled.
|
|
12
12
|
5. Run `gh pr list --state open` and `git log --oneline -5` to see what shipped since the folder was written.
|
|
@@ -18,7 +18,7 @@ if [ -z "$MAIN_ROOT" ]; then
|
|
|
18
18
|
echo "poll: not a git repository, so nothing is classified" >&2
|
|
19
19
|
exit 1
|
|
20
20
|
fi
|
|
21
|
-
STATE_DIR="$MAIN_ROOT/.
|
|
21
|
+
STATE_DIR="$MAIN_ROOT/.canon/tmp/pr-poll"
|
|
22
22
|
mkdir -p "$STATE_DIR"
|
|
23
23
|
STATE="$STATE_DIR/baseline.txt"
|
|
24
24
|
touch "$STATE"
|
|
@@ -42,7 +42,7 @@ before what, and whether a row should run at all stay with the controlling
|
|
|
42
42
|
session, and no body states that boundary for the planning side.
|
|
43
43
|
|
|
44
44
|
Nothing scans a plan for banned words either. `.gitignore` ignores
|
|
45
|
-
`.
|
|
45
|
+
`.canon/plans/`, and the audit's default path set is what git lists, so no gate
|
|
46
46
|
ever opens one. Six ban hits landed across the four trial plans and three of the
|
|
47
47
|
four carried at least one, caught only because the planner ran
|
|
48
48
|
`canon markdown audit` unprompted.
|
|
@@ -21,9 +21,9 @@ from here.
|
|
|
21
21
|
|
|
22
22
|
## Where the session stands
|
|
23
23
|
|
|
24
|
-
- Write one file, the plan, at `.
|
|
24
|
+
- Write one file, the plan, at `.canon/plans/feature-<slug>.md` on the main worktree root. Everything else this session touches is a read.
|
|
25
25
|
- Never enter a worktree, never create a branch, and never write a tracked file. A planner that builds has stopped being one, and the row loses the independent read the worker's own session was going to bring to it.
|
|
26
|
-
- Resolve `.
|
|
26
|
+
- Resolve `.canon/plans/`, `.canon/tasks/`, and `.canon/review/` at the main worktree root. Those folders are gitignored, so a copy beside a linked worktree is absent rather than empty.
|
|
27
27
|
- Plan the row the launch named. Report a second row met while reading rather than planning it, since which rows run is the controller's call.
|
|
28
28
|
|
|
29
29
|
## What to read before deciding
|
|
@@ -33,9 +33,9 @@ Each item below is something a plan needed and a launch string did not carry.
|
|
|
33
33
|
- The task file, and its `## Findings` before deciding anything. A row can carry its own disproof under a title that still states the original claim, which is how one trial nearly planned against a premise the file had already recorded as dead.
|
|
34
34
|
- The source files themselves, opened rather than summarized. Never a count quoted from the task file, which was wrong or stale in ten places across four plans.
|
|
35
35
|
- `CLAUDE.md` and `.claude/ARCHITECTURE.md`, for the decision and the alternative it was taken against rather than for the decision alone.
|
|
36
|
-
- The plan of any row this one is sequenced behind, including one already moved to `.
|
|
37
|
-
- `.
|
|
38
|
-
- `${CLAUDE_SKILL_DIR}/../../standards/plan.md` for the shape, then `canon records validate plans` and `canon markdown audit <the plan file>` on the file once it is written. Nothing else opens a plan, since `.
|
|
36
|
+
- The plan of any row this one is sequenced behind, including one already moved to `.canon/plans/archive/`. Reading a shipped plan produced the strongest constraint in the first trial and no brief asked for it.
|
|
37
|
+
- `.canon/tasks/priority.md` for the row's Touches column and its stated blocker. That column is the file set the dispatch disjointness gate already reads.
|
|
38
|
+
- `${CLAUDE_SKILL_DIR}/../../standards/plan.md` for the shape, then `canon records validate plans` and `canon markdown audit <the plan file>` on the file once it is written. Nothing else opens a plan, since `.canon/plans/` is gitignored and the audit's default path set is what git lists.
|
|
39
39
|
|
|
40
40
|
## Read what is in flight rather than inferring it
|
|
41
41
|
|
|
@@ -46,7 +46,7 @@ Each item below is something a plan needed and a launch string did not carry.
|
|
|
46
46
|
|
|
47
47
|
## The board is read-only
|
|
48
48
|
|
|
49
|
-
- Never write `.
|
|
49
|
+
- Never write `.canon/tasks/priority.md` or `.canon/tasks/backlog.md`. Both are gitignored, so an overwrite drops a row with no history to recover it from.
|
|
50
50
|
- Never write the task file either. The plan is the whole output, and a row edited from here changes what the controller reads back as the state of the board.
|
|
51
51
|
- Report what the row got wrong rather than repairing it. A stale count, a moved line, or a path that no longer resolves goes into the plan and into the handback, and the controller decides which of the two carries the correction.
|
|
52
52
|
- Leave the cross-feature call alone. Which rows collide, what merges before what, and whether a row should run at all stay with the controller. `priority.md` shows blockers and file sets and is enough to write a confident merge order off a partial picture, which is the failure this boundary exists to prevent.
|
|
@@ -36,8 +36,8 @@ Read these in parallel from the project root, skipping any that do not exist:
|
|
|
36
36
|
- `CLAUDE.md`: project type, conventions, and commands
|
|
37
37
|
- `.claude/REQUIREMENTS.md`: feature scope and non-goals
|
|
38
38
|
- `.claude/ARCHITECTURE.md`: technical design decisions
|
|
39
|
-
- `.
|
|
40
|
-
- `.
|
|
39
|
+
- `.canon/tasks/priority.md`: where this feature sits on the board and what each neighboring row waits on. Resolve this one at the main worktree root per Worktrees in `CLAUDE.md`, since the board is gitignored and a linked worktree holds no copy of it
|
|
40
|
+
- `.canon/plans/feature-<slug>.md` for the branch, when present: the intent the PR should satisfy
|
|
41
41
|
|
|
42
42
|
Coding standards from `.claude/rules/` are auto-loaded by Claude Code.
|
|
43
43
|
|
|
@@ -141,7 +141,7 @@ Use severity: `critical` (blocks merge), `should-fix` (fix before merge), `minor
|
|
|
141
141
|
|
|
142
142
|
## Step 4: post to the PR
|
|
143
143
|
|
|
144
|
-
Write the comment to `.
|
|
144
|
+
Write the comment to `.canon/tmp/pr-review/body-<number>-<short-sha>.md`, which the rest of this step calls `<body-file>`. The PR number stops two sessions reviewing different pull requests from overwriting each other between the write and the post. The head commit stops a second pass overwriting the first one's body, and leaves the folder a record of which commit each review covered.
|
|
145
145
|
|
|
146
146
|
Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
|
|
147
147
|
|
|
@@ -228,12 +228,12 @@ The `What is right` section is optional, capped at three bullets, and included o
|
|
|
228
228
|
|
|
229
229
|
Close the body with `🤖 Reviewed by Claude Code` on its own line so the review reads as an independent machine pass, not a human sign-off.
|
|
230
230
|
|
|
231
|
-
Before posting, run the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against the body. The hook skips `.
|
|
231
|
+
Before posting, run the scan in `${CLAUDE_SKILL_DIR}/../../standards/publish.md` against the body. The hook skips `.canon/tmp/`, so this scan is the only gate on the published comment. A finding phrased against an internal phase label is what the label half of the scan catches here.
|
|
232
232
|
|
|
233
233
|
Do not run the command below when `<prior-heading>` from Step 2 reads `## Review closed` and this pass carries nothing owed. That pass replaces the standing comment rather than adding one, under `### A close-out that repeats the standing one` at the end of this step. Posting first and reaching that section afterward leaves two close-outs both naming the new head, which is worse than the pair the guard exists against.
|
|
234
234
|
|
|
235
235
|
```bash
|
|
236
|
-
gh pr review <number> --comment --body-file .
|
|
236
|
+
gh pr review <number> --comment --body-file .canon/tmp/pr-review/body-<number>-<short-sha>.md
|
|
237
237
|
```
|
|
238
238
|
|
|
239
239
|
A pass carrying nothing at all takes `## Review closed` and a short body, with the footer line included either way. On a first pass, post `✅ No findings. Reviewed against project docs and the board.` On a later pass, post `✅ Prior findings addressed. Re-reviewed <short-sha>, N commits since the prior pass.`
|
|
@@ -120,13 +120,13 @@ If nothing is wrong, use: `✅ No findings.`
|
|
|
120
120
|
|
|
121
121
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
122
122
|
|
|
123
|
-
Write the full report directly to `.
|
|
123
|
+
Write the full report directly to `.canon/review/branch/review-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
|
|
124
124
|
|
|
125
125
|
From a linked worktree the file-editing tools refuse that path, so the report goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
126
126
|
|
|
127
127
|
If there are no findings, write `✅ No findings.` to the file with a timestamp.
|
|
128
128
|
|
|
129
|
-
The `.
|
|
129
|
+
The `.canon/review/` directory is gitignored. Do not stage or commit the file.
|
|
130
130
|
|
|
131
131
|
The report is disposable. It outlives the ship chain that reads it, and `claude-docs` sweeps it once the branch it names is gone, because the durable record of what a review found is the comment `claude-pr-review` posts on the pull request. A review run on a branch that never opens one leaves nothing behind once that branch is gone, so fold anything worth keeping into the pull request body or a task finding while the report is still on disk.
|
|
132
132
|
|
|
@@ -136,7 +136,7 @@ Output only the summary line and the file path. Do not repeat the full report in
|
|
|
136
136
|
|
|
137
137
|
```plaintext
|
|
138
138
|
X critical, Y should-fix, Z minor across N files.
|
|
139
|
-
📝 Wrote .
|
|
139
|
+
📝 Wrote .canon/review/branch/review-<slug>.md
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
If no findings: `✅ No findings. Wrote .
|
|
142
|
+
If no findings: `✅ No findings. Wrote .canon/review/branch/review-<slug>.md`
|
|
@@ -68,7 +68,7 @@ Before proposing an Update, grep the target section for the seed text's keywords
|
|
|
68
68
|
|
|
69
69
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
70
70
|
|
|
71
|
-
Write the full proposal to `.
|
|
71
|
+
Write the full proposal to `.canon/review/seed-audit-<slug>.md` at the main worktree root. Do not print the proposal inline.
|
|
72
72
|
|
|
73
73
|
From a linked worktree the file-editing tools refuse that path, so the proposal goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
74
74
|
|
|
@@ -123,7 +123,7 @@ Decision:
|
|
|
123
123
|
|
|
124
124
|
Update items show both sides in one `diff` block: removed lines from the project version with `-`, added lines from the seed version with `+`, unchanged context lines without a prefix. Add items show only `+` lines. Customized sections appear in the scope table only, never numbered. A file with no drift still appears in the scope table as `in sync`.
|
|
125
125
|
|
|
126
|
-
After writing, tell the user `✅ Wrote proposal to .
|
|
126
|
+
After writing, tell the user `✅ Wrote proposal to .canon/review/seed-audit-<slug>.md`. Ask them to fill in `Decision:` per item, then re-ping or use the chat shortcut.
|
|
127
127
|
|
|
128
128
|
Rewrite the review file in place whenever the proposal changes mid-review. The file stays the source of truth for the current decisions.
|
|
129
129
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claude-tasks
|
|
3
|
-
description: Creates a task file in `.
|
|
3
|
+
description: Creates a task file in `.canon/tasks/` with the filename, phase label, and frontmatter the standard requires, and archives a shipped one out of the folder. Use when asked to "add a task", "create a task", "queue this", "put this on the board", "archive that task", or "close out a shipped task". Do NOT use to mark an outcome `[x]` or to archive a plan. That is `claude-docs`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Claude tasks
|
|
@@ -13,9 +13,9 @@ Read `${CLAUDE_SKILL_DIR}/../../standards/tasks.md` before writing any file. It
|
|
|
13
13
|
|
|
14
14
|
- Resolve the board at the main worktree root, not `pwd`. Run `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd` outside a git repo. Every read and write below resolves against that root. The board is gitignored scratch shared across worktrees, so a linked worktree writing to its own `pwd` creates a second board nothing else reads.
|
|
15
15
|
- From a linked worktree the file-editing tools refuse that root, so a new task file goes out through `Bash` as a plain single command carrying a heredoc. Archiving already runs through `canon tasks archive`, which resolves the root in-process. Marking an outcome shipped is `claude-docs` and runs through `canon tasks outcome`. See Worktrees in `CLAUDE.md`.
|
|
16
|
-
- If `.
|
|
16
|
+
- If `.canon/tasks/` does not exist at that root, stop: `❌ No .canon/tasks/ board. Run canon claude init to set it up.`
|
|
17
17
|
- Route on the request rather than on a flag. Creating names work that does not exist yet, archiving names a task file already on the board. If the request fits neither, stop: `❌ Ambiguous. Say whether to create a task or archive one.`
|
|
18
|
-
- Never hand-edit `.
|
|
18
|
+
- Never hand-edit `.canon/tasks/index.md`. A hook regenerates it from sibling frontmatter after a write. Do not run the regen command directly, except after a shell write from a linked worktree: the hook matches `Write|Edit|MultiEdit` and nothing fires on `Bash`, so that one case regenerates explicitly with `canon indexes regen --no-stage --root <main-root> <main-root>/.canon/tasks/index.md`.
|
|
19
19
|
|
|
20
20
|
## Create
|
|
21
21
|
|
|
@@ -29,15 +29,15 @@ Accept work whose origin is the conversation itself only when the user says so e
|
|
|
29
29
|
|
|
30
30
|
### Step 2: propose the phase label
|
|
31
31
|
|
|
32
|
-
List the existing filenames in `.
|
|
32
|
+
List the existing filenames in `.canon/tasks/` and read `index.md` for what each holds. Propose the next label from what is already on the board, and say which neighbors it sits between.
|
|
33
33
|
|
|
34
34
|
Do not derive the label from a version file. `${CLAUDE_SKILL_DIR}/../../standards/versioning.md` permits free renumbering, so the board is the only surface that knows what a label currently means. Pad the phase to two digits in the filename, since index entries sort by filename alone and a bare `v9.0` sorts after `v15.0`.
|
|
35
35
|
|
|
36
36
|
### Step 3: write the file
|
|
37
37
|
|
|
38
|
-
Write `.
|
|
38
|
+
Write `.canon/tasks/vXX.Y-<slug>.md` following the format in `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. Include a link line only when the file or folder it names exists. A link to a plan nobody has written yet is the broken pointer the archive rules exist to prevent.
|
|
39
39
|
|
|
40
|
-
Write `Plan:`, `Groundwork:`, and `Intake:` as markdown links relative to `.
|
|
40
|
+
Write `Plan:`, `Groundwork:`, and `Intake:` as markdown links relative to `.canon/tasks/`, as in `Plan: [feature-<slug>](../plans/feature-<slug>.md)`. Leave `Issue:` a bare `#NNN`. A task written in the older bare-path form still parses, so it costs the board a clickable line rather than an archive, but it leaves the board in two shapes for every reader after.
|
|
41
41
|
|
|
42
42
|
Never write a `Pull request:` line here. `git-pr` adds it when a pull request opens, and a number guessed at create time points at someone else's work.
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ Write it immediately. Claude Code's tool permission dialog is the confirmation g
|
|
|
45
45
|
|
|
46
46
|
### Step 4: place it on a surface
|
|
47
47
|
|
|
48
|
-
A task file with no row is a dropped task, so name the surface it lands on in the same pass that creates it. A task that would plausibly be planned within the next few waves takes a row under `## Needs a plan` in `.
|
|
48
|
+
A task file with no row is a dropped task, so name the surface it lands on in the same pass that creates it. A task that would plausibly be planned within the next few waves takes a row under `## Needs a plan` in `.canon/tasks/priority.md`, positioned by where it sits against the rows already there, with the reason for that position in its `Waiting on` cell. Anything else takes a line in `.canon/tasks/backlog.md`, which is unordered and where in the file it goes means nothing.
|
|
49
49
|
|
|
50
50
|
The test and both file shapes are in `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. From a linked worktree the file-editing tools refuse the main root, so a row lands through the same `Bash` route the file itself took.
|
|
51
51
|
|
|
@@ -55,9 +55,9 @@ Say which surface it went to and why in the report. The call is a judgment resta
|
|
|
55
55
|
|
|
56
56
|
Scan for work that has been decided and would otherwise be forgotten. Three origins carry it, and every run reads all three.
|
|
57
57
|
|
|
58
|
-
List `.
|
|
58
|
+
List `.canon/groundwork/` and run `gh issue list --state open` when a remote is configured, then grep the board for each track name and issue number. Report any with no task, one line each.
|
|
59
59
|
|
|
60
|
-
Read the dumps through `canon intake list --json`, which reports items, open, unread, and malformed per folder and owns the parse of the answer contract `${CLAUDE_SKILL_DIR}/../../standards/intake.md` fixes. Then grep both `.
|
|
60
|
+
Read the dumps through `canon intake list --json`, which reports items, open, unread, and malformed per folder and owns the parse of the answer contract `${CLAUDE_SKILL_DIR}/../../standards/intake.md` fixes. Then grep both `.canon/tasks/` and `.canon/tasks/archive/` for each folder slug. A dump with no live task is the ordinary shape of one already promoted and shipped, so a check reading the board by itself reports every finished folder as abandoned.
|
|
61
61
|
|
|
62
62
|
A dump is the stronger case for this scan rather than the weaker one. A track holds one question and stays visible, while a dump holds dozens of items whose verdicts were reached and then left with nothing carrying them forward.
|
|
63
63
|
|
|
@@ -122,7 +122,7 @@ Leave `TASK-ARCHIVE.md` alone when it is present in the archive folder. It recor
|
|
|
122
122
|
|
|
123
123
|
### Step 4: clear prose naming the task
|
|
124
124
|
|
|
125
|
-
The command drops the task's row from `.
|
|
125
|
+
The command drops the task's row from `.canon/tasks/priority.md` and leaves prose alone. Remove any sentence that still names the archived task or counts the rows that changed, since a stale count reads as board state.
|
|
126
126
|
|
|
127
127
|
## Output
|
|
128
128
|
|
|
@@ -131,21 +131,21 @@ Emit the full relative path from the project root for every file written or move
|
|
|
131
131
|
Create:
|
|
132
132
|
|
|
133
133
|
```plaintext
|
|
134
|
-
✅ Created: .
|
|
134
|
+
✅ Created: .canon/tasks/vXX.Y-<slug>.md
|
|
135
135
|
|
|
136
136
|
<label> sits between <neighbor> and <neighbor>.
|
|
137
137
|
<board or backlog, and why it landed there>.
|
|
138
138
|
|
|
139
139
|
**Origin with no task:**
|
|
140
140
|
|
|
141
|
-
- `.
|
|
142
|
-
- `.
|
|
141
|
+
- `.canon/groundwork/<slug>/`: open, touched <date>
|
|
142
|
+
- `.canon/intake/<slug>/`: every item answered, nothing promoted
|
|
143
143
|
- #NNN: <issue title>
|
|
144
144
|
|
|
145
145
|
**Waiting on you:**
|
|
146
146
|
|
|
147
|
-
- `.
|
|
148
|
-
- `.
|
|
147
|
+
- `.canon/intake/<slug>/`: <n> of <n> items unread
|
|
148
|
+
- `.canon/intake/<slug>/`: <n> items carry no answer slot, so no verb reaches them
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
Drop either block when it carries no rows. When both are empty, which is the ordinary result, replace them with one line naming what was read: `Read <n> tracks, <n> dumps, and <n> open issues. Nothing unlinked.`
|
|
@@ -153,7 +153,7 @@ Drop either block when it carries no rows. When both are empty, which is the ord
|
|
|
153
153
|
Archive, reporting the paths the command returned:
|
|
154
154
|
|
|
155
155
|
```plaintext
|
|
156
|
-
📦 Archived: .
|
|
156
|
+
📦 Archived: .canon/tasks/archive/vXX.Y-<slug>.md
|
|
157
157
|
|
|
158
158
|
<ordering and index disposition in one line>
|
|
159
159
|
```
|
|
@@ -118,7 +118,7 @@ Follow `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` for what makes a lesson
|
|
|
118
118
|
A lesson is a page carrying a stylesheet and a script, and an editor preview opens it with neither, so a path alone delivers unstyled markup that reads as the lesson. Serve the teach root and give the learner a link they can click:
|
|
119
119
|
|
|
120
120
|
```bash
|
|
121
|
-
canon serve .
|
|
121
|
+
canon serve .canon/teach --entry <nn>-<topic>/index.html --json
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
Start it in the background so the session keeps going, and read `url` off the record rather than composing one. The verb walks past a port already in use, so the port it took is exactly the half a guessed URL gets wrong. Report the refusal and its `reason` when `ok` is false, and report it rather than proceeding silently when the verb does not resolve at all, which is an installed CLI predating it.
|
|
@@ -149,12 +149,12 @@ Still owed: <what the destination expects that the page does not carry yet>
|
|
|
149
149
|
|
|
150
150
|
Then stop and let the operator strike, redirect, or confirm each block.
|
|
151
151
|
|
|
152
|
-
Write nothing to a destination here. One skill owns the durable writes, and two skills editing one file at one step is the failure that rule exists against. Record each confirmed block in `.
|
|
152
|
+
Write nothing to a destination here. One skill owns the durable writes, and two skills editing one file at one step is the failure that rule exists against. Record each confirmed block in `.canon/tmp/teach-promotion/<slug>.md` at the main worktree root instead, appending when the file exists, with one H2 per destination naming its path, the source page beneath it, and the page body fenced:
|
|
153
153
|
|
|
154
154
|
````markdown
|
|
155
155
|
## <destination path>
|
|
156
156
|
|
|
157
|
-
Source: .
|
|
157
|
+
Source: .canon/teach/<nn>-<topic>/reference/<slug>.md
|
|
158
158
|
|
|
159
159
|
```markdown
|
|
160
160
|
<the page body as it should land, with the source line the destination expects>
|
|
@@ -172,10 +172,10 @@ An append is a whole-file operation, so send it as a plain single `Bash` command
|
|
|
172
172
|
## Output
|
|
173
173
|
|
|
174
174
|
```plaintext
|
|
175
|
-
✅ <opened|resumed> .
|
|
176
|
-
Lesson: .
|
|
177
|
-
Reference: .
|
|
178
|
-
Record: .
|
|
175
|
+
✅ <opened|resumed> .canon/teach/<nn>-<topic>/
|
|
176
|
+
Lesson: .canon/teach/<nn>-<topic>/lessons/<nnnn>-<slug>.html
|
|
177
|
+
Reference: .canon/teach/<nn>-<topic>/reference/<slug>.md
|
|
178
|
+
Record: .canon/teach/<nn>-<topic>/learning-records/<nnnn>-<slug>.md
|
|
179
179
|
Progress: <n> of <m> success lines met
|
|
180
180
|
Open: [<the url the serve verb reported>](<the same url>)
|
|
181
181
|
```
|
|
@@ -189,8 +189,8 @@ Emit every path from the project root, in the form the project's instruction fil
|
|
|
189
189
|
A promotion pass reports its own shape instead, one line per page the operator confirmed and one naming the handoff:
|
|
190
190
|
|
|
191
191
|
```plaintext
|
|
192
|
-
➡️ Promoting: .
|
|
193
|
-
→ Confirmed pages wait at .
|
|
192
|
+
➡️ Promoting: .canon/teach/<nn>-<topic>/reference/<slug>.md → <destination path>
|
|
193
|
+
→ Confirmed pages wait at .canon/tmp/teach-promotion/<slug>.md. Run /claude-docs from a branch to fold them in.
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
A pass where the operator confirmed nothing writes no handoff file and reports that alone.
|
|
@@ -59,19 +59,19 @@ If all changes are automatable, skip the manual checklist:
|
|
|
59
59
|
|
|
60
60
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
61
61
|
|
|
62
|
-
When a manual checklist is produced, write it directly to `.
|
|
62
|
+
When a manual checklist is produced, write it directly to `.canon/review/ui-checklist-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
|
|
63
63
|
|
|
64
64
|
From a linked worktree the file-editing tools refuse that path, so the checklist goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
65
65
|
|
|
66
66
|
Skip the file write when all changes are covered by e2e tests and no checklist was produced.
|
|
67
67
|
|
|
68
|
-
The `.
|
|
68
|
+
The `.canon/review/` directory is gitignored. Do not stage or commit the file.
|
|
69
69
|
|
|
70
70
|
## Output order
|
|
71
71
|
|
|
72
72
|
1. Write and run e2e tests (report pass/fail)
|
|
73
73
|
2. If a manual checklist was produced, write it to file, then output only the file path in chat:
|
|
74
|
-
`📝 Wrote .
|
|
74
|
+
`📝 Wrote .canon/review/ui-checklist-<slug>.md`
|
|
75
75
|
3. If no checklist was needed: `✅ All changes covered by e2e tests. No manual verification needed.`
|
|
76
76
|
|
|
77
77
|
Do not repeat the full checklist in chat.
|
|
@@ -21,7 +21,7 @@ Read these in parallel from the project root, skipping any that do not exist:
|
|
|
21
21
|
|
|
22
22
|
## Step 2: identify surfaces
|
|
23
23
|
|
|
24
|
-
List the UI surfaces in the project. A surface is a distinct screen, page, panel, or major component (e.g. sidepanel, popup, settings page, empty state). Group files by surface. Do not audit speculative or unfinished code flagged in `.
|
|
24
|
+
List the UI surfaces in the project. A surface is a distinct screen, page, panel, or major component (e.g. sidepanel, popup, settings page, empty state). Group files by surface. Do not audit speculative or unfinished code flagged in `.canon/tasks/` as in-progress.
|
|
25
25
|
|
|
26
26
|
## Step 3: audit each surface
|
|
27
27
|
|
|
@@ -59,13 +59,13 @@ If nothing is wrong, use: `✅ No observations.`
|
|
|
59
59
|
|
|
60
60
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
61
61
|
|
|
62
|
-
Write the full report directly to `.
|
|
62
|
+
Write the full report directly to `.canon/review/ux-audit-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
|
|
63
63
|
|
|
64
64
|
From a linked worktree the file-editing tools refuse that path, so the report goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
65
65
|
|
|
66
66
|
If there are no observations, write `✅ No observations.` to the file with a timestamp.
|
|
67
67
|
|
|
68
|
-
The `.
|
|
68
|
+
The `.canon/review/` directory is gitignored. Do not stage or commit the file.
|
|
69
69
|
|
|
70
70
|
### Chat output
|
|
71
71
|
|
|
@@ -73,7 +73,7 @@ Output only the summary line and the file path. Do not repeat the full report in
|
|
|
73
73
|
|
|
74
74
|
```plaintext
|
|
75
75
|
X observations across N surfaces.
|
|
76
|
-
📝 Wrote .
|
|
76
|
+
📝 Wrote .canon/review/ux-audit-<slug>.md
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
If no observations: `✅ No observations. Wrote .
|
|
79
|
+
If no observations: `✅ No observations. Wrote .canon/review/ux-audit-<slug>.md`
|
|
@@ -106,11 +106,11 @@ Report the reading and stop there. A remedy for a poor verdict is a change with
|
|
|
106
106
|
|
|
107
107
|
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
108
108
|
|
|
109
|
-
Write the full reading directly to `.
|
|
109
|
+
Write the full reading directly to `.canon/review/ux-measure-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
|
|
110
110
|
|
|
111
111
|
From a linked worktree the file-editing tools refuse that path, so the reading goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
112
112
|
|
|
113
|
-
The `.
|
|
113
|
+
The `.canon/review/` directory is gitignored. Do not stage or commit the file.
|
|
114
114
|
|
|
115
115
|
### Chat output
|
|
116
116
|
|
|
@@ -118,5 +118,5 @@ Output the summary line and the file path. Do not repeat the table in chat.
|
|
|
118
118
|
|
|
119
119
|
```plaintext
|
|
120
120
|
3 metrics measured against <url>. <n> past threshold.
|
|
121
|
-
📝 Wrote .
|
|
121
|
+
📝 Wrote .canon/review/ux-measure-<slug>.md
|
|
122
122
|
```
|
|
@@ -22,13 +22,13 @@ running and re-invoking it would restart the build.
|
|
|
22
22
|
|
|
23
23
|
## Where the session stands
|
|
24
24
|
|
|
25
|
-
- Resolve `.
|
|
25
|
+
- Resolve `.canon/plans/`, `.canon/tasks/`, `.canon/review/`, and `.canon/memory/` at the main worktree root, never against the linked worktree this session builds in. Those folders are gitignored, so `git worktree add` never creates them and the copy beside the build is absent rather than empty.
|
|
26
26
|
- Report a plan that fails to resolve as unreadable from here, naming the main-root path. Reporting the task as having no plan is true where this session stands and wrong about the world, and a reader with no second tree to check cannot separate the two.
|
|
27
27
|
- Build the plan the launch named. Do not write a second one when the path fails to resolve, since a row that cites a plan already has one and drafting another produces two plans for one row.
|
|
28
28
|
|
|
29
29
|
## The board is read-only
|
|
30
30
|
|
|
31
|
-
- Never write `.
|
|
31
|
+
- Never write `.canon/tasks/priority.md` or `.canon/tasks/backlog.md`. The controlling session is their only writer apart from `canon tasks archive`, and both are gitignored, so an overwrite drops a row with no history to recover it from.
|
|
32
32
|
- Report a row this build turns up rather than adding it. Picking a free label means reading every task file and every archive entry, which this session has not done, so a label it invents collides with one already taken.
|
|
33
33
|
- Write the task file this build closes and the plan it ran under. The ban covers the shared board rather than the artifacts of the row in hand.
|
|
34
34
|
|
|
@@ -13,7 +13,7 @@ Wrap the `EnterWorktree` entry path with name derivation so the user does not pi
|
|
|
13
13
|
- If neither command resolves, the session is not in a git repo and no `WorktreeCreate` hook is configured. Stop: `❌ Not a git repository. EnterWorktree needs git or a WorktreeCreate hook.`
|
|
14
14
|
- If the two match and `git rev-parse --show-superproject-working-tree` prints a path, the session is inside a submodule checkout. Stop: `❌ Inside a submodule of <path>. Run this from there instead.`
|
|
15
15
|
|
|
16
|
-
The submodule guard sits on the matching branch rather than ahead of the first one, and a measurement decided that. Inside a submodule at git 2.43.0 both reads return the same absorbed path under the superproject's `.git/modules/`, so the first guard does not fire and the session proceeds. Every derivation below then reads the submodule as the project: Step 1 resolves the main root to the submodule, the plan lookup reads a `.
|
|
16
|
+
The submodule guard sits on the matching branch rather than ahead of the first one, and a measurement decided that. Inside a submodule at git 2.43.0 both reads return the same absorbed path under the superproject's `.git/modules/`, so the first guard does not fire and the session proceeds. Every derivation below then reads the submodule as the project: Step 1 resolves the main root to the submodule, the plan lookup reads a `.canon/plans/` the project never wrote, and entry builds `.claude/worktrees/` inside a tree the superproject tracks as a commit. The superproject read is empty in a linked worktree of a submodule and in one of the superproject alike, which is why it separates the two states rather than qualifying the first guard.
|
|
17
17
|
|
|
18
18
|
## Step 1: resolve the main worktree root
|
|
19
19
|
|
|
@@ -38,8 +38,8 @@ The directory test separates the defect from a genuinely bare repository, which
|
|
|
38
38
|
Try each source in order. Stop at the first match.
|
|
39
39
|
|
|
40
40
|
0. **Caller-supplied.** The invocation carried an argument. Take it as the name and infer nothing further. Accept `<name>` or `<type>/<name>`, where a leading segment matching a type in `${CLAUDE_SKILL_DIR}/../../standards/branch.md` sets `<type>` and the rest is `<name>`. A bare `<name>` falls to the default type below.
|
|
41
|
-
1. **Plan matched to current branch.** Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. An empty result falls through to the next source here rather than becoming `latest`, since the slug is one candidate among several. If `<main-root>/.
|
|
42
|
-
2. **Single plan file.** List `<main-root>/.
|
|
41
|
+
1. **Plan matched to current branch.** Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. An empty result falls through to the next source here rather than becoming `latest`, since the slug is one candidate among several. If `<main-root>/.canon/plans/feature-<slug>.md` exists, use `<slug>`.
|
|
42
|
+
2. **Single plan file.** List `<main-root>/.canon/plans/feature-*.md`. If exactly one match, derive `<slug>` from the filename.
|
|
43
43
|
3. **Multiple plan files, no branch match.** Ask the user which plan. Show the candidate slugs as a numbered list. Do not pick.
|
|
44
44
|
4. **Current branch.** When no plan exists, use the `<slug>` from step 1 if it is not `main` or `master`.
|
|
45
45
|
4b. **Session context.** When on `main` or `master` with no matching plan, read the current conversation to infer a kebab slug from the topic being discussed. Propose it: `Infer: <slug>. Confirm or rename?` Do not enter the worktree until the user confirms or provides a corrected name.
|
|
@@ -48,12 +48,12 @@ The `pull_request` check the git-pr surface carries reads a pull request's own t
|
|
|
48
48
|
Map a bug to `--label bug` and a task to `--label enhancement`.
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
mkdir -p .
|
|
52
|
-
cat <<'BODY' > .
|
|
51
|
+
mkdir -p .canon/tmp/issue
|
|
52
|
+
cat <<'BODY' > .canon/tmp/issue/body.md
|
|
53
53
|
<body following the issue.md sections>
|
|
54
54
|
BODY
|
|
55
|
-
gh issue create --title "<type>: <subject>" --label <bug or enhancement> --body-file .
|
|
56
|
-
rm -rf .
|
|
55
|
+
gh issue create --title "<type>: <subject>" --label <bug or enhancement> --body-file .canon/tmp/issue/body.md
|
|
56
|
+
rm -rf .canon/tmp/issue
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
## After execution
|
|
@@ -111,8 +111,8 @@ Detect an open pull request on the current head and branch: edit it in place whe
|
|
|
111
111
|
Labels apply after that branch converges, against a pull request that already exists. `gh pr create --label` refuses a label the remote does not carry and opens no pull request at all, so a mistyped row costs the run rather than the label. One command after the fact also covers the create and the edit path together.
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
mkdir -p .
|
|
115
|
-
cat <<'BODY' > .
|
|
114
|
+
mkdir -p .canon/tmp/pr
|
|
115
|
+
cat <<'BODY' > .canon/tmp/pr/body.md
|
|
116
116
|
<body content following pr.md template exactly>
|
|
117
117
|
BODY
|
|
118
118
|
pr_labels="<comma-separated labels, empty when the map resolves to nothing>"
|
|
@@ -120,16 +120,16 @@ git push -u origin HEAD || exit 1
|
|
|
120
120
|
base_branch=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) || exit 1
|
|
121
121
|
pr_number=$(gh pr list --head "$(git branch --show-current)" --base "$base_branch" --state open --json number --jq '.[0].number // empty')
|
|
122
122
|
if [ -n "$pr_number" ]; then
|
|
123
|
-
pr_url=$(gh pr edit "$pr_number" --title "<title>" --body-file .
|
|
123
|
+
pr_url=$(gh pr edit "$pr_number" --title "<title>" --body-file .canon/tmp/pr/body.md) || exit 1
|
|
124
124
|
else
|
|
125
|
-
pr_url=$(gh pr create --title "<title>" --body-file .
|
|
125
|
+
pr_url=$(gh pr create --title "<title>" --body-file .canon/tmp/pr/body.md) || exit 1
|
|
126
126
|
pr_number=${pr_url##*/}
|
|
127
127
|
fi
|
|
128
128
|
if [ -n "$pr_labels" ]; then
|
|
129
129
|
gh pr edit "$pr_number" --add-label "$pr_labels" >/dev/null ||
|
|
130
130
|
printf 'Label apply failed. Create a missing label with: gh label create <name>\n' >&2
|
|
131
131
|
fi
|
|
132
|
-
rm -rf .
|
|
132
|
+
rm -rf .canon/tmp/pr
|
|
133
133
|
printf 'number=%s\nurl=%s\n' "$pr_number" "$pr_url"
|
|
134
134
|
```
|
|
135
135
|
|
|
@@ -137,7 +137,7 @@ printf 'number=%s\nurl=%s\n' "$pr_number" "$pr_url"
|
|
|
137
137
|
|
|
138
138
|
Write the `number` the final command printed onto the task the branch is closing. Do not resolve it again. A head branch that carried an earlier pull request now has two, and a second `gh pr view` would pick between them by a precedence rule nothing here states. Reading what created or edited the pull request needs no such rule.
|
|
139
139
|
|
|
140
|
-
The task is the one whose `Plan:` line names the plan this branch implemented. Name that plan by its file, which is `.
|
|
140
|
+
The task is the one whose `Plan:` line names the plan this branch implemented. Name that plan by its file, which is `.canon/plans/feature-<slug>.md` at the main worktree root with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. `claude-feature` writes the plan under the branch slug, so the two correspond on any branch that came through the plan-to-execute path. When the session already knows which plan it implemented, because a caller read it earlier in the chain, use that filename instead of re-deriving.
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
143
|
canon tasks pull-request <number> --plan feature-<slug> --json
|