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.
Files changed (47) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +50 -44
  3. package/dist/cli-core.js +35 -15
  4. package/dist/lib/agents.js +230 -112
  5. package/dist/lib/buildlog.js +50 -30
  6. package/dist/lib/buildlogsync.js +21 -12
  7. package/dist/lib/check.js +69 -35
  8. package/dist/lib/commitmsg.js +53 -32
  9. package/dist/lib/git.js +86 -31
  10. package/dist/lib/intent.js +91 -31
  11. package/dist/lib/latch.js +70 -39
  12. package/dist/lib/orient.js +78 -39
  13. package/dist/lib/plugins.js +11 -8
  14. package/dist/lib/settings.js +65 -32
  15. package/dist/lib/sidecar.js +320 -150
  16. package/dist/lib/templates.js +17 -6
  17. package/dist/verbs/agent.js +116 -55
  18. package/dist/verbs/build.js +27 -12
  19. package/dist/verbs/check.js +33 -7
  20. package/dist/verbs/checkpoint.js +153 -78
  21. package/dist/verbs/doctor.js +192 -95
  22. package/dist/verbs/finish.js +86 -45
  23. package/dist/verbs/handoff.js +56 -20
  24. package/dist/verbs/init.js +37 -12
  25. package/dist/verbs/park.js +14 -3
  26. package/dist/verbs/revert.js +64 -24
  27. package/dist/verbs/spike.js +89 -30
  28. package/dist/verbs/start.js +72 -38
  29. package/dist/verbs/status.js +44 -17
  30. package/dist/verbs/turn.js +88 -45
  31. package/dist/verbs/use.js +20 -9
  32. package/package.json +1 -1
  33. package/skills/{pb-build → build}/SKILL.md +25 -25
  34. package/skills/{pb-doctor → doctor}/SKILL.md +1 -1
  35. package/skills/{pb-finish → finish}/SKILL.md +3 -3
  36. package/skills/{pb-harvest → harvest}/SKILL.md +4 -4
  37. package/skills/{pb-park → park}/SKILL.md +2 -2
  38. package/skills/{pb-plan → plan}/SKILL.md +11 -11
  39. package/skills/{pb-refine → refine}/SKILL.md +7 -7
  40. package/skills/{pb-revert → revert}/SKILL.md +2 -2
  41. package/skills/{pb-spike → spike}/SKILL.md +4 -4
  42. package/skills/{pb-status → status}/SKILL.md +3 -3
  43. package/skills/{pb-step → step}/SKILL.md +9 -9
  44. package/skills/{pb-verify → verify}/SKILL.md +8 -8
  45. package/templates/build-log.md +7 -7
  46. package/templates/intent.md +8 -8
  47. package/templates/spike-report.md +1 -1
@@ -1,16 +1,26 @@
1
- // `plumbbob turn` — the turn-ledger hook (D64). Wired to Claude Code's
2
- // UserPromptSubmit, it runs once per human prompt: it ticks `.plumbbob/TURN` (the
3
- // monotonic count of human turns the checkpoint latch reads to know a human turn
4
- // intervened since a step began) and rewrites `.plumbbob/GRANT` from the literal
5
- // prompt — minting a one-turn self-approval only when the human typed
6
- // `/pb-build --auto` or a `N-M` range (D65), clearing it otherwise. When a step is
7
- // in flight it also emits ONE `UserPromptSubmit` additionalContext line so a fresh
8
- // session (post-compaction, or a new `-p` turn where no skill is in context) still
9
- // knows the beat — a tangent is parked, not chased (amends D64's "writes nothing";
10
- // guidance only, D10/D13). It ALWAYS exits 0 and any failure degrades to no output,
11
- // so neither the tick nor the emit can ever wedge prompting (C3).
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
- // C3: a broken turn must never wedge a prompt — swallow and exit 0.
32
+ // A broken turn must never wedge a prompt — swallow and exit 0.
23
33
  }
24
34
  return 0;
25
35
  }
