opencode-thrum-pro 0.1.6 → 0.1.7

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 (52) hide show
  1. package/assets/commands/thrum-compact-extended.md +36 -21
  2. package/assets/commands/thrum-compact.md +19 -18
  3. package/assets/commands/thrum-restart-extended.md +1 -5
  4. package/assets/commands/thrum-restart.md +1 -1
  5. package/assets/commands/thrum-sleep-extended.md +1 -5
  6. package/assets/commands/thrum-sleep.md +1 -5
  7. package/assets/commands/thrum-update-project.md +1 -1
  8. package/assets/skills/choosing-subagent-models/SKILL.md +188 -72
  9. package/assets/skills/closing-findings-while-warm/SKILL.md +1 -2
  10. package/assets/skills/configure-roles/SKILL.md +2 -2
  11. package/assets/skills/coordinator-branch-split-on-block/SKILL.md +1 -2
  12. package/assets/skills/coordinator-dispatching-work/SKILL.md +2 -3
  13. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +3 -1
  14. package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +1 -2
  15. package/assets/skills/coordinator-maintaining-memory/SKILL.md +1 -1
  16. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +1 -2
  17. package/assets/skills/coordinator-merging-code/SKILL.md +18 -11
  18. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +1 -2
  19. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +1 -2
  20. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +4 -5
  21. package/assets/skills/coordinator-running-review-cycles/SKILL.md +1 -2
  22. package/assets/{commands/thrum-_deviations-protocol.md → skills/deviations-protocol/SKILL.md} +6 -12
  23. package/assets/skills/generator-idempotency-protocol/SKILL.md +9 -0
  24. package/assets/skills/implementer-maintaining-memory/SKILL.md +3 -4
  25. package/assets/skills/implementer-orchestrating-execution/SKILL.md +1 -2
  26. package/assets/skills/implementer-receiving-dispatch/SKILL.md +15 -17
  27. package/assets/skills/implementer-receiving-review-feedback/SKILL.md +3 -4
  28. package/assets/skills/implementer-status-and-handoff/SKILL.md +1 -14
  29. package/assets/skills/implementer-tdd-and-quality/SKILL.md +2 -2
  30. package/assets/skills/memory-curate/SKILL.md +1 -1
  31. package/assets/skills/memory-write-discipline/SKILL.md +1 -1
  32. package/assets/skills/orchestrate/SKILL.md +33 -4
  33. package/assets/skills/prime-agent/SKILL.md +1 -1
  34. package/assets/skills/project-hotpath-gate/SKILL.md +1 -2
  35. package/assets/skills/project-philosophy/SKILL.md +1 -2
  36. package/assets/skills/project-rules-protocol/SKILL.md +12 -0
  37. package/assets/skills/project-setup/SKILL.md +7 -8
  38. package/assets/skills/project-setup/resources/implementation-agent.md +1 -2
  39. package/assets/skills/researcher-answering-queries/SKILL.md +1 -2
  40. package/assets/skills/researcher-investigating/SKILL.md +6 -8
  41. package/assets/skills/researcher-maintaining-memory/SKILL.md +1 -1
  42. package/assets/{commands/thrum-_snapshot-protocol.md → skills/snapshot-protocol/SKILL.md} +10 -15
  43. package/assets/{commands/thrum-_stamp-protocol.md → skills/stamp-protocol/SKILL.md} +5 -6
  44. package/assets/skills/using-thrum-state/SKILL.md +2 -2
  45. package/assets/skills/verify-against-plan/SKILL.md +2 -2
  46. package/dist/installer-assets.test.d.ts +1 -0
  47. package/dist/installer-assets.test.js +41 -0
  48. package/package.json +1 -1
  49. package/assets/commands/thrum-_compact-runtime-commands.md +0 -61
  50. package/assets/commands/thrum-_generator-idempotency-protocol.md +0 -15
  51. package/assets/commands/thrum-_project-rules-protocol.md +0 -18
  52. package/assets/commands/thrum-_verify-before-write-protocol.md +0 -27
@@ -51,14 +51,11 @@ skill) BEFORE composing your snapshot below — these survive compaction
51
51
  independently of the prose continuation file and are what a post-compact
52
52
  render reads back.
53
53
 
54
- Read the partial at the absolute path (resolve `$REPO` yourself first via
55
- `thrum agent worktree --authoritative` — NEVER `thrum whoami --field worktree`
56
- or `git rev-parse --show-toplevel`, both cwd-resolved and the root cause of
57
- a documented snapshot-save loss class; there is no git fallback):
58
-
59
- ```text
60
- ${REPO}/claude-plugin/commands/_snapshot-protocol.md
61
- ```
54
+ Invoke the /thrum:snapshot-protocol skill and follow it, starting with its
55
+ Step 1 (resolve your worktree ONLY via `thrum agent worktree --authoritative` —
56
+ NEVER `thrum whoami --field worktree` or `git rev-parse --show-toplevel`, both
57
+ cwd-resolved and the root cause of a documented snapshot-save loss class;
58
+ there is no git fallback).
62
59
 
63
60
  Apply its Step 2 (compose your continuation) per the structure guidance.
64
61
 
@@ -77,6 +74,15 @@ self-contained:
77
74
  > `thrum prime --light` briefing already auto-injected by the SessionStart
78
75
  > hook; only run `thrum:prime-agent` if it did NOT appear. Do NOT manually run
79
76
  > full `thrum prime`. Then continue from §16.
