@devo-bmad-custom/agent-orchestration 1.0.8 → 1.0.10
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
|
@@ -5,8 +5,9 @@ Verified, tested tmux command templates for agent orchestration. Every command i
|
|
|
5
5
|
**CRITICAL RULES:**
|
|
6
6
|
1. `sleep 10` before AND after every tmux command — no exceptions
|
|
7
7
|
2. Always append `Enter` to every `tmux send-keys` call
|
|
8
|
-
3.
|
|
9
|
-
4.
|
|
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
|
+
4. Verify pane exists before any operation targeting it
|
|
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.
|
|
10
11
|
|
|
11
12
|
---
|
|
12
13
|
|
|
@@ -55,31 +56,38 @@ ROLE="dev"
|
|
|
55
56
|
ROLE_COLOR=$(get_role_color "$ROLE")
|
|
56
57
|
SPAWNER_PANE=$(tmux display-message -p "#{pane_id}")
|
|
57
58
|
|
|
58
|
-
# 1. Split the pane
|
|
59
|
+
# 1. Split the pane — wait 15s for WSL bash + Claude to initialize before sending commands
|
|
59
60
|
sleep 10
|
|
60
61
|
tmux split-window -h -c "$PROJECT_ROOT" \
|
|
61
62
|
"claude --dangerously-skip-permissions 'You are the $ROLE agent. \
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
Your spawner pane is $SPAWNER_PANE. Session file: $SESSION_FILE. \
|
|
64
|
+
Always use -l flag for message content in tmux send-keys. \
|
|
64
65
|
Always sleep 10 before and after every tmux command. \
|
|
65
66
|
Always append Enter to every tmux send-keys call. \
|
|
66
67
|
Always verify pane exists before targeting it. \
|
|
67
68
|
$TASK_CONTEXT'"
|
|
68
|
-
sleep
|
|
69
|
+
sleep 15
|
|
69
70
|
|
|
70
71
|
# 2. Capture new pane ID
|
|
71
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
|
|
72
80
|
sleep 10
|
|
73
81
|
|
|
74
|
-
#
|
|
82
|
+
# 4. Disable OSC 2 auto-rename (we use /rename instead)
|
|
75
83
|
tmux set-option -t "$NEW_PANE_ID" -p allow-rename off
|
|
76
84
|
sleep 10
|
|
77
85
|
|
|
78
|
-
#
|
|
86
|
+
# 5. Set pane border title (visible in tmux, separate from /rename)
|
|
79
87
|
tmux select-pane -t "$NEW_PANE_ID" -T "${ROLE}-${NEW_PANE_ID}"
|
|
80
88
|
sleep 10
|
|
81
89
|
|
|
82
|
-
#
|
|
90
|
+
# 6. Rebalance layout with master awareness
|
|
83
91
|
tmux select-pane -t "$MASTER_PANE"
|
|
84
92
|
sleep 10
|
|
85
93
|
tmux select-layout main-vertical
|
|
@@ -103,9 +111,11 @@ if [ -z "$PANE_EXISTS" ]; then
|
|
|
103
111
|
exit 1
|
|
104
112
|
fi
|
|
105
113
|
|
|
106
|
-
# 2. Send the message (
|
|
114
|
+
# 2. Send the message — use -l (literal) to prevent | : and other chars being
|
|
115
|
+
# interpreted as tmux key sequences. ALWAYS append Enter separately.
|
|
107
116
|
sleep 10
|
|
108
|
-
tmux send-keys -t "$TARGET_PANE_ID" "$MESSAGE"
|
|
117
|
+
tmux send-keys -t "$TARGET_PANE_ID" -l "$MESSAGE"
|
|
118
|
+
tmux send-keys -t "$TARGET_PANE_ID" Enter
|
|
109
119
|
sleep 10
|
|
110
120
|
|
|
111
121
|
# 3. Verify delivery — grep for first 2 words of message in pane buffer
|
|
@@ -115,7 +125,8 @@ if [ -z "$DELIVERED" ]; then
|
|
|
115
125
|
# Retry once
|
|
116
126
|
echo "WARN: message not found in buffer, retrying..."
|
|
117
127
|
sleep 10
|
|
118
|
-
tmux send-keys -t "$TARGET_PANE_ID" "$MESSAGE"
|
|
128
|
+
tmux send-keys -t "$TARGET_PANE_ID" -l "$MESSAGE"
|
|
129
|
+
tmux send-keys -t "$TARGET_PANE_ID" Enter
|
|
119
130
|
sleep 10
|
|
120
131
|
fi
|
|
121
132
|
```
|
|
@@ -200,9 +211,11 @@ else
|
|
|
200
211
|
fi
|
|
201
212
|
```
|
|
202
213
|
|
|
203
|
-
### 6. `tmux_register_agent` — Agent startup: find session, register
|
|
214
|
+
### 6. `tmux_register_agent` — Agent startup: find session, register
|
|
215
|
+
|
|
216
|
+
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.
|
|
204
217
|
|
|
205
|
-
|
|
218
|
+
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.
|
|
206
219
|
|
|
207
220
|
```bash
|
|
208
221
|
# Inputs: ROLE, SESSION_FILE (passed in spawn context)
|
|
@@ -213,11 +226,6 @@ SESSION_NAME=$(tmux display-message -p "#{session_name}")
|
|
|
213
226
|
WINDOW_ID=$(tmux display-message -p "#{window_id}")
|
|
214
227
|
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")
|
|
215
228
|
|
|
216
|
-
# 2. Set own identity via Claude Code commands
|
|
217
|
-
# (These are sent as slash commands in the Claude conversation, not bash)
|
|
218
|
-
# /color <role_color>
|
|
219
|
-
# /rename <role>-agent
|
|
220
|
-
|
|
221
229
|
# 3. Find session file
|
|
222
230
|
if [ -n "$BMAD_SESSION_ID" ]; then
|
|
223
231
|
SESSION_FILE="$PROJECT_ROOT/_bmad-output/sessions/$BMAD_SESSION_ID/agent-sessions.md"
|
|
@@ -250,8 +258,10 @@ RESULT="pass"
|
|
|
250
258
|
SESSION_ID="<claude_session_id>"
|
|
251
259
|
|
|
252
260
|
sleep 10
|
|
253
|
-
|
|
254
|
-
|
|
261
|
+
# Use -l (literal) so | and : are not interpreted as tmux key sequences
|
|
262
|
+
tmux send-keys -t "$SPAWNER_PANE" -l \
|
|
263
|
+
"STEP COMPLETE: $TASK_ID | result: $RESULT | session: $SESSION_ID"
|
|
264
|
+
tmux send-keys -t "$SPAWNER_PANE" Enter
|
|
255
265
|
sleep 10
|
|
256
266
|
|
|
257
267
|
# 4. Check for more pending tasks for this role
|
|
@@ -336,18 +346,107 @@ tmux send-keys -t "$AGENT_PANE" "/color $NEW_COLOR" Enter
|
|
|
336
346
|
sleep 10
|
|
337
347
|
tmux send-keys -t "$AGENT_PANE" "/rename $NEW_ROLE-agent" Enter
|
|
338
348
|
sleep 10
|
|
339
|
-
tmux send-keys -t "$AGENT_PANE" "Handle TASK-003 from the session file"
|
|
349
|
+
tmux send-keys -t "$AGENT_PANE" -l "Handle TASK-003 from the session file"
|
|
350
|
+
tmux send-keys -t "$AGENT_PANE" Enter
|
|
340
351
|
sleep 10
|
|
341
352
|
```
|
|
342
353
|
|
|
343
354
|
---
|
|
344
355
|
|
|
356
|
+
## Verification & Retry Protocol
|
|
357
|
+
|
|
358
|
+
Every tmux operation must be verified after execution. Never assume a command worked.
|
|
359
|
+
|
|
360
|
+
### Verifying `/color` and `/rename` applied
|
|
361
|
+
|
|
362
|
+
After the spawner sends identity commands, verify the pane is alive and responsive:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# After sending /color and /rename, verify pane is still active (not crashed)
|
|
366
|
+
sleep 10
|
|
367
|
+
PANE_ALIVE=$(tmux list-panes -a -F "#{pane_id}" | grep -Fx "$NEW_PANE_ID")
|
|
368
|
+
if [ -z "$PANE_ALIVE" ]; then
|
|
369
|
+
echo "ERROR: agent pane $NEW_PANE_ID died after identity commands"
|
|
370
|
+
exit 1
|
|
371
|
+
fi
|
|
372
|
+
# Note: /color and /rename visual effects are immediate in Claude Code.
|
|
373
|
+
# If the pane is alive, the commands were received.
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Verifying message delivery
|
|
377
|
+
|
|
378
|
+
Always capture the pane buffer after sending a message and grep for the key token:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
tmux_verify_delivery() {
|
|
382
|
+
local PANE="$1"
|
|
383
|
+
local TOKEN="$2" # unique substring from the message
|
|
384
|
+
local RETRIES=3
|
|
385
|
+
|
|
386
|
+
for i in $(seq 1 $RETRIES); do
|
|
387
|
+
sleep 10
|
|
388
|
+
FOUND=$(tmux capture-pane -t "$PANE" -p -S - | grep -F "$TOKEN")
|
|
389
|
+
if [ -n "$FOUND" ]; then
|
|
390
|
+
echo "OK: message confirmed in pane $PANE (attempt $i)"
|
|
391
|
+
return 0
|
|
392
|
+
fi
|
|
393
|
+
if [ $i -lt $RETRIES ]; then
|
|
394
|
+
echo "WARN: '$TOKEN' not found in pane $PANE, retrying ($i/$RETRIES)..."
|
|
395
|
+
fi
|
|
396
|
+
done
|
|
397
|
+
|
|
398
|
+
echo "ERROR: message '$TOKEN' never confirmed in pane $PANE after $RETRIES attempts"
|
|
399
|
+
return 1
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
# Usage after sending a message:
|
|
403
|
+
tmux send-keys -t "$TARGET_PANE" -l "$MESSAGE"
|
|
404
|
+
tmux send-keys -t "$TARGET_PANE" Enter
|
|
405
|
+
tmux_verify_delivery "$TARGET_PANE" "TASK-001" # use a unique token from the message
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Verifying agent spawned and initialized
|
|
409
|
+
|
|
410
|
+
After splitting, confirm the pane exists and Claude has started (prompt visible):
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Wait for Claude prompt to appear in new pane (up to 30s)
|
|
414
|
+
READY=0
|
|
415
|
+
for i in 1 2 3; do
|
|
416
|
+
sleep 10
|
|
417
|
+
PROMPT=$(tmux capture-pane -t "$NEW_PANE_ID" -p -S - | grep -c "❯\|>\|Claude\|Human")
|
|
418
|
+
if [ "$PROMPT" -gt 0 ]; then
|
|
419
|
+
READY=1
|
|
420
|
+
break
|
|
421
|
+
fi
|
|
422
|
+
echo "Waiting for agent to initialize (attempt $i)..."
|
|
423
|
+
done
|
|
424
|
+
if [ "$READY" -eq 0 ]; then
|
|
425
|
+
echo "ERROR: agent pane $NEW_PANE_ID did not show prompt after 30s"
|
|
426
|
+
exit 1
|
|
427
|
+
fi
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Retry rules
|
|
431
|
+
|
|
432
|
+
| Operation | Verify by | Max retries | On failure |
|
|
433
|
+
|---|---|---|---|
|
|
434
|
+
| Message send | grep token in pane buffer | 3 | Log error, write to session file |
|
|
435
|
+
| `/color` / `/rename` | pane still alive | 1 | Re-send both commands |
|
|
436
|
+
| Pane spawn | pane ID in list + prompt visible | 3 | Kill and re-spawn |
|
|
437
|
+
| Layout rebalance | `tmux list-panes` shows expected count | 1 | Re-run `select-layout` |
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
345
441
|
## Common Mistakes (Avoid These)
|
|
346
442
|
|
|
347
443
|
1. **No `Enter` on send-keys** — message typed but never submitted
|
|
348
444
|
2. **No sleep between tmux commands** — race conditions, stale pane lists
|
|
349
|
-
3. **
|
|
350
|
-
4. **
|
|
351
|
-
5. **
|
|
352
|
-
6. **
|
|
353
|
-
7. **
|
|
445
|
+
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
|
|
446
|
+
4. **Using OSC 2 / `select-pane -T` for naming** — Claude Code overwrites these
|
|
447
|
+
5. **Killing pane without `/exit` first** — leaves partial writes, git locks
|
|
448
|
+
6. **Using `tiled` layout instead of `main-vertical`/`main-horizontal`** — breaks master position
|
|
449
|
+
7. **Reading pane titles for routing** — unreliable; use session file pane IDs
|
|
450
|
+
8. **Spawning without `--dangerously-skip-permissions`** — agent halts on every tool use
|
|
451
|
+
9. **No `-l` flag on message content** — `|` and `:` get interpreted as key sequences, message is garbled
|
|
452
|
+
10. **Agent self-invoking `/color`+`/rename`** — unreliable; spawner sends these via `tmux send-keys` after the agent starts
|