opencode-thrum-pro 0.1.11 → 0.1.13

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.
@@ -226,6 +226,11 @@ if [ "$SNAPSHOT_OK" = 1 ] && [ "$SESSION_OK" = 1 ]; then
226
226
  # all, so this is caught synchronously, not inferred later from silence.
227
227
  thrum tmux send "$AGENT" "/compact"
228
228
  SEND_RC=$?
229
+ # Exit 0 may print "ACCEPTED (non-turn command)": the runtime acknowledged the
230
+ # command without starting a model turn (for example compaction began). That is
231
+ # SUCCESS - continue to the next step exactly as for a plain exit 0.
232
+ # Exit 4 UNCONFIRMED means no acknowledgement was seen: inspect the pane before
233
+ # doing anything else.
229
234
  # Exit 3 = HELD, exit 4 = VERDICT UNKNOWN (thrum tmux send --help). In both
230
235
  # the "/compact" text is ALREADY TYPED into this pane and Enter was withheld
231
236
  # or unconfirmed. NEVER fall through to the raw retry below: it would append a
@@ -223,6 +223,11 @@ if [ "$SNAPSHOT_OK" = 1 ] && [ "$SESSION_OK" = 1 ]; then
223
223
  # turn regardless, so the delay costs nothing.
224
224
  thrum tmux send "$SESSION" "/compact"
225
225
  SEND_RC=$?
226
+ # Exit 0 may print "ACCEPTED (non-turn command)": the runtime acknowledged the
227
+ # command without starting a model turn (for example compaction began). That is
228
+ # SUCCESS - continue to the next step exactly as for a plain exit 0.
229
+ # Exit 4 UNCONFIRMED means no acknowledgement was seen: inspect the pane before
230
+ # doing anything else.
226
231
  # Exit 3 = HELD (Enter withheld), 4 = VERDICT UNKNOWN: "/compact" is already
227
232
  # typed in the pane. Do NOT retype it (that yields "/compact/compact"); report
228
233
  # and stop so a human/coordinator can inspect the pane.
@@ -127,7 +127,8 @@ rediscovering these the hard way:
127
127
  A bound-timeout with ZERO test failures is a FALSE RED, not a finding:
128
128
  distinguish it from a genuine hang/deadlock via
129
129
  `go run ./cmd/testgate classify-timeout --log <file> --shard-config <file>
130
- --shard <name>` (fails closed — only BOUND-TIMEOUT exits 0; HANG and
130
+ --shard <name> --pkg-dir <package dir>` (shard configs are hash-placed, so
131
+ `--pkg-dir` is required) (fails closed — only BOUND-TIMEOUT exits 0; HANG and
131
132
  UNCLASSIFIED both exit nonzero) before reporting it as a regression.
132
133
  If a gate's own command line invokes the bare package path for RPC, that is a gate defect, not a passing lane.
133
134
  A HANG or UNCLASSIFIED verdict from `classify-timeout` requires human review.
@@ -96,7 +96,7 @@ dispatch time — hand this list verbatim:
96
96
  `scripts/test-run.sh race ./internal/daemon/rpc`, or `make gate`) and confirm
97
97
  the gate's output shows it executed. A bound-timeout with ZERO test failures
98
98
  is a false red: classify it with `go run ./cmd/testgate classify-timeout
99
- --log <file> --shard-config <file> --shard <name>` (only BOUND-TIMEOUT exits
99
+ --log <file> --shard-config <file> --shard <name> --pkg-dir <package dir>` (only BOUND-TIMEOUT exits
100
100
  0) before reporting a regression. See item 7 of `coordinator-hotpath-merge-gate`.
101
101
  7. Build+test the MERGED-tree result as a SEPARATE condition — neither gate
102
102
  currently runs a build of the actual post-merge tree; a clean pre-merge
@@ -26,12 +26,28 @@ every agent in your `roster`:
26
26
  unreachable) is escalated to your `parent` every cycle until a coordinator
27
27
  or human removes it from your roster — never dropped, never silently
28
28
  given up on (see Escalation).
