@erclx/canon 5.78.0 → 5.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/app-drive/REQUIREMENT.md +12 -0
  4. package/claude/skills/app-drive/SKILL.md +44 -8
  5. package/claude/skills/app-drive/references/config.md +18 -8
  6. package/claude/skills/app-drive/references/drive-record.md +4 -0
  7. package/claude/skills/auto-ship/REQUIREMENT.md +1 -1
  8. package/claude/skills/auto-ship/SKILL.md +5 -4
  9. package/claude/skills/auto-ship/references/draft-mark.md +33 -15
  10. package/claude/skills/auto-ship/references/failure-recovery.md +4 -2
  11. package/claude/skills/canon-cli/SKILL.md +13 -10
  12. package/claude/skills/design-pick/SKILL.md +8 -0
  13. package/claude/skills/design-pick/references/design-config.md +9 -6
  14. package/claude/skills/design-references/REQUIREMENT.md +32 -0
  15. package/claude/skills/design-references/SKILL.md +120 -0
  16. package/claude/skills/design-references/references/films.md +90 -0
  17. package/claude/skills/design-references/references/sites.md +36 -0
  18. package/claude/skills/design-taste/SKILL.md +16 -4
  19. package/claude/skills/design-taste/references/adopted.md +5 -1
  20. package/claude/skills/design-taste/references/kinds.md +1 -0
  21. package/claude/skills/design-taste/references/preflight.md +27 -1
  22. package/claude/skills/design-taste/references/tells.md +2 -0
  23. package/claude/skills/git-followup/SKILL.md +1 -0
  24. package/claude/skills/git-pr/REQUIREMENT.md +2 -0
  25. package/claude/skills/git-pr/SKILL.md +2 -0
  26. package/claude/skills/git-pr/references/final-command.md +34 -2
  27. package/claude/skills/git-pr/references/pr.md +1 -1
  28. package/claude/skills/git-ship/REQUIREMENT.md +2 -2
  29. package/claude/skills/git-ship/SKILL.md +16 -11
  30. package/claude/skills/git-ship/references/ci-watch.md +28 -4
  31. package/claude/skills/markdown-craft/references/markdown.md +4 -4
  32. package/claude/skills/plan-feature/references/plan.md +2 -0
  33. package/claude/skills/review-address/SKILL.md +2 -1
  34. package/claude/skills/review-pr/references/key-changes.md +2 -1
  35. package/claude/skills/review-ui/references/driving.md +33 -1
  36. package/claude/skills/role-orchestrator/REQUIREMENT.md +1 -1
  37. package/claude/skills/role-orchestrator/SKILL.md +2 -2
  38. package/claude/skills/role-orchestrator/references/orchestrator-hand-launch.md +2 -0
  39. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
  40. package/claude/skills/role-orchestrator/references/orchestrator-limit-stops.md +47 -0
  41. package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +3 -1
  42. package/claude/skills/role-worker/SKILL.md +1 -1
  43. package/claude/skills/search-craft/REQUIREMENT.md +3 -3
  44. package/claude/skills/search-craft/SKILL.md +12 -1
  45. package/claude/skills/target-scaffold/REQUIREMENT.md +31 -0
  46. package/claude/skills/target-scaffold/SKILL.md +44 -0
  47. package/claude/skills/target-setup/SKILL.md +5 -1
  48. package/claude/skills/task-board/SKILL.md +1 -0
  49. package/claude/skills/task-board/references/tasks.md +1 -0
  50. package/claude/skills/ui-checklist/SKILL.md +5 -1
  51. package/claude/skills/ui-craft/SKILL.md +9 -9
  52. package/claude/skills/ui-craft/references/adopted.md +4 -2
  53. package/claude/skills/ui-craft/references/capture.md +8 -0
  54. package/claude/skills/ui-craft/references/controls.md +6 -0
  55. package/claude/skills/ui-craft/references/motion.md +6 -0
  56. package/claude/skills/ui-film/references/take-craft.md +2 -0
  57. package/docs/agents/output-shape.md +2 -1
  58. package/docs/target/projects.md +2 -2
  59. package/docs/workflow/ai-workflow.md +1 -1
  60. package/docs/workflow/parallel-features.md +2 -1
  61. package/docs/workflow/skill-map.md +7 -5
  62. package/docs/workflow/visual-design-workflow.md +4 -0
  63. package/governance/ledger/skills/design-references/SKILL.md +38 -0
  64. package/governance/ledger/skills/design-taste/SKILL.md +36 -30
  65. package/governance/ledger/skills/design-taste/kinds.md +1 -0
  66. package/governance/ledger/skills/design-taste/tells.md +22 -20
  67. package/governance/ledger/skills/search-craft/SKILL.md +6 -0
  68. package/governance/ledger/skills/ui-craft/capture.md +10 -0
  69. package/governance/ledger/skills/ui-craft/controls.md +8 -0
  70. package/governance/ledger/skills/ui-craft/motion.md +9 -1
  71. package/package.json +3 -3
  72. package/src/capture/render.ts +154 -2
  73. package/src/capture/sections.ts +257 -0
  74. package/src/claude/cases/misc.ts +5 -0
  75. package/src/claude/cases/setup.ts +7 -0
  76. package/src/commands/capture.ts +149 -4
  77. package/src/commands/pr.ts +138 -15
  78. package/src/commands/sessions.ts +88 -6
  79. package/src/commands/tasks.ts +41 -2
  80. package/src/commands/tooling.ts +72 -0
  81. package/src/git/files.ts +5 -2
  82. package/src/indexes/frontmatter.ts +27 -6
  83. package/src/indexes/render.ts +21 -3
  84. package/src/markdown/colons.ts +14 -4
  85. package/src/markdown/heading-case.ts +9 -2
  86. package/src/pr/bijection.ts +8 -0
  87. package/src/pr/evidence.ts +38 -9
  88. package/src/pr/health.ts +63 -15
  89. package/src/pr/links.ts +160 -0
  90. package/src/pr/local.ts +17 -4
  91. package/src/pr/paths.ts +20 -2
  92. package/src/sessions/stop.ts +145 -0
  93. package/src/sessions/transfer/bundle.ts +1 -1
  94. package/src/take/encode.ts +16 -42
  95. package/src/take/frame-clock.ts +46 -0
  96. package/src/take/perform.ts +29 -4
  97. package/src/take/screencast.ts +114 -11
  98. package/src/tasks/holders.ts +198 -0
  99. package/src/tasks/validate.ts +148 -0
  100. package/src/tooling/list.ts +3 -0
  101. package/src/tooling/scaffold.ts +193 -0
  102. package/tooling/cloudflare/manifest.toml +1 -1
  103. package/tooling/cloudflare/reference.md +8 -0
  104. /package/src/sessions/{transfer/transcript.ts → transcript.ts} +0 -0
