plumbbob 0.9.5 → 0.10.1

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 (144) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +89 -87
  3. package/dist/cli-core.js +18 -8
  4. package/dist/cli.js +1 -1
  5. package/dist/lib/agents.js +26 -26
  6. package/dist/lib/buildlog.js +21 -11
  7. package/dist/lib/buildlogsync.js +8 -8
  8. package/dist/lib/check.js +14 -14
  9. package/dist/lib/commitbody.js +72 -0
  10. package/dist/lib/commitmsg.js +7 -7
  11. package/dist/lib/git.js +44 -15
  12. package/dist/lib/intent.js +20 -19
  13. package/dist/lib/latch.js +16 -16
  14. package/dist/lib/orient.js +36 -17
  15. package/dist/lib/reentry.js +3 -3
  16. package/dist/lib/settings.js +16 -16
  17. package/dist/lib/sidecar.js +70 -54
  18. package/dist/lib/templates.js +1 -1
  19. package/dist/verbs/abandon.js +122 -0
  20. package/dist/verbs/agent.js +25 -25
  21. package/dist/verbs/build.js +9 -9
  22. package/dist/verbs/check.js +6 -6
  23. package/dist/verbs/checkpoint.js +48 -47
  24. package/dist/verbs/doctor.js +35 -29
  25. package/dist/verbs/finish.js +27 -40
  26. package/dist/verbs/handoff.js +9 -8
  27. package/dist/verbs/init.js +9 -9
  28. package/dist/verbs/park.js +3 -3
  29. package/dist/verbs/recover.js +12 -12
  30. package/dist/verbs/revert.js +12 -12
  31. package/dist/verbs/spike.js +21 -21
  32. package/dist/verbs/start.js +49 -19
  33. package/dist/verbs/status.js +8 -8
  34. package/dist/verbs/turn.js +16 -16
  35. package/dist/verbs/use.js +4 -4
  36. package/node_modules/checkride/.claude-plugin/plugin.json +1 -1
  37. package/node_modules/checkride/CHANGELOG.md +401 -0
  38. package/node_modules/checkride/README.md +27 -9
  39. package/node_modules/checkride/dist/adapters.d.ts +12 -4
  40. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  41. package/node_modules/checkride/dist/adapters.js +21 -1
  42. package/node_modules/checkride/dist/adapters.js.map +1 -1
  43. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +9 -1
  44. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -1
  45. package/node_modules/checkride/dist/agent-setup/cursor.js +59 -1
  46. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -1
  47. package/node_modules/checkride/dist/agent-setup/harness.d.ts +1 -1
  48. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -1
  49. package/node_modules/checkride/dist/agent-setup/harness.js +10 -1
  50. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -1
  51. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +23 -0
  52. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -1
  53. package/node_modules/checkride/dist/agent-setup/scripts.js +387 -82
  54. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -1
  55. package/node_modules/checkride/dist/baseline/fallow.js +2 -2
  56. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +14 -5
  57. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  58. package/node_modules/checkride/dist/baseline/fingerprint.js +58 -5
  59. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  60. package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
  61. package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
  62. package/node_modules/checkride/dist/baseline/history.js +232 -0
  63. package/node_modules/checkride/dist/baseline/history.js.map +1 -0
  64. package/node_modules/checkride/dist/baseline/index.d.ts +4 -2
  65. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  66. package/node_modules/checkride/dist/baseline/index.js +2 -1
  67. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  68. package/node_modules/checkride/dist/baseline/store.d.ts +30 -7
  69. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  70. package/node_modules/checkride/dist/baseline/store.js +50 -16
  71. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  72. package/node_modules/checkride/dist/cli.d.ts +5 -1
  73. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  74. package/node_modules/checkride/dist/cli.js +98 -25
  75. package/node_modules/checkride/dist/cli.js.map +1 -1
  76. package/node_modules/checkride/dist/config.d.ts +33 -4
  77. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  78. package/node_modules/checkride/dist/config.js +21 -6
  79. package/node_modules/checkride/dist/config.js.map +1 -1
  80. package/node_modules/checkride/dist/digest/digest.js +1 -1
  81. package/node_modules/checkride/dist/doctor.d.ts +2 -0
  82. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  83. package/node_modules/checkride/dist/doctor.js +39 -1
  84. package/node_modules/checkride/dist/doctor.js.map +1 -1
  85. package/node_modules/checkride/dist/gate.d.ts +49 -4
  86. package/node_modules/checkride/dist/gate.d.ts.map +1 -1
  87. package/node_modules/checkride/dist/gate.js +143 -16
  88. package/node_modules/checkride/dist/gate.js.map +1 -1
  89. package/node_modules/checkride/dist/init.d.ts +8 -1
  90. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  91. package/node_modules/checkride/dist/init.js +68 -7
  92. package/node_modules/checkride/dist/init.js.map +1 -1
  93. package/node_modules/checkride/dist/node-pin.d.ts +1 -1
  94. package/node_modules/checkride/dist/node-pin.js +1 -1
  95. package/node_modules/checkride/dist/orchestrator.d.ts +13 -0
  96. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  97. package/node_modules/checkride/dist/orchestrator.js +118 -13
  98. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  99. package/node_modules/checkride/dist/pm/index.d.ts +1 -0
  100. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  101. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  102. package/node_modules/checkride/dist/pm/launch.d.ts +23 -2
  103. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -1
  104. package/node_modules/checkride/dist/pm/launch.js +16 -0
  105. package/node_modules/checkride/dist/pm/launch.js.map +1 -1
  106. package/node_modules/checkride/dist/pm/translate.js +1 -1
  107. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  108. package/node_modules/checkride/dist/qa/mutation.d.ts +4 -4
  109. package/node_modules/checkride/dist/qa/mutation.js +4 -4
  110. package/node_modules/checkride/dist/recover.d.ts +48 -0
  111. package/node_modules/checkride/dist/recover.d.ts.map +1 -0
  112. package/node_modules/checkride/dist/recover.js +220 -0
  113. package/node_modules/checkride/dist/recover.js.map +1 -0
  114. package/node_modules/checkride/dist/smoke.d.ts +1 -1
  115. package/node_modules/checkride/dist/smoke.js +1 -1
  116. package/node_modules/checkride/dist/snippets.d.ts +1 -1
  117. package/node_modules/checkride/package.json +3 -2
  118. package/node_modules/checkride/schema/checkride.config.schema.json +9 -1
  119. package/node_modules/checkride/skills/check/SKILL.md +9 -1
  120. package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
  121. package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
  122. package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
  123. package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
  124. package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
  125. package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
  126. package/node_modules/checkride/templates/shared/vale.ini +34 -0
  127. package/package.json +13 -11
  128. package/skills/abandon/SKILL.md +20 -0
  129. package/skills/build/SKILL.md +69 -64
  130. package/skills/doctor/SKILL.md +11 -11
  131. package/skills/finish/SKILL.md +20 -19
  132. package/skills/harvest/SKILL.md +13 -12
  133. package/skills/park/SKILL.md +10 -10
  134. package/skills/plan/SKILL.md +63 -54
  135. package/skills/recover/SKILL.md +7 -7
  136. package/skills/refine/SKILL.md +18 -16
  137. package/skills/revert/SKILL.md +6 -6
  138. package/skills/spike/SKILL.md +9 -9
  139. package/skills/status/SKILL.md +5 -5
  140. package/skills/step/SKILL.md +17 -12
  141. package/skills/verify/SKILL.md +45 -40
  142. package/templates/build-log.md +7 -7
  143. package/templates/intent.md +49 -39
  144. package/templates/spike-report.md +10 -10
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "plumbbob",
3
3
  "displayName": "PlumbBob",
