Introduction
Symphony is a long-running automation service that orchestrates coding agents to complete project work. It continuously reads issues from a tracker (Linear), creates isolated workspaces, and runs coding agent sessions inside those workspaces.Symphony is a scheduler/runner and tracker reader, not a general workflow engine. Ticket writes (state transitions, comments, PR links) are performed by the coding agent using tools in the runtime environment.
Architecture Principles
Separation of Concerns
Symphony is organized into distinct layers:Policy Layer
Repository-defined rules in
WORKFLOW.md for ticket handling and validationCoordination Layer
Orchestrator managing polling, eligibility, concurrency, and retries
Execution Layer
Workspace management and agent subprocess lifecycle
Integration Layer
Tracker adapters normalizing external API data
Key Design Goals
- Single authoritative orchestrator for dispatch, retries, and reconciliation
- Deterministic per-issue workspaces preserved across runs
- Restart recovery without requiring a persistent database
- Bounded concurrency with global and per-state limits
- Exponential backoff recovery from transient failures
System Components
The architecture consists of these main components:Component Responsibilities
Orchestrator
Orchestrator
Core coordination engine that:
- Owns the poll tick and in-memory runtime state
- Decides which issues to dispatch, retry, stop, or release
- Tracks session metrics and retry queue state
- Reconciles running issues against current tracker state
SymphonyElixir.Orchestrator (GenServer)Workspace Manager
Workspace Manager
Isolated filesystem management that:
- Maps issue identifiers to workspace paths
- Ensures per-issue workspace directories exist
- Runs lifecycle hooks (after_create, before_run, after_run, before_remove)
- Cleans workspaces for terminal issues
SymphonyElixir.WorkspaceAgent Runner
Agent Runner
Coding agent execution that:
- Creates/reuses workspace for each issue
- Builds prompts from issue + workflow template
- Launches Codex app-server client in workspace
- Streams agent updates back to orchestrator
- Manages multi-turn sessions on the same thread
SymphonyElixir.AgentRunnerTracker Client
Tracker Client
Issue tracker integration that:
- Fetches candidate issues in active states
- Fetches current states for running issues (reconciliation)
- Fetches terminal-state issues during startup cleanup
- Normalizes tracker payloads into stable issue model
SymphonyElixir.Tracker + SymphonyElixir.Linear.AdapterWorkflow Loader
Workflow Loader
Configuration management that:
- Reads
WORKFLOW.mdfrom repository - Parses YAML front matter and prompt body
- Watches for changes and hot-reloads config
- Returns typed configuration for runtime
SymphonyElixir.Workflow + SymphonyElixir.ConfigData Flow
Poll Cycle Flow
Agent Execution Flow
Retry Flow
Reconciliation Flow
Reconciliation runs before dispatch on every poll tick to ensure running sessions stay aligned with tracker state.
State Management
Orchestrator Runtime State
The orchestrator maintains a single in-memory authoritative state:Issue Orchestration States
Unclaimed
Issue not running, no retry scheduled
Claimed
Reserved to prevent duplicate dispatch (Running or RetryQueued)
Running
Worker task exists, tracked in
running mapRetryQueued
Worker not running, retry timer active in
retry_attemptsReleased
Claim removed (terminal, non-active, missing, or retry completed)
Safety Invariants
-
Workspace isolation: Run coding agent only in per-issue workspace path
- Validate:
cwd == workspace_pathbefore launching subprocess
- Validate:
-
Workspace containment: All workspace paths must stay inside workspace root
- Normalize both paths to absolute
- Require workspace_path has workspace_root as prefix
- Reject paths outside workspace root
-
Workspace key sanitization: Only
[A-Za-z0-9._-]allowed in directory names- Replace all other characters with
_
- Replace all other characters with
SymphonyElixir.Workspace.validate_workspace_path/1
Configuration Hot-Reload
Symphony watchesWORKFLOW.md for changes and hot-reloads configuration:
Invalid reloads do not crash the service—it keeps operating with the last known good configuration.
Next Steps
Component Deep Dive
Detailed implementation of each component
Workflow Lifecycle
Issue polling → dispatch → execution → cleanup
Workspace Isolation
How workspaces are isolated and managed
Configuration
Complete WORKFLOW.md reference