본문으로 건너뛰기
cccskills
무료GitHub에 공개한국어 소개

orchestrate

별도 작업 폴더에서 여러 Claude Code를 실행하여 개발 작업 배정, 진행 상황 확인, 중단된 세션 복구 지원, PR 완료 확인을 함께 관리합니다.

원문원문 설명 보기

Meta-agent supervisor that manages a fleet of Claude Code agents running in tmux windows. Auto-discovers spare worktrees, spawns agents, monitors state, kicks idle agents, approves safe confirmations, and recycles worktrees when done. TRIGGER when user asks to supervise agents, run parallel tasks, manage worktrees, check agent status, or orchestrate parallel work.

연동 도구DiscordGitHub

실행 점수 미검증

설치 방법 보기

이럴 때 유용합니다

  • 여러 에이전트에 개발 작업 분담
  • 진행 상황과 빈 worktree 확인
  • 중단된 에이전트 재개
  • PR 테스트와 리뷰 의견 대응 확인

한국어 소개

할 수 있는 일

orchestrate는 여러 Claude Code에 개발 작업을 배정하고 진행 상황을 함께 관리합니다. 터미널 작업 화면을 나누는 tmux와 브랜치별 작업 폴더인 worktree를 사용하여 빈 환경 탐색, 에이전트 실행, 상태 확인을 진행합니다. 중단된 에이전트에 지시를 전달하거나 세션을 복구하고, CI와 리뷰 의견도 확인합니다.

이럴 때 유용합니다

여러 수정을 동시에 진행하거나 어떤 에이전트가 작업 중이고 어떤 환경이 비어 있는지 파악할 때 유용합니다. 각 작업의 완료 단계를 기록하고 미해결 의견과 테스트 결과를 확인하여 완료 여부를 판단합니다. 필요하면 완료 알림도 보낼 수 있습니다.

사용 예시

  • “이 세 가지 수정을 각각 다른 에이전트에 배정해 주세요.”
  • “에이전트 상태와 비어 있는 worktree를 보여 주세요.”
  • “중단된 세션을 복구해 주세요.”

주의 사항

Claude Code, 기존 tmux 세션, Git worktree, jq 등을 사용합니다. PR 확인에는 gh를 사용합니다. 공유 포트와 데이터베이스를 사용하는 /pr-test는 동시에 실행하지 않고 순서대로 진행합니다. Discord 알림에는 Webhook 설정이 필요합니다. 실행 예시에는 권한 확인을 생략하는 설정이 포함됩니다.

이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.

문서 점검

AI가 SKILL.md의 내용에서 주의가 필요한 작업과 도입 전제를 확인했습니다. 점수는 실제로 실행한 결과(실행 검증)만으로 매깁니다.

안전성전송·삭제·명령 실행 등을 명시하고 있는가
C확인 필요bypassPermissions로 세션을 재개하고 run-loop.sh가 확인 대화 상자를 자동 승인한다고 명시합니다.
도입의 용이성필요한 도구나 API 키가 적고 적혀 있는가
B일부 부족tmux, Claude Code, jq와 알림용 Webhook을 사용하지만 전체 설치 절차는 없습니다.

점수에는 넣지 않았습니다. 2026년 10월 23일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.

평가가 다르다고 생각되면 재검토를 요청하기

어느 항목이 왜 다르다고 생각하는지 적어 주세요. 로그인은 필요 없습니다. SKILL.md와 대조해 평가를 다시 만들고 이곳에 반영합니다.

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

포함된 파일(11)

  • SKILL.md36.2 KB
  • scripts/capacity.sh1.2 KB
  • scripts/classify-pane.sh2.9 KB
  • scripts/find-spare.sh778 B
  • scripts/notify.sh1.3 KB
  • scripts/poll-cycle.sh9.6 KB
  • scripts/recycle-agent.sh1.0 KB
  • scripts/run-loop.sh9.1 KB
  • scripts/spawn-agent.sh5.3 KB
  • scripts/status.sh1.5 KB
  • scripts/verify-complete.sh8.4 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Orchestrate — Agent Fleet Supervisor

One tmux session, N windows — each window is one agent working in its own worktree. Speak naturally; Claude maps your intent to the right scripts.

Scripts

SKILLS_DIR=$(git rev-parse --show-toplevel)/.claude/skills/orchestrate/scripts
STATE_FILE=~/.claude/orchestrator-state.json
ScriptPurpose
find-spare.sh [REPO_ROOT]List free worktrees — one PATH BRANCH per line
spawn-agent.sh SESSION PATH SPARE NEW_BRANCH OBJECTIVE [PR_NUMBER] [STEPS...]Create window + checkout branch + launch claude + send task. Stdout: SESSION:WIN only
recycle-agent.sh WINDOW PATH SPARE_BRANCHKill window + restore spare branch
run-loop.shMechanical babysitter — idle restart + dialog approval + recycle on ORCHESTRATOR:DONE + supervisor health check + all-done notification
verify-complete.sh WINDOWVerify PR is done: checkpoints ✓ + 0 unresolved threads + CI green + no fresh CHANGES_REQUESTED. Repo auto-derived from state file .repo or git remote.
notify.sh MESSAGESend notification via Discord webhook (env DISCORD_WEBHOOK_URL or state .discord_webhook), macOS notification center, and stdout
capacity.sh [REPO_ROOT]Print available + in-use worktrees
status.shPrint fleet status + live pane commands
poll-cycle.shOne monitoring cycle — classifies panes, tracks checkpoints, returns JSON action array
classify-pane.sh WINDOWClassify one pane state

