"The bosun runs the work crew on deck while the captain charts the course."
Coordinate parallel Claude Code (or any) sessions on isolated git worktrees, with one place to see what's happening and clean merge-back when work is done.
git clone https://github.com/jasondillingham/bosun.git ~/bosun-demo
cd ~/bosun-demo && go build -o ~/bin/bosun ./cmd/bosun
bosun tourbosun tour walks you through init, parallel edits, predict, merge, and cleanup on a throwaway repo — no setup, no agent launching, no Anthropic API key. About 5 minutes.
Watch a recording of the auto-driven tour (BOSUN_TOUR_AUTO=1 bosun tour):
Higher-fidelity playback options:
- Interactive player at asciinema.org/a/aPMDJsNbseBdi307 (lets you pause / scrub / copy text out)
- Local:
asciinema play docs/assets/bosun-tour.cast
bosun tui is the Bubbletea control center: one screen for every session, with keybinds to merge, cleanup, remove, launch, and preview briefs without leaving the table.
Bosun control · 4 sessions · 2 DONE · 2 WORKING · 8 ahead
SESSION BRANCH STATE AHEAD DIRTY CLAIMED LAST
session-1 bosun/session-1 DONE 3 0 2 1m ago · implement auth handler
▸ session-2 bosun/session-2 WORKING 1 4 1 14s ago · add data layer
session-3 bosun/session-3 DONE 4 0 3 2m ago · write integration tests
session-4 bosun/session-4 WORKING 0 0 0 — — (no commits)
Recent activity
session-3 [done] ready to merge — 4 commits squashed
session-2 [claim] internal/data/, cmd/bosun/cmd_status.go
session-1 [merge] merged — 3 commit(s) squashed
status: merge session-1: merged — 3 commit(s) squashed
j/k move · m merge · M merge-all · c cleanup · r remove · l launch · s brief · R refresh · q quit
$ bosun init 4
Created 4 sessions:
session-1 → ../myproject-bosun-1 (branch: bosun/session-1)
session-2 → ../myproject-bosun-2 (branch: bosun/session-2)
session-3 → ../myproject-bosun-3 (branch: bosun/session-3)
session-4 → ../myproject-bosun-4 (branch: bosun/session-4)
$ bosun status
SESSION BRANCH AHEAD DIRTY LAST_COMMIT
session-1 bosun/session-1 2 0 23s ago — implement auth handler
session-2 bosun/session-2 1 3 1m ago — add data layer
session-3 bosun/session-3 0 0 — — (no commits)
session-4 bosun/session-4 4 0 8s ago — refactor http routing
$ bosun merge
session-1: ✓ merged (squashed 2 commits)
session-2: ⏭ skipped — has uncommitted changes (`bosun show session-2` to inspect)
session-3: ⏭ skipped — no commits ahead
session-4: ✓ merged (squashed 4 commits)
If you've ever run 3–4 Claude Code sessions in parallel on the same repo, you've hit these problems:
- Either everyone's on
main(collisions) or each on its own branch with no coordination - You context-switch between N terminals just to know what's happening
- The integration step at the end reveals conflicts you could have avoided
- When sessions step on each other, recovery costs more than the work would have
Bosun solves all four by giving each session an isolated git worktree, surfacing live state in one place, providing clean merge-back, and (since v0.2) exposing live cross-session coordination as MCP tool calls.
Bosun runs alongside your normal git workflow, on the same checkout you already use. The rules below describe exactly what it touches without being asked, what it does only when you ask, and what it never does at all.
Without explicit command, bosun:
- Creates branches under the
bosun/prefix (e.g.bosun/session-1,bosun/auth). Your existing branches andmainare not touched. - Creates worktrees as sibling directories of your repo, named
<repo>-bosun-<session>(e.g.myproj-bosun-1). Nothing is created inside the repo root other than.bosun/. - Writes coordination state under
.bosun/in your repo root: per-session claim files, DONE/STUCK markers, an MCP socket at.bosun/mcp.sock, and.bosun/init.statewhilebosun initis in progress..bosun/is auto-added to.gitignore.
Only on explicit command, bosun:
bosun mergesquash-merges DONE sessions back to your base branch — the only action that touchesmain.bosun remove <session>andbosun cleanupdelete the session's worktree and branch. Both default to safe-delete (git branch -d);--forceswitches to-D.bosun cleanup --purgediscards committed work that hasn't been merged. Loud on purpose: this is the only path that can drop session commits.bosun merge --undoresetsmainto a prior SHA, and only whenmainhasn't advanced past it.
Never, regardless of command, bosun:
- Touches
mainoutside ofbosun merge. - Writes outside
<repo>and the<repo>-bosun-*sibling worktrees. - Pushes to any remote, fetches from one, or talks to a forge (GitHub, GitLab, …).
- Modifies your global git config or your
user.{name,email}. - Modifies repo-level git config beyond what
git worktree addalready does.
Download a prebuilt binary. Tagged releases publish darwin/linux/windows × amd64/arm64 archives on the Releases page. One-liner that grabs the right archive for the current host, extracts the bosun binary, and drops it on PATH:
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/jasondillingham/bosun/main/scripts/install.sh | sh# Windows (PowerShell)
iwr -useb https://raw.githubusercontent.com/jasondillingham/bosun/main/scripts/install.ps1 | iexPrefer not to pipe a script straight into a shell? Both installers are short and self-contained — scripts/install.sh and scripts/install.ps1 — read them first, then run locally. Or grab the archive for your OS/arch directly from the Releases page and extract by hand.
From source (Go 1.25+):
go install github.com/jasondillingham/bosun/cmd/bosun@latest
Or build from source — see Makefile. Full install options (prebuilt binary, go install, build from source, Homebrew when available) live in docs/installing.md.
# 1. Sanity-check your environment (one-time, recommended).
bosun doctor
# 2. Describe the work; bosun proposes the lane split for you.
bosun init 3 --suggest "add auth, refactor http routing, write tests"
# (writes .bosun/suggested-plan.md, creates 3 worktrees + branches,
# and drops a per-session BOSUN_BRIEF.md in each)
# 3. Open an agent in each session (or use --launch on init).
bosun launch session-1
bosun launch session-2
bosun launch session-3
# 4. Watch what's happening.
bosun status # one-shot table
bosun tui # interactive control center
# 5. Each session, when ready, runs `bosun done`. Then:
bosun merge # squash-merge every DONE session back to your base branch
bosun cleanup # reap merged sessions
If anything looks off, bosun doctor is the first thing to try.
Bosun's default agent is Claude Code (claude), but the agent
command is per-repo and per-session configurable. Point it at a
wrapper script — for example, one that hands the session off to a
local Ollama server or runs Claude inside a Docker container — and
bosun launches that instead.
# Repo-wide default
bosun config set agent_command examples/agent-wrappers/ollama-aider.sh
# Per-session override via the brief
cat > plan.md <<'EOF'
## session-1 (command: examples/agent-wrappers/ollama-aider.sh)
Routine refactor — cheap local model is fine.
## session-2
Architecture work — falls back to the config default (claude).
EOF
bosun init 2 --brief plan.mdStarter wrapper scripts live in examples/agent-wrappers/;
read the README there for the
contract and known limitations. The design that motivates the
feature is docs/agent-command-design.md.
For single-host Docker isolation, bosun ships a native docker
launcher (no wrapper script needed):
bosun config set launcher docker
bosun config set docker.image ghcr.io/your-org/bosun-agent:latest
bosun init 4 # each session runs in its own container, locallyBosun composes docker run --rm -it -v <worktree>:/work ... and
hands it to your OS terminal launcher. Worktree + MCP socket are
bind-mounted; operator-configured docker.extra_mounts and
docker.env_passthrough cover credentials and runtime config.
For multi-host / remote-docker (offload sessions to one or many
other machines), configure docker.hosts with SSH or TCP endpoints:
bosun config set launcher docker
bosun config set docker.image ghcr.io/your-org/bosun-agent:latest
# Edit .bosun/config.json directly for the hosts list:
# "docker": { "hosts": ["ssh://thor", "ssh://loki"] }
bosun init 4 # sessions distribute round-robin across hostsWhen docker.hosts has multiple entries, bosun init N assigns
sessions round-robin across them — operator with a 3-host fleet
gets parallelism across hardware without per-session brief
clauses. Per-session (host: ssh://...) clauses or
--docker-host still override when needed. bosun doctor's
docker-hosts check pings every configured endpoint via
docker info so unreachable bridges surface before init half-
creates worktrees. The MCP socket is bridged into each remote
container via ssh -R, so coordination works across hosts.
Full design at docs/sandbox-launcher-design.md
and docs/remote-docker-plan.md.
Bosun fires HTTP POSTs at lifecycle events when config.webhooks
is populated. Sibling to the existing hooks (shell commands) —
webhooks deliver async to Slack, Discord, or any HTTPS endpoint
without you having to wrap curl in a shell script.
{
"webhooks": [
{
"url": "https://hooks.slack.com/services/...",
"events": ["post-done", "post-merge"],
"format": "slack"
},
{
"url": "https://discord.com/api/webhooks/...",
"format": "discord"
},
{
"url": "https://collector.internal/bosun",
"format": "plain",
"headers": {"X-Auth-Token": "..."}
}
]
}eventsis a filter — empty means "all lifecycle events" (pre/post init, post-done, pre/post merge, pre/post cleanup, pre-remove). Typos fail at config-load time.formatshapes the body.slackanddiscordsend the one-line text payload those incoming-webhook APIs accept;plainsends a full JSON envelope (event, session, env, ts) for custom collectors.- Delivery is fire-and-forget: a slow endpoint can't stall
bosun done. Failures log to stderr; bosun doesn't retry (operators who need guaranteed delivery should put a real queue between bosun and the endpoint). timeout_secondscaps each POST. Default 10s, max 60s.
Agent runtimes that report token + cost usage (Claude Code, wrapped
Aider, etc.) can call the bosun_usage MCP tool after each turn.
Bosun aggregates the per-session ledger and surfaces it in three
places:
bosun statusadds aCOSTcolumn when at least one session has reported usage. Sessions with no reported usage show—.bosun show <session>prints cumulative cost, token totals, the last model used, and a per-model breakdown when more than one model was used in the session.bosun mergeprints a one-line round summary —bosun: round cost — session-1: $0.42 · session-2: $1.17 · total $1.59— after the per-session merge results.
Set a per-session budget to gate runaway spend:
bosun config set usage_budget_usd 5.00When set, bosun_claim checks the calling session's ledger and:
- attaches an advisory
budget_warningto the result at ≥ 80% of budget (claim still succeeds); - refuses the claim outright at ≥ 100% of budget. Already-open claims and in-flight work aren't affected — the gate only blocks new claims so a runaway agent can't open more fronts.
0 (the default) means no limit. Full protocol details:
docs/mcp-protocol.md — bosun_usage and
"Budget gate" sections.
A fully annotated reference config lives at
examples/config.example.json —
shows every supported key with placeholder values. Copy the JSON
body (strip the // comment lines) into your repo's
.bosun/config.json and edit. .bosun/config.json is gitignored
by bosun itself; only the annotated example file is GitHub-tracked.
Operators can also run bosun config init inside a repo to
generate .bosun/config.example.json with current-version
defaults — that's the same content, generated at runtime.
bosun init [N | label...] [--brief plan.md | --suggest "<goal>"] [--launch] [--isolate-cache] [--force] [--resume]
Create worktrees + branches (numeric N or named
labels). --suggest generates a brief from a goal
description; --brief consumes a hand-written one.
bosun launch <session> [--initial-prompt "..."]
Spawn an agent window for an existing session
bosun status [--with-overlaps] [--watch] [--json] [--summary-only]
Print a table of session states + path collisions
bosun show <session> [--json]
Inspect one session's brief, claims, recent commits
bosun claim <session> <paths...>
Session declares paths it's editing (advisory)
bosun done <session> Session signals it is ready to merge
bosun merge [<session>...] [--dry-run] [--undo <sha>] [--no-load-check]
Squash-merge DONE sessions back to base
bosun rescue <session> [--launch]
Recover a CRASHED session: snapshot its dirty
files to .bosun/rescues/, or relaunch a window
bosun remove <session> [--force]
Tear down a session cleanly; --force salvages
uncommitted files into .bosun/rescues/ first
bosun cleanup [--orphans] [--purge]
Reap DONE or empty sessions in bulk
bosun list [--ready] [--json]
Print session names (--ready for DONE only)
bosun config show|set|get|unset|init|validate
Inspect or edit .bosun/config.json
bosun predict <plan.md> Heuristic conflict prediction across a plan's lanes
bosun suggest "<goal>" Propose disjoint lanes for a goal; write a plan
bosun doctor System health check before bosun goes to work
bosun mcp [--socket path] Run the MCP server (foreground)
bosun tui Bubbletea control center
bosun serve [--port N] HTTP dashboard with SSE event stream
bosun audit [--kind spawn|subtask|all] [--tail N] [--session L] [--outcome refused] [--json]
Read the spawn / sub-task audit logs at .bosun/audit/
bosun cost [--by session|day] [--since 7d] [--session L] [--json]
Roll up LLM cost + tokens across sessions (Phase 4 ledger)
bosun spawn <parent> --brief <plan.md> [--launch]
Spawn sub-sessions under <parent> from a brief (CLI analogue of bosun_spawn)
- Git on PATH (>= 2.40)
- Go 1.25+ to build (the MCP SDK requires it)
| OS | Status | Notes |
|---|---|---|
| macOS (Intel + Apple Silicon) | ✓ primary development target | iCloud-path refusal in bosun init; see below |
| Linux (x86_64) | ✓ tested on Ubuntu 25.04 (kernel 6.14) | bosun tour + bosun doctor + full init/merge/cleanup cycle validated end-to-end |
| Windows | ✓ supported — see Windows notes | Terminal launcher prefers wt.exe (Windows Terminal, default on Win11, opt-in on Win10) with tab support; falls back to cmd /c start for windows. Lockfile uses real LockFileEx; process detection uses gopsutil. Live trial coverage is narrower than macOS / Linux — please open an issue if you hit something on real-world Windows work. |
macOS users: keep the bosun project out of ~/Documents/, ~/Desktop/, and ~/Library/Mobile Documents/ — all are iCloud-synced by default, and iCloud File Provider strips git's worktree admin metadata under load. bosun init refuses these paths by default (override with --force-icloud if you've disabled iCloud sync for the dir). bosun doctor catches and recovers the corruption shape if you hit it. See docs/macos-setup.md for the full guide and the recipe to relocate an existing repo out of iCloud.
Windows users: the launcher uses wt.exe when present (real tab support via wt -w 0 new-tab), cmd /c start "" cmd /K … otherwise. Set your agent_command in .bosun/config.json to claude (PATH-resolved — Anthropic's installer ships claude.cmd and Go's exec.LookPath finds it). One known difference from POSIX: bosun_attach's best-effort PID-cwd validation is a no-op on Windows because per-process cwd isn't cleanly exposed without a new dependency — the gate degrades to "register the PID, trust the next liveness check" rather than refusing. Repos with spaces in the path (C:\Users\Some User\repos\…) should work — the launcher quotes paths for both wt.exe and cmd.exe — but exercise it once before relying on it.
Bosun overlaps with a few neighbors. Honest tradeoffs below — if any one of these is already what you want, stay there.
vs. raw git worktree. git worktree add plus your own tmux/terminal discipline handles two branches fine. Bosun is heavier — a binary, a .bosun/ directory, a coordination model — and only earns its weight once you're juggling 3+ lanes and want one table to see them all, plus a merge orchestrator and a documented safety contract. If you're managing two branches, raw worktrees are the right answer.
vs. Claude Code's Agent(isolation: "worktree"). That tool delegates one task to a sub-agent inside one conversation; the worktree dies when the sub-agent returns. Visibility is parent-to-child only; nothing outside that pair can see the work. Bosun is for N persistent sessions that survive Ghostty restarts and laptop reboots, with bosun status / bosun tui showing them all in one place, predict-before-merge (bosun predict), reflog-based undo (bosun merge --undo), and bosun rescue for CRASHED state. When the isolated Agent wins: one-shot tasks that fit in a single conversation — the Agent tool is the lighter answer there.
vs. hosted / cloud AI-coordinators (Devin, Cursor background agents, etc.). Most of those are aimed at a single agent doing more work autonomously, often in a managed sandbox. Bosun is a local CLI for the operator-in-the-loop case: you launch the agents, they coordinate via local files + MCP, and nothing leaves your machine. When they win: if you want hosted/cloud execution, async work-while-you-sleep, or a polished web UI, bosun isn't competing.
How is this different from running git worktree myself?
You can build this yourself with git worktree add, a few tmux panes, and discipline. Bosun is the packaged version — one table for status, declarative claims so sessions know what each other is editing, a squash-merge orchestrator with reflog undo, and a documented safety contract. If you already have a workflow you like, keep it.
What if I'm not using Claude Code?
Bosun is agent-agnostic. The CLI surface (init, status, merge, …) works for any agent or human you put in a worktree — Cursor, Aider, your own shell, a teammate, a script. The MCP tools are the only Claude-Code-shaped piece, and they're optional.
Does bosun talk to GitHub (or any forge)? No. The safety contract is explicit: bosun never pushes, fetches, or talks to a forge. Worktrees, branches, and squash-merges are all local. You push when you push.
Can I use bosun on Windows?
Yes. The launcher prefers wt.exe (Windows Terminal, default on Win11, opt-in on Win10) for tab-aware launching and falls back to cmd /c start "" cmd /K … otherwise; the lockfile uses real LockFileEx; process detection uses gopsutil. Live trial coverage is narrower than macOS / Linux — please open an issue if you hit something. See the Supported platforms table for the operator-facing notes (no-op bosun_attach cwd validation, path quoting, claude.cmd discovery).
Is bosun safe for production codebases?
The safety contract holds — bosun never touches main except via bosun merge, never pushes, never modifies global git config. It's been trialed end-to-end through SIGBUS, CRASHED state, corrupted-gitdir recovery, and merge --undo reflog reset (docs/v0.8-trial-findings.md, docs/v0.9-trial-3c-findings.md). Honest caveat: zero external users so far — try it on a side project first.
How do I undo a bosun merge?
bosun merge --undo <sha> resets your base branch to a prior SHA via the reflog, but only when main hasn't advanced past it. If you've already pushed or rebased past the merge, recovery is on you — the reflog is the source of truth.
How does bosun work under the hood?
docs/architecture.md — one read covering the operating model, state machine, claim graph, spawn tree, MCP protocol, liveness gate, trust model, failure modes, and design principles. Per-subsystem specs live alongside it for depth.
What happens if a session crashes mid-work?
The session goes to CRASHED state. bosun rescue <session> snapshots its dirty files to .bosun/rescues/ so nothing is lost, and can relaunch the window. bosun doctor is the first thing to run if anything looks off.
Validated end-to-end. Safety contract held across SIGBUS, CRASHED state, corrupted-gitdir recovery, and merge --undo reflog reset in trial #2 (docs/v0.8-trial-findings.md). The v0.9 spawn-tree machinery — hierarchical labels, merge --tree post-order cascade, dotted-label worktree naming — held in trial #3c (docs/v0.9-trial-3c-findings.md). Issue #15 (macOS iCloud worktree-admin corruption) has a foundational fix: bosun init refuses iCloud-managed paths by default, bosun doctor detects the corruption shape, and bosun doctor --fix recovers it. The fix's empirical validation gate is "a real user hits this and the doctor catches it" — see issue #15. All 23 packages green under make check; make fuzz and make stress clean; cross-OS validated on macOS + Ubuntu 25.04.
Not yet validated. Zero external users. Three v0.9 trials (#3, #3a, #3b, #3c) ran on a maintainer-owned repo on a maintainer's machine. The "stranger picked it up and shipped real work" signal flips this from "compelling prototype" to "this graduates." Until then: treat the safety contract as load-bearing trust and the rest as well-tested-but-unprovenfor your specific workflow.
See RELEASES.md for full version history, SPEC.md for the v0.1 implementation spec, and CLAUDE.md if you're a Claude Code session contributing to this codebase.
Pre-launch — this slot is reserved for community usage.
So far, bosun is in real use on:
- The maintainer's day-to-day workflow (the bosun repo itself dogfoods bosun for its own parallel-session development — every release has shipped under bosun coordination).
- Release-prep work for
architect-mcp.
If you've shipped real work with bosun, open a PR adding your project here — an honest one-liner about how you used it is plenty. No logos required; no "trusted by 500+ teams" marketing inflation.
- v0.1 — init/status/show/claim/done/merge/remove/list. Filesystem-based coordination. Optional brief fan-out + session launcher.
- v0.2 — MCP server interface:
bosun_claim/bosun_release/bosun_done/bosun_stuck/bosun_announce/bosun_checktool calls, plus polish (--summary-only,bosun launch,cleanup --orphans, dependency-aware briefs, non-Ghostty tab support). - v0.3 — Bubbletea TUI control center (
bosun tui), HTTP dashboard (bosun serve), custom session labels, agent process detection, cross-process claimsflock. - v0.4 — Lifecycle hooks scaffolding,
merge --dry-run,list/show --json, web brief preview + events feed, orphan-dir recovery,bosun config. - v0.5 — All hook call-sites wired (pre-merge / post-merge / pre-cleanup / post-cleanup / pre-remove), kickoff robustness (per-op timeouts, progress reporting), predictive conflict analysis (
bosun predict),bosun suggestbrief authoring. - v0.6 — Resilience anchor: agent-liveness gate on destructive ops, pre-merge
git fsck, reflog-basedmerge --undo, CRASHED state +bosun rescue, heartbeat MCP tool, hook timeout enforcement, init resumability (bosun init --resume), README "Safety contract" section. - v0.7 — Polish round: launch UX, predictor accuracy (Files-avoid exclusion), pre-flight robustness (stale-branch refusal in init, load check at merge), state+rescue resilience (Spotlight phantom filter, corrupted-gitdir recovery, salvage on
remove --force). Plus a bug-hunt wave: proc detection via cmdline, MCP goroutine leak, rescue salvage error surfacing, cleanup/merge silent-error fixes. Refactors:internal/phantom,internal/lockfile. Fuzz + stress test targets viamake fuzzandmake stress. - v0.8 — Public-launch readiness:
bosun doctorsystem preflight,init --suggestfor one-step onboarding, external-repo trial #2, README + LICENSE + RELEASES.md catchup. - v0.9 — Agent-driven coordination:
bosun_spawnMCP tool, spawn-tree data layer with hierarchical session labels (session-1.auth), tree-shapedstatus/show/list,cleanup --treecascade,merge --treepost-order, PreToolUse hook for auto-claim. - v0.10 — "Somewhat solid from day one." Phase 1 macOS reliability: detect + refuse iCloud-managed paths, recover from issue #15 admin-dir corruption via
bosun doctor --fix. Phase 2A agent UX:bosun_spawncontext-isolation pitch reframe,bosun_check_treetool, structured.bosun/audit/spawn.log, v1.0 sub-task spec. Phase 3 first-5-minutes:bosun tourinteractive walkthrough,bosun new-brief --patternscaffolding, README quickstart, demo asset. - v0.11 — v1.0-track + pre-launch close-out across two tagged releases.
v0.11.0shippedbosun_subtaskMCP tools for lightweight agent fan-out (#11) and timestamp-suffix worktree naming (#8) withbosun migrate.v0.11.1closed the gap-analysis backlog: spawn lifecycle bug-clean (SyncWithGit+ launcher rapid-fire fix), community files (CONTRIBUTING / SECURITY / CoC + issue + PR templates), GoReleaser + signed multi-platform release archives,golangci-lintCI gate, Dependabot,bosun status --watch,bosun events --tail,bosun debugbundle,.bosun/history/session archive. - Unreleased (on
main) — Remote-docker stack: SSH bridging, multi-host round-robin distribution,bosun doctorhost reachability. Phase 4 cost tracking:bosun_usageMCP tool, per-session budget gate, COST column in status,bosun costrollup. Phase 5 surface: custom MCP tools viaconfig.mcp_tools, webhooks for lifecycle events (Slack/Discord/plain), audit CLI, in-container heartbeat shim,bosun suggestauto-refines on overlap.bosun spawnCLI surface, real Windows lockfile viaLockFileEx,docs/architecture.md(the "how bosun thinks" single read), pre-commit gofmt hook +make fmt/fmt-check/install-hooks. Two security audits + three bug-hunt passes closed with zero High-severity findings open.
Beyond main: no committed roadmap. Bosun is in shipping shape with the safety contract validated end-to-end. The next graduation signal is external usage — see the Used by section. The only open Medium-severity finding is suggest token-budget bounding; the only open issue is #15 (iCloud field-validation gate, awaiting a real-user incident report).
Apache 2.0 — see LICENSE.

