Contrabass

Contrabass Logo

A project-level orchestrator for AI coding agents
Go + Charm stack reimplementation of OpenAI's Symphony (openai/symphony) — manage work, not agents

Contrabass Demo (TUI in Action)

Contrabass is a terminal-first orchestrator for issue-driven agent runs, with an optional local web dashboard for live visibility.

Current scope

Today Contrabass ships with:

Requirements

From a fresh clone, run bun install once before using the JS/landing build and test commands.

Installation

Homebrew (macOS/Linux)

brew install junhoyeo/contrabass/contrabass

Download from GitHub Releases

Pre-built binaries for macOS and Linux (amd64/arm64) are available on the Releases page.

Build from source

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@latest works for the CLI and TUI, but the embedded web dashboard (--port) will be empty because go install does not run the JS build step.

Quick start

Run with the demo workflow

LINEAR_API_KEY=your-linear-token \
./contrabass --config testdata/workflow.demo.md

Run with the embedded web dashboard

LINEAR_API_KEY=your-linear-token \
./contrabass --config testdata/workflow.demo.md --port 8080

Then open http://localhost:8080.

Run headless

LINEAR_API_KEY=your-linear-token \
./contrabass --config testdata/workflow.demo.md --no-tui

CLI flags

--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)

Team subcommand flags

contrabass team run --config workflow.md [flags]

--worker-mode string   override worker mode (goroutine|tmux, default from config)

How Contrabass works

  1. Poll the configured tracker for candidate issues.
  2. Claim an eligible issue.
  3. Create or reuse a git worktree in workspaces/<issue-id>.
  4. Render the prompt body from WORKFLOW.md using issue data.
  5. Launch the configured agent runner.
  6. Stream agent events, track tokens/phases, and publish orchestrator events.
  7. Retry failed runs with exponential backoff + deterministic jitter.
  8. Mirror state into the TUI and, when enabled, the embedded web dashboard.

Runtime notes

Team worker modes

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:

goroutine 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}/.

Workflow file format

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.

Template bindings

The current prompt renderer exposes:

Environment-variable interpolation

String values in YAML front matter can reference environment variables using $NAME syntax.

Examples:

OMC / OMX workflow sections

For 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:

Team configuration

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

Example workflow files

Supported integrations

Surface Current support
Trackers Linear, GitHub Issues, Internal Board
Agent runners Codex app-server, OpenCode, oh-my-opencode, OMX, OMC
Operator surfaces Charm TUI, embedded web dashboard, headless mode
Live config reload Yes (WORKFLOW.md via fsnotify)
State streaming JSON snapshot API + SSE

Trackers

Agent runners

Web dashboard and HTTP API (WIP)

When --port is set, Contrabass serves the embedded dashboard and a small JSON/SSE API.

Current endpoints

The dashboard currently renders:

Development

Build and test

make build            # build dashboard, then build ./contrabass
make build-dashboard  # build packages/dashboard/dist only
make build-landing    # build packages/landing/dist only
make test             # go test ./... -count=1
make test-dashboard   # bun test in packages/dashboard
make test-landing     # astro check in packages/landing
make test-quick       # recommended local validation path
make test-all         # Go + dashboard tests + landing checks
make ci               # lint + test-quick + binary/dashboard build + landing build
make lint             # go vet ./...
make clean            # remove built artifacts
make release-dry      # dry-run GoReleaser locally (skips publish)

For day-to-day local validation, use make test-quick. For a fuller pre-push or CI-style pass, use make ci.

Dashboard development

make dev-dashboard
make dev-landing

The repository is a root Bun workspace with packages/dashboard and packages/landing. The Astro landing site renders README.md, so this file is both repo documentation and site content.

Running from source

go run ./cmd/contrabass --config testdata/workflow.demo.md --port 8080

Docs and fixtures

Charm stack

Direct dependencies from the Charm v2 ecosystem:

Logo Library Import Path Purpose
   Bubble Tea Bubble Tea charm.land/bubbletea/v2 TUI framework (Elm architecture)
Lip Gloss Lip Gloss charm.land/lipgloss/v2 Styling & layout
Bubbles Bubbles charm.land/bubbles/v2 Reusable TUI components
Log Log github.com/charmbracelet/log Structured logging
X x github.com/charmbracelet/x x/mosaic for terminal image rendering

Plus:

Releasing

CI and release workflows run automatically via GitHub Actions:

To ship a new release:

git tag v0.2.0
git push origin v0.2.0

This builds cross-platform binaries (macOS/Linux, amd64/arm64) via GoReleaser, publishes a GitHub Release with grouped changelogs, and updates the Homebrew tap.

After GoReleaser publishes the release, scripts/generate-release-notes.ts appends contributor attribution — each change is tagged with the author's @username and linked PR, and first-time contributors get a dedicated shout-out section.

Notes for contributors

For detailed contribution guidelines, see CONTRIBUTING.md.