beeops 0.1.0

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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +156 -0
  3. package/README.md +80 -0
  4. package/bin/beeops.js +502 -0
  5. package/command/bo.md +120 -0
  6. package/contexts/agent-modes.json +100 -0
  7. package/contexts/code-reviewer.md +118 -0
  8. package/contexts/coder.md +247 -0
  9. package/contexts/default.md +1 -0
  10. package/contexts/en/agent-modes.json +100 -0
  11. package/contexts/en/code-reviewer.md +129 -0
  12. package/contexts/en/coder.md +247 -0
  13. package/contexts/en/default.md +1 -0
  14. package/contexts/en/fb.md +15 -0
  15. package/contexts/en/leader.md +158 -0
  16. package/contexts/en/log.md +16 -0
  17. package/contexts/en/queen.md +240 -0
  18. package/contexts/en/review-leader.md +190 -0
  19. package/contexts/en/reviewer-base.md +27 -0
  20. package/contexts/en/security-reviewer.md +200 -0
  21. package/contexts/en/test-auditor.md +146 -0
  22. package/contexts/en/tester.md +135 -0
  23. package/contexts/en/worker-base.md +69 -0
  24. package/contexts/fb.md +15 -0
  25. package/contexts/ja/agent-modes.json +100 -0
  26. package/contexts/ja/code-reviewer.md +129 -0
  27. package/contexts/ja/coder.md +247 -0
  28. package/contexts/ja/default.md +1 -0
  29. package/contexts/ja/fb.md +15 -0
  30. package/contexts/ja/leader.md +158 -0
  31. package/contexts/ja/log.md +17 -0
  32. package/contexts/ja/queen.md +240 -0
  33. package/contexts/ja/review-leader.md +190 -0
  34. package/contexts/ja/reviewer-base.md +27 -0
  35. package/contexts/ja/security-reviewer.md +200 -0
  36. package/contexts/ja/test-auditor.md +146 -0
  37. package/contexts/ja/tester.md +135 -0
  38. package/contexts/ja/worker-base.md +68 -0
  39. package/contexts/leader.md +158 -0
  40. package/contexts/log.md +16 -0
  41. package/contexts/queen.md +240 -0
  42. package/contexts/review-leader.md +190 -0
  43. package/contexts/reviewer-base.md +27 -0
  44. package/contexts/security-reviewer.md +200 -0
  45. package/contexts/test-auditor.md +146 -0
  46. package/contexts/tester.md +135 -0
  47. package/contexts/worker-base.md +69 -0
  48. package/hooks/checkpoint.py +89 -0
  49. package/hooks/prompt-context.py +139 -0
  50. package/hooks/resolve-log-path.py +93 -0
  51. package/hooks/run-log.py +429 -0
  52. package/package.json +42 -0
  53. package/scripts/launch-leader.sh +282 -0
  54. package/scripts/launch-worker.sh +184 -0
  55. package/skills/bo-dispatch/SKILL.md +299 -0
  56. package/skills/bo-issue-sync/SKILL.md +103 -0
  57. package/skills/bo-leader-dispatch/SKILL.md +211 -0
  58. package/skills/bo-log-writer/SKILL.md +101 -0
  59. package/skills/bo-review-backend/SKILL.md +234 -0
  60. package/skills/bo-review-database/SKILL.md +243 -0
  61. package/skills/bo-review-frontend/SKILL.md +236 -0
  62. package/skills/bo-review-operations/SKILL.md +268 -0
  63. package/skills/bo-review-process/SKILL.md +181 -0
  64. package/skills/bo-review-security/SKILL.md +214 -0
  65. package/skills/bo-review-security/references/finance-security.md +351 -0
  66. package/skills/bo-self-improver/SKILL.md +145 -0
  67. package/skills/bo-self-improver/refs/agent-manager.md +61 -0
  68. package/skills/bo-self-improver/refs/command-manager.md +46 -0
  69. package/skills/bo-self-improver/refs/skill-manager.md +59 -0
  70. package/skills/bo-self-improver/scripts/analyze.py +359 -0
  71. package/skills/bo-task-decomposer/SKILL.md +130 -0
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "beeops",
3
+ "version": "0.1.0",
4
+ "description": "3-layer multi-agent orchestration system (Queen โ†’ Leader โ†’ Worker) powered by tmux",
5
+ "author": "YuugouOhno",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/YuugouOhno/beeops.git"
10
+ },
11
+ "homepage": "https://github.com/YuugouOhno/beeops#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/YuugouOhno/beeops/issues"
14
+ },
15
+ "bin": {
16
+ "beeops": "./bin/beeops.js"
17
+ },
18
+ "files": [
19
+ "bin/",
20
+ "scripts/",
21
+ "hooks/",
22
+ "contexts/",
23
+ "skills/",
24
+ "command/"
25
+ ],
26
+ "keywords": [
27
+ "multi-agent",
28
+ "orchestration",
29
+ "tmux",
30
+ "automation",
31
+ "ai-agents",
32
+ "beeops",
33
+ "claude-code"
34
+ ],
35
+ "scripts": {
36
+ "test": "node --test test/cli.test.js",
37
+ "prepublishOnly": "npm test"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ }
42
+ }
@@ -0,0 +1,282 @@
1
+ #!/bin/bash
2
+ # launch-leader.sh - Launch Leader or Review Leader in a tmux window (with git worktree isolation)
3
+ # Usage: launch-leader.sh <role> <issue> <branch> [fix]
4
+ #
5
+ # Part of beeops: 3-layer multi-agent system (Queen โ†’ Leader โ†’ Worker)
6
+ #
7
+ # Features:
8
+ # - tmux new-window: each issue gets its own window (not pane)
9
+ # - Git worktree isolation: impl leader gets isolated copy of the repo
10
+ # - Review leader works on main repo (read-only)
11
+ # - FIX_MODE: reuse existing worktree/branch when called with 'fix'
12
+
13
+ set -euo pipefail
14
+
15
+ ROLE="$1"
16
+ ISSUE="$2"
17
+ BRANCH="$3"
18
+ FIX_MODE="${4:-}"
19
+ SESSION="bo"
20
+ REPO_DIR="$(git rev-parse --show-toplevel)"
21
+ REPORTS_DIR="$REPO_DIR/.claude/tasks/reports"
22
+ PROMPTS_DIR="$REPO_DIR/.claude/tasks/prompts"
23
+ WORKTREES_DIR="$REPO_DIR/.claude/worktrees"
24
+
25
+ mkdir -p "$REPORTS_DIR/processed" "$PROMPTS_DIR" "$WORKTREES_DIR"
26
+
27
+ # โ”€โ”€ Role configuration โ”€โ”€
28
+ case "$ROLE" in
29
+ leader)
30
+ ROLE_SHORT="leader"
31
+ ENV_VAR="BO_LEADER"
32
+ WINDOW_NAME="issue-${ISSUE}"
33
+ BORDER_FG="blue"
34
+ ROLE_ICON="๐Ÿ‘‘"
35
+ MAX_TURNS=80
36
+ ALLOWED_TOOLS="Read,Write,Edit,Bash,Glob,Grep,Skill"
37
+ ;;
38
+ review-leader)
39
+ ROLE_SHORT="review-leader"
40
+ ENV_VAR="BO_REVIEW_LEADER"
41
+ WINDOW_NAME="review-${ISSUE}"
42
+ BORDER_FG="magenta"
43
+ ROLE_ICON="๐Ÿ”ฎ"
44
+ MAX_TURNS=40
45
+ ALLOWED_TOOLS="Read,Grep,Glob,Bash,Skill"
46
+ ;;
47
+ *)
48
+ echo "Unknown role: $ROLE (expected: leader | review-leader)" >&2
49
+ exit 1
50
+ ;;
51
+ esac
52
+
53
+ PANE_TITLE="${ROLE_ICON} ${ROLE_SHORT}-${ISSUE}"
54
+
55
+ # โ”€โ”€ Worktree setup (leader only, review-leader uses main repo) โ”€โ”€
56
+ WORK_DIR="$REPO_DIR"
57
+ WORKTREE_PATH=""
58
+
59
+ if [ "$ROLE" = "leader" ]; then
60
+ WORKTREE_PATH="$WORKTREES_DIR/$BRANCH"
61
+
62
+ if [ "$FIX_MODE" = "fix" ] && [ -d "$WORKTREE_PATH" ]; then
63
+ # FIX_MODE: reuse existing worktree
64
+ WORK_DIR="$WORKTREE_PATH"
65
+ else
66
+ # Clean up stale worktree if exists
67
+ if [ -d "$WORKTREE_PATH" ]; then
68
+ git -C "$REPO_DIR" worktree remove "$WORKTREE_PATH" --force 2>/dev/null || true
69
+ fi
70
+ # Create fresh worktree with new branch from main
71
+ git -C "$REPO_DIR" worktree add "$WORKTREE_PATH" -b "$BRANCH" main 2>/dev/null || \
72
+ git -C "$REPO_DIR" worktree add "$WORKTREE_PATH" "$BRANCH" 2>/dev/null || {
73
+ git -C "$REPO_DIR" branch -D "$BRANCH" 2>/dev/null || true
74
+ git -C "$REPO_DIR" worktree add "$WORKTREE_PATH" -b "$BRANCH" main
75
+ }
76
+ WORK_DIR="$WORKTREE_PATH"
77
+ # Symlink node_modules and other untracked but required dirs
78
+ ln -sfn "$REPO_DIR/node_modules" "$WORKTREE_PATH/node_modules" 2>/dev/null || true
79
+ ln -sfn "$REPO_DIR/.next" "$WORKTREE_PATH/.next" 2>/dev/null || true
80
+ # Ensure reports/prompts dirs are accessible from worktree
81
+ mkdir -p "$WORKTREE_PATH/.claude/tasks"
82
+ ln -sfn "$REPORTS_DIR" "$WORKTREE_PATH/.claude/tasks/reports"
83
+ ln -sfn "$PROMPTS_DIR" "$WORKTREE_PATH/.claude/tasks/prompts"
84
+ fi
85
+ fi
86
+
87
+ # โ”€โ”€ Write prompt file โ”€โ”€
88
+ PROMPT_FILE="$PROMPTS_DIR/${ROLE_SHORT}-${ISSUE}.md"
89
+
90
+ # Use fix prompt if it exists (written by Queen)
91
+ FIX_PROMPT="$PROMPTS_DIR/fix-${ROLE_SHORT}-${ISSUE}.md"
92
+ if [ "$FIX_MODE" = "fix" ] && [ -f "$FIX_PROMPT" ]; then
93
+ cp "$FIX_PROMPT" "$PROMPT_FILE"
94
+ rm "$FIX_PROMPT"
95
+ else
96
+ case "$ROLE" in
97
+ leader)
98
+ cat > "$PROMPT_FILE" <<PROMPT_EOF
99
+ You are a Leader agent (beeops L2).
100
+ You are responsible for completing the implementation of GitHub Issue #${ISSUE}.
101
+
102
+ ## Work Environment
103
+ - Working directory: ${WORK_DIR}
104
+ - Branch '${BRANCH}' is already checked out (git worktree)
105
+ - Report output directory: ${REPORTS_DIR}
106
+ - Prompt output directory: ${PROMPTS_DIR}
107
+ - Issue number: ${ISSUE}
108
+
109
+ ## Procedure
110
+ 1. Review the issue: gh issue view ${ISSUE} --json body,title,labels
111
+ 2. Skill: bo-task-decomposer to decompose into subtasks
112
+ 3. Skill: bo-leader-dispatch to launch Workers in parallel
113
+ 4. Evaluate Worker reports for quality (re-run up to 2 times if unsatisfactory)
114
+ 5. After all subtasks are complete, perform a self-critical review (read the PR diff and verify alignment with Issue requirements)
115
+ 6. Write ${REPORTS_DIR}/leader-${ISSUE}-summary.yaml
116
+ 7. Send tmux wait-for -S queen-wake
117
+
118
+ ## Report Format (leader-${ISSUE}-summary.yaml)
119
+ \`\`\`yaml
120
+ issue: ${ISSUE}
121
+ role: leader
122
+ status: completed # completed | failed
123
+ branch: ${BRANCH}
124
+ pr: "PR URL"
125
+ summary: "High-level overview of the implementation"
126
+ subtasks_completed: 3
127
+ subtasks_total: 3
128
+ concerns: null # Note any concerns if applicable
129
+ key_changes:
130
+ - file: "file path"
131
+ what: "description of change"
132
+ design_decisions:
133
+ - decision: "what was chosen"
134
+ reason: "why"
135
+ \`\`\`
136
+
137
+ ## Critical Rules
138
+ - Never ask the user questions. Make all decisions yourself
139
+ - Delegate work to Workers. Do not write code yourself
140
+ - Have the final worker-coder create the PR
141
+ - Handle errors on your own
142
+ PROMPT_EOF
143
+ ;;
144
+
145
+ review-leader)
146
+ cat > "$PROMPT_FILE" <<PROMPT_EOF
147
+ You are a Review Leader agent (beeops L2).
148
+ You are responsible for reviewing the PR for Issue #${ISSUE}.
149
+
150
+ ## Work Environment
151
+ - Working directory: ${WORK_DIR}
152
+ - Branch: ${BRANCH}
153
+ - Report output directory: ${REPORTS_DIR}
154
+ - Prompt output directory: ${PROMPTS_DIR}
155
+ - Issue number: ${ISSUE}
156
+
157
+ ## Procedure
158
+ 1. Review the PR diff: gh pr diff --name-only && gh pr diff
159
+ 2. Determine complexity (simple/standard/complex)
160
+ 3. Skill: bo-leader-dispatch to launch Review Workers in parallel
161
+ 4. Aggregate Worker findings + perform anti-sycophancy check
162
+ 5. Write ${REPORTS_DIR}/review-leader-${ISSUE}-verdict.yaml
163
+ 6. Send tmux wait-for -S queen-wake
164
+
165
+ ## Complexity Rules
166
+ | Complexity | Criteria | Workers to Launch |
167
+ |------------|----------|-------------------|
168
+ | simple | Changed files <= 2 and all are config/docs | worker-code-reviewer only |
169
+ | complex | Changed files >= 5, includes auth/migration | worker-code-reviewer + worker-security + worker-test-auditor |
170
+ | standard | Everything else | worker-code-reviewer + worker-security |
171
+
172
+ ## Report Format (review-leader-${ISSUE}-verdict.yaml)
173
+ \`\`\`yaml
174
+ issue: ${ISSUE}
175
+ role: review-leader
176
+ complexity: standard
177
+ council_members: [worker-code-reviewer, worker-security]
178
+ final_verdict: approve # approve | fix_required
179
+ anti_sycophancy_triggered: false
180
+ merged_findings:
181
+ - source: worker-security
182
+ severity: high
183
+ file: "file path"
184
+ line: line number
185
+ message: "description of finding"
186
+ fix_instructions: null # Only populate when fix_required
187
+ \`\`\`
188
+
189
+ ## Critical Rules
190
+ - Never ask the user questions. Make all decisions yourself
191
+ - Delegate reviews to Review Workers. Do not read code yourself (only grasp the diff overview)
192
+ - Only mark fix_required for critical issues
193
+ PROMPT_EOF
194
+ ;;
195
+ esac
196
+ fi # end of fix prompt check
197
+
198
+ # โ”€โ”€ Wrapper script (runs inside tmux pane) โ”€โ”€
199
+ WRAPPER="/tmp/agent-wrapper-${ROLE_SHORT}-${ISSUE}.sh"
200
+ cat > "$WRAPPER" <<'WRAPPER_HEADER'
201
+ #!/bin/bash
202
+ set -uo pipefail
203
+ WRAPPER_HEADER
204
+
205
+ cat >> "$WRAPPER" <<WRAPPER_BODY
206
+ WORK_DIR="${WORK_DIR}"
207
+ REPO_DIR="${REPO_DIR}"
208
+ REPORTS_DIR="${REPORTS_DIR}"
209
+ PROMPT_FILE="${PROMPT_FILE}"
210
+ ROLE="${ROLE}"
211
+ ROLE_SHORT="${ROLE_SHORT}"
212
+ ENV_VAR="${ENV_VAR}"
213
+ ISSUE="${ISSUE}"
214
+ BRANCH="${BRANCH}"
215
+ WORKTREE_PATH="${WORKTREE_PATH}"
216
+ MAX_TURNS="${MAX_TURNS}"
217
+ ALLOWED_TOOLS="${ALLOWED_TOOLS}"
218
+ BO_SCRIPTS_DIR="${BO_SCRIPTS_DIR:-}"
219
+ BO_CONTEXTS_DIR="${BO_CONTEXTS_DIR:-}"
220
+
221
+ cd "\$WORK_DIR"
222
+
223
+ # Run agent
224
+ unset CLAUDECODE
225
+ env \${ENV_VAR}=1 \
226
+ BO_SCRIPTS_DIR="\$BO_SCRIPTS_DIR" \
227
+ BO_CONTEXTS_DIR="\$BO_CONTEXTS_DIR" \
228
+ claude --dangerously-skip-permissions \
229
+ --allowedTools "\$ALLOWED_TOOLS" \
230
+ --max-turns \$MAX_TURNS \
231
+ "\$(cat "\$PROMPT_FILE")"
232
+ EXIT_CODE=\$?
233
+
234
+ # Write basic report
235
+ TIMESTAMP=\$(date -u +%Y-%m-%dT%H:%M:%SZ)
236
+ STATUS=\$([ \$EXIT_CODE -eq 0 ] && echo completed || echo failed)
237
+
238
+ cat > "\$REPORTS_DIR/\${ROLE_SHORT}-\${ISSUE}.yaml" <<REPORT
239
+ issue: \$ISSUE
240
+ role: \$ROLE
241
+ status: \$STATUS
242
+ exit_code: \$EXIT_CODE
243
+ branch: \$BRANCH
244
+ timestamp: \$TIMESTAMP
245
+ REPORT
246
+
247
+ # Update pane style to indicate completion
248
+ if [ \$EXIT_CODE -eq 0 ]; then
249
+ tmux select-pane -T "โœ… \${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
250
+ tmux set-option -p @agent_label "โœ… \${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
251
+ else
252
+ tmux select-pane -T "โŒ \${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
253
+ tmux set-option -p @agent_label "โŒ \${ROLE_SHORT}-\${ISSUE}" 2>/dev/null || true
254
+ fi
255
+ tmux set-option -p pane-border-style "fg=colour240" 2>/dev/null || true
256
+
257
+ # Signal Queen
258
+ tmux wait-for -S queen-wake 2>/dev/null || true
259
+
260
+ # Note: worktree is intentionally kept alive after Leader completion.
261
+ # The branch is needed for PR review cycles and CI checks.
262
+ # Cleanup happens after PR merge (managed by Queen via bo-dispatch).
263
+
264
+ echo "--- \$ROLE completed (exit=\$EXIT_CODE) ---"
265
+ WRAPPER_BODY
266
+
267
+ chmod +x "$WRAPPER"
268
+
269
+ # โ”€โ”€ Kill existing window with same name if present โ”€โ”€
270
+ tmux kill-window -t "$SESSION:$WINDOW_NAME" 2>/dev/null || true
271
+
272
+ # โ”€โ”€ Create new tmux window โ”€โ”€
273
+ tmux new-window -t "$SESSION" -n "$WINDOW_NAME" "bash '$WRAPPER'; exit 0"
274
+
275
+ # Pane title + styling
276
+ tmux select-pane -t "$SESSION:$WINDOW_NAME.0" -T "$PANE_TITLE"
277
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" @agent_label "$PANE_TITLE" 2>/dev/null || true
278
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" allow-rename off 2>/dev/null || true
279
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" remain-on-exit on 2>/dev/null || true
280
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.0" pane-border-style "fg=${BORDER_FG}" 2>/dev/null || true
281
+
282
+ echo "launched:${ROLE_SHORT}-${ISSUE} (window: ${WINDOW_NAME}, worktree: ${WORKTREE_PATH:-none})"
@@ -0,0 +1,184 @@
1
+ #!/bin/bash
2
+ # launch-worker.sh - Launch Worker in a tmux split-pane (within Leader's window)
3
+ # Usage: launch-worker.sh <role> <issue> <subtask_id> <branch>
4
+ #
5
+ # Part of beeops: 3-layer multi-agent system (Queen โ†’ Leader โ†’ Worker)
6
+ #
7
+ # Features:
8
+ # - tmux split-window -h: adds pane within Leader's window
9
+ # - No worktree creation (shares Leader's worktree)
10
+ # - Signals leader-{issue}-wake on completion
11
+ # - Smaller max_turns (15-30)
12
+
13
+ set -euo pipefail
14
+
15
+ ROLE="$1"
16
+ ISSUE="$2"
17
+ SUBTASK_ID="$3"
18
+ BRANCH="$4"
19
+ SESSION="bo"
20
+ REPO_DIR="$(git rev-parse --show-toplevel)"
21
+ REPORTS_DIR="$REPO_DIR/.claude/tasks/reports"
22
+ PROMPTS_DIR="$REPO_DIR/.claude/tasks/prompts"
23
+
24
+ mkdir -p "$REPORTS_DIR/processed" "$PROMPTS_DIR"
25
+
26
+ # โ”€โ”€ Role configuration โ”€โ”€
27
+ case "$ROLE" in
28
+ worker-coder)
29
+ ROLE_SHORT="worker-coder"
30
+ ENV_VAR="BO_WORKER_CODER"
31
+ WINDOW_NAME="issue-${ISSUE}"
32
+ BORDER_FG="green"
33
+ ROLE_ICON="โšก"
34
+ MAX_TURNS=30
35
+ ALLOWED_TOOLS="Read,Write,Edit,Bash,Glob,Grep"
36
+ ;;
37
+ worker-tester)
38
+ ROLE_SHORT="worker-tester"
39
+ ENV_VAR="BO_WORKER_TESTER"
40
+ WINDOW_NAME="issue-${ISSUE}"
41
+ BORDER_FG="cyan"
42
+ ROLE_ICON="๐Ÿงช"
43
+ MAX_TURNS=30
44
+ ALLOWED_TOOLS="Read,Write,Edit,Bash,Glob,Grep"
45
+ ;;
46
+ worker-code-reviewer)
47
+ ROLE_SHORT="worker-code-reviewer"
48
+ ENV_VAR="BO_WORKER_CODE_REVIEWER"
49
+ WINDOW_NAME="review-${ISSUE}"
50
+ BORDER_FG="blue"
51
+ ROLE_ICON="๐Ÿ”"
52
+ MAX_TURNS=15
53
+ ALLOWED_TOOLS="Read,Grep,Glob,Bash"
54
+ ;;
55
+ worker-security)
56
+ ROLE_SHORT="worker-security"
57
+ ENV_VAR="BO_WORKER_SECURITY"
58
+ WINDOW_NAME="review-${ISSUE}"
59
+ BORDER_FG="red"
60
+ ROLE_ICON="๐Ÿ›ก"
61
+ MAX_TURNS=15
62
+ ALLOWED_TOOLS="Read,Grep,Glob,Bash"
63
+ ;;
64
+ worker-test-auditor)
65
+ ROLE_SHORT="worker-test-auditor"
66
+ ENV_VAR="BO_WORKER_TEST_AUDITOR"
67
+ WINDOW_NAME="review-${ISSUE}"
68
+ BORDER_FG="yellow"
69
+ ROLE_ICON="๐Ÿงช"
70
+ MAX_TURNS=15
71
+ ALLOWED_TOOLS="Read,Grep,Glob,Bash"
72
+ ;;
73
+ *)
74
+ echo "Unknown role: $ROLE (expected: worker-coder | worker-tester | worker-code-reviewer | worker-security | worker-test-auditor)" >&2
75
+ exit 1
76
+ ;;
77
+ esac
78
+
79
+ PANE_TITLE="${ROLE_ICON} ${ROLE_SHORT}-${ISSUE}-${SUBTASK_ID}"
80
+ SIGNAL_NAME="leader-${ISSUE}-wake"
81
+
82
+ # โ”€โ”€ Determine work directory (use Leader's worktree if available) โ”€โ”€
83
+ WORKTREE_PATH="$REPO_DIR/.claude/worktrees/$BRANCH"
84
+ if [ -d "$WORKTREE_PATH" ]; then
85
+ WORK_DIR="$WORKTREE_PATH"
86
+ else
87
+ WORK_DIR="$REPO_DIR"
88
+ fi
89
+
90
+ # โ”€โ”€ Read prompt file (Leader writes this before launching worker) โ”€โ”€
91
+ PROMPT_FILE="$PROMPTS_DIR/worker-${ISSUE}-${SUBTASK_ID}.md"
92
+ if [ ! -f "$PROMPT_FILE" ]; then
93
+ echo "ERROR: Prompt file not found: $PROMPT_FILE" >&2
94
+ exit 1
95
+ fi
96
+
97
+ # โ”€โ”€ Wrapper script (runs inside tmux pane) โ”€โ”€
98
+ WRAPPER="/tmp/agent-wrapper-${ROLE_SHORT}-${ISSUE}-${SUBTASK_ID}.sh"
99
+ cat > "$WRAPPER" <<'WRAPPER_HEADER'
100
+ #!/bin/bash
101
+ set -uo pipefail
102
+ WRAPPER_HEADER
103
+
104
+ cat >> "$WRAPPER" <<WRAPPER_BODY
105
+ WORK_DIR="${WORK_DIR}"
106
+ REPO_DIR="${REPO_DIR}"
107
+ REPORTS_DIR="${REPORTS_DIR}"
108
+ PROMPT_FILE="${PROMPT_FILE}"
109
+ ROLE="${ROLE}"
110
+ ROLE_SHORT="${ROLE_SHORT}"
111
+ ENV_VAR="${ENV_VAR}"
112
+ ISSUE="${ISSUE}"
113
+ SUBTASK_ID="${SUBTASK_ID}"
114
+ BRANCH="${BRANCH}"
115
+ SIGNAL_NAME="${SIGNAL_NAME}"
116
+ MAX_TURNS="${MAX_TURNS}"
117
+ ALLOWED_TOOLS="${ALLOWED_TOOLS}"
118
+ BO_SCRIPTS_DIR="${BO_SCRIPTS_DIR:-}"
119
+ BO_CONTEXTS_DIR="${BO_CONTEXTS_DIR:-}"
120
+
121
+ cd "\$WORK_DIR"
122
+
123
+ # Run agent
124
+ unset CLAUDECODE
125
+ env \${ENV_VAR}=1 \
126
+ BO_SCRIPTS_DIR="\$BO_SCRIPTS_DIR" \
127
+ BO_CONTEXTS_DIR="\$BO_CONTEXTS_DIR" \
128
+ claude --dangerously-skip-permissions \
129
+ --allowedTools "\$ALLOWED_TOOLS" \
130
+ --max-turns \$MAX_TURNS \
131
+ --no-session-persistence \
132
+ "\$(cat "\$PROMPT_FILE")"
133
+ EXIT_CODE=\$?
134
+
135
+ # Write basic report
136
+ TIMESTAMP=\$(date -u +%Y-%m-%dT%H:%M:%SZ)
137
+ STATUS=\$([ \$EXIT_CODE -eq 0 ] && echo completed || echo failed)
138
+
139
+ cat > "\$REPORTS_DIR/worker-\${ISSUE}-\${SUBTASK_ID}.yaml" <<REPORT
140
+ issue: \$ISSUE
141
+ subtask_id: \$SUBTASK_ID
142
+ role: \$ROLE
143
+ status: \$STATUS
144
+ exit_code: \$EXIT_CODE
145
+ branch: \$BRANCH
146
+ timestamp: \$TIMESTAMP
147
+ REPORT
148
+
149
+ # Update pane style to indicate completion
150
+ if [ \$EXIT_CODE -eq 0 ]; then
151
+ tmux select-pane -T "โœ… \${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
152
+ tmux set-option -p @agent_label "โœ… \${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
153
+ else
154
+ tmux select-pane -T "โŒ \${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
155
+ tmux set-option -p @agent_label "โŒ \${ROLE_SHORT}-\${ISSUE}-\${SUBTASK_ID}" 2>/dev/null || true
156
+ fi
157
+ tmux set-option -p pane-border-style "fg=colour240" 2>/dev/null || true
158
+
159
+ # Signal Leader
160
+ tmux wait-for -S \$SIGNAL_NAME 2>/dev/null || true
161
+
162
+ echo "--- \$ROLE (subtask \$SUBTASK_ID) completed (exit=\$EXIT_CODE) ---"
163
+ WRAPPER_BODY
164
+
165
+ chmod +x "$WRAPPER"
166
+
167
+ # โ”€โ”€ Clean up dead panes from previous runs โ”€โ”€
168
+ for DEAD_PANE in $(tmux list-panes -t "$SESSION:$WINDOW_NAME" -F '#{pane_index} #{pane_dead}' 2>/dev/null | awk '$2=="1"{print $1}' | sort -rn); do
169
+ tmux kill-pane -t "$SESSION:$WINDOW_NAME.${DEAD_PANE}" 2>/dev/null || true
170
+ done
171
+
172
+ # โ”€โ”€ Launch in tmux split-pane (within Leader's window) โ”€โ”€
173
+ tmux split-window -h -t "$SESSION:$WINDOW_NAME" "bash '$WRAPPER'; exit 0"
174
+
175
+ # Pane title + styling
176
+ LAST_PANE=$(tmux list-panes -t "$SESSION:$WINDOW_NAME" -F '#{pane_index}' | tail -1)
177
+ tmux select-pane -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" -T "$PANE_TITLE"
178
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" @agent_label "$PANE_TITLE" 2>/dev/null || true
179
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" allow-rename off 2>/dev/null || true
180
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" remain-on-exit on 2>/dev/null || true
181
+ tmux set-option -p -t "$SESSION:$WINDOW_NAME.${LAST_PANE}" pane-border-style "fg=${BORDER_FG}" 2>/dev/null || true
182
+ tmux select-layout -t "$SESSION:$WINDOW_NAME" tiled 2>/dev/null || true
183
+
184
+ echo "launched:${ROLE_SHORT}-${ISSUE}-${SUBTASK_ID} (window: ${WINDOW_NAME})"