Orchestrator
Purpose
The orchestrator manages the agent lifecycle for a project. It detects ready issues from configured backends (GitHub, Linear, or tk), spawns agents with isolated worktrees, tracks ticket claims to prevent duplicate work, and coordinates merge/push operations when agents complete their tasks.
Non-goals: The orchestrator does not implement issue tracking itself (delegated to backends), does not directly execute code (delegated to agents), and does not manage cross-project coordination (each project has its own orchestrator).
Interface
CLI Commands
| Command | Description |
|---|---|
fab agent list |
List all running agents |
fab agent claim <ticket-id> |
Claim a ticket (run inside agent worktree) |
fab agent done |
Signal task completion and trigger merge |
fab agent describe <desc> |
Set agent status description |
fab agent abort <id> |
Stop an agent gracefully or forcefully |
fab claims |
List active ticket claims |
Key Types
The orchestrator coordinates several components:
- Orchestrator: Main loop that polls for ready issues and spawns agents
- ClaimRegistry: In-memory map preventing duplicate ticket claims
- CommitLog: Bounded log of successfully merged agent work
- Agent: Claude Code subprocess working in an isolated worktree
- Worktree: Git worktree at
~/.fab/projects/<project>/worktrees/wt-{agentID}
Configuration
Project-level configuration in ~/.config/fab/config.toml:
[[projects]]
name = "myapp"
max-agents = 3 # Concurrent agents (default: 3)
issue-backend = "tk" # tk, github, or linear
merge-strategy = "direct" # direct or pull-request
coding-backend = "claude" # Agent CLI backend
Internal orchestrator config (set programmatically):
| Option | Default | Description |
|---|---|---|
PollInterval |
10s | Time between ready issue checks |
InterventionSilence |
60s | Pause automation after user input |
KickstartPrompt |
(builtin) | Initial instructions sent to agents |
Verification
Run the orchestrator unit tests:
$ go test ./internal/orchestrator/... -v
=== RUN TestClaimRegistry_Claim
Check that the claims registry prevents duplicate claims:
$ go test ./internal/orchestrator/... -run TestClaimRegistry -v
--- PASS: TestClaimRegistry_Claim
Examples
Typical Agent Lifecycle
- Orchestrator detects ready issue: Polls issue backend every 10s
- Agent spawns: Creates worktree
wt-{agentID}and branchfab/{agentID} - Agent claims issue:
fab agent claim 123registers claim in registry - Agent works: Implements changes, runs tests, commits
- Agent completes:
fab agent donetriggers rebase and merge to main - Cleanup: Worktree deleted, claims released, next agent spawns
Merge Conflict Recovery
When fab agent done encounters a merge conflict:
- Orchestrator aborts the rebase
- Worktree is rebased to latest
origin/main - Agent stays running to resolve conflicts
- Agent commits resolution and retries
fab agent done
Pull Request Strategy
With merge-strategy = "pull-request":
- Agent branch pushed to origin:
git push -u origin fab/{agentID} - PR created via
gh pr create - Agent stops but worktree persists for PR feedback
- Manual merge after review
Gotchas
- Claims are in-memory: Restarting the daemon clears all claims. Agents should re-claim if restarted.
- Worktree limit:
max-agentslimits concurrent worktrees.ErrNoWorktreeAvailablewhen exceeded. - Intervention pauses automation: User input pauses the kickstart prompt for
InterventionSilenceduration. Set to 0 to disable. - Rebase required: Agents must rebase onto
origin/mainbefore merge. Conflicts block completion.
Decisions
Worktree isolation: Each agent gets its own worktree to enable parallel development without interference. The worktree path includes the agent ID for traceability.
In-memory claims: Claims are stored in memory rather than persisted because they're transient coordination state. If the daemon restarts, agents can re-claim their issues.
Merge serialization: All merges go through a single mutex (mergeMu) to prevent race conditions when multiple agents complete simultaneously.
Fast-forward only: Direct merge uses --ff-only to maintain linear history and fail fast on conflicts.
Paths
internal/orchestrator/orchestrator.go- Main orchestrator and lifecycle loopinternal/orchestrator/claims.go- Ticket claim registryinternal/orchestrator/commits.go- Commit log trackinginternal/agent/agent.go- Agent state machineinternal/project/project.go- Worktree management