@@ -5,7 +5,7 @@ description: What the git-ship CI watch does when the installed CLI predates the
5
5
 
6
6
  # CI watch fallback and refusals
7
7
 
8
- Applies to step 9 of `git-ship` once the watch wakes on anything but a `state` of `passing` or `failing` or a `conflicted: true` record, and to a target whose CLI carries no `canon pr checks`.
8
+ Applies to step 9 of `git-ship` once the watch wakes on anything but a `state` of `passing` or `failing` or a `conflicted: true` record, to a `failing` record whose failed runs were all cancelled, and to a target whose CLI carries no `canon pr checks`.
9
9
 
10
10
  ## The fallback watch
11
11
 
@@ -23,9 +23,33 @@ Empty output stops rather than waits, since `no checks reported on the '<branch>
23
23
 
24
24
  ## Refused and unsettled reads
25
25
 
26
- Neither of these is a pass, and neither emits `✅ Shipped`.
26
+ None of these is a pass, and none emits `✅ Shipped`. A `reason` and no `state` means the read was refused, and the watch sorts refusals into two kinds.
27
27
 
28
- - A `reason` and no `state` means the read was refused, such as `no-remote-branch` for a branch deleted on the remote. Stop and report that `reason`.
29
- - A watch that hit its timeout and printed no final record is CI unsettled after 60 minutes, so report it that way
28
+ | Kind | Reasons | What the watch did |
29
+ | --------- | ------------------------------------------------------------ | ---------------------------------------------------------------- |
30
+ | Permanent | `no-remote-branch`, `ambiguous-pull`, `no-branch` | Exited on the first one, since no amount of waiting changes them |
31
+ | Transient | Every other reason, such as `gh-failed` or `runs-unreadable` | Kept polling, since the next read can clear |
32
+
33
+ The set lives in the watch command rather than in the verb, so a refusal `canon pr checks` adds later defaults to transient and waits, which is the safe side.
34
+
35
+ - A permanent refusal ends the sequence. Stop and report that `reason`, such as `no-remote-branch` for a branch deleted on the remote.
36
+ - A transient refusal in the final record came from the read after the loop, since the loop never exits on one. Read `canon pr checks <number> --json` once more and route on that.
37
+ - A second refusal on that read stops the sequence with its `reason`
38
+ - A watch that hit its timeout and printed no final record is CI unsettled after 60 minutes, so report it that way. A transient refusal that never cleared ends here too.
30
39
 
31
40
  Do not auto-fix any of these. A stop report is one of the two exceptions to the no-text-between-steps rule.
41
+
42
+ ## A failing record with only cancelled runs
43
+
44
+ A run cancelled by a runner or a superseded workflow reads as `failing`, and a reviewer reads it as a real failure. This section decides whether a `failing` wake reruns or stops, and the rerun is the one exception to the no-auto-fix rule.
45
+
46
+ List the failed check runs on the record's `tip`, keeping the newest run per check name as `canon pr checks` does, and print each run id when every one of them was cancelled. The read goes through REST, since `gh pr checks` runs on GraphQL and a cloud session's proxy refuses it:
47
+
48
+ ```bash
49
+ gh api "repos/{owner}/{repo}/commits/<tip>/check-runs?per_page=100" --jq '[.check_runs | group_by(.name)[] | max_by(.id) | select(.conclusion | IN("failure", "timed_out", "cancelled", "action_required", "startup_failure"))] | if length > 0 and all(.conclusion == "cancelled") then [.[].details_url | capture("/runs/(?<id>[0-9]+)").id] | unique | .[] else empty end'
50
+ ```
51
+
52
+ - A non-zero exit means the read was refused, so stop and report the refusal rather than reading it as a real failure
53
+ - An empty print on a zero exit means at least one check really failed, so stop and report it with its URL
54
+ - Otherwise run `gh run rerun <id> --failed` once per printed id, then start the watch again from `### Watching CI`
55
+ - Rerun once per ship. A second `failing` wake on the same cancelled runs stops and reports them as cancelled, naming each URL.
@@ -41,7 +41,7 @@ Does not govern:
41
41
  ## Headings
42
42
 
43
43
  - H1 for document title, H2 for main sections, H3 for subsections, and no H4
44
- - Use sentence case for every heading. The audit reports a heading or a frontmatter `title` with a capitalized word after the first.
44
+ - Use sentence case for every heading. The audit reports a heading or `title` with a capital after the first word, past any task phase label.
45
45
  - Proper nouns and product names keep their casing, whatever the audit reports
46
46
  - Shape a record as H2 per section and H3 per item a reader looks up by name. Use a table only for a fixed-shape set.
47
47
 
@@ -133,7 +133,7 @@ A bullet's punctuation follows its sentence count, and a list opens unannounced.
133
133
  ## Punctuation
134
134
 
135
135
  - Do not use em dashes (`—`) or semicolons (`;`). Rewrite or restructure the sentence to avoid them. A colon or a comma standing where the dash was is the same sentence, so split it or rewrite it.
136
- - Do not use a colon to join two clauses in the middle of a sentence. A colon belongs after a label or at the end of a line introducing a list.
136
+ - Do not use a colon to join two clauses in a sentence. A colon follows a label of three words or fewer, or ends a line introducing a list.
137
137
  - The check misses a clause colon in a list of colon items, but it is wrong.
138
138
  - Do not use parenthetical asides in prose (`the config (which is optional) controls...`). Split into its own sentence or drop it. Parentheses in rule definitions for grouping examples are fine.
139
139
 
@@ -173,8 +173,8 @@ When frontmatter carries a `title` or `description` used for catalog display:
173
173
  ## Links and file references
174
174
 
175
175
  - Use descriptive anchor text for links. Avoid `click here` or `read more`.
176
- - Wrap file references in backticks by default. Never repeat the path verbatim as a link label.
177
- - Use a labeled markdown link (`[label](path)`) only on rendered-for-human surfaces (`README.md`, `docs/`) and in an index file, whose rows exist to be followed
176
+ - Wrap file references in backticks by default. Never repeat the path verbatim as a link label, bar a Key changes code span.
177
+ - Use a labeled markdown link (`[label](path)`) only on human-read surfaces (`README.md`, `docs/`), an index file, and a pull request body's Key changes
178
178
  - A relative link resolves against the filesystem over the corpus the ban scan reads, and one carrying a placeholder in angle brackets, such as `<slug>`, is an exempt illustration
