@erclx/canon 5.69.0 → 5.70.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 (53) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +33 -159
  3. package/assets/brand/mark.svg +17 -9
  4. package/claude/.claude-plugin/plugin.json +1 -1
  5. package/claude/skills/app-drive/SKILL.md +3 -2
  6. package/claude/skills/app-drive/references/drive-record.md +52 -10
  7. package/claude/skills/app-drive/references/isolate.md +1 -1
  8. package/claude/skills/design-pick/SKILL.md +1 -0
  9. package/claude/skills/ui-craft/references/copy.md +4 -1
  10. package/claude/skills/ui-film/REQUIREMENT.md +4 -2
  11. package/claude/skills/ui-film/SKILL.md +24 -11
  12. package/claude/skills/ui-film/references/compose-craft.md +81 -0
  13. package/claude/skills/ui-film/references/config.md +6 -1
  14. package/claude/skills/ui-film/references/handoff.md +13 -3
  15. package/claude/skills/ui-film/references/take-craft.md +27 -1
  16. package/docs/index.md +1 -0
  17. package/docs/migrations/by-hand.md +107 -0
  18. package/docs/migrations/by-verb.md +118 -0
  19. package/docs/migrations/index.md +14 -0
  20. package/docs/target/index.md +1 -2
  21. package/docs/target/projects.md +2 -2
  22. package/docs/target/sync.md +22 -2
  23. package/docs/workflow/ai-workflow.md +1 -1
  24. package/governance/ledger/skills/ui-craft/copy.md +8 -4
  25. package/package.json +3 -1
  26. package/scripts/core/design-sync.ts +204 -0
  27. package/scripts/core/regen-web-favicon.ts +27 -12
  28. package/scripts/core/regen-web-previews.ts +8 -1
  29. package/scripts/core/render-film.ts +179 -0
  30. package/src/capture/frame-values.ts +12 -12
  31. package/src/commands/records.ts +3 -2
  32. package/src/commands/sandbox.ts +9 -2
  33. package/src/commands/take.ts +159 -11
  34. package/src/design/favicon.ts +85 -13
  35. package/src/design/reference.ts +98 -0
  36. package/src/design/render.ts +16 -14
  37. package/src/design/tokens.ts +4 -3
  38. package/src/gate/stages.ts +6 -0
  39. package/src/init/steps.ts +2 -2
  40. package/src/migrate/status.ts +3 -3
  41. package/src/records/validate.ts +14 -2
  42. package/src/sandbox/expect.ts +32 -0
  43. package/src/sandbox/headless/run.ts +6 -3
  44. package/src/take/camera.ts +99 -10
  45. package/src/take/film.ts +35 -2
  46. package/src/take/fixtures/input.html +138 -0
  47. package/src/take/keys.ts +193 -0
  48. package/src/take/log.ts +94 -1
  49. package/src/take/perform.ts +165 -10
  50. package/src/take/plan.ts +101 -6
  51. package/src/take/screencast.ts +28 -3
  52. package/src/take/stepper.ts +122 -18
  53. package/docs/target/migrations.md +0 -205
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.70.0](https://github.com/erclx/canon/compare/v5.69.0...v5.70.0) (2026-10-27)
4
+
5
+
6
+ ### Features
7
+
8
+ * **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))
9
+ * **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))
10
+ * **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))
11
+ * **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))
12
+ * **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))
13
+ * **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))
14
+ * **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))
15
+ * **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))
16
+ * **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))
17
+ * **ui-film:** add footage guidance for composing takes ([#2793](https://github.com/erclx/canon/issues/2793)) ([dc98a98](https://github.com/erclx/canon/commit/dc98a981bae97921d796e1412a36fb89844e3bba))
18
+ * **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))
19
+
3
20
  ## [5.69.0](https://github.com/erclx/canon/compare/v5.68.0...v5.69.0) (2026-10-26)
4
21
 
