taskmaestro — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited taskmaestro (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
현재 tmux 세션의 기존 패널들에서 Claude Code를 병렬로 실행하고, 이 패널(지휘자)에서 제어한다. 각 패널은 독립된 git worktree에서 작업하며, 지휘자가 작업 지시, 상태 감시를 수행한다.
전제 조건: 지휘자(이 Claude Code)가 tmux 패널 중 하나에서 실행 중이어야 하며, 나머지 패널들이 이미 열려있어야 한다.
$ARGUMENTS를 파싱하여 서브커맨드와 인수를 분리한다:
start [--repo <path>] [--base <branch>] [--panes <1,2,3>] [--review-pane] [--no-review-pane]assign <패널번호> "<작업 지시>"statuswatchsend <패널번호> "<텍스트>"stop [패널번호|all]서브커맨드에 해당하는 섹션으로 이동한다.
모든 서브커맨드에서 먼저 실행:
# 현재 tmux 소켓, 세션, 윈도우 정보를 자동 감지
TMUX_SOCKET=$(tmux display-message -p '#{socket_path}')
# 소켓 이름 추출 (경로에서 마지막 부분)
SOCKET_NAME=$(basename "$TMUX_SOCKET")
SESSION=$(tmux display-message -p '#{session_name}')
WIN_IDX=$(tmux display-message -p '#{window_index}')
MY_PANE=$(tmux display-message -p '#{pane_index}')tmux 명령어에서-L플래그는 소켓 이름을 사용한다.tmux -L "$SOCKET_NAME" send-keys ...형태로 사용.
워커가 작업을 완료하면 .taskmaestro/wt-N/RESULT.json 파일을 생성하여 지휘자에게 결과를 알린다. 이 파일은 watch 모드의 1차 감지 수단이며, capture-pane은 fallback으로만 사용한다.
{
"status": "success | failure | error | review_pending | review_addressed | approved",
"issue": "#767",
"pr_number": 123,
"pr_url": "https://github.com/org/repo/pull/123",
"timestamp": "2026-03-22T01:13:00.000Z",
"cost": "$0.45",
"error": null,
"review_cycle": 0,
"review_comments": []
}| 필드 | 타입 | 필수 | 설명 | |||||
|---|---|---|---|---|---|---|---|---|
status | `"success" \ | "failure" \ | "error" \ | "review_pending" \ | "review_addressed" \ | "approved"` | ✅ | 작업 결과. success: PR 생성 완료 (리뷰 대기), failure: 작업 실패 (테스트 실패 등), error: 예기치 못한 오류, review_pending: 지휘자 리뷰 코멘트 작성 완료 (워커 응답 대기), review_addressed: 워커가 리뷰 반영 완료 (재리뷰 대기), approved: 지휘자 최종 승인 (진짜 완료) |
issue | `string \ | null` | ❌ | 관련 이슈 번호 (예: "#767") | ||||
pr_number | `number \ | null` | ❌ | 생성된 PR 번호 | ||||
pr_url | `string \ | null` | ❌ | 생성된 PR URL | ||||
timestamp | string | ✅ | ISO 8601 완료 시각 | |||||
cost | `string \ | null` | ❌ | 세션 비용 (예: "$0.45") | ||||
error | `string \ | null` | ❌ | 에러 메시지 (status가 "error"일 때) | ||||
review_cycle | number | ❌ | 현재 리뷰 사이클 횟수 (기본값: 0) | |||||
review_comments | string[] | ❌ | 지휘자가 남긴 리뷰 코멘트 요약 목록 |
<repo>/.taskmaestro/wt-<N>/RESULT.json (각 워커의 worktree 루트)워커가 RESULT.json에 status: "success"를 기록하면 리뷰 사이클이 시작되고, status: "approved"가 될 때까지 반복된다. 승인이 "진짜 완료"다.
Canonical source: 리뷰 사이클 프로토콜의 단일 소스는packages/rules/.ai-rules/rules/pr-review-cycle.md이다. 아래 섹션은 taskmaestro 전용 구현 세부사항(tmux 트리거,taskmaestro-state.json구조)만 남기고, 프로토콜 전체는 canonical 문서를 참조한다.
지휘자의 watch 모드는 .taskmaestro/wt-N/RESULT.json의 status 필드를 감지한다:
status | 지휘자 동작 |
|---|---|
success | 리뷰 사이클 시작 (done으로 보고하지 않음) |
failure / error | 사용자에게 보고, 리뷰 미진행 |
review_pending | 워커 응답 대기 |
review_addressed | 재리뷰 시작 |
approved | 진짜 완료 ✅ |
review_pane이 설정되지 않았으면 (기본) → Conductor Review 실행review_pane이 설정되었으면 → 해당 패널의 Review Agent로 위임두 경우 모두 실행하는 프로토콜(CI gate → local verify → diff → code quality → spec → tests → write review → approve)은 canonical 문서를 따른다. Severity 등급(critical/high/medium/low), approval 조건, commit hygiene(amend + force-with-lease), 최대 3회 사이클 상한도 canonical 문서가 정의한다.
Conductor Review가 기본 동작인 이유: 지휘자는 PLAN 컨텍스트를 보유하지만, 워커 리뷰어는 그렇지 않다.
프로토콜의 "워커에게 리뷰 반영 지시" 단계를 taskmaestro는 file-based trigger로 구현한다. 긴 프롬프트를 send-keys로 직접 전송하면 잘릴 수 있으므로:
Review Fix TASK.md를 워커 worktree 루트($REPO/.taskmaestro/wt-$PANE_IDX/TASK.md)에 작성한다. 내용은 아래 Review Fix TASK.md 템플릿을 따른다.send-keys로 전송한다: tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE_IDX" \
"Read TASK.md and execute all steps." Enter리뷰 에이전트 패널($REVIEW_PANE)에 리뷰 프롬프트를 전송할 때도 동일한 파일 기반 패턴을 사용한다.
#### Review Fix TASK.md 템플릿
워커 worktree에 작성하는 TASK.md의 내용:
# Review Fix Task
See rules/pr-review-cycle.md for the canonical worker response protocol.
## Steps
1. `gh pr view <PR_NUMBER> --comments` 로 리뷰 코멘트를 확인한다.
2. 각 코멘트에 대응: 수용 시 코드 수정, 거부 시 반박 코멘트, `Resolved: ...` 회신.
3. MANDATORY 사전 체크: `yarn prettier --write . && yarn lint --fix && yarn type-check && yarn test` — 모두 통과해야 push 한다.
4. 커밋 위생: `git commit --amend --no-edit && git push --force-with-lease` (fix 커밋을 쌓지 말 것).
5. `RESULT.json`을 업데이트한다: `{ "status": "review_addressed", "review_cycle": <current_cycle> }`
[CONTINUOUS] DO NOT stop. Only stop AFTER updating RESULT.json to "review_addressed".핵심: 워커는 리뷰 반영 후 반드시RESULT.json의status를review_addressed로 업데이트해야 watch cron이 재리뷰를 트리거한다.
리뷰 사이클 중 각 패널의 taskmaestro-state.json 필드:
{
"index": 1,
"role": "worker",
"worktree": "...",
"branch": "...",
"task": "...",
"status": "review_pending",
"result": { "...RESULT.json 내용..." },
"review_cycle": 1,
"pr_number": 42
}리뷰 에이전트 패널은 role: "reviewer", status: "reviewing"을 사용한다. 리뷰 에이전트의 결과 파일(<repo>/.taskmaestro/wt-<review_pane>/RESULT.json)은 다음 스키마를 따른다:
{
"status": "success",
"review_result": "approve | changes_requested",
"issues_found": 3,
"critical_count": 0,
"high_count": 1
}Severity 카운트 필드(critical_count, high_count)는 rules/severity-classification.md의 Code Review Severity 스케일을 따른다.
지휘자는 리뷰 에이전트 결과를 읽고:
review_result: "approve" → 워커 RESULT.json을 approved로 업데이트, 승인 코멘트 게시, 사용자에게 완료 보고review_result: "changes_requested" → 워커 RESULT.json을 review_pending으로 업데이트하고 review_cycle 증가, file-based 리뷰 수정 트리거 전송RESULT.json을 삭제해 다음 리뷰를 위해 초기화status 값 매핑:
working → 워커 작업 중reviewing → 리뷰 에이전트가 PR 리뷰 중 (reviewer 패널 전용)review_pending → 리뷰 코멘트 작성 완료, 워커 응답 대기review_addressed → 워커 리뷰 반영 완료, 재리뷰 대기approved → 최종 승인 완료 (진짜 done)done → 리뷰 없이 완료 (failure/error)The conductor MUST NEVER merge PRs or modify the master/main branch.
Prohibited commands:
gh pr merge (all flags: --squash, --merge, --rebase, --admin, --auto)git mergegit pull origin master / git pull origin main (includes merge)Allowed:
git fetch origin (read-only)gh pr create (create PR, not merge)gh pr view (read-only)Protocol:
/ship → reports PR URLgit fetch origin to verify, then proceedsWave transition:
Before assigning issues to a wave, predict the FULL file footprint per issue:
package.json — dependency changesconfig.schema.ts / *.config.* — schema/config updatesindex.ts / barrel exports — new module exportsREADME.md — documentation updates.gitignore — new artifactsconfig.schema.ts as potential overlapANY issue that creates a new MCP handler MUST flag these files as modified:
apps/mcp-server/src/mcp/handlers/index.tsapps/mcp-server/src/mcp/mcp.module.tsANY issue that creates a new NestJS module MUST flag:
apps/mcp-server/src/app.module.tsANY issue that adds to an existing module MUST flag that module file.
Two issues touching the same barrel/module file → MUST be in different waves.
Overlap check:
For each pair of issues in the wave:
shared_files = issue_A.files ∩ issue_B.files
if shared_files is not empty:
→ Move one issue to next wave OR make sequential in same paneReference incidents:
NEVER use array indexing in monitoring/watch scripts. zsh is 1-indexed, bash is 0-indexed. This causes wrong issue mapping.
# ❌ BANNED — index mismatch between shells
EXPECTED=("#888" "#811")
echo ${EXPECTED[$IDX]}
# ✅ REQUIRED — explicit key:value mapping
for PANE_INFO in "1:#888" "2:#811" "3:#813"; do
N="${PANE_INFO%%:*}"
EXP="${PANE_INFO##*:}"
doneReference incident: zsh 1-based indexing caused pane 3 and 4's valid RESULT.json to be deleted.
For long taskMaestro sessions (multiple waves):
docs/codingbuddy/context.md before compact (via update_context)Recommended flow:
Wave 1 → Wave 2 → compact → Wave 3 → Wave 4 → compact → ...Warning signs that compact is needed:
/taskmaestro start [--repo <path>] [--base <branch>] [--panes <1,2,3>] [--review-pane] [--no-review-pane]
현재 세션의 기존 패널들에 worktree + Claude Code를 세팅한다.
--repo: 대상 레포 경로 (기본값: 현재 작업 디렉토리)--base: 베이스 브랜치 (기본값: 현재 브랜치)--panes: 사용할 패널 번호 목록 (기본값: 지휘자 패널을 제외한 모든 패널)--review-pane: 리뷰 전용 패널 할당 (기본값: 비활성화). 활성화하려면 --review-pane 명시 사용# repo가 git 레포인지 확인
git -C "$REPO" rev-parse --git-dir에러 시 "대상 경로가 git 레포지토리가 아닙니다" 출력 후 중단.
# 사용 가능한 패널 목록 확인 (지휘자 패널 제외)
tmux -L "$SOCKET_NAME" list-panes -t "$SESSION:$WIN_IDX" -F '#{pane_index} #{pane_current_command}'지휘자 패널($MY_PANE)을 제외한 패널들이 워커 대상이 된다. --panes로 지정하지 않으면 모든 비활성 패널을 사용한다.
리뷰 패널 할당 (`--review-pane`, 기본 비활성화): --review-pane 플래그를 명시하면 사용 가능한 패널 중 마지막 패널을 리뷰 에이전트 전용으로 할당한다. 기본값은 비활성화이며, 지휘자가 직접 리뷰를 수행한다 (Conductor Review). Rationale: Conductor has PLAN context; worker reviewers do not.
# 리뷰 패널 할당 (기본: 비활성화 — --review-pane 명시 시에만 활성화)
if [ "$REVIEW_PANE_ENABLED" = true ]; then
REVIEW_PANE=$(echo "$AVAILABLE_PANES" | tail -1)
WORKER_PANES=$(echo "$AVAILABLE_PANES" | head -n -1)
# 워커 패널이 최소 1개는 있어야 함
if [ -z "$WORKER_PANES" ]; then
echo "ERROR: 리뷰 패널을 할당하면 워커 패널이 없습니다. --no-review-pane을 사용하거나 패널을 추가하세요."
exit 1
fi
else
REVIEW_PANE=""
WORKER_PANES="$AVAILABLE_PANES"
fi최소 패널 요구: --review-pane 사용 시 지휘자 + 워커 1개 + 리뷰어 1개 = 최소 3개 패널이 필요하다.워커 패널이 없는 경우: 지휘자 패널만 존재하면, 첫 번째 숫자 인수(기본값 3)만큼 새 패널을 생성한다:
PANE_COUNT=${1:-3} # 기본 3개
DIR=$(cd "$REPO" && pwd)
for ((i = 0; i < PANE_COUNT; i++)); do
tmux -L "$SOCKET_NAME" split-window -t "$SESSION:$WIN_IDX" -c "$DIR"
tmux -L "$SOCKET_NAME" select-layout -t "$SESSION:$WIN_IDX" tiled
done
# 지휘자 패널로 포커스 복귀
tmux -L "$SOCKET_NAME" select-pane -t "$SESSION:$WIN_IDX.$MY_PANE"생성 후 다시 패널 목록을 조회하여 워커 패널을 결정한다.
cat ~/.claude/taskmaestro-state.json 2>/dev/null이미 활성 세션이 존재하면 AskUserQuestion으로 사용자에게 질문:
TIMESTAMP=$(date +%s)
DIR=$(cd "$REPO" && pwd)
BASE_BRANCH="${BASE:-$(git -C "$DIR" branch --show-current)}"
mkdir -p "$DIR/.taskmaestro"
# .gitignore에 .taskmaestro/ 추가
grep -qxF '.taskmaestro/' "$DIR/.gitignore" 2>/dev/null || echo '.taskmaestro/' >> "$DIR/.gitignore"
# 각 워커 패널 + 리뷰 패널에 대해 worktree 생성
ALL_PANES="$WORKER_PANES"
[ -n "$REVIEW_PANE" ] && ALL_PANES="$ALL_PANES $REVIEW_PANE"
for PANE_IDX in $ALL_PANES; do
BRANCH="taskmaestro/$TIMESTAMP/pane-$PANE_IDX"
WT_PATH="$DIR/.taskmaestro/wt-$PANE_IDX"
if [ -d "$WT_PATH" ]; then
if git -C "$DIR" worktree list | grep -q "$WT_PATH"; then
git -C "$DIR" worktree remove "$WT_PATH" --force
else
rm -rf "$WT_PATH"
fi
fi
git -C "$DIR" worktree add "$WT_PATH" -b "$BRANCH" "$BASE_BRANCH"
doneBefore launching Claude Code, verify each worktree:
# 워커 + 리뷰 패널 모두 사전 검증
ALL_PANES="$WORKER_PANES"
[ -n "$REVIEW_PANE" ] && ALL_PANES="$ALL_PANES $REVIEW_PANE"
for PANE_IDX in $ALL_PANES; do
WT_PATH="$DIR/.taskmaestro/wt-$PANE_IDX"
# 1. Remove stale artifacts
rm -f "$WT_PATH/RESULT.json" "$WT_PATH/TASK.md"
# 2. Copy permission presets (#905)
if [ -f "$REPO/.claude/settings.local.json" ]; then
mkdir -p "$WT_PATH/.claude"
cp "$REPO/.claude/settings.local.json" "$WT_PATH/.claude/settings.local.json"
fi
# 3. Install dependencies (CRITICAL — without this, yarn prettier/lint/test all fail)
echo "Installing dependencies in wt-$PANE_IDX..."
(cd "$WT_PATH" && yarn install --immutable 2>/dev/null) || echo "WARNING: yarn install failed in wt-$PANE_IDX"
# 4. Verify git status clean
if ! git -C "$WT_PATH" diff --quiet 2>/dev/null; then
echo "WARNING: wt-$PANE_IDX has uncommitted changes"
fi
doneThis prevents:
# 워커 패널에 Claude Code 실행
for PANE_IDX in $WORKER_PANES; do
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE_IDX" \
"unset CLAUDECODE && cd $DIR/.taskmaestro/wt-$PANE_IDX && claude --dangerously-skip-permissions" Enter
done
# 리뷰 패널에 Claude Code 실행
if [ -n "$REVIEW_PANE" ]; then
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$REVIEW_PANE" \
"unset CLAUDECODE && cd $DIR/.taskmaestro/wt-$REVIEW_PANE && claude --dangerously-skip-permissions" Enter
fi중요: 지휘자 Claude Code 세션의 tmux 패널은CLAUDECODE환경변수를 상속받아 중첩 실행이 차단된다.unset CLAUDECODE로 해제해야 한다.
Claude Code 시작 시 trust 프롬프트와 약관 동의 프롬프트가 나타날 수 있다:
# 10초 대기 후 trust 프롬프트 승인 (Enter = "Yes, I trust")
sleep 10
for PANE_IDX in $WORKER_PANES; do
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE_IDX" Enter
done
# 3초 대기 후 약관 동의 프롬프트 처리 (Down → "Yes, I accept" → Enter)
sleep 3
for PANE_IDX in $WORKER_PANES; do
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE_IDX" Down
done
sleep 1
for PANE_IDX in $WORKER_PANES; do
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE_IDX" Enter
done이미 동의한 환경에서는 이 프롬프트가 나타나지 않을 수 있다. send-keys는 무해하게 무시된다.
10초 대기 후 각 패널의 Claude Code가 프롬프트(❯) 상태인지 capture-pane으로 확인한다.
~/.claude/taskmaestro-state.json에 세션 정보를 기록한다.
{
"socket_name": "workspace-1",
"session": "workspace-1",
"window_index": 0,
"conductor_pane": 0,
"review_pane": 3,
"repo": "절대경로",
"base_branch": "브랜치",
"created_at": "ISO timestamp",
"watch_cron_id": null,
"panes": [
{"index": 1, "role": "worker", "worktree": "절대경로/.taskmaestro/wt-1", "branch": "taskmaestro/ts/pane-1", "task": null, "status": "idle", "result": null},
{"index": 2, "role": "worker", "worktree": "절대경로/.taskmaestro/wt-2", "branch": "taskmaestro/ts/pane-2", "task": null, "status": "idle", "result": null},
{"index": 3, "role": "reviewer", "worktree": "절대경로/.taskmaestro/wt-3", "branch": "taskmaestro/ts/pane-3", "task": null, "status": "idle", "result": null}
]
}review_pane: 리뷰 에이전트 패널 인덱스. --no-review-pane 사용 시 nullrole: 각 패널의 역할. "worker" 또는 "reviewer"review_pane: null), 모든 패널의 role은 "worker"CronCreate로 30초 주기 cron job을 생성하여 watch 모드를 자동 시작한다. 생성된 cron job ID를 상태 파일의 watch_cron_id에 기록한다.
프롬프트: 각 워커 패널에 대해 1차: RESULT.json 파일 확인 → 2차: capture-pane fallback 순서로 상태를 감지한다. 워커의 "success" 감지 시 Review Routing (review_pane 존재 시 리뷰 에이전트에 위임). 리뷰 에이전트 패널의 RESULT.json도 확인하여 리뷰 결과 처리. 완료/에러 상태 패널이 있으면 사용자에게 보고한다.
사용자에게 보고:
TaskMaestro 시작 완료!
세션: workspace-1
레포: /path/to/repo
지휘자: 패널 0
워커: 패널 1, 2
리뷰어: 패널 3
베이스: main
/taskmaestro assign <번호> "작업" 으로 작업을 배정하세요.
/taskmaestro status 로 상태를 확인하세요.리뷰 패널이 없는 경우 (--no-review-pane): "리뷰어" 줄을 생략하고 모든 패널을 워커로 표시한다./taskmaestro assign <패널 번호> "<작업 지시>"
특정 패널의 Claude Code에 새 작업을 배정한다. 상태 파일의 task/status를 업데이트한다.
cat ~/.claude/taskmaestro-state.json소켓/세션/윈도우 정보를 가져온다. 패널 번호가 워커 패널 목록에 포함되는지 검증한다. 지휘자 패널이거나 존재하지 않는 패널이면 에러 출력 후 중단.
워커에게 작업 지시와 함께 RESULT.json 작성 지시를 포함한 프롬프트를 TASK.md 파일로 전달한다.
중요: 긴 프롬프트를send-keys로 직접 전송하면 잘릴 수 있다. 반드시 TASK.md 파일에 작성하고 짧은 트리거만send-keys로 전송한다.
#### Step 2a: TASK.md 파일 작성
워커 worktree 루트에 TASK.md를 작성한다:
WT_PATH="$REPO/.taskmaestro/wt-$PANE"
cat > "$WT_PATH/TASK.md" << 'TASKEOF'
# Task: <작업 지시 요약>
<작업 지시 전체 내용>
---
[MANDATORY PR RULES]
When creating PR with gh pr create, ALWAYS include --add-label with appropriate labels (feat, chore, fix, etc.).
[MANDATORY PRE-PUSH] yarn prettier --write . && yarn lint --fix && yarn type-check && yarn test — ALL must pass before push.
[COMPLETION] Write RESULT.json: {"status":"success|failure|error","issue":"#NNNN","pr_number":N,"pr_url":"URL","timestamp":"ISO","cost":null,"error":null}
[CONTINUOUS] DO NOT stop. Complete ALL steps. Only stop AFTER RESULT.json.
TASKEOF#### Step 2b: 짧은 트리거 전송
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE" \
"Read TASK.md and execute all steps. Follow TDD. Create PR with correct labels. Write RESULT.json when done. " Enter참고: 트리거 메시지에 핵심 지시를 한 줄로 요약하여 포함한다. 상세 지시는 TASK.md에서 읽게 된다.
해당 패널의 task와 status를 업데이트한다:
task: 작업 지시 내용status: "working"워커는 작업 완료 후 RESULT.json을 작성한다. 이후 리뷰 사이클이 시작되면:
"Read TASK.md and execute all steps." 트리거를 받고 TASK.md를 읽어 실행한다"review_addressed"를 감지하여 재리뷰를 트리거한다핵심: 워커가 리뷰 반영 후 RESULT.json을 "review_addressed"로 업데이트하지 않으면, watch cron이 재리뷰를 시작할 수 없다. TASK.md 템플릿에 이 지시가 포함되어 있다.패널 $PANE에 작업을 배정했습니다: "<작업 지시>"/taskmaestro send <패널 번호> "<텍스트>"
특정 패널에 텍스트를 직접 전송한다. 이미 진행 중인 작업에 후속 지시나 응답을 보낼 때 사용한다. assign과 달리 상태 파일의 task/status를 변경하지 않는다.
소켓/세션/윈도우 정보를 가져온다. 패널 번호 유효성 검증.
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE" "<텍스트>" Enter패널 $PANE에 전송 완료: "<텍스트>"/taskmaestro status
모든 워커 패널의 현재 상태를 수집하여 요약 보고한다.
cat ~/.claude/taskmaestro-state.json각 워커 패널의 worktree에서 RESULT.json 존재 여부를 먼저 확인한다:
for PANE_IDX in $WORKER_PANES; do
RESULT_FILE="$REPO/.taskmaestro/wt-$PANE_IDX/RESULT.json"
if [ -f "$RESULT_FILE" ]; then
STATUS=$(cat "$RESULT_FILE" | jq -r '.status')
PR_NUMBER=$(cat "$RESULT_FILE" | jq -r '.pr_number // empty')
REVIEW_CYCLE=$(cat "$RESULT_FILE" | jq -r '.review_cycle // 0')
# → status 값에 따라 적절한 상태 아이콘과 메시지 표시
fi
doneRESULT.json이 존재하는 패널은 status 값에 따라 분기하여 표시한다:
"success" → 리뷰 대기 (PR 생성 완료)"review_pending" → 리뷰 코멘트 작성 완료, 워커 응답 대기"review_addressed" → 워커 리뷰 반영 완료, 재리뷰 대기"approved" → 최종 승인 완료 (진짜 done)"failure" / "error" → 실패/에러 (기존 동작)RESULT.json이 없는 패널에 대해서만 capture-pane으로 상태를 확인한다:
for PANE_IDX in $NO_RESULT_PANES; do
tmux -L "$SOCKET_NAME" capture-pane -t "$SESSION:$WIN_IDX.$PANE_IDX" -p -S -30 | tail -15
done캡처된 내용을 분석:
❯ 또는 > 로 시작하는 입력 대기) → "idle"Error, error, failed, FAIL) → "error"상태 파일의 task 정보와 결합하여 테이블로 출력:
TaskMaestro 상태 (workspace-1):
패널 1: ✅ approved - "API 엔드포인트 구현" → PR #42 (review complete) (worker)
패널 2: 🔍 reviewing - PR #43 (reviewer)
패널 3: 📝 review_addressed - "모듈 리팩토링" → PR #44 (awaiting re-review) (worker)
패널 4: 🔄 working - "인증 기능 추가" (worker)
패널 5: ⏳ review_pending - "캐시 레이어" → PR #45 (awaiting worker response) (worker)
패널 6: ❌ error - "모듈을 찾을 수 없음" (worker)상태별 아이콘:
| status | 아이콘 | 설명 |
|---|---|---|
approved | ✅ | 최종 승인 완료 (진짜 done) |
success (리뷰 시작 전) | 🔍 | 리뷰 사이클 진행 중 |
reviewing | 🔍 | 리뷰 에이전트가 PR 리뷰 중 (reviewer 패널 전용) |
review_pending | ⏳ | 리뷰 완료, 워커 응답 대기 |
review_addressed | 📝 | 워커 반영 완료, 재리뷰 대기 |
working | 🔄 | 작업 중 |
failure | ❌ | 작업 실패 |
error | ❌ | 예기치 못한 오류 |
approved 패널: RESULT.json에서 pr_url, cost, review_cycle 등을 함께 표시error/crashed 패널: capture-pane 내용 마지막 10줄도 함께 표시Every status line MUST include parenthetical evidence:
패널 1: ✅ approved - "task" → PR #N (RESULT.json: approved, review cycles: 2, pane idle ✓) (worker)
패널 2: 🔄 working - "task" (active: ✽ Implementing… · ↓ 5.3k tokens) (worker)
패널 3: 🔍 reviewing - PR #N (RESULT.json: reviewing PR #N for #M, pane active ✓) (reviewer)
패널 4: ⏳ review_pending - "task" → PR #N (RESULT.json: review_pending, cycle 1/3, awaiting worker) (worker)
패널 5: 📝 review_addressed - "task" → PR #N (RESULT.json: review_addressed, cycle 2/3, awaiting re-review) (worker)
패널 6: ⚠️ uncertain - "task" (RESULT.json exists BUT pane still active — cross-verify needed) (worker)
패널 7: ❌ error - "task" (error in last 10 lines: "ModuleNotFoundError") (worker)Rules:
approved + pane idle = confirmed donesuccess = start review cycle (NOT done)review_pending = awaiting worker responsereview_addressed = awaiting conductor re-review/taskmaestro watch
주기적 감시 모드를 토글한다 (시작/중지).
watch 모드는 RESULT.json 파일 기반 감지를 1차 수단으로 사용하고, capture-pane을 fallback으로만 사용한다.
#### 1차: RESULT.json 파일 감지 (빠르고 정확)
# 1차: 워커 패널의 RESULT.json 확인
for PANE_IDX in $WORKER_PANES; do
RESULT_FILE="$REPO/.taskmaestro/wt-$PANE_IDX/RESULT.json"
if [ -f "$RESULT_FILE" ]; then
STATUS=$(cat "$RESULT_FILE" | jq -r '.status')
case "$STATUS" in
"success")
# → Review Routing: review_pane 존재 시 리뷰 에이전트에 위임, 없으면 직접 리뷰
# Review Cycle Protocol 참조
;;
"failure"|"error")
# → 사용자에게 에러/실패 보고 (기존 동작 유지)
;;
"review_pending")
# → 워커 응답 대기 중. 지휘자는 대기한다
;;
"review_addressed")
# → Review Routing: review_pane 존재 시 리뷰 에이전트에 재리뷰 위임, 없으면 직접 재리뷰
;;
"approved")
# → 진짜 완료 ✅. 상태를 "done"으로 업데이트하고 사용자에게 보고
;;
esac
fi
done
# 2차: 리뷰 에이전트 패널의 RESULT.json 확인
if [ -n "$REVIEW_PANE" ]; then
REVIEW_RESULT_FILE="$REPO/.taskmaestro/wt-$REVIEW_PANE/RESULT.json"
if [ -f "$REVIEW_RESULT_FILE" ]; then
REVIEW_STATUS=$(cat "$REVIEW_RESULT_FILE" | jq -r '.status')
REVIEW_RESULT=$(cat "$REVIEW_RESULT_FILE" | jq -r '.review_result')
if [ "$REVIEW_STATUS" = "success" ]; then
# → Conductor Handling of Review Agent Result 참조
# review_result에 따라 워커 PR approve 또는 changes_requested 처리
# 처리 후 리뷰 에이전트의 RESULT.json 삭제 (다음 리뷰 준비)
rm -f "$REVIEW_RESULT_FILE"
fi
fi
fiRESULT.json status 매핑:
| status | watch 동작 |
|---|---|
"success" | 리뷰 사이클 시작 ("done"이 아님) |
"failure" / "error" | 사용자에게 보고 (기존 동작 유지) |
"review_pending" | 워커 응답 대기 중 |
"review_addressed" | 지휘자 재리뷰 시작 |
"approved" | 진짜 완료 ✅ |
#### 2차 (fallback): capture-pane 기반 감지
RESULT.json이 없는 패널에 대해서만 capture-pane으로 상태를 확인한다:
for PANE_IDX in $NO_RESULT_PANES; do
CAPTURED=$(tmux -L "$SOCKET_NAME" capture-pane -t "$SESSION:$WIN_IDX.$PANE_IDX" -p -S -30 | tail -15)
# 캡처 내용 분석:
# - 프롬프트 대기 (❯) → "idle" (작업 완료했으나 RESULT.json 미작성)
# - 도구 실행 중 → "working"
# - 에러 패턴 → "error"
# - 프로세스 없음 → "crashed"
done워커 패널 순회 (1차: RESULT.json → 2차: capture-pane fallback):
각 워커 패널에 대해 $REPO/.taskmaestro/wt-$PANE_IDX/RESULT.json을 확인하고, status에 따라 분기한다:
review_pane 확인review_pane 존재 시 → Review Agent Protocol에 따라 리뷰 에이전트에 위임review_pane 없으면 → Conductor Review 실행:a. gh pr diff <PR_NUMBER> 로 PR 변경사항 읽기 b. codingbuddy generate_checklist 도구로 체크리스트 생성 c. gh pr review <PR_NUMBER> --comment --body "<리뷰>" 로 리뷰 코멘트 작성 d. 워커의 RESULT.json 업데이트: status: "review_pending", review_cycle 증가, review_comments 추가 e. 워커 worktree에 Review Fix TASK.md 작성 (아래 템플릿 참조):
# Review Fix TASK.md를 워커 worktree에 작성
cat > "$REPO/.taskmaestro/wt-$PANE_IDX/TASK.md" << 'TASKEOF'
# Review Fix Task
... (Review Fix TASK.md Template 참조)
TASKEOFf. 워커에게 짧은 트리거 전송:
tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE_IDX" \
"Read TASK.md and execute all steps." Enterreview_cycle 확인. 3 이상이면 사용자에게 보고하고 해당 패널 리뷰 중단review_pane 확인review_pane 존재 시 → 리뷰 에이전트에 재리뷰 위임review_pane 없으면 → Conductor Review 재실행:a. gh pr diff <PR_NUMBER> 재확인 b. 미해결 코멘트 확인 (gh pr view <PR_NUMBER> --comments) c. 충분히 개선 → status: "approved", PR approve 코멘트 작성, 사용자에게 완료 보고 d. 아직 부족 → 새 리뷰 코멘트 작성 후 Review Fix TASK.md를 다시 워커에게 전달
리뷰 에이전트 패널 확인 (review_pane이 설정된 경우):
$REPO/.taskmaestro/wt-$REVIEW_PANE/RESULT.json 확인:
review_result: "approve" → 워커의 RESULT.json을 status: "approved"로 업데이트, PR approve 코멘트 작성, 리뷰 에이전트 RESULT.json 삭제review_result: "changes_requested" → 워커의 RESULT.json을 status: "review_pending"으로 업데이트 (review_cycle 증가), 워커 worktree에 Review Fix TASK.md 작성, 워커에게 "Read TASK.md and execute all steps." 트리거 전송, 리뷰 에이전트 RESULT.json 삭제Fallback (RESULT.json 없는 패널):
capture-pane으로 상태 확인. idle인데 status가 "working"이면 Auto-Nudge Protocol 실행. Claude Code가 비정상 종료된 패널이 있으면 재시작 여부를 사용자에게 질문한다.
watch_cron_id에 기록/taskmaestro watch를 다시 실행하세요."watch_cron_id 확인watch_cron_id를 null로 업데이트When a pane is detected as idle (❯ prompt visible) but its task status is "working":
tmux send-keys "continue" Entertmux send-keys "continue with the next incomplete task" EnterInclude in watch cron prompt:
If pane is idle (❯ visible) and status is "working":
nudge_count[pane] += 1
if nudge_count <= 1: send "continue"
elif nudge_count == 2: send "continue with the next incomplete task"
else: send explicit instruction
Report: "Pane N: IDLE → auto-nudged (#count)"CronCreate job은 현재 Claude Code 세션에 종속되며, 7일 후 자동 만료된다. 세션이 종료되거나 만료 시 watch도 중단된다. 재시작하려면 /taskmaestro watch를 다시 실행한다.
/taskmaestro stop [패널 번호|all]
Claude Code를 종료하고 worktree를 정리한다.
all: 모든 워커 패널 종료 tmux -L "$SOCKET_NAME" send-keys -t "$SESSION:$WIN_IDX.$PANE" "/exit" Enter # uncommitted changes 확인
if git -C "$WORKTREE_PATH" diff --quiet && git -C "$WORKTREE_PATH" diff --cached --quiet; then
git -C "$REPO" worktree remove "$WORKTREE_PATH"
else
# AskUserQuestion으로 사용자에게 알림
# "패널 N의 worktree에 커밋되지 않은 변경사항이 있습니다. 강제 삭제할까요?"
# Yes → git worktree remove --force
# No → worktree 보존, 경로 안내
fi tmux -L "$SOCKET_NAME" kill-pane -t "$SESSION:$WIN_IDX.$PANE"패널 N을 종료했습니다. (브랜치 taskmaestro/xxx/pane-N 유지됨)/exit 전송 for PANE_IDX in $(echo "$WORKER_PANES" | sort -rn); do
tmux -L "$SOCKET_NAME" kill-pane -t "$SESSION:$WIN_IDX.$PANE_IDX"
done.taskmaestro/ 디렉토리가 비었으면 삭제: rmdir "$REPO/.taskmaestro" 2>/dev/null TaskMaestro 종료 완료.
정리된 워커: N개
유지된 브랜치: taskmaestro/xxx/pane-1, pane-2, ...주의: stop all은 tmux 세션을 종료하지 않는다. 패널들은 그대로 남아있으며 zsh 상태로 돌아간다.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.