29
- 2. **Watch its context% and warn.** Read its ctx% from YOUR OWN tmux
30
- capture of its status bar — **never from a figure it claims about
31
- itself** (a message, a memory-footer line, anywhere). If it's getting
32
- close to the end and hasn't restarted, warn it. This is the exact
33
- mechanism — a watcher that trusts the target's self-report would catch
34
- none of them.
29
+ 2. **Watch context, warn, and compact only when exhausted.** Read ctx% from
30
+ YOUR OWN tmux capture of its status bar — **never from a figure it claims
31
+ about itself** (a message, a memory-footer line, anywhere). Reuse your
32
+ configured `restart_ctx_pct` as the target warning threshold (default
33
+ 50%); this does not change its separate use for your own self-restart.
34
+ At that threshold, warn the target if it has not restarted. Do not compact
35
+ at the threshold alone. Compact only when a fresh pane capture shows the
36
+ target is out of context AND two consecutive fresh checks show it at rest,
37
+ using the idle criteria in "Declared-intent reminders" below. Never
38
+ interrupt an active turn.
39
+
40
+ Get the target runtime from that member's `runtime` field in
41
+ `thrum team --json`; do not guess. Send its verified compact command (`/compact` for Claude,
42
+ Codex, and OpenCode; `/summarize` for Cursor; no command for runtimes
43
+ without a verified equivalent) with one `thrum tmux send <session>
44
+ "<command>"` call. That call settles and withholds Enter if a dialog
45
+ appears; never send a separate Enter. Exit 3 (Enter withheld) or 4
46
+ (verdict unknown) requires a fresh capture before any retry. If a
47
+ cross-peer send fails (for example, `can_send_keys` is unavailable),
48
+ escalate to your `parent` instead of retrying or switching transports.
49
+ Never resend while the command is queued or already visible in the pane.
50
+ After sending, report one line to your `parent`.
35
51
  3. **All of it is judgment.** Read pane, judge (unblock / warn-on-ctx /
36
52
  escalate), act or escalate. Every cycle, every roster member.
37
53
  4. **Catch declared-but-unexecuted intent.** If a roster member's last
@@ -60,7 +76,7 @@ every agent in your `roster`:
60
76
 
61
77
  ### Approving or dismissing a modal: keys only, never text
62
78
 
63
- > 🔴 **NEVER answer a modal with a text payload — not even a single
79
+ > 🔴 **For modal handling, NEVER answer with a text payload — not even a single
64
80
  > character, and never a bare positional argument to `thrum tmux send`.**
65
81
  > Plain text TYPES INTO the agent's input box; it does not act as a
66
82
  > keypress. If the modal isn't actually showing, or focus differs from what
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: using-monitors
3
- description: "Use when scheduling a reminder, watching a log, or running a periodic check that must reach an agent - thrum monitor start, cron --schedule, --match, --notify-on-success, --debounce, recurring nudge, script check with exit codes, why a monitor message did not arrive, how to verify a monitor delivered."
3
+ description: "Use when scheduling a reminder, watching a log, or running a periodic check that must reach an agent - thrum monitor start, cron --schedule, --match, --notify-on-success, --debounce, recurring nudge, plan follow-up reminder, remind me to check on my plan, check whether blockers have moved, prompt my pane on a schedule, monitor script that runs thrum tmux send, edit the script not the monitor, change a reminder without recreating the monitor, script check with exit codes, why a monitor message did not arrive, how to verify a monitor delivered."
4
4
  ---
5
5
 
6
- # Thrum Monitors - Reminders And Script Checks
6
+ # Thrum Monitors - Reminders, Pane Prompts And Script Checks
7
7
 
8
8
  ## Overview
9
9
 
@@ -14,6 +14,12 @@ kept line, a scheduled monitor sends all the lines of a run in one message. With
14
14
  and restarts with backoff when it exits. Monitors persist across daemon
15
15
  restarts and run only on the daemon that owns them.
16
16
 
17
+ A monitor reaches an agent in two ways. Its matched lines arrive as inbox
18
+ messages, read at the next inbox check. Its command can also be a script that
19
+ runs `thrum tmux send` to put a short prompt into the agent's own pane, which
20
+ starts a turn. Keep the wording and logic of anything that will change in a
21
+ script file: you then edit the script, and the monitor stays as it is.
22
+
17
23
  Every flag below appears in `thrum monitor start --help`. Re-read the help
