opencode-thrum-pro 0.1.4 → 0.1.6

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 (69) hide show
  1. package/assets/commands/thrum-_compact-runtime-commands.md +61 -0
  2. package/assets/commands/thrum-_snapshot-protocol.md +17 -6
  3. package/assets/commands/thrum-_stamp-protocol.md +9 -2
  4. package/assets/commands/thrum-compact-extended.md +352 -0
  5. package/assets/commands/thrum-compact.md +300 -0
  6. package/assets/commands/thrum-inbox.md +1 -1
  7. package/assets/commands/thrum-restart-extended.md +84 -11
  8. package/assets/commands/thrum-restart.md +105 -13
  9. package/assets/commands/thrum-send.md +4 -1
  10. package/assets/commands/thrum-sleep-extended.md +67 -46
  11. package/assets/commands/thrum-sleep.md +67 -58
  12. package/assets/skills/adversarial-critique/SKILL.md +5 -8
  13. package/assets/skills/agent-messaging-protocol/SKILL.md +35 -0
  14. package/assets/skills/brainstorm-steward/SKILL.md +65 -11
  15. package/assets/skills/brainstormer-staying-current/SKILL.md +113 -0
  16. package/assets/skills/choosing-subagent-models/SKILL.md +14 -0
  17. package/assets/skills/conversation-only-context/SKILL.md +11 -11
  18. package/assets/skills/conversation-only-context/resources/driver-subagent-pattern.md +1 -1
  19. package/assets/skills/conversation-only-context/resources/remote-environment-scenarios.md +1 -1
  20. package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +98 -6
  21. package/assets/skills/coordinator-context-monitoring/SKILL.md +29 -19
  22. package/assets/skills/coordinator-deploying-a-node/SKILL.md +124 -0
  23. package/assets/skills/coordinator-dispatching-work/SKILL.md +24 -11
  24. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +62 -20
  25. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +6 -6
  26. package/assets/skills/coordinator-merging-code/SKILL.md +25 -11
  27. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +28 -7
  28. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +3 -3
  29. package/assets/skills/coordinator-rolling-out-to-nodes/SKILL.md +92 -0
  30. package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +3 -3
  31. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +58 -71
  32. package/assets/skills/coordinator-running-review-cycles/SKILL.md +15 -4
  33. package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +0 -2
  34. package/assets/skills/efficient-multi-agent-research/SKILL.md +6 -7
  35. package/assets/skills/implementer-orchestrating-execution/SKILL.md +11 -14
  36. package/assets/skills/orchestrate/SKILL.md +47 -35
  37. package/assets/skills/persistent-watcher-archetype/SKILL.md +188 -37
  38. package/assets/skills/persistent-watcher-archetype/resources/capture_archive.py +618 -0
  39. package/assets/skills/persistent-watcher-archetype/resources/jev_watcher_filter.py +837 -0
  40. package/assets/skills/persistent-watcher-archetype/resources/roster-watch.sh +1140 -0
  41. package/assets/skills/persistent-watcher-archetype/resources/roster-watch_test.sh +291 -0
  42. package/assets/skills/persistent-watcher-archetype/resources/thrum-capture-fallback.sh +2 -2
  43. package/assets/skills/persistent-watcher-archetype/resources/thrum-watch-pane-capture.sh +20 -8
  44. package/assets/skills/prime-agent/SKILL.md +10 -0
  45. package/assets/skills/project-setup/SKILL.md +22 -16
  46. package/assets/skills/project-setup/resources/implementation-agent.md +56 -35
  47. package/assets/skills/researcher-investigating/SKILL.md +2 -5
  48. package/assets/skills/state-migration/SKILL.md +1 -1
  49. package/assets/skills/thrum/SKILL.md +14 -7
  50. package/assets/skills/thrum/resources/ANTI_PATTERNS.md +16 -18
  51. package/assets/skills/thrum/resources/CLI_REFERENCE.md +17 -11
  52. package/assets/skills/thrum/resources/LISTENER_PATTERN.md +9 -3
  53. package/assets/skills/thrum/resources/MESSAGING.md +18 -11
  54. package/assets/skills/thrum/resources/WORKTREES.md +1 -1
  55. package/assets/skills/thrum-memory/SKILL.md +1 -1
  56. package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +1 -1
  57. package/assets/skills/update-queue/SKILL.md +6 -8
  58. package/assets/skills/using-the-dashboard/SKILL.md +30 -0
  59. package/assets/skills/using-the-queue/SKILL.md +76 -5
  60. package/assets/skills/using-thrum-state/SKILL.md +84 -1
  61. package/assets/skills/verify-against-plan/SKILL.md +120 -5
  62. package/assets/skills/watcher-archetype/SKILL.md +18 -0
  63. package/assets/skills/writing-durable-markdown/SKILL.md +5 -0
  64. package/dist/installer.js +4 -4
  65. package/dist/permission-fixture.integration.test.js +4 -4
  66. package/package.json +1 -1
  67. package/assets/skills/coordinator-deploying-the-fleet/SKILL.md +0 -396
  68. package/dist/allowlist-sync.test.d.ts +0 -1
  69. package/dist/allowlist-sync.test.js +0 -44
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: brainstormer-staying-current
3
+ description: "Use when a long-lived brainstormer worktree may be behind its configured merge target, before review or handoff, or when asked to merge-forward and leave the worktree clean. Resolves the target and merge owner from Thrum config, preserves local work, and verifies freshness after the merge."
4
+ ---
5
+
6
+ # Brainstormer: Stay Current with the Merge Target
7
+
8
+ Keep a long-lived brainstorm branch current without landing it into the merge
9
+ target. Every git write in this skill (commit, merge, revert, push) stays with
10
+ you — never delegate a git write to a subagent. Every `fetch` also stays with
11
+ you, the acting agent, per Preserve and Bind freshness below. If you delegate
12
+ the read-only merge-base/status analysis, load `choosing-subagent-models`
13
+ first and fence the subagent to `show`, `log`, `diff`, `grep`, `rev-parse`,
14
+ `merge-base`, `status` — the same read-only git surface CLAUDE.md requires for
15
+ every sub-agent — never `stash`, `reset`, `rebase`, `restore`, `clean`,
16
+ `commit`, `push`, or `checkout`.
17
+
18
+ ## Resolve authority from config
19
+
20
+ Locate the canonical config from the current worktree:
21
+
22
+ ```bash
23
+ CONFIG=.thrum/config.json
24
+ [ -f .thrum/redirect ] && CONFIG="$(cat .thrum/redirect)/config.json"
25
+ test -f "$CONFIG"
26
+ TARGET=$(jq -er '.orchestration.merge_target | select(type == "string" and length > 0)' "$CONFIG")
27
+ MERGE_KING=$(jq -r --arg target "$TARGET" '.orchestration.merge_kings[$target] // "unset"' "$CONFIG")
28
+ ```
29
+
30
+ Treat an absent config or target as a blocker — merge-forward has nowhere to
31
+ target without them. A merge-forward only brings `origin/$TARGET` into the
32
+ brainstorm branch; it never grants permission to merge the brainstorm branch
33
+ into `$TARGET`, so it needs no landing authority to run and an `unset`
34
+ `MERGE_KING` never blocks it.
35
+
36
+ `orchestration.merge_kings` may not be populated for every target yet: `unset`
37
+ does NOT mean "nobody owns landing, proceed however" — it means the map
38
+ hasn't caught up (same gap `coordinator-merging-code/SKILL.md` documents for
39
+ branch-keyed lookups). `MERGE_KING` matters only when a conflict needs routing
40
+ or at final report. With it `unset` at either point, fall back to whichever
41
+ coordinator has actually been the merge authority for `$TARGET` in practice
42
+ (check with your team, or the project's operational convention) and
43
+ route/report to them the same as if the map had named them explicitly.
44
+
45
+ ## Preserve before merging
46
+
47
+ Record the current branch, HEAD, status, and ahead/behind counts. Require an
48
+ attached non-target feature branch. Fetch the target branch explicitly:
49
+
50
+ ```bash
51
+ git fetch origin "refs/heads/$TARGET:refs/remotes/origin/$TARGET"
52
+ git rev-list --left-right --count HEAD..."origin/$TARGET"
53
+ ```
54
+
55
+ If the worktree is dirty, preserve tracked and untracked changes as a WIP
56
+ commit and record its SHA — never `git stash`. `stash` is a single shared
57
+ stack across every worktree on this box, not scoped to this worktree or to
58
+ you; a stash push or pop here can silently destroy or restore another agent's
59
+ uncommitted work, with no reflog entry and no recoverable blob for unstaged
60
+ content. A commit is yours alone and fully recoverable.
61
+
62
+ ```bash
63
+ git add -A
64
+ git commit -m "wip: preserve <branch> before merge-forward <timestamp>"
65
+ git rev-parse HEAD
66
+ git status --short
67
+ ```
68
+
69
+ Do not squash, drop, or revert the WIP commit when the requested outcome is a
70
+ clean worktree — it is real history now, not something to discard.
71
+
72
+ Stop if the worktree is still dirty after the WIP commit. Never use `stash`,
73
+ reset, rebase, force checkout, clean, or force push to obtain a clean state —
74
+ `stash` is banned here exactly like the others, with no worktree-scoped
75
+ exception.
76
+
77
+ ## Merge-forward
78
+
79
+ Merge the remote-tracking target into the brainstorm branch:
80
+
81
+ ```bash
82
+ git merge --no-edit "origin/$TARGET"
83
+ ```
84
+
85
+ Resolve a conflict only when the correct result is supported by current source
86
+ and the branch's intended work. Otherwise stop with the conflict intact and
87
+ send the branch, worktree, target, and conflicted paths to the user or
88
+ `$MERGE_KING` for direction — falling back to the operational-convention
89
+ authority per above if `$MERGE_KING` is `unset`.
90
+
91
+ After a successful merge, run validation relevant to every resolved file and
92
+ always run `git diff --check origin/$TARGET..HEAD`.
93
+
94
+ ## Bind freshness to handoff
95
+
96
+ Immediately before reporting success, fetch the target branch explicitly again
97
+ and verify the fetched target is an ancestor of HEAD:
98
+
99
+ ```bash
100
+ git fetch origin "refs/heads/$TARGET:refs/remotes/origin/$TARGET"
101
+ git rev-list --left-right --count HEAD..."origin/$TARGET"
102
+ git merge-base --is-ancestor "origin/$TARGET" HEAD
103
+ git status --short
104
+ ```
105
+
106
+ If the target advanced, repeat the merge-forward and verification, up to three
107
+ merge cycles in one run. After three moving-target results, stop and report the
108
+ new target SHA instead of claiming the branch is current.
109
+
110
+ Report the branch and target SHAs, ahead/behind counts, `$MERGE_KING` (or the
111
+ fallback authority if `unset`), validation, clean status, and the WIP commit
112
+ SHA if one was made. Do not push, squash, or drop the WIP commit unless the
113
+ user separately asks.
@@ -22,6 +22,20 @@ mechanical-task carve-out anymore — lint runs, grep-and-collect, file maps,
22
22
  config edits, and all other "simple" work now dispatch at sonnet-low, not Haiku.
23
23
  Never select Haiku on own judgment — use sonnet-low instead.
24
24
 
25
+ ### Read the tiers at the moment of use
26
+
27
+ **Role templates and launch examples do not name models or effort levels; this
28
+ skill and the live config do.** Read the tier when you are about to spawn or
29
+ launch, never from memory or from a copied example:
30
+
31
+ ```bash
32
+ jq -r '.runtime.role_models' .thrum/config.json
33
+ ```
34
+
35
+ Launching with `--role` and no `--model` resolves the role default
36
+ automatically. A `--model` / `--effort` flag in a launch command takes its value
37
+ from `runtime.role_models` for the target role, per this skill.
38
+
25
39
  ### Agent tiers
26
40
 
27
41
  Effort tier governs whether an agent does the hard thing or the expedient thing.
@@ -62,7 +62,7 @@ Workflow `agent()` opts, agent-definition frontmatter, `thrum tmux launch
62
62
  ```python
63
63
  Agent(subagent_type="general-purpose",
64
64
  name="<prefix>_<slug>",
65
- model="sonnet",
65
+ model="<per choosing-subagent-models>",
66
66
  description="<3-5 words>",
67
67
  prompt="""<task>
68
68
 
@@ -92,14 +92,14 @@ to fire-and-forget monitors, not to a named agent you re-message.
92
92
 
93
93
  | Subagent role | Name prefix | Model / effort (effort only where exposed) | Result file |
94
94
  |---|---|---|---|
95
- | Investigation, grep, doc summary, mechanical | `<topic>` (e.g. `vmdocs`) | `sonnet` / low | `<scratch>/<name>.md` |
96
- | Root-cause | `<bead>_rc` | `sonnet` / low | `<scratch>/<bead>-rc.md` |
97
- | Verifier, reviewer, design-verify | `<bead>_verify` | `sonnet` / medium | `<scratch>/<bead>-verify.md` |
98
- | Implementer | `impl_<slug>` | `sonnet` / medium | `<scratch>/<slug>-impl.md` |
99
- | VM driver | `vmdriver_<slug>` | `sonnet` / medium | `<scratch>/<slug>-vm.md` |
100
- | Prose or deep review | any | `opus` — **only when the operator asks** | as above |
95
+ | Investigation, grep, doc summary, mechanical | `<topic>` (e.g. `vmdocs`) | per `choosing-subagent-models` | `<scratch>/<name>.md` |
96
+ | Root-cause | `<bead>_rc` | per `choosing-subagent-models` | `<scratch>/<bead>-rc.md` |
97
+ | Verifier, reviewer, design-verify | `<bead>_verify` | per `choosing-subagent-models` | `<scratch>/<bead>-verify.md` |
98
+ | Implementer | `impl_<slug>` | per `choosing-subagent-models` | `<scratch>/<slug>-impl.md` |
99
+ | VM driver | `vmdriver_<slug>` | per `choosing-subagent-models` | `<scratch>/<slug>-vm.md` |
100
+ | Prose or deep review | any | per `choosing-subagent-models` — **only when the operator asks** | as above |
101
101
 
102
- Haiku is banned. Opus is never yours to grant onward.
102
+ The model ban list lives in `choosing-subagent-models`. A costly tier is never yours to grant onward.
103
103
 
104
104
  ### CONSTRAINTS block — paste verbatim into every dispatch
105
105
 
@@ -111,8 +111,8 @@ Haiku is banned. Opus is never yours to grant onward.
111
111
  tool's own guidance suggests it. It trips a permission modal, and A FROZEN
112
112
  PANE EMITS NOTHING, so nobody can tell you are blocked. If you must background
113
113
  work, wait for the completion notification.
114
- - Every sub-agent YOU spawn gets an explicit `model:` — sonnet (low mechanical,
115
- medium judgment). HAIKU IS BANNED. Opus is never yours.
114
+ - Every sub-agent YOU spawn gets an explicit `model:` chosen per `choosing-subagent-models`
115
+ (read `runtime.role_models`). The model ban list lives there. A costly tier is never yours.
116
116
  - READ-ONLY git outside your own worktree. NEVER `checkout`/`reset`/`restore`/
117
117
  `stash`/`clean` in ANY directory — `stash` is one shared stack across all
118
118
  worktrees and the shared tree holds live agents' uncommitted state.
@@ -186,7 +186,7 @@ Restart on a number read from the pane footer, never on a felt sense.
186
186
  - The parent reading code or docs "to just check quickly" — message the subagent that already read them and ask for the one field.
187
187
  - One subagent handed ten tasks — partition it and dispatch the parts in parallel.
188
188
  - A spawn with no `name:` — it cannot be re-messaged. Name every spawn.
189
- - A spawn with no `model:` — it silently inherits Opus. Pin `model:` on every spawn, and `effort` wherever the mechanism takes it.
189
+ - A spawn with no `model:` — it silently inherits your own model. Pin `model:` on every spawn, and `effort` wherever the mechanism takes it.
190
190
  - Holding a design-gating answer behind the rest of the pass while an implementer builds on the old premise — that one goes immediately; the rest ships as one consolidated message.
191
191
  - Acting on the resume plan alone and skipping the middle of the prime — the falsified premise sits in the part you skipped.
192
192
  - Trusting an older "not started" message over a newer "already running" one — verify, do not recall; that cuts both directions.
@@ -21,7 +21,7 @@ findings, and its troubleshooting state across rounds.
21
21
 
22
22
  Do this:
23
23
 
24
- 1. `Agent(name: "vmdriver_<slug>", model: "sonnet", prompt: <round-1 GO>)`.
24
+ 1. `Agent(name: "vmdriver_<slug>", model: <per choosing-subagent-models>, prompt: <round-1 GO>)`.
25
25
  2. Wait for its report.
26
26
  3. `SendMessage(to: "vmdriver_<slug>", message: <round-2 GO>)`.
27
27
 
@@ -10,7 +10,7 @@ sanctions for reaching it.
10
10
 
11
11
  You want a multi-hour load or soak run and a verdict, not a log.
12
12
 
13
- 1. Spawn `vmdriver_<slug>` with `model: "sonnet"`. The GO names the run, the
13
+ 1. Spawn `vmdriver_<slug>` with `model: <per choosing-subagent-models>`. The GO names the run, the
14
14
  revision under test, and the exact metrics to report.
15
15
  2. The driver opens a persistent session with `<your-ssh-wrapper> <remote-host>`,
16
16
  starts the run detached, and writes the exit code to its own file.
@@ -19,6 +19,30 @@ Apply the gate and containment checks below and reach your own
19
19
  conclusion. Destructive steps still follow the standing reap preconditions and
20
20
  pacing rules; nothing here shortcuts them.
21
21
 
22
+ ## Standing reap preconditions — ALL must hold
23
+
24
+ Reaping an agent (removing its worktree) is safe only when every one of these is
25
+ true. It is a gate, not a checklist to rationalize past:
26
+
27
+ 1. **Idle > 48h** — no activity in its transcript for more than two days (rank by
28
+ message CONTENT, not mtime; your own broadcasts reset mtime).
29
+ 2. **No messages exchanged in the last 24h** — nothing sent to it or from it.
30
+ 3. **Task complete AND nobody is waiting on it** — it finished and its
31
+ dispatcher/manager moved on, so a reply it waits for will never come. (A pushed
32
+ branch held on a still-queued merge is the one nuance — see the
33
+ held-pending-merge rule.)
34
+ 4. **Salvage done first** — its only-copy state is copied to a durable location and
35
+ verified (see Containment and the reap steps).
36
+
37
+ **When a needed decision or merge is delayed, ESCALATE — never silently wait.** If an
38
+ agent is parked past the 24h window on something its manager/owner has not acted on,
39
+ raise it explicitly to whoever owns that decision, and re-raise on every subsequent
40
+ run. If the human owner is unresponsive, escalate through your designated escalation
41
+ contact (the human's proxy) rather than leaving the agent parked. A silent park is
42
+ the failure this whole procedure exists to prevent: each run must drive a parked
43
+ agent toward a terminal state — decision made / merge lands (reap-able) or deemed
44
+ orphaned (reap).
45
+
22
46
  ## The instruments, in order of trust
23
47
 
24
48
  | Question | Instrument |
@@ -81,10 +105,42 @@ sentence IS the terminal statement; a working agent's merely contains one.
81
105
  **Name what it is waiting for, then prove that thing is dead or landed.**
82
106
 
83
107
  *"Held pending the coordinator merge"* is finished only if the merge landed or was
84
- abandoned. If the merge is still queued, the agent is **correctly** waiting and
85
- reaping it destroys live context that nobody else holds.
86
-
87
- **If you cannot name the blocker, it is not a candidate.**
108
+ abandoned. If the merge is still queued, whether the agent is *correctly* waiting
109
+ depends on its branch and its idle time — see the held-pending-merge rule below.
110
+
111
+ **If you cannot name the blocker, it is not a candidate.** (This governs the
112
+ *no-transcript* case — absence of evidence — not a named-but-stale merge wait.)
113
+
114
+ ## 🔴 The held-pending-merge case — a PUSHED branch changes the gate
115
+
116
+ An agent parked "pending the merge" is judged by ONE thing first — **is its branch
117
+ pushed?** — because a merge wait only makes sense if the merge king can reach the
118
+ branch.
119
+
120
+ - **Branch NOT pushed — broken at ANY idle age.** The merge king cannot access an
121
+ unpushed branch, so the wait can never resolve, and the agent's commits are also
122
+ the only copy (unsafe to reap). This is not a legitimate wait — it is a stuck one.
123
+ → Get the branch PUSHED (nudge the agent / its orchestrator to push it, or escalate
124
+ that it needs pushing). Never reap an unpushed held-pending-merge agent — pushing
125
+ first is both what unblocks the merge and what makes any later reap safe.
126
+ - **Branch pushed, idle < 24h.** Legitimately waiting its turn in the merge queue.
127
+ Leave it (the pushed branch means the merge king can reach it and nothing is lost).
128
+ - **Branch pushed, idle ≥ 24h.** The wait is no longer legitimate — a pushed branch
129
+ is not the only copy of anything, so any agent could carry the merge. Resolve it to
130
+ one of two clear states:
131
+ - **Merge HAPPENED** (branch is an ancestor of trunk, or was abandoned/superseded)
132
+ → the agent is **ORPHANED**, waiting for a response that will never come → **reap**
133
+ (salvage-first, and still subject to the standing reap preconditions).
134
+ - **Merge still PENDING** (branch not on trunk, not abandoned) → the merge king
135
+ forgot it or the queue is stuck → **ESCALATE** to the merge king (name the branch
136
+ tip + how long it has waited), and **re-escalate on every subsequent skill run**
137
+ until it resolves. Never leave it silently parked.
138
+
139
+ **The escalation is the load-bearing half.** Because each skill run re-checks and
140
+ re-escalates a still-pending merge, the condition is self-correcting: it drives toward
141
+ one of two terminal states — the merge completes (agent then reap-able) or the agent
142
+ is deemed orphaned (reap) — instead of a pushed-branch agent parked forever on a merge
143
+ nobody is tracking. A silent park is exactly the failure this rule prevents.
88
144
 
89
145
  ## Containment, before anything is stood down
90
146
 
@@ -126,8 +182,8 @@ an empty/never-read premise as a match"*). `--force` does NOT bypass it; the gua
126
182
  correct. So the reap that actually frees load is worktree removal — but salvage BEFORE you remove,
127
183
  then remove PLAIN (no `--force`):
128
184
 
129
- 1. Enumerate untracked+ignored `.thrum` content — BOTH flags, one flag alone misses a class
130
- (thrum-j14q3): `git status --untracked-files=all --ignored -- .thrum`
185
+ 1. Enumerate untracked+ignored `.thrum` content — BOTH flags, one flag alone misses a class:
186
+ `git status --untracked-files=all --ignored -- .thrum`
131
187
  2. Salvage BOTH kinds to their canonical redirect paths, and `cmp`-verify each copy is
132
188
  byte-identical to its source:
133
189
  - `?? .thrum/agents/<agent>/sessions/*-restart.md` — the restart snapshot.
@@ -218,6 +274,42 @@ RSS-MB.
218
274
  you decide**. It is read-only and dry-run — it prints a kill-list, it never
219
275
  kills anything.
220
276
 
277
+ ## 🔴 Footguns — never do these (each measured, each cost real time or state)
278
+
279
+ - **Never glob/`cp` `.thrum/context/*.md` when salvaging** — the glob matches the
280
+ shared `project_state.md` and overwrites the canonical copy with a stale worktree
281
+ copy. Salvage the agent-specific `<agent>.md` by exact name only.
282
+ - **A worktree's `.thrum/` holds a redirect file to the main repo AND a physical
283
+ stale local copy of shared files** (e.g. `project_state.md`) — the physical
284
+ worktree copy is NOT canonical; never treat it as the source of truth or copy it
285
+ upward.
286
+ - **Never use shell-specific builtins in a reap loop without checking the shell** —
287
+ `mapfile`/`readarray` are bash-only and silently fail in zsh (`command not
288
+ found`), so the salvage you thought ran did not. Use portable `while read` and
289
+ verify each salvaged file actually landed.
290
+ - **`rm -rf` raises a confirmation modal that blocks the PARENT pane invisibly** —
291
+ use `rm -r` for scratch cleanup (identical deletion, no modal). Never `rm -rf`.
292
+ - **`git worktree remove` (plain) silently deletes gitignored-only content (rc=0)**
293
+ and refuses (rc=128) only on untracked/modified files — salvage is the ONLY
294
+ protection for gitignored only-copy state.
295
+ - **`git worktree remove` refuses while a just-salvaged untracked snapshot still
296
+ sits in the worktree** — remove that salvaged copy from the worktree first, then
297
+ plain-remove.
298
+ - **Never `checkout`/`reset`/`restore`/`stash`/`clean` in a shared tree, even to
299
+ undo** — to restore a file to its committed version, write it with a plain
300
+ redirect from `git show <ref>:<path>`, not a checkout.
301
+ - **Test the reap on ONE agent first and verify the EFFECT** (gone from the worktree
302
+ list AND disk), not just the exit code.
303
+ - **Rank candidates by last-message CONTENT, not elapsed time** — your own
304
+ broadcasts reset every recipient's idle clock.
305
+ - **`--force` on agent-delete does NOT bypass the CAS guard** on a stale agent — the
306
+ reap that frees load is worktree removal, not the delete.
307
+ - **Reap order is `thrum tmux kill <session>` FIRST, THEN `git worktree remove`** —
308
+ removing the worktree alone leaves the agent's tmux session alive with a
309
+ now-deleted cwd, which the fleet flags as recurring "cwd drift" and whose runtime
310
+ process keeps consuming RAM/CPU. Kill the session, verify it's gone, then remove
311
+ the worktree.
312
+
221
313
  ## Why this fails dangerously if you skip the gate
222
314
 
223
315
  The failure direction is **false-GONE**: concluding a live agent is finished. It
@@ -26,40 +26,51 @@ What's forbidden is a script that bypasses this skill and fires
26
26
  `thrum tmux restart --force` unconditionally (that violates
27
27
  `feedback_restart_discipline` — burn the runway, don't restart on schedule).
28
28
 
29
- ## Coordinator self-restart — ALWAYS `/thrum:restart-extended`
29
+ ## Coordinator self-restart — ALWAYS the EXTENDED form, compact-extended FIRST
30
30
 
31
31
  This skill's tier ladder (Steps 3–5) governs how the coordinator restarts
32
32
  **other** agents. When the **coordinator restarts ITSELF**, a different rule
33
- applies and it is absolute:
33
+ applies and it is absolute — but D5 (owner-ruled)
34
+ REVERSES which command that is:
34
35
 
35
- > **The coordinator ALWAYS self-restarts via `/thrum:restart-extended`, NEVER
36
- > `/thrum:restart`.**
36
+ > **The coordinator ALWAYS uses the EXTENDED snapshot grade for itself — never
37
+ > the standard/compact form. Which command carries that grade is
38
+ > runtime-directed: `/thrum:compact-extended` on any runtime with a verified
39
+ > compact-equivalent skill (D6, the default), `/thrum:restart-extended` ONLY
40
+ > as the fallback on a runtime without one (today: muse, copilot).**
41
+
42
+ This is a REVERSAL of the prior absolute rule ("ALWAYS restart-extended, NEVER
43
+ compact") — that rule is retired, not merely relaxed. Do not restore it.
37
44
 
38
45
  Rationale: the coordinator is the nerve center. Its handoff must carry the full
39
46
  16-section snapshot (wire contracts, capability matrix, cycle history, open
40
47
  L-questions, anticipated Q&A, design rationale) so the next session resumes
41
- steady-state coordination without re-deriving fleet state. The standard
42
- `/thrum:restart` compact format drops that load-bearing context and strands the
43
- next session. This holds regardless of which tier the coordinator's own context
44
- sits in — there is no ctx-band at which the coordinator downgrades to the
45
- compact restart.
48
+ steady-state coordination without re-deriving fleet state — that requirement
49
+ is UNCHANGED and is what "EXTENDED" governs; only the compact-vs-restart choice
50
+ changed. Compacting (rather than restarting) additionally keeps the SAME
51
+ process/session alive — sub-agents, background loops, and cron schedules the
52
+ coordinator owns survive the compaction, where a restart would drop them.
53
+ There is no ctx-band at which the coordinator downgrades to the standard/
54
+ compact-grade snapshot — the tier ladder below governs OTHER agents, not this.
46
55
 
47
- Practical trigger points for coordinator self-restart:
56
+ Practical trigger points for coordinator self-restart/compact:
48
57
 
49
58
  - A warn-tier context nudge fires on the coordinator's own pane (e.g. 70%+).
50
59
  - The coordinator hits a clean checkpoint and elects a fresh session.
51
60
  - Rate-limit / stuck-state recovery on the coordinator itself.
52
61
 
53
- In every one of these, run `/thrum:restart-extended`. (Captured as role-rule
54
- `coord-always-restart-extended` /
55
- `Coordinator ALWAYS uses /thrum:restart-extended`; this skill is the
56
- always-loaded home so the rule survives even when memory isn't consulted.)
62
+ In every one of these: run `/thrum:compact-extended` if the coordinator's
63
+ runtime has a compact equivalent (the default); `/thrum:restart-extended` only
64
+ if it does not. (The role-rule `coord-always-restart-extended` — `Coordinator
65
+ ALWAYS uses /thrum:restart-extended` — is RETIRED as of D5; see
66
+ `thrum memory` for its retirement record. This skill is the always-loaded home
67
+ so the CURRENT rule survives even when memory isn't consulted.)
57
68
 
58
69
  Note the distinction from Steps 3–5 below: those steps drive `/thrum:restart`
59
70
  (Step 4) and `/thrum:restart-extended` (Step 5) into
60
71
  **implementer/brainstormer** panes per their ctx tier — that tiering is correct
61
72
  for worker agents. The carve-out here is ONLY about the coordinator's own
62
- restart, which is unconditionally the extended form.
73
+ restart/compact, which is unconditionally the extended grade, compact-first.
63
74
 
64
75
  ## How the scheduled sweep works (v0.10.6+ — thrum monitor)
65
76
 
@@ -274,10 +285,7 @@ brick.
274
285
 
275
286
  ## Subagent model selection
276
287
 
277
- > **Model tiers:** pass an explicit `model:` on every dispatch — `sonnet`
278
- > (low effort) mechanical, `sonnet` (medium effort) judgment, Opus only on
279
- > operator-ask or a skill step that names it. See the
280
- > `choosing-subagent-models` skill for the full policy.
288
+ > **Model tiers:** pass an explicit `model:` on every dispatch; choose model and effort per the `choosing-subagent-models` skill (read `runtime.role_models` at the moment of use). Never let a sub-agent inherit your own model.
281
289
 
282
290
  ## Step 1 — Run the sweep
283
291
 
@@ -464,6 +472,8 @@ by typing the restart command directly into their input field:
464
472
  thrum tmux send <tmux_session_name> '/thrum:restart'
465
473
  ```
466
474
 
475
+ If it exits 3 (Enter WITHHELD, text already typed) or 4 (verdict unknown), do NOT retype it: `thrum tmux capture` the pane and submit with `thrum tmux send <tmux_session_name> --keys Enter` only if no dialog is showing.
476
+
467
477
  (Find the tmux session name in sweep output — it's typically the worktree
468
478
  basename, e.g. `myepic-impl`, NOT the agent_id.)
469
479
 
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: coordinator-deploying-a-node
3
+ description: "Use when deploying a build to a single node, migrating or not — deploying a build, schema-migrating deploy, pro-bundle install plus service restart on a node, roll out a build to a node, ship to a node, single-node canary. Loads the deploy runbook — verifying the artifact actually CONTAINS the fix, install-before-restart ordering, verify-by-effect, and preventing store corruption on migration."
4
+ ---
5
+
6
+ # Coordinator: Deploying a Build to a Single Node — migrating or not
7
+
8
+ > This runbook covers EVERY deploy to a single node, migrating or not. Most sections apply to every deploy; only migration-weight and store-corruption specifics are bump-only.
9
+
10
+ ## 0. Pull-current first (ff-only)
11
+
12
+ The absolute first action before anything else: fetch the control-plane repository and fast-forward to the orchestrator's pin.
13
+
14
+ - Read the project's deployment adapter inside `.thrum/config.json` (`fleet.deployment`; reference at the deployment-adapter reference) to obtain `preflight.pull_command` and `preflight.pin_command`.
15
+ - Run `preflight.pull_command` (must be ff-only; if not fast-forwardable, STOP and surface — never blind-merge in the shared tree).
16
+ - Verify the delivered artifact actually CONTAINS the fix at the pinned SHA (adapter `artifact.commit_file` sidecar).
17
+
18
+ This ensures the node's coordinator reasons from a checkout that is actually current before evaluating backup, install, or migration.
19
+
20
+ > Example — Thrum project: pull via `git fetch origin && git merge --ff-only origin/<branch>` before any backup or install.
21
+
22
+ ## 1. Who executes — resolve the node's local coordinator (via adapter identity)
23
+
24
+ The node's own coordinator drives the deploy locally on its own host. Never drive a node's build/install/restart from another host.
25
+
26
+ - Resolve WHO via `topology.identity_resolution` (adapter `fleet.deployment.thrum.topology.identity_resolution` or `fleet.deployment.products.<id>.topology`) — a `daemon_id` join plus hostname and absence of `.thrum/redirect`, never by agent name or worktree name.
27
+ - When connected-repo daemons share a host, respect the adapter-defined restart order within that host.
28
+
29
+ If the target node has no working coordinator, state why explicitly before using any fallback.
30
+
31
+ ## 2. Back up before touching anything (via adapter backup command + sizing formula)
32
+
33
+ - Run the project's backup command (`fleet.deployment.thrum.backup.command` or `fleet.deployment.products.<id>.backup.command`) and verify per `backup.verify`.
34
+ - Size BEFORE you run it on a bloated node: apply the adapter's `backup.sizing_formula` (`free_at_completion = free_now - zip(stale current/) + size(stale current/) - size(live lane)`) — the stale `current/` is removed before the fresh export, so peak is not double-count. Retention runs last and does not bound the peak.
35
+ - On failure, roll back via `backup.restore_command`; never delete the store.
36
+
37
+ > Example — Thrum project: backup via `thrum backup`, sized per the formula above, verified with `sqlite3 ?mode=ro&immutable=1` read.
38
+
39
+ ## 3. Storage access — through the engine or control-plane CLI, never file-bypass
40
+
41
+ Access the state store only through the engine or the control-plane CLI in read-only mode. Never bypass the storage engine's file ownership.
42
+
43
+ - Via: `storage_access.via` (e.g., CLI or `?mode=ro`).
44
+ - Forbidden: `storage_access.forbidden` (e.g., hand-copy of live `-wal`/`-shm`, concurrent `.backup` on live store).
45
+ - A bare read-write open can fire a checkpoint that truncates the write log out from under live readers → sustained corruption. Always use `?mode=ro` where applicable.
46
+
47
+ If the project has no WAL/SHM, this section is N/A — skip and note.
48
+
49
+ ## 4. Never wrap service start/restart in a blind timeout
50
+
51
+ Run the project's service restart command (`fleet.deployment.thrum.service.restart_command` or product equivalent) without a blind timeout wrapper. A timeout that kills a migrating restart mid-migration manufactures a half-migrated store.
52
+
53
+ - Adapter flag `service.never_timeout` is true.
54
+ - Signal-window rules are adapter data: `migration.signal_rules` (`SIGQUIT` fatal-always, `SIGUSR1` fatal-before-socket). Respect them — do not send fatal signals in the forbidden window.
55
+
56
+ > Example — Thrum project: restart via `thrum daemon restart`, never wrapped in `timeout`; mac path via `scripts/mac-daemon-restart-via-cron.sh`.
57
+
58
+ ## 5. Install from the delivered artifact (never rebuild on the node)
59
+
60
+ Install from the identical bundle the orchestrator built, delivered to `artifact.distribution.drop_path`.
61
+
62
+ - Verify BEFORE unpack that the delivered bundle's version/checksum/commit sidecar equals the orchestrator's pin (adapter `artifact.checksum`, `artifact.version_file`, `artifact.commit_file`).
63
+ - Run `install.command` (from adapter). The node does not compile, sign, or rebuild — it installs.
64
+ - Collect BEFORE readings (current version, state counters, checkpoint counts, health probes) before the install.
65
+
66
+ > Example — Thrum project: install from the adapter's `artifact.distribution.drop_path` via the adapter's `install.command`.
67
+
68
+ ## 6. Measure from the running process, never the checkout
69
+
70
+ Read version/state from the running service, not from the filesystem checkout.
71
+
72
+ - Verify via `install.verify_by_effect` probes: version equals pin, NEW PID, service status reports pin, sidecar equals pin.
73
+ - Do not trust installer exit 0 alone.
74
+
75
+ ## 7. Migrate via service restart — verify by effect
76
+
77
+ Migration is performed by restarting the service after install; the service's own boot migration does the schema/data move.
78
+
79
+ - Calibrate weight via `migration.weight_calibration` (heavy bulk-export vs light add-column) — do not assume a fixed duration.
80
+ - Known signatures that require a cold-restart recovery: `migration.sigbus_signatures` (e.g., WAL-index recover signatures) and `migration.on_sigbus`.
81
+ - Observe that the restarted service reports the new version/state and that health probes have converged (adapter `health.probes`, `health.convergence_wait`).
82
+
83
+ ## 8. Verify post-migration (liveness, health probes, checkpoint counts, agent liveness)
84
+
85
+ Run adapter `health.probes` and compare BEFORE/AFTER:
86
+
87
+ - Service alive and reporting pin.
88
+ - State counters converged per `health.convergence_wait` (mechanism-derived, e.g., `3m`).
89
+ - Crash log empty, expected agents live.
90
+
91
+ For tandem daemons that share a host or depend on each other, verify the coordinated set per adapter.
92
+
93
+ ## 8a. Re-render configuration/templates if the build changes them
94
+
95
+ If the build carries template or role changes, re-render between install and restart:
96
+
97
+ - Commands: `templates.refresh_command` and `templates.deploy_command`.
98
+ - Order: `templates.order` (`refresh→deploy` between `install.sh` and daemon restart).
99
+ - Verify by effect (render output, then service restart).
100
+
101
+ > Example — Thrum project: `thrum roles refresh` then `thrum roles deploy` between install and restart.
102
+
103
+ ## 8b. Plugin/skill refresh if the deploy carries skill changes
104
+
105
+ If the bundle carries skill/plugin changes, refresh the plugin cache:
106
+
107
+ - Refresh driver: `plugin.refresh` (version bump required — cache keyed by version).
108
+ - Manifests: `plugin.manifests` (all skill-carrying manifests bumped in the same commit as the new skills).
109
+
110
+ Do not hand-edit generated marketplace manifests.
111
+
112
+ ## 8c. Reconcile registry/phase after restart
113
+
114
+ Re-verify the daemon registry and agent phases after restart (adapter `health.probes` includes phase reconciliation). Confirm the pinned version is durable across a clean cold-boot probe where applicable.
115
+
116
+ ## Red flags — STOP
117
+
118
+ - Pull not ff-only.
119
+ - Backup skipped or undersized.
120
+ - Storage accessed via forbidden path (`storage_access.forbidden`).
121
+ - Restart wrapped in a blind timeout or killed with `SIGQUIT`/`SIGUSR1` in a fatal window (`migration.signal_rules`).
122
+ - Install rebuilt locally instead of from the delivered artifact.
123
+ - Post-migration health not verified by observed effect.
124
+ - Template re-render skipped when the build changed templates (`templates.order` violated).
@@ -65,10 +65,7 @@ optimization.
65
65
 
66
66
  ## Subagent model selection
67
67
 
68
- > **Model tiers:** pass an explicit `model:` on every dispatch — `sonnet`
69
- > (low effort) mechanical, `sonnet` (medium effort) judgment, Opus only on
70
- > operator-ask or a skill step that names it. See the
71
- > `choosing-subagent-models` skill for the full policy.
68
+ > **Model tiers:** pass an explicit `model:` on every dispatch; choose model and effort per the `choosing-subagent-models` skill (read `runtime.role_models` at the moment of use). Never let a sub-agent inherit your own model.
72
69
 
73
70
  ## Check the target's queue before you dispatch (R3)
74
71
 
@@ -162,13 +159,30 @@ re-dispatch overhead.
162
159
  3. Acceptance criteria as bullets
163
160
  4. The worktree path the work happens in
164
161
  5. An explicit reminder to pass `model:` on any sub-agents the implementer
165
- spawns (sonnet-low for mechanical, sonnet-medium for judgment)
162
+ spawns (model and effort per `choosing-subagent-models`)
166
163
  6. Spec/plan paths to read before starting
167
164
  7. **Adjacent candidate beads** from the adjacency pass above, labeled as
168
165
  CANDIDATES with their validity explicitly unverified — plus the instruction to
169
166
  check them against the merged-forward tip and either fold them in or return
170
167
  them as completed
171
168
 
169
+ ## Anti-pattern-removal epics must ship a ratchet lens
170
+
171
+ **Why:** during a prior owner-bypass remediation, judgment
172
+ review alone let 11 new instances of the exact anti-pattern being removed
173
+ land through the merge gate mid-sprint, because no mechanical check enforced
174
+ a monotonic budget across diffs.
175
+
176
+ **How to apply:** When dispatching an epic whose purpose is removing an
177
+ existing anti-pattern (not just fixing one instance of it), the acceptance
178
+ criteria MUST include a mechanical ratchet lens (see
179
+ `coordinator-hotpath-merge-gate` § "Invariant-ratchet lenses") wired into
180
+ `.thrum/hotpath-gate.json` as `always_run` before the epic is considered
181
+ closeable — not as a follow-up. A judgment-only acceptance ("reviewer
182
+ confirms the count went down") is insufficient; the count must be enforced
183
+ by a standing mechanical budget the gate itself checks on every subsequent
184
+ merge.
185
+
172
186
  ## Execution invariants — carry these in every implementation dispatch
173
187
 
174
188
  **Why:** A plan is a snapshot; trunk moves and reality drifts from it. Sprints
@@ -208,17 +222,16 @@ with a different name — do not rename in place.
208
222
 
209
223
  ## Propagate model-selection discipline downward
210
224
 
211
- **Why:** Sub-agents inherit the parent model by default. A coordinator on Opus
212
- that spawns an unspecified sub-agent gets Opus-cost work for tasks that need
213
- sonnet-low. The same trap repeats inside an implementer's worktree: if the
225
+ **Why:** Sub-agents inherit the parent model by default. A coordinator whose own tier is
226
+ costly that spawns an unspecified sub-agent gets costly work for tasks that need
227
+ a cheap tier. The same trap repeats inside an implementer's worktree: if the
214
228
  implementer doesn't propagate the discipline, their own sub-agents silently
215
229
  inherit too. Cost compounds across a session.
216
230
 
217
231
  **How to apply:** Every dispatch prompt should include the model-selection rule
218
232
  explicitly: "When you spawn your own sub-agents, pass explicit `model:` —
219
- `sonnet` (low effort) for mechanical work (lint, tests, find/replace), `sonnet`
220
- (medium effort) for judgment work (review, complex implementation), `opus`
221
- only when justified. Default to sonnet over opus." Audit the dispatch prompt before sending.
233
+ choose model and effort per the `choosing-subagent-models` skill (read
234
+ `runtime.role_models` at the moment of use); never inherit your own model." Audit the dispatch prompt before sending.
222
235
 
223
236
  ## The impl-prompt review stamp satisfies pre-dispatch review
224
237