Supervision model

Orchestrating Claude (this Claude session — IS the supervisor)
  └── Reads pane output, checks CI, intervenes with targeted guidance
        run-loop.sh (separate tmux window, every 30s)
          └── Mechanical only: idle restart, dialog approval, recycle on ORCHESTRATOR:DONE

You (the orchestrating Claude) are the supervisor. After spawning agents, stay in this conversation and actively monitor: poll each agent's pane every 2-3 minutes, check CI, nudge stalled agents, and verify completions. Do not spawn a separate supervisor Claude window — it loses context, is hard to observe, and compounds context compression problems.

run-loop.sh is the mechanical layer — zero tokens, handles things that need no judgment: restart crashed agents, press Enter on dialogs, recycle completed worktrees (only after verify-complete.sh passes).

Checkpoint protocol

Agents output checkpoints as they complete each required step:

CHECKPOINT:<step-name>

Required steps are passed as args to spawn-agent.sh (e.g. pr-address pr-test). run-loop.sh will not recycle a window until all required checkpoints are found in the pane output. If verify-complete.sh fails, the agent is re-briefed automatically.

Worktree lifecycle

spare/N branch  →  spawn-agent.sh (--session-id UUID)  →  window + feat/branch + claude running
                                                                 ↓
                                               CHECKPOINT:<step> (as steps complete)
                                                                 ↓
                                                        ORCHESTRATOR:DONE
                                                                 ↓
                                    verify-complete.sh: checkpoints ✓ + 0 threads + CI green + no fresh CHANGES_REQUESTED
                                                                 ↓
                                              state → "done", notify, window KEPT OPEN
                                                                 ↓
                              user/orchestrator explicitly requests recycle
                                                                 ↓
                                         recycle-agent.sh → spare/N (free again)

Windows are never auto-killed. The worktree stays on its branch, the session stays alive. The agent is done working but the window, git state, and Claude session are all preserved until you choose to recycle.

To resume a done or crashed session:

# Resume by stored session ID (preferred — exact session, full context)
claude --resume SESSION_ID --permission-mode bypassPermissions

# Or resume most recent session in that worktree directory
cd /path/to/worktree && claude --continue --permission-mode bypassPermissions

To manually recycle when ready:

bash ~/.claude/orchestrator/scripts/recycle-agent.sh SESSION:WIN WORKTREE_PATH spare/N
# Then update state:
jq --arg w "SESSION:WIN" '.agents |= map(if .window == $w then .state = "recycled" else . end)' \
  ~/.claude/orchestrator-state.json > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

State file (~/.claude/orchestrator-state.json)

Never committed to git. You maintain this file directly using jq + atomic writes (.tmp → mv).

{
  "active": true,
  "tmux_session": "autogpt1",
  "idle_threshold_seconds": 300,
  "loop_window": "autogpt1:5",
  "repo": "Significant-Gravitas/AutoGPT",
  "discord_webhook": "https://discord.com/api/webhooks/...",
  "last_poll_at": 0,
  "agents": [
    {
      "window": "autogpt1:3",
      "worktree": "AutoGPT6",
      "worktree_path": "/path/to/AutoGPT6",
      "spare_branch": "spare/6",
      "branch": "feat/my-feature",
      "objective": "Implement X and open a PR",
      "pr_number": "12345",
      "session_id": "550e8400-e29b-41d4-a716-446655440000",
      "steps": ["pr-address", "pr-test"],
      "checkpoints": ["pr-address"],
      "state": "running",
      "last_output_hash": "",
      "last_seen_at": 0,
      "spawned_at": 0,
      "idle_since": 0,
      "revision_count": 0,
      "last_rebriefed_at": 0
    }
  ]
}

Top-level optional fields:

  • repo — GitHub owner/repo for CI/thread checks. Auto-derived from git remote if omitted.
  • discord_webhook — Discord webhook URL for completion notifications. Also reads DISCORD_WEBHOOK_URL env var.

Per-agent fields:

  • session_id — UUID passed to claude --session-id at spawn; use with claude --resume UUID to restore exact session context after a crash or window close.
  • last_rebriefed_at — Unix timestamp of last re-brief; enforces 5-min cooldown to prevent spam.

Agent states: running | idle | stuck | waiting_approval | complete | done | escalated

done means verified complete — window is still open, session still alive, worktree still on task branch. Not recycled yet.

Serial /pr-test rule

/pr-test and /pr-test --fix run local Docker + integration tests that use shared ports, a shared database, and shared build caches. Running two /pr-test jobs simultaneously will cause port conflicts and database corruption.

Rule: only one /pr-test runs at a time. The orchestrator serializes them.

