@devo-bmad-custom/agent-orchestration 1.0.9 → 1.0.11
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/package.json
CHANGED
|
@@ -7,7 +7,7 @@ Verified, tested tmux command templates for agent orchestration. Every command i
|
|
|
7
7
|
2. Always append `Enter` to every `tmux send-keys` call
|
|
8
8
|
3. **Use `-l` (literal) flag for all free-form message content** — prevents `|`, `:`, and other chars being interpreted as tmux key sequences. Send `Enter` as a separate call after. Do NOT use `-l` for slash commands (`/color`, `/rename`, `/exit`) — those must be interpreted.
|
|
9
9
|
4. Verify pane exists before any operation targeting it
|
|
10
|
-
5.
|
|
10
|
+
5. **`/color` and `/rename` are sent by the spawner** via separate `tmux send-keys` calls after the agent starts — never rely on the agent's prompt to self-invoke them. Each command is its own `send-keys` call with `Enter`, with `sleep 10` between.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -56,31 +56,38 @@ ROLE="dev"
|
|
|
56
56
|
ROLE_COLOR=$(get_role_color "$ROLE")
|
|
57
57
|
SPAWNER_PANE=$(tmux display-message -p "#{pane_id}")
|
|
58
58
|
|
|
59
|
-
# 1. Split the pane
|
|
59
|
+
# 1. Split the pane — wait 15s for WSL bash + Claude to initialize before sending commands
|
|
60
60
|
sleep 10
|
|
61
61
|
tmux split-window -h -c "$PROJECT_ROOT" \
|
|
62
62
|
"claude --dangerously-skip-permissions 'You are the $ROLE agent. \
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
Your spawner pane is $SPAWNER_PANE. Session file: $SESSION_FILE. \
|
|
64
|
+
Always use -l flag for message content in tmux send-keys. \
|
|
65
65
|
Always sleep 10 before and after every tmux command. \
|
|
66
66
|
Always append Enter to every tmux send-keys call. \
|
|
67
67
|
Always verify pane exists before targeting it. \
|
|
68
68
|
$TASK_CONTEXT'"
|
|
69
|
-
sleep
|
|
69
|
+
sleep 15
|
|
70
70
|
|
|
71
71
|
# 2. Capture new pane ID
|
|
72
72
|
NEW_PANE_ID=$(tmux list-panes -F "#{pane_id}" | tail -1)
|
|
73
|
+
|
|
74
|
+
# 3. Set agent identity — spawner sends /color and /rename as separate commands.
|
|
75
|
+
# Do NOT combine into one send-keys call; each must be submitted individually.
|
|
76
|
+
sleep 10
|
|
77
|
+
tmux send-keys -t "$NEW_PANE_ID" "/color $ROLE_COLOR" Enter
|
|
78
|
+
sleep 10
|
|
79
|
+
tmux send-keys -t "$NEW_PANE_ID" "/rename ${ROLE}-agent" Enter
|
|
73
80
|
sleep 10
|
|
74
81
|
|
|
75
|
-
#
|
|
82
|
+
# 4. Disable OSC 2 auto-rename (we use /rename instead)
|
|
76
83
|
tmux set-option -t "$NEW_PANE_ID" -p allow-rename off
|
|
77
84
|
sleep 10
|
|
78
85
|
|
|
79
|
-
#
|
|
86
|
+
# 5. Set pane border title (visible in tmux, separate from /rename)
|
|
80
87
|
tmux select-pane -t "$NEW_PANE_ID" -T "${ROLE}-${NEW_PANE_ID}"
|
|
81
88
|
sleep 10
|
|
82
89
|
|
|
83
|
-
#
|
|
90
|
+
# 6. Rebalance layout with master awareness
|
|
84
91
|
tmux select-pane -t "$MASTER_PANE"
|
|
85
92
|
sleep 10
|
|
86
93
|
tmux select-layout main-vertical
|
|
@@ -126,18 +133,25 @@ fi
|
|
|
126
133
|
|
|
127
134
|
### 3. `tmux_kill_agent` — Gracefully close an agent pane
|
|
128
135
|
|
|
136
|
+
**Trigger:** Coordinator sees a pane with status `ready-to-close` in the session file Pane Lifecycle table.
|
|
137
|
+
|
|
138
|
+
**Pre-conditions (verify all before killing):**
|
|
139
|
+
- [ ] Agent's report-back received (STEP COMPLETE message seen in this pane or session file updated)
|
|
140
|
+
- [ ] Task marked `done` in session file Tasks section
|
|
141
|
+
- [ ] Claude session ID saved to session file
|
|
142
|
+
|
|
129
143
|
```bash
|
|
130
|
-
# Inputs: TARGET_PANE_ID, MASTER_PANE,
|
|
144
|
+
# Inputs: TARGET_PANE_ID, MASTER_PANE, SESSION_FILE
|
|
131
145
|
TARGET_PANE_ID="%31"
|
|
132
146
|
MASTER_PANE="%0"
|
|
133
147
|
|
|
134
|
-
# 1. Verify pane exists
|
|
148
|
+
# 1. Verify pane exists
|
|
135
149
|
sleep 10
|
|
136
|
-
VERIFIED=$(tmux list-panes -a -F "#{pane_id}
|
|
137
|
-
| grep "^$TARGET_PANE_ID ")
|
|
150
|
+
VERIFIED=$(tmux list-panes -a -F "#{pane_id}" | grep -Fx "$TARGET_PANE_ID")
|
|
138
151
|
if [ -z "$VERIFIED" ]; then
|
|
139
|
-
echo "
|
|
140
|
-
exit
|
|
152
|
+
echo "WARN: pane $TARGET_PANE_ID already gone — marking closed in session file"
|
|
153
|
+
# Update session file status to closed and exit
|
|
154
|
+
exit 0
|
|
141
155
|
fi
|
|
142
156
|
|
|
143
157
|
# 2. Send /exit (lets Claude flush writes and exit cleanly)
|
|
@@ -145,17 +159,24 @@ sleep 10
|
|
|
145
159
|
tmux send-keys -t "$TARGET_PANE_ID" "/exit" Enter
|
|
146
160
|
sleep 10
|
|
147
161
|
|
|
148
|
-
# 3.
|
|
149
|
-
tmux
|
|
150
|
-
|
|
162
|
+
# 3. Verify pane closed on its own (Claude exits after /exit)
|
|
163
|
+
STILL_ALIVE=$(tmux list-panes -a -F "#{pane_id}" | grep -Fx "$TARGET_PANE_ID")
|
|
164
|
+
if [ -n "$STILL_ALIVE" ]; then
|
|
165
|
+
# Force kill if still up after /exit
|
|
166
|
+
tmux kill-pane -t "$TARGET_PANE_ID"
|
|
167
|
+
sleep 10
|
|
168
|
+
fi
|
|
151
169
|
|
|
152
|
-
# 4.
|
|
170
|
+
# 4. Update session file — mark pane as closed
|
|
171
|
+
# Edit Pane Lifecycle row: change status to `closed`, check off remaining boxes
|
|
172
|
+
|
|
173
|
+
# 5. Rebalance remaining panes
|
|
153
174
|
tmux select-pane -t "$MASTER_PANE"
|
|
154
175
|
sleep 10
|
|
155
176
|
tmux select-layout main-vertical
|
|
156
177
|
sleep 10
|
|
157
178
|
|
|
158
|
-
echo "
|
|
179
|
+
echo "Closed pane $TARGET_PANE_ID — session file updated, layout rebalanced"
|
|
159
180
|
```
|
|
160
181
|
|
|
161
182
|
### 4. `tmux_rebalance` — Equalize pane sizes with master awareness
|
|
@@ -204,9 +225,11 @@ else
|
|
|
204
225
|
fi
|
|
205
226
|
```
|
|
206
227
|
|
|
207
|
-
### 6. `tmux_register_agent` — Agent startup: find session, register
|
|
228
|
+
### 6. `tmux_register_agent` — Agent startup: find session, register
|
|
229
|
+
|
|
230
|
+
Spawned agents do NOT self-invoke `/color` or `/rename` — the spawner sends those via `tmux send-keys` before handing off the task. This template handles session registration only.
|
|
208
231
|
|
|
209
|
-
|
|
232
|
+
The master/coordinator conversation is the exception: it runs `/color blue` and `/rename master-agent` manually as its first two actions since there is no spawner above it.
|
|
210
233
|
|
|
211
234
|
```bash
|
|
212
235
|
# Inputs: ROLE, SESSION_FILE (passed in spawn context)
|
|
@@ -217,11 +240,6 @@ SESSION_NAME=$(tmux display-message -p "#{session_name}")
|
|
|
217
240
|
WINDOW_ID=$(tmux display-message -p "#{window_id}")
|
|
218
241
|
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")
|
|
219
242
|
|
|
220
|
-
# 2. Set own identity via Claude Code commands
|
|
221
|
-
# (These are sent as slash commands in the Claude conversation, not bash)
|
|
222
|
-
# /color <role_color>
|
|
223
|
-
# /rename <role>-agent
|
|
224
|
-
|
|
225
243
|
# 3. Find session file
|
|
226
244
|
if [ -n "$BMAD_SESSION_ID" ]; then
|
|
227
245
|
SESSION_FILE="$PROJECT_ROOT/_bmad-output/sessions/$BMAD_SESSION_ID/agent-sessions.md"
|
|
@@ -261,8 +279,13 @@ tmux send-keys -t "$SPAWNER_PANE" Enter
|
|
|
261
279
|
sleep 10
|
|
262
280
|
|
|
263
281
|
# 4. Check for more pending tasks for this role
|
|
264
|
-
# 5. If found: claim next task
|
|
265
|
-
# 6. If none:
|
|
282
|
+
# 5. If found: claim next task and continue
|
|
283
|
+
# 6. If none:
|
|
284
|
+
# a. Set status to `ready-to-close` in Pane Lifecycle table (NOT Active Agents)
|
|
285
|
+
# b. Check all close-down boxes in Pane Lifecycle row:
|
|
286
|
+
# ☑ report-back sent · ☑ session ID saved · ☑ task marked done · ☑ ready-to-close set
|
|
287
|
+
# c. The COORDINATOR is responsible for executing /exit + kill-pane.
|
|
288
|
+
# Do NOT self-exit unless you are the coordinator or explicitly told to.
|
|
266
289
|
```
|
|
267
290
|
|
|
268
291
|
---
|
|
@@ -349,12 +372,100 @@ sleep 10
|
|
|
349
372
|
|
|
350
373
|
---
|
|
351
374
|
|
|
375
|
+
## Verification & Retry Protocol
|
|
376
|
+
|
|
377
|
+
Every tmux operation must be verified after execution. Never assume a command worked.
|
|
378
|
+
|
|
379
|
+
### Verifying `/color` and `/rename` applied
|
|
380
|
+
|
|
381
|
+
After the spawner sends identity commands, verify the pane is alive and responsive:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
# After sending /color and /rename, verify pane is still active (not crashed)
|
|
385
|
+
sleep 10
|
|
386
|
+
PANE_ALIVE=$(tmux list-panes -a -F "#{pane_id}" | grep -Fx "$NEW_PANE_ID")
|
|
387
|
+
if [ -z "$PANE_ALIVE" ]; then
|
|
388
|
+
echo "ERROR: agent pane $NEW_PANE_ID died after identity commands"
|
|
389
|
+
exit 1
|
|
390
|
+
fi
|
|
391
|
+
# Note: /color and /rename visual effects are immediate in Claude Code.
|
|
392
|
+
# If the pane is alive, the commands were received.
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Verifying message delivery
|
|
396
|
+
|
|
397
|
+
Always capture the pane buffer after sending a message and grep for the key token:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
tmux_verify_delivery() {
|
|
401
|
+
local PANE="$1"
|
|
402
|
+
local TOKEN="$2" # unique substring from the message
|
|
403
|
+
local RETRIES=3
|
|
404
|
+
|
|
405
|
+
for i in $(seq 1 $RETRIES); do
|
|
406
|
+
sleep 10
|
|
407
|
+
FOUND=$(tmux capture-pane -t "$PANE" -p -S - | grep -F "$TOKEN")
|
|
408
|
+
if [ -n "$FOUND" ]; then
|
|
409
|
+
echo "OK: message confirmed in pane $PANE (attempt $i)"
|
|
410
|
+
return 0
|
|
411
|
+
fi
|
|
412
|
+
if [ $i -lt $RETRIES ]; then
|
|
413
|
+
echo "WARN: '$TOKEN' not found in pane $PANE, retrying ($i/$RETRIES)..."
|
|
414
|
+
fi
|
|
415
|
+
done
|
|
416
|
+
|
|
417
|
+
echo "ERROR: message '$TOKEN' never confirmed in pane $PANE after $RETRIES attempts"
|
|
418
|
+
return 1
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
# Usage after sending a message:
|
|
422
|
+
tmux send-keys -t "$TARGET_PANE" -l "$MESSAGE"
|
|
423
|
+
tmux send-keys -t "$TARGET_PANE" Enter
|
|
424
|
+
tmux_verify_delivery "$TARGET_PANE" "TASK-001" # use a unique token from the message
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Verifying agent spawned and initialized
|
|
428
|
+
|
|
429
|
+
After splitting, confirm the pane exists and Claude has started (prompt visible):
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
# Wait for Claude prompt to appear in new pane (up to 30s)
|
|
433
|
+
READY=0
|
|
434
|
+
for i in 1 2 3; do
|
|
435
|
+
sleep 10
|
|
436
|
+
PROMPT=$(tmux capture-pane -t "$NEW_PANE_ID" -p -S - | grep -c "❯\|>\|Claude\|Human")
|
|
437
|
+
if [ "$PROMPT" -gt 0 ]; then
|
|
438
|
+
READY=1
|
|
439
|
+
break
|
|
440
|
+
fi
|
|
441
|
+
echo "Waiting for agent to initialize (attempt $i)..."
|
|
442
|
+
done
|
|
443
|
+
if [ "$READY" -eq 0 ]; then
|
|
444
|
+
echo "ERROR: agent pane $NEW_PANE_ID did not show prompt after 30s"
|
|
445
|
+
exit 1
|
|
446
|
+
fi
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Retry rules
|
|
450
|
+
|
|
451
|
+
| Operation | Verify by | Max retries | On failure |
|
|
452
|
+
|---|---|---|---|
|
|
453
|
+
| Message send | grep token in pane buffer | 3 | Log error, write to session file |
|
|
454
|
+
| `/color` / `/rename` | pane still alive | 1 | Re-send both commands |
|
|
455
|
+
| Pane spawn | pane ID in list + prompt visible | 3 | Kill and re-spawn |
|
|
456
|
+
| Layout rebalance | `tmux list-panes` shows expected count | 1 | Re-run `select-layout` |
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
352
460
|
## Common Mistakes (Avoid These)
|
|
353
461
|
|
|
354
462
|
1. **No `Enter` on send-keys** — message typed but never submitted
|
|
355
463
|
2. **No sleep between tmux commands** — race conditions, stale pane lists
|
|
356
|
-
3. **
|
|
357
|
-
4. **
|
|
358
|
-
5. **
|
|
359
|
-
6. **
|
|
360
|
-
7. **
|
|
464
|
+
3. **Combining `/color` and `/rename` in one send-keys call** — only the first command runs; send each as a separate call with `sleep 10` between
|
|
465
|
+
4. **Using OSC 2 / `select-pane -T` for naming** — Claude Code overwrites these
|
|
466
|
+
5. **Killing pane without `/exit` first** — leaves partial writes, git locks
|
|
467
|
+
6. **Using `tiled` layout instead of `main-vertical`/`main-horizontal`** — breaks master position
|
|
468
|
+
7. **Reading pane titles for routing** — unreliable; use session file pane IDs
|
|
469
|
+
8. **Spawning without `--dangerously-skip-permissions`** — agent halts on every tool use
|
|
470
|
+
9. **No `-l` flag on message content** — `|` and `:` get interpreted as key sequences, message is garbled
|
|
471
|
+
10. **Agent self-invoking `/color`+`/rename`** — unreliable; spawner sends these via `tmux send-keys` after the agent starts
|