18
24
  before relying on a flag not listed here.
19
25
 
@@ -37,6 +43,13 @@ thrum monitor delete <name|id>
37
43
  it (`--schedule ""`) switches the mode, which is refused while the monitor is
38
44
  running and allowed while it is stopped.
39
45
  - `--debounce` is leading-edge with a 30s minimum (default 1m).
46
+ - `update` changes only the match, target, debounce and schedule. The command,
47
+ its arguments, `--cwd` and `--env` are fixed when the monitor starts, so text
48
+ written inline in the command can be changed only by deleting the monitor and
49
+ starting a new one. Text kept in a script file is changed by editing the file.
50
+ - `--cwd` is the working directory the command runs in (default: the directory
51
+ you start the monitor from). `--env` adds one `KEY=VALUE` variable to the
52
+ command's environment and can be repeated.
40
53
  - `stop` leaves a stopped record that still holds the name; `delete` frees the
41
54
  name. Use a unique name per monitor.
42
55
 
@@ -45,6 +58,11 @@ thrum monitor delete <name|id>
45
58
  Each output line is tested against `--match` on its own. A line is truncated at
46
59
  2048 bytes with a marker appended.
47
60
 
61
+ Read generated summaries as `<name>@<host>` and system notices as
62
+ `[monitor:<name>@<host>]`; an unavailable hostname omits `@<host>`.
63
+ Matched summaries show up to 160 characters of the deciding line; read the full
64
+ matched output below, within the existing output and message limits.
65
+
48
66
  A scheduled (`--schedule`) job is a one-shot run, so its exit code is
49
67
  authoritative. It delivers ONE message at exit that carries every matched line,
50
68
  in order. A continuous job has no exit code per line, so it classifies and
@@ -52,11 +70,12 @@ delivers and classifies each matched line on its own, by its words.
52
70
 
53
71
  | Scheduled job | Delivered as |
54
72
  | --------------------------------------------------------------- | --------------------------------------------- |
55
- | Non-zero exit, or the command failed to start | `[FAIL] <name>: exit code N` with the output tail, then the matched lines |
56
- | Exit 0, a matched line starts `ERROR:`, `FATAL:` or `FAIL:` | `[FAIL] <name>: matched error pattern` + all matched lines |
57
- | Exit 0, highest prefix is `WARN:`, `WARNING:` or `ALERT:` | `[WARN] <name>: matched WARNING` + all matched lines |
73
+ | Non-zero exit | `[FAIL] <name>@<host>: exit code N` with the output tail, then the matched lines |
74
+ | Command failed to start | `[FAIL] <name>@<host>: <start error>` with details and an inspect command |
75
+ | Exit 0, a matched line starts `ERROR:`, `FATAL:` or `FAIL:` | `[FAIL] <name>@<host>: <matched line>` + all matched lines |
76
+ | Exit 0, highest prefix is `WARN:`, `WARNING:` or `ALERT:` | `[WARN] <name>@<host>: <matched line>` + all matched lines |
58
77
  | Exit 0, lines matched, no such prefix | All matched lines, in order, verbatim |
59
- | Exit 0, nothing matched, `--notify-on-success` | `[OK] <name>: succeeded` |
78
+ | Exit 0, nothing matched, `--notify-on-success` | `[OK] <name>@<host>: succeeded` |
60
79
  | Exit 0, nothing matched | Nothing (logged only) |
61
80
 
62
81
  Cadence: the first non-zero scheduled run sends its `[FAIL]` notice; repeats of
@@ -93,8 +112,8 @@ past the retained prefix still sets the label.
93
112
 
94
113
  | Continuous job (no `--schedule`) | Delivered as |
95
114
  | --------------------------------------------------------------- | --------------------------------------------- |