179
179
 
180
180
  ## Examples
@@ -218,6 +218,8 @@ Every outcome reaches the review with its proof named.
218
218
 
219
219
  - Name, for each outcome, the test or the command that proves it, as one bullet leading with the outcome and ending on the command in backticks.
220
220
  - Write a command a later session can run as given, from the project root. A description of what would be checked leaves the executing session to invent the check.
221
+ - Write each command as one command, with no pipe, `&&`, `;`, or command substitution.
222
+ - A permission mode can refuse a compound form, and a substituted check no longer matches the plan, so reach a filter through a verb's own argument or flag, or name a test that holds it.
221
223
  - Name the visual check where no test reaches, and say it is visual, so a reader can tell a proof from a look.
222
224
 
223
225
  ### Risks
@@ -138,7 +138,8 @@ gh api -X POST 'repos/{owner}/{repo}/issues/<number>/comments' -F body=@.canon/t
138
138
 
139
139
  After the push, read Watching CI in `${CLAUDE_SKILL_DIR}/../git-ship/SKILL.md` without invoking that skill, start its background watch, end the turn on its line, and run the rest of this step and Step 8 on the wake. Reuse a watch already running on this PR, since it reads the new tip.
140
140
 
141
- - On the wake, stop on `conflicted` naming a rebase, on a `reason` naming it, and on a timeout reporting CI unsettled
141
+ - On the wake, stop on `conflicted` naming a rebase, and on a timeout reporting CI unsettled
142
+ - Route a `reason` through the refused reads in `${CLAUDE_SKILL_DIR}/../git-ship/references/ci-watch.md`, which re-read a transient one once and stop on a permanent one naming it
142
143
  - If any check fails, skip the edit and report the failing check so it can be fixed first
143
144
 
144
145
  When every finding is addressed and the state is `passing`, append the closing confirmation to the reply file Step 6 posted, so the thread carries one terminal state rather than a second comment. A rebase-only run appends the line `${CLAUDE_SKILL_DIR}/references/rebase-only.md` gives instead.
@@ -16,11 +16,12 @@ Branch on the record rather than on the exit code, which a shell function wrappi
16
16
  | Field | Reading |
17
17
  | ------------ | -------------------------------------------------------------------------------------- |
18
18
  | `unmet` | a `should-fix` finding under the `**PR body**` block the stale box takes, one per path |
19
+ | `mislinked` | a `should-fix` finding under the same block, one per link, since it opens another file |
19
20
  | `unnamed` | read for yourself and raise nothing off the count |
20
21
  | `unresolved` | reported nowhere, since it was judged in neither direction |
21
22
  | `incidental` | reported nowhere, since it owes no bullet |
22
23
 
23
- Each `unmet` finding quotes the `preview` bullet and the `head`.
24
+ Each `unmet` finding quotes the `preview` bullet and the `head`. The exit is 2 for a `mislinked` entry too, so a body exiting 2 with `unmet` empty is not clean.
24
25
 
25
26
  ### Before filing an unmet path
26
27
 
@@ -27,13 +27,45 @@ A box written to the drivable format reads:
27
27
 
28
28
  - **Route.** A path goes through `pw goto <rung><path>`, the rung before the access join. A control name, or "from the page the app opens on", is reached by clicking from the opened address.
29
29
  - **Width.** `pw resize <width> 900` before acting. A box naming no width is driven at 1440.
30
- - **Verb.** The action the driver performs: `click`, `fill`, `press`, `hover`, a scroll through `eval` of `scrollIntoView`, or a resize.
30
+ - **Verb.** The action the driver performs: `click`, `fill`, `press`, `hover`, a resize, or the real input `## A box that moves` sets for a wheel, a key, a tap, or a hover at a phone width.
31
+ - An `eval` of `scrollIntoView` brings a target into view before another verb acts, and never stands as the scroll a box checks.
31
32
  - **`(taste)`.** The result is a judgment of look or feel. Capture, never judge.
32
33
  - **`(local only)`.** The state needs something a hosted preview cannot reach. On a hosted address the box is not driven, naming the marker as the reason.
33
34
  - **`(needs fixture)`.** The drive fixture lacks the state. Drive the box if the state now answers, and otherwise it is not driven for a cause on the branch, as the verdicts below state.
34
35
 
35
36
  A box written before that format may carry no route, no width, and a verb such as "read" or "look at". Drive it anyway: take the opened address as the route and 1440 as the width, turn the verb into the nearest action, and name each guess in the verdict's evidence.
36
37
 
38
+ ## A box that moves
39
+
40
+ A scripted scroll lands where it is told, so it passes a snap or scroll-linked page that a wheel cannot move. A box naming a wheel, a key, a tap, or a hover on a phone is driven with that input, and its verdict rests on reads taken after each step.
41
+
42
+ ### Wheel at two paces
43
+
44
+ Start each pace from the top, resetting with `pw --raw eval "scrollTo(0, 0)"`, and read `scrollY`, or the `scrollTop` of the container the box names, after each step.
45
+
46
+ - **Spaced.** Six `pw mousewheel 0 100` calls, one notch a call, reading after each.
47
+ - **Burst.** One `pw run-code` sending the same six notches 50 ms apart, reading once it settles, as the block below sends them.
48
+ - The box fails when either pace leaves the surface short of the result it names, and the fail names the pace that stuck.
49
+ - The evidence quotes both paces' reads, such as `spaced 0, 0, 0, 0, 0, 0, burst 522`.
50
+
51
+ ```bash
52
+ pw run-code "async page => { for (let i = 0; i < 6; i++) { await page.mouse.wheel(0, 100); await page.waitForTimeout(50) } await page.waitForTimeout(800) }"
53
+ ```
54
+
55
+ ### Keys
56
+
57
+ A box naming a key sends it through `pw press <key>`, such as `ArrowDown` or `PageDown`, and reads the position after each press the way the wheel does.
58
+
59
+ ### Touch and hover
60
+
61
+ A box naming a tap, a swipe, or a hover at a phone width opens a second session, `canon browser -s=<project>-<number>-mobile open <address> --mobile`, since a resized desktop session keeps hover on and refuses a tap. Every call for such a box goes through that session, shortened here to `pw-mobile`, and never through `pw`.
62
+
63
+ - The mobile session opens at 360 wide, measured on `2026-11-08`, so a box naming another width runs `pw-mobile resize <width> 900` before its first read, as `## Reading a line` does for desktop
64
+ - Read `pw-mobile --raw eval "matchMedia('(hover: hover)').matches"` first and quote it, since a pass that never saw it false proves nothing about a hover query
65
+ - Tap through `pw-mobile run-code` with `page.touchscreen.tap(<x>, <y>)` at the target's center, taken from `getBoundingClientRect()`
66
+ - Take the box's frame through `pw-mobile screenshot`, and close the session with `pw-mobile close` once its boxes land
67
+ - A phone-width box naming no touch or hover stays a resize of the desktop session, with no second session
68
+
37
69
  ## Finding the element