77
+ > If you must re-read this file (no briefing appeared): read the NEWEST
78
+ > `.thrum/agents/<your-id>/sessions/*-restart.md` in the MAIN repo (the prime
79
+ > ARCHIVES the snapshot there); fall back to `.thrum/restart/<your-id>.md` only
80
+ > if it still exists. Find the newest with:
81
+ > `R=$(git rev-parse --show-toplevel); ls -1t "$(cat "$R/.thrum/redirect" 2>/dev/null || echo "$R/.thrum")"/agents/<your-id>/sessions/*-restart.md | head -1`
82
+ > (`$R/.thrum/redirect` in a worktree names the main repo's `.thrum`; using `$R`
83
+ > keeps this independent of your current directory). Open it with the Read tool
84
+ > (not Bash sed/cat). The `sessions/` file lives under the repo's `.thrum`, so
85
+ > that is allowed.
80
86
 
81
87
  Then §1…§16 as normal, with §16 (immediate next actions) actionable from a
82
88
  compacted (not cold) start.
@@ -135,12 +141,6 @@ is not torn down, so `/thrum:sleep-extended`'s teardown-loss risk does not apply
135
141
  > A single `thrum tmux send "$SESSION" "<command>"` call has no such split to
136
142
  > make.
137
143
 
138
- On a non-Claude runtime this block sends that runtime's own compact-equivalent
139
- command in place of `/compact` — see
140
- `${REPO}/claude-plugin/commands/_compact-runtime-commands.md` for the cited
141
- per-runtime table; `scripts/sync-skills.sh` applies the substitution when
142
- syncing this file to each runtime's plugin tree.
143
-
144
144
  Firing `/compact` before the Step 3 Write lands compacts a pre-write context and
145
145
  resumes from a stale/blank file — the exact failure this command prevents. This
146
146
  block (paste the two values printed by the Step 3 PREP block into its first two
@@ -236,6 +236,7 @@ if [ "$SNAPSHOT_OK" = 1 ] && [ "$SESSION_OK" = 1 ]; then
236
236
  echo "Report this to your coordinator (or the operator if you are top-level) and stop; a human or coordinator must inspect the pane and submit or clear it."
237
237
  exit 1
238
238
  fi
239
+ RESUME_PROMPT="Compaction complete - please continue: your Resume Plan is in the auto-injected briefing (# Previous Session Context). If it is missing, read ${SNAPSHOT} or the newest *-restart.md in .thrum/agents/${AGENT}/sessions/ of the main repo, then execute its numbered resume plan."
239
240
  if [ "$SEND_RC" -ne 0 ]; then
240
241
  echo "ERROR: thrum tmux send exited ${SEND_RC} — the daemon-routed self-send failed; it will NOT queue or deliver /compact."
241
242
  # Fail-loud fallback, NOT silent idle: attempt the compact command
@@ -274,16 +275,29 @@ if [ "$SNAPSHOT_OK" = 1 ] && [ "$SESSION_OK" = 1 ]; then
274
275
  exit 1
275
276
  fi
276
277
  echo "Raw fallback send-keys succeeded on socket $RAW_TMUX_SOCK."
278
+ # The daemon route is known-dead here (that is why this is the
279
+ # fallback), and on several runtimes no hook fires at all after
280
+ # compaction — so queue the resume prompt on the same explicit socket,
281
+ # same single-call text+C-m discipline. Without this the pane idles
282
+ # after compaction with an empty composer until a human types.
283
+ tmux -S "$RAW_TMUX_SOCK" send-keys -t "${SESSION}:0.0" "$RESUME_PROMPT" C-m
284
+ RAW_RESUME_RC=$?
285
+ if [ "$RAW_RESUME_RC" -eq 0 ]; then
286
+ :
287
+ else
288
+ echo "WARNING: raw resume-prompt send-keys exited ${RAW_RESUME_RC} — the post-compact resume prompt was NOT queued. If the pane sits idle after compaction, send it a resume prompt by hand."
289
+ fi
277
290
  fi
278
- # thrum-xyz: queue the RESUME PROMPT right behind /compact, on the same
279
- # daemon queue (only when the daemon-routed /compact send succeeded; the raw
280
- # fallback path leaves any hook-side nudge as the kickoff). Hook output is
291
+ # resume-prompt: queue the RESUME PROMPT right behind /compact — on the daemon
292
+ # queue when the daemon-routed send succeeded (dispatched once the pane is
293
+ # idle again AFTER the compaction, FIFO behind /compact: not a timer, fires
294
+ # exactly once), or via the raw explicit-socket send above when the raw
295
+ # fallback carried /compact. Hook output is
281
296
  # context only — it does not start a turn — so without this an idle pane with
282
297
  # an empty inbox can sit at 0% context, empty composer, until a human types.
283
298
  # The daemon dispatches it once the pane is idle again AFTER the compaction
284
299
  # (FIFO behind /compact), so it is not a timer and it fires exactly once.
285
300
  if [ "$SEND_RC" -eq 0 ]; then
286
- RESUME_PROMPT="Compaction complete - please continue: your Resume Plan is in the auto-injected briefing (# Previous Session Context). If it is missing, read ${SNAPSHOT} or the newest *-restart.md in .thrum/agents/${AGENT}/sessions/ of the main repo, then execute its numbered resume plan."
287
301
  thrum tmux send "$AGENT" "$RESUME_PROMPT"
288
302
  RESUME_RC=$?
289
303
  if [ "$RESUME_RC" -eq 0 ]; then
@@ -333,9 +347,10 @@ of that is needed here. Resume LEAN, in this order:
333
347
  snapshot (moves `${REPO}/.thrum/restart/${AGENT}.md` into the main repo's
334
348
  `.thrum/agents/${AGENT}/sessions/`), so the original path is normally GONE
335
349
  by the time you look — that is by design, not loss. Only if no briefing
336
- appeared (daemon unreachable), read the newest `*-restart.md` in that
337
- `sessions/` directory (or `${REPO}/.thrum/restart/${AGENT}.md` if it still
338
- exists) and run `thrum:prime-agent` manually as the fallback. Never manually
350
+ appeared (daemon unreachable), read the NEWEST `*-restart.md` in that
351
+ `sessions/` directory, e.g. `ls -1t "$(cat "${REPO}/.thrum/redirect" 2>/dev/null || echo "${REPO}/.thrum")"/agents/${AGENT}/sessions/*-restart.md | head -1`
352
+ (fall back to `${REPO}/.thrum/restart/${AGENT}.md` only if it still
353
+ exists; use the Read tool, not Bash sed/cat, on `~/.claude` paths) and run `thrum:prime-agent` manually as the fallback. Never manually
339
354
  run full `thrum prime` when the briefing is present.
340
355
  2. **A resume prompt starts your first turn.** Step 4 queued a "Compaction
341
356
  complete - please continue" prompt on the daemon right behind `/compact`; it
@@ -53,14 +53,11 @@ skill) BEFORE composing your snapshot below — these survive compaction
53
53
  independently of the prose continuation file and are what a post-compact