4
- "version": "0.9.5",
4
+ "version": "0.10.1",
5
5
  "description": "Attention-first build process — driver skills + a CLI that keep you the decider: guidance on the work, a latch on the record.",
6
6
  "author": { "name": "Rob McLarty", "email": "hello@robmclarty.com", "url": "https://robmclarty.com" },
7
7
  "homepage": "https://github.com/robmclarty/plumbbob#readme",
package/README.md CHANGED
@@ -10,20 +10,20 @@
10
10
  <a href="https://robmclarty.github.io/plumbbob/api.html">API reference</a>
11
11
  </p>
12
12
 
13
- PlumbBob is a Claude Code plugin — thirteen skills and a small CLI — that runs
13
+ PlumbBob is a Claude Code plugin (fourteen skills and a small CLI) that runs
14
14
  LLM-assisted coding as a loop you control. You and the model settle the plan in a file
15
15
  *before* any code; then the model builds one small step at a time and **stops after
16
16
  each one**, waiting for you to read the diff and approve it before anything is
17
- committed. It's built for the small-to-medium work that fills most days — a feature, a
18
- bug, a refactor — where a fully autonomous build is overkill but freestyle prompting
17
+ committed. It's built for the small-to-medium work that fills most days (a feature, a
18
+ bug, a refactor) where a fully autonomous build is overkill but freestyle prompting
19
19
  leaves you dragged behind the model, reacting instead of deciding.
20
20
 
21
21
  > Establish *plumb* before you build. The LLM is a hand, not a head.
22
22
 
23
23
  Its one law is **vibe to execute, never vibe to decide**: the human owns every
24
24
  decision, the LLM owns the labor, and the boundary between them is a **pause you