38
70
 
39
71
  `open`, `goto`, and every action print a snapshot path under `.playwright-cli/`. Search that file for the target's role or text and take its ref, or click by a role locator such as `"getByRole('link', { name: 'Pricing' })"`. Never print a snapshot whole, since a full page costs tens of thousands of bytes the verdict never needs.
@@ -9,7 +9,7 @@ description: What the one warm control session owns, why it plans and dispatches
9
9
 
10
10
  Without this skill, the control session builds or merges, and the cross-feature picture goes with it. Plans go out unread against each other and a moved tree, the queue empties or fills with whatever is oldest, a parked row's blocker is never re-tested, and a second orchestrator writes a board neither can read.
11
11
 
12
- The channel fails at every hand-off. A finding or a reply stays in a thread nobody re-reads, a dispatch launches a branch other than the one the check cleared, a wave's cost grows unweighed, a report buries the human's decision, and a compaction loses the way back in.
12
+ The channel fails at every hand-off. A finding or a reply stays in a thread nobody re-reads, a dispatch launches a branch other than the one the check cleared, a wave's cost grows unweighed, a report buries the human's decision, a compaction loses the way back in, and a wave a usage limit stopped reads as finished.
13
13
 
14
14
  ## Must
15
15
 
@@ -42,7 +42,7 @@ The human asks for each side of a compaction, and this skill reads the runbook.
42
42
 
43
43
  - On a request to write the handoff, follow `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md`. It sends the generic half to `canon:session-map` and adds decisions taken under delegated authority.
44
44
  - That map follows `${CLAUDE_SKILL_DIR}/../session-map/references/session.md`. Write nothing to the handoff that the board, a task file, or a groundwork folder already carries.
45
- - Hand launch: `${CLAUDE_SKILL_DIR}/references/orchestrator-hand-launch.md`
45
+ - Hand launch: `${CLAUDE_SKILL_DIR}/references/orchestrator-hand-launch.md`. Limit stops, on request or on this session's first turn after: `${CLAUDE_SKILL_DIR}/references/orchestrator-limit-stops.md`.
46
46
  - A lesson about how to work goes to the owning task's Findings, as a bold-labeled line per `${CLAUDE_SKILL_DIR}/../task-board/references/tasks.md`
47
47
  - On a request to resume after a compaction, read `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md`, which reads that file back with the board and the groundwork behind the live work
48
48
 
@@ -56,7 +56,7 @@ A board that is not moving is a third such moment. On a request to re-test the p
56
56
 
57
57
  That routing lives in this body and this skill is user-invoked, so a session that has dropped the body routes nothing and the request lands as ordinary conversation. Approaching a compaction, when the handoff matters, is when a long session is likeliest to have dropped it.
58
58
 
59
- Re-invoke `/canon:role-orchestrator` first whenever the session has run long or the ask goes unanswered. The three runbooks sit at `references/orchestrator-handoff.md`, `references/orchestrator-resume.md`, and `references/orchestrator-parked.md`, so a person who knows their plugin root can follow one without this skill loaded.
59
+ Re-invoke `/canon:role-orchestrator` first whenever the session has run long or the ask goes unanswered. The runbooks sit under `references/`, so a person who knows their plugin root can follow one without this skill loaded.
60
60
 
61
61
  ## Output
62
62
 
@@ -24,6 +24,8 @@ The `Controller:` line replaces the background template's message clauses, which
24
24
 
25
25
  The first wave carries the worker. The wave after its pull request opens carries the reviewer alone.
26
26
 
27
+ Once the operator confirms a worker launched, run `canon tasks promote <stem>`, the same call a background launch makes. Nothing else moves a hand-launched row out of `## Up next`.
28
+
27
29
  ````markdown
28
30
  # Dispatch prompts
29
31
 
@@ -18,7 +18,7 @@ Read the threshold off `review-pr`, which states it once and governs the heading
18
18
 
19
19
  Read the pull request's own draft flag rather than the state a worker reports, and report what the read returned and when rather than the state alone. `canon pr head --help` states why a reported field can lag and say nothing about it.
20
20
 
21
- The flag settles the question only once the worker's chain has run its undo, and nothing marks that moment. A read taken between the pull request opening and that call sees a ready pull request about to become a draft, and once told an operator the opposite of what the worker had said.
21
+ A chain's create drafts at once, so its pull request reads draft from the first read. Before a lift or a person readies it, a ready read means the create missed and the fallback mark has yet to run or has failed, so report it as that rather than as a settled state.
22
22
 
23
23
  ## The rebase handback