54
54
  render reads back.
55
55
 
56
- Read the partial at the absolute path (resolve `$REPO` yourself first via
57
- `thrum agent worktree --authoritative` — NEVER `thrum whoami --field worktree`
58
- or `git rev-parse --show-toplevel`, both cwd-resolved and the root cause of
59
- a documented snapshot-save loss class; there is no git fallback):
60
-
61
- ```text
62
- ${REPO}/claude-plugin/commands/_snapshot-protocol.md
63
- ```
56
+ Invoke the /thrum:snapshot-protocol skill and follow it, starting with its
57
+ Step 1 (resolve your worktree ONLY via `thrum agent worktree --authoritative` —
58
+ NEVER `thrum whoami --field worktree` or `git rev-parse --show-toplevel`, both
59
+ cwd-resolved and the root cause of a documented snapshot-save loss class;
60
+ there is no git fallback).
64
61
 
65
62
  Apply its Step 2 (compose your continuation) per the structure guidance.
66
63
 
@@ -79,6 +76,15 @@ self-contained:
79
76
  > `thrum prime --light` briefing already auto-injected by the SessionStart
80
77
  > hook; only run `thrum:prime-agent` if it did NOT appear. Do NOT manually run
81
78
  > full `thrum prime`. Then continue from §9.
79
+ > If you must re-read this file (no briefing appeared): read the NEWEST
80
+ > `.thrum/agents/<your-id>/sessions/*-restart.md` in the MAIN repo (the prime
81
+ > ARCHIVES the snapshot there); fall back to `.thrum/restart/<your-id>.md` only
82
+ > if it still exists. Find the newest with:
83
+ > `R=$(git rev-parse --show-toplevel); ls -1t "$(cat "$R/.thrum/redirect" 2>/dev/null || echo "$R/.thrum")"/agents/<your-id>/sessions/*-restart.md | head -1`
84
+ > (`$R/.thrum/redirect` in a worktree names the main repo's `.thrum`; using `$R`
85
+ > keeps this independent of your current directory). Open it with the Read tool
86
+ > (not Bash sed/cat). The `sessions/` file lives under the repo's `.thrum`, so
87
+ > that is allowed.
82
88
 
83
89
  Then §1…§11 as normal, with §9 (Numbered resume plan) actionable from a
84
90
  compacted (not cold) start.
@@ -135,12 +141,6 @@ not torn down, so `/thrum:sleep`'s teardown-loss risk does not apply here).
135
141
  > A single `thrum tmux send "$SESSION" "<command>"` call has no such split to
136
142
  > make.
137
143
 
138
- On a non-Claude runtime this block sends that runtime's own compact-equivalent
139
- command in place of `/compact` — see
140
- `${REPO}/claude-plugin/commands/_compact-runtime-commands.md` for the cited
141
- per-runtime table; `scripts/sync-skills.sh` applies the substitution when
142
- syncing this file to each runtime's plugin tree.
143
-
144
144
  Firing `/compact` before the Step 3 Write lands compacts a pre-write context and
145
145
  resumes from a stale/blank file — the exact failure this command prevents. This