96
- | Contains `error`, `fatal`, `fail`, `permission denied` | `[FAIL] <name>: matched error pattern` + line |
97
- | Contains `warn` or `warning` | `[WARN] <name>: matched WARNING` + line |
115
+ | Contains `error`, `fatal`, `fail`, `permission denied` | `[FAIL] <name>@<host>: <matched line>` + line |
116
+ | Contains `warn` or `warning` | `[WARN] <name>@<host>: <matched line>` + line |
98
117
  | Contains a whole word `success`, `succeeded`, `complete`, `completed`, `done`, `ok` | Not delivered (logged only) |
99
118
  | Any other matched line | The line, verbatim |
100
119
 
@@ -111,10 +130,22 @@ Delivery limits:
111
130
  - The `[FAIL]` body for a non-zero exit carries only the last 500 bytes of
112
131
  output, so the message that matters goes last.
113
132
 
114
- ## Prompt-Only Reminder
133
+ ## Choosing A Reminder Form
134
+
135
+ | Need | Form |
136
+ | ----------------------------------------------------------------- | ----------------------------- |
137
+ | Fixed wording, enough that it is read at the next inbox check | Inbox reminder |
138
+ | Must start a turn, or the wording will change as the work moves | Pane prompt through a script |
139
+ | A probe that reports a finding only when something is wrong | Script check |
140
+
141
+ A reminder that arrives, in the inbox or in the pane, shows the schedule fired.
142
+ It does not show that the work moved. Check the work itself (commits, queue,
143
+ state) before treating the reminder as progress.
115
144
 
116
- A reminder is a monitor whose command only prints a fixed line. Give the line a
117
- stable prefix and match exactly that prefix.
145
+ ## Inbox Reminder
146
+
147
+ An inbox reminder is a monitor whose command only prints a fixed line. Give the
148
+ line a stable prefix and match exactly that prefix.
118
149
 
