@erclx/canon 5.69.0 → 5.71.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/CHANGELOG.md +25 -0
- package/README.md +33 -159
- package/assets/brand/mark.svg +17 -9
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/app-drive/SKILL.md +3 -2
- package/claude/skills/app-drive/references/drive-record.md +52 -10
- package/claude/skills/app-drive/references/isolate.md +1 -1
- package/claude/skills/design-pick/SKILL.md +1 -0
- package/claude/skills/git-pr/references/task-number.md +13 -0
- package/claude/skills/markdown-craft/references/markdown.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +6 -20
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +10 -0
- package/claude/skills/role-orchestrator/references/orchestrator-talk-launch.md +30 -0
- package/claude/skills/task-board/references/tasks-record-lines.md +40 -0
- package/claude/skills/task-board/references/tasks.md +4 -8
- package/claude/skills/ui-craft/references/copy.md +4 -1
- package/claude/skills/ui-film/REQUIREMENT.md +4 -2
- package/claude/skills/ui-film/SKILL.md +24 -11
- package/claude/skills/ui-film/references/compose-craft.md +81 -0
- package/claude/skills/ui-film/references/config.md +6 -1
- package/claude/skills/ui-film/references/handoff.md +13 -3
- package/claude/skills/ui-film/references/take-craft.md +27 -1
- package/docs/index.md +1 -0
- package/docs/migrations/by-hand.md +107 -0
- package/docs/migrations/by-verb.md +118 -0
- package/docs/migrations/index.md +14 -0
- package/docs/target/index.md +1 -2
- package/docs/target/projects.md +2 -2
- package/docs/target/sync.md +22 -2
- package/docs/workflow/ai-workflow.md +1 -1
- package/governance/ledger/skills/ui-craft/copy.md +8 -4
- package/package.json +3 -1
- package/scripts/core/design-sync.ts +204 -0
- package/scripts/core/regen-web-favicon.ts +27 -12
- package/scripts/core/regen-web-previews.ts +8 -1
- package/scripts/core/render-film.ts +179 -0
- package/src/capture/frame-values.ts +12 -12
- package/src/commands/markdown.ts +6 -1
- package/src/commands/records.ts +3 -2
- package/src/commands/sandbox.ts +9 -2
- package/src/commands/take.ts +159 -11
- package/src/commands/tasks.ts +133 -0
- package/src/design/favicon.ts +85 -13
- package/src/design/reference.ts +98 -0
- package/src/design/render.ts +16 -14
- package/src/design/tokens.ts +4 -3
- package/src/gate/stages.ts +6 -0
- package/src/init/steps.ts +2 -2
- package/src/markdown/colons.ts +102 -16
- package/src/migrate/status.ts +3 -3
- package/src/records/validate.ts +14 -2
- package/src/sandbox/expect.ts +32 -0
- package/src/sandbox/headless/run.ts +6 -3
- package/src/take/camera.ts +99 -10
- package/src/take/film.ts +35 -2
- package/src/take/fixtures/input.html +138 -0
- package/src/take/keys.ts +193 -0
- package/src/take/log.ts +94 -1
- package/src/take/perform.ts +165 -10
- package/src/take/plan.ts +101 -6
- package/src/take/screencast.ts +28 -3
- package/src/take/stepper.ts +122 -18
- package/src/tasks/archive.ts +54 -1
- package/src/tasks/record.ts +118 -0
- package/src/tasks/validate.ts +37 -0
- package/docs/target/migrations.md +0 -205
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.71.0](https://github.com/erclx/canon/compare/v5.70.0...v5.71.0) (2026-10-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **markdown:** read colon lists as labels ([#2797](https://github.com/erclx/canon/issues/2797)) ([f733a5f](https://github.com/erclx/canon/commit/f733a5f8d74e63cf5e257557a4d227b3478ca04a))
|
|
9
|
+
* **tasks:** name the sessions behind a task on a Sessions line ([#2799](https://github.com/erclx/canon/issues/2799)) ([acf80c4](https://github.com/erclx/canon/commit/acf80c4ce9d2c1adbc3e1ea2dfde433a08d46b4e))
|
|
10
|
+
|
|
11
|
+
## [5.70.0](https://github.com/erclx/canon/compare/v5.69.0...v5.70.0) (2026-10-27)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **app-drive:** give each drive log finding a heading and fields ([#2791](https://github.com/erclx/canon/issues/2791)) ([f853659](https://github.com/erclx/canon/commit/f853659f5d7793c1af820fcbf55d56fd2f71b981))
|
|
17
|
+
* **brand:** replace the ledger with the ink c and vermilion pip mark ([#2775](https://github.com/erclx/canon/issues/2775)) ([2b7d71e](https://github.com/erclx/canon/commit/2b7d71e329dbaa2ca828dba749ec8c236dc6676b))
|
|
18
|
+
* **design:** land board frames in canon/design through a design sync ([#2792](https://github.com/erclx/canon/issues/2792)) ([b635a33](https://github.com/erclx/canon/commit/b635a33f722a51606b51e1d8539e322233206e39))
|
|
19
|
+
* **design:** land the brand mark sheet as the foundations reference ([#2796](https://github.com/erclx/canon/issues/2796)) ([116caec](https://github.com/erclx/canon/commit/116caec1b233ae58dec8060ada8020381c9722b8))
|
|
20
|
+
* **readme:** open on the mark, claim, launch loop, and install ([#2783](https://github.com/erclx/canon/issues/2783)) ([c86fa26](https://github.com/erclx/canon/commit/c86fa264421cada9ad58c90dd46cf39224330c0f))
|
|
21
|
+
* **sandbox:** read the runner cap from the envelope subtype ([#2794](https://github.com/erclx/canon/issues/2794)) ([4fc750e](https://github.com/erclx/canon/commit/4fc750edc03c302fbfd098c4bf237d745d3124d1))
|
|
22
|
+
* **take:** film drags, key presses, double clicks, and modified clicks ([#2795](https://github.com/erclx/canon/issues/2795)) ([52926e3](https://github.com/erclx/canon/commit/52926e3714a07e13d2efb535c2b8771ea204548d))
|
|
23
|
+
* **take:** name the fallback on a refused beat and add camera controls ([#2789](https://github.com/erclx/canon/issues/2789)) ([6ce5be6](https://github.com/erclx/canon/commit/6ce5be646601274c4b7203527bd6b6cd5e005be8))
|
|
24
|
+
* **ui-craft:** bar the trailing period on every short rendered string ([#2788](https://github.com/erclx/canon/issues/2788)) ([1fc3b4b](https://github.com/erclx/canon/commit/1fc3b4bdd1921a39c21bee225905a138d7422cc5))
|
|
25
|
+
* **ui-film:** add footage guidance for composing takes ([#2793](https://github.com/erclx/canon/issues/2793)) ([dc98a98](https://github.com/erclx/canon/commit/dc98a981bae97921d796e1412a36fb89844e3bba))
|
|
26
|
+
* **web:** rebuild the landing page around one change, plan to merge ([#2787](https://github.com/erclx/canon/issues/2787)) ([c6fdf16](https://github.com/erclx/canon/commit/c6fdf160f7e5140a8066f9370a5703d6d021c2e1))
|
|
27
|
+
|
|
3
28
|
## [5.69.0](https://github.com/erclx/canon/compare/v5.68.0...v5.69.0) (2026-10-26)
|
|
4
29
|
|
|
5
30
|
|
package/README.md
CHANGED
|
@@ -1,193 +1,67 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
3
|
<picture>
|
|
4
|
-
<source media="(prefers-color-scheme: dark)" srcset="assets/brand/mark-
|
|
5
|
-
<img src="assets/brand/mark-
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/brand/mark-color.svg">
|
|
5
|
+
<img src="assets/brand/mark-color-light.svg" alt="canon" width="56" height="56">
|
|
6
6
|
</picture>
|
|
7
7
|
|
|
8
8
|
# canon
|
|
9
9
|
|
|
10
|
+
A CLI and Claude Code plugin that runs your agent's work from plan to merge, holds it to established engineering practice, and installs the same setup in every repo.
|
|
11
|
+
|
|
10
12
|
[](https://www.npmjs.com/package/@erclx/canon)
|
|
11
13
|
[](https://github.com/erclx/canon/actions/workflows/verify.yml)
|
|
12
14
|
[](LICENSE)
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
<picture>
|
|
17
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/loops/launch.gif">
|
|
18
|
+
<img src="assets/loops/launch-light.gif" alt="One change running through canon, from the groundwork that measured it through its plan, dispatch, build, and review to the merge" width="960">
|
|
19
|
+
</picture>
|
|
16
20
|
|
|
17
21
|
</div>
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
## Why
|
|
22
|
-
|
|
23
|
-
If an agent writes code for you in more than one repository, this is for you. canon runs that work from plan to merge. A planner writes the plan, a worker builds it on its own branch, and a separate session reviews the pull request.
|
|
24
|
-
|
|
25
|
-
It holds the work to a practice, with rules that load when a matching path is edited and checks that fail when a rule is ignored. Both run on one setup, installed the same way in every repository you keep.
|
|
26
|
-
|
|
27
|
-
### The shared setup
|
|
28
|
-
|
|
29
|
-
That shared setup is what the rest of this page describes, and it drifts without a source. Every AI coding setup accumulates the same assets. Prompts to reuse, rules agents should follow, slash commands, skills, seed docs, sync scripts. Once you have enough projects, your copies drift and your agents stop getting consistent signals.
|
|
30
|
-
|
|
31
|
-
Three design choices shape the toolkit.
|
|
32
|
-
|
|
33
|
-
- Agent-first: every command has a non-interactive path and a JSON catalog. If a Claude Code skill or any other agent cannot drive the CLI without prompts, the design is wrong.
|
|
34
|
-
- Text-native: conventions, rules, and prompts are authored as markdown that you and your agents read the same way. No hidden behavior, no compiled state.
|
|
35
|
-
- One source, many consumers: this repo is the authoritative copy. Your projects install and sync on demand, never author in place.
|
|
36
|
-
|
|
37
|
-
Two limits worth knowing before you install. Claude Code is the only agent runtime the plugin targets, and the CLI needs Bun on your path.
|
|
38
|
-
|
|
39
|
-
## Install
|
|
40
|
-
|
|
41
|
-
Add the marketplace, then install the Claude Code plugin.
|
|
23
|
+
## Quick start
|
|
42
24
|
|
|
43
25
|
```bash
|
|
44
26
|
claude plugin marketplace add https://github.com/erclx/canon
|
|
45
27
|
claude plugin install canon@canon
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
<picture>
|
|
49
|
-
<source media="(prefers-color-scheme: dark)" srcset="assets/frames/install.png">
|
|
50
|
-
<img src="assets/frames/install-light.png" alt="Adding the canon marketplace and installing the plugin in Claude Code">
|
|
51
|
-
</picture>
|
|
52
|
-
|
|
53
|
-
The skills land as `/canon:<name>`. If your session was already open, run `/reload-plugins` to pick them up.
|
|
54
|
-
|
|
55
|
-
Several skills call the `canon` CLI to read catalogs and run installs, and the plugin doesn't put it on your path. Install it from the registry.
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
28
|
bun install --global @erclx/canon
|
|
59
29
|
```
|
|
60
30
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
## What is inside
|
|
64
|
-
|
|
65
|
-
Each domain has a canonical source in this repo and a thin install or sync CLI on your side. The domains split on one line: some are copied into your project and become yours to edit, and some are never copied at all.
|
|
66
|
-
|
|
67
|
-
### Domain catalog
|
|
68
|
-
|
|
69
|
-
| Domain | What it is | How it reaches you |
|
|
70
|
-
| -------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
71
|
-
| Plugin skills | Skills that plan a feature, review a diff, sync the planning docs, and run the ship chain | Loaded live from the plugin, never copied |
|
|
72
|
-
| Governance | Coding and authoring rules that load into a Claude session when a matching path is edited | Installed per project by `canon gov install`, refreshed by sync |
|
|
73
|
-
| Tooling stacks | Golden configs, seeds, and a reference per framework | Laid down by `canon init`, reconciled by `canon tooling sync` |
|
|
74
|
-
| Design system | Ships a `DESIGN.md` intent format pointing at your stylesheet for values, and a skill that drafts one | `canon:design-record` drafts it in your repo |
|
|
75
|
-
| Transcripts | A YouTube transcript with metadata frontmatter | `canon transcripts <url>` writes it into any repo |
|
|
76
|
-
| Sandbox | Scenario scaffolds that provision an isolated project state for verifying each domain flow | `canon sandbox` |
|
|
77
|
-
|
|
78
|
-
The design board lives outside canon in [Frameboard](https://www.npmjs.com/package/frameboard), which `canon:design-pick` drives for each round of candidates.
|
|
79
|
-
|
|
80
|
-
### How domains reach you
|
|
81
|
-
|
|
82
|
-
Those domains reach you in three shapes. A tooling stack lands as real files under version control, because a config is something your build reads and your project owns. A plugin skill and the references it carries are never copied, so there is no copy in your repo to drift from this one.
|
|
83
|
-
|
|
84
|
-
Governance is the third shape. A rule with a path glob loads only when a matching path is edited, and a rule with none loads every session. Run `canon gov list` to see the glob beside each rule.
|
|
85
|
-
|
|
86
|
-
## It runs on itself
|
|
87
|
-
|
|
88
|
-
The workflow this toolkit ships is the workflow that built it. Several Claude Code sessions run at once, each in its own git worktree on its own branch, and each opens its own pull request.
|
|
89
|
-
|
|
90
|
-
<picture>
|
|
91
|
-
<source media="(prefers-color-scheme: dark)" srcset="demos/agent-view/demo.gif">
|
|
92
|
-
<img src="demos/agent-view-light/demo.gif" alt="The canon landing page scrolling from the dispatch section to the branch graph, three workers and a planner on disjoint file sets with the pull request each opened">
|
|
93
|
-
</picture>
|
|
94
|
-
|
|
95
|
-
That recording is the landing page's own `dispatch` and `workers` sections, driven through a browser against a local build. The branch graph beside the pull request numbers is authored rather than read, because nothing on a build machine records which files four sessions held.
|
|
96
|
-
|
|
97
|
-
## Documentation
|
|
98
|
-
|
|
99
|
-
Scaffolding your first project? Start with target projects, then the AI workflow loop. Everything else answers questions that arrive later.
|
|
100
|
-
|
|
101
|
-
Working with an agent rather than reading this yourself? It loads `CLAUDE.md` at your project root first, then whichever rules under `.claude/rules/` match the paths it edits. Run `canon docs agents` for the command catalog with flags, exit codes, and JSON shapes.
|
|
102
|
-
|
|
103
|
-
- [AI workflow](docs/workflow/ai-workflow.md): feature-development loop inside a toolkit-managed project
|
|
104
|
-
- [Operating model](docs/workflow/operating-model.md): orchestrator, planner, and worker roles for building across parallel sessions
|
|
105
|
-
- [Skill map](docs/workflow/skill-map.md): plugin skills grouped by the moment a project meets them
|
|
106
|
-
- [Skill map on request](docs/workflow/skill-map-on-request.md): plugin skills that serve a request rather than a moment
|
|
107
|
-
- [Visual design workflow](docs/workflow/visual-design-workflow.md): how canon plans, builds, and reviews a UI
|
|
108
|
-
- [Target projects](docs/target/projects.md): scaffold, add a domain later, sync upstream drift
|
|
109
|
-
- [Agents](docs/agents/index.md): CLI flags, exit codes, and JSON output shapes
|
|
110
|
-
- [Docs index](docs/index.md): every reference doc in this repo
|
|
111
|
-
|
|
112
|
-
## Update
|
|
113
|
-
|
|
114
|
-
Nothing refreshes on its own. Claude Code ships auto-update off for third-party marketplaces, so an installed copy serves whatever version it was installed at until you refresh it.
|
|
115
|
-
|
|
116
|
-
```bash
|
|
117
|
-
claude plugin marketplace update canon
|
|
118
|
-
claude plugin update canon@canon
|
|
119
|
-
canon upgrade
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
The first two update the skills, the third updates the CLI, and they move independently. Restart Claude Code, or run `/reload-plugins`, to pick the skills up.
|
|
31
|
+
The skills land as `/canon:<name>`, and the CLI needs Bun on your path. canon runs on Linux and macOS.
|
|
123
32
|
|
|
124
|
-
|
|
33
|
+
Set up a repository with `canon init`, which lays down its rules, seeds, and configs.
|
|
125
34
|
|
|
126
|
-
|
|
35
|
+
## How a change runs
|
|
127
36
|
|
|
128
|
-
|
|
37
|
+
| 1. Plan | 2. Build | 3. Review | 4. Merge |
|
|
38
|
+
| -------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------- |
|
|
39
|
+
| A planner reads the code and writes one plan you approve | A worker builds it on its own branch, held to the rules | A fresh session reviews the pull request and posts findings | You read the review and merge |
|
|
129
40
|
|
|
130
|
-
|
|
41
|
+
Each session works in its own worktree, so several changes run at once.
|
|
131
42
|
|
|
132
|
-
##
|
|
43
|
+
## What lands in your repo
|
|
133
44
|
|
|
134
|
-
|
|
45
|
+
| Part | How it reaches you |
|
|
46
|
+
| ----------------- | ------------------------------------------------------------------------------ |
|
|
47
|
+
| Skills | Loaded live from the plugin, so there is no copy to drift |
|
|
48
|
+
| Rules | Files under `.claude/rules/` that load when you edit a matching path |
|
|
49
|
+
| Configs and seeds | Real files you own, laid down by `canon init` and kept current by `canon sync` |
|
|
135
50
|
|
|
136
|
-
|
|
51
|
+
## For your agent
|
|
137
52
|
|
|
138
|
-
|
|
53
|
+
- Every command runs without a prompt, and data on stdout pipes clean
|
|
54
|
+
- `canon <command> --help` prints each command's flags, exit codes, and examples
|
|
55
|
+
- Rules load by path, so the agent gets the rule for the file it is editing
|
|
139
56
|
|
|
140
|
-
|
|
141
|
-
- [Git](https://git-scm.com) with worktree support
|
|
142
|
-
- [GitHub CLI](https://cli.github.com) (optional) for ship flows
|
|
143
|
-
- Shell: `zsh`, since bootstrap appends its aliases to `~/.zshrc`.
|
|
57
|
+
## Docs
|
|
144
58
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
bun install
|
|
151
|
-
bun run bootstrap
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
The script is idempotent, so re-run it after pulling upstream changes without duplicating anything. It confirms the install by resolving `canon --help` on the last step.
|
|
155
|
-
|
|
156
|
-
- It leaves an alias block you already have alone rather than refreshing it, so an alias added upstream needs the block deleted and the script re-run.
|
|
157
|
-
- [Zshrc aliases](docs/workflow/zshrc-aliases.md) covers what each alias does, how to pick up a new one, and how to opt out of the block.
|
|
158
|
-
|
|
159
|
-
With the CLI linked, scaffold a fresh project.
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
mkdir ~/my-project && cd ~/my-project
|
|
163
|
-
git init
|
|
164
|
-
canon init
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
`canon init` installs base tooling configs, Claude seeds, and governance rules in one pass.
|
|
168
|
-
|
|
169
|
-
- Governance defaults to the `base` stack, so a bare init lands the workflow and doc-authoring rules in `.claude/rules/`.
|
|
170
|
-
- Each rule names the skill it loads, so no corpus is copied into your project.
|
|
171
|
-
- Pass `--stack <name>` for a language stack such as `node` or `python`, or `--skip governance` to leave rules out.
|
|
172
|
-
- Run `canon tooling list --json` to see the catalog.
|
|
173
|
-
|
|
174
|
-
For the full journey from scaffold through adding a domain later to syncing upstream drift, see [target projects](docs/target/projects.md).
|
|
175
|
-
|
|
176
|
-
### Internal narrative
|
|
177
|
-
|
|
178
|
-
Each domain carries an entry written for someone maintaining the toolkit rather than installing it. These paths resolve in a clone only. The published package ships `docs` and not `.claude`, so an installed copy does not carry them.
|
|
179
|
-
|
|
180
|
-
- [Claude Code plugin](canon/context/surfaces/plugin.md)
|
|
181
|
-
- [Governance rules](canon/context/surfaces/governance.md)
|
|
182
|
-
- [Tooling stacks](canon/context/surfaces/tooling.md)
|
|
183
|
-
- [Design system](canon/context/features/design.md)
|
|
184
|
-
- [Transcripts](canon/context/features/transcripts.md)
|
|
185
|
-
- [Sandbox](canon/context/development/sandbox.md)
|
|
59
|
+
- [AI workflow](docs/workflow/ai-workflow.md): the loop a feature runs
|
|
60
|
+
- [Operating model](docs/workflow/operating-model.md): planners, workers, and reviewers in parallel
|
|
61
|
+
- [Skill map](docs/workflow/skill-map.md): every skill by the moment you reach for it
|
|
62
|
+
- [Agents](docs/agents/index.md): flags, exit codes, and output shapes
|
|
63
|
+
- [Docs index](docs/index.md): every reference doc, updating canon among them
|
|
186
64
|
|
|
187
65
|
## Contributing
|
|
188
66
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
## License
|
|
192
|
-
|
|
193
|
-
[MIT](LICENSE)
|
|
67
|
+
Issues are welcome. Pull requests are by invitation, so read the [contributing guide](CONTRIBUTING.md) before you open one. Released under the [MIT license](LICENSE).
|
package/assets/brand/mark.svg
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
<!-- A
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<!-- A squarish bold c with one pip just past its mouth, in a 100 unit grid.
|
|
2
|
+
The body is a 76 square at (8, 12) with corner radius 30, stroked 20, so
|
|
3
|
+
the counter is a 36 square at (28, 32) with corner radius 10. The mouth is
|
|
4
|
+
cut from x 46 to the right edge level with the counter, so the inside runs
|
|
5
|
+
straight out of its curve, and the arm ends fall where that cut meets the
|
|
6
|
+
outer corners. The pip is one stroke wide, a 20 square at (81.3, 40) with
|
|
7
|
+
corner radius 3.8, on the center line. The view is centered on the bounds
|
|
8
|
+
so the pip does not clip.
|
|
9
|
+
|
|
10
|
+
The c is one outline rather than a masked square, and nothing carries an
|
|
11
|
+
id, since the nav, the hero, and the card inline this file and two inlined
|
|
12
|
+
copies sharing an id collide. The c fills currentColor so an inlining
|
|
13
|
+
surface hands it the text ink, and the pip carries its own fill under a
|
|
14
|
+
class a CSS rule overrides with the brand pair. -->
|
|
15
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.35 -5 110 110">
|
|
16
|
+
<path d="M82.28,32 A30,30 0 0 0 54,12 H38 A30,30 0 0 0 8,42 V58 A30,30 0 0 0 38,88 H54 A30,30 0 0 0 82.28,68 H38 A10,10 0 0 1 28,58 V42 A10,10 0 0 1 38,32 Z" fill="currentColor" />
|
|
17
|
+
<rect class="pip" x="81.3" y="40" width="20" height="20" rx="3.8" fill="#c2380e" />
|
|
10
18
|
</svg>
|
|
@@ -32,11 +32,11 @@ Read `${CLAUDE_SKILL_DIR}/references/config.md` for `canon/config/app-drive.toml
|
|
|
32
32
|
1. Derive `<slug>` from the build being driven, such as `app-drive-0-12-0` for a tag. Claim the folder with `canon records ordinal intake <slug> --claim`.
|
|
33
33
|
2. Record the baseline with `canon intake drive-check <slug> --baseline --json` from the main root, before the first build step. Stop on any `reason` other than `recorded`.
|
|
34
34
|
3. Make the throwaway worktree, build it, and serve it per `${CLAUDE_SKILL_DIR}/references/isolate.md`, which also carries the close and the recovery after a crash.
|
|
35
|
-
4. Confirm the address with `canon pr local --root <worktree> --json` and hand it to the operator before driving.
|
|
35
|
+
4. Confirm the address with `canon pr local --root <worktree> --json`, write it as the drive log's `Address` row, and hand it to the operator before driving.
|
|
36
36
|
|
|
37
37
|
## Step 2: drive
|
|
38
38
|
|
|
39
|
-
Read `${CLAUDE_SKILL_DIR}/references/drive-record.md` before the first finding, for the log
|
|
39
|
+
Read `${CLAUDE_SKILL_DIR}/references/drive-record.md` before the first finding, for the drive log's shape, the severity scale, and the record the check reads.
|
|
40
40
|
|
|
41
41
|
Work through three sources in this order, and name the source on every finding:
|
|
42
42
|
|
|
@@ -63,6 +63,7 @@ Append each finding to the drive log as it happens, never batched at the end, si
|
|
|
63
63
|
- Move each frame a finding cites from scratch into the intake folder's `evidence/`, and cite it by that path
|
|
64
64
|
- Copy each image the operator pastes into `evidence/` in the turn its message arrives, under its finding's number, or under a `ref-` prefix when no finding cites it yet
|
|
65
65
|
- Keep the measured number beside the claim in the log, never only in chat
|
|
66
|
+
- Write an operator's decision under the finding it settles, even when later findings already sit below it, since it is the one edit above the end of the log
|
|
66
67
|
- Write `drive.json` into the intake folder in the shape `drive-record.md` sets, with one entry per goal
|
|
67
68
|
|
|
68
69
|
## Step 4: sort
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Drive record
|
|
3
|
-
description: The drive log
|
|
3
|
+
description: The drive log, the severity scale, the finding sources, and the drive.json shape that canon intake drive-check reads
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Drive record
|
|
@@ -9,23 +9,65 @@ Read before the first finding of `app-drive`. A drive leaves two records in its
|
|
|
9
9
|
|
|
10
10
|
## The drive log
|
|
11
11
|
|
|
12
|
-
Write the log to `evidence/drive-log.md` inside the intake folder, one
|
|
12
|
+
Write the log to `evidence/drive-log.md` inside the intake folder. It opens on a setup table, then takes one heading per finding, appended as the finding happens.
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
|
|
14
|
+
```markdown
|
|
15
|
+
# Drive log
|
|
16
|
+
|
|
17
|
+
| Setup | Value |
|
|
18
|
+
| --------- | ------------------------------------------------- |
|
|
19
|
+
| Commit | `v0.13.138` |
|
|
20
|
+
| Copy | `/tmp/tmp.Xy12/app` |
|
|
21
|
+
| Launch | `bun install && bun run build && bun run preview` |
|
|
22
|
+
| Address | `http://127.0.0.1:4530` |
|
|
23
|
+
| In flight | `feat/landing-page` holds `web/` |
|
|
24
|
+
|
|
25
|
+
## 02. Layers click leaves a half-hidden frame in place
|
|
26
|
+
|
|
27
|
+
`minor` · operator · developer
|
|
28
|
+
|
|
29
|
+
- **Did:** clicked the frame in Layers
|
|
30
|
+
- **Saw:** the view stayed put, with 64% of the frame under the panel edge
|
|
31
|
+
- **Cause:** from code, the reveal acts only when the box is wholly outside the view
|
|
32
|
+
- **Evidence:** `evidence/02-partial-no-pan.png`
|
|
33
|
+
- **Decision (operator):** center the frame unless it is wholly visible
|
|
16
34
|
```
|
|
17
35
|
|
|
18
36
|
- `<nn>` numbers findings in the order they were found, and the frame carries the same number
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- A
|
|
37
|
+
- The title names what the persona met, in sentence case with no trailing period
|
|
38
|
+
- The meta line holds the severity, the source, and the persona, in that order. The source is `goal`, `last-drive`, or `operator`, and a finding naming none sorts as taste.
|
|
39
|
+
- A `last-drive` finding adds `fixed`, `still open`, or `changed` to its meta line
|
|
40
|
+
|
|
41
|
+
### Setup rows
|
|
42
|
+
|
|
43
|
+
The setup table is written once, before the first finding, and every row stays even when its value is empty.
|
|
44
|
+
|
|
45
|
+
- `Commit`, `Copy`, and `Launch` come from making the copy, per `isolate.md`
|
|
46
|
+
- `Address` is the `url` that `canon pr local --root <worktree> --json` confirmed in Step 1
|
|
47
|
+
- `In flight` names each open branch or live plan holding a path the drive covers, as `canon:role-planner` reads what is in flight, and reads `none` when nothing is
|
|
48
|
+
|
|
49
|
+
### Fields
|
|
50
|
+
|
|
51
|
+
The fields under the meta line carry the drive itself, one fact to a line.
|
|
52
|
+
|
|
53
|
+
- `Saw` carries the number read off the page or the app when the claim has one, such as `scrollWidth 436 against clientWidth 320`
|
|
54
|
+
- `Cause` is optional, and says whether it was measured or read from code
|
|
55
|
+
- Write the operator's call as `Decision (operator)` under the finding it settles, even when it arrives after later findings
|
|
56
|
+
- A decision settling two findings sits under the first, and the second carries `Decision (operator):` naming that finding's number, such as `see 02`
|
|
57
|
+
- Keep each field to one line. A field that runs long splits into a second field rather than growing.
|
|
58
|
+
|
|
59
|
+
### Passed goals
|
|
60
|
+
|
|
61
|
+
A goal tried and passed takes a heading too, so the next drive can tell a goal checked from one skipped. Its meta line reads `pass` · goal · persona, and it carries `Did` and `Evidence` alone.
|
|
22
62
|
|
|
23
63
|
### Operator images
|
|
24
64
|
|
|
25
|
-
Operator images count as evidence on arrival. One showing a finding takes that finding's number and is cited from
|
|
65
|
+
Operator images count as evidence on arrival. One showing a finding takes that finding's number and is cited from its `Evidence` field. One no finding cites yet is a reference shot with a heading of its own.
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
## ref-01. The operator's Figma typography panel
|
|
26
69
|
|
|
27
|
-
|
|
28
|
-
- ref-<nn>. [operator] <what the image shows>. Evidence: evidence/ref-<nn>-<name>.png
|
|
70
|
+
- **Evidence:** `evidence/ref-01-figma-typography.png`
|
|
29
71
|
```
|
|
30
72
|
|
|
31
73
|
- `ref-<nn>` numbers reference shots apart from findings, so a later finding citing one keeps the path it already has
|
|
@@ -13,7 +13,7 @@ Run each command from the main worktree root.
|
|
|
13
13
|
|
|
14
14
|
1. Run `git worktree prune` first, which drops the registration a crashed drive left behind once its folder is gone.
|
|
15
15
|
2. Make a folder with `mktemp -d`, outside the repository, and add the worktree with `git worktree add --detach <dir>/app <commit>`. The commit is the tag or sha the operator names, or the trunk's tip.
|
|
16
|
-
3. Record the commit, the folder, and the launch command as the
|
|
16
|
+
3. Record the commit, the folder, and the launch command as rows of the drive log's setup table, in the shape `drive-record.md` sets.
|
|
17
17
|
4. Put the worktree's path in `drive.json` as `worktree`, so the check fails a drive whose close never removed it.
|
|
18
18
|
|
|
19
19
|
A folder under the repository is the wrong home. The parent repository becomes the app's repository root, and a walk-up search for config or a lockfile finds the project instead of the copy.
|
|
@@ -48,6 +48,7 @@ Each frame carries its own label and follows the board theme, so the set reads a
|
|
|
48
48
|
- Label each arm inside its frame with its id and its cost, since the composite capture draws no captions
|
|
49
49
|
- Theme every arm off the `data-theme` attribute the board sets on each frame's root, so the theme toggle sets the whole set at once. A set spanning both themes cannot be compared.
|
|
50
50
|
- Give no arm a script that stores a theme and reapplies it on load. It overwrites the toggle, and a fresh browser profile hides the fault.
|
|
51
|
+
- Write each frame's headings, labels, and captions by `${CLAUDE_SKILL_DIR}/../ui-craft/references/copy.md`, since a candidate's copy is often the first draft of the shipped page's
|
|
51
52
|
|
|
52
53
|
### Default path and live app
|
|
53
54
|
|
|
@@ -29,6 +29,19 @@ The verb resolves the board at the main worktree root in-process, the root `sess
|
|
|
29
29
|
- A line already reading as a list of `#NNN` entries takes the new number appended, reported as `appended`, so a task shipped in slices keeps every pull request
|
|
30
30
|
- The same write drops this branch from the `Pending branch:` line `canon tasks outcome` wrote, which lets the merge-time archive close the task
|
|
31
31
|
|
|
32
|
+
## Record the session
|
|
33
|
+
|
|
34
|
+
Beside the number, name this session on the same task's `Sessions:` line. It is the one record that covers a hand-launched worker, which no dispatcher saw start. Read the id from the roster's own row for the caller, then hand it to the verb under the same plan:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
id=$(canon sessions list --self --json | jq -r '.sessions[0].sessionId // empty')
|
|
38
|
+
[ -n "$id" ] && canon tasks session "$id" --plan feature-<slug> --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- A dispatched worker is already listed, since its dispatcher recorded it at launch, and the verb reports `unchanged` rather than writing it twice
|
|
42
|
+
- An empty `id` means the roster could not name the caller, so skip the write and report that no session was recorded
|
|
43
|
+
- Skip the same three refusals as the number below, and report `bad-input` or `no-name`, since either is a defect in this call
|
|
44
|
+
|
|
32
45
|
## Refusals
|
|
33
46
|
|
|
34
47
|
Skip silently when the record is `ok: false` and `reason` is `no-board`, `no-match`, or `ambiguous`, meaning no board, no task naming the plan, or more than one. A guessed write would compound each, since a wrong match archives the wrong task unattended once the branch merges. Report any other refusal rather than swallowing it.
|
|
@@ -134,6 +134,7 @@ A bullet's punctuation follows its sentence count, and a list opens unannounced.
|
|
|
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
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.
|
|
137
|
+
- The check misses a clause colon in a list of colon items, but it is wrong.
|
|
137
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.
|
|
138
139
|
|
|
139
140
|
## Language
|
|
@@ -86,6 +86,7 @@ The readout is the text `Created cloud session: <title>`, unanchored since a ter
|
|
|
86
86
|
- On a failed create, report the typescript's last lines and fall back to the human-launch line in `orchestrator-dispatch.md`
|
|
87
87
|
- The wrapper is a stopgap any change to the interactive create screen breaks, which is why the readout fails loudly instead of guessing
|
|
88
88
|
- Record `session` beside the row's branch in this pass's launched record, since that and the pull request list are the only readings that know it exists
|
|
89
|
+
- Name it on the row's task with `canon tasks session "$session" <task> --name cloud-<project>-<slug> --json`, since a cloud worker has no board and the roster never lists it
|
|
89
90
|
- Report the dispatch as the local shape does, naming the row, the plan, the repository, and the session id in place of a session name
|
|
90
91
|
|
|
91
92
|
## Recognize the pull request
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Orchestrator launch runbook
|
|
3
|
-
description: The launch every dispatch kind shares, being the build, cloud build, review-address, planning
|
|
3
|
+
description: The launch every dispatch kind shares, being the build, cloud build, review-address, and planning templates with a pointer to the talk variant, the session name and controller id each carries, why the command sits at position zero, and what the brief may carry
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Run this once `orchestrator-dispatch.md` has cleared a row, or from its planning or review-address shape below when that runbook's checks do not bind. The model each template names comes from `## Pick the model` in that runbook.
|
|
@@ -79,6 +79,10 @@ The prompt carries pointers and standing context, and stops there. The branch an
|
|
|
79
79
|
|
|
80
80
|
Report the dispatch as loudly as the human-launch line it replaces, naming the branch, the model, the task, and the session name, so a person reading the transcript can follow what fired without watching it happen.
|
|
81
81
|
|
|
82
|
+
### Record the worker on its task
|
|
83
|
+
|
|
84
|
+
Once a build or review-address launch returns, run `canon tasks session <worker-id> <task> --json` with the sessionId the launch output carries. On `no-name`, the worker already exited, so rerun with `--name` and the name passed to `-n`.
|
|
85
|
+
|
|
82
86
|
## Dispatch to a cloud worker
|
|
83
87
|
|
|
84
88
|
Read `${CLAUDE_SKILL_DIR}/references/orchestrator-cloud-launch.md` when `orchestrator-dispatch.md` picked cloud for the row. It holds the prompt that carries the plan as text and announces over GitHub, the create under `script`, and the readout that refuses to record a missing session id.
|
|
@@ -137,25 +141,7 @@ Hold all planning of a row any talk session has said by message it is planning,
|
|
|
137
141
|
|
|
138
142
|
## Dispatch a talk session
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
claude --bg --model <model> -n "planner-<project>-<slug>-talk" "Run /canon:role-planner, then /canon:plan-feature <task>. This is a talk session: the operator will talk with you here, so run your role's talk clause, and message your controller when the operator ends the conversation. Your controller is the session whose sessionId is <dispatcher-id>. ..."
|
|
144
|
-
claude --bg --model <model> -n "worker-<project>-<slug>-talk" "/canon:auto-ship <plan>
|
|
145
|
-
This is a talk session: the operator will talk with you here, so run your role's talk clause, and message your controller when the operator ends the conversation. Your controller is the session whose sessionId is <dispatcher-id>. ..."
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
The ellipsis stands for the rest of the cold template's message clauses, unchanged. The build variant keeps `/canon:auto-ship <plan>` at position zero with nothing before it, per the rule above.
|
|
149
|
-
|
|
150
|
-
- Keep the role prefix and add the suffix, since `orchestrator-handoff.md` separates dispatched sessions by `worker-` and `planner-` and a new prefix reads as a hand launch
|
|
151
|
-
- A talk session is retired only on the operator's word, stated once in `orchestrator-handoff.md`, so do not restate it in a launch report
|
|
152
|
-
- Reviewers get no talk shape, since a reviewer's pass holds no operator dialogue
|
|
153
|
-
|
|
154
|
-
### Recording the talk session
|
|
155
|
-
|
|
156
|
-
Read the session's `sessionId` off the launch output, carry it in this session's own context, and write it into the map's `## Talk sessions held open` at the next handoff. The client can rename a session and drop the suffix, so the id is the durable marker and the suffix is only for display.
|
|
157
|
-
|
|
158
|
-
The map exists only once the handoff writes it, so this session's own launches, read with the prior map, are what the first wind-down reads talk sessions from.
|
|
144
|
+
Read `${CLAUDE_SKILL_DIR}/references/orchestrator-talk-launch.md` when the operator will talk with a planner or worker rather than leave it to report back. It states the `-talk` name suffix, the one sentence the brief adds, and where the session's id is kept for the handoff.
|
|
159
145
|
|
|
160
146
|
## Hand launch
|
|
161
147
|
|
|
@@ -21,6 +21,16 @@ claude --bg --model <model> -n "reviewer-<project>-<number>" "Run /canon:role-re
|
|
|
21
21
|
- Append the cross-branch facts after the controller clause, per `### What the brief may carry` in `orchestrator-launch.md`
|
|
22
22
|
- Check `canon sessions list --json` for a live `reviewer-<project>-<number>` before launching, and message it instead when one holds the pull request
|
|
23
23
|
|
|
24
|
+
### Record the reviewer on the task
|
|
25
|
+
|
|
26
|
+
A reviewer writes no task file, so this session names it on the task the pull request closes, through the sessionId the launch output carries:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
canon tasks session <reviewer-id> <task> --json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Record the UI reviewer below the same way after its launch. A `no-name` refusal means the reviewer exited before the read, so rerun with `--name` and the name the launch passed to `-n`.
|
|
33
|
+
|
|
24
34
|
### The channel clauses
|
|
25
35
|
|
|
26
36
|
The channel clauses restate what `role-reviewer` holds, so a reviewer whose plugin cache predates that body still sends the dispatch itself. The worker reads the reviewer's sessionId off that message and sends its re-review request back to it, since a reviewer holds the trunk branch and no branch lookup finds it.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Orchestrator talk launch
|
|
3
|
+
description: The talk variant of the planning and build launches, being the name suffix, the one added brief sentence, and where the talk session's id is recorded for the handoff
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Run this when the operator wants to talk with a planner or worker rather than leave it to report back. The rules every launch shares stay in `orchestrator-launch.md`.
|
|
7
|
+
|
|
8
|
+
# Talk launch
|
|
9
|
+
|
|
10
|
+
## The launch
|
|
11
|
+
|
|
12
|
+
A planner or worker the operator will talk with takes the same launch as its cold shape in `orchestrator-launch.md`, with a `-talk` suffix on its name and one sentence added to its brief. A cold session works alone and reports back, and a talk session stays open after its plan or pull request lands so the operator can keep shaping the row.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
claude --bg --model <model> -n "planner-<project>-<slug>-talk" "Run /canon:role-planner, then /canon:plan-feature <task>. This is a talk session: the operator will talk with you here, so run your role's talk clause, and message your controller when the operator ends the conversation. Your controller is the session whose sessionId is <dispatcher-id>. ..."
|
|
16
|
+
claude --bg --model <model> -n "worker-<project>-<slug>-talk" "/canon:auto-ship <plan>
|
|
17
|
+
This is a talk session: the operator will talk with you here, so run your role's talk clause, and message your controller when the operator ends the conversation. Your controller is the session whose sessionId is <dispatcher-id>. ..."
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The ellipsis stands for the rest of the cold template's message clauses, unchanged. The build variant keeps `/canon:auto-ship <plan>` at position zero with nothing before it, per `### Position zero` in `orchestrator-launch.md`.
|
|
21
|
+
|
|
22
|
+
- Keep the role prefix and add the suffix, since `orchestrator-handoff.md` separates dispatched sessions by `worker-` and `planner-` and a new prefix reads as a hand launch
|
|
23
|
+
- A talk session is retired only on the operator's word, stated once in `orchestrator-handoff.md`, so do not restate it in a launch report
|
|
24
|
+
- Reviewers get no talk shape, since a reviewer's pass holds no operator dialogue
|
|
25
|
+
|
|
26
|
+
## Recording the talk session
|
|
27
|
+
|
|
28
|
+
Read the session's `sessionId` off the launch output, carry it in this session's own context, and write it into the map's `## Talk sessions held open` at the next handoff. The client can rename a session and drop the suffix, so the id is the durable marker and the suffix is only for display.
|
|
29
|
+
|
|
30
|
+
The map exists only once the handoff writes it, so this session's own launches, read with the prior map, are what the first wind-down reads talk sessions from.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Task record lines reference
|
|
3
|
+
description: The lines a verb writes on a task below its origin lines, being the Pull request line that lets a merge close its task, the Pending branch marker that holds that merge back, and the Sessions line naming who worked it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task record lines reference
|
|
7
|
+
|
|
8
|
+
Applies to the lines a task carries under its origin lines that no session writes by hand. Each one has a `canon tasks` verb as its writer, and this file fixes what each line means and who calls that verb.
|
|
9
|
+
|
|
10
|
+
This is an attribute standard. It governs lines inside a task file rather than a file of its own, so it carries no template.
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
|
|
14
|
+
Governs the `Pull request:`, `Pending branch:`, and `Sessions:` lines.
|
|
15
|
+
|
|
16
|
+
Does not govern:
|
|
17
|
+
|
|
18
|
+
- The task file's layout, filename, format, origin lines, and archiving: `tasks.md`
|
|
19
|
+
- The `Declined:` line: `tasks-decline.md`
|
|
20
|
+
|
|
21
|
+
## The `Pull request:` line
|
|
22
|
+
|
|
23
|
+
`Pull request:` lists every pull request that shipped part of the task as bare numbers, oldest first and comma-separated, as in `Pull request: #NNN, #NNN`. It is not an origin, so a task without one is well-formed, and `git-pr` appends to it when a pull request opens.
|
|
24
|
+
|
|
25
|
+
The line lets a merge close its own task. `canon tasks archive --pull-request <n>` finds the task by any listed number and archives it only on the last.
|
|
26
|
+
|
|
27
|
+
- One pull request, one task. Two tasks naming the same number refuse to archive rather than both moving.
|
|
28
|
+
- `Pending branch: <branch>` holds that merge back while a branch that ticked an outcome waits on its own number
|
|
29
|
+
- `canon tasks outcome` writes that line, skipping it when the branch's pull request is already listed, and `canon tasks pull-request` clears it
|
|
30
|
+
|
|
31
|
+
## The `Sessions:` line
|
|
32
|
+
|
|
33
|
+
`Sessions:` names each session that built or reviewed the task, by roster name and full sessionId, as in `Sessions: <name> (<sessionId>), <name> (<sessionId>)`. A retro or a regression hunt reaches each transcript through `canon sessions export <sessionId>`, which takes the full id alone. It is not an origin either.
|
|
34
|
+
|
|
35
|
+
- `canon tasks session <sessionId> <task>` writes it, or `--plan <slug>` in place of the stem, so it is never hand-edited
|
|
36
|
+
- The verb reads the name off the live roster. A session that already exited takes `--name`, and so does a cloud session's `session_` id, since the roster never lists one.
|
|
37
|
+
- The id is the key. A repeat call for a listed id keeps the name first recorded, so two callers recording one worker write it once.
|
|
38
|
+
- The dispatcher records each worker and reviewer it launches, and `git-pr` records the session opening the pull request, which covers a hand launch
|
|
39
|
+
|
|
40
|
+
The line sits below the origin, `Pull request:`, and `Pending branch:` lines. `canon tasks validate` reports a line that does not parse as name and id pairs as `sessions-misshapen`.
|