146
146
  block (paste the two values printed by the Step 3 PREP block into its first two
@@ -234,7 +234,7 @@ if [ "$SNAPSHOT_OK" = 1 ] && [ "$SESSION_OK" = 1 ]; then
234
234
  echo "ERROR: thrum tmux send exited ${SEND_RC} — /compact was not queued. Report and stop."
235
235
  exit 1
236
236
  fi
237
- # thrum-xyz: queue the RESUME PROMPT right behind /compact, on the same
237
+ # resume-prompt: queue the RESUME PROMPT right behind /compact, on the same
238
238
  # daemon queue. Hook output is context only — it does not start a turn — so
239
239
  # without this an idle pane with an empty inbox can sit at 0% context, empty
240
240
  # composer, until a human types. The daemon dispatches it once the pane is
@@ -281,9 +281,10 @@ of that is needed here. Resume LEAN, in this order:
281
281
  snapshot (moves `${REPO}/.thrum/restart/${AGENT}.md` into the main repo's
282
282
  `.thrum/agents/${AGENT}/sessions/`), so the original path is normally GONE
283
283
  by the time you look — that is by design, not loss. Only if no briefing
284
- appeared (daemon unreachable), read the newest `*-restart.md` in that
285
- `sessions/` directory (or `${REPO}/.thrum/restart/${AGENT}.md` if it still
286
- exists) and run `thrum:prime-agent` manually as the fallback. Never manually
284
+ appeared (daemon unreachable), read the NEWEST `*-restart.md` in that
285
+ `sessions/` directory, e.g. `ls -1t "$(cat "${REPO}/.thrum/redirect" 2>/dev/null || echo "${REPO}/.thrum")"/agents/${AGENT}/sessions/*-restart.md | head -1`
286
+ (fall back to `${REPO}/.thrum/restart/${AGENT}.md` only if it still
287
+ exists; use the Read tool, not Bash sed/cat, on `~/.claude` paths) and run `thrum:prime-agent` manually as the fallback. Never manually
287
288
  run full `thrum prime` when the briefing is present.
288
289
  2. **A resume prompt starts your first turn.** Step 4 queued a "Compaction
289
290
  complete - please continue" prompt on the daemon right behind `/compact`; it
@@ -54,11 +54,7 @@ mkdir -p "${REPO}/.thrum/restart"
54
54
 
55
55
  ### 2. Read the shared snapshot-composition partial
56
56
 
57
- Read the partial at the absolute path:
58
-
59
- ```text
60
- ${REPO}/claude-plugin/commands/_snapshot-protocol.md
61
- ```
57
+ Invoke the /thrum:snapshot-protocol skill and follow it.
62
58
 
63
59
  It carries the CRITICAL DISCIPLINE block and BOTH the standard 11-section
64
60
  structure and the EXTENDED 16-section structure with per-section guidance.
@@ -70,7 +70,7 @@ shapes everything else you write below it.
70
70
 
71
71
  **Stamp your snapshot with the base it was authored against.**
72
72
  Derive and emit the **Authored-against** stamp per
73
- `claude-plugin/commands/_stamp-protocol.md` and place it at the very top of your
73
+ the /thrum:stamp-protocol skill and place it at the very top of your
74
74
  §1 section (that protocol computes the SHA and merge_target for you — never
75
75
  hand-type them). This is what lets `thrum prime` diff your snapshot at the next
76
76
  wake and flag which cited files have MOVED; an unstamped snapshot reads as
@@ -58,11 +58,7 @@ no session end. Exit code 1.
58
58
 
59
59
  ### 2. Read the shared snapshot-composition partial
60
60
 
61
- Read the partial at the absolute path:
62
-
63
- ```text
64
- ${REPO}/claude-plugin/commands/_snapshot-protocol.md
65
- ```
61
+ Invoke the /thrum:snapshot-protocol skill and follow it.
66
62
 
67
63
  Apply its Step 2 (compose your continuation) per the structure guidance.
68
64
 
@@ -62,11 +62,7 @@ no session end. Exit code 1. The skill is the wrong tool for non-tmux agents.
62
62
 
63
63
  ### 2. Read the shared snapshot-composition partial
64
64
 
65
- Read the partial at the absolute path:
66
-
67
- ```text
68
- ${REPO}/claude-plugin/commands/_snapshot-protocol.md
69
- ```
65
+ Invoke the /thrum:snapshot-protocol skill and follow it.
70
66
 
71
67
  Apply its Step 2 (compose your continuation) per the structure guidance.
72
68
 
@@ -104,7 +104,7 @@ updating.
104
104
 
105
105
  1. **Header line** — Update `Last Updated` date and `Phase` status summary. Also
106
106
  derive and insert the Authored-against stamp, placing it immediately after
107
- the `Last Updated` line (see `claude-plugin/commands/_stamp-protocol.md`
107
+ the `Last Updated` line (see the /thrum:stamp-protocol skill
108
108
  for the exact two-line format).
109
109
 
110
110
  2. **Current State Summary — LIVE STATE ONLY, SUPERSEDED EACH SESSION.**
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: choosing-subagent-models
3
- description: "Use when about to launch, spawn, or dispatch a subagent, sub-agent, or parallel agent - including the Agent/Task tool, an Explore agent, fanning out research, or any time you choose a model for a subagent. ALSO fires on every REVIEW dispatch - dispatching a reviewer, a code review, a code-quality review, a spec-compliance review, a dual review, a verify-against-plan or verify-against-source pass, or a merge-gate sub-agent. Reviewer dispatch is the HIGHEST-STAKES judgment-tier spawn and is the one most often done from memory. Enforces the role-based model tiering (opus-low orchestrators, sonnet-medium implementers and reviewers, sonnet-low sub-agents) and cheap parallel fan-out."
3
+ description: "Use when about to launch, spawn, or dispatch a subagent, sub-agent, or parallel agent - including the Agent/Task tool, an Explore agent, fanning out research, or any time you choose a model for a subagent. ALSO fires on every REVIEW dispatch - dispatching a reviewer, a code review, a code-quality review, a spec-compliance review, a dual review, a verify-against-plan or verify-against-source pass, or a merge-gate sub-agent. Reviewer dispatch is the HIGHEST-STAKES judgment-tier spawn and is the one most often done from memory. Enforces role-based model TIERING (mechanical, judgment, orchestration) resolved to a concrete model+effort for whichever runtime you are actually running under, and cheap parallel fan-out."
4
4
  ---
5
5
 
6
6
  # Choosing Subagent Models
@@ -11,16 +11,39 @@ description: "Use when about to launch, spawn, or dispatch a subagent, sub-agent
11
11
  (e.g. `/tmp/<task>.md`); its reply to you is only a summary. Put this
12
12
  in the prompt.**
13
13
 
14
- ## Pin every spawn. The floor depends on the agent's ROLE.
15
-
16
- Every subagent you spawn MUST pass an explicit `model:` (plus effort where the
17
- runtime supports it). Omitting it runs the subagent on YOUR model (Opus) — the
18
- single biggest avoidable cost leak in agent work.
19
-
20
- **Haiku is banned entirely.** There is no
21
- mechanical-task carve-out anymore — lint runs, grep-and-collect, file maps,
22
- config edits, and all other "simple" work now dispatch at sonnet-low, not Haiku.
23
- Never select Haiku on own judgment — use sonnet-low instead.
14
+ ## Pick a TIER by role/task, then resolve it for YOUR runtime. Pin every spawn.
15
+
16
+ Model selection here is two steps, always in this order:
17
+
18
+ 1. **Pick the semantic tier** by the spawned agent's role/task — one of three,
19
+ named identically everywhere in the fleet (Go constants, role templates,
20
+ this doc): **`mechanical`** (rote/find-replace/grep-and-collect/lint/file-maps —
21
+ the cheapest tier), **`judgment`** (the default tier for implementers,
22
+ reviewers, verifiers, researchers — real analysis, not busywork), and
23
+ **`orchestration`** (orchestrator/coordinator tier — never spawned for a
24
+ sub-agent, only ever the operator's own agent or a skill that explicitly
25
+ names it for one step).
26
+ 2. **Resolve that tier to a concrete `model:` + `effort:` for the runtime you
27
+ are actually running under** — via that runtime's own preset
28
+ (`RuntimePreset.TierModels`) or operator config (`runtime.role_models`);
29
+ see "Where the tier-model mapping lives" below. Never assume Claude's
30
+ model names (`sonnet`, `opus`, `haiku`) apply —
31
+ a Codex or OpenCode agent reading this same file has no such models, and
32
+ passing one either errors or silently falls back to the runtime's own
33
+ default (see "Never let an unresolved pin fall through" below).
34
+
35
+ Every subagent you spawn MUST pass an explicit, resolved `model:` (plus effort
36
+ where the runtime supports it). Omitting it runs the subagent on YOUR model —
37
+ the single biggest avoidable cost leak in agent work.
38
+
39
+ **The mechanical tier never resolves to a below-floor model, for any runtime.**
40
+ On Claude specifically that means **Haiku is banned entirely** — there is no
41
+ mechanical-task carve-out that reaches for it; lint runs, grep-and-collect,
42
+ file maps, config edits, and all other "simple" work dispatch at the
43
+ mechanical tier's Claude resolution (sonnet-low), not Haiku. Never select
44
+ Haiku on own judgment on Claude — use the mechanical tier's resolved value
45
+ instead. Other runtimes floor at their own mechanical-tier value
46
+ (`RuntimePreset.TierModels`), not at a Claude name.
24
47
 
25
48
  ### Read the tiers at the moment of use
26
49
 
@@ -39,36 +62,44 @@ from `runtime.role_models` for the target role, per this skill.
39
62
  ### Agent tiers
40
63
 
41
64
  Effort tier governs whether an agent does the hard thing or the expedient thing.
42
- These are the tiers now:
43
-
44
- | Role | Model / Effort |
45
- | ---------------------------- | ------------------- |
46
- | **Orchestrator** | **`opus` / low** |
47
- | **Implementer** | **`sonnet` / medium** |
48
- | **Verifier / reviewer** | **`sonnet` / medium** |
49
- | **Sub-agent** (investigation, grep, mechanical) | **`sonnet` / low** |
50
-
51
- - **`model: "sonnet"` @ low effort — sub-agents ONLY.** Investigation,
52
- grep-and-collect, file maps, lint runs, mechanical tasks. This is the floor for
53
- a *sub-agent*, NOT for an implementer or a reviewer.
54
- - **`model: "sonnet"` @ MEDIUM effort — implementers, verifiers, reviewers.**
55
- Not low. A reviewer on low effort is a rubber stamp with extra steps, and
56
- rubber-stamped reviews are how a merge gate that ran zero tests survived six
57
- sessions.
58
- - **`model: "opus"` @ low — orchestrators.** Not selectable for sub-agents —
59
- set by the operator on the agent's runtime-config.
60
- - **`model: "opus"` — NOT your call.** Allowed only when (a) the operator
61
- explicitly asked for a deep review or prose review in this task, or (b) a
62
- skill you are running prescribes Opus for the specific step you are currently
63
- executing — NOT for every spawn under that skill. "This research is hard /
64
- important" is NOT a justification — hard investigation is exactly what Sonnet
65
- is for.
65
+ These are the three tiers, with their Claude-runtime resolution shown as a
66
+ worked example — **if you are running under a different runtime, resolve the
67
+ same tier from your own runtime's preset (`RuntimePreset.TierModels`) or
68
+ `runtime.role_models`, not from the Claude column:**
69
+
70
+ | Role | Tier | Resolved for Claude (example) |
71
+ | ---------------------------- | ------------- | ------------------- |
72
+ | **Orchestrator / coordinator** | `orchestration` | **`opus` / low** |
73
+ | **Implementer** | `judgment` | **`sonnet` / medium** |
74
+ | **Verifier / reviewer** | `judgment` | **`sonnet` / medium** |
75
+ | **Sub-agent** (investigation, grep, mechanical) | `mechanical` | **`sonnet` / low** |
76
+
77
+ - **`mechanical` tier (sub-agents ONLY)** — investigation, grep-and-collect,
78
+ file maps, lint runs, mechanical tasks. Resolves to `sonnet` @ low effort on
79
+ Claude. This is the floor for a *sub-agent*, NOT for an implementer or a
80
+ reviewer, and NOT the tier a non-Claude runtime should read as its default.
81
+ - **`judgment` tier (implementers, verifiers, reviewers)** — resolves to
82
+ `sonnet` @ MEDIUM effort on Claude. Not low. A reviewer on low effort is a
83
+ rubber stamp with extra steps, and rubber-stamped reviews are how a merge
84
+ gate that ran zero tests survived six sessions.
85
+ - **`orchestration` tier (orchestrators/coordinators)** — resolves to `opus` @
86
+ low on Claude. Not selectable for sub-agents — set by the operator on the
87
+ agent's runtime-config.
88
+ - **`orchestration` tier is NOT your call to spawn.** Allowed only when (a) the
89
+ operator explicitly asked for a deep review or prose review in this task, or
90
+ (b) a skill you are running prescribes the orchestration tier for the
91
+ specific step you are currently executing — NOT for every spawn under that
92
+ skill. "This research is hard / important" is NOT a justification — hard
93
+ investigation is exactly what the `judgment` tier is for.
66
94
 
67
95
  ## Worked examples — LITERAL ARGUMENTS, AND EFFORT IS TOOL-DEPENDENT
68
96
 
69
- **Pin `model` on every spawn. Pass `effort` wherever the mechanism exposes it.**
70
- Syntax per mechanism — re-check the schema in front of you rather than restating
71
- from memory, because it can change:
97
+ **Pin `model` on every spawn, using the value your runtime's own preset
98
+ (`RuntimePreset.TierModels`) or `runtime.role_models` resolves the tier to.**
99
+ **Pass
100
+ `effort` wherever the mechanism exposes it** — some mechanisms don't. Syntax per
101
+ mechanism — re-check the schema in front of you rather than restating from
102
+ memory, because it can change:
72
103
 
73
104
  | Mechanism | `model` | `effort` |
74
105
  |---|---|---|
@@ -76,8 +107,14 @@ from memory, because it can change:
76
107
  | **Workflow `agent()`** (opts: label, phase, schema, model, effort, isolation, agentType) | ✅ settable | ✅ settable |
77
108
  | **Agent DEFINITION** (`.claude/agents/*.md` / plugin `agents/*.md` frontmatter) | ✅ | ✅ — sets the default for that agent type |
78
109
  | **`thrum tmux create` / `launch`** | ✅ `--model` | ✅ `--effort` — pass on BOTH |
110
+ | **Other runtimes' own spawn mechanism** | ✅ settable | runtime-dependent — check its own schema |
79
111
 
80
- **Agent tool — `model` only. It takes no `effort` argument.**
112
+ **Below is ONE fully concrete example — what a `judgment`-tier spawn looks
113
+ like once resolved for Claude's own Agent tool (which takes no `effort`
114
+ argument).** It is Claude-specific syntax with a Claude-specific model string;
115
+ if you are running under a different runtime, use that runtime's own spawn
116
+ mechanism and its own resolved model+effort from `RuntimePreset.TierModels` /
117
+ `runtime.role_models` instead of copying this literal string.
81
118
 
82
119
  ```python
83
120
  Agent(subagent_type="general-purpose", model="sonnet",
@@ -85,12 +122,14 @@ Agent(subagent_type="general-purpose", model="sonnet",
85
122
  prompt="...")
86
123
  ```
87
124
 
88
- **The tier philosophy still governs even where the Agent tool cannot express it:**
89
- sonnet-low for investigation and mechanical work, sonnet-medium for reviewers,
90
- verifiers and implementers. Where effort is not settable, carry the intent through
91
- the agent definition, the Workflow opts, or the tmux launch flags.
125
+ **The tier philosophy still governs even where a mechanism cannot express
126
+ `effort`:** the `model` value alone still must be the tier's resolved value for
127
+ YOUR runtime — never a bare Claude name assumed universal. Where effort is not
128
+ settable, carry the intent through the agent definition, the Workflow opts, or
129
+ the tmux launch flags instead.
92
130
 
93
- An agent definition can also carry a default:
131
+ An agent definition can also carry a default (Claude example — resolve to
132
+ your own runtime's `mechanical`-tier value if you are not Claude):
94
133
 
95
134
  ```yaml
96
135
  # claude-plugin/agents/message-listener.md
@@ -99,53 +138,88 @@ model: sonnet
99
138
  effort: low
100
139
  ```
101
140
 
102
- **Workflow `agent()` — effort IS a literal argument. Pass it.**
141
+ **Workflow `agent()` — effort IS a literal argument. Pass it, resolved for
142
+ your runtime's tier:**
103
143
 
104
144
  ```javascript
105
- agent(prompt, { model: "sonnet", effort: "medium" }) // reviewer / implementer
106
- agent(prompt, { model: "sonnet", effort: "low" }) // mechanical sub-agent
145
+ agent(prompt, { model, effort }) // `model`/`effort` = your runtime's resolution
146
+ // of the `judgment` tier (reviewer/implementer)
147
+ // or the `mechanical` tier (sub-agent) —
148
+ // resolve via RuntimePreset.TierModels /
149
+ // runtime.role_models for the literal values
107
150
  ```
108
151
 
109
- **THE DIRECTIVE, imperative and not a comment: REVIEWERS RUN SONNET AT MEDIUM
110
- EFFORT.** Pass `effort: "medium"` literally under Workflow, in the agent
111
- definition, or on `thrum tmux create`/`launch`. Never dispatch a reviewer "from
112
- memory".
152
+ **THE DIRECTIVE, imperative and not a comment: REVIEWERS RUN THE `judgment`
153
+ TIER, WHICH IS MEDIUM EFFORT ON EVERY RUNTIME THAT HAS AN EFFORT KNOB.** Pass
154
+ the resolved effort literally under Workflow, in the agent definition, or on
155
+ `thrum tmux create`/`launch` (the Agent tool takes no `effort`, so `model`
156
+ alone must still be the `judgment`-tier value there). Never dispatch a
157
+ reviewer "from memory", and never dispatch one at the mechanical tier.
113
158
 
114
159
  **AND VERIFY, DO NOT ASSERT:** any claim about what a tool does or does not expose
115
160
  must be checked against the schema in front of you.
116
161
 
117
- Never select Opus or Haiku on own judgment — use Sonnet, at the floor of
118
- sonnet-low.
162
+ Never select the `orchestration` tier or a below-floor model on your own
163
+ judgment — use the `judgment` tier's resolved value for your runtime, at the
164
+ floor of that tier's lowest effort.
165
+
166
+ ## Where the tier-model mapping lives
167
+
168
+ **Do not copy a tier's model string from this doc — read it at the moment of
169
+ use.** The three semantic tiers (`mechanical` / `judgment` / `orchestration`)
170
+ are the same across every runtime; only the concrete model+effort differs per
171
+ runtime, and that mapping lives in exactly two places:
172
+
173
+ - **The runtime's own preset** (the `TierModels` field of the runtime preset
174
+ schema) — the machine-checked, per-runtime tier→model
175
+ table. A runtime with no entry for a tier has no fleet-configured value for
176
+ it and resolves to nothing rather than inheriting another runtime's model.
177
+ - **`runtime.role_models` in `.thrum/config.json`** — operator configuration
178
+ for this project, which always outranks the preset's tier table.
119
179
 
120
- ## Fleet model-tiering by runtime/role
180
+ **If you are running under Claude**, use the Agent tiers table above
181
+ (orchestrator/implementer/reviewer/sub-agent → orchestration/judgment/
182
+ judgment/mechanical), plus brainstormer → `orchestration` and brainstormer's
183
+ own subagents → `mechanical` (except reviewers, which are always `judgment`).
121
184
 
122
- Different runtimes and roles pin different tiers. Claude tiers are canonical —
123
- see the Agent tiers table above (orchestrator/implementer/reviewer/sub-agent),
124
- plus brainstormer → opus-medium and brainstormer's own subagents → sonnet-low
125
- (except reviewers → sonnet-medium). Other runtimes:
185
+ **If you are running under a different runtime, read your own tier's value
186
+ from the two sources above** — never assume Claude's model names apply, and
187
+ never hard-code a model string you saw once in a doc or a prior session.
126
188
 
127
- | Runtime | Role | Model / effort |
128
- | ------------ | ---------------------------- | --------------------------------------------------- |
129
- | OpenCode | default | GLM-5.2 (fine as-is) |
130
- | Codex | orchestrator / reviewer | gpt-5.5-medium |
131
- | Codex | implementer | gpt-5.5-low |
132
- | Cursor-agent | default | composer-2.5 (fine as-is) |
189
+ A runtime/role pair with no fleet-configured tier value has no override —
190
+ resolve it to that runtime's own configured default, and pass it explicitly
191
+ (never leave it unset — see "Never let an unresolved pin fall through"
192
+ below).
133
193
 
134
194
  ## Pin every spawn explicitly — the floor depends on the ROLE, not the depth
135
195
 
136
- Every orchestrator MUST pass an explicit `model:` on EVERY subagent it spawns, and
137
- `effort` wherever the mechanism exposes it. An unspecified subagent SILENTLY
138
- INHERITS THE PARENT'S MODEL — so an Opus orchestrator that forgets the pin just
139
- spent Opus tokens on a grep.
196
+ Every orchestrator MUST pass an explicit `model:` on EVERY subagent it spawns,
197
+ resolved for its own runtime, and `effort` wherever the mechanism exposes it.
198
+ An unspecified subagent SILENTLY INHERITS THE PARENT'S MODEL — so an
199
+ orchestration-tier orchestrator that forgets the pin just spent its
200
+ (expensive) tier's tokens on a grep.
140
201
 
141
202
  **The floor is set by what the agent DOES, not by how deep it sits** — see the
142
203
  Agent tiers table above. This applies recursively: an implementer spawning its
143
204
  own helpers pins them by THEIR role, not by copying its own tier down.
144
205
 
145
206
  The check before every spawn: what is this agent's ROLE? Reviewer or implementer?
146
- sonnet-medium. Pure investigation or mechanical work? sonnet-low. Never leave it
207
+ `judgment` tier. Pure investigation or mechanical work? `mechanical` tier. Then
208
+ resolve that tier to your runtime's concrete model+effort. Never leave it
147
209
  unspecified.
148
210
 
211
+ ### Never let an unresolved pin fall through
212
+
213
+ **An unsupported or unrecognized model name must never block delegation, and
214
+ must never cause silent inheritance of the parent's model.** If your
215
+ runtime's preset has no `TierModels` entry for this tier, or a resolved name
216
+ is rejected by the runtime you're spawning under, do NOT skip the pin and do
217
+ NOT let the spawn go unpinned so it falls back to inheriting the caller's
218
+ model — fall back explicitly to the runtime's own configured default for the
219
+ matching tier and pass THAT, so every spawn is always pinned to some resolved
220
+ model+effort. An unset `model:` is a bug at every layer of this stack, not
221
+ just under Claude.
222
+
149
223
  ## Paste the constraint block into the child prompt — the pin is not enough
150
224
 
151
225
  **A model pin is an ARGUMENT and travels by itself. A behavioural constraint is
@@ -162,8 +236,11 @@ that stops at depth 1 is absent where the work happens.
162
236
  tool's own guidance suggests it. It trips a permission modal, and A FROZEN
163
237
  PANE EMITS NOTHING, so nobody can tell you are blocked. If you must background
164
238
  work, wait for the completion notification.
165
- - Every sub-agent YOU spawn gets an explicit `model:` — sonnet (low mechanical,
166
- medium judgment). HAIKU IS BANNED. Opus is never yours.
239
+ - Every sub-agent YOU spawn gets an explicit `model:`, resolved for your
240
+ runtime's tier — `mechanical` (rote/find-replace) or `judgment` (real
241
+ analysis). On Claude that's sonnet-low / sonnet-medium and HAIKU IS BANNED;
242
+ on another runtime, use that runtime's own resolved row. The
243
+ `orchestration` tier is never yours to spawn.
167
244
  - READ-ONLY git outside your own worktree. NEVER `checkout`/`reset`/`restore`/