119
150
  ```bash
120
151
  thrum monitor start --name standup-nudge --to @me \
@@ -128,9 +159,94 @@ thrum monitor start --name standup-nudge --to @me \
128
159
  carries no action.
129
160
  - Add `--notify-on-success` only when a delivered line must be guaranteed for a
130
161
  run that matched nothing.
131
- - A delivered reminder shows the schedule fired. It does not show that the work
132
- moved. Check the work itself (commits, queue, state) before treating the
133
- reminder as progress.
162
+ - An inline `echo` suits wording that will not change. For wording that will
163
+ change, use a pane prompt through a script.
164
+
165
+ ## Pane Prompt Through A Script
166
+
167
+ Use this form for a recurring nudge that must start a turn, and for any reminder
168
+ whose wording follows the work. The standard case is plan follow-up: a
169
+ brainstormer or plan owner schedules a prompt that tells it to check how
170
+ implementation of its plan is going and to notify the coordinator or the
171
+ orchestrators working on the plan if blockers have not moved.
172
+
173
+ The monitor runs a script file. The script runs
174
+ `thrum tmux send <your-agent> "<prompt>"`: the daemon types the text into the
175
+ pane and submits it. The prompt text and all logic live in the script.
176
+
177
+ Put the script at a stable path you own, outside tracked source, that survives a
178
+ restart of your session. Use its absolute path in the monitor command.
179
+
180
+ ```bash
181
+ #!/usr/bin/env bash
182
+ # plan-nudge.sh: prompt my own pane to follow up on my plan.
183
+ # Edit AGENT and PROMPT when the plan moves. The monitor stays as it is.
184
+ AGENT="<your-agent>"
185
+ PROMPT="Check how implementation of <plan> is going. If the blockers have not moved since the last check, notify the coordinator or the orchestrators working on it."
186
+
187
+ timeout 30 thrum tmux send "$AGENT" "$PROMPT" >/dev/null 2>&1
188
+ rc=$?
189
+ case "$rc" in
190
+ 0) exit 0 ;;
191
+ 3 | 4)
192
+ echo "WARN: PLAN-NUDGE send exit $rc, the prompt was typed into $AGENT but its submit is not confirmed; look at the pane"
193
+ exit 0
194
+ ;;
195
+ *)
196
+ echo "PLAN-NUDGE: thrum tmux send to $AGENT failed with exit $rc"
197
+ exit "$rc"
198
+ ;;
199
+ esac
200
+ ```
201
+
202
+ ```bash
203
+ chmod +x <script-dir>/plan-nudge.sh
204
+ <script-dir>/plan-nudge.sh # run once by hand: the prompt lands, nothing prints
205
+
206
+ thrum monitor start --name plan-nudge-<your-agent> --to @<your-agent> \
207
+ --match 'PLAN-NUDGE' --schedule "0 */2 * * *" --cwd <your-worktree> -- \
208
+ <script-dir>/plan-nudge.sh
209
+ ```
210
+
211
+ Exit codes of a text `thrum tmux send`, from its help:
212
+
213
+ | Exit | Meaning | Script does |
214
+ | ----- | ----------------------------------------------------------------- | ------------------------------------ |
215
+ | 0 | Delivered | Prints nothing, exits 0 |
216
+ | 3 | Held: the text was typed, the confirming Enter was withheld | Prints a `WARN:` line, exits 0 |
217
+ | 4 | Verdict unknown: Enter may or may not have been sent | Prints a `WARN:` line, exits 0 |
218
+ | 1 | Any other error | Prints the finding, exits non-zero |
219
+
220
+ What the monitor then delivers to `--to`, per the scheduled-job table above:
221
+
222
+ | Script outcome | Target receives |
223
+ | -------------------------------------- | -------------------------------------------- |
224
+ | Prompt delivered | Nothing in the inbox; the prompt in the pane |
225
+ | Exit 3 or 4 | One `[WARN]` message for that tick |
226
+ | Any other non-zero exit, or the `timeout` (124) | One `[FAIL] <name>@<host>: exit code N` message with the finding line |
227
+
228
+ Rules:
229
+
230
+ 1. Keep the prompt to one or two sentences. It is a nudge; the plan and your
231
+ state hold the detail.
232
+ 2. When the plan moves (a blocker clears, a new one appears, a different
233
+ orchestrator owns the work), edit the script. The next tick uses the new
234
+ text. Do not run `thrum monitor update` and do not delete and recreate the
235
+ monitor for a change of wording or logic.
236
+ 3. Change the monitor only for what the monitor owns: `update --schedule` for a
237
+ new cadence, `update --to` for a new recipient of failure notices.
238
+ 4. Bound the send with `timeout`; a hung send holds the tick.
239
+ 5. Never call raw `tmux send-keys` from a monitor script. `thrum tmux send` is
240
+ the only way a script types into a pane.
241
+ 6. Target your own pane. Prompt another agent's pane only when that agent's
242
+ owner asked for it.
243
+ 7. Never send the text a second time from the script. After exit 3 or 4 the text
244
+ may already sit in the pane: look at the pane and submit or clear it. The
245
+ next tick sends again by itself.
246
+ 8. Keep the output quiet on success. A matching line on every tick fills the
247
+ inbox with the reminder the pane already received.
248
+ 9. Start the monitor with `--cwd` set to your own worktree, so the send runs
249
+ from the checkout that carries your identity.
134
250
 
135
251
  ## Script Check
136
252
 
@@ -146,6 +262,10 @@ thrum monitor start --name disk-check --to @me \
146
262
  exit 3'
147
263
  ```
148
264
 
265
+ Inline `bash -c` suits a short probe whose text and threshold are fixed. Put a
266
+ probe whose logic, threshold or wording will change in a script file and give
267
+ the monitor the file's path, as in the pane prompt example.
268
+
149
269
  Rules:
150
270
 
151
271
  1. Bound every probe with `timeout <secs>`; a hung probe holds the tick.
@@ -161,7 +281,7 @@ Rules:
161
281
  | Outcome | Script does | Target receives |
162
282
  | -------- | ---------------------------------------- | ---------------------------------- |
163
283
  | Quiet | Exit 0, no matching line | Nothing |
164
- | Failure | Non-zero exit, finding line last | One `[FAIL] <name>: exit code N` message with the tail and the finding line |
284
+ | Failure | Non-zero exit, finding line last | One `[FAIL] <name>@<host>: exit code N` message with the tail and the finding line |
165
285
  | Finding | Exit 0, matching line(s) | The line(s), verbatim (labeled only by an `ERROR:`/`FATAL:`/`FAIL:` or `WARN:`/`WARNING:`/`ALERT:` prefix) |
