opencode-thrum-pro 0.1.5 → 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 (90) hide show
  1. package/assets/commands/thrum-compact-extended.md +367 -0
  2. package/assets/commands/thrum-compact.md +301 -0
  3. package/assets/commands/thrum-inbox.md +1 -1
  4. package/assets/commands/thrum-restart-extended.md +85 -16
  5. package/assets/commands/thrum-restart.md +106 -14
  6. package/assets/commands/thrum-send.md +4 -1
  7. package/assets/commands/thrum-sleep-extended.md +68 -51
  8. package/assets/commands/thrum-sleep.md +68 -63
  9. package/assets/commands/thrum-update-project.md +1 -1
  10. package/assets/skills/adversarial-critique/SKILL.md +5 -8
  11. package/assets/skills/brainstorm-steward/SKILL.md +65 -11
  12. package/assets/skills/brainstormer-staying-current/SKILL.md +1 -4
  13. package/assets/skills/choosing-subagent-models/SKILL.md +200 -70
  14. package/assets/skills/closing-findings-while-warm/SKILL.md +1 -2
  15. package/assets/skills/configure-roles/SKILL.md +2 -2
  16. package/assets/skills/conversation-only-context/SKILL.md +11 -11
  17. package/assets/skills/conversation-only-context/resources/driver-subagent-pattern.md +1 -1
  18. package/assets/skills/conversation-only-context/resources/remote-environment-scenarios.md +1 -1
  19. package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +98 -6
  20. package/assets/skills/coordinator-branch-split-on-block/SKILL.md +1 -2
  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 +26 -14
  24. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +65 -21
  25. package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +1 -2
  26. package/assets/skills/coordinator-maintaining-memory/SKILL.md +1 -1
  27. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +7 -8
  28. package/assets/skills/coordinator-merging-code/SKILL.md +43 -22
  29. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +29 -9
  30. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +4 -5
  31. package/assets/skills/coordinator-rolling-out-to-nodes/SKILL.md +92 -0
  32. package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +3 -3
  33. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +25 -25
  34. package/assets/skills/coordinator-running-review-cycles/SKILL.md +16 -6
  35. package/assets/{commands/thrum-_deviations-protocol.md → skills/deviations-protocol/SKILL.md} +6 -12
  36. package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +0 -2
  37. package/assets/skills/efficient-multi-agent-research/SKILL.md +3 -3
  38. package/assets/skills/generator-idempotency-protocol/SKILL.md +9 -0
  39. package/assets/skills/implementer-maintaining-memory/SKILL.md +3 -4
  40. package/assets/skills/implementer-orchestrating-execution/SKILL.md +12 -16
  41. package/assets/skills/implementer-receiving-dispatch/SKILL.md +15 -17
  42. package/assets/skills/implementer-receiving-review-feedback/SKILL.md +3 -4
  43. package/assets/skills/implementer-status-and-handoff/SKILL.md +1 -14
  44. package/assets/skills/implementer-tdd-and-quality/SKILL.md +2 -2
  45. package/assets/skills/memory-curate/SKILL.md +1 -1
  46. package/assets/skills/memory-write-discipline/SKILL.md +1 -1
  47. package/assets/skills/orchestrate/SKILL.md +77 -36
  48. package/assets/skills/persistent-watcher-archetype/SKILL.md +172 -25
  49. package/assets/skills/persistent-watcher-archetype/resources/capture_archive.py +618 -0
  50. package/assets/skills/persistent-watcher-archetype/resources/jev_watcher_filter.py +837 -0
  51. package/assets/skills/persistent-watcher-archetype/resources/roster-watch.sh +1140 -0
  52. package/assets/skills/persistent-watcher-archetype/resources/roster-watch_test.sh +291 -0
  53. package/assets/skills/persistent-watcher-archetype/resources/thrum-capture-fallback.sh +2 -2
  54. package/assets/skills/persistent-watcher-archetype/resources/thrum-watch-pane-capture.sh +20 -8
  55. package/assets/skills/prime-agent/SKILL.md +10 -0
  56. package/assets/skills/project-hotpath-gate/SKILL.md +1 -2
  57. package/assets/skills/project-philosophy/SKILL.md +1 -2
  58. package/assets/skills/project-rules-protocol/SKILL.md +12 -0
  59. package/assets/skills/project-setup/SKILL.md +27 -22
  60. package/assets/skills/project-setup/resources/implementation-agent.md +55 -35
  61. package/assets/skills/researcher-answering-queries/SKILL.md +1 -2
  62. package/assets/skills/researcher-investigating/SKILL.md +8 -13
  63. package/assets/skills/researcher-maintaining-memory/SKILL.md +1 -1
  64. package/assets/{commands/thrum-_snapshot-protocol.md → skills/snapshot-protocol/SKILL.md} +27 -21
  65. package/assets/{commands/thrum-_stamp-protocol.md → skills/stamp-protocol/SKILL.md} +14 -8
  66. package/assets/skills/thrum/SKILL.md +14 -7
  67. package/assets/skills/thrum/resources/ANTI_PATTERNS.md +16 -18
  68. package/assets/skills/thrum/resources/CLI_REFERENCE.md +17 -11
  69. package/assets/skills/thrum/resources/LISTENER_PATTERN.md +9 -3
  70. package/assets/skills/thrum/resources/MESSAGING.md +18 -11
  71. package/assets/skills/thrum/resources/WORKTREES.md +1 -1
  72. package/assets/skills/thrum-memory/SKILL.md +1 -1
  73. package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +1 -1
  74. package/assets/skills/update-queue/SKILL.md +6 -8
  75. package/assets/skills/using-the-dashboard/SKILL.md +30 -0
  76. package/assets/skills/using-the-queue/SKILL.md +76 -5
  77. package/assets/skills/using-thrum-state/SKILL.md +85 -2
  78. package/assets/skills/verify-against-plan/SKILL.md +122 -7
  79. package/assets/skills/watcher-archetype/SKILL.md +18 -0
  80. package/assets/skills/writing-durable-markdown/SKILL.md +5 -0
  81. package/dist/installer-assets.test.js +41 -0
  82. package/dist/installer.js +4 -4
  83. package/dist/permission-fixture.integration.test.js +4 -4
  84. package/package.json +1 -1
  85. package/assets/commands/thrum-_generator-idempotency-protocol.md +0 -15
  86. package/assets/commands/thrum-_project-rules-protocol.md +0 -18
  87. package/assets/commands/thrum-_verify-before-write-protocol.md +0 -27
  88. package/assets/skills/coordinator-deploying-the-fleet/SKILL.md +0 -396
  89. package/dist/allowlist-sync.test.js +0 -44
  90. /package/dist/{allowlist-sync.test.d.ts → installer-assets.test.d.ts} +0 -0
