The foreman doesn't write the code — they manage the crew that does.
Multi-agent coding orchestrator. Decomposes development work into parallelizable tasks, dispatches them to AI coding agents in isolated git worktrees, and automatically merges results back — all driven by a real-time pipeline and inter-agent messaging.
You already have AI coding agents. What you don't have is a way to run several of them simultaneously on the same codebase without them stepping on each other. Foreman solves this:
- Work decomposition — PRD → TRD → beads (structured, dependency-aware tasks)
- Git isolation — each agent gets its own worktree (zero conflicts during development)
- Pipeline phases — Explorer → Developer ↔ QA → Reviewer → Finalize
- Pi SDK runtime — agents run in-process via
@mariozechner/pi-coding-agentSDK (createAgentSession) - Built-in messaging — SQLite-backed inter-agent messaging with native
send_mailtool, phase lifecycle notifications, and file reservations - Auto-merge — completed branches rebase onto target and merge automatically via the refinery
- Progress tracking — every task, agent, and phase tracked in SQLite + beads_rust
Foreman CLI / Dispatcher
│
├─ per task: agent-worker.ts (detached process)
│ └─ Pi SDK (in-process)
│ createAgentSession() → session.prompt()
│ Tools: read, write, edit, bash, grep, find, ls, send_mail
│
├─ Pipeline Executor (workflow YAML-driven)
│ Phases defined in .foreman/workflows/*.yaml
│ Model selection, retries, mail hooks, artifacts — all YAML config
│
├─ Messaging (SQLite, .foreman/foreman.db — no external server)
│ send_mail tool: agents call directly as a native Pi SDK tool
│ Lifecycle: phase-started, phase-complete, agent-error
│ Coordination: branch-ready, merge-complete, bead-closed
│ File reservations: prevent concurrent worktree conflicts
│
└─ Refinery + autoMerge
Triggers immediately after finalize phase
T1/T2: TypeScript auto-merge (fast path, no LLM)
T3/T4: AI conflict resolution via Pi session
Pipeline phases (orchestrated by TypeScript, not AI):
- Explorer (Haiku, 30 turns, read-only) — codebase analysis →
EXPLORER_REPORT.md - Developer (Sonnet, 80 turns, read+write) — implementation + tests
- QA (Sonnet, 30 turns, read+bash) — test verification →
QA_REPORT.md - Reviewer (Sonnet, 20 turns, read-only) — code review →
REVIEW.md - Finalize — git add/commit/push, br close
Dev ↔ QA retries up to 2x before proceeding to Review.
The following diagram shows the full lifecycle of a bead from foreman run to merged branch:
flowchart TD
subgraph CLI["foreman run"]
A[User runs foreman run] --> B[Dispatcher.dispatch]
B --> C{Check agent slots\navailable?}
C -- No slots --> DONE[Return: skipped]
C -- Slots open --> D[br ready — fetch unblocked beads]
D --> E{bv client\navailable?}
E -- Yes --> F[bv.robotTriage → score + sort by AI recommendation]
E -- No --> G[Sort by priority P0→P4]
F --> H
G --> H[For each bead...]
H --> I{Skip checks}
I -- already active --> SKIP[Skip: already running]
I -- completed, unmerged --> SKIP2[Skip: awaiting merge]
I -- in backoff from stuck --> SKIP3[Skip: exponential backoff]
I -- over max agents limit --> SKIP4[Skip: agent limit]
I -- passes all checks --> J[Fetch full bead detail\ntitle, description, notes, labels]
end
subgraph SETUP["Per-bead setup"]
J --> K[resolveBaseBranch\nstack on dependency branch?]
K --> L[createWorktree\ngit worktree add foreman/bead-id]
L --> M[Write TASK.md\ninto worktree]
M --> N[store.createRun → SQLite]
N --> O[store.logEvent dispatch]
O --> P[br update bead → in_progress]
P --> Q[spawnAgent]
end
subgraph SPAWN["Agent spawn"]
Q --> R{Pi binary\non PATH?}
R -- Yes --> S[PiRpcSpawnStrategy\npi --mode rpc JSONL]
R -- No --> T[Claude SDK\nquery fallback]
S --> U[Write config.json\nto temp file]
T --> U
U --> V[spawn agent-worker.ts\nas detached child process]
V --> W[store.updateRun → running]
end
subgraph WORKER["agent-worker process (detached)"]
W --> X[Read + delete config.json]
X --> Y[Open SQLite store\nOpen ~/.foreman/logs/runId.log]
Y --> Z[Init SqliteMailClient\n.foreman/mail.db]
Z --> AA{pipeline mode?}
AA -- No --> AB[Single agent via Pi RPC]
AA -- Yes --> AC[runPipeline]
end
subgraph PIPELINE["Pipeline phases"]
AC --> P1
subgraph P1["Phase 1: Explorer (Haiku, 30 turns, read-only)"]
P1A[Register agent-mail identity] --> P1B[Run SDK query\nexplorerPrompt]
P1B --> P1C[Write EXPLORER_REPORT.md]
P1C --> P1D[Mail report to developer inbox]
end
P1 --> P1_ok{success?}
P1_ok -- No --> STUCK[markStuck → bead reset to open\nexponential backoff]
P1_ok -- Yes --> P2
subgraph P2["Phase 2: Developer (Sonnet, 80 turns, read+write)"]
P2A[Reserve worktree files via Agent Mail] --> P2B[Run SDK query\ndeveloperPrompt + explorer context]
P2B --> P2C[Write DEVELOPER_REPORT.md]
P2C --> P2D[Release file reservations]
end
P2 --> P2_ok{success?}
P2_ok -- No --> STUCK
P2_ok -- Yes --> P3
subgraph P3["Phase 3: QA (Sonnet, 30 turns, read+bash)"]
P3A[Run SDK query\nqaPrompt + dev report]
P3A --> P3B[Run tests\nWrite QA_REPORT.md]
P3B --> P3C[Parse verdict: PASS / FAIL]
end
P3 --> P3_ok{QA verdict?}
P3_ok -- FAIL, retries left --> RETRY[Increment devRetries\nPass QA feedback to dev]
RETRY --> P2
P3_ok -- FAIL, max retries --> P4
P3_ok -- PASS --> P4
subgraph P4["Phase 4: Reviewer (Sonnet, 20 turns, read-only)"]
P4A[Run SDK query\nreviewerPrompt]
P4A --> P4B[Write REVIEW.md]
P4B --> P4C{CRITICAL or\nWARNING issues?}
P4C -- Yes --> FAIL_REV[Mark pipeline FAILED_REVIEW]
end
P4C -- No --> P5
subgraph P5["Phase 5: Finalize"]
P5A[git add, commit, push\nforeman/bead-id branch]
P5A --> P5B[br close bead]
P5B --> P5C[Enqueue to MergeQueue\nmail branch-ready to merge-agent]
end
end
subgraph MERGE["Merge queue"]
P5C --> MQ1[MergeQueue picks up branch]
MQ1 --> MQ2{Conflict tier?}
MQ2 -- T1/T2: no conflicts --> MQ3[Auto-rebase + merge to main]
MQ2 -- T3/T4: conflicts --> MQ4[AI conflict resolution via Pi session]
MQ4 --> MQ3
MQ3 --> MQ5[mail merge-complete to foreman]
MQ5 --> MQ6[store.updateRun → merged]
end
Key decision points:
| Decision | Outcome |
|---|---|
| Backoff check | Bead recently failed/stuck → exponential delay before retry |
| Dependency stacking | Bead depends on open bead → worktree branches from that dependency's branch |
| Pi vs SDK | pi binary on PATH → JSONL RPC protocol; otherwise Claude SDK query() |
| Pipeline vs single | --pipeline flag → 4-phase orchestration; otherwise single agent |
| Dev↔QA retry | Max 2 retries; QA feedback injected into next developer prompt |
| Reviewer FAIL | CRITICAL/WARNING issues → run marked failed, bead reset to open |
| Merge tiers T1-T4 | T1/T2 = TypeScript auto-merge; T3/T4 = AI-assisted conflict resolution |
- Node.js 20+
- beads_rust (
br) — task tracking CLIcargo install beads_rust # or: download binary to ~/.local/bin/br - Pi (installed as npm dependency) — agent runtime via
@mariozechner/pi-coding-agentSDK. No separate binary needed. - Anthropic API key —
export ANTHROPIC_API_KEY=sk-ant-...or log in via Pi:pi /login
brew tap oftheangels/tap
brew install foremannpm install -g @oftheangels/foremancurl -fsSL https://raw.githubusercontent.com/ldangelo/foreman/main/install.sh | shirm https://raw.githubusercontent.com/ldangelo/foreman/main/install.ps1 | iexforeman --version
foreman doctor # Check dependencies (br, API key, etc.)Also required: beads_rust (
br) for task tracking:cargo install beads_rustor download the binary to~/.local/bin/br
# 1. Initialize in your project
cd ~/your-project
foreman init --name my-project
# 2. Create tasks (beads)
br create --title "Add user auth" --description "Implement JWT-based auth" --type feature --priority 1
br create --title "Write auth tests" --type task --priority 2
# 3. Dispatch agents to ready tasks
foreman run
# 4. Monitor progress
foreman status
# 5. Merge completed branches (runs automatically in foreman run loop)
foreman mergeForeman includes a built-in messaging system for inter-agent communication and pipeline coordination. Messages are stored in SQLite (.foreman/foreman.db) — no external server, no HTTP, no additional dependencies.
Agents use the native send_mail tool, registered as a Pi SDK ToolDefinition. This is a structured tool call — agents don't run bash commands or invoke skills to send messages.
Tool: send_mail
Parameters:
to: "foreman"
subject: "agent-error"
body: '{"phase":"developer","error":"type check failed"}'
The pipeline executor also sends lifecycle messages automatically (phase-started, phase-complete) based on the workflow YAML mail hooks.
| Subject | From → To | When |
|---|---|---|
worktree-created |
foreman → foreman | Worktree initialized for a bead |
bead-claimed |
foreman → foreman | Bead dispatched to an agent |
phase-started |
executor → foreman | Phase begins (YAML: mail.onStart) |
phase-complete |
executor → foreman | Phase succeeds (YAML: mail.onComplete) |
agent-error |
agent → foreman | Agent encounters an error |
branch-ready |
foreman → refinery | Finalize complete, ready to merge |
merge-complete |
refinery → foreman | Branch merged to target |
merge-failed |
refinery → foreman | Merge failed (conflicts, tests) |
bead-closed |
refinery → foreman | Bead closed after successful merge |
foreman inbox # Latest run's messages
foreman inbox --bead bd-abc1 # Messages for a specific bead
foreman inbox --all --watch # Live stream across all runs
foreman debug <bead-id> # AI analysis including full mail timelinePhases that modify files can reserve the worktree directory to prevent concurrent access:
# In workflow YAML
files:
reserve: true
leaseSecs: 600Foreman uses the Pi SDK (@mariozechner/pi-coding-agent) to run AI agents in-process. Each pipeline phase creates a fresh AgentSession with phase-specific tools and model configuration.
const { session } = await createAgentSession({
cwd: worktreePath,
model: getModel("anthropic", "claude-sonnet-4-6"),
tools: [createReadTool(cwd), createBashTool(cwd), ...],
customTools: [createSendMailTool(mailClient, agentRole)],
sessionManager: SessionManager.inMemory(),
});
await session.prompt(phasePrompt);The send_mail tool is registered as a custom ToolDefinition on every agent session:
| Tool | Description |
|---|---|
send_mail |
Send messages to other agents or foreman. Used for error reporting. |
Standard Pi tools are also available per phase (configured in workflow YAML):
read,write,edit— file operationsbash— shell command executiongrep,find,ls— search and navigation
Models are configured per-phase in the workflow YAML with priority-based overrides. See Workflow YAML Reference for full details.
| Phase | Default Model | P0 Override | Max Turns |
|---|---|---|---|
| Explorer | haiku | sonnet | 30 |
| Developer | sonnet | opus | 80 |
| QA | sonnet | opus | 30 |
| Reviewer | sonnet | opus | 20 |
| Finalize | haiku | — | 20 |
For the complete CLI reference with all options and examples, see CLI Reference.
For common problems and solutions, see Troubleshooting Guide.
Initialize Foreman in a project directory. Runs br init and registers the project.
foreman init --name "my-project"Dispatch AI coding agents to ready tasks. Enters a watch loop that auto-merges completed branches.
foreman run # Dispatch to all ready tasks
foreman run --bead bd-abc # Dispatch one specific task
foreman run --max-agents 3 # Limit concurrent agents
foreman run --model claude-opus-4-6 # Override model for all agents
foreman run --no-tests # Skip test suite in merge step
foreman run --dry-run # Preview without dispatchingEach agent gets:
- Its own git worktree (branch:
foreman/<bead-id>) - A
TASK.mdwith task instructions, phase prompts, and bead context brCLI for status updates- Phase-specific tool restrictions (via Pi extension or SDK
disallowedTools)
Show current task and agent status.
foreman status
foreman status --watch # Live-updating displayMerge completed work branches back to main. Runs automatically in the foreman run loop.
foreman merge # Merge all completed
foreman merge --target-branch develop # Merge to develop
foreman merge --no-tests # Skip test suite
foreman merge --test-command "npm test" # Custom test commandAuto-merge tiers (T1–T4):
- T1: Fast-forward or trivial rebase — no conflicts
- T2: Auto-resolve report-file conflicts (
.beads/,EXPLORER_REPORT.md, etc.) - T3: AI-assisted conflict resolution via Pi session
- T4: Create PR for human review (true code conflicts)
Run the PRD → TRD pipeline using Ensemble slash commands.
foreman plan "Build a user auth system with OAuth2"
foreman plan docs/description.md # From file
foreman plan --from-prd docs/PRD.md "unused" # Skip to TRD
foreman plan --prd-only "Build a REST API" # Stop after PRDParse a TRD and create seeds + beads task hierarchy.
foreman sling trd docs/TRD.md # Parse and create tasks
foreman sling trd docs/TRD.md --dry-run # Preview without creating
foreman sling trd docs/TRD.md --auto # Skip confirmationCheck environment health: br binary, Pi binary, Agent Mail server, SQLite integrity.
foreman doctor
foreman doctor --fix # Auto-fix recoverable issuesReset failed/stuck runs: kill agents, remove worktrees, reset beads to open.
foreman reset # Reset failed/stuck runs
foreman reset --all # Reset ALL active runs
foreman reset --detect-stuck # Detect stuck runs first, then reset
foreman reset --detect-stuck --timeout 20 # Stuck after 20 minutesCreate pull requests for completed branches that couldn't be auto-merged.
foreman prForeman uses beads_rust (br) for task tracking. Tasks are stored in .beads/beads.jsonl (git-tracked).
# View ready tasks (open, unblocked)
br ready
# Create tasks
br create --title "Implement feature X" --type feature --priority 1
br create --title "Fix bug Y" --type bug --priority 0
# Work lifecycle
br update bd-abc --status=in_progress
br close bd-abc --reason="Completed"
# Dependencies
br dep add bd-tests bd-feature # tests depend on feature
# Sync with git
br sync --flush-only # Export DB to JSONL before committingPriority scale: 0 (critical) → 1 (high) → 2 (medium) → 3 (low) → 4 (backlog).
Foreman pipelines are configured via workflow YAML files. See the Workflow YAML Reference for complete documentation with examples for Node.js, .NET, Go, Python, and Rust.
Workflows define:
- Setup steps — dependency installation, build commands (stack-agnostic)
- Setup cache — symlink dependency directories from a shared cache
- Phase sequence — which agents run in what order
- Model selection — per-phase models with priority-based overrides
- Retry loops — QA/Reviewer failure → Developer retry with feedback
- Mail hooks — lifecycle notifications and artifact forwarding
# .foreman/workflows/default.yaml (project-local override)
name: default
setup:
- command: npm install --prefer-offline --no-audit
failFatal: true
setupCache:
key: package-lock.json
path: node_modules
phases:
- name: developer
prompt: developer.md
models:
default: sonnet
P0: opus
maxTurns: 80
- name: qa
prompt: qa.md
verdict: true
retryWith: developer
retryOnFail: 2export ANTHROPIC_API_KEY=sk-ant-... # Required (or use `pi /login` for OAuth)
export FOREMAN_MAX_AGENTS=5 # Max concurrent agents (default: 5)| Path | Contents |
|---|---|
.beads/ |
beads_rust task database (JSONL, git-tracked) |
.foreman/foreman.db |
SQLite: runs, merge_queue, projects |
.foreman-worktrees/ |
Git worktrees for active agents |
~/.foreman/logs/ |
Per-run agent logs |
foreman/
├── src/
│ ├── cli/ # CLI entry point + commands
│ │ └── commands/
│ │ ├── run.ts # Main dispatch + merge loop
│ │ ├── status.ts # Status display
│ │ ├── merge.ts # Manual merge trigger
│ │ └── doctor.ts # Health checks
│ ├── orchestrator/ # Core orchestration engine
│ │ ├── dispatcher.ts # Task → agent spawning strategies
│ │ ├── pi-rpc-spawn-strategy.ts # Pi RPC spawn (primary)
│ │ ├── agent-worker.ts # Claude SDK pipeline (fallback)
│ │ ├── agent-mail-client.ts # Agent Mail HTTP wrapper
│ │ ├── refinery.ts # Merge + test + cleanup
│ │ ├── conflict-resolver.ts # T1-T4 conflict resolution
│ │ ├── roles.ts # Phase prompts + tool configs
│ │ └── sentinel.ts # Background health monitor
│ └── lib/
│ ├── beads-rust.ts # br CLI wrapper
│ ├── git.ts # Git worktree management
│ └── store.ts # SQLite state store
├── packages/
│ └── foreman-pi-extensions/ # Pi extension package
│ ├── src/tool-gate.ts # Block disallowed tools per phase
│ ├── src/budget-enforcer.ts # Turn + token limits
│ └── src/audit-logger.ts # Audit trail → Agent Mail
└── docs/
├── TRD/ # Technical Requirements Documents
└── PRD/ # Product Requirements Documents
Foreman can be distributed as a standalone executable for all 5 platforms — no Node.js required. Binaries are compiled via pkg which embeds the CJS bundle + Node.js runtime.
Note:
better_sqlite3.node(native addon) is a side-car file that must stay in the same directory as the binary. It cannot be embedded inside the executable.
# Full pipeline: tsc → CJS bundle → compile all 5 platforms
npm run build:binaries
# Dry-run (prints commands, does not compile)
npm run build:binaries:dry-run
# Single target (e.g. darwin-arm64)
npm run build && npm run bundle:cjs
tsx scripts/compile-binary.ts --target darwin-arm64dist/binaries/
darwin-arm64/
foreman-darwin-arm64 # macOS Apple Silicon
better_sqlite3.node # side-car native addon
darwin-x64/
foreman-darwin-x64 # macOS Intel
better_sqlite3.node
linux-x64/
foreman-linux-x64 # Linux x86-64
better_sqlite3.node
linux-arm64/
foreman-linux-arm64 # Linux ARM64 (e.g. AWS Graviton)
better_sqlite3.node
win-x64/
foreman-win-x64.exe # Windows x64
better_sqlite3.node
better_sqlite3.node differs per platform. The prebuilt binaries for all 5 targets are committed to scripts/prebuilds/. To refresh them from the better-sqlite3 GitHub Releases:
npm run prebuilds:download # Download for all targets
npm run prebuilds:download:force # Re-download even if present
npm run prebuilds:status # Check what's availableForeman uses release-please for automated semantic versioning driven by Conventional Commits.
- Merge a PR to
mainwhose commits (or PR title) follow the conventional-commit format. - The
.github/workflows/release.ymlworkflow runsrelease-please, which:- Inspects commits since the last release tag.
- Opens (or updates) a Release PR with a bumped
package.jsonversion and an updatedCHANGELOG.md.
- Merge the Release PR → release-please creates the GitHub Release + tag.
- The
release-binaries.ymlworkflow fires on the new tag and publishes platform binaries.
| Prefix | Bump |
|---|---|
fix: |
patch (0.1.0 → 0.1.1) |
feat: |
minor (0.1.0 → 0.2.0) |
feat!: or BREAKING CHANGE: footer |
major (0.1.0 → 1.0.0) |
feat: add --dry-run flag to foreman run
fix: handle missing EXPLORER_REPORT.md gracefully
feat!: rename foreman monitor to foreman sentinel
BREAKING CHANGE: The monitor subcommand has been renamed to sentinel.
release-please-config.json— release-please package config.release-please-manifest.json— current version manifest (updated by release-please)CHANGELOG.md— auto-generated; do not edit manually
The .github/workflows/release-binaries.yml workflow:
- Triggers on
v*.*.*tag push (created automatically by release-please) - Compiles all 5 platform binaries on Ubuntu (cross-compilation via prebuilds)
- Smoke-tests the linux-x64 binary
- Packages each platform as
.tar.gz(zip for Windows) - Creates a GitHub Release with all assets attached
To trigger a release manually (bypassing release-please):
git tag v1.0.0
git push origin v1.0.0Or trigger manually from the Actions tab with optional dry-run mode.
For additional install options (specific versions, custom directories, manual binary download), see the CLI Reference and Troubleshooting Guide.
If you want to contribute or build from source:
# Clone and build
git clone https://github.com/ldangelo/foreman
cd foreman
npm install && npm run build
# Link for local development
npm link
# Development commands
npm run build # TypeScript compile (atomic — safe while foreman is running)
npm test # vitest run (159 test files, ~2800 tests)
npm run dev # tsx watch mode
npx tsc --noEmit # Type check only
npm run bundle # esbuild single-file bundleRules:
- TypeScript strict mode — no
anyescape hatches - ESM only — all imports use
.jsextensions - TDD — RED-GREEN-REFACTOR cycle
- Test coverage — unit ≥ 80%, integration ≥ 70%
br sync --flush-onlybefore every git commit
MIT
Built by Leo D'Angelo at Fortium Partners.