opencode-thrum-pro 0.1.3 → 0.1.5

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.
@@ -0,0 +1,396 @@
1
+ ---
2
+ name: coordinator-deploying-the-fleet
3
+ description: "Use when rolling a build across ALL boxes - fleet deploy, fleet roll, rolling the fleet, deploy everywhere, ship to every box, canary then the rest, promote the canary, fleet rollout, deploying after a merge batch. Orchestrates the staged multi-box order and the promotion gate between stages, and delegates each individual box to the coordinator-deploying-a-box runbook. Load this BEFORE dispatching any box."
4
+ ---
5
+
6
+ # Coordinator: Deploying a Build Across the WHOLE FLEET — staged order, canary, promotion gate
7
+
8
+ **This skill is the ORCHESTRATION layer. It does not replace
9
+ `coordinator-deploying-a-box` — it calls it, once per box.**
10
+
11
+ - **This skill answers:** which box goes first, what must be true before the next
12
+ one goes, who runs each one, and what is owed after the last one.
13
+ - **`coordinator-deploying-a-box` answers:** how to deploy one box safely.
14
+
15
+ > # 🔴🔴 LOAD `coordinator-deploying-a-box` FOR EVERY BOX — **INCLUDING THE BUILD BOX, YOUR OWN BOX. NO EXCEPTIONS.**
16
+ >
17
+ > **This is the #1 way this skill fails, and it has failed this way MORE THAN ONCE
18
+ > (Leon, 2026-09-03).** You dispatch the per-box runbook to every REMOTE coordinator —
19
+ > and then you drive your OWN box (the build box) by hand, improvising the install and restart,
20
+ > because *"I'm the coordinator, I'll just do it."* **That improvisation IS the failure.**
21
+ > The per-box runbook carries steps that are invisible until they bite:
22
+ > - 🔴 **On macOS you MUST restart via `scripts/mac-daemon-restart-via-cron.sh`, NEVER a
23
+ > bare `thrum daemon restart`** — a terminal/VSCode-parented daemon is silently DENIED
24
+ > Local Network (TCC) permission and cannot dial LAN peers. A new binary is a new cdhash,
25
+ > so the "Allow devices on the local network" prompt MUST re-fire and the operator MUST
26
+ > click Allow. **A bare restart on the build box looks successful and leaves every LAN peer
27
+ > bridge hanging "connecting" forever** (§6b-mac of the per-box runbook).
28
+ > - the backup sizing formula, the SHA-CONTAINS-the-fix ancestry check, the by-effect
29
+ > verification, the strand-gate, the phase reconcile — none of which you carry in your head.
30
+ >
31
+ > **⇒ THE MOMENT YOU REACH YOUR OWN BOX (or ANY box you drive yourself), STOP AND LOAD
32
+ > `coordinator-deploying-a-box`.** Executing-directly (not dispatching) is the ONLY thing
33
+ > that differs on your own box — you still LOAD IT AND FOLLOW IT, step for step. Reaching for
34
+ > `thrum daemon restart`, `install.sh`, or `thrum backup` on your own box WITHOUT the per-box
35
+ > runbook loaded is the red flag; if you're doing that, you have already skipped this.
36
+
37
+ **Read both. Skipping the per-box runbook because you read this one — or because the box is
38
+ your OWN and you'll "just do it" — is the failure this split is designed to prevent.**
39
+
40
+ ---
41
+
42
+ ## 0. THE ONE RULE THAT OUTRANKS EVERYTHING HERE
43
+
44
+ 🔴 **NEVER ssh-deploy INTO a box. Each box's OWN coordinator drives its OWN
45
+ deploy, LOCALLY.** (Leon, standing, binding.)
46
+
47
+ A non-interactive ssh deploy silently drops node/pnpm from PATH, `make build-ui`
48
+ exits 127, **the deploy CONTINUES and reports success**, and lands an UNBUILT
49
+ SHA. The rule exists because the failure reports green.
50
+
51
+ **So your job in a fleet roll is DISPATCH AND GATE, never execution — except on
52
+ your own box, which you EXECUTE directly (not dispatch) but STILL under
53
+ `coordinator-deploying-a-box`, loaded and followed step for step (see the 🔴🔴 block
54
+ above).** "Except on your own box" means you run the commands yourself instead of
55
+ dispatching them — it does NOT mean you improvise them from memory. If you find
56
+ yourself typing `ssh` and `make install` in the same command, stop — and if you find
57
+ yourself running `thrum daemon restart` / `install.sh` / `thrum backup` on your own box
58
+ without having loaded the per-box runbook, stop there too.
59
+
60
+ ⚠️ **CLARIFICATION — an `scp` of the signed pro-bundle zip into a box's
61
+ `~/.thrum/update/` is DISTRIBUTION OF AN ARTIFACT, not a remote build or
62
+ install, and does NOT violate this rule.** The rule forbids driving a box's
63
+ build/install/restart FROM another machine. Copying an already-built,
64
+ already-signed bundle to where that box's own coordinator will unzip and
65
+ install it FROM is the sanctioned distribution mechanism (see §4) — the box
66
+ still does its own unzip + `install.sh` + `thrum daemon restart`, locally, on
67
+ its own account. Never conflate "the bytes moved over the network" with "the
68
+ box was remote-driven."
69
+
70
+ ---
71
+
72
+ ## 1. THE ORDER — ONE fixed point, the rest composed per roll
73
+
74
+ 🔴 **ONLY ONE THING IS A STANDING RULE: the designated canary (per
75
+ `.fleet.deploy_roster`) goes FIRST, ALONE.**
76
+
77
+ **EVERYTHING ELSE IS COMPOSED FRESH EACH TIME.** Recorded rolls disagree, and
78
+ they disagree deliberately.
79
+
80
+ 🔴 **"COMPOSED FRESH" IS THE ORDER, NOT THE MEMBERSHIP.** Every box in the roster
81
+ MUST be rolled — the roster is the fleet. Compose the order per roll, never the
82
+ set. Deferring a box requires the owner's explicit sign-off for that roll and a
83
+ message to that box's coordinator that it is deferred.
84
+
85
+ ⚠️ **DO NOT WRITE "THE BUILD BOX GOES LAST" INTO YOUR PLAN AS A RULE. IT IS A
86
+ DEFAULT, AND IT HAS BEEN DELIBERATELY OVERRIDDEN** — on 2026-07-28 the build box
87
+ went SECOND, because the owner needed the changes demonstrable at a meetup.
88
+ **The owner sets the order; this skill sequences whatever order is set.**
89
+
90
+ **Sensible default when nobody says otherwise:** the canary → the remaining
91
+ boxes (parallel where they share no state) → the build box last.
92
+ **Reason to keep the build box late:** it hosts the most agents and is the
93
+ coordinator's own box, so a bad build there costs you the ability to drive the
94
+ recovery. **That is a reason, not a law.**
95
+
96
+ Each box's coordinator and deploy target are defined in `.thrum/config.json`
97
+ under `.fleet.deploy_roster` — read them there; **never hardcode box
98
+ identities in this skill.**
99
+
100
+ 🔑 **This skill runs from the fleet orchestrator's own box (the build box); the
101
+ roster lives in that box's config.** Resolve the box list and, for each box,
102
+ its `ssh_alias` / `coordinator` / `daemon_id` from that same
103
+ `.fleet.deploy_roster` entry:
104
+
105
+ ```bash
106
+ jq -r '.fleet.deploy_roster | keys[] | select(startswith("_") | not)' .thrum/config.json
107
+ # box list — underscore-prefixed
108
+ # keys (e.g. `_note`) are roster
109
+ # metadata, not boxes; filter them
110
+ jq '.fleet.deploy_roster["<box>"]' .thrum/config.json # one box's entry
111
+ # (ssh_alias, coordinator, daemon_id)
112
+ ```
113
+
114
+ **Resolve coordinators by `daemon_id` JOIN, NEVER by name** — a name is a
115
+ label somebody chose; an agent named for a box has been found resident on a
116
+ different one. **The public-line box is EXCLUDED** (public 0.10.x line — see below).
117
+
118
+ ⚠️ **At least one box's position in the roll is INCONSISTENT across rolls** —
119
+ sometimes explicitly "in order", sometimes trailing. **Ask; do not assume.** It
120
+ is always driven by its own coordinator, never dispatched around.
121
+
122
+ ### PREP-AND-HOLD — the mechanism that makes a staged roll safe
123
+ Dispatch several boxes at once to do **READ-ONLY prep only**: measure current
124
+ state, take the backup, `git pull`, capture BEFORE readings. Then:
125
+
126
+ > **"PREPARE AND HOLD. CANCEL NOTHING. DO NOT RESTART until I release you BY
127
+ > NAME."**
128
+
129
+ **Release one box at a time, by name.** This gets the slow prep done in parallel
130
+ without any box mutating itself before the canary has reported.
131
+
132
+ ⚠️ **The public-line box's coordinator runs the PUBLIC 0.10.x line and is
133
+ EXCLUDED from 0.11 rolls.** Do not dispatch it.
134
+
135
+ 🔴 **RESOLVE EVERY COORDINATOR FROM `thrum team` AT DISPATCH TIME, NOT FROM A
136
+ CACHED NAME.** A name is a label somebody chose; the authoritative method is a
137
+ `daemon_id` join — join the `daemon_id` from `.fleet.deploy_roster` against
138
+ `thrum team`'s live roster, never match on name. An agent's NAME and its
139
+ WORKTREE NAME are not its location — an agent named for a box has been found
140
+ resident on a different one, and obeying that name would have driven the
141
+ forbidden ssh path.
142
+ ⚠️ **`thrum agent list --all` returns ZERO for agents that certainly exist** —
143
+ do not use it as your roster instrument, and do not read its empty output as an
144
+ absence.
145
+
146
+ ---
147
+
148
+ ## 2. THE PROMOTION GATE — what the canary must prove before anyone else goes
149
+
150
+ **Do not release stages 2-5 on "the canary finished." Release them on these,
151
+ each measured BY EFFECT on that box:**
152
+
153
+ - Installed binary `--version` **equals the pin exactly** — not "close", not
154
+ "the branch".
155
+ - Daemon restarted with a **NEW PID**, and `daemon status` reports the pin.
156
+ ⇒ **MERGED == INSTALLED == RUNNING, all three agreeing.**
157
+ - Schema **before AND after** — proves migrating-vs-not by effect rather than
158
+ from the delta.
159
+ - UI built for real (module count, signed) — **not the exit-127 shape**.
160
+ - Built from a **CLEAN detached worktree at the pin**, `git status --porcelain`
161
+ empty ⇒ contamination closed BY CONSTRUCTION, not by inspection.
162
+ - 🔑 **`sync_checkpoints` count BEFORE and AFTER, and they match.** A reset is
163
+ the silent peer-stranding failure that has **no repair command**. **This check
164
+ is worthless without a BEFORE reading** — take your own; do not skip it
165
+ because the canary's was clean.
166
+ - `crash-fatal.log` — 0 bytes, or read it before declaring success.
167
+
168
+ ⚠️ **"CANARY GREEN" IS NOT "ALL THREE PASSES PROVEN."** The canary usually
169
+ proves the BINARY pass only. Say which passes you verified, every time.
170
+
171
+ 🔴 **THE CANARY RESULT DOES NOT TRANSFER. EVERY BOX IS MEASURED ON ITS OWN
172
+ NUMBERS.** Measured instance: the canary came back green while another box
173
+ had **207 matured tombstones over live agents**. The canary proves the BUILD is
174
+ sound; it says nothing about any other box's state. **Do not let a green canary
175
+ talk a box out of taking its own BEFORE readings.**
176
+
177
+ ⏱ **GIVE A CONVERGENCE CHECK LONG ENOUGH TO DISCRIMINATE.** A short wait cannot
178
+ tell "the fix works" from "it had already converged before you looked." One roll
179
+ made a full 3-minute wait a hard requirement after a too-short check produced an
180
+ uninterpretable pass. **Pick the interval from what the mechanism needs, not
181
+ from impatience.**
182
+
183
+ ### The go/no-go has never been a fixed number — get it from the owner
184
+ The go/no-go has never been a fixed number. **State YOUR
185
+ bar explicitly before promoting, so it can be challenged.** An unstated bar is
186
+ indistinguishable from no bar.
187
+
188
+ ---
189
+
190
+ ## 3. THE THREE PASSES — a "deploy" silently conflates three independent things
191
+
192
+ **Every box owes all three. They fail independently and a box can be current on
193
+ one and month-stale on another.**
194
+
195
+ | Pass | What it updates | Who runs it |
196
+ |---|---|---|
197
+ | 1. install the pre-built, Developer-ID-signed pro-bundle via its own `install.sh`, **then** `thrum daemon restart` | the **binary** | the box's own coordinator |
198
+ | 2. `thrum roles refresh` **then** `thrum roles deploy` | **role preambles** | the box's own coordinator |
199
+ | 3. plugin refresh / reinstall (installs the BUNDLE's plugins — already made correct/complete by the plugin-bundle spine — rather than the box's own checkout) | **skills, commands, hooks** | 🔴 **the OPERATOR (Leon)** — a coordinator CANNOT self-serve this |
200
+
201
+ 🔴 **THE BOX NEVER BUILDS OR SIGNS ITS OWN BINARY. IT INSTALLS A DELIVERED
202
+ ARTIFACT.** `make install` (build-from-local-checkout-and-sign) is retired from
203
+ the Pass-1 fleet/box binary-update path. The box's job is: obtain the pro-bundle
204
+ zip (see §4), unzip it, run its `install.sh`, restart the daemon. Nothing on the
205
+ box compiles Go or codesigns.
206
+
207
+ 🔴 **PASS 2 ORDER IS LOAD-BEARING AND NOT OBVIOUS:** `refresh` FIRST (shipped
208
+ templates → role template), THEN `deploy` (role template → per-agent preamble).
209
+ **Running `deploy` alone re-renders agents from the OLD templates and reports
210
+ success.**
211
+
212
+ 🔴 **RUN PASS 2 BETWEEN THE BUNDLE INSTALL AND THE DAEMON RESTART, ALWAYS:**
213
+ bundle `install.sh` → `thrum roles refresh` → `thrum roles deploy` → daemon
214
+ restart. Do the refresh+deploy the instant `install.sh` finishes and BEFORE
215
+ restarting the daemon, so the current preamble is already in place when any
216
+ agent next runs `thrum prime`, restarts, or checks its preamble.
217
+
218
+ 🔴 **PASS 2 IS MANDATORY WHENEVER THE BUILD CHANGES
219
+ `internal/context/roleconfig/templates/` OR the compiled-in preamble.**
220
+ Preambles are RENDERED, not read live — installing a binary changes the source
221
+ and changes **nothing any agent reads**. There is **no staleness signal**: a box
222
+ serving a month-old render looks identical to a current one.
223
+
224
+ 🔴 **PASS 3 REQUIRES A PLUGIN VERSION BUMP OR IT REACHES NOBODY.** The install
225
+ cache is keyed by version; an unchanged version means the installer skips the
226
+ re-copy and every skill edit stays invisible. Invoke the `plugin-update` skill;
227
+ do not improvise it.
228
+
229
+ ### 🔴 THE BOX'S **REPO CHECKOUT** MUST BE AT THE PIN BEFORE PASS 3 — THE BINARY BEING AT THE PIN IS NOT SUFFICIENT
230
+
231
+ The plugin source is a **LOCAL PATH**, so pass 3 reads the checkout, not the
232
+ binary — a box whose binary is at the pin can still install a plugin version
233
+ one bump behind if its working tree lags.
234
+
235
+ ⚠️ **AND THE BOX'S OWN VERIFICATION CANNOT SEE IT.** It compared installed
236
+ skills against its own source, byte-for-byte, zero mismatches — and
237
+ **both sides were the stale version.** That proves the box is internally
238
+ consistent WITH ITSELF and is structurally incapable of detecting a stale
239
+ source. Same shape as render-fidelity-vs-doctrine-currency for preambles, except
240
+ **pass 3 has no equivalent of the ancestry check**, so nothing warns you.
241
+
242
+ 🔴 **IT IS SELF-SEALING.** The cache is keyed by version, so at the stale version
243
+ the installer sees a match and **skips the re-copy permanently.** Re-running the
244
+ refresh does NOT fix it. Only bringing the checkout to the pin and re-running
245
+ does.
246
+
247
+ **⇒ Before handing a box to the operator for pass 3, verify BY EFFECT that all
248
+ FOUR manifests read the pin's version.** A partial bump is worse than none — the
249
+ runtimes then disagree about which build they are. And name the cache directory
250
+ **explicitly** when verifying; never `ls | tail -1`, because version directories
251
+ do not sort the way you expect (`…1.12` sorts BELOW `…1.3` and `…1.5`, and
252
+ several versions coexist).
253
+
254
+ **When reporting a deploy, name which passes you verified.** "Deployed" that
255
+ silently covers all three is how staleness hides.
256
+
257
+ ---
258
+
259
+ ## 4. PRE-FLIGHT — before dispatching box 1
260
+
261
+ 0. 🔴 **FIRST ACTION, NON-OPTIONAL: `git fetch origin` then fast-forward-only
262
+ pull the repo root to `origin/<branch>`.** If the pull is not
263
+ fast-forwardable, STOP and surface it — never blind-merge in a shared tree.
264
+ Do this before reading any other pre-flight state below; a stale checkout
265
+ makes every subsequent check (trunk-green, pin, schema) a check against the
266
+ wrong tree.
267
+ 1. **Is trunk green?** Trunk-green is defined as `make gate` passing. A green
268
+ lane, a green package, or a clean dual review is **not** that claim.
269
+ ⚠️ **Publishing a green without naming its invocation is the most common
270
+ error here:** 0-of-6 and 0-of-15 are different claims in identical words.
271
+ 2. **PIN AN EXACT SHA. NEVER "tip".** Tip moves under boxes mid-roll — two boxes
272
+ told to deploy "tip" ship different code and both report success.
273
+ 3. **Migrating or not?** Compare `CurrentVersion` at the pin against each box's
274
+ running schema. A migrating roll pulls in the whole heavy-migration section
275
+ of the per-box runbook; a non-migrating one does not.
276
+ 4. **Forward-only:** each box's current SHA must be an ancestor of the pin.
277
+ Pair the check with a control that MUST refuse (an invented SHA).
278
+ 5. **Backup sizing** — the per-box runbook carries the formula. A percentage
279
+ rule is not it, and a stale `current/` answers "are we protected?" with a
280
+ wrong yes.
281
+ 6. **Announce the pin and the order** to every coordinator before starting, so
282
+ nobody deploys a different SHA.
283
+ 7. 🔴 **BUILD ONCE, DISTRIBUTE THE SAME ZIP TO EVERY BOX.** The build box
284
+ produces exactly ONE `make pro-bundle` at the pinned SHA. That
285
+ single zip — never rebuilt per box — is what every box in the roll installs
286
+ from. The staged roll therefore orchestrates three phases in order:
287
+ **build once** (the build box, `make pro-bundle` at the pin) **→ distribute**
288
+ (hand the same zip to each box's coordinator, via drop-folder or direct
289
+ hand-off — see below) **→ each box installs from the delivered bundle**
290
+ (§3 Pass 1). No box re-derives the artifact; every box's binary is
291
+ byte-identical because it came from the same zip.
292
+ - **Distribution mechanism 1 — drop-folder:** the built zip is placed where
293
+ each box's own sync/fetch path picks it up into its local
294
+ `~/.thrum/update/` for that box's coordinator to find and unzip.
295
+ - **Distribution mechanism 2 — hand-off:** the coordinator running the roll
296
+ hands the zip directly to a box's coordinator (e.g. `scp` into
297
+ `~/.thrum/update/` — see §0's clarification: this is artifact
298
+ distribution, not remote build/install).
299
+ - Whichever mechanism is used, confirm the box installed from the SAME
300
+ bundle (matching version/checksum) that was built at the pin — never a
301
+ locally-reconstructed one.
302
+ - 🔴 **NEVER pass `PRO_BUNDLE_VERSION=$(git describe)` when building the pro
303
+ bundle — trust the Makefile default** (`v0.11.0-rc.1` as of this writing,
304
+ re-check the current default before citing it). `git describe` falls back
305
+ to the nearest ancestor tag when the exact commit isn't tagged, which can
306
+ silently produce a WRONG version string — this is exactly how a stale
307
+ `v0.10.6-rc.4` string previously shipped in a v0.11 build: the
308
+ `v0.11.0-rc.1` tag was stranded on an unmerged release branch, so
309
+ `git describe` fell back to an ancestor v0.10.6 tag.
310
+
311
+ ---
312
+
313
+ ## 5. DISPATCHING A BOX — what the message must carry
314
+
315
+ 🔑 **Resolve the box's `ssh_alias` / `coordinator` / `daemon_id` from
316
+ `.fleet.deploy_roster` in `.thrum/config.json` before dispatching** (see §1) —
317
+ never from a remembered name. Join the coordinator by `daemon_id` against
318
+ `thrum team`'s live roster, NEVER by name.
319
+
320
+ Give each coordinator, explicitly:
321
+
322
+ - **The exact pinned SHA** and the instruction to build from a clean detached
323
+ worktree at it.
324
+ - **An instruction to load `coordinator-deploying-a-box` and follow it** — not a
325
+ summary of it. ⚠️ **A summary you wrote reads as complete precisely because
326
+ you wrote it**, and its omissions are silent.
327
+ - **Which passes it owes** (1 and 2; pass 3 is the operator's).
328
+ - **Its own BEFORE readings** — `sync_checkpoints`, schema, PID.
329
+ - **That acceptance is BY EFFECT, never by exit code.**
330
+ - **That it must report which passes it verified**, separately.
331
+
332
+ ---
333
+
334
+ ## 6. AFTER THE LAST BOX
335
+
336
+ - 🔴 **ROSTER COMPLETENESS GATE — first.** Re-enumerate the roster from config,
337
+ not from propagated deploy-state (a box with a wedged sync never propagates its
338
+ row). Confirm every box is rolled on the pin or owner-deferred with its
339
+ coordinator notified. Name each box and its disposition in the roll-complete
340
+ report.
341
+ - **Agent phase reconciliation, per box.** A restart leaves recorded `phase`
342
+ disagreeing with reality — live agents read `stale`, dead ones can read
343
+ `active`. Phase is local state and does not cross the peer boundary, so every
344
+ box runs it against its own daemon.
345
+ - **Restart the orchestrators and long-lived agents** so they pick up the new
346
+ preambles and skills. 🔴 **Agents adopt a new preamble ON THEIR NEXT RESTART,
347
+ not immediately** — a live agent keeps behaving per the identity it was born
348
+ with. Track adoption by session birth time, never file mtime.
349
+ - **Pre-release test suite — CHECK WHETHER IT IS OWED; do not assume it is.**
350
+ It is documented as a gate for cutting an RC/release, and a remote box runs it
351
+ after fleet deploys by standing arrangement. ⚠️ **A search of past rolls did
352
+ NOT establish it as a mandatory step for a routine binary/preamble/plugin
353
+ roll.** Read the run index: if its newest entry predates this deploy, the suite
354
+ has not run against what is now deployed — then decide, with the owner,
355
+ whether this roll warrants one. **Stated as a gap rather than invented as a
356
+ rule.**
357
+ - **Update the deploy-state record** — per box: serving SHA, schema, AS OF, and
358
+ how established. **Do not normalise every row to one SHA**; an unmeasured row
359
+ is not a measured negative, and a tidied row is indistinguishable from a fresh
360
+ measurement.
361
+ - **Sweep for SHA-anchored rules that just went stale.** A superseded SHA has
362
+ two roles that fail in OPPOSITE directions: as a GUARD it refuses legitimate
363
+ work and presents as caution; as a TARGET it validates the wrong artifact and
364
+ produces **a green that means nothing**. The target direction is the dangerous
365
+ one and it is the one a guard-sweep misses. Prefer re-deriving the live build
366
+ at run time over re-anchoring, which only re-arms the trap for the next roll.
367
+
368
+ ---
369
+
370
+ ## 7. HOLDS
371
+
372
+ - **A fleet deploy is the OWNER'S CALL.** A lifted prohibition is not a
373
+ permission.
374
+ - **Any box may hold its own deploy** and must say why. A box-local blocker that
375
+ does not touch the deploy path is not a reason to hold — check whether the
376
+ runbook's acceptance checks actually need the thing that is broken.
377
+ - **If the canary fails, the roll stops.** Do not promote on a partial result.
378
+ - **Deploy often, in small batches.** A large roll bundles unrelated changes, so
379
+ when a box misbehaves afterwards, attribution across a hundred commits gets
380
+ expensive fast.
381
+
382
+ ---
383
+
384
+ ## Red flags — STOP
385
+
386
+ - `ssh` and `make install` in the same command.
387
+ - Dispatching a box by NAME without resolving its coordinator at dispatch time.
388
+ - Promoting past the canary on "it finished" rather than on the §2 checks.
389
+ - Reporting "deployed" without saying WHICH of the three passes was verified.
390
+ - Running `roles deploy` without `roles refresh` first.
391
+ - Expecting skill changes to reach agents without a plugin version bump.
392
+ - Deploying "tip" instead of a pinned SHA.
393
+ - Reading an installer's exit 0 as proof the binary landed.
394
+ - Taking an `after` reading with no `before` — especially `sync_checkpoints`.
395
+ - Summarising the per-box runbook into a dispatch instead of telling the
396
+ coordinator to load it.
@@ -120,8 +120,8 @@ rediscovering these the hard way:
120
120
  7. Build+test the MERGED-tree result as a SEPARATE condition — neither gate
121
121
  currently runs a build of the actual post-merge tree; a clean pre-merge
122
122
  build/test does not prove the merged result compiles or passes.
123
- 8. Use `rm -r`, NEVER `rm -rf`, and use `git worktree remove --force` to drop a
124
- worktree. A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp` allow,
123
+ 8. Use `rm -r`, NEVER `rm -rf`; use plain `git worktree remove` to drop a worktree, never
124
+ `--force` as the default (see item 12 below). A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp` allow,
125
125
  so `rm -rf` raises a human permission prompt EVERY time regardless of path —
126
126
  it stalls gate sub-agents mid-run waiting on a keystroke. `rm -r` runs free. Do NOT widen the ask rule
127
127
  to work around this; that entry is the only deletion protection on the box.
@@ -154,7 +154,11 @@ rediscovering these the hard way:
154
154
  HEAD is a gate-produced merge reachable from no ref and removal orphans
155
155
  it. Usually fine (a gate merge is reproducible by redoing it) but say so
156
156
  in your report rather than doing it silently.
157
- Then `git worktree remove --force <wt>`.
157
+ Then `git worktree remove <wt>` — **plain, no `--force`.** Its rc=128 refusal backstops
158
+ ONLY untracked/modified content (see rule 8 on `rm -r`) — it does NOT cover gitignored
159
+ content, which git removes silently with no refusal; a clean rc=0 is not proof nothing of
160
+ value was in there (see coordinator-assessing-agent-completion's reap procedure). `--force`
161
+ is a justified override only, never the default (see coordinator-merging-code §7a).
158
162
 
159
163
  ## Trigger-directory skip logic
160
164
 
@@ -110,8 +110,8 @@ dispatch time — hand this list verbatim:
110
110
  (c) only if a pipeline is unavoidable, use `${pipestatus[1]}` on zsh /
111
111
  `${PIPESTATUS[0]}` on bash — and STATE WHICH SHELL, because the same
112
112
  string means different things in each.
113
- 8. Use `rm -r`, NEVER `rm -rf`, and use `git worktree remove --force` to drop
114
- a worktree. A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp`
113
+ 8. Use `rm -r`, NEVER `rm -rf`; use plain `git worktree remove` to drop a worktree, never
114
+ `--force` as the default (see item 12 below). A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp`
115
115
  allow, so `rm -rf` raises a human permission prompt EVERY time regardless
116
116
  of path and stalls gate sub-agents mid-run waiting on a keystroke. `rm -r`
117
117
  runs free. Do NOT widen the ask rule to work around this; that entry is
@@ -149,7 +149,11 @@ dispatch time — hand this list verbatim:
149
149
  HEAD is a gate-produced merge reachable from no ref and removal orphans
150
150
  it. Usually fine (a gate merge is reproducible by redoing it) but say so
151
151
  in your report rather than doing it silently.
152
- Then `git worktree remove --force <wt>` (see rule 8 on `rm -r`). Rule 11's
152
+ Then `git worktree remove <wt>` — **plain, no `--force`.** Its rc=128 refusal backstops
153
+ ONLY untracked/modified content (see rule 8 on `rm -r`) — it does NOT cover gitignored
154
+ content, which git removes silently with no refusal; a clean rc=0 is not proof nothing of
155
+ value was in there (see coordinator-assessing-agent-completion's reap procedure). `--force`
156
+ is a justified override only, never the default (see coordinator-merging-code §7a). Rule 11's
153
157
  hazard notice on its own — teardown can destroy uncommitted state — reads
154
158
  as a reason NOT to tear down. A warning without a procedure does not
155
159
  produce caution; it produces paralysis plus litter.
@@ -43,9 +43,10 @@ at every stage:
43
43
  each time (`verify-against-source` + a prose-quality reviewer, sonnet sub-agents
44
44
  in parallel — see "Review-loop mechanics" below). Skipping any review gate is a
45
45
  documented anti-pattern. The brainstorm review catches design issues; the plan
46
- review catches contract-drift and quality issues `writing-plans`' internal
47
- reviewer misses; the prompt review catches plan→prompt translation errors before
48
- the implementer executes against them.
46
+ review is the SOLE quality gate on the plan doc — the researcher authors the
47
+ plan directly (no external tool with its own internal reviewer sits upstream of
48
+ this gate); the prompt review catches plan→prompt translation errors before the
49
+ implementer executes against them.
49
50
 
50
51
  ## Subagent model selection
51
52
 
@@ -81,7 +82,7 @@ forwarding.
81
82
  ### Footer → commit → stamp (per stage)
82
83
 
83
84
  1. After the artifact is written, append the gate footer:
84
- `<!-- THRUM-GATE: stage=<brainstorm|plan|prompt> next=<dual-review|writing-plans|project-setup|dispatch> -->`
85
+ `<!-- THRUM-GATE: stage=<brainstorm|plan|prompt> next=<dual-review|plan|project-setup|dispatch> -->`
85
86
  2. **Commit the artifact (WIP) including the footer** — this gives the
86
87
  supplementary `requesting-code-review` pass a real `HEAD~1..HEAD` range.
87
88
  3. Run the dual review against that range; each fix cycle commits its changes
@@ -120,7 +121,7 @@ forwarding.
120
121
 
121
122
  ### Soft pre-flight greps (the SOFT enforcement tier)
122
123
 
123
- Before invoking `writing-plans` (Phase 6) and before `project-setup` (Phase 7),
124
+ Before writing the plan (Phase 6) and before `project-setup` (Phase 7),
124
125
  grep the prior artifact for `THRUM-REVIEW: stage=<S> verdict=Ready:Yes` (or
125
126
  `verdict=OVERRIDE`); absent → STOP and run the review first. Anchor the match —
126
127
  `grep -E '...verdict=Ready:Yes([[:space:]]|-->|$)'`, never `grep -F` — or an
@@ -150,32 +151,22 @@ structurally-enforceable gate is `project-setup` Phase 0 (it hard-bails).
150
151
  `## Deviations from Source` block with attribution `owner decision`, never
151
152
  silently absorbed.
152
153
 
153
- ### Superpowers dependency (D6)
154
+ ### No external plugin drives this pipeline (D6)
154
155
 
155
- The wrapper drives `superpowers:brainstorming` / `writing-plans`. Two distinct
156
- pre-flight behaviors:
156
+ Neither the brainstorm stage (Phase 2) nor the plan stage (Phase 6) invokes an
157
+ external skill — the researcher writes both artifacts directly, governed by
158
+ this skill's own protocol block (Phase 2) and structure/stamp/deviations
159
+ requirements (Phase 6). There is nothing to pre-flight-check or bail on for
160
+ either stage, and no `/plugin install` path: no such plugin is declared
161
+ anywhere in this repo's `.claude-plugin/marketplace.json` (thrum-tsaq4).
157
162
 
158
- - `requesting-code-review` not resolvable → SKIP the supplementary quality pass
159
- gracefully (the loop still runs on the general-purpose primary).
160
- - `brainstorming` / `writing-plans` not present → **BAIL** with an install
161
- instruction (`/plugin install superpowers@<marketplace>`).
163
+ The one genuinely optional external supplement is `requesting-code-review`
164
+ (Review-loop mechanics, "Quality" row) — not resolvable → SKIP the
165
+ supplementary quality pass gracefully; the loop still runs on the
166
+ general-purpose primary, which is authoritative regardless.
162
167
 
163
- `verify-against-source` carries no superpowers dependency and always works.
164
-
165
- ### Countermand the superpowers chain (outcome-based)
166
-
167
- `brainstorming` auto-chains to `writing-plans`, and `writing-plans` defaults
168
- pull toward subagent-driven execution — both bypass thrum's `project-setup`. At
169
- each invocation, inject (keyed on the concept, so it survives upstream
170
- rewording):
171
-
172
- > Regardless of any execution-handoff, "recommended" sub-skill, or save-location
173
- > default these skills emit, the ONLY downstream path in thrum is the next thrum
174
- > stage. After the artifact is written, STOP — do not auto-chain. Save to the
175
- > thrum path, not the superpowers default. For `writing-plans`: remove/replace
176
- > the plan-header line matching the stable substring
177
- > `REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development` and ignore
178
- > the Execution-Handoff offer — the plan feeds `project-setup`.
168
+ `verify-against-source` and the general-purpose prose-quality pass carry no
169
+ external-plugin dependency and always work.
179
170
 
180
171
  ## Phase 1 — Set up the worktree, branch, and agent
181
172
 
@@ -353,12 +344,10 @@ distinction in the inbox display):
353
344
  8. **Go-deep-then-ready instruction** — one sentence telling them to confirm
354
345
  readiness, research aggressively, and have meaty material ready when the user
355
346
  joins (not to sit idle waiting).
356
- 9. **Countermand callout** — `superpowers:brainstorming`'s terminal state is
357
- "invoke writing-plans". Tell the researcher explicitly: when brainstorming
358
- reaches that terminal state, STOP at the design doc — do NOT auto-chain to
359
- `writing-plans`. The brainstorm goes through the Phase 3 review gate first,
360
- then Phase 6 runs `writing-plans` deliberately (with its own countermand).
361
- See "Review-loop mechanics → Countermand the superpowers chain."
347
+ 9. **Stop-at-the-artifact instruction** — tell the researcher explicitly: once
348
+ the brainstorm design doc is drafted, STOP there. It goes through the
349
+ Phase 3 review gate before anything else happens; the plan doc is a
350
+ separate, deliberate Phase 6 step after the brainstorm is LOCKED.
362
351
 
363
352
  Send the whole thing as one `thrum send` call. The recipient's runtime will
364
353
  display it as a single inbox message; structure beats brevity here.
@@ -475,23 +464,21 @@ expensive footguns hide.
475
464
  ## Phase 6 — Researcher writes the plan (with dual-review gate)
476
465
 
477
466
  Once the brainstorm is LOCKED (and any companion design spec is LOCKED), the
478
- researcher runs `superpowers:writing-plans` to convert brainstorm + spec into
479
- the implementation plan doc. (First, the soft pre-flight grep: `grep -F` the
480
- brainstorm for its `THRUM-REVIEW: stage=brainstorm verdict=Ready:Yes` (or
481
- `OVERRIDE`) stamp — absent → STOP and finish the brainstorm review.) **Inject
482
- the outcome-based countermand** (see Review-loop mechanics) at the
483
- `writing-plans` invocation: stop when the plan is written, save to the thrum
484
- path, and strip the `subagent-driven-development` plan-header line — the plan
485
- feeds `project-setup`, not superpowers execution.
467
+ researcher writes the implementation plan doc directly, converting the
468
+ brainstorm + spec into concrete steps. (First, the soft pre-flight grep:
469
+ `grep -F` the brainstorm for its `THRUM-REVIEW: stage=brainstorm
470
+ verdict=Ready:Yes` (or `OVERRIDE`) stamp — absent → STOP and finish the
471
+ brainstorm review.) The plan feeds `project-setup` — there is no other
472
+ downstream path.
486
473
 
487
474
  **The plan doc gets the SAME dual-review treatment as the brainstorm.** This
488
- review step is mandatory — `writing-plans` has an internal reviewer, but real-
489
- world experience shows that's not sufficient. Independent review catches
490
- contract-drift and quality issues the internal reviewer misses.
475
+ review step is mandatory: there is no internal reviewer upstream of it, so
476
+ this gate is the plan's only quality check. Independent review catches
477
+ contract-drift and quality issues a single author would miss.
491
478
 
492
479
  **The researcher (not coord) dispatches the dual-review** in their own worktree:
493
480
 
494
- 1. Researcher writes plan v1 via `writing-plans` skill (countermand applied).
481
+ 1. Researcher writes plan v1 directly.
495
482
  2. Researcher authors the `## Deviations from Source` block per
496
483
  `claude-plugin/commands/_deviations-protocol.md`, diffing plan v1 against
497
484
  the brainstorm + design spec — BEFORE dual-review, so
@@ -573,9 +560,8 @@ review catches translation errors (plan → prompt) plus prompt-specific quality
573
560
  4. Researcher signals "project-setup complete + post-setup dual-review applied"
574
561
  back to coord, citing both review passes + final artifact paths.
575
562
 
576
- Reaffirmation (countermand at the prompt stage): `project-setup` is the only
577
- downstream path — do not adopt `subagent-driven-development` execution even if a
578
- superpowers skill suggests it.
563
+ Reaffirmation (at the prompt stage): `project-setup` is the only downstream
564
+ path for the implementer prompt.
579
565
 
580
566
  If the researcher signals "project-setup complete" WITHOUT mentioning the
581
567
  post-setup reviews, ASK explicitly: "did the post-setup dual-review run on the
@@ -607,9 +593,9 @@ encodes this; include the verbatim protocol block in every briefing.
607
593
  ❌ **Half-batched findings.** Sending review findings before BOTH dual reviews
608
594
  complete. Researcher fixes batch 1 and never sees batch 2.
609
595
 
610
- ❌ **Skipping the post-plan dual-review.** Treating `writing-plans` skill's
611
- internal reviewer as sufficient and proceeding directly to `project-setup`
612
- without an independent review of the plan doc. The plan and the impl
596
+ ❌ **Skipping the post-plan dual-review.** Proceeding directly to
597
+ `project-setup` without an independent review of the plan doc — there is no
598
+ internal reviewer upstream of it to lean on. The plan and the impl
613
599
  prompt MUST get the same dual-axis review treatment the brainstorm gets — Phase
614
600
  6 + Phase 7 explicit.
615
601
 
@@ -15,10 +15,9 @@ single report.
15
15
  **Core principle:** The coordinator decides, sub-agents investigate. Keep
16
16
  investigation results out of the main context until consolidated.
17
17
 
18
- **REQUIRED BACKGROUND:** Read superpowers:dispatching-parallel-agents before
19
- using this skill. That skill
20
- covers general parallel dispatch. This skill extends it with a specific research
21
- workflow: partition, investigate to disk, consolidate, then decide.
18
+ This skill is self-contained: partition, investigate to disk, consolidate,
19
+ then decide — the full dispatch mechanics (Agent tool syntax, background mode,
20
+ read-only scoping) are in "Core Pattern" below.
22
21
 
23
22
  ## When to Use
24
23