@@ -42,25 +42,115 @@ every agent in your `roster`:
42
42
  (your own pane capture) — see "Declared-intent reminders" below for the
43
43
  full mechanics.
44
44
 
45
- ## The modal bright line (non-negotiable)
46
-
47
- - Approve ONLY clearly-safe, recognized, non-`rm`/non-`--force` modals.
48
- - `rm`, `--force`, or an unrecognized command → refuse or escalate to your
49
- `parent`. That filter is mechanical.
50
- - Within the safe set, judge the COMMAND TEXT, not the modal's phrasing: read
51
- the command and approve if it is clearly-safe and recognized whatever wording
52
- the modal uses, else cancel or escalate. Never key on fixed prompt phrases;
53
- never approve blind.
45
+ ## The modal judgment rubric (non-negotiable)
46
+
47
+ - Approve a modal when you can explain what the command does, it fits what
48
+ the requesting agent is visibly doing in its pane, and a mistake would be
49
+ recoverable. Otherwise escalate to your `parent` with a one-line reason.
50
+ - Judge the TARGET, not the keyword: `rm -rf /tmp/<dir the agent just
51
+ created>` is routine cleanup; `rm -rf /tmp/*` is not. One `rm` of a stale
52
+ lock file by a coordinator mid-deploy is fine. A force-push, or a delete
53
+ whose target or purpose you can't tell, is an escalate.
54
+ - Escalating is always allowed. Refusing only because a keyword appeared is
55
+ not.
56
+ - Judge the COMMAND TEXT, not the modal's phrasing: read the command and
57
+ approve or refuse on what it actually does, whatever wording the modal
58
+ uses. Never key on fixed prompt phrases; never approve blind.
54
59
  - Verify by re-capture after acting — never trust exit status alone.