5
22
 
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-accent.svg">
5
- <img src="assets/brand/mark-accent-light.svg" alt="canon" width="56" height="56">
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
  [![npm version](https://img.shields.io/npm/v/@erclx/canon)](https://www.npmjs.com/package/@erclx/canon)
11
13
  [![CI status](https://img.shields.io/github/actions/workflow/status/erclx/canon/verify.yml?branch=main)](https://github.com/erclx/canon/actions/workflows/verify.yml)
12
14
  [![License MIT](https://img.shields.io/npm/l/@erclx/canon)](LICENSE)
13
15
 
14
- canon is a CLI and Claude Code plugin that runs your agent's work from plan to merge, holds it to the practices that make code worth keeping, and installs the same setup in every repository.
15
- **[See it run at canon.erclx.dev](https://canon.erclx.dev)**
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
- That page is one real session the toolkit ran on itself, and every count on it is read from this repository when the page builds.
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
- [Bun](https://bun.sh) is the CLI runtime and has to be on your path first. Confirm the install by resolving `canon --help`.
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
- `canon upgrade` reads the package manager off its own install path and reinstalls with that one, so you don't have to remember which put it there. It names what it detected before it runs anything, and it refuses a source checkout rather than reinstalling over your clone.
33
+ Set up a repository with `canon init`, which lays down its rules, seeds, and configs.
125
34
 
126
- ### Checking for drift
35
+ ## How a change runs
127
36
 
128
- You don't have to wait until something breaks to find out you're behind. `canon sync --check` and `canon claude skills drift` both report the installed version against the newest published one, and neither changes its exit code over it, so an offline machine reads unknown rather than red.
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
- To stop doing this by hand, turn auto-update on once under `/plugin` in the Marketplaces tab. Confirm what you are running with `canon --version` and `claude plugin list`.
41
+ Each session works in its own worktree, so several changes run at once.
131
42
 
132
- ## Development
43
+ ## What lands in your repo
133
44
 
134
- Working on the toolkit starts from a clone. Running the CLI doesn't, since it installs from the registry. Skip this section unless you're changing the toolkit itself.
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
- ### Prerequisites
51
+ ## For your agent
137
52
 
138
- Bun, Git, and a shell are required, and the GitHub CLI is optional.
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
- - [Bun](https://bun.sh) for the CLI runtime and scripts
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
- Clone the repo, then run the bootstrap script. It installs dependencies, links the CLI globally, and appends a marked block of Claude Code shell aliases to your `~/.zshrc`.
146
-
147
- ```bash
148
- git clone https://github.com/erclx/canon.git
149
- cd canon
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
- Portfolio project. Issues are welcome. Pull requests are accepted by invitation only, so open an issue rather than a branch. Read the [contributing guidelines](CONTRIBUTING.md) for the local loop, the authoring split, and the commit convention before you file anything.
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).
@@ -1,10 +1,18 @@
1
- <!-- A bound ledger: two pages fanned open around a spine, drawn as three
2
- solid masses rather than thin strokes, so the shape survives being
3
- rendered at favicon size instead of averaging into grey. The 10-unit
4
- gap between each page and the spine, against an 80-unit frame, is what
5
- keeps the split a visible channel at 16px; a first draft at half that
6
- gap closed into an unreadable blob at the same size. -->
7
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="10 10 80 80">
8
- <path d="M34,20 L15,28 L15,72 L34,80 Z M66,20 L85,28 L85,72 L66,80 Z" fill="currentColor" />
9
- <rect x="44" y="15" width="12" height="70" rx="2" fill="currentColor" />
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>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "canon",
3
3
  "description": "Runs your agent's work and keeps its code good, on one setup for every repo.",
4
- "version": "5.69.0",
4
+ "version": "5.70.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -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 line, the severity scale, and the record the check reads.
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 line, the severity scale, the finding sources, and the drive.json shape that canon intake drive-check reads
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 line per finding, appended as the finding happens.
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
- ```plaintext
15
- - <nn>. [<severity>] [<source>] <persona>: did <action>, saw <result>. Evidence: evidence/<nn>-<name>.png
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
- - `<source>` is `goal`, `last-drive`, or `operator`. A finding naming none sorts as taste.
20
- - `<result>` carries the number read off the page or the app when the claim has one, such as `scrollWidth 436 against clientWidth 320`
21
- - A goal tried and passed takes a line too, as `[pass] [goal]`, so the next drive can tell a goal checked from one skipped
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 that finding's line, while one no finding cites yet is a reference shot with a log line of its own.
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
- ```plaintext
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 first lines of the drive log.
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
 
@@ -3,7 +3,10 @@
3
3
  ## Punctuation
4
4
 
5
5
  - Write no em dash (`—`) or semicolon in rendered copy. Use a comma or a period, or restructure the sentence.
6
- - Add no trailing punctuation to a button label or a short action string.
6
+ - Add no trailing period, colon, or exclamation mark to a heading, label, link, button, nav item, caption, status, or one-sentence tagline. Keep the question mark a question needs.
7
+ - Rewrite a two-sentence tagline as one sentence rather than keeping a period inside it.
8
+ - End a one-sentence error or validation message with no period, such as `Enter an email address`.
9
+ - Keep end punctuation on body copy, multi-sentence messages, and quoted text, which a reader reads as prose.
7
10
 
8
11
  ## Button copy
9
12
 
@@ -19,13 +19,15 @@ A session that does reach `canon take` writes the plan from its own reading of t
19
19
  - The session looks at a still of each take before handing it off or posting it as a pull request reel, and names a beat that fell back to the real-time route
20
20
  - HyperFrames receives the takes with what it needs to apply the camera and draw the cursor
21
21
 
22
- One video keeps its plan, takes, and composition in one workspace the operator can find, backed up without its media.
22
+ One video keeps its plan, takes, and composition in one workspace the operator can find, backed up without its media. A README there records how to re-film the takes, and the composing session adds how to re-render.
23
+
24
+ A session composing the takes finds the footage guidance HyperFrames lacks, being captions over app UI, other shapes, a README loop, and sped-up clips.
23
25
 
24
26
  ## Must not
25
27
 
26
28
  - Film before the operator approves, or with nobody there to approve, unless `pr-evidence` named pull request mode, whose still check stands in for the approval
27
29
  - Write a tracked file, the config included
28
- - Compose, caption, or render the video
30
+ - Run the composition or render the video, or write any composition file
29
31
  - Trigger on anything but a request to record or film the app
30
32
  - Stay when no caller besides the operator reaches it, such as a pull request clip through `pr-evidence`, which a review checks
31
33
 
@@ -71,12 +71,15 @@ canon take <url> .canon/video/<slug>/plan.json --out .canon/video/<slug>/takes -
71
71
 
72
72
  Branch on the record's `reason`, never on the exit code, which a shell function wrapping `canon` can flatten to zero.
73
73
 
74
- | Record | Route |
75
- | -------------------- | --------------------------------------------------------------------------------------- |
76
- | No `reason` | Continue to the stills |
77
- | `target-missing` | Find the target the record's `beat` names on the page, fix the plan, and film once more |
78
- | `server-unreachable` | Restart the server from Step 1 and film once more |
79
- | Any other `reason` | Report the `reason` and `message` to the operator and stop, since each is a setup step |
74
+ | Record | Route |
75
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
76
+ | No `reason` | Continue to the stills |
77
+ | `target-missing` with `fallback` | Check the access before the selector, per the note below the table |
78
+ | `target-missing` | Open the record's `still`, find the target the record's `beat` names on the page, fix the plan, and film once more |
79
+ | `server-unreachable` | Restart the server from Step 1 and film once more |
80
+ | Any other `reason` | Report the `reason` and `message` to the operator and stop, since each is a setup step |
81
+
82
+ A refusal carrying `fallback` means the screencast opened the address a second time, so a single-use link was spent before the step ran. Read `${CLAUDE_SKILL_DIR}/references/config.md` for the access the take opens with, and fix that before touching the target.
80
83
 
81
84
  A second refusal of the same kind stops the run and reports both records.
82
85
 
@@ -85,30 +88,40 @@ A second refusal of the same kind stops the run and reports both records.
85
88
  Open each beat's `takes/<dir>/still.jpg` before handing off, since a clip can film the wrong state cleanly. The verb writes it from the clip's closing frame, where the action's result shows.
86
89
 
87
90
  - Say what each still shows beside the beat it belongs to
88
- - Report a beat the record marks with `fallback` as filmed in real time at 1080p, which goes soft under a zoom, and offer to re-film it with the beat's input simplified
91
+ - Report a beat the record marks with `fallback` as filmed in real time at 1080p, whose zoom stops near 1.35x rather than 1.8x, and offer to re-film it with the beat's input simplified
89
92
 
90
93
  ## Step 5: hand off
91
94
 
92
- Read `${CLAUDE_SKILL_DIR}/references/handoff.md` on reaching this step. It sets what HyperFrames receives and how a composition applies the camera track and draws the cursor.
95
+ Read `${CLAUDE_SKILL_DIR}/references/handoff.md` on reaching this step, for what HyperFrames receives, where each composition lives, and how one applies the camera track and draws the cursor. Read `${CLAUDE_SKILL_DIR}/references/compose-craft.md` beside it, for the footage rules the HyperFrames skills lack.
93
96
 
94
97
  Close the throwaway copy per `isolate.md` when Step 1 built one, after the stills are read.
95
98
 
99
+ ### Write the workspace README
100
+
101
+ Write the filming half of `.canon/video/<slug>/README.md`, so a later session can re-film without this one. The composing session adds the re-render half under its own heading, as `compose-craft.md` states.
102
+
103
+ - Name what was filmed, beat by beat, and how to re-film each one with `canon take`
104
+ - Say where each folder came from, being the plan, the takes, and the config keys the take read, with `access` described rather than copied when it carries a token
105
+ - Write the file whole through the main-root route when none exists, with the filming half under a `## Filming` heading
106
+ - Add a `## Filming` section when a README is already there, reading the file and writing it back whole, and never overwrite what another session wrote
107
+ - Replace an existing `## Filming` section in place on a re-film, since the commands in it changed
108
+
96
109
  ## Output
97
110
 
98
111
  Emit the takes folder, one line per beat, and the next step.
99
112
 
100
113
  ```plaintext
101
- 🎬 Filmed .canon/video/<slug>/takes/
114
+ 🎬 Filmed .canon/video/<slug>/takes/, re-film notes in .canon/video/<slug>/README.md
102
115
 
103
116
  01-open-the-kit step 4.2 s the board's first page with its frames filled in
104
117
  02-search-for-color screencast (fallback) 3.8 s the page list narrowed to two results
105
118
 
106
- Next: load hyperframes to compose, reading takes/take.json and the handoff notes
119
+ Next: load hyperframes to compose, reading takes/take.json, handoff.md, and compose-craft.md
107
120
  ```
108
121
 
109
122
  ## What this delegates
110
123
 
111
124
  - `app-drive`'s `isolate.md` owns the throwaway copy and its close
112
125
  - `hyperframes-creative`'s story spine owns what a beat says to a viewer
113
- - `hyperframes` and its sibling skills own composing, captioning, and rendering the video
126
+ - `hyperframes` and its sibling skills own composing, captioning, and rendering the video, and `compose-craft.md` adds only what app footage changes about their advice
114
127
  - `review-ui` owns driving a pull request's checklist
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Compose craft
3
+ description: The footage rules a session composing ui-film takes follows where the HyperFrames skills say nothing, being captions over app UI, other shapes, the README loop, sped-up clips, storyboard headings, and the workspace README
4
+ ---
5
+
6
+ # Compose craft
7
+
8
+ Read at Step 5 of `ui-film`, and by the session that composes the takes, which the handoff's next line points here. HyperFrames owns composing, captioning, and rendering, so this file carries only what app footage changes about its advice and restates none of it.
9
+
10
+ Each rule states the principle. Where a number appears, it is the case measured on one app's launch film, not a law for the next app.
11
+
12
+ ## Contents
13
+
14
+ - [Captions over app footage](#captions-over-app-footage)
15
+ - [Other shapes](#other-shapes)
16
+ - [The README loop](#the-readme-loop)
17
+ - [Sped-up clips](#sped-up-clips)
18
+ - [Storyboard headings](#storyboard-headings)
19
+ - [The workspace README](#the-workspace-readme)
20
+ - [Sources](#sources)
21
+
22
+ ## Captions over app footage
23
+
24
+ HyperFrames' caption guide places a landscape caption 80 to 120 px from the bottom and keeps it off a speaker's face. App footage has no speaker, and its bottom edge is often a toolbar where the beat's click lands.
25
+
26
+ - Pick one caption position for the whole film, clear of the app's chrome where actions land, and keep every caption there, since a caption that moves between beats makes the viewer hunt for it
27
+ - Back a caption over bright UI with the scrim HyperFrames' caption guide sizes to the text
28
+ - Snapshot each caption's moment, and move a caption only when it covers its own beat's action
29
+ - Write caption text by the interface copy rules in `ui-craft`'s `copy.md`, so a caption ends with no period
30
+
31
+ ## Other shapes
32
+
33
+ Cut a square or vertical version only when the operator asks for one. A film with one shape needs nothing from this section, and the vertical caption band and safe boxes stay with HyperFrames' frame presets.
34
+
35
+ - Start each shape as its own HyperFrames project, as `hyperframes-studio` states for a different aspect, in the workspace folder `handoff.md` names for it
36
+ - Frame the shape by cropping a window of the page at 1x, never by scaling the 16:9 frame into it, since a page shrunk into a square leaves the action too small to read
37
+ - Pan the window along the camera track's view center, so it follows the action the zoom would have aimed at. Frameboard's square cut used a 1080x1080 window.
38
+ - Expect a screencast take to hold at 1x from a softer 1080p source, while a stepped take gives the same window two clip pixels per page pixel
39
+
40
+ ## The README loop
41
+
42
+ Cut a README loop only when the operator asks for one. A README hero plays inline and silently, so it is a short loop rather than a cut of the film.
43
+
44
+ - Cut it from the raw take showing the app's core action, rather than from a render, in the workspace folder `handoff.md` names for it
45
+ - Crop it to the canvas, so no browser margin or page chrome outside the app shows
46
+ - End it on the finished state, held long enough to read before the loop restarts
47
+ - Export an animated WebP under about 2 MB, since a README renders one inline where a video needs a player. Frameboard's loop played inline at 1.72 MB.
48
+
49
+ ## Sped-up clips
50
+
51
+ A clip the edit plays faster runs its zoom faster too, so a push that settled in real time pumps several times a beat.
52
+
53
+ - Rebuild the beat's track for the playback rate with `canon take camera <dir>/log.json --rate <n> --out <file>`, and drive the wrapper from that file rather than from `camera.json`
54
+ - Never scale `camera.json`'s times by hand, since the rebuilt track also keeps each push inside the 1 s ceiling at the new speed
55
+ - Keep a typing beat at a rate where each word still reads, since a viewer cannot read a fill that finishes in a few frames
56
+
57
+ ## Storyboard headings
58
+
59
+ - Write each frame heading as `## Frame N: title`, since the dash form in HyperFrames' `storyboard-format.md` example fails the markdown audit
60
+ - Treat the parser's read of the colon form as assumed, since its lenient parse was not confirmed against its source
61
+ - Title each frame as the beat the operator approved, so the frame, the take's folder, and the caption share one name a reader can follow across all three
62
+
63
+ ## The workspace README
64
+
65
+ Step 5 writes the filming half of `.canon/video/<slug>/README.md`. The composing session adds its own half under its own heading.
66
+
67
+ - Add how to re-render each project the workspace holds, naming its folder and the render command it runs
68
+ - Name any track rebuilt with `--rate`, with the command that rebuilt it, since a re-film overwrites `camera.json` and leaves a rebuilt track stale
69
+ - Leave the filming half as Step 5 wrote it, so the next session can re-film without reading the composition
70
+
71
+ ## Sources
72
+
73
+ | Rule | Source |
74
+ | --------------------------- | -------------------------------------------------------------------------------------------------------- |
75
+ | Caption placement and scrim | HyperFrames' `captions.md`, adjusted for footage with chrome along its bottom edge |
76
+ | A new project per shape | `hyperframes-studio`'s brief step, which starts a new project for a different aspect |
77
+ | The 1080x1080 window | Frameboard's launch film, cut square from stepped takes |
78
+ | The 2 MB WebP loop | Frameboard's README hero, an animated WebP cut from a raw take, which played inline at 1.72 MB |
79
+ | Rebuilding a sped-up track | `canon take camera --help`, whose `--rate` divides every time in the log |
80
+ | Storyboard heading form | HyperFrames' `storyboard-format.md` and the markdown audit's character bans, with the colon read assumed |
81
+ | The README's two halves | Frameboard's workspace, whose README recorded how to re-film and re-render after a session ended |