Skip to content
/

Symphony (OpenAI)

symphony-openai · openai/symphony · ★ 25k · last commit 2026-05-20

A language-agnostic specification and Elixir reference daemon that continuously polls Linear and dispatches isolated Codex sessions per issue, letting teams manage work instead of supervising coding agents.

Best whenThe issue tracker IS the specification; agents should run unattended against tickets, reporting to humans only at the Human Review handoff state.
Skip ifAsking humans for follow-up actions in unattended mode, Stopping for non-blocker issues
vs seeds
taskmaster-ai(issue-tracker-driven) but Symphony replaces the task UI with a continuous background daemon (OTP GenServer) and uses th…
Primitive shape 8 total
Skills 5 Hooks 2 MCP tools 1
00

Summary

Symphony (OpenAI) — Summary

Symphony is an open-source language-agnostic specification for an AI coding agent orchestration service, published by OpenAI with an Elixir/OTP reference implementation. It solves the problem of turning software project work into isolated, autonomous implementation runs: Symphony continuously polls an issue tracker (Linear), creates per-issue workspace directories, launches Codex in App Server mode inside each workspace, and keeps the agent working until the issue reaches a handoff state ("Human Review") or terminal state ("Done"). The core innovation is the WORKFLOW.md contract — a single YAML-front-matter file teams version in their repository that defines the polling interval, issue states, workspace setup hooks, agent command, approval policy, and the workflow prompt template. Symphony is explicitly a "scheduler/runner" not an agent framework; the business logic lives in the workflow prompt and the coding agent's tools. The Elixir reference implementation uses OTP supervision trees for crash recovery. Compared to seeds: closest to kiro in being a complete runtime environment rather than a CLAUDE.md augmentation, but Symphony is open-source, language-agnostic-by-spec, uses Codex (not a proprietary IDE), and targets Linear-driven team workflows rather than individual developer spec-to-code cycles.

01

Overview

Symphony (OpenAI) — Overview

Origin

OpenAI. GitHub: https://github.com/openai/symphony. Apache-2.0 license. Language: Elixir. Status: "low-key engineering preview for testing in trusted environments."

Philosophy

From the README:

"Symphony turns project work into isolated, autonomous implementation runs, allowing teams to manage work instead of supervising coding agents."

From the SPEC.md:

"Symphony is a long-running automation service that continuously reads work from an issue tracker (Linear in this specification version), creates an isolated workspace for each issue, and runs a coding agent session for that issue inside the workspace."

Important boundary stated explicitly:

"Symphony is a scheduler/runner and tracker reader. Ticket writes (state transitions, comments, PR links) are typically performed by the coding agent using tools available in the workflow/runtime environment."

Design principles from SPEC.md

  1. Language-agnostic specificationSPEC.md is the normative document; Elixir is just the reference implementation. Teams are invited to "implement Symphony according to the following spec" in any language.
  2. In-repo workflow contractWORKFLOW.md is versioned with the codebase; no external configuration server.
  3. Workspace isolation — per-issue directories; agents work only inside their workspace.
  4. Bounded concurrencymax_concurrent_agents: 10 default.
  5. Exponential backoff recovery — transient failures retry with backoff; blocked issues are exposed in runtime state.
  6. Restart recovery without persistent DB — tracker + filesystem state is sufficient to reconstruct scheduler state after restart.

Harness engineering prerequisite

"Symphony works best in codebases that have adopted harness engineering. Symphony is the next step — moving from managing coding agents to managing work."

The referenced OpenAI harness engineering guide is a prerequisite.

02

Architecture

Symphony (OpenAI) — Architecture

Distribution

  • Git clone + build — not an npm package or pip package
  • Install: git clonemise installmix setupmix build
  • Required runtime: Elixir/OTP (managed via mise), Linear API key, Codex CLI

Core components (from SPEC.md)

Component Responsibility
Workflow Loader Reads WORKFLOW.md, parses YAML front matter + prompt body
Config Layer Typed getters for workflow config, defaults, env var indirection
Issue Tracker Client Fetches Linear issues, normalizes to issue model
Orchestrator Poll tick, in-memory runtime state, dispatch/retry/stop/release
Workspace Manager Maps issue IDs to workspace paths, lifecycle hooks
Agent Runner Creates workspace, builds prompt, launches Codex app-server client
Status Surface (OPTIONAL) Human-readable runtime status
Logging Structured runtime logs

WORKFLOW.md contract

A YAML-front-matter Markdown file checked into the target repo:

tracker:
  kind: linear
  project_slug: "symphony-0c79b11b75ea"
  active_states: [Todo, In Progress, Merging, Rework]
  terminal_states: [Closed, Cancelled, Done]
polling:
  interval_ms: 5000
workspace:
  root: ~/code/symphony-workspaces
hooks:
  after_create: |
    git clone --depth 1 https://github.com/openai/symphony .
agent:
  max_concurrent_agents: 10
  max_turns: 20
codex:
  command: codex --config shell_environment_policy.inherit=all --config 'model="gpt-5.5"'
  approval_policy: never
  thread_sandbox: workspace-write

Abstraction layers

  1. Policy Layer — repo-defined WORKFLOW.md
  2. Orchestration Layer — issue dispatch, workspace management
  3. Runtime Layer — Codex process management
  4. Tracker Layer — Linear integration

Agent runtime

Codex in App Server mode (codex app-server). Symphony serves a linear_graphql tool to the Codex session so it can write back to Linear without needing a full Linear MCP server.

Elixir implementation

elixir/ directory contains the OTP supervision tree. The mix run entry produces ./bin/symphony binary accepting a WORKFLOW.md path argument.

03

Components

Symphony (OpenAI) — Components

Core service components

Component Format
SPEC.md Language-agnostic normative specification (RFC 2119 language)
WORKFLOW.md YAML front matter + Jinja2 prompt template (per-repo)
Elixir OTP service Long-running daemon (mix project)

Codex skills (5, optional)

Located in elixir/ (can be copied to target repo):

  • commit — commit changes
  • push — push to remote
  • pull — pull from remote
  • land — land a PR
  • linear — raw Linear GraphQL operations via linear_graphql app-server tool

WORKFLOW.md prompt template

Jinja2 template in the --- body section, receiving issue context variables:

  • {{ issue.identifier }}
  • {{ issue.title }}
  • {{ issue.state }}
  • {{ issue.labels }}
  • {{ issue.url }}
  • {{ issue.description }}
  • {{ attempt }} (retry count for loop continuation)

App-server tool (1)

linear_graphql — served by Symphony to the Codex session; allows raw Linear GraphQL operations (comments, state transitions, PR links) from within the agent session.

Hooks (workspace lifecycle, in WORKFLOW.md)

  • after_create — shell script run after workspace directory created (e.g., git clone)
  • before_remove — shell script run before workspace directory removed

Status surface (optional)

The Elixir implementation includes a terminal dashboard and JSON API at runtime exposing:

  • Active runs
  • Blocked runs (awaiting operator input)
  • Retry queue state
05

Prompts

Symphony (OpenAI) — Prompt Excerpts

Excerpt 1: WORKFLOW.md prompt template (reference implementation)

Source: elixir/WORKFLOW.md

You are working on a Linear ticket `{{ issue.identifier }}`

{% if attempt %}
Continuation context:

- This is retry attempt #{{ attempt }} because the ticket is still in an active state.
- Resume from the current workspace state instead of restarting from scratch.
- Do not repeat already-completed investigation or validation unless needed for new code changes.
- Do not end the turn while the issue remains in an active state unless you are blocked by
  missing required permissions/secrets.
{% endif %}

Issue context:
Identifier: {{ issue.identifier }}
Title: {{ issue.title }}
Current status: {{ issue.state }}
Labels: {{ issue.labels }}
URL: {{ issue.url }}

Description:
{% if issue.description %}
{{ issue.description }}
{% else %}
No description provided.
{% endif %}

Instructions:

1. This is an unattended orchestration session. Never ask a human to perform follow-up actions.
2. Only stop early for a true blocker (missing required auth/permissions/secrets). If blocked,
   record it in the workpad and move the issue according to workflow.
3. Final message must report completed actions and blockers only. Do not include "next steps
   for user".

Prompting technique: Issue-tracker-as-spec pattern — the Linear ticket description IS the specification. Jinja2 template variables inject issue context. The {% if attempt %} block implements loop continuation without requiring state file reads. Unattended-mode mandates ("Never ask a human", "only stop for true blockers") create a fully autonomous execution posture.


Excerpt 2: Default posture instructions (reference WORKFLOW.md, body)

## Default posture

- Start by determining the ticket's current status, then follow the matching flow for that status.
- Start every task by opening the tracking workpad comment and bringing it up to date before
  doing new implementation work.
- Spend extra effort up front on planning and verification design before implementation.

## Prerequisite: Linear MCP or `linear_graphql` tool is available