24
24
 
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: Orchestrator limit stops runbook
3
+ description: Finding the sessions a usage limit stopped through the roster, and resuming each from its own record with one fixed message
4
+ ---
5
+
6
+ A usage limit stops every session on the account at once, and each one then reads `idle`, `shell`, or `waiting` as though it had finished. Run this pass on the operator's ask, or on this session's own first turn after a limit stop, once the limit has lifted.
7
+
8
+ ## Finding the rows
9
+
10
+ Read the roster and keep what this session can reach.
11
+
12
+ ```bash
13
+ canon sessions list --stopped --json
14
+ ```
15
+
16
+ - Keep this repository's rows and report the rest to the operator, since `session-relay` refuses a send across repositories
17
+ - Report `stopsUnread` when it is above zero, since those rows may be stopped and nothing will message them
18
+ - Report `foreignDead` when it is above zero, since this reader could not check those sessions at all
19
+ - Find each row's task with `grep -l <sessionId> .canon/tasks/*.md` at the main worktree root, since `canon tasks session` writes the id there
20
+ - Report a refusal of the flag as an older CLI behind the plugin, never as an empty list
21
+
22
+ ### What the watch cannot tell you
23
+
24
+ `orchestrator-watch.md` reads a worker gone idle as finished, so a limit-stopped worker reports that way there. Its `WORKER-STOPPED` line means a long `waiting` row and says nothing about a limit, so read the `stopped` field in full on every row this pass decides.
25
+
26
+ ## Sending
27
+
28
+ Each row takes the same message with its own record filled in.
29
+
30
+ ```plaintext
31
+ The usage limit lifted. Re-read <record> and continue. Re-run any command whose result you never read.
32
+ ```
33
+
34
+ The last sentence covers a session stopped between starting a command and reading what came back, such as a reviewer stopped mid-lift.
35
+
36
+ Fill `<record>` by the row's role, read off its name. A row with a task and a feature branch whose name states no role is a hand-launched worker.
37
+
38
+ | Row | `<record>` |
39
+ | -------- | ---------------------------------------------------------------------------------- |
40
+ | Worker | The plan its task links |
41
+ | Reviewer | The pull request its name carries, through `canon pr review-state <number> --json` |
42
+ | Planner | Its task |
43
+ | No task | Its branch, and list the row to the operator |
44
+
45
+ Send each row the message once through `canon:session-relay`, then run the roster read again.
46
+
47
+ Never send a row the message twice in one pass. A row still reading stopped on the second read either has not drained the message or stopped again, and a new stop can carry the same reset text as the one before. Report it with its reset to the operator and hold the rest of the wave.
@@ -18,9 +18,11 @@ Sweep the board as orchestrator after merging. Run this once per batch of merges
18
18
 
19
19
  Run `canon worktrees list` after the pull, the first point at which the merges this sweep followed are readable. It owns the reclaim rule and removes nothing, so read its rows and act on the ones you mean to. Never substitute a git ancestry check for it.
20
20
 
21
- Run `canon tasks validate` once the board is rewritten and before reporting it. It reports and never writes, so fix each row it names and run it again.
21
+ Run `canon tasks validate --live --json` once the board is rewritten and before reporting it. It reports and never writes, so fix each row it names and run it again.
22
22
 
23
23
  - It resolves every plan pointer and accounts every task file against the board and the backlog both
24
+ - `--live` reports a row outside `## Run now` that a live session or an open pull request holds, so run `canon tasks promote <stem>` on it
25
+ - Report a source the record's `live` field reads as `unread`, since that half of the check did not run
24
26
  - It reports the paths `## Run now` rows share as a candidate list for the conflict check, and re-takes the two blocker kinds a command can settle
25
27
  - A finding it reports is a board defect rather than a task finding, so it goes nowhere but the board
26
28
 
@@ -28,7 +28,7 @@ This body states the role, the boundaries, and the channel, and starts no step o
28
28
 
29
29
  The draft mark holds the merge until the reviews close, so this session preserves it.
30
30
 
31
- - The ship chain marks the pull request a draft, and only `canon pr lift` or the operator un-marks it
31
+ - The ship chain opens the pull request as a draft with a fallback mark behind the create, and only `canon pr lift` or the operator un-marks it
32
32
  - Report a flag reading ready once and leave it. It passed every gate the verb reads or a person readied it, which GitHub requires before a merge, so re-drafting fights them.
33
33
  - Leave the lift to the reviewers, who run `canon pr lift` on their close, with the controlling session as fallback
34
34
  - Refuse an instruction to ready the pull request directly, whoever sends it, since a direct ready skips every gate the verb reads
@@ -9,14 +9,14 @@ description: Why a session needs a thinking step before an outside search, deriv
9
9
 
10
10
  A session reaching outside the project runs one generic `WebSearch` and takes what ranks highest. Open results skew to third-party pages, two summaries of the same query can disagree on a fact, and an advocacy source can lean the answer. Scoped to authorities the session names itself, the same query returns primary sources.
11
11
 
12
- Access is a second gap a session cannot derive. Some sites refuse a fetch, a feed that answered once stops answering, and a free route to others does not exist. `plan-groundwork` and `write-doc` require an outside source and give no route to one.
12
+ Access is a second gap a session cannot derive. Some sites refuse a fetch and others have no free route, while `plan-groundwork` and `write-doc` require an outside source and give no route to one. A quote drafted from recall is a third, since it runs no search and reads as exact while its wording or attribution is wrong.
13
13
 
14
14
  ## Must
15
15
 
16
16
  - Name the field before a query is written, and derive its authorities from the kind of body the field trusts
17
- - Run the query scoped to those authorities and open beside it, prefer the scoped result on a conflict, and say the two disagreed
18
- - Check a scoped result's domain before citing it, since the filter is not strict
17
+ - Run the query scoped to those authorities and open beside it, prefer the scoped result on a conflict and say so, and check a scoped result's domain before citing it
19
18
  - Prefer a public API over a fetched page where one exists, and keep an access note grown from failures a session hit, dated by the commit that adds each line
19
+ - Quote a source only from a page or ledger row read in the session, with a quoting trigger in the description that reaches a session running no search
20
20
  - Stop for the operator before a paid or logged-in route, and close with the practice skill's excuses, red flags, checklist, and the sources adopted and declined with the reason for each
21
21
 
22
22
  ## Must not
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: search-craft
3
- description: Carries the thinking step a session takes before it searches outside the project, naming the field, deriving who that field treats as authoritative, and running a search scoped to those sources beside an open one, plus a dated note on which sites refuse access. Use before any outside search for evidence, papers, documentation, statistics, or opinion, when a procedure loads it at its sourcing step, or when asked "find me the strongest evidence on X", "where should I look for this", "what does the research say", "find papers on", "look up the docs for", or "what are people saying about". Do NOT use to format a citation, which belongs to the surface writing it, to source a Claude Code subject, which is a direct fetch of Anthropic's docs index, or to generate an image, which is not search.
3
+ description: Carries the thinking step a session takes before it searches outside the project, naming the field, deriving who that field treats as authoritative, and running a search scoped to those sources beside an open one, plus a dated note on which sites refuse access and the rule that a quote comes from a page read rather than recall. Use before any outside search for evidence, papers, documentation, statistics, or opinion, before quoting a source on any surface, when a procedure loads it at its sourcing step, or when asked "find me the strongest evidence on X", "where should I look for this", "what does the research say", "find papers on", "look up the docs for", or "what are people saying about". Do NOT use to format a citation, which belongs to the surface writing it, to source a Claude Code subject, which is a direct fetch of Anthropic's docs index, or to generate an image, which is not search.
4
4
  metadata:
5
5
  family: build
6
6
  ---
@@ -42,6 +42,10 @@ This skill carries the step before the search. Work out where the field's author
42
42
  - Prefer a source's public API over a fetched and summarized HTML page where one exists. An API returns the dates, authors, and identifiers a citation needs, which a summary can drop.
43
43
  - Reach the API with a plain request when it needs no key, rather than writing a wrapper for one search.
44
44
 
45
+ ## Quote what was read
46
+
47
+ - Quote a source only from a page or a ledger row read in this session, never from recall, since a remembered quote reads as exact while its wording or attribution has drifted.
48
+
45
49
  ## Access note
46
50
 
47
51
  Each line is a claim measured once, and the commit that adds it carries the date. Sites change their blocking without notice, so re-check a line before relying on it. Add a line only for a failure a session actually hit.
@@ -65,6 +69,7 @@ Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidan
65
69
  - You are about to write a query and have not named the field.
66
70
  - Every source you are about to cite came from one open search.
67
71
  - You named an authority because it is a site you remember, not because it is the kind of body the field trusts.
72
+ - You are about to quote a source you have not opened in this session.
68
73
 
69
74
  ### Results and access
70
75
 
@@ -82,6 +87,12 @@ These flags fire after the search has run.
82
87
  - Every cited source's domain was checked, and a fact the summaries disagreed on was confirmed on the page itself.
83
88
  - No paid, logged-in, or scraped route was taken without the operator's answer.
84
89
 
90
+ ### Quotes
91
+
92
+ A quote carries its own check, since it can reach a surface with no search run.
93
+
94
+ - Every quote was copied from a page or a ledger row read in this session.
95
+
85
96
  ## What this delegates
86
97
 
87
98
  - The form a citation takes: the surface writing it, such as the standard the procedure writes to
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: target-scaffold
3
+ description: Why an empty folder gets its own skill rather than a branch inside target-setup
4
+ ---
5
+
6
+ # Scaffold requirement
7
+
8
+ ## Gap
9
+
10
+ A developer in an empty folder has no skill to run. `target-setup` detects a stack from files that are not there yet, so it falls back to `base` and installs tooling onto nothing.
11
+
12
+ The tested non-interactive starters sit in the stack manifests. A session left to improvise picks a scaffolder from memory, answers its prompts wrong, or writes into the wrong folder.
13
+
14
+ ## Must
15
+
16
+ - Offer only the stacks the catalog reports as carrying a starter, read at runtime rather than hardcoded
17
+ - Start the project through the CLI verb alone, so the starter that runs is the one `canon tooling verify` tests
18
+ - Write nothing into a folder that already holds files, and route that folder to `target-setup`
19
+ - Leave the project name to the person, refusing rather than renaming when a package manager would reject it
20
+ - Hand the started project to `target-setup` with nothing resolved ahead of its own detection
21
+
22
+ ## Must not
23
+
24
+ - Run a scaffolder command directly, which drifts from the manifest the verb reads
25
+ - Pick a stack for a caller who named none
26
+ - Depend on the author typing its name, since `target-setup` routes an empty folder here
27
+
28
+ ## Out of scope
29
+
30
+ - Installing tooling, governance, and indexes on the started project, which `target-setup` owns
31
+ - Shipping a starter template of its own, since the toolkit ships no application code
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: target-scaffold
3
+ description: Starts a new project on the toolkit from an empty folder. Asks for the stack and the project name, runs the stack's starter through `canon tooling scaffold`, then hands off to `target-setup`. Use when asked to "start a new project", "scaffold a project here", "start a new astro project here", "create a vite app from scratch", or "set up this empty folder". Assumes the `canon` CLI is on PATH. Do NOT use on a folder that already holds files, which is `target-setup`, or to change the stack of an existing project.
4
+ metadata:
5
+ family: setup
6
+ ---
7
+
8
+ # Scaffold
9
+
10
+ Starts a project in an empty folder and hands it to `target-setup`. The CLI owns the starter command, the empty-folder test, and the name check, while this skill picks the arguments, runs the verb, and routes on its record. It runs no scaffolder itself. Nor does it name a stack.
11
+
12
+ ## Steps
13
+
14
+ 1. Resolve the target. The current folder is the default, and its folder name becomes the project name. When the request names a different project name, the target is a new subfolder of that name.
15
+ 2. Run `ls -A` on the target, where a subfolder that does not exist yet counts as empty. When it lists anything but `.git`, stop and route to `/canon:target-setup`, since the folder is already a project.
16
+ 3. Run `canon tooling list --json` and offer only the stacks whose `scaffold` is `true`. A stack without a starter is a layer synced onto a project.
17
+ 4. Resolve the stack. Take one the request named, or ask through the structured question surface with one option per offered stack.
18
+ - With no person present and no stack named, stop and list the offered names rather than picking one
19
+ 5. Preview the stack, the target, the project name, and the command, then run it:
20
+
21
+ ```bash
22
+ canon tooling scaffold <stack> <target> --json
23
+ ```
24
+
25
+ ## Route on the record
26
+
27
+ Branch on the record's `ok` and `reason` rather than on the exit, which a shell function wrapping `canon` can flatten to zero.
28
+
29
+ | Record | Route |
30
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
31
+ | `ok: true` | Report the `files` it moved, then hand off below |
32
+ | `bad-name` | Offer the record's `suggested` name as a subfolder target, and rerun only once the person accepts or renames |
33
+ | `not-empty` | Route to `/canon:target-setup`, since something landed in the folder after step 2 |
34
+ | `scaffold-failed` or `no-output` | Report the `message` and the `scratch` folder the verb kept, and stop. Nothing reached the target. |
35
+ | `no-scaffold`, `no-manifest`, or other | Report the `message` and stop, since the catalog read in step 3 and the verb disagree |
36
+
37
+ Never rename the folder or retry with a name the person did not choose, since the folder name becomes the package name.
38
+
39
+ ## Hand off
40
+
41
+ Invoke `canon:target-setup` with the target as the working folder. Its detect phase now finds the starter's files and resolves the stack from them, so pass it nothing this skill resolved.
42
+
43
+ - The hand-off is the last step. Install, governance, verify, and indexes all belong to `target-setup`.
44
+ - Report the stack, the target, the files the verb moved, and that setup ran, in that order.
@@ -55,7 +55,11 @@ else. Do not pause for a separate confirmation beyond the extras question.
55
55
 