26
- // The `UserPromptSubmit` additionalContext payload when a step is in flight (a STEP
27
- // marker between `build` and `checkpoint`), or null. Guidance only: it reminds a
28
- // fresh session that a tangent is a park (not an edit) and how the step lands, since
29
- // the pb-build prose may not be in context after compaction or on a scripted turn.
30
- // Exported because an in-process test cannot read the hook's real stdout.
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
- // The in-flight step number, or null when no STEP marker is present (no step entered,
44
- // or it already checkpointed). A garbled marker reads as null — never an error (C3).
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
- // The testable core: apply one tick given the raw hook stdin. Split from the fd-0
55
- // read so the unit tests can drive it directly — an in-process test cannot feed fd 0
56
- // (the same constraint checkpoint's `--body` lives under).
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
- // GRANT is minted only from a literal `pb-build` invocation the human typed:
66
- // `pb-build` is disable-model-invocation, so this string can only come from a human
67
- // keystroke, never model-authored pressure (D65). A bounded range beats `--auto`
68
- // (bounded wins); a bare `/pb-build`, or any non-invocation prompt, mints nothing.
69
- // The namespaced `/plumbbob:pb-build` form is honored alongside the bare one.
70
- //
71
- // Only the invocation's own arguments can mint: the tokens that follow it on its
72
- // line, up to the first token that isn't a sanctioned argument (`--auto`, a step
73
- // number, or a range — the argument-hint sanctions nothing else). An unrecognized
74
- // flag ends the scan, so `/pb-build --wip 2020-2024` mints nothing — the `2020-2024`
75
- // is never reached. An incidental range elsewhere in the prompt — an issue number, a
76
- // pasted `2020-2024` — is prose, not a grant. Trailing sentence punctuation on an
77
- // argument (`/pb-build 1-3.`) is still the argument the human typed.
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 = /\/(?:plumbbob:)?pb-build\b/.exec(prompt);
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
- // Extract the `prompt` field from the UserPromptSubmit JSON, or '' when the input is
107
- // absent, unparseable, or carries no string prompt. Malformed input contributes
108
- // nothing (D27): the tick still lands (a human turn did occur) and the empty prompt
109
- // clears any GRANT; the verb never throws over bad stdin.
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
- // The current TURN as a non-negative integer, or 0 when the ledger is absent or
120
- // unreadable — so the first tick creates it at 1.
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
- // Read the hook JSON from fd 0. An interactive TTY never sends EOF, so skip the read
131
- // there rather than hang (mirrors checkpoint's `--body`); a read error degrades to
132
- // '' — extractPrompt then clears the grant and the tick still lands.
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>` (D30) — re-point the per-worktree cursor at an existing
2
- // build and resume it. Both switching and resuming are the same one word (Q10,
3
- // `nvm use`-shaped): the cursor is STATE's single-line content, so pointing it
4
- // elsewhere IS the switch and one-active-per-worktree holds by
5
- // construction (D28). It validates the target folder exists, and warns — but
6
- // allows — leaving a build with a step in flight: that surviving in-flight state
7
- // is D26's whole payoff, resumed the next time you `use` that build.
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
- // A trailing " Builds: a, b." hint when any exist, so a bad or missing slug points
40
- // the user straight at the valid choices.
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
2
  "name": "plumbbob",
3
- "version": "0.8.18",
3
+ "version": "0.9.1",
4
4
  "description": "Attention-first build process: 12 skills + a CLI that keep you the decider — guidance on the work, a latch on the record.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: pb-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 /pb-verify instead. `--auto` self-approves and chains to done; a step range like `1-3` self-approves through step 3, then pauses.
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 `/pb-verify` instead — plumbbob does not care how
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 `/pb-plan` lays down the whole step list up front, the happy path is to fire
20
- `/pb-build` once per step until done — each run builds the next undone step and stops
21
- at the pause for your approval. **Re-firing `/pb-build` is itself the clock tick.**
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. `/pb-build 4`) — or,
31
- if you were given a range like `/pb-build 1-3`, start at the first number and treat
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 `/pb-step` nudge when every
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 `/pb-status` shows the step in
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 `/pb-spike` produces for a mid-build fork (D70).
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 `/pb-verify`
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
- `/pb-build` only ever starts the *next* step. **Never route around a refusal with a
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
- `/pb-status` reports; you supply only the judgment above it. It already drops the model
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 `/pb-build` again. It is what
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 `/pb-refine`** to repair
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
- `/pb-build --auto` is the explicit escape hatch when the human wants unattended
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 `/pb-refine` — an
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
- `/pb-build 1-3` self-approves steps 1 through 3 exactly as `--auto` does, then **pauses
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 `/pb-build 4`).
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; `/pb-verify`
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` → `/pb-refine`. You are still the one
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 `/pb-build`.
220
- Never route around it with a raw `git commit`. An explicit `/pb-build --auto` or a typed
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 `/pb-build --auto` instead.**
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: pb-doctor
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: pb-finish
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
- `/pb-finish` ends the build: it captures what happened, then makes the final commit
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** — `/pb-plan` to frame the next one.
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: pb-harvest
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
- `/pb-harvest` is the complement of `/pb-park`: you parked ideas as seeds during a
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 `/pb-verify` before harvesting.
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 `/pb-status`
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: pb-park
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
- `/pb-park` is the **capture** half of the loop; `/pb-harvest` is where parked items
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: pb-plan
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
- `/pb-plan` is the **whole-goal** move — it opens a session and gets the deciding out
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
- `/pb-build` until done. (Revising a single increment later is the separate `/pb-step`
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 `/pb-build`. The argument only seeds how you get there.
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** `/pb-verify` can check and a **seam** (the exact
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 `/pb-step`. Keep each small enough to
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
- (`pb-plan`, `commitmsg`, `docs`). A step's `(scope)` names the *code area*; the header
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 — `/pb-status` surfaces it before each build —
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 `/pb-refine` to attack the frame for holes (or
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 `/pb-refine` to repair it.
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.** `/pb-plan` writes `intent.md` only — never source.
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: pb-refine
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
- `/pb-refine` keeps `intent.md` honest. Use it at **any point** — right after `/pb-plan`
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 `/pb-step` (which only
16
- sharpens the *next* step): `/pb-refine` works the *whole* plan.
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 `/pb-plan`) first, and edit nothing. Every active state
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.** `/pb-refine` touches `intent.md` only — turning a
60
- decision into a diff is `/pb-build` or your own hands, never this skill.
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.