25
- advance**, not a wall that refuses you. The *why* behind that — attention as the scarce
26
- resource — is in [`docs/attention-first-development.md`](docs/attention-first-development.md).
25
+ advance**, not a wall that refuses you. The *why* behind that (attention as the scarce
26
+ resource) is in [`docs/attention-first-development.md`](docs/attention-first-development.md).
27
27
  PlumbBob is the layer below [Ridgeline](https://github.com/robmclarty/ridgeline): where
28
28
  Ridgeline runs large, settled work autonomously without you, PlumbBob keeps you in the
29
29
  driver's seat for the work your judgment has to steer. This repository was built using
@@ -32,24 +32,24 @@ PlumbBob itself, running its own loop.
32
32
  ## What a prompt can't replicate
33
33
 
34
34
  A system prompt can *ask* a model to plan first and stop for review. What it can't do is
35
- **hold the line when the model doesn't** — and that mechanical half is what PlumbBob adds
35
+ **hold the line when the model doesn't**, and that mechanical half is what PlumbBob adds
36
36
  under the skills. Five deterministic edges, enforced by the CLI and git rather than by the
37
37
  model's goodwill:
38
38
 
39
39
  - **A gate that refuses red.** `checkpoint` won't record a step while the check gate is
40
- red, and `start` refuses a dirty tree — the [checkride](https://www.npmjs.com/package/checkride)
40
+ red, and `start` refuses a dirty tree: the [checkride](https://www.npmjs.com/package/checkride)
41
41
  run (types, lint, tests, dead code, docs) has to pass before a step lands.
42
42
  - **One SHA per verified step.** Every approved step is its own git commit against a
43
- recorded baseline — a ledger of checkpoints, not one undifferentiated diff at the end.
43
+ recorded baseline: a ledger of checkpoints, not one undifferentiated diff at the end.
44
44
  - **A preservation-aware revert.** `/plumbbob:revert` resets exactly to a recorded checkpoint
45
45
  SHA while keeping your plan and notes intact, and restores *only* SHAs the loop wrote.
46
- - **A build record that rides the PR.** The tracked `builds/<slug>/` folder — intent, log,
47
- checkpoints, report — merges into `main` with the branch instead of dying with the
46
+ - **A build record that rides the PR.** The tracked `builds/<slug>/` folder (intent, log,
47
+ checkpoints, report) merges into `main` with the branch instead of dying with the
48
48
  worktree; the archive never destroys.
49
49
  - **The approval latch.** `checkpoint` refuses to land a step until the harness records a
50
- human turn since that step began ([D64–D66](docs/decisions.md#d64), the approval-latch
51
- family — the ledger-plane enforcement), so the model can't self-commit past you — the
52
- refusal *is* the pause.
50
+ human turn since that step began ([D64 (approval-latch)](docs/decisions.md#d64)–[D66
51
+ (oob-commits-surfaced)](docs/decisions.md#d66), the ledger-plane enforcement), so the
52
+ model can't self-commit past you: the refusal *is* the pause.
53
53
 
54
54
  The planning surface is the on-ramp; these five are the floor under it. And the latch's
55
55
  payoff is [measured, not asserted](#why-not-just), not just claimed. **Guidance on the
@@ -64,7 +64,7 @@ work, a latch on the record.**
64
64
  Everything the model must stay true to lives in one file, the build's `intent.md`
65
65
  (under `.plumbbob/builds/<slug>/`), written before any code: the **Frame** (the problem, what done looks like, what you're
66
66
  explicitly *not* doing), the **Decisions** and **Constraints** (the settled calls, each
67
- with its *because*), and the **Steps** — a numbered list where every step carries a
67
+ with its *because*), and the **Steps**: a numbered list where every step carries a
68
68
  **done-when** (a checkable finish line, ideally a test) and a **seam** (the files it's
69
69
  expected to touch).
70
70
 
@@ -76,16 +76,16 @@ expected to touch).
76
76
  /plumbbob:finish report what shipped and why, final commit, clear (once)
77
77
  ```
78
78
 
79
- Nothing is locked and nothing refuses you — the loop does a step's labor, pulls up to
79
+ Nothing is locked and nothing refuses you: the loop does a step's labor, pulls up to
80
80
  the line, and waits for you to advance it. **You are the clock.**
81
81
 
82
82
  ## Install
83
83
 
84
- PlumbBob installs **once, globally** — like `gh` or your dotfiles. There are two ways;
84
+ PlumbBob installs **once, globally** (like `gh` or your dotfiles). Two ways work;
85
85
  pick one (both register a Claude Code plugin named `plumbbob`, so running both
86
86
  collides).
87
87
 
88
- **Marketplace plugin** — Claude Code installs the published `plumbbob` package for you
88
+ **Marketplace plugin**: Claude Code installs the published `plumbbob` package for you
89
89
  (skills, hook, and the CLI on PATH), so you run no `npm i -g` and no `init`:
90
90
 
91
91
  ```text
@@ -93,7 +93,7 @@ collides).
93
93
  /plugin install plumbbob@robmclarty
94
94
  ```
95
95
 
96
- **npm global + `init`** — installs the CLI, then links the skills and hook into Claude
96
+ **npm global + `init`**: installs the CLI, then links the skills and hook into Claude
97
97
  Code in place:
98
98
 
99
99
  ```sh
@@ -102,15 +102,15 @@ plumbbob init # link it into Claude Code; --uninstall to undo
102
102
  ```
103
103
 
104
104
  Restart Claude Code (or `/reload-plugins`) to activate, then run `plumbbob doctor`
105
- (or `/plumbbob:doctor` in-session) to confirm the wiring. The full guide — namespacing,
106
- per-project sessions, the agent-neutral roadmap — is in
105
+ (or `/plumbbob:doctor` in-session) to confirm the wiring. The full guide (namespacing,
106
+ per-project sessions, the agent-neutral roadmap) is in
107
107
  [`docs/install.md`](docs/install.md).
108
108
 
109
109
  ## Your first session
110
110
 
111
111
  In Claude Code, inside any git repo with a clean tree:
112
112
 
113
- 1. **Plan.** Fire `/plumbbob:plan` and give it whatever you have — nothing (it interviews
113
+ 1. **Plan.** Fire `/plumbbob:plan` and give it whatever you have: nothing (it interviews
114
114
  you), a rough line (`/plumbbob:plan rate-limit POST /login, 5/min/IP, return 429`), or a
115
115
  path to a spec file. Together you fill the build's `intent.md`. No code is written
116
116
  yet.
@@ -121,17 +121,17 @@ In Claude Code, inside any git repo with a clean tree:
121
121
  PAUSE — read the diff as an editor. Approve to checkpoint, or send fixes.
122
122
  ```
123
123
 
124
- (The check gate is [checkride](https://www.npmjs.com/package/checkride) — one
124
+ (The check gate is [checkride](https://www.npmjs.com/package/checkride), one
125
125
  run across the tools your repo already configures: types, lint, tests, dead
126
126
  code, docs. To gate through your own command instead, set the `"check"` key in
127
- `.plumbbob/settings.json`, e.g. `"check": "npm test"`.)
128
- 3. **Approve** — or send fixes. On your OK it commits the step as a checkpoint, marks
129
- it done, and returns to the boundary. Fire `/plumbbob:build` again for the next step —
127
+ `.plumbbob/settings.json`, for example `"check": "npm test"`.)
128
+ 3. **Approve**, or send fixes. On your OK it commits the step as a checkpoint, marks
129
+ it done, and returns to the boundary. Fire `/plumbbob:build` again for the next step:
130
130
  re-firing it *is* the clock tick. Whenever you lose the thread, `/plumbbob:status` shows
131
131
  where you are and names the next move.
132
132
  4. **Finish.** When the last step is done, `/plumbbob:finish` writes a report of what shipped
133
133
  and why into the build's tracked folder, makes the final commit, and clears the slate
134
- for the next goal. The folder rides the branch into the PR — the build's record merges
134
+ for the next goal. The folder rides the branch into the PR: the build's record merges
135
135
  into `main` instead of dying with the worktree.
136
136
 
137
137
  A mid-build "ooh, what if…" never derails the step: `/plumbbob:park` captures it to a list
@@ -141,23 +141,23 @@ end, with the real output at every stage, is in
141
141
 
142
142
  ## The skills
143
143
 
144
- You drive the whole loop from your IDE with `/plumbbob:*` skills — no step numbers to
144
+ You drive the whole loop from your IDE with `/plumbbob:*` skills: no step numbers to
145
145
  remember, no raw CLI to type. Every skill is `disable-model-invocation`, so *you* fire
146
146
  every move, and `/plumbbob:status` always names your next one. (Claude Code namespaces
147
147
  them under the plugin, so the command is `/plumbbob:plan`. The bare `/plan` reaches it
148
- too — but only where nothing else owns that name, and four of the thirteen share one with
148
+ too, but only where nothing else owns that name, and four of the fourteen share one with
149
149
  a Claude Code built-in, so these docs write the full form.)
150
150
 
151
- **The happy path** — the three moves every session makes; many sessions need
151
+ **The happy path**: the three moves every session makes; many sessions need
152
152
  nothing else:
153
153
 
154
154
  | Skill <img alt="" width="110" height="1"> | Does |
155
155
  |------------------------------------|------|
156
- | `/plumbbob:plan` | plan the whole goal — open the session and author intent's Frame, Decisions, Constraints, **and all Steps** |
157
- | `/plumbbob:build` | implement the next planned step, then verify it to the pause — `--auto` self-approves and chains to done; a range like `1-3` self-approves through step 3, then pauses |
158
- | `/plumbbob:finish` | finish up — write the report, make the final commit, clear for a fresh goal |
156
+ | `/plumbbob:plan` | plan the whole goal: open the session and author intent's Frame, Decisions, Constraints, **and all Steps** |
157
+ | `/plumbbob:build` | implement the next planned step, then verify it to the pause: `--auto` self-approves and chains to done; a range like `1-3` self-approves through step 3, then pauses |
158
+ | `/plumbbob:finish` | finish up: write the report, make the final commit, clear for a fresh goal |
159
159
 
160
- **Plan-shaping moves** — optional, for when the plan needs work mid-flight:
160
+ **Plan-shaping moves**: optional, for when the plan needs work mid-flight:
161
161
 
162
162
  | Skill <img alt="" width="110" height="1"> | Does |
163
163
  |------------------------------------|------|
@@ -165,49 +165,50 @@ nothing else:
165
165
  | `/plumbbob:refine` | attack the frame for holes, or repair a drifted plan |
166
166
  | `/plumbbob:spike` | throwaway worktree experiment for a fork the plan can't settle |
167
167
 
168
- **Helpers** — orient, verify, recover, diagnose:
168
+ **Helpers**: orient, verify, recover, diagnose:
169
169
 
170
170
  | Skill <img alt="" width="110" height="1"> | Does |
171
171
  |------------------------------------|------|
172
- | `/plumbbob:status` | orient — where you are, the next step's done-when and seam, and the next move |
173
- | `/plumbbob:verify` | the tick, standalone — check → self-review → validate → **PAUSE** → checkpoint, for a diff `/plumbbob:build` didn't write |
174
- | `/plumbbob:revert` | rewind — `git reset --hard` to a recorded checkpoint |
172
+ | `/plumbbob:status` | orient: where you are, the next step's done-when and seam, and the next move |
173
+ | `/plumbbob:verify` | the tick, standalone: check → self-review → validate → **PAUSE** → checkpoint, for a diff `/plumbbob:build` didn't write |
174
+ | `/plumbbob:revert` | rewind: `git reset --hard` to a recorded checkpoint |
175
+ | `/plumbbob:abandon` | drop the in-flight step, keep its work in the tree; the step stays planned |
175
176
  | `/plumbbob:recover` | reconcile the session's own state when the dashboard looks wrong |
176
177
  | `/plumbbob:doctor` | check the install from inside a session |
177
178
 
178
- **Capture** — the park/harvest loop for mid-build ideas:
179
+ **Capture**: the park/harvest loop for mid-build ideas:
179
180
 
180
181
  | Skill <img alt="" width="110" height="1"> | Does |
181
182
  |------------------------------------|------|
182
183
  | `/plumbbob:park` | capture a mid-build idea without chasing it |
183
184
  | `/plumbbob:harvest` | triage parked ideas between steps (blocker / tangent / pivot) |
184
185
 
185
- All thirteen, with inputs and effects, are in
186
+ All fourteen, with inputs and effects, are in
186
187
  [`docs/skills-reference.md`](docs/skills-reference.md).
187
188
 
188
189
  Under the skills ships a lean `plumbbob` CLI (the mechanical verbs the
189
190
  skills shell out to), one session-gated post-edit hook (non-blocking lint feedback in
190
- flow), and a `.plumbbob/` sidecar you can open and edit by hand at any time — a tracked
191
+ flow), and a `.plumbbob/` sidecar you can open and edit by hand at any time: a tracked
191
192
  `builds/<slug>/` folder per build (`intent.md`, `build-log.md`, `checkpoints`, `report.md`)
192
193
  that rides the branch into the PR, plus an untracked control plane (`settings.local.json`,
193
194
  the session sentinel, the in-flight markers).
194
195
 
195
- **`/plumbbob:build` is the default engine, not the only one.** It's one executor — the
196
- loop doesn't care who writes the code. Implement a step by hand — or vibe it in
197
- another session, or in another harness entirely — and run `/plumbbob:verify` instead:
196
+ **`/plumbbob:build` is the default engine, not the only one.** It's one executor: the
197
+ loop doesn't care who writes the code. Implement a step by hand (or vibe it in
198
+ another session, or in another harness entirely) and run `/plumbbob:verify` instead:
198
199
  same checks, same pause, same checkpoint. It reads the *diff, not the author*.
199
200
 
200
201
  **Bring your own agents.** Because the executor is author-blind, you can plug your
201
202
  own in. A **user-authored agent** is any executable that speaks one small JSON
202
203
  envelope; drop it under `.plumbbob/agents/`, bind it to a step's `before`, `build`,
203
204
  or `after` slot in the build's `harness.json`, and PlumbBob runs it through the same
204
- pause — with **no way for it to advance the loop** (checkride still gates, you're
205
+ pause, with **no way for it to advance the loop** (checkride still gates, you're
205
206
  still the clock). The full contract for authors, with a copy-paste example, is in
206
207
  [`docs/agents.md`](docs/agents.md).
207
208
 
208
209
  ## Why "PlumbBob"
209
210
 
210
- The name is the method. A plumb bob is a weight on a string — gravity pulls it into a
211
+ The name is the method. A plumb bob is a weight on a string; gravity pulls it into a
211
212
  perfectly straight vertical line, the builder's oldest reference for *true*: the fixed
212
213
  mark you hold the work against so it never drifts out of square. PlumbBob hangs your
213
214
  **intent** as that line and keeps every step aligned to it, so the build stays plumb
@@ -217,90 +218,91 @@ with what you decided instead of wandering off behind the model.
217
218
 
218
219
  The questions a skeptic should ask, answered straight.
219
220
 
220
- **…use plan mode?** Plan mode is the same instinct — decide before executing —
221
+ **…use plan mode?** Plan mode is the same instinct (decide before executing),
221
222
  scoped to one session. The plan lives in the chat, so it fades with the context
222
223
  window, and the approval gates the *start* of the work, not each increment of it.
223
224
  PlumbBob puts the plan in a file in your repo that survives compaction, restarts,
224
- and next week; moves the approval to **every step** — each checked, reviewed
225
- against the plan, and committed as its own checkpoint, so a wrong turn costs one
225
+ and next week; moves the approval to **every step** (each checked, reviewed
226
+ against the plan, and committed as its own checkpoint), so a wrong turn costs one
226
227
  step, not the afternoon; and records the *whys* alongside the decisions, so the
227
228
  archive can still answer "what did we decide, and why" long after the session is
228
- gone. The two compose fine: plan mode — or anything else — can produce a step's
229
+ gone. The two compose fine: plan mode (or anything else) can produce a step's
229
230
  diff, and `/plumbbob:verify` reads it like any other.
230
231
 
231
232
  **…use git and a TODO file?** That's the honest skeleton, and if your discipline
232
233
  holds by willpower alone, it may be all you need. What the CLI adds is the
233
- [mechanical half of the discipline](#what-a-prompt-cant-replicate) — the five edges up
234
- top — so willpower is spent only at the pause. The one not on that list: a status
234
+ [mechanical half of the discipline](#what-a-prompt-cant-replicate) (the five edges up
235
+ top), so willpower is spent only at the pause. The one not on that list: a status
235
236
  dashboard re-injected into every skill, so the model re-orients on each move without you
236
237
  re-explaining the state.
237
238
 
238
- **…wait for a vendor to ship this natively?** They're converging on it — plan
239
- modes, spec kits, native checkpoints — and that convergence is evidence *for* the
239
+ **…wait for a vendor to ship this natively?** They're converging on it (plan
240
+ modes, spec kits, native checkpoints), and that convergence is evidence *for* the
240
241
  premise. PlumbBob is deliberately thin against that future: the artifacts are
241
242
  plain markdown and ordinary git commits in your own repo, the CLI is lean
242
243
  (node builtins plus one deliberate dependency), and nothing locks you in. The
243
- investment is small — thirteen
244
- skills over a plain-markdown sidecar, learnable in an afternoon — and what you're
244
+ investment is small (fourteen
245
+ skills over a plain-markdown sidecar, learnable in an afternoon), and what you're
245
246
  actually learning is the method: decisions before code, one verified step at a
246
247
  time, capture instead of chase. That transfers to whatever tool wins. If
247
248
  something better ships, you walk away with your archives and your habits intact.
248
249
 
249
- **…admit the pause is unenforceable?** On the **work** plane, yes — on purpose
250
+ **…admit the pause is unenforceable?** On the **work** plane, yes, on purpose
250
251
  ([D10 (pause-not-lock)](docs/decisions.md#d10)/[D13 (no-edit-guards)](docs/decisions.md#d13) in
251
252
  [`docs/decisions.md`](docs/decisions.md)): a hard lock on every edit buys ritual, not
252
253
  control, because a determined model routes around it and a denial mid-thought leaves no
253
254
  legal move. But the **record** is a different plane, and there the tick *is* latched
254
- ([D64–D66](docs/decisions.md#d64), the approval-latch family): `checkpoint` refuses to land a step until the harness
255
- records a human turn since that step began, so the agent cannot self-commit past you —
255
+ ([D64 (approval-latch)](docs/decisions.md#d64)–[D66 (oob-commits-surfaced)](docs/decisions.md#d66)): `checkpoint` refuses to land a step until the harness
256
+ records a human turn since that step began, so the agent cannot self-commit past you:
256
257
  the refusal simply *is* the pause. It extends the [deterministic edges above](#what-a-prompt-cant-replicate)
257
258
  to the one boundary the product is named after, while leaving human what must be human:
258
259
  you, reading the diff. And when a raw commit does slip the ledger, `status` says so and the
259
- checkpoint record makes recovery one command — cheap recovery, not a cage, is the control
260
+ checkpoint record makes recovery one command; cheap recovery, not a cage, is the control
260
261
  that matters.
261
262
 
262
263
  > The latch's payoff is measured, not asserted: the skill-eval harness
263
- > ([`test/evals/`](test/evals/)) sweeps this loop headless — prose-only baseline vs. the
264
- > shipped latch, N=5 per contract, every assertion a mechanical read of git state — and
264
+ > ([`test/evals/`](test/evals/)) sweeps this loop headless (prose-only baseline vs. the
265
+ > shipped latch, N=5 per contract, every assertion a mechanical read of git state) and
265
266
  > commits each receipt under [`docs/evals/`](docs/evals/). The first sweep
266
- > ([opus, 2026-07-11](docs/evals/2026-07-11.md)) closed the route the latch owns —
267
- > *no checkpoint over a red check under pressure* went from **2/5 prose-only to 5/5
268
- > latched** — and named, rather than papered over, the two honest gaps it surfaced: park
267
+ > ([opus, 2026-07-11](docs/evals/2026-07-11.md)) closed the route the latch owns
268
+ > (*no checkpoint over a red check under pressure* went from **2/5 prose-only to 5/5
269
+ > latched**) and named, rather than papered over, the two honest gaps it surfaced: park
269
270
  > capture at 0/5, and adversarial pressure flipping a standing `auto` grant a model could
270
271
  > write into settings, a legal side door. The re-sweep
271
- > ([opus, 2026-07-18](docs/evals/2026-07-18.md), plumbbob 0.8.7) reproduced the win —
272
- > *no checkpoint over a red check* still **5/5 latched** — and pinned both gaps. Both are
272
+ > ([opus, 2026-07-18](docs/evals/2026-07-18.md), plumbbob 0.8.7) reproduced the win
273
+ > (*no checkpoint over a red check* still **5/5 latched**) and pinned both gaps. Both are
273
274
  > now closed. The side door went by construction: [D67 (auto-not-a-grant)](docs/decisions.md#d67)
274
275
  > (self-approval is human-typed only) retired the settings `auto` grant, so the one
275
- > approval a model could forge is gone. Park capture was never the latch's to reach —
276
- > prose-governed by design ([D10 (pause-not-lock)](docs/decisions.md#d10)/[D13 (no-edit-guards)](docs/decisions.md#d13)) —
276
+ > approval a model could forge is gone. Park capture was never the latch's to reach,
277
+ > prose-governed by design ([D10 (pause-not-lock)](docs/decisions.md#d10)/[D13 (no-edit-guards)](docs/decisions.md#d13)),
277
278
  > and it failed because the guidance couldn't reach a fresh session at all; the turn hook
278
279
  > now injects one line when a step is in flight, and the third sweep
279
280
  > ([opus, 2026-07-27](docs/evals/2026-07-27.md), plumbbob 0.9.0) measures it at **5/5**,
280
281
  > alongside every other contract. That sweep ran the latched arm only, so its numbers are
281
- > a regression check on the shipped configuration, not a fresh baseline delta — the
282
+ > a regression check on the shipped configuration, not a fresh baseline delta: the
282
283
  > 2/5→5/5 headline above remains the 2026-07-11 measurement.
283
284
 
284
285
  ## Documentation
285
286
 
286
- Each doc answers one question — in rough reading order for a new user:
287
-
288
- - *What does a session actually look like?* → [`docs/happy-path.md`](docs/happy-path.md) — one goal walked end to end; read this first.
289
- - *Show me the artifacts it leaves behind.* → [`examples/`](examples/) — that same session's finished build folder, file by file.
290
- - *Should I / can I / what about…?* → [`docs/faq.md`](docs/faq.md) — the adoption questions, answered straight.
291
- - *What is each method for?* → [`docs/techniques.md`](docs/techniques.md) — steps, seams, the pause, park/harvest, spikes.
292
- - *What does each skill do?* → [`docs/skills-reference.md`](docs/skills-reference.md) — all thirteen skills: inputs, effects, when to reach for each.
293
- - *How do I plug in my own agent?* → [`docs/agents.md`](docs/agents.md) — the subprocess envelope, the manifest, `harness.json`, and working examples (including a local-model reviewer via Ollama).
294
- - *How do I get a local model reviewing my steps?* → [`docs/local-model-review.md`](docs/local-model-review.md) — the ollama-reviewer example walked end to end, install to every-pause review.
295
- - *How do I install it, exactly?* → [`docs/install.md`](docs/install.md) — the full guide and the agent-neutral roadmap.
296
- - *What does the CLI underneath do?* → [`docs/cli-reference.md`](docs/cli-reference.md) — every verb, flag, exit code, and the `.plumbbob/` sidecar.
297
- - *What are these untracked files, and why is it touching my `.git`?* → [`docs/state-and-git.md`](docs/state-and-git.md) — the state files, the `info/exclude` mechanism, and the objections answered.
298
- - *Something's broken.* → [`docs/troubleshooting.md`](docs/troubleshooting.md) — fixes for the common snags.
299
- - *Why is it built this way?* → [`docs/decisions.md`](docs/decisions.md) — the `D#` / `C#` design-decision key the source cites.
300
- - *How does it hang together inside?* → [`docs/architecture.md`](docs/architecture.md) — the layers and planes, for contributors (in progress).
301
- - *Why does this exist at all?* → [`docs/attention-first-development.md`](docs/attention-first-development.md) — the philosophy: attention as the scarce resource.
302
- - *What does it run on my machine?* → [`SECURITY.md`](SECURITY.md) — execution surface and how to report a vulnerability.
303
- - *How do I contribute?* → [`CONTRIBUTING.md`](CONTRIBUTING.md) — setup, conventions, and how to submit changes.
287
+ Each doc answers one question (in rough reading order for a new user):
288
+
289
+ - *What does a session actually look like?* → [`docs/happy-path.md`](docs/happy-path.md): one goal walked end to end; read this first.
290
+ - *Show me the artifacts it leaves behind.* → [`examples/`](examples/): that same session's finished build folder, file by file.
291
+ - *Should I / can I / what about…?* → [`docs/faq.md`](docs/faq.md): the adoption questions, answered straight.
292
+ - *What is each method for?* → [`docs/techniques.md`](docs/techniques.md): steps, seams, the pause, park/harvest, spikes.
293
+ - *What does each skill do?* → [`docs/skills-reference.md`](docs/skills-reference.md): all fourteen skills: inputs, effects, when to reach for each.
294
+ - *How do I plug in my own agent?* → [`docs/agents.md`](docs/agents.md): the subprocess envelope, the manifest, `harness.json`, and working examples (including a local-model reviewer via Ollama).
295
+ - *How do I get a local model reviewing my steps?* → [`docs/local-model-review.md`](docs/local-model-review.md): the ollama-reviewer example walked end to end, install to every-pause review.
296
+ - *How do I install it, exactly?* → [`docs/install.md`](docs/install.md): the full guide and the agent-neutral roadmap.
297
+ - *What does the CLI underneath do?* → [`docs/cli-reference.md`](docs/cli-reference.md): every verb, flag, exit code, and the `.plumbbob/` sidecar.
298
+ - *What are these untracked files, and why is it touching my `.git`?* → [`docs/state-and-git.md`](docs/state-and-git.md): the state files, the `info/exclude` mechanism, and the objections answered.
299
+ - *Something's broken.* → [`docs/troubleshooting.md`](docs/troubleshooting.md): fixes for the common snags.
300
+ - *Why is it built this way?* → [`docs/decisions.md`](docs/decisions.md): the `D#` / `C#` design-decision key the source cites.
301
+ - *How does it hang together inside?* → [`docs/architecture.md`](docs/architecture.md): the layers and planes, for contributors (in progress).
302
+ - *Why does this exist at all?* → [`docs/attention-first-development.md`](docs/attention-first-development.md): the philosophy: attention as the scarce resource.
303
+ - *Why does AI-written prose get worse over time?* → [`docs/generation-loss.md`](docs/generation-loss.md): the copy-of-a-copy problem, and why anchor texts are written by hand.
304
+ - *What does it run on my machine?* → [`SECURITY.md`](SECURITY.md): execution surface and how to report a vulnerability.
305
+ - *How do I contribute?* → [`CONTRIBUTING.md`](CONTRIBUTING.md): setup, conventions, and how to submit changes.
304
306
 
305
307
  ## License
306
308
 
package/dist/cli-core.js CHANGED
@@ -1,12 +1,12 @@
1
- // plumbbob CLI core — argv dispatch and the help table, separated from the bin
1
+ // plumbbob CLI core: argv dispatch and the help table, separated from the bin
2
2
  // entry (cli.ts) so the routing/help logic is unit-testable in-process without
3
3
  // the top-level process.exit. Node builtins plus a deliberate few dependencies
4
4
  // (currently checkride alone, via check.ts). Functional/procedural: no classes,
5
5
  // no `this`, no default export.
6
6
  //
7
7
  // The deciding/executing boundary is a pause, not a lock, so there is nothing
8
- // to defend in the dispatcher — every verb runs the same whether a human or the
9
- // model triggers it. There is no human-only `mode` escape hatch and no
8
+ // to defend in the dispatcher; every verb runs the same whether a human or the
9
+ // model triggers it. No human-only `mode` escape hatch exists and no
10
10
  // CLAUDECODE in-session refusal; what keeps the human the decider is the pause
11
11
  // at the step boundary (the skills), not a refusal here.
12
12
  import { readFileSync } from 'node:fs';
@@ -19,6 +19,7 @@ import { handoff } from "./verbs/handoff.js";
19
19
  import { check } from "./verbs/check.js";
20
20
  import { checkpoint } from "./verbs/checkpoint.js";
21
21
  import { revert } from "./verbs/revert.js";
22
+ import { abandon } from "./verbs/abandon.js";
22
23
  import { spike } from "./verbs/spike.js";
23
24
  import { use } from "./verbs/use.js";
24
25
  import { finish } from "./verbs/finish.js";
@@ -38,7 +39,7 @@ const BUILD_FLAG = {
38
39
  *
39
40
  * One table drives three things: the top-level verb table, per-verb `--help`,
40
41
  * and the unknown-flag refusal in `run`. Keeping it as data rather than inline
41
- * writes is the deliberate exception to the write-at-the-call-site convention —
42
+ * writes is the deliberate exception to the write-at-the-call-site convention;
42
43
  * a synopsis has to be readable by the validator, not just printable.
43
44
  */
44
45
  const VERBS = [
@@ -113,6 +114,13 @@ const VERBS = [
113
114
  ],
114
115
  notes: 'Refuses (exit 1) with no session, an invalid --to, or a step with no recorded checkpoint.',
115
116
  },
117
+ {
118
+ name: 'abandon',
119
+ description: 'drop the in-flight step but keep its work in the tree',
120
+ synopsis: ['abandon [--build <slug>]'],
121
+ flags: [BUILD_FLAG],
122
+ notes: 'Refuses (exit 1) with no session, no step in flight, or a latched boundary (no human turn since the step began). Clears STEP/SEAM/TICK/handoff and logs the abandon; never touches the working tree, git, or the intent checkbox.',
123
+ },
116
124
  {
117
125
  name: 'park',
118
126
  description: 'append a raw line to the park list',
@@ -255,7 +263,7 @@ export function verbSpec(name) {
255
263
  return VERBS.find((v) => v.name === name) ?? null;
256
264
  }
257
265
  /**
258
- * Every verb name, in table order — the contract tests iterate this.
266
+ * Every verb name, in table order: the contract tests iterate this.
259
267
  */
260
268
  export function verbNames() {
261
269
  return VERBS.map((v) => v.name);
@@ -331,6 +339,8 @@ async function dispatch(verb, cwd, rest) {
331
339
  return checkpoint(cwd, rest);
332
340
  case 'revert':
333
341
  return revert(cwd, rest);
342
+ case 'abandon':
343
+ return abandon(cwd, rest);
334
344
  case 'spike':
335
345
  return spike(cwd, rest);
336
346
  case 'use':
@@ -363,8 +373,8 @@ async function dispatch(verb, cwd, rest) {
363
373
  * report and exit 1, so the bin entry only ever exits with the code returned
364
374
  * here.
365
375
  *
366
- * `cwd` is the repo the verbs act on. It defaults to the process's — the only
367
- * thing the bin entry ever wants — and is a parameter solely so a test can name
376
+ * `cwd` is the repo the verbs act on. It defaults to the process's (the only
377
+ * thing the bin entry ever wants) and is a parameter solely so a test can name
368
378
  * a fixture. Screening argv does not help when the argv is *valid*: `checkpoint
369
379
  * -m --help` reads `--help` as the subject, exactly as it should, and then
370
380
  * commits. Whose repo it commits is decided here, and a default is not a choice
@@ -374,7 +384,7 @@ export async function run(argv, cwd = process.cwd()) {
374
384
  const verb = argv[0] ?? 'help';
375
385
  const rest = argv.slice(1);
376
386
  if (verb === 'help' || verb === '--help' || verb === '-h') {
377
- // `plumbbob help <verb>` is the same page as `plumbbob <verb> --help` —
387
+ // `plumbbob help <verb>` is the same page as `plumbbob <verb> --help`;
378
388
  // both spellings get typed, so both work.
379
389
  const topic = rest.find((a) => !a.startsWith('-'));
380
390
  if (topic === undefined) {
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // plumbbob CLI entry — the published bin. All routing and the help table live in
2
+ // plumbbob CLI entry: the published bin. All routing and the help table live in
3
3
  // cli-core.ts (unit-tested in-process); this file is only the executable shell:
4
4
  // it wires argv to the dispatcher and turns the returned code into the exit code.
5
5
  // Keeping the single process.exit here is what lets cli-core.ts be imported by a