166
286
  | Reminder | Exit 0, one stable-prefix instruction | The line, verbatim |
167
287
 
@@ -186,6 +306,10 @@ Confirm the body carries the prefix, the wording and no unexpected `[FAIL]`
186
306
  or `[WARN]` label. Delete the monitor when done; never alter a monitor another
187
307
  agent owns.
188
308
 
309
+ A pane prompt sends nothing to the inbox when it works. Verify it by running
310
+ the script once by hand and seeing the prompt in the pane, then by `thrum
311
+ monitor show` reporting exit 0 after the first tick.
312
+
189
313
  ## Troubleshooting
190
314
 
191
315
  - Nothing arrived: `thrum monitor show` for state and last exit, `thrum
@@ -196,3 +320,12 @@ agent owns.
196
320
  with `ERROR:`/`FATAL:`/`FAIL:`, or (continuous job) the line contains a fail or
197
321
  error substring.
198
322
  - Name already in use: a stopped record holds it. `thrum monitor delete` it.
323
+ - Pane prompt did not appear: `thrum monitor show` for the last exit, then run
324
+ the script by hand. Check that the script path is absolute and executable,
325
+ that the agent name in the script is current, and that the monitor's
326
+ `--cwd` is your worktree.
327
+ - Pane prompt shows the old wording: the script was not saved, or the monitor
328
+ was started with a different script path than the one you edited.
329
+ - `[WARN]` naming a held or unknown send: the text may sit unsubmitted in the
330
+ pane. Look at the pane and submit or clear the text. Do not send the text
331
+ again by hand; the next tick sends it.
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: using-tmux-ssh
3
+ description: "Use when about to ssh to a host, run a command on a VM or remote box, start a long test or build on another machine, inspect a remote log, or recover after an ssh connection dropped or a remote command timed out. Use tmux-ssh for remote commands, saved-watch resume, and concurrent observation."
4
+ ---
5
+
6
+ # Running Remote Commands With tmux-ssh
7
+
8
+ `tmux-ssh` drives one persistent SSH login per host in a local tmux pane.
9
+ Use it for every command on another machine or VM, short or long, including
10
+ remote tests, builds, and log reads. Use `--read` and `--status` to observe;
11
+ never use plain SSH polling or Monitor loops.
12
+
13
+ ## Where the script is
14
+
15
+ From a Thrum source checkout, run `scripts/tmux-ssh` from the repository root
16
+ and read `scripts/tmux-ssh --help` for current flags. Read the design doc at
17
+ `dev-docs/proxmox/32-tmux-ssh-design.md`. If no source checkout is present, ask
18
+ the coordinator for its path rather than guessing.
19
+
20
+ ## Usage
21
+
22
+ The examples below use `tmux-ssh` for the resolved executable. `HOST` is an
23
+ SSH config alias or `user@host`.
24
+
25
+ ```bash
26
+ tmux-ssh HOST # connect if needed; print status
27
+ tmux-ssh HOST 'uname -a' # finite command; return its exit code
28
+ tmux-ssh HOST --timeout 900 'make test' # bounded observation, in seconds
29
+ tmux-ssh HOST --resume --timeout 900 # continue the saved watch; never resend
30
+ tmux-ssh HOST --status # session and recorded state
31
+ tmux-ssh HOST --read --settle # screen; usable during another call
32
+ tmux-ssh HOST --abort # deliberately interrupt and clear the watch
33
+ tmux-ssh HOST --kill # close SSH and clear saved state
34
+
35
+ tmux-ssh HOST --send 'top' # interactive program
36
+ tmux-ssh HOST --read
37
+ tmux-ssh HOST --send --key C-c
38
+
39
+ tmux-ssh HOST "tmux new -d -s JOB 'long-command >job.log 2>&1'"
40
+ ```
41
+
42
+ Run mode waits for a command that ends. For editors, REPLs, attached tmux,
43
+ and other programs that stay open, use `--send`/`--read`. Run mode refuses
44
+ obvious interactive commands with code 2; use `--force-run` only deliberately.
45
+ `--send` types into the current program and refuses a dead session rather
46
+ than reconnecting and losing interactive state.
47
+
48
+ Quote remote commands locally so variables expand on the intended machine.
49
+ They execute in the remote login shell, which may be zsh; invoke `bash` for
50
+ Bash syntax. For long or complex content, transfer a script using `scp` or
51
+ `rsync` with the same connection options, then run a short command through
52
+ `tmux-ssh`. The wrapper transports commands, not files.
53
+
54
+ ## Rules
55
+
56
+ - **One command per host session.** Mutating calls share a local per-host lock
57
+ and wait up to 30 seconds by default. `--read` and `--status` observe without
58
+ that lock. Coordinate drivers across machines or different `TMUX_SSH_DIR`
59
+ values; these do not provide a global lock.
60
+ - **Resume observation, never resubmit a queued or visible command.** Code 124
61
+ ends the wait; the command may still be running or waiting for input. Use
62
+ `--read`, then `--resume`, which retains the watch and never sends the command
63
+ again. Resume reuses the original timeout unless overridden. Other run calls
64
+ refuse while a watch remains.
65
+ - **Interrupt deliberately.** `--interrupt-on-timeout` sends Ctrl-C when the
66
+ wait expires. `--abort` sends Ctrl-C and clears the watch; code 0 reports a
67
+ ready/finished/gone session, code 1 means the shell did not answer. Inspect
68
+ `--read` before further input. An abort receipt does not prove job success.
69
+ - **Give long jobs an independent remote lifecycle.** Use detached remote
70
+ tmux, retaining the job name and logs. An ordinary call can reconnect a dead
71
+ SSH session, but a drop during foreground execution leaves completion unknown
72
+ and may terminate that command. Check the job and its results before deciding
73
+ to retry. `--kill` closes SSH; it does not stop an independent remote job.
74
+ - **Interpret the diagnostic and completion evidence.** Remote command exit
75
+ codes are passed through and can overlap wrapper codes. Wrapper code 124 is
76
+ a wait timeout; 125 is refusal or 'completion unknown', so it alone cannot
77
+ prove nothing ran; 2 is a usage error; 3 means input state UNKNOWN after a
78
+ failed keystroke, dropped send, or failed watch persistence. Code 3 guards
79
+ later typing until `--kill`; `--read`, `--status`, and `--resume` still work.
80
+ Do not blindly retry unknown completion or input, or kill another driver's
81
+ session or lock merely because it looks stuck.
82
+
83
+ ## Connection options and pool leases
84
+
85
+ Obtain the key, known-hosts file, target address, and actual remote OS hostname
86
+ from the current lease. Keep these values outside the skill.
87
+
88
+ ```bash
89
+ TMUX_SSH_OPTS='-i /path/to/lease-key -o IdentitiesOnly=yes -o UserKnownHostsFile=/path/to/lease-known-hosts -o StrictHostKeyChecking=yes' \
90
+ TMUX_SSH_EXPECT_HOST='<remote-os-hostname>' \
91
+ tmux-ssh user@<lease-address> 'uname -a'
92
+ ```
93
+
94
+ Options precede built-in defaults, so SSH's first `-o` wins. Allowed characters
95
+ are letters, digits, spaces, and `- _ . / = : , @ ~ + %`; paths cannot contain
96
+ spaces. A live session retains its original options: deliberately close it
97
+ with `--kill` before changing them. `--help`, `--status`, and `--kill` work
98
+ with invalid options. `--expect-host` overrides `TMUX_SSH_EXPECT_HOST` and
99
+ matches short/FQDN hostname forms case-insensitively; the SSH alias need not
100
+ match the OS hostname.
101
+
102
+ ## Execution identity checks
103
+
104
+ SSH is the pane's own process; a dropped connection leaves a dead pane, not a
105
+ local shell. Run mode checks a live SSH pane, probes the recorded hostname,
106
+ and wraps execution with a hostname check. Interactive input checks the live
107
+ SSH pane because a program may own stdin. These checks catch mistaken targets;
108
+ they are not an adversarial security boundary. Remote targets reporting the
109
+ local hostname are refused; explicit `localhost`/`127.0.0.1` aliases permit
110
+ intentional local use.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-thrum-pro",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Thrum multi-agent coordination plugin for Open Code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",