55
- - To unblock a REMOTE roster member's modal, use `thrum tmux send <agent> " "`
56
- (proxies by agent name to the owning peer daemon and appends Enter, so a
57
- space+Enter confirms the default-focused option); for a specific selection
58
- use `thrum tmux send <agent> --keys <K1,K2,...>`. `thrum tmux send` is
59
- peer-routed, so it works identically local or remote (fleet-wide) — this is
60
- the replacement for the retired local-only tmux-key primitive. This grants only
61
- the leftmost/default option; the bright line above still applies. From the
62
- CLI/peer-router path this send is QUEUED behind the conservative
63
- monitor-silence wait, not instant — don't re-send while waiting it out.
60
+
61
+ ### Approving or dismissing a modal: keys only, never text
62
+
63
+ > 🔴 **NEVER answer a modal with a text payload — not even a single
64
+ > character, and never a bare positional argument to `thrum tmux send`.**
65
+ > Plain text TYPES INTO the agent's input box; it does not act as a
66
+ > keypress. If the modal isn't actually showing, or focus differs from what
67
+ > you expect, that text lands in the agent's next command line and can
68
+ > corrupt or execute something you never intended. The only correct
69
+ > primitive is `--keys`, on every call, with no exceptions.
70
+
71
+ The procedure, every time, no shortcuts:
72
+
73
+ 1. **Capture the pane fresh.** Never act on a stale capture from an earlier
74
+ cycle.
75
+ 2. **Recognize the modal and which option is currently focused** (`❯` or
76
+ equivalent marks the default). Judge it against the rubric above.
77
+ 3. **Choose keys, never text:**
78
+ - Default/focused option → `thrum tmux send <agent> --keys Enter`.
79
+ - A specific numbered option → the digit, e.g. `thrum tmux send <agent>
80
+ --keys 1`. Named keys (`Enter`, `Escape`, `Up`, `Down`, `Left`, `Right`,
81
+ `Tab`, digits) deliver in order, comma-separated or repeated
82
+ (`--keys Down,Enter` or `--keys Down --keys Enter`) — confirm the exact
83
+ syntax with `thrum tmux send --help` if in doubt, never guess it.
84
+ - To dismiss without selecting → `thrum tmux send <agent> --keys Escape`.
85
+ - This send is QUEUED behind the conservative monitor-silence wait, not
86
+ instant — don't re-send while waiting it out. A send that exits 3 (Enter
87
+ WITHHELD) or 4 (verdict unknown) must NOT be retried blind — capture the
88
+ pane first.
89
+ 4. **Re-capture and verify the modal is actually gone.** If it's still there,
90
+ don't give up and don't loop blindly retrying the same keys — work up an
91
+ escalating transport ladder, re-capturing to verify after EACH attempt:
92
+ a. `thrum tmux send <agent> --keys ...` — the daemon RPC you already tried
93
+ in step 3. It is peer-routed (works for a local member always, and for
94
+ a remote one when the `can_send_keys` capability is granted between
95
+ your box and theirs) — retry once in case the first send was dropped,
96
+ not blindly beyond that.
97
+ b. **Raw local tmux**, for a member on YOUR OWN box whose pane the daemon
98
+ RPC isn't reaching correctly: `tmux send-keys -t <session> <key>`, then
99
+ `tmux capture-pane -t <session> -p` to verify directly, bypassing the
100
+ daemon layer.
101
+ c. **SSH to the member's own box**, for a remote member or whenever (a)
102
+ fails with a proxy-failure signature (`rpcrouter: caller-peer lacks
103
+ required capability`, `peer unreachable`, `circuit open, dial skipped`)
104
+ — use the shipped pair of scripts, don't hand-roll the SSH call:
105
+ `resources/thrum-watch-pane-capture.sh`'s `build_topology_table` /
106
+ `resolve_roster_targets` resolves the target's SSH destination from
107
+ `thrum state get agent_pool:<agent>` (`.entry.value.box`) joined
108
+ against `thrum state show topology:<scope>` (`.entry.value.hostname`
109
+ / `.entry.value.ssh.target` / `.entry.value.ssh.user` /
110
+ `.entry.value.repo_path`), then hands those already-resolved values to
111
+ `resources/thrum-capture-fallback.sh <capture|key> <agent> <ssh_target>
112
+ <ssh_user> <repo_path> [keys...]`, which is the piece that actually
113
+ runs `ssh "<ssh_user>@<ssh_target>" "cd '<repo_path>' && thrum tmux
114
+ send '<agent>' --keys <keys>"` — `thrum-capture-fallback.sh` does no
115
+ resolution of its own, so calling it directly requires you (or the
116
+ caller) to already have those three values. A topology gap fails
117
+ closed (no SSH fallback attempted) rather than guessing a wrong
118
+ destination. There is no per-agent SSH field in the roster/agent Go
119
+ schema — the destination comes from this `thrum state` topology data.
120
+ (There IS a real `.thrum/ssh/config` on fleet boxes — the underlying
121
+ host-alias file, included via `~/.ssh/config`, that makes a bare `ssh
122
+ <box>` resolve at all — but it is not what these scripts read; they
123
+ read the resolved `ssh.target`/`ssh.user` values out of `thrum state`
124
+ instead.)
125
+ Only escalate to your `parent` after exhausting this ladder, or
126
+ immediately on an UNRECOGNIZED modal — and when you do, include the fresh
127
+ capture.
128
+ - Cross-peer send-keys being capability-gated is a deliberate security
129
+ boundary (§ladder step a above), not a bug to route around by other means
130
+ without checking the failure signature first. A peer can always CAPTURE
131
+ another peer's panes read-only regardless of capability.
132
+
133
+ **Worked example** — the standard two-variant Claude Code tool-confirmation
134
+ modal (`internal/daemon/permission/patterns.go`, pattern `tool_confirmation`,
135
+ dialect `claude-tui`), captured verbatim:
136
+
137
+ ```
138
+ ⏺ Bash(curl https://example.com)
139
+ ⎿ Do you want to proceed?
140
+ 1. Yes
141
+ 2. Yes, and don't ask again for Bash(curl)
142
+ 3. No, and tell Claude what to do differently (Esc)
143
+ ```
144
+
145
+ - **Approve once** → `--keys 1`.
146
+ - **Deny, with feedback** → `--keys 3` (or `--keys Escape` on the two-option
147
+ Read-prompt variant, which has no "No, and tell Claude" line).
148
+ - **NEVER `--keys 2`** — "Yes, and don't ask again" grants a standing
149
+ allow-rule beyond this one command; the modal judgment rubric above is a
150
+ per-command judgment, not a license to mint blanket permissions. This is
151
+ pinned by `ApproveKey: "1", // Yes (once) — NEVER "2"` in
152
+ `internal/daemon/permission/patterns.go` and tested by
153
+ `TestApproveKeyNeverForeverAllow`.
64
154
 
