Summary
Full architecture redesign of Symphony from the ground up. The v1 architecture had cost leaks (silent continuation retries), implicit state transitions, no process visibility, a heavyweight observability stack, and GitHub-only tracker support. This redesign addresses all of these with a clean-break approach.
Motivation
Problems with v1
- Cost leaks: No-commits exits silently retried, burning API credits with no progress
- Implicit state: State transitions scattered across orchestrator, no formal FSM
- No visibility: No way to see what agents are doing in real-time
- Heavy observability: Required external Grafana/Prometheus stack for basic monitoring
- GitHub-only: No support for Linear or other issue trackers
- TypeScript sidecar: Claude Code required a Node.js/tsx sidecar, adding operational complexity
- No process control: No pause/resume/kill for individual agents
v2 Design Goals
- Declarative FSM with exhaustive transition table — every state change is explicit and testable
- Per-repo
.symphony/ configuration with symphony.yaml
- Multi-tracker support (GitHub + Linear) via adapter pattern
- Multi-agent support (Claude Code + OpenCode + Codex) via unified
agent.Agent interface
- Built-in TUI dashboard (replaces Grafana stack for day-to-day use)
- PTY-based agents with
symphony attach for real-time observation
- Event-driven architecture with single-goroutine state ownership (no mutexes)
- Property-based testing (55K+ random FSM sequences)
Architecture
Package Structure
internal/
domain/ # Shared types (WorkItem, FSM) — zero external deps
engine/ # Central event loop, handlers, state
tracker/KIND/ # Tracker adapters (github/, linear/, mock/)
codehost/KIND/ # Code host adapters (github/)
agent/KIND/ # Agent adapters (claude/, opencode/, codex/, mock/)
config/ # symphony.yaml parser + validator
prompt/ # Template rendering + field-based routing
workspace/ # Git clone/worktree management
state/ # bbolt persistent store
logging/ # JSONL file logger
server/ # HTTP API (healthz, metrics, webhooks, control)
tui/views/ # Bubble Tea TUI with 3 view modes
FSM (9 states, 16 events, 28 transitions)
open → queued → preparing → running → completed → handed_off
↓
needs_human (stall/budget/no-commits)
↓
failed (retries exhausted)
Key Design Decisions
- No mutexes in engine: Single goroutine processes all events sequentially
- Explicit handoff: No-commits exit →
needs_human (NOT silent retry) — prevents cost leaks
- FSM enforcement: All state changes go through
domain.Transition() with guards
- Event log: Append-only
events.jsonl records every transition for debugging/replay
- Adapter pattern: Tracker, Agent, CodeHost interfaces with factory registration
- PTY agents: Agents run in Go-native PTY via
creack/pty, attachable via Unix socket
CLI Commands
symphony init # Interactive setup wizard
symphony run [--mock] # Start orchestrator with TUI
symphony doctor # Validate config + environment + connectivity
symphony status # JSON state dump
symphony attach <id> # Connect to agent PTY
symphony logs # Tail structured logs
symphony pause/resume/kill <id> # Control individual agents
symphony events # Query FSM event log
symphony config validate/show # Config management
Scope
New packages (v2)
internal/domain/ — WorkItem model, FSM with 28 transitions
internal/engine/ — Event loop, eligibility, retry, stall, budget, handoff, reconcile
internal/agent/ — Agent interface + Claude/OpenCode/Codex/Mock adapters
internal/codehost/ — CodeHost interface + GitHub adapter
internal/tracker/{github,linear,mock}/ — Multi-tracker with factory + contract tests
internal/config/ — symphony.yaml parser, validator, env var resolution
internal/prompt/ — Field-based template routing
internal/server/ — HTTP API with webhook endpoint (HMAC-SHA256 verification)
internal/tui/views/ — Bubble Tea dashboard (overview, detail, logs)
internal/logging/ — JSONL structured logging
cmd/symphony/ — 10+ cobra subcommands
test/property/ — FSM property tests (55K random sequences)
test/scenario/ — 7 end-to-end scenario tests with harness
docs/ — Architecture, configuration, testing, getting-started guides
Removed packages (v1)
internal/adapter/ — Replaced by internal/agent/
internal/orchestrator/ — Replaced by internal/engine/
internal/webhook/ — Merged into internal/server/api.go
internal/ssh/ — Deferred to future work
test/integration/ — Replaced by test/scenario/
Testing
- 177 passing tests across 15 packages
- Property tests: 55K+ random event sequences verify FSM invariants
- Scenario tests: 7 named end-to-end paths (happy path, retry exhaustion, no-commits escalation, stall recovery, reconcile closed, budget exceeded, handoff protection)
- Contract tests: Shared behavioral tests for all tracker implementations
- Unit tests: Eligibility (per-status/per-repo concurrency), retry backoff, stall detection, budget enforcement, handoff evaluation, prompt routing, config parsing/validation
Acceptance Criteria
Summary
Full architecture redesign of Symphony from the ground up. The v1 architecture had cost leaks (silent continuation retries), implicit state transitions, no process visibility, a heavyweight observability stack, and GitHub-only tracker support. This redesign addresses all of these with a clean-break approach.
Motivation
Problems with v1
v2 Design Goals
.symphony/configuration withsymphony.yamlagent.Agentinterfacesymphony attachfor real-time observationArchitecture
Package Structure
FSM (9 states, 16 events, 28 transitions)
Key Design Decisions
needs_human(NOT silent retry) — prevents cost leaksdomain.Transition()with guardsevents.jsonlrecords every transition for debugging/replaycreack/pty, attachable via Unix socketCLI Commands
Scope
New packages (v2)
internal/domain/— WorkItem model, FSM with 28 transitionsinternal/engine/— Event loop, eligibility, retry, stall, budget, handoff, reconcileinternal/agent/— Agent interface + Claude/OpenCode/Codex/Mock adaptersinternal/codehost/— CodeHost interface + GitHub adapterinternal/tracker/{github,linear,mock}/— Multi-tracker with factory + contract testsinternal/config/— symphony.yaml parser, validator, env var resolutioninternal/prompt/— Field-based template routinginternal/server/— HTTP API with webhook endpoint (HMAC-SHA256 verification)internal/tui/views/— Bubble Tea dashboard (overview, detail, logs)internal/logging/— JSONL structured loggingcmd/symphony/— 10+ cobra subcommandstest/property/— FSM property tests (55K random sequences)test/scenario/— 7 end-to-end scenario tests with harnessdocs/— Architecture, configuration, testing, getting-started guidesRemoved packages (v1)
internal/adapter/— Replaced byinternal/agent/internal/orchestrator/— Replaced byinternal/engine/internal/webhook/— Merged intointernal/server/api.gointernal/ssh/— Deferred to future worktest/integration/— Replaced bytest/scenario/Testing
Acceptance Criteria
go build ./...succeedsgo test ./... -count=1— all 177 tests passsymphony initgenerates valid.symphony/configsymphony doctorvalidates config, credentials, connectivitysymphony run --mockstarts TUI with mock agent