56
56
  ## Declined states
57
57
 
58
- Three states reach this skill that the chain does not serve. Name the destination for each, so the refusal routes rather than ends.
58
+ Four states reach this skill that the chain does not serve. Name the destination for each, so the refusal routes rather than ends.
59
+
60
+ ### An empty folder
61
+
62
+ Stop before `detect` when the target holds nothing but `.git`, and hand off to `target-scaffold`. Detection reads a stack from files a project carries, so an empty folder resolves to `base` and installs tooling onto no project. That skill starts the project and hands it back here.
59
63
 
60
64
  ### An existing project
61
65
 
@@ -65,6 +65,7 @@ Run `canon tasks next-label --claim --json` and take its `label` field. The verb
65
65
 
66
66
  Write `.canon/tasks/vXX.Y-<slug>.md` under the claimed label, reading the file first if a session ever stubbed it, following the format in `${CLAUDE_SKILL_DIR}/references/tasks.md`. Write it immediately, since Claude Code's tool permission dialog is the confirmation gate.
67
67
 
68
+ - Double any apostrophe in the title before writing it inside the single-quoted `title:` value, since a lone one fails the YAML parse
68
69
  - Include a link line only when the file or folder it names exists, since a link to an unwritten plan is the broken pointer the archive rules prevent
69
70
  - Write `Plan:`, `Groundwork:`, and `Intake:` as markdown links relative to `.canon/tasks/`, as in `Plan: [feature-<slug>](../plans/feature-<slug>.md)`
70
71
  - Leave `Issue:` a bare `#NNN`. The older bare-path form still parses, but it leaves the board in two shapes for every later reader.
@@ -76,6 +76,7 @@ description: Record what a target installed and report the delta against the too
76
76
  ```
77
77
 
78
78
  - `title`: the phase label and the task title, matching the H1. Quote it, since a leading `vX.Y:` reads as a key to a YAML parser.
79
+ - Double any apostrophe inside the single quotes, as in `'vX.Y: Trim the Board''s ad page'`. A lone one fails the parse, which `canon tasks validate` reports as `frontmatter-invalid`.
79
80
  - `description`: what the task achieves, in one line. A session reads this in the index to decide whether to open the file.
80
81
 
81
82
  ## File format
@@ -33,12 +33,16 @@ The evidence comment already heads the list with `## What to look at`, so the fi
33
33
  - [ ] <route>[, <width>]: <verb> <target> → <expected visual result>
