plumbbob 0.13.0 → 0.13.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 +8 -6
- package/dist/cli-core.js +8 -3
- package/dist/lib/latch.js +23 -5
- package/dist/lib/notice.js +3 -2
- package/dist/lib/orient.js +307 -33
- package/dist/lib/sidecar.js +53 -0
- package/dist/lib/steplist.js +128 -0
- package/dist/verbs/build.js +73 -14
- package/dist/verbs/checkpoint.js +1 -0
- package/dist/verbs/handoff.js +86 -26
- package/dist/verbs/order.js +15 -11
- package/dist/verbs/recover.js +31 -1
- package/dist/verbs/turn.js +83 -52
- package/package.json +1 -1
- package/skills/build/SKILL.md +72 -33
- package/skills/harvest/SKILL.md +10 -1
- package/skills/order/SKILL.md +20 -10
- package/skills/plan/SKILL.md +51 -7
- package/skills/refine/SKILL.md +21 -3
- package/skills/status/SKILL.md +8 -3
- package/skills/step/SKILL.md +16 -3
- package/skills/verify/SKILL.md +1 -1
- package/templates/intent.md +23 -5
package/dist/verbs/turn.js
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
// `plumbbob turn`: the turn-ledger hook. Wired to the harness's
|
|
2
|
-
// UserPromptSubmit event, it runs once per
|
|
2
|
+
// UserPromptSubmit event, it runs once per prompt and maintains two of the
|
|
3
3
|
// sidecar's git-excluded control files (flat files under `.plumbbob/`): it ticks
|
|
4
4
|
// `TURN`, the monotonic count of human turns the checkpoint latch compares
|
|
5
5
|
// against a step's entry stamp to know a human turn intervened since the step
|
|
6
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
|
|
8
|
-
//
|
|
7
|
+
// self-approval only when the human typed `/build --auto` or a step range
|
|
8
|
+
// (`N-M`, or a list such as `20,5-9`), clearing it otherwise (those strings can only come from a human
|
|
9
9
|
// keystroke, because `build` is disable-model-invocation: a grant the model
|
|
10
|
-
// could forge would be no grant).
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// the
|
|
10
|
+
// could forge would be no grant). The harness also sends a background job's
|
|
11
|
+
// completion notice through this event, as a prompt the human never typed, so
|
|
12
|
+
// a notice ticks nothing, keeps the grant, and clears only the ending `RELAY`
|
|
13
|
+
// holds from an earlier turn. When a step is in flight a typed prompt also
|
|
14
|
+
// emits ONE `UserPromptSubmit` additionalContext line so a fresh session
|
|
15
|
+
// (post-compaction, or a scripted `-p` turn where no skill prose is in context)
|
|
16
|
+
// still knows the beat: a tangent is parked, not chased, and a message that
|
|
17
|
+
// also asks something is answered before the park's block. Guidance only: it
|
|
18
|
+
// blocks nothing. It ALWAYS exits 0 and any failure degrades to no output, so
|
|
19
|
+
// neither the tick nor the emit can ever wedge prompting.
|
|
17
20
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
18
|
-
import { findSessionRoot, setGrant, stepPath, turnPath } from "../lib/sidecar.js";
|
|
21
|
+
import { clearRelay, findSessionRoot, notePrompt, readPrompt, setGrant, stepPath, turnPath, } from "../lib/sidecar.js";
|
|
22
|
+
import { normalizeStepList, readBuildArgs } from "../lib/steplist.js";
|
|
19
23
|
/**
|
|
20
|
-
* The hook entry point: apply the
|
|
24
|
+
* The hook entry point: apply the prompt, then emit the in-flight-step nudge
|
|
25
|
+
* when it counted as a human turn.
|
|
21
26
|
*
|
|
22
27
|
* Always returns 0: a broken turn must never wedge a prompt, so any failure is
|
|
23
28
|
* swallowed and degrades to no output.
|
|
24
29
|
*/
|
|
25
30
|
export function turn(cwd, _args) {
|
|
26
31
|
try {
|
|
27
|
-
applyTurn(cwd, readStdin())
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
if (applyTurn(cwd, readStdin())) {
|
|
33
|
+
const context = stepInFlightContext(cwd);
|
|
34
|
+
if (context !== null)
|
|
35
|
+
process.stdout.write(context);
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
catch {
|
|
33
39
|
// A broken turn must never wedge a prompt: swallow and exit 0.
|
|
@@ -78,7 +84,17 @@ function inFlightStep(root) {
|
|
|
78
84
|
}
|
|
79
85
|
}
|
|
80
86
|
/**
|
|
81
|
-
* The testable core: apply one
|
|
87
|
+
* The testable core: apply one prompt given the raw hook stdin, and say
|
|
88
|
+
* whether it counted as a human turn.
|
|
89
|
+
*
|
|
90
|
+
* A typed prompt ticks TURN and rewrites GRANT. A notice touches neither,
|
|
91
|
+
* because the latch reads TURN passing a step's entry stamp as its one sign
|
|
92
|
+
* that a human answered, and a grant the human typed has to outlive a job
|
|
93
|
+
* that reports back partway through the range. A notice that starts a turn of
|
|
94
|
+
* its own clears RELAY, whose ending was judged when its own turn ended; one
|
|
95
|
+
* the harness folds into the running turn arrives under that turn's prompt id
|
|
96
|
+
* and leaves RELAY alone, since the ending the turn just printed has yet to be
|
|
97
|
+
* judged.
|
|
82
98
|
*
|
|
83
99
|
* Split from the fd-0 read so the unit tests can drive it directly: an
|
|
84
100
|
* in-process test cannot feed fd 0 (the same constraint checkpoint's `--body`
|
|
@@ -87,10 +103,35 @@ function inFlightStep(root) {
|
|
|
87
103
|
export function applyTurn(cwd, raw) {
|
|
88
104
|
const root = findSessionRoot(cwd);
|
|
89
105
|
if (root === null)
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
return false; // no active session above cwd: silent no-op.
|
|
107
|
+
const { prompt, promptId } = readPayload(raw);
|
|
108
|
+
const notice = isNotice(prompt);
|
|
109
|
+
if (notice) {
|
|
110
|
+
if (promptId === null || promptId !== readPrompt(root))
|
|
111
|
+
clearRelay(root);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
writeFileSync(turnPath(root), `${readTurn(root) + 1}\n`);
|
|
115
|
+
setGrant(root, grantFromPrompt(prompt));
|
|
116
|
+
}
|
|
117
|
+
// Last, so a record that cannot be written never costs the tick or the grant.
|
|
118
|
+
notePrompt(root, promptId);
|
|
119
|
+
return !notice;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Whether a prompt is the harness reporting on background work rather than
|
|
123
|
+
* the human typing.
|
|
124
|
+
*
|
|
125
|
+
* Nothing in the payload marks one, but every notice opens on a frame of the
|
|
126
|
+
* harness's own at its very first character: `<task-notification>` for a
|
|
127
|
+
* finished shell job, a Monitor event, or a subagent's task, and
|
|
128
|
+
* `<agent-message ` for a subagent's or another session's report. A misread
|
|
129
|
+
* errs safe: a typed prompt taken for a notice costs one tick and one grant,
|
|
130
|
+
* so the latch only grows stricter, while a notice taken for a typed prompt
|
|
131
|
+
* is a turn no human took.
|
|
132
|
+
*/
|
|
133
|
+
export function isNotice(prompt) {
|
|
134
|
+
return prompt.startsWith('<task-notification>') || prompt.startsWith('<agent-message ');
|
|
94
135
|
}
|
|
95
136
|
/**
|
|
96
137
|
* Derive the GRANT content from the human's prompt, or null to clear it.
|
|
@@ -98,9 +139,12 @@ export function applyTurn(cwd, raw) {
|
|
|
98
139
|
* A grant is minted only from a literal `build` invocation the human typed:
|
|
99
140
|
* `build` is disable-model-invocation, so this string can only come from a
|
|
100
141
|
* human keystroke, never model-authored pressure: a grant the model can forge
|
|
101
|
-
* is no grant. A
|
|
102
|
-
*
|
|
103
|
-
*
|
|
142
|
+
* is no grant. A range mints `steps <list>`, exactly the steps it names in
|
|
143
|
+
* their normal form (`20, 5-9` mints `steps 5-9,20`), and beats `--auto`
|
|
144
|
+
* (bounded wins), so a range that does not parse mints nothing rather than
|
|
145
|
+
* falling back to `auto`. A bare `/build`, a bare step number, or any
|
|
146
|
+
* non-invocation prompt mints nothing. The namespaced `/plumbbob:build` form is
|
|
147
|
+
* honored alongside the bare one.
|
|
104
148
|
*
|
|
105
149
|
* The invocation must *start* a token: a slash preceded by a word character,
|
|
106
150
|
* `/`, `.`, `-`, or `~` is a path segment (`src/build`, `./build`), not a
|
|
@@ -120,43 +164,30 @@ export function grantFromPrompt(prompt) {
|
|
|
120
164
|
if (invocation === null)
|
|
121
165
|
return null;
|
|
122
166
|
const line = prompt.slice(invocation.index + invocation[0].length).split('\n', 1)[0] ?? '';
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (word === '')
|
|
128
|
-
continue;
|
|
129
|
-
if (word === '--auto') {
|
|
130
|
-
auto = true;
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const range = /^\d+-(\d+)$/.exec(word);
|
|
134
|
-
if (range !== null) {
|
|
135
|
-
ceiling = range[1];
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (/^\d+$/.test(word))
|
|
139
|
-
continue; // a bare step number: keep scanning for a range/--auto
|
|
140
|
-
break; // an unrecognized flag or free text: the arguments have ended
|
|
141
|
-
}
|
|
142
|
-
if (ceiling !== undefined)
|
|
143
|
-
return `range ${ceiling}`;
|
|
144
|
-
return auto ? 'auto' : null;
|
|
167
|
+
const args = readBuildArgs(line);
|
|
168
|
+
if (args.range)
|
|
169
|
+
return args.steps === null ? null : `steps ${normalizeStepList(args.steps)}`;
|
|
170
|
+
return args.auto ? 'auto' : null;
|
|
145
171
|
}
|
|
146
172
|
/**
|
|
147
|
-
*
|
|
173
|
+
* The `prompt` and `prompt_id` fields of the UserPromptSubmit JSON, as '' and
|
|
174
|
+
* null when either is absent.
|
|
148
175
|
*
|
|
149
176
|
* Absent, unparseable, or non-string input contributes nothing rather than
|
|
150
|
-
* wedging the tool: the tick still lands (a human turn did occur)
|
|
151
|
-
* prompt clears any GRANT; the verb never
|
|
177
|
+
* wedging the tool: the tick still lands (a human turn did occur), the empty
|
|
178
|
+
* prompt clears any GRANT, and a missing id records none; the verb never
|
|
179
|
+
* throws over bad stdin.
|
|
152
180
|
*/
|
|
153
|
-
function
|
|
181
|
+
function readPayload(raw) {
|
|
154
182
|
try {
|
|
155
183
|
const parsed = JSON.parse(raw);
|
|
156
|
-
return
|
|
184
|
+
return {
|
|
185
|
+
prompt: typeof parsed.prompt === 'string' ? parsed.prompt : '',
|
|
186
|
+
promptId: typeof parsed.prompt_id === 'string' && parsed.prompt_id !== '' ? parsed.prompt_id : null,
|
|
187
|
+
};
|
|
157
188
|
}
|
|
158
189
|
catch {
|
|
159
|
-
return '';
|
|
190
|
+
return { prompt: '', promptId: null };
|
|
160
191
|
}
|
|
161
192
|
}
|
|
162
193
|
/**
|
package/package.json
CHANGED
package/skills/build/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
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
|
|
4
|
-
argument-hint: "[step-number | step-range] [--auto]"
|
|
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`, or a list like `20,5-9`, self-approves exactly the steps it names, in build order, then stops."
|
|
4
|
+
argument-hint: "[step-number | step-range | step-list] [--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:*)
|
|
7
7
|
---
|
|
@@ -35,9 +35,10 @@ switch with `/model` and rerun to honor it, or wave you on. Advisory, never a ga
|
|
|
35
35
|
## What this skill does, in order
|
|
36
36
|
|
|
37
37
|
1. **Pick the step.** Use the number you were invoked with (for example `/plumbbob:build 4`), or,
|
|
38
|
-
if you were given a range like `/plumbbob:build 1-3
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
if you were given a range like `/plumbbob:build 1-3` or a list like `/plumbbob:build 20,5-9`,
|
|
39
|
+
start at its first undone step in build order, the one the dashboard above marks
|
|
40
|
+
`← requested`, and land only the steps it names (see the range note under `--auto`).
|
|
41
|
+
With no argument, don't resolve the next step yourself; the CLI does: bare `plumbbob build`
|
|
41
42
|
(step 2) enters the next undone step in build order (the `## Build order` line when the
|
|
42
43
|
plan has one, else the numbering) and refuses with a `/plumbbob:step` nudge when every
|
|
43
44
|
step is checkpointed.
|
|
@@ -181,6 +182,12 @@ switch with `/model` and rerun to honor it, or wave you on. Advisory, never a ga
|
|
|
181
182
|
line in the build-log's `## Log` and then truncates it, so the detail lands in the
|
|
182
183
|
tracked ledger rather than piling up on disk.
|
|
183
184
|
|
|
185
|
+
**A bare range's pause is its stop.** When the injected dashboard's ranges block lists
|
|
186
|
+
this step as a bare range (`/plumbbob:build 5`, its row marked `▸`), the plan reserved a
|
|
187
|
+
call for this pause, and the `stop:` line beneath the row names it. The recommendation
|
|
188
|
+
speaks to that call: the move you would take on the plan's question, and why, rather
|
|
189
|
+
than a verdict on the diff alone.
|
|
190
|
+
|
|
184
191
|
*Paste the turn.* Run `plumbbob handoff` and paste its output whole, verbatim, at top
|
|
185
192
|
level, trailing blank line included, then end the turn. Never nest it inside a fence of
|
|
186
193
|
your own; it carries fences of its own and they cannot nest. It prints the Now line
|
|
@@ -223,8 +230,11 @@ switch with `/model` and rerun to honor it, or wave you on. Advisory, never a ga
|
|
|
223
230
|
|
|
224
231
|
**Then hand off with the next model.** `plumbbob checkpoint` prints the whole boundary
|
|
225
232
|
ending itself: `**Checkpoint**: Step N complete (<sha>)`, the Verdict the step earned,
|
|
226
|
-
any advisory (a staged path outside the seam is the common one),
|
|
227
|
-
|
|
233
|
+
any advisory (a staged path outside the seam is the common one), the Stop part when
|
|
234
|
+
this landing completes a range (`**Stop**: Range 3 of 5 landed - <its stop>`, the reason
|
|
235
|
+
the build stops here), and Next Up. Relay that block whole, the Stop part with the rest
|
|
236
|
+
(the relay check holds a boundary that dropped it), run no second command, and write
|
|
237
|
+
nothing around it. It is the
|
|
228
238
|
orientation tier (no Your Call block, no recommendation), and it points at the next
|
|
229
239
|
undone step carrying that step's `- model:` recommendation (the plan's
|
|
230
240
|
smallest-model-that-fits call) so the human knows which `/model` to select before
|
|
@@ -287,7 +297,18 @@ and approves in the human's place**, and it **chains**:
|
|
|
287
297
|
advance the loop), or a new decision is needed. The step is still in flight and the
|
|
288
298
|
human has a call to make about it, so end on the same turn the default pause does:
|
|
289
299
|
write the detail file, run `plumbbob handoff`, and paste its block.
|
|
290
|
-
- **A
|
|
300
|
+
- **A call the plan reserves halts at its pause.** A step the plan's `## Build ranges`
|
|
301
|
+
names as a bare range (`/plumbbob:build 10`) is a decision the plan left for the human,
|
|
302
|
+
and `plumbbob build` says so as it enters the step (`step 10 ends at its pause, where
|
|
303
|
+
the plan reserves the call for the human`). Build it, verify it, and end on the same
|
|
304
|
+
turn a halt on trouble does: write the detail file, run `plumbbob handoff`, and paste
|
|
305
|
+
its block. The latch would let it land, since `--auto` grants every step, so keeping
|
|
306
|
+
the step open is yours to do
|
|
307
|
+
([D94 (auto-and-stops)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d94)).
|
|
308
|
+
A range that lands its steps runs through, since its stop is a review that can wait
|
|
309
|
+
for the end of the run, and a typed range stays exactly as typed.
|
|
310
|
+
- **A clean halt lands its step first.** The top of a requested range is reached (the
|
|
311
|
+
next step in build order is one the range does not name, or none is left), or no
|
|
291
312
|
planned steps remain, and `plumbbob build` names that step as it enters it (for
|
|
292
313
|
example `step 3 is the last undone step in the plan`). That step checkpoints like
|
|
293
314
|
every step before it, and its
|
|
@@ -302,36 +323,54 @@ only because the human asked for it by name. A range hands the clock back once i
|
|
|
302
323
|
step has landed: the step after it waits for the human's next run. The default (no flag,
|
|
303
324
|
no range) always ends at the pause.
|
|
304
325
|
|
|
305
|
-
### A step range (`N-M`) is a bounded `--auto`
|
|
326
|
+
### A step range (`N-M`, or a list like `20,5-9`) is a bounded `--auto`
|
|
306
327
|
|
|
307
328
|
`/plumbbob:build 1-3` self-approves steps 1 through 3 exactly as `--auto` does, then **stops
|
|
308
|
-
once step 3 has landed** instead of chaining to done.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
329
|
+
once step 3 has landed** instead of chaining to done. A range may also list its steps, numbers
|
|
330
|
+
and spans joined by commas (`/plumbbob:build 20,5-9`, typed with or without a space after a
|
|
331
|
+
comma), and it grants exactly the steps it names: the checkpoint refuses any other
|
|
332
|
+
([D91 (step-list-grants)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d91)).
|
|
333
|
+
The range *is* the opt-in; you do not also pass `--auto`.
|
|
334
|
+
|
|
335
|
+
Run it as the `--auto` loop, walked in build order. **Start at the range's first undone step
|
|
336
|
+
in build order, however it is written** (`5-9,20` under an order that puts 20 first starts at
|
|
337
|
+
20), and after each landing take the next undone step in build order. Build it if the range
|
|
338
|
+
names it; **stop before building any step the range does not name**, or once none is left. It
|
|
339
|
+
adds no machinery: just the one more entry already in the halt list above, and it is a clean
|
|
340
|
+
halt, so the top step is never held back for approval. The human approved it by typing the
|
|
341
|
+
range, and `plumbbob build` says so as it enters that step:
|
|
342
|
+
`step 3 is the top of the range you granted`, or, when the walk ends early (the plan runs
|
|
343
|
+
out, or the next step in build order is one the range does not name),
|
|
315
344
|
`the last undone step in the range you granted`.
|
|
316
345
|
|
|
317
|
-
-
|
|
318
|
-
|
|
319
|
-
and lands the single step `N`. Only a
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
check. Do not skip past
|
|
328
|
-
|
|
329
|
-
|
|
346
|
+
- **A range that parses**: build each step it names in build order, self-approving and
|
|
347
|
+
checkpointing each, the last included, then relay the last one's checkpoint block and end
|
|
348
|
+
the turn. `N-N` is a range like any other: it builds and lands the single step `N`. Only a
|
|
349
|
+
bare `/plumbbob:build N` ends at the pause.
|
|
350
|
+
- **A range that does not parse** (for example `3-1`, or `1--3`): that is not a range you can
|
|
351
|
+
walk, and it grants nothing; report it and stop rather than guess the intent.
|
|
352
|
+
- **A number past the last planned step** (for example `1-9` with three steps): build through
|
|
353
|
+
the last planned step the range names and stop; that is the existing "no planned steps
|
|
354
|
+
remain" halt, not an error. A number the plan lacks is never reached.
|
|
355
|
+
- **A step inside the range won't build** (its seam won't parse): `plumbbob build <n>` fails
|
|
356
|
+
exactly as it always does; surface it and stop, the same as a red check. Do not skip past
|
|
357
|
+
the gap.
|
|
358
|
+
- **The range starts above the next undone step**: you are jumping over earlier planned work;
|
|
359
|
+
note that you are skipping the steps before it, then proceed (the same latitude as a
|
|
330
360
|
single-number jump like `/plumbbob:build 4`).
|
|
331
|
-
- **The build order puts a
|
|
332
|
-
`1, 4, 2, 3` under `/plumbbob:build 1-3`):
|
|
333
|
-
|
|
334
|
-
|
|
361
|
+
- **The build order puts a step the range does not name inside it** (the order reads
|
|
362
|
+
`1, 4, 2, 3` under `/plumbbob:build 1-3`): the halt above fires before step 4, and
|
|
363
|
+
`plumbbob build` names step 1 as the last undone step in the range. The range that walks
|
|
364
|
+
the whole stretch lists step 4 too (`/plumbbob:build 1-4`, or `/plumbbob:build 1,4,2,3`).
|
|
365
|
+
- **At a range's stop, harvest before the next range.** No harvest runs between the steps
|
|
366
|
+
inside a range, so the parks pile up, and a blocker among them would otherwise ride into
|
|
367
|
+
the next one. When the human asks what comes next at a stop with parks open (the note's
|
|
368
|
+
`parked 2 of 7 open`), the move is `/plumbbob:harvest`, then the range the card names.
|
|
369
|
+
- **After an early stop, settle the step, then rerun what is left.** A halt on trouble
|
|
370
|
+
inside a range ends at that step's pause, and the grant ends with the turn. Once the
|
|
371
|
+
human approves and the step lands, the note beneath Next Up names what is left of the
|
|
372
|
+
range (`· range 3 of 5: /plumbbob:build 8-9`), and that is the command the human types
|
|
373
|
+
to carry on.
|
|
335
374
|
|
|
336
375
|
## The hard contracts
|
|
337
376
|
|
package/skills/harvest/SKILL.md
CHANGED
|
@@ -23,6 +23,10 @@ DESIGN boundary, not mid-step. Read the dashboard injected above:
|
|
|
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
|
|
|
26
|
+
A range's stop is the boundary that matters most. No harvest runs between the steps
|
|
27
|
+
inside a range, so the parks it piled up wait for the stop where it lands, and a
|
|
28
|
+
blocker among them is caught there before the next range builds on it.
|
|
29
|
+
|
|
26
30
|
## What this skill does
|
|
27
31
|
|
|
28
32
|
Walk the **Park list** in `build-log.md` item by item and, for each, **propose exactly
|
|
@@ -47,6 +51,11 @@ one line of reasoning, then **wait for the human to confirm or override**. Write
|
|
|
47
51
|
(`- <a id="d5"></a>**D5 (retry-cap)**: <the call>, *because* <why>`), never a bare `D5`.
|
|
48
52
|
A blocker that becomes a new step takes the next free number under `## Steps` and,
|
|
49
53
|
when it has to land before an existing undone step, its place in the sequence through
|
|
50
|
-
`plumbbob order 7 8 5` (the `## Build order` line), never by renumbering.
|
|
54
|
+
`plumbbob order 7 8 5` (the `## Build order` line), never by renumbering. When the plan
|
|
55
|
+
carries `## Build ranges`, the new step goes into a range too (the one it builds with,
|
|
56
|
+
or a bare range of its own when it brings a call the human has to make before it
|
|
57
|
+
lands), and a range it breaks is re-cut in the same confirmed edit
|
|
58
|
+
([D92 (build-ranges)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d92));
|
|
59
|
+
`plumbbob status` afterward carries a `⚠` row for any range still broken.
|
|
51
60
|
- Never reclassify or resolve an item the human hasn't confirmed, and default every
|
|
52
61
|
uncertain item to **tangent**, never to blocker.
|
package/skills/order/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: order
|
|
3
3
|
description: "Set the build order: turn the human's sequence (or a relative one, such as 7 and 8 before 5) into the full list of undone steps and write it by shelling `plumbbob order`, never by editing intent.md. A step keeps its number; the sequence moves."
|
|
4
|
-
argument-hint: "[steps in the sequence to build them]"
|
|
4
|
+
argument-hint: "[steps in the sequence to build them, such as 1, 6, 2-4, 7, 5]"
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
model: haiku
|
|
7
7
|
allowed-tools: Bash(plumbbob status:*), Bash(plumbbob order:*)
|
|
@@ -27,20 +27,30 @@ after the step in flight is the usual reason to run it.
|
|
|
27
27
|
## What this skill does
|
|
28
28
|
|
|
29
29
|
1. **Compose the full sequence.** Read the step list and the `build order` row on the
|
|
30
|
-
dashboard. Take the human's instruction, whether a full list (`7 8 5 10 6
|
|
31
|
-
one ("7 and 8 before 5", "10
|
|
32
|
-
|
|
33
|
-
lives in this one
|
|
30
|
+
dashboard. Take the human's instruction, whether a full list (`7 8 5 10 6`, or
|
|
31
|
+
`1, 6, 2-4, 7, 5` with spans and commas) or a relative one ("7 and 8 before 5", "10
|
|
32
|
+
last"), and turn it into **every undone step, in the sequence to build them**. Never
|
|
33
|
+
renumber a step and never move one inside `## Steps`; the sequence lives in this one
|
|
34
|
+
line.
|
|
34
35
|
2. **Show the sequence and get the human's OK in-turn.** When the human's own message states
|
|
35
36
|
the full sequence, that message **is** the approval: run the verb directly.
|
|
36
|
-
3. **Write it by shelling `plumbbob order 7 8 5 10 6`** via Bash.
|
|
37
|
-
|
|
37
|
+
3. **Write it by shelling `plumbbob order 7 8 5 10 6`** via Bash. The verb reads spans and
|
|
38
|
+
commas, with or without a space after one, so a list typed as `1, 6, 2-4, 7, 5` goes to it
|
|
39
|
+
as typed, and the line it writes spells the span out. `plumbbob order --reset` drops the
|
|
40
|
+
line, and the plan reads in document order again.
|
|
38
41
|
4. **Relay the ending verbatim, then stop.** The verb prints its whole ending: the
|
|
39
42
|
`**Build order**: 7, 8, 5, 10, 6` line, a blank line, and the `**Next Up**` pointer (back
|
|
40
43
|
at the step in flight, or forward to the first step in the new sequence). Run no second
|
|
41
|
-
command. A refusal (a number the plan lacks, a repeat, a step
|
|
42
|
-
CLI's call: report it verbatim, never retry or work around
|
|
43
|
-
number they meant.
|
|
44
|
+
command but the one in step 5. A refusal (a number the plan lacks, a repeat, a step
|
|
45
|
+
already checkpointed) is the CLI's call: report it verbatim, never retry or work around
|
|
46
|
+
it, and ask the human which number they meant.
|
|
47
|
+
5. **Read the ranges when the plan has them.** If the dashboard injected above shows a
|
|
48
|
+
`ranges` block, run `plumbbob status` after the verb and read that block again. A `⚠`
|
|
49
|
+
row that was not there before means the new sequence broke a range (most often
|
|
50
|
+
`the build order puts step 11 inside it`). This skill edits nothing, so it cannot re-cut
|
|
51
|
+
one: open the turn with one line naming the range, its drift words, and
|
|
52
|
+
`/plumbbob:refine` as the move that re-cuts it, then the verb's ending, whole, as the
|
|
53
|
+
turn's last text. With no new `⚠` row, or no ranges block, relay the ending alone.
|
|
44
54
|
|
|
45
55
|
## The one hard contract
|
|
46
56
|
|
package/skills/plan/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan
|
|
3
|
-
description: "Frame a fresh goal and author the whole plan (Frame, Decisions, Constraints, and
|
|
3
|
+
description: "Frame a fresh goal and author the whole plan (Frame, Decisions, Constraints, all Steps, and the build ranges) 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
|
|
6
6
|
allowed-tools: Read, Edit, Write, Bash(plumbbob status:*), Bash(plumbbob handoff:*), Bash(plumbbob start:*), Bash(plumbbob checkpoint:*), Bash(plumbbob agent list:*)
|
|
@@ -117,7 +117,48 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
|
|
|
117
117
|
It is advisory metadata for the human (`/plumbbob:status` surfaces it before each build),
|
|
118
118
|
never a gate, and nothing switches models automatically. Write it plain (no
|
|
119
119
|
backticks) and omit it when any model would do.
|
|
120
|
-
5. **
|
|
120
|
+
5. **Cut the build ranges.** With the steps written, say where the build stops for a
|
|
121
|
+
human call, under `## Build ranges`
|
|
122
|
+
([D92 (build-ranges)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d92)):
|
|
123
|
+
one sentence on how to drive the build, then one numbered item per range, in the
|
|
124
|
+
format the parser reads:
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
1. `/plumbbob:build 1`, **stop:** at step 1's pause, approve the schema before anything writes to it
|
|
128
|
+
- model: opus
|
|
129
|
+
2. `/plumbbob:build 2-5`, **stop:** review the parser before the renderers build on it
|
|
130
|
+
- model: sonnet
|
|
131
|
+
- note: <optional; what the range should watch for>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**A range ends where a human call is due, and nowhere else.** Three things make a
|
|
135
|
+
call: a decision the plan leaves open (an Open question, or a fork only a spike can
|
|
136
|
+
settle), a review before later steps build on what landed, and a thing only the human
|
|
137
|
+
can do, such as a push, a live key, or spending money. A range that runs through one
|
|
138
|
+
has the model make the human's call; a stop that marks none of them is a pause nobody
|
|
139
|
+
needed. The command's form says what kind of stop it is
|
|
140
|
+
([D85 (range-top-lands)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d85)).
|
|
141
|
+
A span such as `2-5` lands every step it names and stops at the boundary after the
|
|
142
|
+
last, so its stop is a review of what landed, or a decision the next steps need before
|
|
143
|
+
they build. A bare `N` builds step N to its pause, so write one for a call that has to
|
|
144
|
+
be made before its step lands, on the step's own work: approving the wording it
|
|
145
|
+
drafted, or the rule it found. Write each stop as what the human decides or reviews
|
|
146
|
+
there, in words they can act on cold.
|
|
147
|
+
|
|
148
|
+
Name every step in exactly one range, by its plan number. A fresh plan has no build
|
|
149
|
+
order, so the ranges follow the numbering. Give each range a `- model:` line naming the
|
|
150
|
+
strongest model any step inside it recommends, written plain the way a step's is,
|
|
151
|
+
because that is the `/model` the human picks before typing the command; any other
|
|
152
|
+
sub-line (a `- note:` on what to watch for) is the reader's, and the CLI leaves it
|
|
153
|
+
alone. Replace the template's placeholder item rather than writing beside it: an item
|
|
154
|
+
still holding its `<...>` fill-ins reads as no range at all.
|
|
155
|
+
|
|
156
|
+
**Size the ranges to the work.** A plan of two or three steps may carry one range, or
|
|
157
|
+
none. When every step would be its own bare range, delete the section: the default
|
|
158
|
+
loop already stops at each step's pause. A range is advice, never a grant
|
|
159
|
+
([D67 (auto-not-a-grant)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d67)):
|
|
160
|
+
the card names the range to type beneath Next Up, and the human still types it.
|
|
161
|
+
6. **Offer harness bindings** *(optional)*. If the build will lean on
|
|
121
162
|
user-authored agents, author `harness.json` in the build folder (beside `intent.md`)
|
|
122
163
|
and review it at the **same plan pause**, alongside the steps; bindings are
|
|
123
164
|
plan-adjacent configuration, so they converge with the plan. It binds agents to a
|
|
@@ -138,7 +179,7 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
|
|
|
138
179
|
`note` and decides when to run one mid-build. Skip the file entirely when no step
|
|
139
180
|
uses an agent; the loop runs identically without it. The plan commit picks it
|
|
140
181
|
up automatically (it lives in the build folder).
|
|
141
|
-
|
|
182
|
+
7. **Commit the plan.** Once the human approves the frame and steps, run
|
|
142
183
|
`plumbbob checkpoint --plan` to commit the scaffold on its own: subject
|
|
143
184
|
`chore(<scope>): plan` (with a `plumbbob plan` body marker), only `.plumbbob/builds/<slug>/`,
|
|
144
185
|
a `plan <sha>` line in
|
|
@@ -148,8 +189,9 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
|
|
|
148
189
|
rationale is worth carrying; skip it for a small plan. Do this
|
|
149
190
|
only on the human's approval; the plan is their convergence.
|
|
150
191
|
- **The plan pause is a decision turn.** Present the framed plan for the human's call,
|
|
151
|
-
|
|
152
|
-
|
|
192
|
+
its build ranges with it (each range's command and its stop, since a stop is where
|
|
193
|
+
the human will be asked, and moving one is cheapest now), then give it the cold
|
|
194
|
+
read (**§ The cold read**), write the result into `.plumbbob/detail.md`, and relay `plumbbob handoff --plan`'s block whole: the CLI
|
|
153
195
|
renders the your-call block with the moves that apply before anything is recorded and
|
|
154
196
|
prints your recommendation last (the decision tier of the
|
|
155
197
|
[turn anatomy](https://github.com/robmclarty/plumbbob/blob/main/docs/presentation.md)),
|
|
@@ -182,7 +224,7 @@ an agent can follow with `/plumbbob:build`. The argument only seeds how you get
|
|
|
182
224
|
(the `--body` earns its keep here), the files staying untracked. Say that
|
|
183
225
|
instead: the rationale is published in `git log`, not the folder, so pass a
|
|
184
226
|
fuller `--body` than you otherwise would, since the message is the whole record.
|
|
185
|
-
|
|
227
|
+
8. **Offer to stress-test it.** Suggest `/plumbbob:refine` to attack the frame for holes (or
|
|
186
228
|
to repair the plan as it drifts). Optional, the human's call.
|
|
187
229
|
|
|
188
230
|
## The cold read
|
|
@@ -198,7 +240,9 @@ Open questions, and keep it to one screen of reading. The lens:
|
|
|
198
240
|
- a collision with the existing code (read the files the seams name);
|
|
199
241
|
- a done-when no test or check can measure, or a seam that names a file that does not
|
|
200
242
|
exist or misses one that must change;
|
|
201
|
-
- a step too large to review in one pass, or a Decision with no *because
|
|
243
|
+
- a step too large to review in one pass, or a Decision with no *because*;
|
|
244
|
+
- a range that runs through a call the plan leaves open, so the model would make it;
|
|
245
|
+
- a range that stops where no call is due, a pause the human did not need.
|
|
202
246
|
|
|
203
247
|
Write what you found into `.plumbbob/detail.md`, overwriting whatever a past session
|
|
204
248
|
left, the findings first and the recommendation last:
|
package/skills/refine/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: refine
|
|
3
|
-
description: "Keep intent.md true: attack the plan for holes (append as Open questions) and refine or repair the Frame, Decisions, Constraints, and
|
|
4
|
-
argument-hint: "[focus]"
|
|
3
|
+
description: "Keep intent.md true: attack the plan for holes (append as Open questions) and refine or repair the Frame, Decisions, Constraints, Steps, and build ranges to match reality (`ranges` re-cuts the whole section). Usable at any point; you propose, the human approves."
|
|
4
|
+
argument-hint: "[focus | ranges]"
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
allowed-tools: Read, Edit, Bash(plumbbob status:*), Bash(plumbbob order:*)
|
|
7
7
|
---
|
|
@@ -22,7 +22,7 @@ it is `NO ACTIVE SESSION`, **refuse** in one line and tell the human to run
|
|
|
22
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
|
-
## Two modes
|
|
25
|
+
## Two modes, and a re-cut
|
|
26
26
|
|
|
27
27
|
- **Attack (diverge in the problem space).** Hand the **Frame**, **Decisions**, and
|
|
28
28
|
**Architecture sketch** a cold, adversarial read and surface holes: ambiguities,
|
|
@@ -57,6 +57,24 @@ is fine; refining is always available.
|
|
|
57
57
|
sequence to build them, and the `## Build order` line it writes is what every next-step
|
|
58
58
|
pick follows. Never renumber, and never edit that line by hand.
|
|
59
59
|
|
|
60
|
+
**A repair keeps the build ranges true.** When the plan carries `## Build ranges`, a
|
|
61
|
+
step the repair adds goes into a range (the one it builds with, or a bare range of its
|
|
62
|
+
own when it brings a call the human has to make before it lands), and a range the
|
|
63
|
+
repair breaks is re-cut in the same before/after
|
|
64
|
+
([D92 (build-ranges)](https://github.com/robmclarty/plumbbob/blob/main/docs/decisions.md#d92)).
|
|
65
|
+
Read `plumbbob status` once the edits are written: its ranges block carries a `⚠` row
|
|
66
|
+
for a range naming a step the plan lacks, a step two ranges name, a step the build order
|
|
67
|
+
puts inside a range that does not name it, and an undone step no range names, and none
|
|
68
|
+
once the section is sound.
|
|
69
|
+
- **Re-cut the ranges (`/plumbbob:refine ranges`).** On request, re-cut the whole
|
|
70
|
+
`## Build ranges` section against the plan as it stands, by the rule `/plumbbob:plan`
|
|
71
|
+
cuts it with: a range ends where a human call is due (a decision the plan leaves open,
|
|
72
|
+
a review before later steps build on what landed, or a thing only the human can do)
|
|
73
|
+
and nowhere else, a bare build for a call made on a step's own work before it lands,
|
|
74
|
+
every undone step in exactly one range, walked in build order, and a `- model:` line
|
|
75
|
+
per range. A landed range stays as written, since its call was made. Show the section
|
|
76
|
+
before and after, and write only what the human approves.
|
|
77
|
+
|
|
60
78
|
## The hard contracts
|
|
61
79
|
|
|
62
80
|
- **You propose; the human converges.** Surface holes and draft repairs, but the human
|
package/skills/status/SKILL.md
CHANGED
|
@@ -11,8 +11,8 @@ allowed-tools: Bash(plumbbob status:*)
|
|
|
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
|
This is a **thin driver** for `plumbbob status`. The dashboard above is your
|
|
14
|
-
orientation: the intent, the step list, the
|
|
15
|
-
inferred next move. Report it verbatim and point the human at that next move. This
|
|
14
|
+
orientation: the intent, the step list, the build ranges when the plan has them, the
|
|
15
|
+
parked/open-question counts, and the inferred next move. Report it verbatim and point the human at that next move. This
|
|
16
16
|
skill carries **no Edit and no Write tool**: the CLI is the source of truth, so
|
|
17
17
|
**never retry**, and never edit a file to change what the orientation says.
|
|
18
18
|
|
|
@@ -31,4 +31,9 @@ annotate it.
|
|
|
31
31
|
can switch (for example `/model sonnet`) before firing `/plumbbob:build`, or ignore it.
|
|
32
32
|
Guidance, never a gate. You relay that line; you do not re-state it on top of the
|
|
33
33
|
verbatim dashboard.
|
|
34
|
-
3.
|
|
34
|
+
3. When the plan carries `## Build ranges`, the dashboard lists them beneath the steps:
|
|
35
|
+
`ranges 2 of 5 done`, `✓` on a landed range and `▸` on the one holding the next step,
|
|
36
|
+
each undone range's stop on the line beneath it, and a `⚠` row for any range the plan
|
|
37
|
+
has outgrown. Its `next →` then names the range's command to type. You relay the block
|
|
38
|
+
with the rest; a `⚠` row is `/plumbbob:refine`'s to fix.
|
|
39
|
+
4. If it reads `NO ACTIVE SESSION`, tell the human to `/plumbbob:plan` to frame a goal.
|