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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +89 -87
- package/dist/cli-core.js +18 -8
- package/dist/cli.js +1 -1
- package/dist/lib/agents.js +26 -26
- package/dist/lib/buildlog.js +21 -11
- package/dist/lib/buildlogsync.js +8 -8
- package/dist/lib/check.js +14 -14
- package/dist/lib/commitbody.js +72 -0
- package/dist/lib/commitmsg.js +7 -7
- package/dist/lib/git.js +44 -15
- package/dist/lib/intent.js +20 -19
- package/dist/lib/latch.js +16 -16
- package/dist/lib/orient.js +36 -17
- package/dist/lib/reentry.js +3 -3
- package/dist/lib/settings.js +16 -16
- package/dist/lib/sidecar.js +70 -54
- package/dist/lib/templates.js +1 -1
- package/dist/verbs/abandon.js +122 -0
- package/dist/verbs/agent.js +25 -25
- package/dist/verbs/build.js +9 -9
- package/dist/verbs/check.js +6 -6
- package/dist/verbs/checkpoint.js +48 -47
- package/dist/verbs/doctor.js +35 -29
- package/dist/verbs/finish.js +27 -40
- package/dist/verbs/handoff.js +9 -8
- package/dist/verbs/init.js +9 -9
- package/dist/verbs/park.js +3 -3
- package/dist/verbs/recover.js +12 -12
- package/dist/verbs/revert.js +12 -12
- package/dist/verbs/spike.js +21 -21
- package/dist/verbs/start.js +49 -19
- package/dist/verbs/status.js +8 -8
- package/dist/verbs/turn.js +16 -16
- package/dist/verbs/use.js +4 -4
- package/node_modules/checkride/.claude-plugin/plugin.json +1 -1
- package/node_modules/checkride/CHANGELOG.md +401 -0
- package/node_modules/checkride/README.md +27 -9
- package/node_modules/checkride/dist/adapters.d.ts +12 -4
- package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
- package/node_modules/checkride/dist/adapters.js +21 -1
- package/node_modules/checkride/dist/adapters.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts +9 -1
- package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/cursor.js +59 -1
- package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/harness.d.ts +1 -1
- package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/harness.js +10 -1
- package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -1
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts +23 -0
- package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -1
- package/node_modules/checkride/dist/agent-setup/scripts.js +387 -82
- package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -1
- package/node_modules/checkride/dist/baseline/fallow.js +2 -2
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts +14 -5
- package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/fingerprint.js +58 -5
- package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
- package/node_modules/checkride/dist/baseline/history.d.ts +98 -0
- package/node_modules/checkride/dist/baseline/history.d.ts.map +1 -0
- package/node_modules/checkride/dist/baseline/history.js +232 -0
- package/node_modules/checkride/dist/baseline/history.js.map +1 -0
- package/node_modules/checkride/dist/baseline/index.d.ts +4 -2
- package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/index.js +2 -1
- package/node_modules/checkride/dist/baseline/index.js.map +1 -1
- package/node_modules/checkride/dist/baseline/store.d.ts +30 -7
- package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
- package/node_modules/checkride/dist/baseline/store.js +50 -16
- package/node_modules/checkride/dist/baseline/store.js.map +1 -1
- package/node_modules/checkride/dist/cli.d.ts +5 -1
- package/node_modules/checkride/dist/cli.d.ts.map +1 -1
- package/node_modules/checkride/dist/cli.js +98 -25
- package/node_modules/checkride/dist/cli.js.map +1 -1
- package/node_modules/checkride/dist/config.d.ts +33 -4
- package/node_modules/checkride/dist/config.d.ts.map +1 -1
- package/node_modules/checkride/dist/config.js +21 -6
- package/node_modules/checkride/dist/config.js.map +1 -1
- package/node_modules/checkride/dist/digest/digest.js +1 -1
- package/node_modules/checkride/dist/doctor.d.ts +2 -0
- package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
- package/node_modules/checkride/dist/doctor.js +39 -1
- package/node_modules/checkride/dist/doctor.js.map +1 -1
- package/node_modules/checkride/dist/gate.d.ts +49 -4
- package/node_modules/checkride/dist/gate.d.ts.map +1 -1
- package/node_modules/checkride/dist/gate.js +143 -16
- package/node_modules/checkride/dist/gate.js.map +1 -1
- package/node_modules/checkride/dist/init.d.ts +8 -1
- package/node_modules/checkride/dist/init.d.ts.map +1 -1
- package/node_modules/checkride/dist/init.js +68 -7
- package/node_modules/checkride/dist/init.js.map +1 -1
- package/node_modules/checkride/dist/node-pin.d.ts +1 -1
- package/node_modules/checkride/dist/node-pin.js +1 -1
- package/node_modules/checkride/dist/orchestrator.d.ts +13 -0
- package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
- package/node_modules/checkride/dist/orchestrator.js +118 -13
- package/node_modules/checkride/dist/orchestrator.js.map +1 -1
- package/node_modules/checkride/dist/pm/index.d.ts +1 -0
- package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/index.js.map +1 -1
- package/node_modules/checkride/dist/pm/launch.d.ts +23 -2
- package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -1
- package/node_modules/checkride/dist/pm/launch.js +16 -0
- package/node_modules/checkride/dist/pm/launch.js.map +1 -1
- package/node_modules/checkride/dist/pm/translate.js +1 -1
- package/node_modules/checkride/dist/pm/translate.js.map +1 -1
- package/node_modules/checkride/dist/qa/mutation.d.ts +4 -4
- package/node_modules/checkride/dist/qa/mutation.js +4 -4
- package/node_modules/checkride/dist/recover.d.ts +48 -0
- package/node_modules/checkride/dist/recover.d.ts.map +1 -0
- package/node_modules/checkride/dist/recover.js +220 -0
- package/node_modules/checkride/dist/recover.js.map +1 -0
- package/node_modules/checkride/dist/smoke.d.ts +1 -1
- package/node_modules/checkride/dist/smoke.js +1 -1
- package/node_modules/checkride/dist/snippets.d.ts +1 -1
- package/node_modules/checkride/package.json +3 -2
- package/node_modules/checkride/schema/checkride.config.schema.json +9 -1
- package/node_modules/checkride/skills/check/SKILL.md +9 -1
- package/node_modules/checkride/templates/shared/styles/Repo/Drift.yml +41 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Latin.yml +14 -0
- package/node_modules/checkride/templates/shared/styles/Repo/LyHyphen.yml +28 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Minted.yml +33 -0
- package/node_modules/checkride/templates/shared/styles/Repo/ThereIs.yml +16 -0
- package/node_modules/checkride/templates/shared/styles/Repo/Weasel.yml +26 -0
- package/node_modules/checkride/templates/shared/vale.ini +34 -0
- package/package.json +13 -11
- package/skills/abandon/SKILL.md +20 -0
- package/skills/build/SKILL.md +69 -64
- package/skills/doctor/SKILL.md +11 -11
- package/skills/finish/SKILL.md +20 -19
- package/skills/harvest/SKILL.md +13 -12
- package/skills/park/SKILL.md +10 -10
- package/skills/plan/SKILL.md +63 -54
- package/skills/recover/SKILL.md +7 -7
- package/skills/refine/SKILL.md +18 -16
- package/skills/revert/SKILL.md +6 -6
- package/skills/spike/SKILL.md +9 -9
- package/skills/status/SKILL.md +5 -5
- package/skills/step/SKILL.md +17 -12
- package/skills/verify/SKILL.md +45 -40
- package/templates/build-log.md +7 -7
- package/templates/intent.md +49 -39
- package/templates/spike-report.md +10 -10
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plumbbob",
|
|
3
3
|
"displayName": "PlumbBob",
|
|
4
|
-
"version": "0.
|
|
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
|
|
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
|
|
18
|
-
bug, a refactor
|
|
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
|
|
26
|
-
resource
|
|
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
|
|
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
|
|
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
|
|
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
|
|
47
|
-
checkpoints, report
|
|
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
|
|
51
|
-
|
|
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
|
|
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
|
|
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**
|
|
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
|
|
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
|
|
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
|
|
106
|
-
per-project sessions, the agent-neutral roadmap
|
|
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
|
|
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)
|
|
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`,
|
|
128
|
-
3. **Approve
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
157
|
-
| `/plumbbob:build` | implement the next planned step, then verify it to the pause
|
|
158
|
-
| `/plumbbob:finish` | finish up
|
|
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
|
|
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
|
|
168
|
+
**Helpers**: orient, verify, recover, diagnose:
|
|
169
169
|
|
|
170
170
|
| Skill <img alt="" width="110" height="1"> | Does |
|
|
171
171
|
|------------------------------------|------|
|
|
172
|
-
| `/plumbbob:status` | orient
|
|
173
|
-
| `/plumbbob:verify` | the tick, standalone
|
|
174
|
-
| `/plumbbob:revert` | rewind
|
|
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
|
|
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
|
|
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
|
|
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
|
|
196
|
-
loop doesn't care who writes the code. Implement a step by hand
|
|
197
|
-
another session, or in another harness entirely
|
|
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
|
|
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
|
|
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
|
|
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**
|
|
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
|
|
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)
|
|
234
|
-
top
|
|
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
|
|
239
|
-
modes, spec kits, native checkpoints
|
|
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
|
|
244
|
-
skills over a plain-markdown sidecar, learnable in an afternoon
|
|
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
|
|
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
|
|
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
|
|
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
|
|
264
|
-
> shipped latch, N=5 per contract, every assertion a mechanical read of git state
|
|
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**
|
|
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**
|
|
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
|
|
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
|
|
287
|
-
|
|
288
|
-
- *What does a session actually look like?* → [`docs/happy-path.md`](docs/happy-path.md)
|
|
289
|
-
- *Show me the artifacts it leaves behind.* → [`examples/`](examples/)
|
|
290
|
-
- *Should I / can I / what about…?* → [`docs/faq.md`](docs/faq.md)
|
|
291
|
-
- *What is each method for?* → [`docs/techniques.md`](docs/techniques.md)
|
|
292
|
-
- *What does each skill do?* → [`docs/skills-reference.md`](docs/skills-reference.md)
|
|
293
|
-
- *How do I plug in my own agent?* → [`docs/agents.md`](docs/agents.md)
|
|
294
|
-
- *How do I get a local model reviewing my steps?* → [`docs/local-model-review.md`](docs/local-model-review.md)
|
|
295
|
-
- *How do I install it, exactly?* → [`docs/install.md`](docs/install.md)
|
|
296
|
-
- *What does the CLI underneath do?* → [`docs/cli-reference.md`](docs/cli-reference.md)
|
|
297
|
-
- *What are these untracked files, and why is it touching my `.git`?* → [`docs/state-and-git.md`](docs/state-and-git.md)
|
|
298
|
-
- *Something's broken.* → [`docs/troubleshooting.md`](docs/troubleshooting.md)
|
|
299
|
-
- *Why is it built this way?* → [`docs/decisions.md`](docs/decisions.md)
|
|
300
|
-
- *How does it hang together inside?* → [`docs/architecture.md`](docs/architecture.md)
|
|
301
|
-
- *Why does this exist at all?* → [`docs/attention-first-development.md`](docs/attention-first-development.md)
|
|
302
|
-
- *
|
|
303
|
-
- *
|
|
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
|
|
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
|
|
9
|
-
// model triggers it.
|
|
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
|
|
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
|
|
367
|
-
* thing the bin entry ever wants
|
|
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
|
|
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
|