plumbbob 0.8.18 → 0.9.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 +50 -44
- package/dist/cli-core.js +35 -15
- package/dist/lib/agents.js +230 -112
- package/dist/lib/buildlog.js +50 -30
- package/dist/lib/buildlogsync.js +21 -12
- package/dist/lib/check.js +69 -35
- package/dist/lib/commitmsg.js +53 -32
- package/dist/lib/git.js +86 -31
- package/dist/lib/intent.js +91 -31
- package/dist/lib/latch.js +70 -39
- package/dist/lib/orient.js +78 -39
- package/dist/lib/plugins.js +11 -8
- package/dist/lib/settings.js +65 -32
- package/dist/lib/sidecar.js +320 -150
- package/dist/lib/templates.js +17 -6
- package/dist/verbs/agent.js +116 -55
- package/dist/verbs/build.js +27 -12
- package/dist/verbs/check.js +33 -7
- package/dist/verbs/checkpoint.js +153 -78
- package/dist/verbs/doctor.js +192 -95
- package/dist/verbs/finish.js +86 -45
- package/dist/verbs/handoff.js +56 -20
- package/dist/verbs/init.js +37 -12
- package/dist/verbs/park.js +14 -3
- package/dist/verbs/revert.js +64 -24
- package/dist/verbs/spike.js +89 -30
- package/dist/verbs/start.js +72 -38
- package/dist/verbs/status.js +44 -17
- package/dist/verbs/turn.js +88 -45
- package/dist/verbs/use.js +20 -9
- package/package.json +1 -1
- package/skills/{pb-build → build}/SKILL.md +25 -25
- package/skills/{pb-doctor → doctor}/SKILL.md +1 -1
- package/skills/{pb-finish → finish}/SKILL.md +3 -3
- package/skills/{pb-harvest → harvest}/SKILL.md +4 -4
- package/skills/{pb-park → park}/SKILL.md +2 -2
- package/skills/{pb-plan → plan}/SKILL.md +11 -11
- package/skills/{pb-refine → refine}/SKILL.md +7 -7
- package/skills/{pb-revert → revert}/SKILL.md +2 -2
- package/skills/{pb-spike → spike}/SKILL.md +4 -4
- package/skills/{pb-status → status}/SKILL.md +3 -3
- package/skills/{pb-step → step}/SKILL.md +9 -9
- package/skills/{pb-verify → verify}/SKILL.md +8 -8
- package/templates/build-log.md +7 -7
- package/templates/intent.md +8 -8
- package/templates/spike-report.md +1 -1
package/dist/verbs/turn.js
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
// `plumbbob turn` — the turn-ledger hook
|
|
2
|
-
// UserPromptSubmit, it runs once per human prompt
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
1
|
+
// `plumbbob turn` — the turn-ledger hook. Wired to the harness's
|
|
2
|
+
// UserPromptSubmit event, it runs once per human prompt and maintains two of the
|
|
3
|
+
// sidecar's git-excluded control files (flat files under `.plumbbob/`): it ticks
|
|
4
|
+
// `TURN`, the monotonic count of human turns the checkpoint latch compares
|
|
5
|
+
// against a step's entry stamp to know a human turn intervened since the step
|
|
6
|
+
// began, and it rewrites `GRANT` from the literal prompt — minting a one-turn
|
|
7
|
+
// self-approval only when the human typed `/build --auto` or an `N-M` step
|
|
8
|
+
// range, clearing it otherwise (those strings can only come from a human
|
|
9
|
+
// keystroke, because `build` is disable-model-invocation — a grant the model
|
|
10
|
+
// could forge would be no grant). When a step is in flight it also emits ONE
|
|
11
|
+
// `UserPromptSubmit` additionalContext line so a fresh session (post-compaction,
|
|
12
|
+
// or a scripted `-p` turn where no skill prose is in context) still knows the
|
|
13
|
+
// beat — a tangent is parked, not chased. Guidance only: it blocks nothing. It
|
|
14
|
+
// ALWAYS exits 0 and any failure degrades to no output, so neither the tick nor
|
|
15
|
+
// the emit can ever wedge prompting.
|
|
12
16
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
13
17
|
import { findSessionRoot, setGrant, stepPath, turnPath } from "../lib/sidecar.js";
|
|
18
|
+
/**
|
|
19
|
+
* The hook entry point: apply the tick, then emit the in-flight-step nudge.
|
|
20
|
+
*
|
|
21
|
+
* Always returns 0 — a broken turn must never wedge a prompt, so any failure is
|
|
22
|
+
* swallowed and degrades to no output.
|
|
23
|
+
*/
|
|
14
24
|
export function turn(cwd, _args) {
|
|
15
25
|
try {
|
|
16
26
|
applyTurn(cwd, readStdin());
|
|
@@ -19,15 +29,20 @@ export function turn(cwd, _args) {
|
|
|
19
29
|
process.stdout.write(context);
|
|
20
30
|
}
|
|
21
31
|
catch {
|
|
22
|
-
//
|
|
32
|
+
// A broken turn must never wedge a prompt — swallow and exit 0.
|
|
23
33
|
}
|
|
24
34
|
return 0;
|
|
25
35
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The `UserPromptSubmit` additionalContext payload when a step is in flight, or null.
|
|
38
|
+
*
|
|
39
|
+
* A step is in flight when a STEP marker (the flat control file recording the
|
|
40
|
+
* step between `build` and `checkpoint`) is present. Guidance only: it reminds a
|
|
41
|
+
* fresh session that a tangent is a park (not an edit) and how the step lands,
|
|
42
|
+
* since the build prose may not be in context after compaction or on a
|
|
43
|
+
* scripted turn. Exported because an in-process test cannot read the hook's
|
|
44
|
+
* real stdout.
|
|
45
|
+
*/
|
|
31
46
|
export function stepInFlightContext(cwd) {
|
|
32
47
|
const root = findSessionRoot(cwd);
|
|
33
48
|
if (root === null)
|
|
@@ -40,8 +55,12 @@ export function stepInFlightContext(cwd) {
|
|
|
40
55
|
`It lands when you run \`plumbbob checkpoint ${step}\` after approval.`;
|
|
41
56
|
return `${JSON.stringify({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: text } })}\n`;
|
|
42
57
|
}
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
/**
|
|
59
|
+
* The in-flight step number, or null when no STEP marker is present.
|
|
60
|
+
*
|
|
61
|
+
* Absent means no step entered, or it already checkpointed. A garbled marker
|
|
62
|
+
* reads as null — never an error, because the hook must not wedge a prompt.
|
|
63
|
+
*/
|
|
45
64
|
function inFlightStep(root) {
|
|
46
65
|
try {
|
|
47
66
|
const n = Number.parseInt(readFileSync(stepPath(root), 'utf8').trim(), 10);
|
|
@@ -51,9 +70,13 @@ function inFlightStep(root) {
|
|
|
51
70
|
return null;
|
|
52
71
|
}
|
|
53
72
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
/**
|
|
74
|
+
* The testable core: apply one tick given the raw hook stdin.
|
|
75
|
+
*
|
|
76
|
+
* Split from the fd-0 read so the unit tests can drive it directly — an
|
|
77
|
+
* in-process test cannot feed fd 0 (the same constraint checkpoint's `--body`
|
|
78
|
+
* lives under).
|
|
79
|
+
*/
|
|
57
80
|
export function applyTurn(cwd, raw) {
|
|
58
81
|
const root = findSessionRoot(cwd);
|
|
59
82
|
if (root === null)
|
|
@@ -62,21 +85,31 @@ export function applyTurn(cwd, raw) {
|
|
|
62
85
|
setGrant(root, grantFromPrompt(extractPrompt(raw)));
|
|
63
86
|
return 0;
|
|
64
87
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Derive the GRANT content from the human's prompt, or null to clear it.
|
|
90
|
+
*
|
|
91
|
+
* A grant is minted only from a literal `build` invocation the human typed:
|
|
92
|
+
* `build` is disable-model-invocation, so this string can only come from a
|
|
93
|
+
* human keystroke, never model-authored pressure — a grant the model can forge
|
|
94
|
+
* is no grant. A bounded range beats `--auto` (bounded wins); a bare
|
|
95
|
+
* `/build`, or any non-invocation prompt, mints nothing. The namespaced
|
|
96
|
+
* `/plumbbob:build` form is honored alongside the bare one.
|
|
97
|
+
*
|
|
98
|
+
* The invocation must *start* a token: a slash preceded by a word character,
|
|
99
|
+
* `/`, `.`, `-`, or `~` is a path segment (`src/build`, `./build`), not a
|
|
100
|
+
* command the human fired, so it mints nothing.
|
|
101
|
+
*
|
|
102
|
+
* Only the invocation's own arguments can mint: the tokens that follow it on
|
|
103
|
+
* its line, up to the first token that isn't a sanctioned argument (`--auto`, a
|
|
104
|
+
* step number, or a range — the argument-hint sanctions nothing else). An
|
|
105
|
+
* unrecognized flag ends the scan, so `/build --wip 2020-2024` mints
|
|
106
|
+
* nothing — the `2020-2024` is never reached. An incidental range elsewhere in
|
|
107
|
+
* the prompt — an issue number, a pasted `2020-2024` — is prose, not a grant.
|
|
108
|
+
* Trailing sentence punctuation on an argument (`/build 1-3.`) is still the
|
|
109
|
+
* argument the human typed.
|
|
110
|
+
*/
|
|
78
111
|
export function grantFromPrompt(prompt) {
|
|
79
|
-
const invocation =
|
|
112
|
+
const invocation = /(?<![\w/.~-])\/(?:plumbbob:)?build\b/.exec(prompt);
|
|
80
113
|
if (invocation === null)
|
|
81
114
|
return null;
|
|
82
115
|
const line = prompt.slice(invocation.index + invocation[0].length).split('\n', 1)[0] ?? '';
|
|
@@ -103,10 +136,13 @@ export function grantFromPrompt(prompt) {
|
|
|
103
136
|
return `range ${ceiling}`;
|
|
104
137
|
return auto ? 'auto' : null;
|
|
105
138
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Extract the `prompt` field from the UserPromptSubmit JSON, or '' otherwise.
|
|
141
|
+
*
|
|
142
|
+
* Absent, unparseable, or non-string input contributes nothing rather than
|
|
143
|
+
* wedging the tool: the tick still lands (a human turn did occur) and the empty
|
|
144
|
+
* prompt clears any GRANT; the verb never throws over bad stdin.
|
|
145
|
+
*/
|
|
110
146
|
function extractPrompt(raw) {
|
|
111
147
|
try {
|
|
112
148
|
const parsed = JSON.parse(raw);
|
|
@@ -116,8 +152,11 @@ function extractPrompt(raw) {
|
|
|
116
152
|
return '';
|
|
117
153
|
}
|
|
118
154
|
}
|
|
119
|
-
|
|
120
|
-
|
|
155
|
+
/**
|
|
156
|
+
* The current TURN count, or 0 when the ledger is absent or unreadable.
|
|
157
|
+
*
|
|
158
|
+
* Starting from 0 means the first tick creates the file at 1.
|
|
159
|
+
*/
|
|
121
160
|
function readTurn(root) {
|
|
122
161
|
try {
|
|
123
162
|
const n = Number.parseInt(readFileSync(turnPath(root), 'utf8').trim(), 10);
|
|
@@ -127,9 +166,13 @@ function readTurn(root) {
|
|
|
127
166
|
return 0;
|
|
128
167
|
}
|
|
129
168
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Read the hook JSON from fd 0, degrading to '' on any failure.
|
|
171
|
+
*
|
|
172
|
+
* An interactive TTY never sends EOF, so skip the read there rather than hang
|
|
173
|
+
* (mirrors checkpoint's `--body`); a read error degrades to '' — extractPrompt
|
|
174
|
+
* then clears the grant and the tick still lands.
|
|
175
|
+
*/
|
|
133
176
|
function readStdin() {
|
|
134
177
|
if (process.stdin.isTTY === true)
|
|
135
178
|
return '';
|
package/dist/verbs/use.js
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
// `plumbbob use <slug>`
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
1
|
+
// `plumbbob use <slug>` — re-point the active-build cursor at an existing build
|
|
2
|
+
// and resume it, `nvm use`-shaped: switching and resuming are the same one word.
|
|
3
|
+
// The cursor is the single-line content of `.plumbbob/STATE`, the untracked
|
|
4
|
+
// per-worktree file whose existence means a session is live and whose one line
|
|
5
|
+
// names the build that session is on — so pointing it elsewhere IS the switch,
|
|
6
|
+
// and one-active-per-worktree holds by construction (one line cannot name two
|
|
7
|
+
// builds). It validates the target folder exists, and warns — but allows —
|
|
8
|
+
// leaving a build with a step in flight: the in-flight markers live per build,
|
|
9
|
+
// so that state survives the switch and resumes the next time you `use` the
|
|
10
|
+
// build.
|
|
8
11
|
import { existsSync } from 'node:fs';
|
|
9
12
|
import { findRepoRoot } from "../lib/git.js";
|
|
10
13
|
import { activeBuild, hasSession, intentPath, listBuilds, setActiveBuild, stepPath } from "../lib/sidecar.js";
|
|
14
|
+
/**
|
|
15
|
+
* Switch the active-build cursor to the named build.
|
|
16
|
+
*
|
|
17
|
+
* Refuses without a session, without a slug, or when the target folder has no
|
|
18
|
+
* intent.md; notes — but allows — a step left in flight on the build being left.
|
|
19
|
+
*/
|
|
11
20
|
export function use(cwd, args) {
|
|
12
21
|
const root = findRepoRoot(cwd);
|
|
13
22
|
if (root === null || !hasSession(root)) {
|
|
@@ -36,8 +45,10 @@ export function use(cwd, args) {
|
|
|
36
45
|
process.stdout.write(`plumbbob: now on build "${target}"${resuming}. \`status\` to orient.\n`);
|
|
37
46
|
return 0;
|
|
38
47
|
}
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
/**
|
|
49
|
+
* A trailing " Builds: a, b." hint when any exist, so a bad or missing slug
|
|
50
|
+
* points the user straight at the valid choices.
|
|
51
|
+
*/
|
|
41
52
|
function buildsHint(builds) {
|
|
42
53
|
return builds.length > 0 ? ` Builds: ${builds.join(', ')}.` : '';
|
|
43
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: The default engine — read the next planned step from intent, implement it (its done-when, seam, Decisions, Constraints), then verify it through to the approval pause. Swappable — build by hand/vibed/another harness and run /
|
|
2
|
+
name: build
|
|
3
|
+
description: The default engine — read the next planned step from intent, implement it (its done-when, seam, Decisions, Constraints), then verify it through to the approval pause. Swappable — build by hand/vibed/another harness and run /plumbbob:verify instead. `--auto` self-approves and chains to done; a step range like `1-3` self-approves through step 3, then pauses.
|
|
4
4
|
argument-hint: "[step-number | step-range] [--auto]"
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
allowed-tools: Read, Edit, Write, Bash(plumbbob status:*), Bash(plumbbob build:*), Bash(plumbbob handoff:*), Bash(plumbbob check:*), Bash(plumbbob checkpoint:*), Bash(plumbbob park:*), Bash(plumbbob agent:*), Bash(plumbbob spike:*), Bash(git diff:*)
|
|
@@ -12,13 +12,13 @@ Current session state (injected when this skill runs): !`plumbbob status 2>/dev/
|
|
|
12
12
|
|
|
13
13
|
This is the **bundled executor** — the default engine, not the only one. It is
|
|
14
14
|
**swappable**: you can implement any step by hand, in a vibe session, or with
|
|
15
|
-
another harness and go straight to `/
|
|
15
|
+
another harness and go straight to `/plumbbob:verify` instead — plumbbob does not care how
|
|
16
16
|
the diff appeared. When you do run it, it reads the plan, writes the step, and
|
|
17
17
|
carries straight through to the verify pause.
|
|
18
18
|
|
|
19
|
-
Since `/
|
|
20
|
-
`/
|
|
21
|
-
at the pause for your approval. **Re-firing `/
|
|
19
|
+
Since `/plumbbob:plan` lays down the whole step list up front, the happy path is to fire
|
|
20
|
+
`/plumbbob:build` once per step until done — each run builds the next undone step and stops
|
|
21
|
+
at the pause for your approval. **Re-firing `/plumbbob:build` is itself the clock tick.**
|
|
22
22
|
|
|
23
23
|
A model note: this skill **inherits the session model** — nothing pins or switches
|
|
24
24
|
it. If the step you're about to build carries a `- model:` recommendation that
|
|
@@ -27,14 +27,14 @@ differs from the model you're running as, say so before implementing — the hum
|
|
|
27
27
|
|
|
28
28
|
## What this skill does, in order
|
|
29
29
|
|
|
30
|
-
1. **Pick the step.** Use the number you were invoked with (e.g. `/
|
|
31
|
-
if you were given a range like `/
|
|
30
|
+
1. **Pick the step.** Use the number you were invoked with (e.g. `/plumbbob:build 4`) — or,
|
|
31
|
+
if you were given a range like `/plumbbob:build 1-3`, start at the first number and treat
|
|
32
32
|
the second as the auto-approve ceiling (see the range note under `--auto`). With no
|
|
33
33
|
argument, don't resolve the next step yourself — the CLI does: bare `plumbbob build`
|
|
34
|
-
(step 2) enters the next undone step and refuses with a `/
|
|
34
|
+
(step 2) enters the next undone step and refuses with a `/plumbbob:step` nudge when every
|
|
35
35
|
step is checkpointed.
|
|
36
36
|
2. **Enter the step.** Run `plumbbob build <n>` — or bare `plumbbob build` to enter the
|
|
37
|
-
next undone step (records the in-flight STEP + SEAM so `/
|
|
37
|
+
next undone step (records the in-flight STEP + SEAM so `/plumbbob:status` shows the step in
|
|
38
38
|
flight; the seam is awareness, not a lock).
|
|
39
39
|
- **Spike-as-step.** If the step's title opens with `spike:` / `Spike:`, the increment
|
|
40
40
|
*is* the experiment — resolving a fork the plan couldn't settle on paper. After
|
|
@@ -42,7 +42,7 @@ differs from the model you're running as, say so before implementing — the hum
|
|
|
42
42
|
`spike-NN-<slug>.md` in the build folder, stamped `via: step <n>`), then work the
|
|
43
43
|
experiment and record your **Findings** and **Verdict** there. A recorded verdict is
|
|
44
44
|
what the step's done-when should check — the report, not just the code, is the
|
|
45
|
-
deliverable. This is the same artifact `/
|
|
45
|
+
deliverable. This is the same artifact `/plumbbob:spike` produces for a mid-build fork (D70).
|
|
46
46
|
3. **Read the plan.** Read the step's **done-when**, its **seam**, and the
|
|
47
47
|
**Decisions** and **Constraints** in `intent.md`. Build to *that* — the deciding
|
|
48
48
|
already happened, off the chat.
|
|
@@ -61,7 +61,7 @@ differs from the model you're running as, say so before implementing — the hum
|
|
|
61
61
|
`harness bindings:` block, a `build`-slot agent may author the diff, a `when`-cue may
|
|
62
62
|
fire an agent mid-build, and a non-`done` envelope routes by its status — see
|
|
63
63
|
**§ Running bound agents**.
|
|
64
|
-
5. **Verify, through to the pause.** Run the verify tick exactly as `/
|
|
64
|
+
5. **Verify, through to the pause.** Run the verify tick exactly as `/plumbbob:verify`
|
|
65
65
|
does: `plumbbob check` (on red, read `.check/summary.json` and the failing slot's
|
|
66
66
|
raw output under `.check/` for the actual diagnostics; while iterating on a fix,
|
|
67
67
|
narrow the loop with `plumbbob check --bail --only <slots>` — the checkpoint gate
|
|
@@ -94,7 +94,7 @@ differs from the model you're running as, say so before implementing — the hum
|
|
|
94
94
|
lets the checkpoint land: on that turn you run `plumbbob checkpoint <n>` (now allowed)
|
|
95
95
|
and **stop at the boundary**. Landing the checkpoint is its own deliberate beat — the
|
|
96
96
|
thing approval triggers — never a side effect of starting the next step, and
|
|
97
|
-
`/
|
|
97
|
+
`/plumbbob:build` only ever starts the *next* step. **Never route around a refusal with a
|
|
98
98
|
raw `git commit`** — the work plane stays free, but the *record* is latched on purpose.
|
|
99
99
|
|
|
100
100
|
**End every default build turn with the standardized hand-off block.** Run `plumbbob
|
|
@@ -102,7 +102,7 @@ differs from the model you're running as, say so before implementing — the hum
|
|
|
102
102
|
choice, what's next) straight from the session: step N built, the looks-good /
|
|
103
103
|
needs-work choice, and the next undone step with its `- model:` recommendation. Show
|
|
104
104
|
your diff and self-review above it. The CLI owns the block so it can't drift from what
|
|
105
|
-
`/
|
|
105
|
+
`/plumbbob:status` reports; you supply only the judgment above it. It already drops the model
|
|
106
106
|
clause when the next step has none, and says so when no planned step remains — you
|
|
107
107
|
don't reproduce the template by hand.
|
|
108
108
|
|
|
@@ -110,7 +110,7 @@ differs from the model you're running as, say so before implementing — the hum
|
|
|
110
110
|
run `plumbbob handoff` again and relay its boundary block — with the step gone from
|
|
111
111
|
in-flight it renders "step N checkpointed" and points at the next undone step, carrying
|
|
112
112
|
that step's `- model:` recommendation (the plan's smallest-model-that-fits call) so the
|
|
113
|
-
human knows which `/model` to select before firing `/
|
|
113
|
+
human knows which `/model` to select before firing `/plumbbob:build` again. It is what
|
|
114
114
|
carries the plan's suggestion across a fresh context window, which inherits the session
|
|
115
115
|
model, not the plan's. No `- model:` line means any model will do. Guidance, never a
|
|
116
116
|
gate.
|
|
@@ -140,7 +140,7 @@ harness *is* bound, this is what each affected step gains, in lifecycle order.
|
|
|
140
140
|
- **Route a non-`done` envelope by its status (step 4).** An agent that returns `blocked`
|
|
141
141
|
couldn't finish (missing input, failed precondition): surface its `notes`, let the human
|
|
142
142
|
unblock, and re-run it — don't work around it. One that returns `drift` finished but found
|
|
143
|
-
the plan no longer matches reality: **stop and send the human to `/
|
|
143
|
+
the plan no longer matches reality: **stop and send the human to `/plumbbob:refine`** to repair
|
|
144
144
|
the plan before continuing, rather than building on a plan that's now wrong. A non-zero
|
|
145
145
|
exit is a failed run: report it and stop.
|
|
146
146
|
- **`after` — advisory input to the verify tick (step 5).** After `plumbbob check`, run any
|
|
@@ -151,7 +151,7 @@ harness *is* bound, this is what each affected step gains, in lifecycle order.
|
|
|
151
151
|
|
|
152
152
|
## `--auto` — let the agent be the clock (opt-in)
|
|
153
153
|
|
|
154
|
-
`/
|
|
154
|
+
`/plumbbob:build --auto` is the explicit escape hatch when the human wants unattended
|
|
155
155
|
progress instead of approving each step. It does the same work, but **the agent reviews
|
|
156
156
|
and approves in the human's place**, and it **chains**:
|
|
157
157
|
|
|
@@ -163,7 +163,7 @@ and approves in the human's place**, and it **chains**:
|
|
|
163
163
|
`after`-agent output simply feeds the *existing* self-review halt condition.
|
|
164
164
|
- **Stop and hand back to the human** the moment any of these is true: the check is red,
|
|
165
165
|
the self-review finds a mismatch (surface exactly what, and do not checkpoint it), a
|
|
166
|
-
bound agent returns `blocked` or `drift` (unblock-and-re-run, or `/
|
|
166
|
+
bound agent returns `blocked` or `drift` (unblock-and-re-run, or `/plumbbob:refine` — an
|
|
167
167
|
agent cannot advance the loop), a new decision is needed, no planned steps
|
|
168
168
|
remain, or the top of a requested range is reached. **When `--auto` halts back to the
|
|
169
169
|
human, give the same hand-off the default pause does** — run `plumbbob handoff` and
|
|
@@ -177,7 +177,7 @@ The default — no flag, no range — always ends at the pause.
|
|
|
177
177
|
|
|
178
178
|
### A step range (`N-M`) is a bounded `--auto`
|
|
179
179
|
|
|
180
|
-
`/
|
|
180
|
+
`/plumbbob:build 1-3` self-approves steps 1 through 3 exactly as `--auto` does, then **pauses
|
|
181
181
|
after step 3** instead of chaining to done. The range *is* the opt-in — you do not also
|
|
182
182
|
pass `--auto`. Run it as the `--auto` loop with one extra halt: **stop before building
|
|
183
183
|
any next step whose plan number is past the top of the range.** It adds no machinery —
|
|
@@ -195,11 +195,11 @@ just the one more entry already in the halt list above.
|
|
|
195
195
|
check. Do not skip past the gap.
|
|
196
196
|
- **N is above the next undone step** — you are jumping over earlier planned work; note
|
|
197
197
|
that you are skipping the steps before N, then proceed (the same latitude as a
|
|
198
|
-
single-number jump like `/
|
|
198
|
+
single-number jump like `/plumbbob:build 4`).
|
|
199
199
|
|
|
200
200
|
## The hard contracts
|
|
201
201
|
|
|
202
|
-
- **Swappable, never required.** The loop works without this skill; `/
|
|
202
|
+
- **Swappable, never required.** The loop works without this skill; `/plumbbob:verify`
|
|
203
203
|
checkpoints a hand-built or vibed diff just the same.
|
|
204
204
|
- **Build the decided step, not a new one.** Implement what `intent.md` settled. A
|
|
205
205
|
new idea mid-build is captured with `plumbbob park`, not an edit — a promise to
|
|
@@ -210,17 +210,17 @@ just the one more entry already in the halt list above.
|
|
|
210
210
|
at its top.
|
|
211
211
|
- **Agents feed the beat; they never advance it**. `before` loads context,
|
|
212
212
|
`build` writes the diff, `after` is advisory — none can checkpoint, flip a step, or
|
|
213
|
-
chain. `blocked` → unblock and re-run; `drift` → `/
|
|
213
|
+
chain. `blocked` → unblock and re-run; `drift` → `/plumbbob:refine`. You are still the one
|
|
214
214
|
who verifies and (bar `--auto`) the human is still the clock. See **§ Running bound
|
|
215
215
|
agents** for the mechanics.
|
|
216
216
|
- **A refused checkpoint is the pause, not an error.** Under plumbbob's turn
|
|
217
217
|
hook a same-turn `checkpoint` is refused by design — present the diff and the closing
|
|
218
218
|
block, **end the turn**; the human's approval on their next turn is what lets you land
|
|
219
|
-
it, and landing it is a deliberate beat, not a side effect of the next `/
|
|
220
|
-
Never route around it with a raw `git commit`. An explicit `/
|
|
219
|
+
it, and landing it is a deliberate beat, not a side effect of the next `/plumbbob:build`.
|
|
220
|
+
Never route around it with a raw `git commit`. An explicit `/plumbbob:build --auto` or a typed
|
|
221
221
|
step range in the human's own prompt are the only self-approvals — **never write `auto`
|
|
222
222
|
into a settings file yourself to unlock a checkpoint. A grant you mint is no grant (the
|
|
223
|
-
latch ignores it since D67); ask the human to re-fire `/
|
|
223
|
+
latch ignores it since D67); ask the human to re-fire `/plumbbob:build --auto` instead.**
|
|
224
224
|
- **Close with the next model.** When a step lands, run `plumbbob handoff` and relay its
|
|
225
225
|
block — it cites the completed step and the next undone step, and names that next step's
|
|
226
226
|
`- model:` recommendation if it has one, which is what a fresh context window needs to
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: doctor
|
|
3
3
|
description: Diagnose the plugin install from inside a session — is plumbbob linked, are the skills and hook present, is there a collision. A thin trigger for `plumbbob doctor`. Matters most for a marketplace install, where the CLI is on PATH only inside Claude Code.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
model: haiku
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: finish
|
|
3
3
|
description: Finish the build — write the report (what shipped, decisions, parked/harvested items, deferred tangents), then make the final commit that closes the session. The build folder rides the branch into the PR — no separate archive. Report by default, no gate.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
allowed-tools: Read, Write, Bash(plumbbob status:*), Bash(plumbbob finish:*)
|
|
@@ -9,7 +9,7 @@ allowed-tools: Read, Write, Bash(plumbbob status:*), Bash(plumbbob finish:*)
|
|
|
9
9
|
|
|
10
10
|
Current session state (injected when this skill runs): !`plumbbob status 2>/dev/null || echo "plumbbob CLI not on PATH in this session. Marketplace install: confirm the plugin is enabled in /plugin, then /reload-plugins. Skills-dir/global install: npm i -g plumbbob && plumbbob init."`
|
|
11
11
|
|
|
12
|
-
`/
|
|
12
|
+
`/plumbbob:finish` ends the build: it captures what happened, then makes the final commit
|
|
13
13
|
that closes the session. **Report by default** — no refuse-without-report gate,
|
|
14
14
|
and no separate docs phase. The build folder is tracked: it merges with the
|
|
15
15
|
branch and shows up in the PR, so there is nothing to archive — the folder *is* the
|
|
@@ -48,7 +48,7 @@ record.
|
|
|
48
48
|
an argument value (`--body "$(cat <<'BODY'…)"`): `--body` ignores an argument and
|
|
49
49
|
reads stdin, so that form leaves stdin open with no EOF and the command hangs. Omit
|
|
50
50
|
`--body` entirely and the commit carries the `plumbbob finish` marker subject only.
|
|
51
|
-
3. **Point at the next goal** — `/
|
|
51
|
+
3. **Point at the next goal** — `/plumbbob:plan` to frame the next one.
|
|
52
52
|
|
|
53
53
|
## The hard contracts
|
|
54
54
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: harvest
|
|
3
3
|
description: Triage the park list at a step boundary — propose one class (blocker/tangent/pivot) per parked item, write only after the human confirms each, record under ## Harvest, and fold a confirmed blocker into intent.
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
allowed-tools: Read, Edit, Bash(plumbbob status:*)
|
|
@@ -9,7 +9,7 @@ allowed-tools: Read, Edit, Bash(plumbbob status:*)
|
|
|
9
9
|
|
|
10
10
|
Current session state (injected when this skill runs): !`plumbbob status 2>/dev/null || echo "plumbbob CLI not on PATH in this session. Marketplace install: confirm the plugin is enabled in /plugin, then /reload-plugins. Skills-dir/global install: npm i -g plumbbob && plumbbob init."`
|
|
11
11
|
|
|
12
|
-
`/
|
|
12
|
+
`/plumbbob:harvest` is the complement of `/plumbbob:park`: you parked ideas as seeds during a
|
|
13
13
|
build; now, at a boundary, you harvest them — decide what each one is.
|
|
14
14
|
|
|
15
15
|
## When to run it — boundary only
|
|
@@ -19,7 +19,7 @@ DESIGN boundary, not mid-step. Read the dashboard injected above:
|
|
|
19
19
|
|
|
20
20
|
- `NO ACTIVE SESSION` — **refuse**; tell the human to `plumbbob start "<title>"` first.
|
|
21
21
|
- A step in flight (the dashboard reads `[BUILD]`, and `next →` points at finishing the
|
|
22
|
-
step) — **refuse** and suggest finishing it with `/
|
|
22
|
+
step) — **refuse** and suggest finishing it with `/plumbbob:verify` before harvesting.
|
|
23
23
|
Chasing parked items mid-step is the disease parking prevents.
|
|
24
24
|
- At the boundary (the dashboard reads `[DESIGN]`) — go ahead.
|
|
25
25
|
|
|
@@ -40,7 +40,7 @@ one line of reasoning, then **wait for the human to confirm or override**. Write
|
|
|
40
40
|
**only after** per-item confirmation:
|
|
41
41
|
|
|
42
42
|
- Record each confirmed class in `build-log.md`'s `## Harvest` section.
|
|
43
|
-
- **Flip the harvested item** from `- [ ]` to `- [x]` in the Park list, so `/
|
|
43
|
+
- **Flip the harvested item** from `- [ ]` to `- [x]` in the Park list, so `/plumbbob:status`
|
|
44
44
|
stops counting it as open.
|
|
45
45
|
- A confirmed **blocker** also folds its decision into `intent.md`.
|
|
46
46
|
- Never reclassify or resolve an item the human hasn't confirmed, and default every
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: park
|
|
3
3
|
description: Compose one tidy tagged park line, get the human's OK in-turn, then capture it by shelling `plumbbob park` — never by editing a file. The capture half of the park/harvest loop.
|
|
4
4
|
argument-hint: "[idea]"
|
|
5
5
|
disable-model-invocation: true
|
|
@@ -11,7 +11,7 @@ allowed-tools: Bash(plumbbob status:*), Bash(plumbbob park:*)
|
|
|
11
11
|
|
|
12
12
|
Current session state (injected when this skill runs): !`plumbbob status 2>/dev/null || echo "plumbbob CLI not on PATH in this session. Marketplace install: confirm the plugin is enabled in /plugin, then /reload-plugins. Skills-dir/global install: npm i -g plumbbob && plumbbob init."`
|
|
13
13
|
|
|
14
|
-
`/
|
|
14
|
+
`/plumbbob:park` is the **capture** half of the loop; `/plumbbob:harvest` is where parked items
|
|
15
15
|
get triaged later. Capturing the instant an idea arrives — instead of acting on
|
|
16
16
|
it — is the whole point: it protects the step in flight.
|
|
17
17
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: plan
|
|
3
3
|
description: "Frame a fresh goal and author the whole plan — Frame, Decisions, Constraints, and all Steps — before any code. Three input modes: no arg interviews you; a file path (or @-mention) absorbs a spec; any other text expands your inline intent."
|
|
4
4
|
argument-hint: "[spec-path | intent]"
|
|
5
5
|
disable-model-invocation: true
|
|
@@ -10,10 +10,10 @@ allowed-tools: Read, Edit, Write, Bash(plumbbob status:*), Bash(plumbbob start:*
|
|
|
10
10
|
|
|
11
11
|
Current session state (injected when this skill runs): !`plumbbob status 2>/dev/null || echo "plumbbob CLI not on PATH in this session. Marketplace install: confirm the plugin is enabled in /plugin, then /reload-plugins. Skills-dir/global install: npm i -g plumbbob && plumbbob init."`
|
|
12
12
|
|
|
13
|
-
`/
|
|
13
|
+
`/plumbbob:plan` is the **whole-goal** move — it opens a session and gets the deciding out
|
|
14
14
|
of your head and onto `intent.md` *before* any code. By default it authors the
|
|
15
15
|
**complete plan, including all the Steps**, so the happy path afterward is just
|
|
16
|
-
`/
|
|
16
|
+
`/plumbbob:build` until done. (Revising a single increment later is the separate `/plumbbob:step`
|
|
17
17
|
move; do not confuse the two.)
|
|
18
18
|
|
|
19
19
|
A model note: this skill **inherits the session model** — nothing pins or switches
|
|
@@ -42,7 +42,7 @@ Look at the argument the human gave and pick the mode yourself:
|
|
|
42
42
|
genuinely ambiguous.
|
|
43
43
|
|
|
44
44
|
All three modes converge on the **same artifact**: a complete, standalone `intent.md`
|
|
45
|
-
an agent can follow with `/
|
|
45
|
+
an agent can follow with `/plumbbob:build`. The argument only seeds how you get there.
|
|
46
46
|
|
|
47
47
|
## What this skill does
|
|
48
48
|
|
|
@@ -79,9 +79,9 @@ an agent can follow with `/pb-build`. The argument only seeds how you get there.
|
|
|
79
79
|
- model: <optional — smallest that can carry it, with the one-phrase why>
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
Every step needs a **done-when** `/
|
|
82
|
+
Every step needs a **done-when** `/plumbbob:verify` can check and a **seam** (the exact
|
|
83
83
|
paths it touches). Later steps may be fuzzier than the first — that's fine; they get
|
|
84
|
-
sharpened just-in-time when you reach them with `/
|
|
84
|
+
sharpened just-in-time when you reach them with `/plumbbob:step`. Keep each small enough to
|
|
85
85
|
verify in one review pass.
|
|
86
86
|
|
|
87
87
|
**The title *is* the commit subject — author it as one** *(D1)*: write each
|
|
@@ -96,7 +96,7 @@ an agent can follow with `/pb-build`. The argument only seeds how you get there.
|
|
|
96
96
|
**Set the build's default scope, then let steps override it** *(D8)*: fill the
|
|
97
97
|
`**Scope:**` header once with a short feature-level name — the catch-all every step
|
|
98
98
|
inherits — and give a step its own `(scope)` when it touches a distinct code area
|
|
99
|
-
(`
|
|
99
|
+
(`plan`, `commitmsg`, `docs`). A step's `(scope)` names the *code area*; the header
|
|
100
100
|
names the *feature*, so scopes stay consistent and greppable across builds. Scope
|
|
101
101
|
resolves title-scope → `**Scope:**` default → build slug → bare, and type resolves
|
|
102
102
|
title-type → `feat`, so a scopeless plain title still yields a clean
|
|
@@ -108,7 +108,7 @@ an agent can follow with `/pb-build`. The argument only seeds how you get there.
|
|
|
108
108
|
`model: sonnet — mechanical, fully specified by the done-when` for rote edits;
|
|
109
109
|
`model: opus — strong-assertion test authoring` where the tests do the thinking;
|
|
110
110
|
`model: fable — subtle cross-cutting design` for judgment-heavy or creative work.
|
|
111
|
-
It is advisory metadata for the human — `/
|
|
111
|
+
It is advisory metadata for the human — `/plumbbob:status` surfaces it before each build —
|
|
112
112
|
never a gate, and nothing switches models automatically. Write it plain (no
|
|
113
113
|
backticks) and omit it when any model would do.
|
|
114
114
|
5. **Offer harness bindings** *(optional)*. If the build will lean on
|
|
@@ -153,7 +153,7 @@ an agent can follow with `/pb-build`. The argument only seeds how you get there.
|
|
|
153
153
|
see the plan and build record in review. In the same breath, offer the way out:
|
|
154
154
|
a repo that won't track a tool folder can restart with `plumbbob start --local`
|
|
155
155
|
(a fully untracked sidecar) before any steps are built.
|
|
156
|
-
7. **Offer to stress-test it.** Suggest `/
|
|
156
|
+
7. **Offer to stress-test it.** Suggest `/plumbbob:refine` to attack the frame for holes (or
|
|
157
157
|
to repair the plan as it drifts). Optional, the human's call.
|
|
158
158
|
|
|
159
159
|
## The interview (mode 1)
|
|
@@ -166,11 +166,11 @@ Make it easy and non-intrusive:
|
|
|
166
166
|
without typing** ("done-when: the 6th request in 60s returns 429 — good?"), while
|
|
167
167
|
taking arbitrary detail when they want to give it, including pointers to other files.
|
|
168
168
|
- **Let them double back.** They will revise as the picture sharpens; that's expected.
|
|
169
|
-
They can also edit `intent.md` by hand at any time, or call `/
|
|
169
|
+
They can also edit `intent.md` by hand at any time, or call `/plumbbob:refine` to repair it.
|
|
170
170
|
|
|
171
171
|
## The hard contracts
|
|
172
172
|
|
|
173
|
-
- **Deciding before code.** `/
|
|
173
|
+
- **Deciding before code.** `/plumbbob:plan` writes `intent.md` only — never source.
|
|
174
174
|
- **The human converges.** You surface options and draft wording; the human picks.
|
|
175
175
|
An unresolved hole is an Open question, not a guessed Decision.
|
|
176
176
|
- **Stands on its own.** Whatever the input mode, the finished `intent.md` carries
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: refine
|
|
3
3
|
description: Keep intent.md true — attack the plan for holes (append as Open questions) and refine or repair the Frame, Decisions, Constraints, and Steps to match reality. Usable at any point; you propose, the human approves.
|
|
4
4
|
argument-hint: "[focus]"
|
|
5
5
|
disable-model-invocation: true
|
|
@@ -10,16 +10,16 @@ allowed-tools: Read, Edit, Bash(plumbbob status:*)
|
|
|
10
10
|
|
|
11
11
|
Current session state (injected when this skill runs): !`plumbbob status 2>/dev/null || echo "plumbbob CLI not on PATH in this session. Marketplace install: confirm the plugin is enabled in /plugin, then /reload-plugins. Skills-dir/global install: npm i -g plumbbob && plumbbob init."`
|
|
12
12
|
|
|
13
|
-
`/
|
|
13
|
+
`/plumbbob:refine` keeps `intent.md` honest. Use it at **any point** — right after `/plumbbob:plan`
|
|
14
14
|
to stress-test a fresh frame, or mid-build to repair a plan that drifted from what the
|
|
15
|
-
code is actually doing. It is the document-level complement to `/
|
|
16
|
-
sharpens the *next* step): `/
|
|
15
|
+
code is actually doing. It is the document-level complement to `/plumbbob:step` (which only
|
|
16
|
+
sharpens the *next* step): `/plumbbob:refine` works the *whole* plan.
|
|
17
17
|
|
|
18
18
|
## No-session refusal
|
|
19
19
|
|
|
20
20
|
This skill refines an existing plan, so it needs one. Read the state injected above: if
|
|
21
21
|
it is `NO ACTIVE SESSION`, **refuse** in one line and tell the human to run
|
|
22
|
-
`plumbbob start "<title>"` (or `/
|
|
22
|
+
`plumbbob start "<title>"` (or `/plumbbob:plan`) first, and edit nothing. Every active state
|
|
23
23
|
is fine — refining is always available.
|
|
24
24
|
|
|
25
25
|
## Two modes
|
|
@@ -56,5 +56,5 @@ is fine — refining is always available.
|
|
|
56
56
|
approves every change to `intent.md`. Never guess a hole into a Decision.
|
|
57
57
|
- **Open questions for holes, edits for drift.** New uncertainty goes to
|
|
58
58
|
`## Open questions`; settled drift gets repaired in place once the human OKs it.
|
|
59
|
-
- **Refine the plan, not the code.** `/
|
|
60
|
-
decision into a diff is `/
|
|
59
|
+
- **Refine the plan, not the code.** `/plumbbob:refine` touches `intent.md` only — turning a
|
|
60
|
+
decision into a diff is `/plumbbob:build` or your own hands, never this skill.
|