168
245
  `stash`/`clean` in ANY directory — `stash` is one shared stack across all
169
246
  worktrees and the shared tree holds live agents' uncommitted state.
@@ -175,7 +252,8 @@ signal this condition produces.
175
252
 
176
253
  ### Cheap subagents → fan out, don't pile up
177
254
 
178
- Because sonnet-low subagents are cheap, prefer MANY small parallel subagents
255
+ Because `mechanical`-tier subagents are cheap (sonnet-low on Claude; the
256
+ mechanical-tier row for your runtime otherwise), prefer MANY small parallel subagents
179
257
  over one subagent handed a pile of tasks. When a research or investigation task
180
258
  has independent parts, partition it and dispatch the parts in parallel (use the
181
259
  `efficient-multi-agent-research` skill) — smaller scopes are cheaper, run
@@ -184,6 +262,12 @@ given ten tasks is the anti-pattern.
184
262
 
185
263
  ## ⚠️ The pin-verification command LIES — do not trust it
186
264
 
265
+ **This section's examples are Claude-specific** (`thrum tmux capture`'s footer
266
+ format, and the historical Sonnet/Opus incident it documents) because that is
267
+ where this defect was measured — but the underlying rule generalizes: verify
268
+ a pin by reading the runtime's own RESOLVED status output, never a stored
269
+ "configured" value, whichever runtime you're on.
270
+
187
271
  `thrum agent runtime-config get <agent>` reports the **configured** value, not the