You (the orchestrating Claude) own the test queue:

  1. Agents do pr-review and pr-address in parallel — that's safe (they only push code and reply to GitHub).
  2. When a PR needs local testing, add it to your mental queue — don't give agents a pr-test step.
  3. Run /pr-test https://github.com/OWNER/REPO/pull/PR_NUMBER --fix yourself, sequentially.
  4. Feed results back to the relevant agent via tmux send-keys:
    tmux send-keys -t SESSION:WIN "Local tests for PR #N: <paste failure output or 'all passed'>. Fix any failures and push, then output ORCHESTRATOR:DONE."
    sleep 0.3
    tmux send-keys -t SESSION:WIN Enter
    
  5. Wait for CI to confirm green before marking the agent done.

If multiple PRs need testing at the same time, pick the one furthest along (fewest pending CI checks) and test it first. Only start the next test after the previous one completes.

Session restore (tested and confirmed)

Agent sessions are saved to disk. To restore a closed or crashed session:

# If session_id is in state (preferred):
NEW_WIN=$(tmux new-window -t SESSION -n WORKTREE_NAME -P -F '#{window_index}')
tmux send-keys -t "SESSION:${NEW_WIN}" "cd /path/to/worktree && claude --resume SESSION_ID --permission-mode bypassPermissions" Enter

# If no session_id (use --continue for most recent session in that directory):
tmux send-keys -t "SESSION:${NEW_WIN}" "cd /path/to/worktree && claude --continue --permission-mode bypassPermissions" Enter

--continue restores the full conversation history including all tool calls, file edits, and context. The agent resumes exactly where it left off. After restoring, update the window address in the state file:

jq --arg old "SESSION:OLD_WIN" --arg new "SESSION:NEW_WIN" \
  '(.agents[] | select(.window == $old)).window = $new' \
  ~/.claude/orchestrator-state.json > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

Intent → action mapping

Match the user's message to one of these intents:

The user says something like…What to do
"status", "what's running", "show agents"Run status.sh + capacity.sh, show output
"how many free", "capacity", "available worktrees"Run capacity.sh, show output
"start N agents on X, Y, Z" or "run these tasks: …"See Spawning agents below
"add task: …", "add one more agent for …"See Adding an agent below
"stop", "shut down", "pause the fleet"See Stopping below
"poll", "check now", "run a cycle"Run poll-cycle.sh, process actions
"recycle window X", "free up autogpt3"Run recycle-agent.sh directly

When the intent is ambiguous, show capacity first and ask what tasks to run.

Spawning agents

1. Resolve tmux session

tmux list-sessions -F "#{session_name}: #{session_windows} windows" 2>/dev/null

Use an existing session. Never create a tmux session from within Claude — it becomes a child of Claude's process and dies when the session ends. If no session exists, tell the user to run tmux new-session -d -s autogpt1 in their terminal first, then re-invoke /orchestrate.

2. Show available capacity

bash $SKILLS_DIR/capacity.sh $(git rev-parse --show-toplevel)

3. Collect tasks from the user

For each task, gather:

  • objective — what to do (e.g. "implement feature X and open a PR")
  • branch name — e.g. feat/my-feature (derive from objective if not given)
  • pr_number — GitHub PR number if working on an existing PR (for verification)
  • steps — required checkpoint names in order (e.g. pr-address pr-test) — derive from objective

Ask for idle_threshold_seconds only if the user mentions it (default: 300).

Never ask the user to specify a worktree — auto-assign from find-spare.sh.

4. Spawn one agent per task

# Get ordered list of spare worktrees
SPARE_LIST=$(bash $SKILLS_DIR/find-spare.sh $(git rev-parse --show-toplevel))

# For each task, take the next spare line:
WORKTREE_PATH=$(echo "$SPARE_LINE" | awk '{print $1}')
SPARE_BRANCH=$(echo "$SPARE_LINE" | awk '{print $2}')

# With PR number and required steps:
WINDOW=$(bash $SKILLS_DIR/spawn-agent.sh "$SESSION" "$WORKTREE_PATH" "$SPARE_BRANCH" "$NEW_BRANCH" "$OBJECTIVE" "$PR_NUMBER" "pr-address" "pr-test")

# Without PR (new work):
WINDOW=$(bash $SKILLS_DIR/spawn-agent.sh "$SESSION" "$WORKTREE_PATH" "$SPARE_BRANCH" "$NEW_BRANCH" "$OBJECTIVE")

Build an agent record and append it to the state file. If the state file doesn't exist yet, initialize it:

# Derive repo from git remote (used by verify-complete.sh + supervisor)
REPO=$(git remote get-url origin 2>/dev/null | sed 's|.*github\.com[:/]||; s|\.git$||' || echo "")

jq -n \
  --arg session "$SESSION" \
  --arg repo "$REPO" \
  --argjson threshold 300 \
  '{active:true, tmux_session:$session, idle_threshold_seconds:$threshold,
    repo:$repo, loop_window:null, supervisor_window:null, last_poll_at:0, agents:[]}' \
  > ~/.claude/orchestrator-state.json

Optionally add a Discord webhook for completion notifications:

jq --arg hook "$DISCORD_WEBHOOK_URL" '.discord_webhook = $hook' ~/.claude/orchestrator-state.json \
  > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

spawn-agent.sh writes the initial agent record (window, worktree_path, branch, objective, state, etc.) to the state file automatically — do not append the record again after calling it. The record already exists and pr_number/steps are patched in by the script itself.

5. Start the mechanical babysitter

LOOP_WIN=$(tmux new-window -t "$SESSION" -n "orchestrator" -P -F '#{window_index}')
LOOP_WINDOW="${SESSION}:${LOOP_WIN}"
tmux send-keys -t "$LOOP_WINDOW" "bash $SKILLS_DIR/run-loop.sh" Enter

jq --arg w "$LOOP_WINDOW" '.loop_window = $w' ~/.claude/orchestrator-state.json \
  > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

6. Begin supervising directly in this conversation

You are the supervisor. After spawning, immediately start your first poll loop (see Supervisor duties below) and continue every 2-3 minutes. Do NOT spawn a separate supervisor Claude window.

Adding an agent

Find the next spare worktree, then spawn and append to state — same as steps 2–4 above but for a single task. If no spare worktrees are available, tell the user.

Supervisor duties (YOUR job, every 2-3 min in this conversation)

You are the supervisor. Run this poll loop directly in your Claude session — not in a separate window.

Poll loop mechanism

You are reactive — you only act when a tool completes or the user sends a message. To create a self-sustaining poll loop without user involvement:

  1. Start each poll with run_in_background: true + a sleep before the work:
    sleep 120 && tmux capture-pane -t autogpt1:0 -p -S -200 | tail -40
    # + similar for each active window
    
  2. When the background job notifies you, read the pane output and take action.
  3. Immediately schedule the next background poll — this keeps the loop alive.
  4. Stop scheduling when all agents are done/escalated.

Never tell the user "I'll poll every 2-3 minutes" — that does nothing without a trigger. Start the background job instead.

Each poll: what to check

# 1. Read state
cat ~/.claude/orchestrator-state.json | jq '.agents[] | {window, worktree, branch, state, pr_number, checkpoints}'

# 2. For each running/stuck/idle agent, capture pane
tmux capture-pane -t SESSION:WIN -p -S -200 | tail -60

For each agent, decide:

What you seeAction
Spinner / tools runningDo nothing — agent is working
Idle ❯ prompt, no ORCHESTRATOR:DONEStalled — send specific nudge with objective from state
Stuck in error loopSend targeted fix with exact error + solution
Waiting for input / questionAnswer and unblock via tmux send-keys
CI redgh pr checks PR_NUMBER --repo REPO → tell agent exactly what's failing
GitHub abuse rate limit errorNudge: "Wait 60 seconds then continue posting replies with sleep 3 between each"
Context compacted / agent lostSend recovery: `cat ~/.claude/orchestrator-state.json
ORCHESTRATOR:DONE in outputQuery GraphQL for actual unresolved count. If >0, re-brief. If 0, run verify-complete.sh

Poll all windows from state, not from memory. Before each poll, run:

jq -r '.agents[] | select(.state | test("running|idle|stuck|waiting_approval|pending_evaluation")) | .window' ~/.claude/orchestrator-state.json

and capture every window listed. If you manually added a window outside spawn-agent.sh, ensure it's in the state file first.

RUNNING count includes waiting_approval agents

The RUNNING count from run-loop.sh includes agents in waiting_approval state (they match the regex running|stuck|waiting_approval|idle). This means a fleet that is only waiting_approval still shows RUNNING > 0 in the log — it does not mean agents are actively working.

When you see RUNNING > 0 in the run-loop log but suspect agents are actually blocked, check state directly:

jq '.agents[] | {window, state, worktree}' ~/.claude/orchestrator-state.json

A count of running=1 waiting=1 in the log actually means one agent is waiting for approval — the orchestrator should check and approve, not wait.

State file staleness recovery

The state file is written by scripts but can drift from reality when windows are closed, sessions expire, or the orchestrator restarts across conversations.

Signs of stale state:

  • loop_window points to a window that no longer exists in the tmux session
  • An agent's state is running but tmux window is closed or shows a shell prompt (not claude)
  • last_seen_at is hours old but state still says running

Recovery steps:

  1. Verify actual tmux windows:
tmux list-windows -t SESSION -F '#{window_index}: #{window_name} (#{pane_current_command})'
  1. Cross-reference with state file:
jq -r '.agents[] | "\(.window) \(.state) \(.worktree)"' ~/.claude/orchestrator-state.json
  1. Fix stale entries:
# Agent window closed — mark idle so run-loop.sh will restart it
jq --arg w "SESSION:WIN" '(.agents[] | select(.window==$w)).state = "idle"' \
  ~/.claude/orchestrator-state.json > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

# loop_window gone — kill the stale reference, then restart run-loop.sh
jq '.loop_window = null' ~/.claude/orchestrator-state.json > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json
LOOP_WIN=$(tmux new-window -t "$SESSION" -n "orchestrator" -P -F '#{window_index}')
LOOP_WINDOW="${SESSION}:${LOOP_WIN}"
tmux send-keys -t "$LOOP_WINDOW" "bash $SKILLS_DIR/run-loop.sh" Enter
jq --arg w "$LOOP_WINDOW" '.loop_window = $w' ~/.claude/orchestrator-state.json \
  > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json
  1. After any state repair, re-run status.sh to confirm coherence before resuming supervision.

Strict ORCHESTRATOR:DONE gate

verify-complete.sh handles the main checks automatically (checkpoints, threads, CI green, spawned_at, and CHANGES_REQUESTED). Run it:

CHANGES_REQUESTED staleness rule: a CHANGES_REQUESTED review only blocks if it was submitted after the latest commit. If the latest commit postdates the review, the review is considered stale (feedback already addressed) and does not block. This avoids false negatives when a bot reviewer hasn't re-reviewed after the agent's fixing commits.

SKILLS_DIR=~/.claude/orchestrator/scripts
bash $SKILLS_DIR/verify-complete.sh SESSION:WIN

If it passes → run-loop.sh will recycle the window automatically. No manual action needed. If it fails → re-brief the agent with the failure reason. Never manually mark state done to bypass this.

Re-brief a stalled agent

Before sending any nudge, verify the pane is at an idle ❯ prompt. Sending text into a still-processing pane produces stuck [Pasted text +N lines] that the agent never sees.

Check:

tmux capture-pane -t SESSION:WIN -p 2>/dev/null | tail -5

If the last line shows a spinner (✳✽✢✶·), Running…, or no ❯ — wait 10–15s and check again before sending.

OBJ=$(jq -r --arg w SESSION:WIN '.agents[] | select(.window==$w) | .objective' ~/.claude/orchestrator-state.json)
PR=$(jq -r --arg w SESSION:WIN '.agents[] | select(.window==$w) | .pr_number' ~/.claude/orchestrator-state.json)
tmux send-keys -t SESSION:WIN "You appear stalled. Your objective: $OBJ. Check: gh pr view $PR --json title,body,headRefName to reorient."
sleep 0.3
tmux send-keys -t SESSION:WIN Enter

If image_path is set on the agent record, include: "Re-read context at IMAGE_PATH with the Read tool."

Self-recovery protocol (agents)

spawn-agent.sh automatically includes this instruction in every objective:

If your context compacts and you lose track of what to do, run: cat ~/.claude/orchestrator-state.json | jq '.agents[] | select(.window=="SESSION:WIN")' and gh pr view PR_NUMBER --json title,body,headRefName to reorient. Output each completed step as CHECKPOINT:<step-name> on its own line.

Passing images and screenshots to agents

tmux send-keys is text-only — you cannot paste a raw image into a pane. To give an agent visual context (screenshots, diagrams, mockups):

  1. Save the image to a temp file with a stable path:

    # If the user drags in a screenshot or you receive a file path:
    IMAGE_PATH="/tmp/orchestrator-context-$(date +%s).png"
    cp "$USER_PROVIDED_PATH" "$IMAGE_PATH"
    
  2. Reference the path in the objective string:

    OBJECTIVE="Implement the layout shown in /tmp/orchestrator-context-1234567890.png. Read that image first with the Read tool to understand the design."
    
  3. The agent uses its Read tool to view the image at startup — Claude Code agents are multimodal and can read image files directly.

Rule: always use /tmp/orchestrator-context-<timestamp>.png as the naming convention so the supervisor knows what to look for if it needs to re-brief an agent with the same image.


Orchestrator final evaluation (YOU decide, not the script)

verify-complete.sh is a gate — it blocks premature marking. But it cannot tell you if the work is actually good. That is YOUR job.

When run-loop marks an agent pending_evaluation and you're notified, do all of these before marking done:

1. Run /pr-test (required, serialized, use TodoWrite to queue)

/pr-test is the only reliable confirmation that the objective is actually met. Run it yourself, not the agent.

When multiple PRs reach pending_evaluation at the same time, use TodoWrite to queue them:

- [ ] /pr-test https://github.com/Significant-Gravitas/AutoGPT/pull/NNNN — <feature description>
- [ ] /pr-test https://github.com/Significant-Gravitas/AutoGPT/pull/MMMM — <feature description>

Run one at a time. Check off as you go.

/pr-test https://github.com/Significant-Gravitas/AutoGPT/pull/PR_NUMBER

/pr-test can be lazy — if it gives vague output, re-run with full context:

/pr-test https://github.com/OWNER/REPO/pull/PR_NUMBER
Context: This PR implements <objective from state file>. Key files: <list>.
Please verify: <specific behaviors to check>.

Only one /pr-test at a time — they share ports and DB.

/pr-test result evaluation

PARTIAL on any headline feature scenario is an immediate blocker. Do not approve, do not mark done, do not let the agent output ORCHESTRATOR:DONE.

/pr-test resultAction
All headline scenarios PASSProceed to evaluation step 2
Any headline scenario PARTIALRe-brief the agent immediately — see below
Any headline scenario FAILRe-brief the agent immediately

What PARTIAL means: the feature is only partly working. Example: the Apply button never appeared, or the AI returned no action blocks. The agent addressed part of the objective but not all of it.

When any headline scenario is PARTIAL or FAIL:

  1. Do NOT mark the agent done or accept ORCHESTRATOR:DONE
  2. Re-brief the agent with the specific scenario that failed and what was missing:
    tmux send-keys -t SESSION:WIN "PARTIAL result on /pr-test — S5 (Apply button) never appeared. The AI must output JSON action blocks for the Apply button to render. Fix this before re-running /pr-test."
    sleep 0.3
    tmux send-keys -t SESSION:WIN Enter
    
  3. Set state back to running:
    jq --arg w "SESSION:WIN" '(.agents[] | select(.window == $w)).state = "running"' \
      ~/.claude/orchestrator-state.json > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json
    
  4. Wait for new ORCHESTRATOR:DONE, then re-run /pr-test from scratch

Rule: only ALL-PASS qualifies for approval. A mix of PASS + PARTIAL is a failure.

Why this matters: A PR was once wrongly approved with S5 PARTIAL — the AI never output JSON action blocks so the Apply button never appeared. The fix was already in the agent's reach but slipped through because PARTIAL was not treated as blocking.

2. Do your own evaluation

  1. Read the PR diff and objective — does the code actually implement what was asked? Is anything obviously missing or half-done?
  2. Read the resolved threads — were comments addressed with real fixes, or just dismissed/resolved without changes?
  3. Check CI run names — any suspicious retries that shouldn't have passed?
  4. Check the PR description — title, summary, test plan complete?

3. Decide

  • /pr-test all scenarios PASS + evaluation looks good → mark done in state, tell the user the PR is ready, ask if window should be closed
  • /pr-test any scenario PARTIAL or FAIL → re-brief the agent with the specific failing scenario, set state back to running (see /pr-test result evaluation above)
  • Evaluation finds gaps even with all PASS → re-brief the agent with specific gaps, set state back to running

Never mark done based purely on script output. You hold the full objective context; the script does not.

# Mark done after your positive evaluation:
jq --arg w "SESSION:WIN" '(.agents[] | select(.window == $w)).state = "done"' \
  ~/.claude/orchestrator-state.json > /tmp/orch.tmp && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

When to stop the fleet

Stop the fleet (active = false) when all of the following are true:

CheckHow to verify
All agents are done or escalated`jq '[.agents[]
All PRs have 0 unresolved review threadsGraphQL isResolved check per PR
All PRs have green CI on a run triggered after the agent's last pushgh run list --branch BRANCH --limit 1 timestamp > spawned_at in state
No fresh CHANGES_REQUESTED (after latest commit)verify-complete.sh checks this — stale pre-commit reviews are ignored
No agents are escalated without human reviewIf any are escalated, surface to user first

