by junhoyeo
🎸 A project-level orchestrator for AI coding agents — Go & Charm stack implementation of OpenAI's Symphony
# Add to your Claude Code skills
git clone https://github.com/junhoyeo/contrabassGuides for using ai agents skills like contrabass.
A project-level orchestrator for AI coding agents Go + Charm stack reimplementation of OpenAI's Symphony (openai/symphony) — manage work, not agents

Contrabass is a terminal-first orchestrator for issue-driven agent runs, with an optional local web dashboard for live visibility.
Today Contrabass ships with:
WORKFLOW.md parser with YAML front matter, Liquid prompt rendering, and $ENV_VAR interpolationworkspaces/<issue-id>git worktree)codex app-serveropencode serveoh-my-opencodeomx (oh-my-codex team runtime)omc (oh-my-claudecode team runtime)LINEAR_API_KEYGITHUB_TOKENFrom a fresh clone, run bun install once before using the JS/landing build and test commands.
brew install junhoyeo/contrabass/contrabass
Pre-built binaries for macOS and Linux (amd64/arm64) are available on the Releases page.
git clone https://github.com/junhoyeo/contrabass.git
cd contrabass
bun install
make build
make build first builds packages/dashboard/dist/ and then embeds it into the Go binary.
Note:
go install github.com/junhoyeo/contrabass/cmd/contrabass@latestworks for the CLI and TUI, but the embedded web dashboard (--port) will be empty becausego installdoes not run the JS build step.
LINEAR_API_KEY=your-linear-token \
./contrabass --config testdata/workflow.demo.md
LINEAR_API_KEY=your-linear-token \
./contrabass --config testdata/workflow.demo.md --port 8080
Then open http://localhost:8080.
LINEAR_API_KEY=your-linear-token \
./contrabass --config testdata/workflow.demo.md --no-tui
--config string path to WORKFLOW.md file (required)
--dry-run exit after first poll cycle
--log-file string log output path (default "contrabass.log")
--log-level string log level (debug/info/warn/error) (default "info")
--no-tui headless mode — skip TUI, log events to stdout
--port int web dashboard port (0 = disabled)
contrabass team run --config workflow.md [flags]
--worker-mode string override worker mode (goroutine|tmux, default from config)
workspaces/<issue-id>.WORKFLOW.md using issue data.WORKFLOW.md is watched with fsnotify; on parse errors, Contrabass keeps the last known good config.JSONL) to codex app-server rather than Content-Length framed messages. See docs/codex-protocol.md.workspace, hooks, and some codex settings are parsed, but the current runtime mainly uses tracker selection, timeouts, retry settings, binary paths, and prompt/template fields.Teams support two worker modes, configured via team.worker_mode in the workflow file or the --worker-mode CLI flag:
| Mode | Description | Default |
|------|-------------|---------|
| tmux | Each worker runs in a separate tmux pane with process isolation, cross-process IPC via JSONL events, and file-based heartbeats | Yes |
| goroutine | Workers run as goroutines within the contrabass process — lighter weight, no tmux dependency | |
tmux mode (default) provides:
flock(2) for safe concurrent accessgoroutine mode runs all workers in-process using Go's errgroup and sync.Mutex. It requires no external dependencies but shares the process address space.
Team state is persisted as JSON files under .contrabass/state/team/{teamName}/.
Contrabass reads a Markdown workflow file with YAML front matter followed by the prompt template body.
---
max_concurrency: 3
poll_interval_ms: 2000
max_retry_backoff_ms: 240000
model: openai/gpt-5-codex
project_url: https://linear.app/acme/project/example
agent_timeout_ms: 900000
stall_timeout_ms: 60000
tracker:
type: linear
agent:
type: codex
codex:
binary_path: codex app-server
---
# Workflow Prompt
Issue title: {{ issue.title }}
Issue description: {{ issue.description }}
Issue URL: {{ issue.url }}
Produce code and tests that satisfy the issue requirements.
The current prompt renderer exposes:
issue.titleissue.descriptionissue.urlString values in YAML front matter can reference environment variables using $NAME syntax.
Examples:
tracker.token: $GITHUB_TOKENopencode.password: $OPENCODE_SERVER_PASSWORDomx.binary_path: $OMX_BINARYomc.binary_path: $OMC_BINARYFor team-runtime-backed runners, set agent.type to omx or omc and configure the corresponding section.
agent:
type: omx
omx:
binary_path: omx
team_spec: 2:executor
poll_interval_ms: 1500
startup_timeout_ms: 22000
ralph: true
agent:
type: omc
omc:
binary_path: omc
team_spec: 2:claude
poll_interval_ms: 1200
startup_timeout_ms: 21000
Notes:
binary_path can point to the installed CLI wrapper, for example omx or omc.team_spec is passed directly to the team runtime, such as 1:executor, 2:executor, or 2:claude..contrabass/runner/<runner>/... inside the workspace and instructs the team runtime to execute from that file.The team section configures multi-agent coordination:
team:
max_workers: 5
max_fix_loops: 3
claim_lease_seconds: 300
state_dir: .contrabass/state/team
execution_mode: team # team | single | auto
worker_mode: tmux # tmux (default) | goroutine
worker_mode: Controls how agent workers are spawned. tmux (default) uses separate tmux panes with process isolation. goroutine runs workers in-process.execution_mode: Controls coordination strategy. team uses the full phased pipeline, single runs one agent at a time, auto selects based on task count.testdata/workflow.demo.md — demo Linear + Codex workflowtestdata/workflow.github.md — GitHub + OpenCode workflowtestdata/workflow.ohmyopencode.md — oh-my-opencode workflowtestdata/workflow.omx.md — OMX workflowtestdata/workflow.omc.md — OMC workflowtestdata/workflow.md — realistic Linear fixtureNo comments yet. Be the first to share your thoughts!