| name | pinpoint-orchestrator |
| description | Orchestrate parallel subagent work in git worktrees — task selection, end-to-end dispatch, monitoring, follow-up, and cleanup. |
Pinpoint Orchestrator
Coordinate multiple subagents working in parallel across isolated git worktrees.
When to Use This Skill
- Multiple independent beads issues ready to work (
bd ready shows 2+ items)
- Assigning an issue end-to-end to a subagent (implement → PR → CI green)
- Review feedback on multiple PRs needs addressing
- Parallel feature development across branches
- User says "spin up agents", "orchestrate", "parallel work", "dispatch"
Scripts Reference
./scripts/workflow/orchestration-status.sh
./scripts/workflow/orchestration-status.sh --prs-only
./scripts/workflow/orchestration-status.sh --security-only
./scripts/workflow/pr-dashboard.sh [PR numbers...]
./scripts/workflow/pr-watch.py <PR>
./scripts/workflow/pr-watch.py --check-ready <PR>
bash scripts/workflow/merge-pr.sh <PR>
bash scripts/workflow/merge-pr.sh <PR> --dry-run
bash scripts/workflow/mark-claude-review.sh <PR> "<summary>"
./scripts/workflow/stale-worktrees.sh
./scripts/workflow/stale-worktrees.sh --clean
git worktree list
python3 scripts/worktree_cleanup.py <worktree-path>
Lead Orchestrator Role
You are a coordinator, not an implementer:
- DO launch subagents, review their output, send them follow-up corrections
- DO check CI dashboards, manage beads
- DON'T directly fix code in worktrees — message the subagent instead
If a subagent can't be reached (GC'd, session ended), spawn a new one on the same branch.
Phase 1: Task Selection
bd ready
bd list --status=open
Present options to user. Before proceeding, verify tasks are independent:
- No task blocks another (
bd show <id>)
- Tasks don't modify the same files
Phase 2: Worktree Setup
isolation: "worktree" handles creation automatically. The Husky post-checkout hook runs scripts/worktree_setup.py to allocate ports and generate configs.
Known bug — dispatch-from-linked-worktree (anthropics/claude-code#47548): Dispatching Agent(isolation: "worktree") from inside a linked (non-primary) worktree, e.g. .claude/worktrees/agent-*, silently switches the parent worktree's branch to the subagent's new branch. Fires at N=1. Always dispatch from the main worktree — the original clone where .git/ is a directory. The WorktreeCreate hook does NOT fix this bug (it is path-based, not race-based).
Parallel-batch race mitigated — hook active (anthropics/claude-code#47266): The .claude/hooks/worktree-create.sh hook (PP-bg45) wraps git worktree add with lockf(1) (macOS flock(2) equivalent) on ~/.config/pinpoint/worktree-add.lock — a kernel-level lock shared across all Claude sessions on the host — plus retry + exponential backoff. Any N Agent(isolation: "worktree") calls per message are now safe from the main worktree — the hook serializes worktree creation at the OS level. The prior N=1-per-message rule from PR #1353 is relaxed.
Fallback: If the hook is disabled or missing, revert to the N=1-per-message rule: dispatch one, confirm .claude/worktrees/agent-* appeared on disk, then dispatch the next.
Manual worktree creation is for the lead's own use only:
git worktree add ../pinpoint-worktrees/<branch-name> -b <branch-name>
Phase 3: Agent Dispatch
Agent(
subagent_type: "general-purpose",
isolation: "worktree",
run_in_background: true,
mode: "bypassPermissions",
name: "<short-name>", # optional but useful — makes the agent addressable via SendMessage({to: name})
prompt: "<full prompt — see template below>"
)
Model: omit model to inherit the session model (usually correct). Override only when confident a tier fits: a heavier model for judgment-heavy work, a lighter one for mechanical, well-specified changes.
Quality is self-enforced — hooks don't fire for subagents. Keep the prompt small — the bead is the source of truth and the subagent can read it. Every prompt MUST include:
- The bead ID + "First run
bd show <id> && bd update <id> --claim, then work from the bead." The bead carries scope, files, line numbers, and acceptance criteria — do NOT restate them in the prompt (two places to drift).
- Only context that ISN'T already in the bead — cross-bead conflicts, a reference PR, sequencing constraints. Omit when there's nothing to add.
- Quality gate: "Run
pnpm run check before returning."
- Full PR lifecycle: "Create PR, verify CI green."
- Structured return format: branch, PR#, CI status, blockers
Prompt template:
## Task
Work bead <ID>. First run `bd show <ID>` && `bd update <ID> --claim` — the bead is the spec. Implement exactly what it describes; don't expand scope.
## Context not in the bead
<only what the bead doesn't already say — cross-bead conflicts, reference PRs, sequencing. Omit this section entirely if there's nothing to add.>
## Quality Gates
Run `pnpm run check` before returning. Then self-review: run `/code-review` on your own diff (the model-invocable local review — **not** `ultra`, which is user-triggered/billed and you cannot launch) and address serious findings. After your final push, if Copilot hasn't reviewed your head commit within ~10 min, run `bash scripts/workflow/mark-claude-review.sh <PR> "<summary>"` so the `reviewed` merge gate passes.
## Return Format
Report back with:
- **Branch**: <branch name>
- **PR**: #<number>
- **CI**: passing/failing/pending
- **Self-review**: findings addressed / marker posted?
- **Blockers**: none or description
Full annotated version: references/agent-prompt-template.md.
The bead must be complete — especially for mechanical refactors. Because the agent executes the bead literally and you're no longer restating scope in the prompt, the bead has to carry it. A "convert/rename only X" bead MUST include an explicit out-of-scope list naming the look-alikes that are intentionally excluded, and why — otherwise the agent over-scopes. Casework: a "convert 2 catch blocks to the err() helper" bead ballooned to 6, Sentry-wrapping a rate-limit guard and a Zod-validation guard that are expected user conditions, not server errors (PR #1247 → reverted in #1250). If the bead doesn't say "don't touch Y," the agent will.
Phase 4: Monitor Loop
Dashboard
./scripts/workflow/pr-dashboard.sh 940 941 942
./scripts/workflow/pr-dashboard.sh
./scripts/workflow/pr-watch.py <PR>
Follow-Up via SendMessage
A spawned agent keeps its context — continue it with SendMessage using its ID or name rather than spawning fresh. Common scenarios:
- CI fails → get failure logs → send failure context
- User requests changes → send review feedback
Handle Failures
CI fails → Get context, then message the subagent:
gh run view <run-id> --log-failed | tail -50
Review comments → Inspect via MCP (see pinpoint-pr-workflow skill Phase 3.2-3.3), then message the subagent:
mcp__github__pull_request_read(method: "get_review_comments", owner, repo, pullNumber, perPage: 100)
Infrastructure failures:
gh run rerun <run-id> --failed
Label Ready PRs
See pinpoint-pr-workflow skill Phase 3.4. Apply ready-for-review after CI green + zero unresolved review threads via:
mcp__github__issue_write(method: "update", owner, repo, issue_number: <PR>, labels: [<existing>..., "ready-for-review"])
Or fallback: gh pr edit <PR> --add-label ready-for-review.
Ensure every PR is reviewed (lead backstop)
The subagent self-reviews its own diff (Phase 3 template), but that can be skipped or Copilot can silently miss the head commit — so the lead re-checks at the merge boundary. Before applying ready-for-review or handing a PR to merge-pr.sh, confirm the head commit is covered by either a Copilot review or a SHA-pinned Claude marker (<!-- pinpoint-claude-review: <head_sha> -->). If neither covers head:
- Run
/code-review on the PR diff — the model-invocable local review. (ultra is the cloud multi-agent review; it is user-triggered and billed, so the agent cannot launch it.)
- Address serious findings (fix → have the subagent push → re-review; a fix re-arms the gate). Decline the rest.
bash scripts/workflow/mark-claude-review.sh <PR> "<summary>" to post the marker.
The reviewed gate in merge-pr.sh is the hard enforcement — it FAILs the merge if the head commit has no Copilot or Claude review once the 600s Copilot window has elapsed. Running the fallback is how you satisfy it; --force-bypassing it defeats the guarantee.
Phase 5: Completion
Beads Issue Lifecycle
Do NOT close beads issues when a PR is created. Issues stay in_progress until PR merges.
| Event | Beads Action |
|---|
| Agent creates PR | Issue stays in_progress |
| PR merges | bd close <id> --reason="PR #N merged" |
| PR closed without merge | bd update <id> --status=open |
Final Summary
## Orchestration Complete
PRs Ready for Review:
- #123: Fix machine dropdown — All checks passing
PRs Needing Attention:
- #124: Add owner link — CI failing
Remaining Worktrees:
- feat/task-def (PR #124 needs work)
Cleanup
Worktrees created by Agent(isolation: "worktree") are cleaned up by Claude Code's WorktreeRemove hook (runs scripts/worktree_cleanup.py). For manually created worktrees, run the script yourself — plain git worktree remove leaks slot entries and Docker volumes:
python3 scripts/worktree_cleanup.py ../pinpoint-worktrees/<branch>
Proactive Beads Maintenance
On Session Start
bd ready -n 50 (default limit is 10, which hides work)
bd list --status=in_progress to check for stale in-progress issues
- Cross-reference: any in-progress issues whose PRs are already merged? Close them
- Check for closed issues still blocking others (
bd blocked → bd dep remove)
During Work
- PR merges → immediately close the beads issue
- Agent creates PR → issue stays
in_progress
- Discover new work →
bd create
- Stale dependencies →
bd dep remove to unblock
On Session End
bd list --status=in_progress — anything done? Close it
bd dolt pull if using beads remote sync
Anti-Patterns
- DON'T assume hooks enforce quality for subagents — include
pnpm run check in the prompt
- DON'T fix code yourself as the orchestrator — message the subagent
- DON'T dispatch from a linked worktree — bug #47548 (see Phase 2)
Error Recovery
| Problem | Fix |
|---|
| Subagent fails to create PR | Check output, verify worktree state, message it with context |
| Permission denied on worktree | Add paths to .claude/settings.json, restart session |
| Worktree creation fails | supabase stop (current worktree only — never --all), then re-create with git worktree add |
.git/config.lock race on parallel dispatch | anthropics/claude-code#47266 — the WorktreeCreate hook mitigates this. Verify worktree-create.sh is registered in .claude/settings.json; only if missing/disabled, serialize to one dispatch per message |
| Parent branch flips after dispatch | anthropics/claude-code#47548. You dispatched from a linked worktree. Always dispatch from the main worktree |
| Husky post-checkout hook fails | Check .husky/post-checkout for merge conflict markers |