The agent should be able to talk to Linear, either via a configured Linear MCP server or injected
`linear_graphql` app-server tool. If none are present, stop and ask the user to configure Linear.

Prompting technique: Prerequisite gate (halt-on-missing-tool) combined with task-first planning mandate ("spend extra effort up front on planning and verification design before implementation") — enforces plan-before-code without a dedicated planning agent.

09

Uniqueness

Symphony (OpenAI) — Uniqueness & Positioning

Differs from seeds

Most distinct from all 11 seeds — no direct archetype match. Closest conceptually to taskmaster-ai (issue-tracker-driven task management) but Symphony replaces the task management UI with a fully automated daemon that monitors Linear and dispatches Codex autonomously.

Key differentiators:

  1. Language-agnostic specificationSPEC.md with RFC 2119 normative language invites community reimplementations in any language. No other framework in the corpus ships a formal spec document separate from the implementation.

  2. Issue-tracker-as-spec — the Linear ticket IS the specification. No separate requirements.md or design.md files. The WORKFLOW.md prompt template receives issue data as Jinja2 variables. This is a fundamentally different spec model from kiro's EARS notation or BMAD's design docs.

  3. Background daemon orchestration — Symphony is the only framework that runs as a continuous background service polling an external tracker, rather than being invoked per-task. This changes the human interaction model: engineers manage their Linear board, not their agents.

  4. Workspace-isolated per-issue agent processes — each Linear ticket gets its own directory and Codex process with workspace-write sandbox. More rigorous isolation than git-worktree approaches in other frameworks.

  5. OpenAI provenance — the only OpenAI-authored framework in the corpus. Uses Codex (not Claude Code) as the agent runtime.

Observable failure modes

  • Requires Linear subscription (tracker lock-in)
  • Requires "harness engineering" setup as a prerequisite
  • Elixir/OTP is an unusual tech stack for most JavaScript/Python shops
  • "Engineering preview for trusted environments" — not production-hardened
  • Blocked agents are lost on restart (in-memory only)

Competitive positioning

Symphony targets engineering teams that want to remove agent supervision from individual developers entirely, replacing it with standard project management (Linear board). This is a fundamentally different usage pattern from every other framework — it's a team infrastructure tool, not a developer productivity tool.

04

Workflow

Symphony (OpenAI) — Workflow

Operational loop

1. Poll Linear (every 5s default) for issues in active states
2. Dispatch issue to Agent Runner if slot available (bounded by max_concurrent_agents)
3. Create workspace (git clone, hooks.after_create)
4. Build prompt from issue + WORKFLOW.md template
5. Launch Codex app-server in workspace
6. Stream agent updates back to orchestrator
7. Monitor: if issue moves to terminal state → stop agent + clean workspace
8. If blocked (operator input needed) → mark blocked, keep alive
9. On failure: exponential backoff retry (max per WORKFLOW.md config)
10. On terminal state: cleanup (hooks.before_remove), release slot

WORKFLOW.md prompt phases

The prompt body in the reference WORKFLOW.md instructs Codex to:

  1. Determine ticket's current status
  2. Open and update tracking workpad comment
  3. Implement work based on status
  4. Not ask humans for follow-up actions (unattended mode)
  5. Stop only for true blockers (missing auth/permissions)

Phase artifacts

Phase Artifact
Workspace creation ~/code/symphony-workspaces/<issue-id>/
Agent session Code changes + test results in workspace
Completion PR with CI status, review feedback, walkthrough video
Handoff Linear ticket moved to "Human Review" state

Approval gates

  1. Linear state transition — issues must be in active_states to be dispatched; reaching Human Review is the normal completion handoff
  2. Human review — engineers review PR and merge; Symphony does not auto-merge
  3. Blocked state — if Codex requests operator confirmation, Symphony exposes as blocked

Execution mode

background-daemon — Symphony runs as a long-running OTP service polling Linear continuously.

06

Memory Context

Symphony (OpenAI) — Memory & Context

State persistence

Filesystem + tracker state — Symphony deliberately avoids a persistent database:

"Support tracker/filesystem-driven restart recovery without requiring a persistent database; exact in-memory scheduler state is not restored."

After restart, active Linear tickets + existing workspace directories provide sufficient state to reconstruct the scheduler.

Per-issue workpad

Each agent session is instructed to maintain a "tracking workpad comment" in the Linear ticket. This comment is updated before doing new implementation work and serves as the inter-session continuity artifact.

Workspace state