34
34
  ```
35
35
 
36
+ ### The parts of a box
37
+
36
38
  Write each box so a session driving the running app can run it without guessing, with one rule for each part:
37
39
 
38
40
  - **Route.** A path or the control that reaches it. A box naming none is driven from the address the driver opens.
39
41
  - Write "from the page the app opens on" for a state reached by a sequence.
40
42
  - **Width.** Only when the change can differ by width, such as layout, spacing, or anything responsive. Copy, color, or a state rendering the same everywhere leaves it off.
41
- - **Verb.** An action a driver performs, such as "scroll to", "click", "resize to", or "tab to". Never "read" or "look at", which name no action.
43
+ - **Verb.** An action a driver performs, such as "scroll to", "click", "resize to", "tab to", "wheel", "press", or "tap". Never "read" or "look at", which name no action.
44
+ - A changed surface that scrolls, snaps, or tracks the scroll takes "wheel" or "press" with the key, never "scroll to", which a scripted scroll passes on a page the wheel cannot move.
45
+ - A touch or hover behavior takes "tap" or "hover" at a phone width. A change that moves nothing takes no wheel box.
42
46
  - **Taste.** End the line with `(taste)` when the result is a judgment of look or feel. A driver reports such a box as needing a person's eyes rather than passing it.
43
47
  - **Setup.** State inline the setup the page does not open in and the fixture state it needs. End with `(local only)` when a hosted preview cannot reach it, such as a stopped service.
44
48
  - **Fixture.** End with `(needs fixture)` when the drive fixture lacks the state. The builder adds it, or with no `canon/config/app-drive.toml` writes the setup inline and drops the marker.
@@ -15,15 +15,15 @@ Load this before building rather than after, since a missing state or a trapped
15
15
 
16
16
  Read every reference on the always row for any rendered change, then each row the change matches.
17
17
 
18
- | The change | Read |
19
- | ------------------------------------------------------------------ | ------------------------------------- |
20
- | Any rendered change | `a11y.md`, `keyboard.md`, `states.md` |
21
- | A click, press, drag, gesture, or popover dismissal | `pointer.md` |
22
- | A form, a field, validation, or a sign-in step | `forms.md` |
23
- | An animation, transition, autoplay, or carousel | `motion.md` |
24
- | A destructive action, an edit cancel, or a hover or disabled state | `controls.md` |
25
- | A rendered string, heading, label, or link | `copy.md` |
26
- | A rendered surface has changed and is about to be handed over | `capture.md` |
18
+ | The change | Read |
19
+ | ---------------------------------------------------------------------------------------------------- | ------------------------------------- |
20
+ | Any rendered change | `a11y.md`, `keyboard.md`, `states.md` |
21
+ | A click, press, drag, gesture, or popover dismissal | `pointer.md` |
22
+ | A form, a field, validation, or a sign-in step | `forms.md` |
23
+ | An animation, transition, autoplay, carousel, or scroll-driven or dragged motion | `motion.md` |
24
+ | A destructive action, an edit cancel, a hover or disabled state, or chrome that looks like a control | `controls.md` |
25
+ | A rendered string, heading, label, or link | `copy.md` |
26
+ | A rendered surface has changed and is about to be handed over, or a change scrolls or snaps | `capture.md` |
27
27
 
28
28
  Each name sits under `${CLAUDE_SKILL_DIR}/references/`. A row's reference is read whole, since its sections name the cases a change reaches without saying so.
29
29
 
@@ -12,11 +12,13 @@ Every bullet in a reference has its own source row in a ledger outside the plugi
12
12
  Each field below names the source its references cite, and a house choice covers a threshold or a scope no source states.
13
13
 
14
14
  - **Web accessibility.** The W3C's [WCAG 2.2](https://www.w3.org/TR/WCAG22/) and the [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/) back the accessibility, keyboard, pointer, and motion references.
15
- - **CSS behavior.** [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) and the CSS specifications back the focus ring, `color-scheme`, and overflow bullets.
15
+ - **CSS behavior.** [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) and the CSS specifications back the focus ring, `color-scheme`, overflow, cursor, and hover query bullets.
16
16
  - **Native targets.** Apple's and Android's platform guidelines back the native touch target figures in `pointer.md`.
17
17
  - **Forms and copy.** The [GOV.UK Design System](https://design-system.service.gov.uk/) and its style guide back `forms.md` and the copy and casing sections of `copy.md`.
18
+ - **Interaction design.** [Ben Shneiderman](https://www.cs.umd.edu/~ben/)'s direct manipulation paper and the motion system of [Material Components](https://github.com/material-components/material-components-android) back the reader-paced section of `motion.md`.
19
+ - **Web performance.** Google's [web.dev](https://web.dev/) guidance on layout shift backs the held-size bullet in `motion.md`.
18
20
  - **Usability research.** The [Nielsen Norman Group](https://www.nngroup.com/articles/) backs most of `states.md`, part of `controls.md`, and the link sections of `copy.md`.
19
- - **Capture.** `capture.md` is a house procedure, with its reflow width taken from the WCAG reflow criterion `a11y.md` cites.
21
+ - **Capture.** `capture.md` is a house procedure, with its reflow width taken from the WCAG reflow criterion `a11y.md` cites. Its keyboard pass for a change that moves rests on WCAG 2.1.1 Keyboard.
20
22
 
21
23
  ## Where the rows sit
22
24
 
@@ -35,6 +35,14 @@ Only a change with no visible result in any reachable state is exempt, such as a
35
35
  - Capture a state case at one width, driving states a first render cannot reach, such as an open menu.
36
36
  - Add a surface's case with the surface, and remove it with the surface.
37
37
 
38
+ ## What a moving change owes
39
+
40
+ - Verify a change that scrolls, snaps, or tracks the scroll with the input a person uses, at each width it is captured at. A scripted `scrollIntoView` only brings a target into view.
41
+ - Send the wheel in 100 px notches at two paces, spaced and in a burst, since a snap or scroll-linked page can stall at one pace and move at the other.
42
+ - Move the same surface with the keyboard, through the arrow keys and Page Down, since a surface the wheel moves and the keys cannot fails keyboard operation.
43
+ - Sample the motion at fixed steps across its range, reading the position after each notch or key, never only where it ends.
44
+ - Drive a touch or hover behavior in a touch session, since a resized desktop window keeps hover on and cannot fail a hover query.
45
+
38
46
  ## Sharing a capture
39
47
 
40
48
  - Write a capture into a folder named `evidence`, which the pull request comment collects from.
@@ -12,7 +12,13 @@
12
12
  - Say why a control is disabled, in text beside it or a tooltip, and keep it focusable through `aria-disabled` when the reason matters.
13
13
  - Declare `color-scheme` on `:root` to match each theme, so scrollbars and form controls follow the theme instead of staying light.
14
14
 
15
+ ## Signifiers
16
+
17
+ - Give nothing a control's look, such as a button fill or a tab underline, unless it acts, since the look promises a response.
18
+ - Keep the default cursor on decorative chrome, such as a mock tab bar, a status pill, or an address bar.
19
+
15
20
  ## Hover and focus effects
16
21
 
17
22
  - Keep content shown on hover or focus dismissible without moving the pointer, hoverable, and visible until the trigger leaves or the person dismisses it (WCAG 1.4.13).
18
23
  - Change no context, such as navigating, submitting, or moving focus, when a control gains focus or changes value, unless the person was told first (WCAG 3.2.1, 3.2.2).
24
+ - Put hover styles behind `@media (hover: hover)`, since a touch screen keeps the last tapped element in hover.
@@ -6,6 +6,12 @@
6
6
  - Halt an auto-advancing carousel or ticker while it holds keyboard focus or pointer hover.
7
7
  - Never flash content more than three times in any one second (WCAG 2.3.1).
8
8
 
9
+ ## Motion the reader drives
10
+
11
+ - When the reader sets the pace, as with a scroll, a drag, or a swipe, move by the input rather than a timer, so stopping halfway leaves the motion halfway and reversing the input reverses it.
12
+ - Never blend two texts mid-transition. Swap them at a threshold so every moment shows one readable state, with no blank frame between them.
13
+ - Keep a component's outer size fixed while it animates, or swaps instantly under reduced motion, letting its contents give and take room inside it, so the page around it never moves.
14
+
9
15
  ## Reduced motion
10
16
 
11
17
  - Honor `prefers-reduced-motion: reduce` for every animation and transition that conveys no state. Remove it or replace it with an instant change.
@@ -83,6 +83,8 @@ Two rules hold once a beat is filmed.
83
83
  - Use a `move` to a point only for a target the page reveals on hover, and follow it with the click
84
84
  - Read each target off the served page before writing it. The verb refuses `target-missing` rather than filming a guess, and a refusal costs a reload.
85
85
 
86
+ Both forms reach inside an open shadow root, such as a web component banner. A document-tree match wins over one inside a root, unless a `text=` match contains the root's match, where the inner one wins. A selector cannot span a shadow boundary, and a target inside a closed root or a frame refuses as missing.
87
+
86
88
  ## The pointer
87
89
 
88
90
  - Draw no pointer in the page. The edit draws one from the log at a constant size, and two pointers on one frame leave the viewer guessing which one acted.
@@ -46,7 +46,7 @@ Discover names at runtime rather than hardcoding them.
46
46
 
47
47
  | Command | Returns |
48
48
  | --------------------------------- | ---------------------------------------------------------------- |
49
- | `canon tooling list --json` | Stacks, extends chain, dep and script counts |
49
+ | `canon tooling list --json` | Stacks, extends chain, dep and script counts, scaffold flag |
50
50
  | `canon gov list --json` | Governance stacks, rule sets, evidence, and unreferenced rules |
51
51
  | `canon gov detect --json` | Opt-in rules a target's dependencies and paths propose |
52
52
  | `canon claude seeds list --json` | Seed doc sources with content |
@@ -75,6 +75,7 @@ canon tooling sync astro /path/to/project --write
75
75
  canon tooling inject base /path/to/project --configs --seeds
76
76
  canon tooling prune-gitignore base /path/to/project
77
77
  canon tooling verify vite-react
78
+ canon tooling scaffold astro /path/to/empty-folder --json
78
79
  canon audits run --json
79
80
  canon secrets scan --json
80
81
  canon deps audit --json