Do NOT stop just because agents output ORCHESTRATOR:DONE. That is a signal to verify, not a signal to stop.

Do stop if the user explicitly says "stop", "shut down", or "kill everything", even with agents still running.

# Graceful stop
jq '.active = false' ~/.claude/orchestrator-state.json > /tmp/orch.tmp \
  && mv /tmp/orch.tmp ~/.claude/orchestrator-state.json

LOOP_WINDOW=$(jq -r '.loop_window // ""' ~/.claude/orchestrator-state.json)
[ -n "$LOOP_WINDOW" ] && tmux kill-window -t "$LOOP_WINDOW" 2>/dev/null || true

Does not recycle running worktrees — agents may still be mid-task. Run capacity.sh to see what's still in progress.

tmux send-keys pattern

Always split long messages into text + Enter as two separate calls with a sleep between them. If sent as one call ("text" Enter), Enter can fire before the full string is buffered into Claude's input — leaving the message stuck as [Pasted text +N lines] unsent.

# CORRECT — text then Enter separately
tmux send-keys -t "$WINDOW" "your long message here"
sleep 0.3
tmux send-keys -t "$WINDOW" Enter

# WRONG — Enter may fire before text is buffered
tmux send-keys -t "$WINDOW" "your long message here" Enter

Short single-character sends (y, Down, empty Enter for dialog approval) are safe to combine since they have no buffering lag.


Protected worktrees

Some worktrees must never be used as spare worktrees for agent tasks because they host files critical to the orchestrator itself:

WorktreeProtected branchWhy
AutoGPT1dx/orchestrate-skillHosts the orchestrate skill scripts. recycle-agent.sh would check out spare/1, wiping .claude/skills/ and breaking all subsequent spawn-agent.sh calls.

Rule: when selecting spare worktrees via find-spare.sh, skip any worktree whose CURRENT branch matches a protected branch. If you accidentally spawn an agent in a protected worktree, do not let recycle-agent.sh run on it — manually restore the branch after the agent finishes.

When dx/orchestrate-skill is merged into dev, AutoGPT1 becomes a normal spare again.


Thread resolution integrity (critical)

Agents MUST NOT resolve review threads via GraphQL unless a real code fix has been committed and pushed first.

This is the most common failure mode: agents call resolveReviewThread to make unresolved counts drop without actually fixing anything. This produces a false "done" signal that gets past verify-complete.sh.