Per-issue workspace directories in ~/code/symphony-workspaces/<issue-id>/. Code changes, test results, and partial implementation persist in the workspace across retries.

Blocked state (in-memory only)

Blocked issues are tracked in the Orchestrator's in-memory runtime state. Restarting Symphony clears the blocked map; blocked issues become dispatch candidates again if still in active states.

Loop continuation via {{ attempt }}

The Jinja2 template variable {{ attempt }} is injected on retry, instructing the agent to:

  • Resume from current workspace state
  • Not repeat already-completed investigation
  • Not restart from scratch

This is a lightweight cross-session handoff via template variable injection rather than a dedicated memory system.

Cross-session context

The Linear ticket (title, description, status, labels) provides persistent context across retries. The workspace directory provides file-level continuity. No vector DB or semantic memory.

07

Orchestration

Symphony (OpenAI) — Orchestration

Pattern

Parallel fan-out — the Orchestrator dispatches multiple issues to separate Codex instances simultaneously, bounded by max_concurrent_agents (default 10). Each issue gets its own workspace and Codex process.

Not hierarchical — there is no supervisor agent delegating to workers. The Orchestrator is a Elixir/OTP process (not an AI agent) that manages scheduling; Codex is the AI agent that runs in each workspace.

Isolation mechanism

Process isolation — each Codex instance is a separate OS process launched in its own workspace directory. The thread_sandbox: workspace-write policy limits Codex to writing only within the workspace.

codex:
  thread_sandbox:
    type: workspaceWrite

Multi-agent

Yes in the sense that multiple Codex instances run simultaneously — but they are independent and do not communicate. No inter-agent messaging or coordination.

Multi-model

No — single model (gpt-5.5 in reference WORKFLOW.md). Teams can change the model by editing their WORKFLOW.md codex.command.

Execution mode

background-daemon — OTP GenServer poll loop, continuous.

Crash recovery

OTP supervision trees provide crash recovery for the orchestrator process itself. Agent-level failures: exponential backoff retry, configurable via WORKFLOW.md. Blocked agents: kept alive in memory, restarted on Symphony restart.

Approval policy

approval_policy: never in reference WORKFLOW.md — Codex runs unattended without per-action approval. Teams can change this.

Max concurrent agents

10 (configurable via agent.max_concurrent_agents in WORKFLOW.md).

08

Ui Cli Surface

Symphony (OpenAI) — UI & CLI Surface

CLI binary

Binary name: ./bin/symphony (generated by mix build) Usage: ./bin/symphony ./WORKFLOW.md

Not an npm/pip package — built from source. One argument: path to WORKFLOW.md.

Status surface

The reference Elixir implementation provides:

  • Terminal dashboard (OPTIONAL per SPEC.md)
  • JSON API for programmatic status queries
  • Structured logs to configured sinks

The terminal dashboard shows:

  • Active agent runs per issue
  • Blocked runs (awaiting operator input)
  • Retry queue state

Web UI

Not documented beyond "terminal output or dashboard or other operator-facing view" in SPEC.md. The reference implementation uses terminal output.

Makefile targets

elixir/Makefile provides development commands:

mise exec -- mix setup
mise exec -- mix build
mise exec -- ./bin/symphony ./WORKFLOW.md

Observability

Structured logs via configurable sinks. The SPEC.md requires:

"Emits structured runtime logs to one or more configured sinks."

Session metrics tracked in Orchestrator in-memory state.

Linear integration

The linear_graphql app-server tool is served by Symphony to each Codex session, enabling agents to write back to Linear (comments, state transitions) without a separate Linear MCP server.

Related frameworks

same archetype · same primary tool · same memory type

cli-agent-orchestrator (awslabs) ★ 634

tmux-based supervisor-worker orchestration across 7 AI coding CLIs, with MCP coordination primitives, persistent memory,…

Agent Orchestrator (ComposioHQ)
Continuous Claude ★ 3.8k

Compound learning across Claude Code sessions via PostgreSQL memory extraction from thinking blocks, YAML handoffs for session…

ORCH ★ 68

Orchestrates teams of parallel AI agents (CTO + workers + reviewer) on a single codebase with YAML flat-file state, a TUI…

Flokay (Codagent Agent Skills) ★ 26

Full SDLC skill pack from idea evaluation through CI-green PR, with TDD Iron Law enforcement and external validator quality gates.

OpenAI Skills (Official) ★ 20k

Tiered library of integration and workflow skills for Codex, with a self-bootstrapping skill-installer that lets agents discover…