188
272
  **resolved** one.
189
273
 
@@ -264,3 +348,35 @@ launch **by construction**.
264
348
  An implementer pinned to sonnet, with an implementer role-default of sonnet, comes up
265
349
  correct whether or not the pin landed — so "pin sonnet, confirm sonnet" passes whether
266
350
  or not the fix works.
351
+
352
+ ## Paste blocks for child prompts
353
+
354
+ Paste these verbatim into a child prompt when the work involves the named activity.
355
+
356
+ --- SUB-AGENT HYGIENE ---
357
+ - No kill -0, Monitor or until-loop polling.
358
+ - No pgrep -f.
359
+ - Kill only by a captured PID number.
360
+ - Use rm -r, never rm -rf; a variable path uses "${d:?}".
361
+ - No 2>/dev/null on destructive commands.
362
+ - Bounded timeouts on everything.
363
+ - Remove only the worktree you created in this task, by its recorded path, never with --force.
364
+ - Never demonstrate an unguarded destructive idiom, even on a literal path.
365
+ --- END SUB-AGENT HYGIENE ---
366
+
367
+ --- TESTS ---
368
+ - To prove a selector resolves, use `go test <pkg> -list '<selector>'` plus a `-list '^TestNoSuchThingAtAll$'` negative control that must list zero tests. Never `-run '<sel>' -list '.*'`.
369
+ - `bd list -l` is --label; use `-n` for a limit.
370
+ - A timeout with 0 FAIL is neither red nor green: classify it as a bound failure, read the panic's "running tests:" line, and re-run wider.
371
+ --- END TESTS ---
372
+
373
+ --- WORKTREE TEARDOWN & SALVAGE ---
374
+ - Before any teardown, enumerate with both flags: `git -C <wt> status --porcelain --untracked-files=all --ignored -- .thrum`.
375
+ - Salvage anything found to a durable path (not /tmp), one subdirectory per worktree, filenames path-flattened.
376
+ - Never glob `.thrum/context/*.md`; salvage the exact agent-name file only, and assert no `project_state.md` landed in any salvage output.
377
+ - Verify salvage by name set first, then `cmp` each file, with a negative control proving `cmp` detects a difference.
378
+ - Kill the tmux session first (`thrum tmux kill <session>`), verify it is gone, then plain `git worktree remove`, never `--force`.
379
+ - Afterwards verify by effect: gone from `git worktree list` and from disk, and every remaining live pane's cwd still resolves (`tmux list-panes -a -F '#{pane_current_path}'`, then `git rev-parse --show-toplevel` per pane).
380
+ - Build the in-use protection set from live pane cwds, not from a name or registry list.
381
+ - Report the removal count and the registry delta separately.
382
+ --- END WORKTREE TEARDOWN & SALVAGE ---
@@ -94,8 +94,7 @@ tool that can prove it, not by trusting the sentence that claims it.
94
94
 