The only valid resolution sequence:

  1. Read the thread and understand what it's asking
  2. Make the actual code change
  3. git commit and git push
  4. Reply to the thread with the commit SHA (e.g. "Fixed in abc1234")
  5. THEN call resolveReviewThread

The supervisor must verify actual thread counts via GraphQL — never trust an agent's claim of "0 unresolved." After any agent's ORCHESTRATOR:DONE, always run:

# Step 1: get total count
TOTAL=$(gh api graphql -f query='{ repository(owner: "OWNER", name: "REPO") { pullRequest(number: PR) { reviewThreads { totalCount } } } }' \
  | jq '.data.repository.pullRequest.reviewThreads.totalCount')
echo "Total threads: $TOTAL"

# Step 2: paginate all pages and count unresolved
CURSOR=""; UNRESOLVED=0
while true; do
  AFTER=${CURSOR:+", after: \"$CURSOR\""}
  PAGE=$(gh api graphql -f query="{ repository(owner: \"OWNER\", name: \"REPO\") { pullRequest(number: PR) { reviewThreads(first: 100${AFTER}) { pageInfo { hasNextPage endCursor } nodes { isResolved } } } } }")
  UNRESOLVED=$(( UNRESOLVED + $(echo "$PAGE" | jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false)] | length') ))
  HAS_NEXT=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')
  CURSOR=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor')
  [ "$HAS_NEXT" = "false" ] && break
done
echo "Unresolved: $UNRESOLVED"

If unresolved > 0, the agent is NOT done — re-brief with the actual count and the rule.

Include this in every agent objective:

IMPORTANT: Do NOT resolve any review thread via GraphQL unless the code fix is committed and pushed first. Fix the code → commit → push → reply with SHA → then resolve. Never resolve without a real commit. "Accepted" or "Acknowledged" replies are NOT resolutions — only real commits qualify.

Detecting fake resolutions

When an agent claims "0 unresolved threads", query GitHub GraphQL yourself and also inspect how each thread was resolved. A resolved thread whose last comment is "Acknowledged", "Same as above", "Accepted trade-off", or "Deferred" — with no commit SHA — is a fake resolution.

To spot these, paginate all pages and collect resolved threads with missing SHA links:

# Paginate all pages — first:100 misses threads beyond page 1 on large PRs
CURSOR=""; FAKE_RESOLUTIONS="[]"
while true; do
  AFTER=${CURSOR:+", after: \"$CURSOR\""}
  PAGE=$(gh api graphql -f query="
  {
    repository(owner: \"Significant-Gravitas\", name: \"AutoGPT\") {
      pullRequest(number: PR_NUMBER) {
        reviewThreads(first: 100${AFTER}) {
          pageInfo { hasNextPage endCursor }
          nodes {
            isResolved
            comments(last: 1) {
              nodes { body author { login } }
            }
          }
        }
      }
    }
  }")
  PAGE_FAKES=$(echo "$PAGE" | jq '[.data.repository.pullRequest.reviewThreads.nodes[]
    | select(.isResolved == true)
    | {body: .comments.nodes[0].body[:120], author: .comments.nodes[0].author.login}
    | select(.body | test("Fixed in|Removed in|Addressed in") | not)]')
  FAKE_RESOLUTIONS=$(echo "$FAKE_RESOLUTIONS $PAGE_FAKES" | jq -s 'add')
  HAS_NEXT=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage')
  CURSOR=$(echo "$PAGE" | jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor')
  [ "$HAS_NEXT" = "false" ] && break
done
echo "$FAKE_RESOLUTIONS"

Any resolved thread whose last comment does NOT contain "Fixed in", "Removed in", or "Addressed in" (with a commit link) should be investigated — either the agent falsely resolved it, or it was a genuine false positive that needs explanation.

GitHub abuse rate limits

Two distinct rate limits exist with different recovery times:

ErrorHTTP statusCauseRecovery
{"code":"abuse"} in body403Secondary rate limit — too many write operations (comments, mutations) in a short windowWait 2–3 minutes. 60s is often not enough.
API rate limit exceeded429Primary rate limit — too many read calls per hourWait until X-RateLimit-Reset timestamp

Prevention: Agents must add sleep 3 between individual thread reply API calls. For >20 unresolved threads, increase to sleep 5.

If you see a 403 abuse error from an agent's pane:

  1. Nudge the agent: "You hit a GitHub secondary rate limit (403). Stop all API writes. Wait 2 minutes, then resume with sleep 3 between each thread reply."
  2. Do NOT nudge again during the 2-minute wait — a second nudge restarts the clock.

Add this to agent briefings when there are >20 unresolved threads:

Post replies with sleep 3 between each reply. If you hit a 403 abuse error, wait 2 minutes (not 60s — secondary limits take longer to clear) then continue.

Key rules

  1. Scripts do all the heavy lifting — don't reimplement their logic inline in this file
  2. Never ask the user to pick a worktree — auto-assign from find-spare.sh output
  3. Never restart a running agent — only restart on idle kicks (foreground is a shell)
  4. Auto-dismiss settings dialogs — if "Enter to confirm" appears, send Down+Enter
  5. Always --permission-mode bypassPermissions on every spawn
  6. Escalate after 3 kicks — mark escalated, surface to user
  7. Atomic state writes — always write to .tmp then mv
  8. Never approve destructive commands outside the worktree scope — when in doubt, escalate
  9. Never recycle without verification — verify-complete.sh must pass before recycling
  10. No TASK.md files — commit risk; use state file + gh pr view for agent context persistence
  11. Re-brief stalled agents — read objective from state file + gh pr view, send via tmux
  12. ORCHESTRATOR:DONE is a signal to verify, not to accept — always run verify-complete.sh and check CI run timestamp before recycling
  13. Protected worktrees — never use the worktree hosting the skill scripts as a spare
  14. Images via file path — save screenshots to /tmp/orchestrator-context-<ts>.png, pass path in objective; agents read with the Read tool
  15. Split send-keys — always separate text and Enter with sleep 0.3 between calls for long strings
  16. Poll ALL windows from state file — never hardcode window count. Derive active windows dynamically: jq -r '.agents[] | select(.state | test("running|idle|stuck")) | .window' ~/.claude/orchestrator-state.json. If you added a window mid-session outside spawn-agent.sh, add it to the state file immediately.
  17. Orchestrator handles its own approvals — when spawning a subagent to make edits (SKILL.md, scripts, config), review the diff yourself and approve/reject without surfacing it to the user. The user should never have to open a file to check the orchestrator's work. Use the Agent tool with subagent_type: general-purpose for drafting, then verify the result yourself before considering the task done.
  18. Update state file on re-task — whenever an agent is re-tasked mid-session (objective changes, new PR assigned), update the state file record immediately so objectives stay accurate for re-briefing after compaction.
  19. No GraphQL resolveReviewThread without a commit — see Thread resolution integrity above. This is rule #1 for pr-address work.
  20. Verify thread counts yourself — after any agent claims "0 unresolved threads", query GitHub GraphQL directly before accepting. Never trust the agent's self-report.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

open-pr

무료요약 있음

코드 변경의 테스트와 기존 기능에 미치는 영향을 확인하고 저장소 템플릿에 맞춰 PR을 생성하며, 리뷰 요청부터 지적 사항 대응까지 진행합니다.

  • 지정된 템플릿으로 PR 생성
  • 기존 동작과 새 기능의 테스트 확인
  • 로컬 검증이 어려울 때 봇 리뷰 요청
Significant-Gravitas/AutoGPT18.8만2026년 10월 23일 업데이트

perf-compare

무료요약 있음

Sentry 데이터로 변경 전후나 환경 간 속도와 실패율을 비교합니다. 통계적 변동을 고려해 빨라짐, 느려짐, 변화 감지 안 됨, 데이터 부족을 판정합니다.

  • 릴리스 전후 성능 비교
  • 미리 보기 환경과 대조 환경 검증
  • 다른 처리의 성능 저하 확인
Significant-Gravitas/AutoGPT18.8만2026년 10월 23일 업데이트

pr-address

무료요약 있음

PR 검토 의견을 모아 코드 수정, 커밋, 답변과 스레드 해결을 진행합니다. CI 실패, 충돌, 새 댓글도 계속 확인하며 대응이 끝날 때까지 추적합니다.

  • PR 검토에서 지적된 코드 수정
  • 사람과 봇의 검토 의견에 답변
  • 푸시 후 CI 실패 조사와 수정
Significant-Gravitas/AutoGPT18.8만2026년 10월 23일 업데이트

pr-polish

무료요약 있음

PR 검토와 수정을 반복하며 미해결 의견, CI 실패, 병합 충돌을 확인합니다. 늦게 도착하는 댓글도 기다려 PR을 병합할 수 있는 상태로 정리합니다.

  • PR을 병합 가능한 상태로 정리
  • 새 지적이 없어질 때까지 수정
  • 늦게 도착하는 봇 검토에 대응
Significant-Gravitas/AutoGPT18.8만2026년 10월 23일 업데이트

pr-review

무료요약 있음

코드 변경 제안인 PR의 목적과 차이를 읽고 정확성, 보안, 설계, 테스트를 점검합니다. 기존 의견과 중복되지 않도록 심각도를 붙여 해당 코드 줄에 댓글을 게시합니다.

  • 병합 전 PR 검토
  • 코드 변경의 보안 점검
  • 경계 조건의 테스트 누락 확인
Significant-Gravitas/AutoGPT18.8만2026년 10월 23일 업데이트

pr-test

무료요약 있음

실행 중인 시스템에서 PR이나 브랜치 변경을 조작하고 화면, API, 저장 데이터의 변화를 대조하여 작업 전후 스크린샷과 함께 검증 결과를 보고합니다.

  • 화면과 API로 PR 전체 흐름 테스트
  • 화면, API, 저장 데이터의 변화 대조
  • 잘못된 입력 등 예외 상황 검증
Significant-Gravitas/AutoGPT18.8만2026년 10월 23일 업데이트

Significant-Gravitas의 스킬 모두 보기

이 스킬의 문제 신고