65
155
  ## Your own restart (auto-restart-at-ctx-threshold)
66
156
 
@@ -121,6 +211,22 @@ is the entire reason the watch exists — and a blocked coordinator cannot
121
211
  receive its own escalation. The escalation would arrive at the one inbox
122
212
  guaranteed not to be read.
123
213
 
214
+ ### 🔴 HUMAN-NEEDED escalation goes to the owner by message, never pane-only
215
+
216
+ When you need a human decision, resolve the owner from CONFIG — never hardcode
217
+ a name — and deliver it as a message, not pane text:
218
+
219
+ OWNER=$(jq -r '.permission_supervisors[] | select(startswith("@user:"))' .thrum/config.json | sed 's/^@//' | head -1)
220
+ thrum send --to "$OWNER" --stdin <<'EOF'
221
+ [ESCALATION] <what needs a decision>: <why>. Action needed: <what>.
222
+ EOF
223
+
224
+ Writing the escalation only into your own pane is not delivery — nobody reads
225
+ watcher panes. If you get no response within 15 minutes, resend and verify
226
+ delivery (`thrum sent --unread`) before assuming it was seen. SAFE recognized
227
+ modals stay approver-of-record and are approved directly, unchanged — this
228
+ rule applies only to escalations that need a human decision.
229
+
124
230
  ### An unwatchable roster member: escalate every cycle until it is removed
125
231
 
126
232
  A roster member you **cannot watch at all** — capture fails by every path
@@ -217,8 +323,8 @@ Register the loop as a `thrum monitor` instead — a daemon-scheduled job,
217
323
  independent of your session, that keeps running across your restarts.
218
324
 
219
325
  **A ready-to-use script ships with this skill** — `resources/thrum-watch-
220
- pane-capture.sh` (paired with `resources/thrum-capture-fallback.sh`,
221
- thrum-3mhrt). It is generic and roster-driven: it reads your own
326
+ pane-capture.sh` (paired with `resources/thrum-capture-fallback.sh`).
327
+ It is generic and roster-driven: it reads your own
222
328
  `watch_params.json`, captures each roster member's pane (local `thrum tmux
