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.
- package/assets/commands/thrum-compact-extended.md +367 -0
- package/assets/commands/thrum-compact.md +301 -0
- package/assets/commands/thrum-inbox.md +1 -1
- package/assets/commands/thrum-restart-extended.md +85 -16
- package/assets/commands/thrum-restart.md +106 -14
- package/assets/commands/thrum-send.md +4 -1
- package/assets/commands/thrum-sleep-extended.md +68 -51
- package/assets/commands/thrum-sleep.md +68 -63
- package/assets/commands/thrum-update-project.md +1 -1
- package/assets/skills/adversarial-critique/SKILL.md +5 -8
- package/assets/skills/brainstorm-steward/SKILL.md +65 -11
- package/assets/skills/brainstormer-staying-current/SKILL.md +1 -4
- package/assets/skills/choosing-subagent-models/SKILL.md +200 -70
- package/assets/skills/closing-findings-while-warm/SKILL.md +1 -2
- package/assets/skills/configure-roles/SKILL.md +2 -2
- package/assets/skills/conversation-only-context/SKILL.md +11 -11
- package/assets/skills/conversation-only-context/resources/driver-subagent-pattern.md +1 -1
- package/assets/skills/conversation-only-context/resources/remote-environment-scenarios.md +1 -1
- package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +98 -6
- package/assets/skills/coordinator-branch-split-on-block/SKILL.md +1 -2
- package/assets/skills/coordinator-context-monitoring/SKILL.md +29 -19
- package/assets/skills/coordinator-deploying-a-node/SKILL.md +124 -0
- package/assets/skills/coordinator-dispatching-work/SKILL.md +26 -14
- package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +65 -21
- package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +1 -2
- package/assets/skills/coordinator-maintaining-memory/SKILL.md +1 -1
- package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +7 -8
- package/assets/skills/coordinator-merging-code/SKILL.md +43 -22
- package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +29 -9
- package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +4 -5
- package/assets/skills/coordinator-rolling-out-to-nodes/SKILL.md +92 -0
- package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +3 -3
- package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +25 -25
- package/assets/skills/coordinator-running-review-cycles/SKILL.md +16 -6
- package/assets/{commands/thrum-_deviations-protocol.md → skills/deviations-protocol/SKILL.md} +6 -12
- package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +0 -2
- package/assets/skills/efficient-multi-agent-research/SKILL.md +3 -3
- package/assets/skills/generator-idempotency-protocol/SKILL.md +9 -0
- package/assets/skills/implementer-maintaining-memory/SKILL.md +3 -4
- package/assets/skills/implementer-orchestrating-execution/SKILL.md +12 -16
- package/assets/skills/implementer-receiving-dispatch/SKILL.md +15 -17
- package/assets/skills/implementer-receiving-review-feedback/SKILL.md +3 -4
- package/assets/skills/implementer-status-and-handoff/SKILL.md +1 -14
- package/assets/skills/implementer-tdd-and-quality/SKILL.md +2 -2
- package/assets/skills/memory-curate/SKILL.md +1 -1
- package/assets/skills/memory-write-discipline/SKILL.md +1 -1
- package/assets/skills/orchestrate/SKILL.md +77 -36
- package/assets/skills/persistent-watcher-archetype/SKILL.md +172 -25
- package/assets/skills/persistent-watcher-archetype/resources/capture_archive.py +618 -0
- package/assets/skills/persistent-watcher-archetype/resources/jev_watcher_filter.py +837 -0
- package/assets/skills/persistent-watcher-archetype/resources/roster-watch.sh +1140 -0
- package/assets/skills/persistent-watcher-archetype/resources/roster-watch_test.sh +291 -0
- package/assets/skills/persistent-watcher-archetype/resources/thrum-capture-fallback.sh +2 -2
- package/assets/skills/persistent-watcher-archetype/resources/thrum-watch-pane-capture.sh +20 -8
- package/assets/skills/prime-agent/SKILL.md +10 -0
- package/assets/skills/project-hotpath-gate/SKILL.md +1 -2
- package/assets/skills/project-philosophy/SKILL.md +1 -2
- package/assets/skills/project-rules-protocol/SKILL.md +12 -0
- package/assets/skills/project-setup/SKILL.md +27 -22
- package/assets/skills/project-setup/resources/implementation-agent.md +55 -35
- package/assets/skills/researcher-answering-queries/SKILL.md +1 -2
- package/assets/skills/researcher-investigating/SKILL.md +8 -13
- package/assets/skills/researcher-maintaining-memory/SKILL.md +1 -1
- package/assets/{commands/thrum-_snapshot-protocol.md → skills/snapshot-protocol/SKILL.md} +27 -21
- package/assets/{commands/thrum-_stamp-protocol.md → skills/stamp-protocol/SKILL.md} +14 -8
- package/assets/skills/thrum/SKILL.md +14 -7
- package/assets/skills/thrum/resources/ANTI_PATTERNS.md +16 -18
- package/assets/skills/thrum/resources/CLI_REFERENCE.md +17 -11
- package/assets/skills/thrum/resources/LISTENER_PATTERN.md +9 -3
- package/assets/skills/thrum/resources/MESSAGING.md +18 -11
- package/assets/skills/thrum/resources/WORKTREES.md +1 -1
- package/assets/skills/thrum-memory/SKILL.md +1 -1
- package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +1 -1
- package/assets/skills/update-queue/SKILL.md +6 -8
- package/assets/skills/using-the-dashboard/SKILL.md +30 -0
- package/assets/skills/using-the-queue/SKILL.md +76 -5
- package/assets/skills/using-thrum-state/SKILL.md +85 -2
- package/assets/skills/verify-against-plan/SKILL.md +122 -7
- package/assets/skills/watcher-archetype/SKILL.md +18 -0
- package/assets/skills/writing-durable-markdown/SKILL.md +5 -0
- package/dist/installer-assets.test.js +41 -0
- package/dist/installer.js +4 -4
- package/dist/permission-fixture.integration.test.js +4 -4
- package/package.json +1 -1
- package/assets/commands/thrum-_generator-idempotency-protocol.md +0 -15
- package/assets/commands/thrum-_project-rules-protocol.md +0 -18
- package/assets/commands/thrum-_verify-before-write-protocol.md +0 -27
- package/assets/skills/coordinator-deploying-the-fleet/SKILL.md +0 -396
- package/dist/allowlist-sync.test.js +0 -44
- /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
|
|
46
|
-
|
|
47
|
-
- Approve
|
|
48
|
-
|
|
49
|
-
`parent
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
|
250
|
-
|
|
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:
|
|
276
|
-
dual-daemon caller-identity collision;
|
|
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 —
|