95
95
  ## Project-specific rules (already loaded)
96
96
 
97
- Read the shared partial at the absolute path:
98
- `claude-plugin/commands/_project-rules-protocol.md`
97
+ Load the /thrum:project-rules-protocol skill and follow it.
99
98
 
100
99
  If you accumulate a new rule mid-session (the user corrects you), capture it
101
100
  via the `implementer-maintaining-memory` skill (or `coordinator-maintaining-
@@ -155,7 +155,7 @@ For each role:
155
155
  - If beads detected: include `bd` commands in Task Tracking section
156
156
  - If MCP servers detected: add to Efficiency section
157
157
  - If specific skills detected: reference them
158
- - If worktree restrictions: adjust Scope Boundaries
158
+ - If worktree restrictions: adjust the Scope section
159
159
 
160
160
  3. Write to `.thrum/role_templates/{role}.md`. Keep per-agent template tokens
161
161
  (`{{.AgentName}}`, `{{.Module}}`, `{{.WorktreePath}}`,
@@ -226,4 +226,4 @@ rendered files from saved answers without asking any questions.
226
226
  | Thrum MCP server | Add MCP tool references, CLI fallback for sub-agents |
227
227
  | Claude plugin skills | List installed skills with usage guidance |
228
228
  | Context7 MCP | Add library docs guidance to Efficiency section |
229
- | Multiple worktrees | Add worktree scope rules to Scope Boundaries |
229
+ | Multiple worktrees | Add worktree scope rules to the Scope section |