223
329
  capture` first, always — that already reaches remote agents by name via the
224
330
  normal rpcrouter proxy; see "SSH fallback" below for what the second script
@@ -246,10 +352,10 @@ runtime-versioned path involved:
246
352
 
247
353
  Then register the monitor against that absolute copy path —
248
354
  **`--notify-on-success` is MANDATORY, not optional decoration**: a
249
- `--schedule`d job delivers NOTHING on `--match` alone (thrum-ruz1z §5c —
250
- this fails completely silently, every status field reads healthy, and it
355
+ `--schedule`d job delivers NOTHING on `--match` alone — this fails
356
+ completely silently, every status field reads healthy, and it
251
357
  is exactly the trap a literal reading of the syntax below used to walk
252
- readers into):
358
+ readers into:
253
359
 
254
360
  ```bash
255
361
  thrum monitor start --name <you>-pane-watch \
@@ -267,13 +373,54 @@ At the start of every cycle, confirm the monitor is still running
267
373
  (`thrum monitor list`) — if it's missing or dead, re-`thrum monitor start`
268
374
  it rather than assuming someone else will notice.
269
375
 
376
+ **Roster snapshot monitor:** copy `resources/roster-watch.sh`,
377
+ `resources/capture_archive.py`, and `resources/jev_watcher_filter.py` into `<worktree>/.thrum-watch/`, then
378
+ `chmod +x <worktree>/.thrum-watch/roster-watch.sh` — a mode-preserving copy of
379
+ this resource can land as `644` depending on the runtime plugin's own tree
380
+ (don't rely on the source file's mode alone) — then register the monitor
381
+ against that copied `roster-watch.sh`. Keep the helper beside the script; the
382
+ roster archive path must not depend on a plugin or research worktree path at
383
+ run time. Captures and their archive land under `.thrum/agents/<you>/watch-captures/`
384
+ (redirect-resolved), not beside the deployed script itself.
385
+
386
+ Register roster-watch.sh's own monitor the same way, matching its actual
387
+ output lines (`"roster capture ready:"` for a normal tick, `"ROSTER
388
+ INCIDENT:"` for a capture-failure incident):
389
+
390
+ ```bash
391
+ thrum monitor start --name roster-watch-<you> \
392
+ --match "^(roster capture ready:|ROSTER INCIDENT:)" \
393
+ --to @<you> \
394
+ --env AGENT_NAME=<you> \
395
+ --notify-on-success \
396
+ --schedule '*/10 * * * *' \
397
+ -- <worktree>/.thrum-watch/roster-watch.sh
398
+ ```
399
+
400
+ Set `use_jev: true` in the watcher's redirect-resolved `watch_params.json`
401
+ to filter notifications. JEV is opt-in ONLY when a key is actually present:
402
+ `use_jev: true` alone does not engage it. The helper reads API keys from the
403
+ watcher worktree's repo-root `.env` (or `ROSTER_JEV_ENV_FILE` if set);
404
+ environment variables take precedence. `OPENROUTER_API_KEY` is an optional
405
+ provider fallback. If `use_jev: true` but neither `THRUM_TYPESAFE_KEY` nor
406
+ `OPENROUTER_API_KEY` is found (env or that `.env` file), the watcher logs
407
+ `JEV requested but no key found — skipped` and runs the plain non-JEV path
408
+ for that tick — no manifest filter, no decision directory, and
409
+ `jev_watcher_filter.py` never runs. Confident active permission prompts and
410
+ blocking user-choice dialogs wake the watcher. Failed or uncertain decisions use
411
+ the normal watcher path. Missing or false `use_jev` retains normal behavior.
412
+
413
+ Keep --notify-on-success when changing use_jev. A compatible daemon
414
+ suppresses the success confirmation only after a completed, confidently ordinary
415
+ JEV tick; changing the boolean needs no monitor re-registration.
416
+
270
417
  ### SSH fallback (resilience net, not the primary path)
271
418
 
272
419
  `thrum tmux capture <agent>` already reaches remote agents by name via the
273
420
  rpcrouter proxy — that is how fleet-wide watching works today for a healthy
274
421
  peer. `thrum-capture-fallback.sh` exists for when that proxy path is
275
- broken on the caller's side (known bug classes: thrum-7vwgy same-host
276
- dual-daemon caller-identity collision; thrum-zkqut phantom-routing
422
+ broken on the caller's side (known bug classes: a same-host
423
+ dual-daemon caller-identity collision; a phantom-routing
277
424
  regression on a daemon build predating `EnsureProxies`). It is a strict
278
425
  FALLBACK, never primary and never SSH-first: `thrum-watch-pane-capture.sh`
279
426
  always tries the local proxy path first, and only retries via an SSH hop —