Skip to main content
Symphony is configured through a WORKFLOW.md file that combines YAML frontmatter for settings with a Markdown body for the agent prompt template.

Starting the Service

Pass a custom workflow file path when starting Symphony:
./bin/symphony /path/to/custom/WORKFLOW.md
If no path is provided, Symphony defaults to ./WORKFLOW.md in the current directory.

Command-Line Flags

--logs-root
string
default:"./log"
Directory where Symphony writes log files for each agent session
--port
integer
Enable the HTTP observability service on the specified port. When set, exposes:
  • / - Dashboard UI
  • /api/v1/state - Full system state as JSON
  • /api/v1/<issue_identifier> - Issue-specific state
  • /api/v1/refresh - Force state refresh
--i-understand-that-this-will-be-running-without-the-usual-guardrails
boolean
required
Required acknowledgement flag. Symphony runs Codex without typical safety guardrails.

Configuration Sections

tracker

Defines the issue tracking system and project scope.
tracker.kind
string
required
Tracker type. Currently supports "linear" or "memory" (for testing).
tracker:
  kind: linear
tracker.project_slug
string
required
Linear project slug. Find this by right-clicking your project in Linear and copying the URL.
tracker:
  project_slug: "symphony-0c79b11b75ea"
The project slug is the part of the Linear URL after /project/: linear.app/team/project/<slug>
tracker.api_key
string
default:"$LINEAR_API_KEY"
Linear API token. Defaults to reading from the LINEAR_API_KEY environment variable.
tracker:
  api_key: $LINEAR_API_KEY
tracker.endpoint
string
default:"https://api.linear.app/graphql"
Linear GraphQL API endpoint. Rarely needs customization.
tracker.assignee
string
Filter issues by assignee. Use "me" to match the API token owner, or a specific Linear user ID.
tracker:
  assignee: me
tracker.active_states
array
default:"[\"Todo\", \"In Progress\"]"
Linear states that Symphony considers “active” and will poll for.
tracker:
  active_states:
    - Todo
    - In Progress
    - Merging
    - Rework
tracker.terminal_states
array
States that trigger workspace cleanup and agent termination.
tracker:
  terminal_states:
    - Closed
    - Cancelled
    - Duplicate
    - Done

polling

Controls how frequently Symphony checks Linear for new issues.
polling.interval_ms
integer
default:"30000"
Milliseconds between Linear API polls.
polling:
  interval_ms: 5000  # Poll every 5 seconds

workspace

Defines where Symphony creates isolated workspaces for each issue.
workspace.root
string
required
Parent directory for issue workspaces. Supports ~ expansion and $VAR environment variables.
workspace:
  root: ~/code/symphony-workspaces
workspace:
  root: $SYMPHONY_WORKSPACE_ROOT

agent

Controls agent concurrency and turn limits.
agent.max_concurrent_agents
integer
default:"10"
Maximum number of agents running simultaneously across all states.
agent:
  max_concurrent_agents: 5
agent.max_turns
integer
default:"20"
Maximum back-to-back Codex turns per agent invocation when the issue remains active.
agent:
  max_turns: 50
agent.max_retry_backoff_ms
integer
default:"300000"
Maximum backoff delay in milliseconds when retrying failed agent runs.
agent.max_concurrent_agents_by_state
object
State-specific concurrency limits. Overrides max_concurrent_agents for specific states.
agent:
  max_concurrent_agents: 10
  max_concurrent_agents_by_state:
    "in progress": 5
    merging: 2

codex

Configures Codex app-server invocation and sandboxing.
codex.command
string
default:"codex app-server"
Shell command to launch Codex. Supports environment variable expansion.
codex:
  command: codex --model gpt-5.3-codex app-server
codex:
  command: $CODEX_BIN app-server --config model_reasoning_effort=xhigh
codex.approval_policy
string | object
Codex approval policy. String values: "untrusted", "on-failure", "on-request", "never". Object form uses reject structure.
codex:
  approval_policy: never
codex.thread_sandbox
string
default:"workspace-write"
Thread-level sandbox mode. Options: "read-only", "workspace-write", "danger-full-access".
codex:
  thread_sandbox: workspace-write
codex.turn_sandbox_policy
object
default:"see description"
Turn-level sandbox policy. Defaults to workspaceWrite rooted at the issue workspace.
codex:
  turn_sandbox_policy:
    type: workspaceWrite
Supported type values:
  • dangerFullAccess
  • readOnly
  • externalSandbox
  • workspaceWrite
codex.turn_timeout_ms
integer
default:"3600000"
Maximum milliseconds for a single Codex turn (1 hour default).
codex.read_timeout_ms
integer
default:"5000"
Read timeout for Codex stdio communication.
codex.stall_timeout_ms
integer
default:"300000"
Stall detection timeout. Terminates if no progress for this duration.

hooks

Lifecycle hooks for workspace management.
hooks.after_create
string
Shell script executed after workspace creation. Typically clones your repository.
hooks:
  after_create: |
    git clone --depth 1 https://github.com/your-org/repo .  
    mise trust
    mise exec -- npm install
If using mise inside hooks, trust the repo and fetch dependencies in after_create before invoking mise from other hooks.
hooks.before_run
string
Executed before each agent run.
hooks.after_run
string
Executed after each agent run completes.
hooks.before_remove
string
Cleanup script before workspace deletion.
hooks:
  before_remove: |
    mise exec -- mix workspace.before_remove
hooks.timeout_ms
integer
default:"60000"
Timeout for each hook execution in milliseconds.

observability

Controls the terminal dashboard display.
observability.dashboard_enabled
boolean
default:"true"
Enable/disable the terminal dashboard.
observability.refresh_ms
integer
default:"1000"
Dashboard state refresh interval in milliseconds.
observability.render_interval_ms
integer
default:"16"
Dashboard render framerate (~60 FPS at 16ms).

server

Optional HTTP API server configuration.
server.port
integer
HTTP server port. Enables JSON API and dashboard when set.
server:
  port: 4000
server.host
string
default:"127.0.0.1"
HTTP server bind address.

Configuration Validation

Symphony validates configuration on startup:
  • Missing or invalid WORKFLOW.md halts startup
  • tracker.kind must be "linear" or "memory"
  • Linear mode requires api_key and project_slug
  • Path values resolve ~ and $VAR references
  • Codex runtime settings must be valid

Environment Variable Expansion

tracker:
  api_key: $LINEAR_API_KEY
For workspace.root, $VAR is resolved before path expansion. For codex.command, variables are expanded by the launched shell.

Minimal Example

The smallest valid configuration:
tracker:
  kind: linear
  project_slug: "your-project-slug"
workspace:
  root: ~/code/workspaces
hooks:
  after_create: |
    git clone git@github.com:your-org/repo.git .
agent:
  max_concurrent_agents: 10
codex:
  command: codex app-server
If no Markdown body is provided, Symphony uses a default prompt that includes {{ issue.identifier }}, {{ issue.title }}, and {{ issue.description }}.

Build docs developers (and LLMs) love