Worth checking before choosing or changing a subscription. Handig om te checken voordat je een abonnement kiest of wijzigt.
An open-source spec for Codex orchestration: Symphony. An open-source spec for Codex orchestration: Symphony.
Title: An open-source spec for Codex orchestration: Symphony. Title: An open-source spec for Codex orchestration: Symphony.
Quick editorial signal Snelle redactionele duiding
- Track this as a OpenAI update, not just a standalone headline. Bekijk dit als OpenAI-update, niet alleen als losse headline.
- Check plan details before changing subscriptions or advising a team. Controleer plandetails voordat je abonnementen wijzigt of een team adviseert.
- Likely worth revisiting after people have used the release in practice. Waarschijnlijk de moeite waard om opnieuw te bekijken zodra mensen het in praktijk gebruiken.
An open-source spec for Codex orchestration: Symphony. | OpenAI
Skip to main content
[](https://openai.com/)
* Research
* Products
* Business
* Developers
* Company
* Foundation(opens in a new window)
Log inTry ChatGPT(opens in a new window)
April 27, 2026
Engineering
An open-source spec for Codex orchestration: Symphony
By Alex Kotliarskyi, Victor Zhu, and Zach Brock
Listen to article
Six months ago, while working on an internal productivity tool, our team made a controversial (at the time) decision: we’d build our repo with no human-written code. Every line in our project repository had to be generated by Codex.
To make that work, we redesigned our engineering workflow from the ground up. We built an agent-friendly repository, invested heavily in automated tests and guardrails, and treated Codex as a full-fledged teammate. We documented that journey in our previous blog post on harness engineering.
And it worked, but then we ran into the next bottleneck: context switching.
To solve this new problem, we built a system called _Symphony_. Symphony(opens in a new window) is an agent orchestrator that turns a project-management board like Linear into a control plane for coding agents. Every open task gets an agent, agents run continuously, and humans review the results.
This post explains how we created Symphony—resulting in a 500% increase in landed pull requests on some teams—and how to use it to turn your own issue tracker into an always-on agent orchestrator.
The ceiling of interactive coding agents
Even as they get easier to use, coding agents—whether accessed through web apps or CLI—are still interactive tools.
As the scale of agentic work increased at OpenAI, we found a new kind of burden. Each engineer would open a few Codex sessions, assign tasks, review the output, steer the agent, and repeat. In practice, most people could comfortably manage three to five sessions at a time before context switching became painful. Beyond that, productivity dropped. We'd forget which session was doing what, jump between terminals to nudge agents back on track, and debug long-running tasks that stalled halfway through.
The agents were fast, but we had a system bottleneck: human attention. We had effectively built a team of extremely capable junior engineers, then assigned our human engineers to micromanaging them. That wasn’t going to scale.
A shift in perspective
We realized we were optimizing the wrong thing. We were orienting our system around coding sessions and merged PRs, when PRs and sessions are really a means to an end. Software workflows are largely organized around deliverables: issues, tasks, tickets, milestones.
So we asked ourselves what would happen if we stopped supervising agents directly and instead let them pull work from our task tracker.
That idea became Symphony, a written spec that functions as a supervisor to orchestrate agentic work.
Turning our issue tracker into an agent orchestrator
Symphony started with a simple concept: any open task should get picked up and completed by an agent. Instead of managing Codex sessions in multiple tabs, we made our issue tracker the control plane.
00:00
In this setup, each open Linear issue maps to a dedicated agent workspace. Symphony continuously watches the task board and ensures that every active task has an agent running in the loop until it’s done. If an agent crashes or stalls, Symphony restarts it. If new work appears, Symphony picks it up and starts organizing work.
We built our workflow based on ticket statuses, using the task manager Linear as a state machine.
In practice, Symphony decouples work from sessions and from pull requests. Some issues produce multiple PRs across repos; others are pure investigation or analysis that never touch the codebase.
> Once work is abstracted this way, tickets can represent much larger units of work.
We regularly use Symphony to orchestrate complex features and infrastructure migrations. For example, we might file a task asking the agent to analyze the codebase, Slack, or Notion and produce an implementation plan. Once we’re happy with the plan, the agent generates a tree of tasks, breaking the work into stages and defining dependencies between tasks.
Agents only start working on tasks that aren’t blocked, so execution unfolds naturally and optimally in parallel for this DAG (a sequence of execution steps). For example, we marked the React upgrade as blocked on a migration to Vite. As expected, agents started upgrading React only after the migration to Vite was complete.
Agents can also create work themselves. During implementation or review, they often notice improvements that fall outside the scope of the current task: a performance issue, a refactoring opportunity, or a better architecture. When that happens, they simply file a new issue that we can evaluate and schedule later—many of these follow-up tasks also get picked up by agents. While we oversee this process, agents stay organized and keep work moving forward.
This way of working dramatically reduces the cognitive cost of kicking off ambiguous work. If the agent gets something wrong, that’s still useful information, and the cost to us is near zero. We can very cheaply file tickets for the agent to go prototype and explore, and throw away any explorations we don’t like.
Because the orchestrator runs on devboxes and never sleeps, we can add tasks from anywhere and know an agent will pick it up. For instance, one engineer on our team made three significant changes from the Linear app on his phone from a cozy cabin on shoddy wifi.
An increase in exploration from working this way
When observing the effects of working with Symphony, the most obvious change was output. Among some teams at OpenAI, we saw the number of landed PRs increase by 500% in the first three weeks. Outside of OpenAI, Linear founder Karri Saarinen highlighted a spike in workspaces created(opens in a new window) as we released Symphony. However, the deeper shift is how teams think about work.
When our engineers no longer spend time supervising Codex sessions, the economics of code changes completely. The perceived cost of each change drops because we’re no longer investing human effort in driving the implementation itself.
That changed our behavior. It's become trivial to spin up speculative tasks in Symphony. Try an idea, explore a refactor, test a hypothesis, and only keep the results that look promising.
It also broadens who can initiate work. Our product manager and designer can now file feature requests directly into Symphony. They don’t need to check out the repo or manage a Codex session. They describe the feature and get back a review packet that includes a video walkthrough of the feature working inside the real product.
Symphony also shines in large monorepos (like the one we have at OpenAI) where the last mile of landing a PR is slow and fragile. The system watches CI, rebases when needed, resolves conflicts, retries flaky checks, and generally shepherds changes through the pipeline. By the time a ticket reaches Merging, we have high confidence the change will make it into the main branch without human babysitting.
After implementing Symphony, we delegate more work to agents and focus on harder, more exploratory tasks.
Progress comes with new, different problems
Operating at this level comes with tradeoffs. When we moved from steering agents interactively to assigning them work at the ticket level, we lost the ability to constantly nudge them mid-flight and course-correct when needed. Sometimes the agent produced something that completely missed the mark. That was useful—those failures revealed gaps in the system and helped us make it more robust.
Instead of patching the result manually, we added guardrails and skills so the agents could succeed the next time. Over time, this led us to add new capabilities to our harness, like running end-to-end tests, driving the app through Chrome DevTools, and managing QA smoke tests. We significantly improved our documentation and clarified what good looks like.
Not every task fits the Symphony style of work. Some problems still require engineers working directly with interactive Codex sessions, especially ambiguous problems or work that requires strong judgment and expertise. In practice, these are usually the most interesting and enjoyable tasks for our engineers to spend time on.
The difference is that Symphony can handle the bulk of routine implementation work. That lets engineers focus on a single hard problem at a time instead of constantly context-switching between smaller tasks.
We also learned that treating agents as rigid nodes in a state machine doesn’t work well. Models get smarter and can solve bigger problems than the box we try to fit them in. Our early versions of agentic work was only asking Codex to implement the task. That approach proved too limiting. Codex is perfectly capable of creating multiple PRs as well as reading review feedback and addressing it. So we gave it tools—gh CLI, skills to read CI logs, etc.—and now we can ask Codex to do more, like closing old PRs or pulling reports on completed vs. abandoned work. These types of tasks fell way outside the initial feature implementation box.
So we eventually moved toward giving agents _objectives_ instead of strict transitions, much like a good manager would assign a goal to a direct report on their team. The power of models comes from their ability to reason, so give them tools and context and let them cook.
Using Symphony to build Symphony
When you open the Symphony repository,(opens in a new window) the first thing you’ll notice is that Symphony is technically just a SPEC.md file—a definition of the problem and the intended solution. Rather than building a complex supervision system, we defined the problem and intended solutions, giving agents high-level steering.
Markdown
1# Symphony Service Specification23Status: Draft v1 (language-agnostic)45Purpose: Define a service that orchestrates coding agents to get project work done.67## 1. Problem Statement89Symphony is a long-running automation service that continuously reads work from an issue tracker10(Linear in this specification version), creates an isolated workspace for each issue, and runs a11coding agent session for that issue inside the workspace.1213The service solves four operational problems:1415- It turns issue execution into a repeatable daemon workflow instead of manual scripts.16- It isolates agent execution in per-issue workspaces so agent commands run only inside per-issue17 workspace directories.18- It keeps the workflow policy in-repo (WORKFLOW.md) so teams version the agent prompt and runtime19 settings with their code.20- It provides enough observability to operate and debug multiple concurrent agent runs.2122Implementations are expected to document their trust and safety posture explicitly. This23specification does not require a single approval, sandbox, or operator-confirmation policy; some24implementations may target trusted environments with a high-trust configuration, while others may25require stricter approvals or sandboxing.2627Important boundary:2829- Symphony is a scheduler/runner and tracker reader.30- Ticket writes (state transitions, comments, PR links) are typically performed by the coding agent31 using tools available in the workflow/runtime environment.32- A successful run may end at a workflow-defined handoff state (for example Human Review), not33 necessarily Done.3435## 2. Goals and Non-Goals3637### 2.1 Goals3839- Poll the issue tracker on a fixed cadence and dispatch work with bounded concurrency.40- Maintain a single authoritative orchestrator state for dispatch, retries, and reconciliation.41- Create deterministic per-issue workspaces and preserve them across runs.42- Stop active runs when issue state changes make them ineligible.43- Recover from transient failures with exponential backoff.44- Load runtime behavior from a repository-owned WORKFLOW.md contract.45- Expose operator-visible observability (at minimum structured logs).46- Support restart recovery without requiring a persistent database.4748### 2.2 Non-Goals4950- Rich web UI or multi-tenant control plane.51- Prescribing a specific dashboard or terminal UI implementation.52- General-purpose workflow engine or distributed job scheduler.53- Built-in business logic for how to edit tickets, PRs, or comments. (That logic lives in the54 workflow prompt and agent tooling.)55- Mandating strong sandbox controls beyond what the coding agent and host OS provide.56- Mandating a single default approval, sandbox, or operator-confirmation posture for all57 implementations.5859## 3. System Overview6061### 3.1 Main Components62631. Workflow Loader64 - Reads WORKFLOW.md.65 - Parses YAML front matter and prompt body.66 - Returns {config, prompt_template}.67682. Config Layer69 - Exposes typed getters for workflow config values.70 - Applies defaults and environment variable indirection.71 - Performs validation used by the orchestrator before dispatch.72733. Issue Tracker Client74 - Fetches candidate issues in active states.75 - Fetches current states for specific issue IDs (reconciliation).76 - Fetches terminal-state issues during startup cleanup.77 - Normalizes tracker payloads into a stable issue model.78794. Orchestrator80 - Owns the poll tick.81 - Owns the in-memory runtime state.82 - Decides which issues to dispatch, retry, stop, or release.83 - Tracks session metrics and retry queue state.84855. Workspace Manager86 - Maps issue identifiers to workspace paths.87 - Ensures per-issue workspace directories exist.88 - Runs workspace lifecycle hooks.89 - Cleans workspaces for terminal issues.90916. Agent Runner92 - Creates workspace.93 - Builds prompt from issue + workflow template.94 - Launches the coding agent app-server client.95 - Streams agent updates back to the orchestrator.96977. Status Surface (optional)98 - Presents human-readable runtime status (for example terminal output, dashboard, or other99 operator-facing view).1001018. Logging102 - Emits structured runtime logs to one or more configured sinks.103104### 3.2 Abstraction Levels105106Symphony is easiest to port when kept in these layers:1071081. Policy Layer (repo-defined)109 - WORKFLOW.md prompt body.110 - Team-specific rules for ticket handling, validation, and handoff.1111122. Configuration Layer (typed getters)113 - Parses front matter into typed runtime settings.114 - Handles defaults, environment tokens, and path normalization.1151163. Coordination Layer (orchestrator)117 - Polling loop, issue eligibility, concurrency, retries, reconciliation.1181194. Execution Layer (workspace + agent subprocess)120 - Filesystem lifecycle, workspace preparation, coding-agent protocol.1211225. Integration Layer (Linear adapter)123 - API calls and normalization for tracker data.1241256. Observability Layer (logs + optional status surface)126 - Operator visibility into orchestrator and agent behavior.127128### 3.3 External Dependencies129130- Issue tracker API (Linear for tracker.kind: linear in this specification version).131- Local filesystem for workspaces and logs.132- Optional workspace population tooling (for example Git CLI, if used).133- Coding-agent executable that supports JSON-RPC-like app-server mode over stdio.134- Host environment authentication for the issue tracker and coding agent.135136## 4. Core Domain Model137138### 4.1 Entities139140#### 4.1.1 Issue141142Normalized issue record used by orchestration, prompt rendering, and observability output.143144Fields:145146- id (string)147 - Stable tracker-internal ID.148- identifier (string)149 - Human-readable ticket key (example: ABC-123).150- title (string)151- description (string or null)152- priority (integer or null)153 - Lower numbers are higher priority in dispatch sorting.154- state (string)155 - Current tracker state name.156- branch_name (string or null)157 - Tracker-provided branch metadata if available.158- url (string or null)159- labels (list of strings)160 - Normalized to lowercase.161- blocked_by (list of blocker refs)162 - Each blocker ref contains:163 - id (string or null)164 - identifier (string or null)165 - state (string or null)166- created_at (timestamp or null)167- updated_at (timestamp or null)168169#### 4.1.2 Workflow Definition170171Parsed WORKFLOW.md payload:172173- config (map)174 - YAML front matter root object.175- prompt_template (string)176 - Markdown body after front matter, trimmed.177178#### 4.1.3 Service Config (Typed View)179180Typed runtime values derived from WorkflowDefinition.config plus environment resolution.181182Examples:183184- poll interval185- workspace root186- active and terminal issue states187- concurrency limits188- coding-agent executable/args/timeouts189- workspace hooks190191#### 4.1.4 Workspace192193Filesystem workspace assigned to one issue identifier.194195Fields (logical):196197- path (workspace path; current runtime typically uses absolute paths, but relative roots are198 possible if configured without path separators)199- workspace_key (sanitized issue identifier)200- created_now (boolean, used to gate after_create hook)201202#### 4.1.5 Run Attempt203204One execution attempt for one issue.205206Fields (logical):207208- issue_id209- issue_identifier210- attempt (integer or null, null for first run, >=1 for retries/continuation)211- workspace_path212- started_at213- status214- error (optional)215216#### 4.1.6 Live Session (Agent Session Metadata)217218State tracked while a coding-agent subprocess is running.219220Fields:221222- session_id (string, -)223- thread_id (string)224- turn_id (string)225- codex_app_server_pid (string or null)226- last_codex_event (string/enum or null)227- last_codex_timestamp (timestamp or null)228- last_codex_message (summarized payload)229- codex_input_tokens (integer)230- codex_output_tokens (integer)231- codex_total_tokens (integer)232- last_reported_input_tokens (integer)233- last_reported_output_tokens (integer)234- last_reported_total_tokens (integer)235- turn_count (integer)236 - Number of coding-agent turns started within the current worker lifetime.237238#### 4.1.7 Retry Entry239240Scheduled retry state for an issue.241242Fields:243244- issue_id245- identifier (best-effort human ID for status surfaces/logs)246- attempt (integer, 1-based for retry queue)247- due_at_ms (monotonic clock timestamp)248- timer_handle (runtime-specific timer reference)249- error (string or null)250251#### 4.1.8 Orchestrator Runtime State252253Single authoritative in-memory state owned by the orchestrator.254255Fields:256257- poll_interval_ms (current effective poll interval)258- max_concurrent_agents (current effective global concurrency limit)259- running (map issue_id -> running entry)260- claimed (set of issue IDs reserved/running/retrying)261- retry_attempts (map issue_id -> RetryEntry)262- completed (set of issue IDs; bookkeeping only, not dispatch gating)263- codex_totals (aggregate tokens + runtime seconds)264- codex_rate_limits (latest rate-limit snapshot from agent events)265266### 4.2 Stable Identifiers and Normalization Rules267268- Issue ID269 - Use for tracker lookups and internal map keys.270- Issue Identifier271 - Use for human-readable logs and workspace naming.272- Workspace Key273 - Derive from issue.identifier by replacing any character not in [A-Za-z0-9._-] with _.274 - Use the sanitized value for the workspace directory name.275- Normalized Issue State276 - Compare states after lowercase.277- Session ID278 - Compose from coding-agent thread_id and turn_id as -.279280## 5. Workflow Specification (Repository Contract)281282### 5.1 File Discovery and Path Resolution283284Workflow file path precedence:2852861. Explicit application/runtime setting (set by CLI startup path).2872. Default: WORKFLOW.md in the current process working directory.288289Loader behavior:290291- If the file cannot be read, return missing_workflow_file error.292- The workflow file is expected to be repository-owned and version-controlled.293294### 5.2 File Format295296WORKFLOW.md is a Markdown file with optional YAML front matter.297298Design note:299300- WORKFLOW.md should be self-contained enough to describe and run different workflows (prompt,301 runtime settings, hooks, and tracker selection/config) without requiring out-of-band302 service-specific configuration.303304Parsing rules:305306- If file starts with ---, parse lines until the next --- as YAML front matter.307- Remaining lines become the prompt body.308- If front matter is absent, treat the entire file as prompt body and use an empty config map.309- YAML front matter must decode to a map/object; non-map YAML is an error.310- Prompt body is trimmed before use.311312Returned workflow object:313314- config: front matter root object (not nested under a config key).315- prompt_template: trimmed Markdown body.316317### 5.3 Front Matter Schema318319Top-level keys:320321- tracker322- polling323- workspace324- hooks325- agent326- codex327328Unknown keys should be ignored for forward compatibility.329330Note:331332- The workflow front matter is extensible. Optional extensions may define additional top-level keys333 (for example server) without changing the core schema above.334- Extensions should document their field schema, defaults, validation rules, and whether changes335 apply dynamically or require restart.336- Common extension: server.port (integer) enables the optional HTTP server described in Section337 13.7.338339#### 5.3.1 tracker (object)340341Fields:342343- kind (string)344 - Required for dispatch.345 - Current supported value: linear346- endpoint (string)347 - Default for tracker.kind == "linear": https://api.linear.app/graphql348- api_key (string)349 - May be a literal token or $VAR_NAME.350 - Canonical environment variable for tracker.kind == "linear": LINEAR_API_KEY.351 - If $VAR_NAME resolves to an empty string, treat the key as missing.352- project_slug (string)353 - Required for dispatch when tracker.kind == "linear".354- active_states (list of strings)355 - Default: Todo, In Progress356- terminal_states (list of strings)357 - Default: Closed, Cancelled, Canceled, Duplicate, Done358359#### 5.3.2 polling (object)360361Fields:362363- interval_ms (integer or string integer)364 - Default: 30000365 - Changes should be re-applied at runtime and affect future tick scheduling without restart.366367#### 5.3.3 workspace (object)368369Fields:370371- root (path string or $VAR)372 - Default: /symphony_workspaces373 - ~ and strings containing path separators are expanded.374 - Bare strings without path separators are preserved as-is (relative roots are allowed but375 discouraged).376377#### 5.3.4 hooks (object)378379Fields:380381- after_create (multiline shell script string, optional)382 - Runs only when a workspace directory is newly created.383 - Failure aborts workspace creation.384- before_run (multiline shell script string, optional)385 - Runs before each agent attempt after workspace preparation and before launching the coding386 agent.387 - Failure aborts the current attempt.388- after_run (multiline shell script string, optional)389 - Runs after each agent attempt (success, failure, timeout, or cancellation) once the workspace390 exists.391 - Failure is logged but ignored.392- before_remove (multiline shell script string, optional)393 - Runs before workspace deletion if the directory exists.394 - Failure is logged but ignored; cleanup still proceeds.395- timeout_ms (integer, optional)396 - Default: 60000397 - Applies to all workspace hooks.398 - Non-positive values should be treated as invalid and fall back to the default.399 - Changes should be re-applied at runtime for future hook executions.400401#### 5.3.5 agent (object)402403Fields:404405- max_concurrent_agents (integer or string integer)406 - Default: 10407 - Changes should be re-applied at runtime and affect subsequent dispatch decisions.408- max_retry_backoff_ms (integer or string integer)409 - Default: 300000 (5 minutes)410 - Changes should be re-applied at runtime and affect future retry scheduling.411- max_concurrent_agents_by_state (map state_name -> positive integer)412 - Default: empty map.413 - State keys are normalized (lowercase) for lookup.414 - Invalid entries (non-positive or non-numeric) are ignored.415416#### 5.3.6 codex (object)417418Fields:419420For Codex-owned config values such as approval_policy, thread_sandbox, and421turn_sandbox_policy, supported values are defined by the targeted Codex app-server version.422Implementors should treat them as pass-through Codex config values rather than relying on a423hand-maintained enum in this spec. To inspect the installed Codex schema, run424codex app-server generate-json-schema --out and inspect the relevant definitions referenced425by v2/ThreadStartParams.json and v2/TurnStartParams.json. Implementations may validate these426fields locally if they want stricter startup checks.427428- command (string shell command)429 - Default: codex app-server430 - The runtime launches this command via bash -lc in the workspace directory.431 - The launched process must speak a compatible app-server protocol over stdio.432- approval_policy (Codex AskForApproval value)433 - Default: implementation-defined.434- thread_sandbox (Codex SandboxMode value)435 - Default: implementation-defined.436- turn_sandbox_policy (Codex SandboxPolicy value)437 - Default: implementation-defined.438- turn_timeout_ms (integer)439 - Default: 3600000 (1 hour)440- read_timeout_ms (integer)441 - Default: 5000442- stall_timeout_ms (integer)443 - Default: 300000 (5 minutes)444 - If cwd default).4932. YAML front matter values.4943. Environment indirection via $VAR_NAME inside selected YAML values.4954. Built-in defaults.496497Value coercion semantics:498499- Path/command fields support:500 - ~ home expansion501 - $VAR expansion for env-backed path values502 - Apply expansion only to values intended to be local filesystem paths; do not rewrite URIs or503 arbitrary shell command strings.504505### 6.2 Dynamic Reload Semantics506507Dynamic reload is required:508509- The software should watch WORKFLOW.md for changes.510- On change, it should re-read and re-apply workflow config and prompt template without restart.511- The software should attempt to adjust live behavior to the new config (for example polling512 cadence, concurrency limits, active/terminal states, codex settings, workspace paths/hooks, and513 prompt content for future runs).514- Reloaded config applies to future dispatch, retry scheduling, reconciliation decisions, hook515 execution, and agent launches.516- Implementations are not required to restart in-flight agent sessions automatically when config517 changes.518- Extensions that manage their own listeners/resources (for example an HTTP server port change) may519 require restart unless the implementation explicitly supports live rebind.520- Implementations should also re-validate/reload defensively during runtime operations (for example521 before dispatch) in case filesystem watch events are missed.522- Invalid reloads should not crash the service; keep operating with the last known good effective523 configuration and emit an operator-visible error.524525### 6.3 Dispatch Preflight Validation526527This validation is a scheduler preflight run before attempting to dispatch new work. It validates528the workflow/config needed to poll and launch workers, not a full audit of all possible workflow529behavior.530531Startup validation:532533- Validate configuration before starting the scheduling loop.534- If startup validation fails, fail startup and emit an operator-visible error.535536Per-tick dispatch validation:537538- Re-validate before each dispatch cycle.539- If validation fails, skip dispatch for that tick, keep reconciliation active, and emit an540 operator-visible error.541542Validation checks:543544- Workflow file can be loaded and parsed.545- tracker.kind is present and supported.546- tracker.api_key is present after $ resolution.547- tracker.project_slug is present when required by the selected tracker kind.548- codex.command is present and non-empty.549550### 6.4 Config Fields Summary (Cheat Sheet)551552This section is intentionally redundant so a coding agent can implement the config layer quickly.553554- tracker.kind: string, required, currently linear555- tracker.endpoint: string, default https://api.linear.app/graphql when tracker.kind=linear556- tracker.api_key: string or $VAR, canonical env LINEAR_API_KEY when tracker.kind=linear557- tracker.project_slug: string, required when tracker.kind=linear558- tracker.active_states: list of strings, default ["Todo", "In Progress"]559- tracker.terminal_states: list of strings, default ["Closed", "Cancelled", "Canceled", "Duplicate", "Done"]560- polling.interval_ms: integer, default 30000561- workspace.root: path, default /symphony_workspaces562- worker.ssh_hosts (extension): list of SSH host strings, optional; when omitted, work runs563 locally564- worker.max_concurrent_agents_per_host (extension): positive integer, optional; shared per-host565 cap applied across configured SSH hosts566- hooks.after_create: shell script or null567- hooks.before_run: shell script or null568- hooks.after_run: shell script or null569- hooks.before_remove: shell script or null570- hooks.timeout_ms: integer, default 60000571- agent.max_concurrent_agents: integer, default 10572- agent.max_turns: integer, default 20573- agent.max_retry_backoff_ms: integer, default 300000 (5m)574- agent.max_concurrent_agents_by_state: map of positive integers, default {}575- codex.command: shell command string, default codex app-server576- codex.approval_policy: Codex AskForApproval value, default implementation-defined577- codex.thread_sandbox: Codex SandboxMode value, default implementation-defined578- codex.turn_sandbox_policy: Codex SandboxPolicy value, default implementation-defined579- codex.turn_timeout_ms: integer, default 3600000580- codex.read_timeout_ms: integer, default 5000581- codex.stall_timeout_ms: integer, default 300000582- server.port (extension): integer, optional; enables the optional HTTP server, 0 may be used583 for ephemeral local bind, and CLI --port overrides it584585## 7. Orchestration State Machine586587The orchestrator is the only component that mutates scheduling state. All worker outcomes are588reported back to it and converted into explicit state transitions.589590### 7.1 Issue Orchestration States591592This is not the same as tracker states (Todo, In Progress, etc.). This is the service's internal593claim state.5945951. Unclaimed596 - Issue is not running and has no retry scheduled.5975982. Claimed599 - Orchestrator has reserved the issue to prevent duplicate dispatch.600 - In practice, claimed issues are either Running or RetryQueued.6016023. Running603 - Worker task exists and the issue is tracked in running map.6046054. RetryQueued606 - Worker is not running, but a retry timer exists in retry_attempts.6076085. Released609 - Claim removed because issue is terminal, non-active, missing, or retry path completed without610 re-dispatch.611612Important nuance:613614- A successful worker exit does not mean the issue is done forever.615- The worker may continue through multiple back-to-back coding-agent turns before it exits.616- After each normal turn completion, the worker re-checks the tracker issue state.617- If the issue is still in an active state, the worker should start another turn on the same live618 coding-agent thread in the same workspace, up to agent.max_turns.619- The first turn should use the full rendered task prompt.620- Continuation turns should send only continuation guidance to the existing thread, not resend the621 original task prompt that is already present in thread history.622- Once the worker exits normally, the orchestrator still schedules a short continuation retry623 (about 1 second) so it can re-check whether the issue remains active and needs another worker624 session.625626### 7.2 Run Attempt Lifecycle627628A run attempt transitions through these phases:6296301. PreparingWorkspace6312. BuildingPrompt6323. LaunchingAgentProcess6334. InitializingSession6345. StreamingTurn6356. Finishing6367. Succeeded6378. Failed6389. TimedOut63910. Stalled64011. CanceledByReconciliation641642Distinct terminal reasons are important because retry logic and logs differ.643644### 7.3 Transition Triggers645646- Poll Tick647 - Reconcile active runs.648 - Validate config.649 - Fetch candidate issues.650 - Dispatch until slots are exhausted.651652- Worker Exit (normal)653 - Remove running entry.654 - Update aggregate runtime totals.655 - Schedule continuation retry (attempt 1) after the worker exhausts or finishes its in-process656 turn loop.657658- Worker Exit (abnormal)659 - Remove running entry.660 - Update aggregate runtime totals.661 - Schedule exponential-backoff retry.662663- Codex Update Event664 - Update live session fields, token counters, and rate limits.665666- Retry Timer Fired667 - Re-fetch active candidates and attempt re-dispatch, or release claim if no longer eligible.668669- Reconciliation State Refresh670 - Stop runs whose issue states are terminal or no longer active.671672- Stall Timeout673 - Kill worker and schedule retry.674675### 7.4 Idempotency and Recovery Rules676677- The orchestrator serializes state mutations through one authority to avoid duplicate dispatch.678- claimed and running checks are required before launching any worker.679- Reconciliation runs before dispatch on every tick.680- Restart recovery is tracker-driven and filesystem-driven (no durable orchestrator DB required).681- Startup terminal cleanup removes stale workspaces for issues already in terminal states.682683## 8. Polling, Scheduling, and Reconciliation684685### 8.1 Poll Loop686687At startup, the service validates config, performs startup cleanup, schedules an immediate tick, and688then repeats every polling.interval_ms.689690The effective poll interval should be updated when workflow config changes are re-applied.691692Tick sequence:6936941. Reconcile running issues.6952. Run dispatch preflight validation.6963. Fetch candidate issues from tracker using active states.6974. Sort issues by dispatch priority.6985. Dispatch eligible issues while slots remain.6996. Notify observability/status consumers of state changes.700701If per-tick validation fails, dispatch is skipped for that tick, but reconciliation still happens702first.703704### 8.2 Candidate Selection Rules705706An issue is dispatch-eligible only if all are true:707708- It has id, identifier, title, and state.709- Its state is in active_states and not in terminal_states.710- It is not already in running.711- It is not already in claimed.712- Global concurrency slots are available.713- Per-state concurrency slots are available.714- Blocker rule for Todo state passes:715 - If the issue state is Todo, do not dispatch when any blocker is non-terminal.716717Sorting order (stable intent):7187191. priority ascending (1..4 are preferred; null/unknown sorts last)7202. created_at oldest first7213. identifier lexicographic tie-breaker722723### 8.3 Concurrency Control724725Global limit:726727- available_slots = max(max_concurrent_agents - running_count, 0)728729Per-state limit:730731- max_concurrent_agents_by_state[state] if present (state key normalized)732- otherwise fallback to global limit733734The runtime counts issues by their current tracked state in the running map.735736Optional SSH host limit:737738- When worker.max_concurrent_agents_per_host is set, each configured SSH host may run at most739 that many concurrent agents at once.740- Hosts at that cap are skipped for new dispatch until capacity frees up.741742### 8.4 Retry and Backoff743744Retry entry creation:745746- Cancel any existing retry timer for the same issue.747- Store attempt, identifier, error, due_at_ms, and new timer handle.748749Backoff formula:750751- Normal continuation retries after a clean worker exit use a short fixed delay of 1000 ms.752- Failure-driven retries use delay = min(10000 * 2^(attempt - 1), agent.max_retry_backoff_ms).753- Power is capped by the configured max retry backoff (default 300000 / 5m).754755Retry handling behavior:7567571. Fetch active candidate issues (not all issues).7582. Find the specific issue by issue_id.7593. If not found, release claim.7604. If found and still candidate-eligible:761 - Dispatch if slots are available.762 - Otherwise requeue with error no available orchestrator slots.7635. If found but no longer active, release claim.764765Note:766767- Terminal-state workspace cleanup is handled by startup cleanup and active-run reconciliation768 (including terminal transitions for currently running issues).769- Retry handling mainly operates on active candidates and releases claims when the issue is absent,770 rather than performing terminal cleanup itself.771772### 8.5 Active Run Reconciliation773774Reconciliation runs every tick and has two parts.775776Part A: Stall detection777778- For each running issue, compute elapsed_ms since:779 - last_codex_timestamp if any event has been seen, else780 - started_at781- If elapsed_ms > codex.stall_timeout_ms, terminate the worker and queue a retry.782- If stall_timeout_ms success989- turn/failed -> failure990- turn/cancelled -> failure991- turn timeout (turn_timeout_ms) -> failure992- subprocess exit -> failure993994Continuation processing:995996- If the worker decides to continue after a successful turn, it should issue another turn/start997 on the same live threadId.998- The app-server subprocess should remain alive across those continuation turns and be stopped only999 when the worker run is ending.10001001Line handling requirements:10021003- Read protocol messages from stdout only.1004- Buffer partial stdout lines until newline arrives.1005- Attempt JSON parse on complete stdout lines.1006- Stderr is not part of the protocol stream:1007 - ignore it or log it as diagnostics1008 - do not attempt protocol JSON parsing on stderr10091010### 10.4 Emitted Runtime Events (Upstream to Orchestrator)10111012The app-server client emits structured events to the orchestrator callback. Each event should1013include:10141015- event (enum/string)1016- timestamp (UTC timestamp)1017- codex_app_server_pid (if available)1018- optional usage map (token counts)1019- payload fields as needed10201021Important emitted events may include:10221023- session_started1024- startup_failed1025- turn_completed1026- turn_failed1027- turn_cancelled1028- turn_ended_with_error1029- turn_input_required1030- approval_auto_approved1031- unsupported_tool_call1032- notification1033- other_message1034- malformed10351036### 10.5 Approval, Tool Calls, and User Input Policy10371038Approval, sandbox, and user-input behavior is implementation-defined.10391040Policy requirements:10411042- Each implementation should document its chosen approval, sandbox, and operator-confirmation1043 posture.1044- Approval requests and user-input-required events must not leave a run stalled indefinitely. An1045 implementation should either satisfy them, surface them to an operator, auto-resolve them, or1046 fail the run according to its documented policy.10471048Example high-trust behavior:10491050- Auto-approve command execution approvals for the session.1051- Auto-approve file-change approvals for the session.1052- Treat user-input-required turns as hard failure.10531054Unsupported dynamic tool calls:10551056- Supported dynamic tool calls that are explicitly implemented and advertised by the runtime should1057 be handled according to their extension contract.1058- If the agent requests a dynamic tool call (item/tool/call) that is not supported, return a tool1059 failure response and continue the session.1060- This prevents the session from stalling on unsupported tool execution paths.10611062Optional client-side tool extension:10631064- An implementation may expose a limited set of client-side tools to the app-server session.1065- Current optional standardized tool: linear_graphql.1066- If implemented, supported tools should be advertised to the app-server session during startup1067 using the protocol mechanism supported by the targeted Codex app-server version.1068- Unsupported tool names should still return a failure result and continue the session.10691070linear_graphql extension contract:10711072- Purpose: execute a raw GraphQL query or mutation against Linear using Symphony's configured1073 tracker auth for the current session.1074- Availability: only meaningful when tracker.kind == "linear" and valid Linear auth is configured.1075- Preferred input shape:10761077 json1078 {1079 "query": "single GraphQL query or mutation document",1080 "variables": {1081 "optional": "graphql variables object"1082 }1083 }1084 10851086- query must be a non-empty string.1087- query must contain exactly one GraphQL operation.1088- variables is optional and, when present, must be a JSON object.1089- Implementations may additionally accept a raw GraphQL query string as shorthand input.1090- Execute one GraphQL operation per tool call.1091- If the provided document contains multiple operations, reject the tool call as invalid input.1092- operationName selection is intentionally out of scope for this extension.1093- Reuse the configured Linear endpoint and auth from the active Symphony workflow/runtime config; do1094 not require the coding agent to read raw tokens from disk.1095- Tool result semantics:1096 - transport success + no top-level GraphQL errors -> success=true1097 - top-level GraphQL errors present -> success=false, but preserve the GraphQL response body1098 for debugging1099 - invalid input, missing auth, or transport failure -> success=false with an error payload1100- Return the GraphQL response or error payload as structured tool output that the model can inspect1101 in-session.11021103Illustrative responses (equivalent payload shapes are acceptable if they preserve the same outcome):11041105json1106{"id":"","result":{"approved":true}}1107{"id":"","result":{"success":false,"error":"unsupported_tool_call"}}110811091110Hard failure on user input requirement:11111112- If the agent requests user input, fail the run attempt immediately.1113- The client detects this via:1114 - explicit method (item/tool/requestUserInput), or1115 - turn methods/flags indicating input is required.11161117### 10.6 Timeouts and Error Mapping11181119Timeouts:11201121- codex.read_timeout_ms: request/response timeout during startup and sync requests1122- codex.turn_timeout_ms: total turn stream timeout1123- codex.stall_timeout_ms: enforced by orchestrator based on event inactivity11241125Error mapping (recommended normalized categories):11261127- codex_not_found1128- invalid_workspace_cwd1129- response_timeout1130- turn_timeout1131- port_exit1132- response_error1133- turn_failed1134- turn_cancelled1135- turn_input_required11361137### 10.7 Agent Runner Contract11381139The Agent Runner wraps workspace + prompt + app-server client.11401141Behavior:114211431. Create/reuse workspace for issue.11442. Build prompt from workflow template.11453. Start app-server session.11464. Forward app-server events to orchestrator.11475. On any error, fail the worker attempt (the orchestrator will retry).11481149Note:11501151- Workspaces are intentionally preserved after successful runs.11521153## 11. Issue Tracker Integration Contract (Linear-Compatible)11541155### 11.1 Required Operations11561157An implementation must support these tracker adapter operations:115811591. fetch_candidate_issues()1160 - Return issues in configured active states for a configured project.116111622. fetch_issues_by_states(state_names)1163 - Used for startup terminal cleanup.116411653. fetch_issue_states_by_ids(issue_ids)1166 - Used for active-run reconciliation.11671168### 11.2 Query Semantics (Linear)11691170Linear-specific requirements for tracker.kind == "linear":11711172- tracker.kind == "linear"1173- GraphQL endpoint (default https://api.linear.app/graphql)1174- Auth token sent in Authorization header1175- tracker.project_slug maps to Linear project slugId1176- Candidate issue query filters project using project: { slugId: { eq: $projectSlug } }1177- Issue-state refresh query uses GraphQL issue IDs with variable type [ID!]1178- Pagination required for candidate issues1179- Page size default: 501180- Network timeout: 30000 ms11811182Important:11831184- Linear GraphQL schema details can drift. Keep query construction isolated and test the exact query1185 fields/types required by this specification.11861187A non-Linear implementation may change transport details, but the normalized outputs must match the1188domain model in Section 4.11891190### 11.3 Normalization Rules11911192Candidate issue normalization should produce fields listed in Section 4.1.1.11931194Additional normalization details:11951196- labels -> lowercase strings1197- blocked_by -> derived from inverse relations where relation type is blocks1198- priority -> integer only (non-integers become null)1199- created_at and updated_at -> parse ISO-8601 timestamps12001201### 11.4 Error Handling Contract12021203Recommended error categories:12041205- unsupported_tracker_kind1206- missing_tracker_api_key1207- missing_tracker_project_slug1208- linear_api_request (transport failures)1209- linear_api_status (non-200 HTTP)1210- linear_graphql_errors1211- linear_unknown_payload1212- linear_missing_end_cursor (pagination integrity error)12131214Orchestrator behavior on tracker errors:12151216- Candidate fetch failure: log and skip dispatch for this tick.1217- Running-state refresh failure: log and keep active workers running.1218- Startup terminal cleanup failure: log warning and continue startup.12191220### 11.5 Tracker Writes (Important Boundary)12211222Symphony does not require first-class tracker write APIs in the orchestrator.12231224- Ticket mutations (state transitions, comments, PR metadata) are typically handled by the coding1225 agent using tools defined by the workflow prompt.1226- The service remains a scheduler/runner and tracker reader.1227- Workflow-specific success often means "reached the next handoff state" (for example1228 Human Review) rather than tracker terminal state Done.1229- If the optional linear_graphql client-side tool extension is implemented, it is still part of1230 the agent toolchain rather than orchestrator business logic.12311232## 12. Prompt Construction and Context Assembly12331234### 12.1 Inputs12351236Inputs to prompt rendering:12371238- workflow.prompt_template1239- normalized issue object1240- optional attempt integer (retry/continuation metadata)12411242### 12.2 Rendering Rules12431244- Render with strict variable checking.1245- Render with strict filter checking.1246- Convert issue object keys to strings for template compatibility.1247- Preserve nested arrays/maps (labels, blockers) so templates can iterate.12481249### 12.3 Retry/Continuation Semantics12501251attempt should be passed to the template because the workflow prompt may provide different1252instructions for:12531254- first run (attempt null or absent)1255- continuation run after a successful prior session1256- retry after error/timeout/stall12571258### 12.4 Failure Semantics12591260If prompt rendering fails:12611262- Fail the run attempt immediately.1263- Let the orchestrator treat it like any other worker failure and decide retry behavior.12641265## 13. Logging, Status, and Observability12661267### 13.1 Logging Conventions12681269Required context fields for issue-related logs:12701271- issue_id1272- issue_identifier12731274Required context for coding-agent session lifecycle logs:12751276- session_id12771278Message formatting requirements:12791280- Use stable key=value phrasing.1281- Include action outcome (completed, failed, retrying, etc.).1282- Include concise failure reason when present.1283- Avoid logging large raw payloads unless necessary.12841285### 13.2 Logging Outputs and Sinks12861287The spec does not prescribe where logs must go (stderr, file, remote sink, etc.).12881289Requirements:12901291- Operators must be able to see startup/validation/dispatch failures without attaching a debugger.1292- Implementations may write to one or more sinks.1293- If a configured log sink fails, the service should continue running when possible and emit an1294 operator-visible warning through any remaining sink.12951296### 13.3 Runtime Snapshot / Monitoring Interface (Optional but Recommended)12971298If the implementation exposes a synchronous runtime snapshot (for dashboards or monitoring), it1299should return:13001301- running (list of running session rows)1302- each running row should include turn_count1303- retrying (list of retry queue rows)1304- codex_totals1305 - input_tokens1306 - output_tokens1307 - total_tokens1308 - seconds_running (aggregate runtime seconds as of snapshot time, including active sessions)1309- rate_limits (latest coding-agent rate limit payload, if available)13101311Recommended snapshot error modes:13121313- timeout1314- unavailable13151316### 13.4 Optional Human-Readable Status Surface13171318A human-readable status surface (terminal output, dashboard, etc.) is optional and1319implementation-defined.13201321If present, it should draw from orchestrator state/metrics only and must not be required for1322correctness.13231324### 13.5 Session Metrics and Token Accounting13251326Token accounting rules:13271328- Agent events may include token counts in multiple payload shapes.1329- Prefer absolute thread totals when available, such as:1330 - thread/tokenUsage/updated payloads1331 - total_token_usage within token-count wrapper events1332- Ignore delta-style payloads such as last_token_usage for dashboard/API totals.1333- Extract input/output/total token counts leniently from common field names within the selected1334 payload.1335- For absolute totals, track deltas relative to last reported totals to avoid double-counting.1336- Do not treat generic usage maps as cumulative totals unless the event type defines them that1337 way.1338- Accumulate aggregate totals in orchestrator state.13391340Runtime accounting:13411342- Runtime should be reported as a live aggregate at snapshot/render time.1343- Implementations may maintain a cumulative counter for ended sessions and add active-session1344 elapsed time derived from running entries (for example started_at) when producing a1345 snapshot/status view.1346- Add run duration seconds to the cumulative ended-session runtime when a session ends (normal exit1347 or cancellation/termination).1348- Continuous background ticking of runtime totals is not required.13491350Rate-limit tracking:13511352- Track the latest rate-limit payload seen in any agent update.1353- Any human-readable presentation of rate-limit data is implementation-defined.13541355### 13.6 Humanized Agent Event Summaries (Optional)13561357Humanized summaries of raw agent protocol events are optional.13581359If implemented:13601361- Treat them as observability-only output.1362- Do not make orchestrator logic depend on humanized strings.1363
The reference implementation is written in Elixir—because when code is effectively free, you can finally pick languages for their strengths, like Elixir's concurrency—but the core idea can be expressed in a simple Markdown document. We encourage you to point your favorite coding agent at the spec and have it implement its own version.
The first version of Symphony was just a Codex session running in tmux, polling Linear and spawning sub-agents for new tasks. It worked, but it wasn’t particularly reliable. The second version lived inside our main project repository, which was built with agents in mind. We had already built the agent harness to give agents the skills and context to do high quality work in this repo, so Symphony simply connects it all.
Once the basic functionality existed, we used Symphony to build Symphony.
When we internally demoed the system managing tasks and attaching its proof-of-work video, the reaction was overwhelmingly positive: our Symphony project channel grew, and teams across the organization started using it organically. Internal product market fit is a prerequisite for launching externally at OpenAI. Based on the usage we saw at OpenAI, it became clear we should share Symphony beyond company walls.
So we extracted the idea into a standalone SPEC.md and asked Codex to implement it. For the reference implementation, we chose Elixir, a relatively niche language with excellent primitives for orchestrating and supervising concurrent processes. Codex built the Elixir implementation in one shot, and we kept iterating on both spec and implementation from there. To polish the spec, we even asked Codex to implement it in several other languages—TypeScript, Go, Rust, Java, Python—and use the results to identify ambiguities and simplify the system. It succeeded in every language.
Through the process of building Symphony, we removed a lot of incidental complexity, like dependencies on specific repositories or Linear MCP. Symphony no longer depends on our internal repositories or workflows. The core approach became simple:
> For every open task, guarantee that an agent is running in its own workspace.
In addition to helping with the active work, the development workflow is now something agents know and follow. The development workflow—work on an issue, check out a repo, put it in progress so the PM knows it's being worked on, add the PR, move it to the Review status, attach videos, etc.—is now captured in a simple WORKFLOW.md file. All of this is a process that humans followed, but it was never documented. Rather than relying on this implicit set of steps, we now document it, and Symphony ensures agents follow it. This lets us build agents that work alongside us. If we decide that agents should also attach self-reflection to finished work, we'll add that to the WORKFLOW.md, and Symphony will guide the agents to that step.
We also got to use Codex in app server mode(opens in a new window), a built-in headless mode for Codex. This mode allowed us to run Codex and talk to it programmatically via a well documented JSON-RPC API for things like starting a thread or reacting to turns. It’s more convenient and scalable than trying to interact with Codex via CLI or live tmux sessions.
Codex App Server was a perfect fit for our use case: we take advantage of the harness Codex provides while having knobs and hooks to plug into. For example, to avoid exposing the Linear access token to subagents, we use dynamic tool calls(opens in a new window) to expose the raw linear_graphql function that executes arbitrary requests against Linear, without relying on MCP or exposing the access token to containers.
What’s next
Symphony is an intentionally minimal orchestration layer. We’re open sourcing it to demonstrate the power of Codex App Server when paired with different workflow tools, like Linear. As such, we don't plan to maintain Symphony as a standalone product. Think of it as a reference implementation. Similar to how many developers pointed their coding agents at the harness engineering post to scaffold their repositories, we hope you point your favorite coding agent at the Symphony spec(opens in a new window) and repository(opens in a new window) to build your own versions tailored to your environments.
The power comes from Codex and its app server. Symphony was a way to connect Codex to Linear, two things we already used, to solve the work management problem. As coding agents become better at reasoning and following instructions, we suspect the bottleneck at other companies will shift from writing code toward managing agentic work, too. The exciting part is that the barrier to experimenting with these coding agent systems is now surprisingly low. You can just build things with Codex.
Community shoutouts
We're thrilled to see the engineering community using Symphony in the weeks since release, garnering over 15K GitHub stars(opens in a new window) as of April 23.
Sort
Social Post
March 8
Link copied to clipboard!
Caleeeb
@adacaleeeb
·Follow
[](https://x.com/adacaleeeb/status/2030490162921124030)
Told an agent to make a version of openAI's symphony repo in my elixir ERP app. One shotted a full dashboard with genservers and custom agents to catch bugs in prod and spin up agents to fix and commit. Also added a user request feature that ties into the same system. 🤯🤯🤯
3:45 AM · Mar 8, 2026[](https://help.x.com/en/x-for-websites-ads-info-and-privacy)
1ReplyCopy link
Read more on X
March 7
JUNØ
@_junhoyeo
[](https://x.com/_junhoyeo/status/2030159898424844593)
OpenAI dropped Symphony, a project-level AI coding agent orchestrator I built a Go implementation with @charmcli stack TUI 🎸 github.com/junhoyeo/contr…
can
@marmaduke091
🎵 OpenAI introduces Symphony "Symphony turns project work into isolated, autonomous implementation runs, allowing teams to manage work instead of supervising coding agents." Check it out, seems cool: github.com/openai/symphony
Watch on X
5:53 AM · Mar 7, 2026[](https://help.x.com/en/x-for-websites-ads-info-and-privacy)
10ReplyCopy link
Read 1 reply
Hoon Choi
@sapsaldog84
[](https://x.com/sapsaldog84/status/2030421903777915071)
OpenAI's Symphony is a great coding agent orchestrator — but @OpenAI codex-only. I forked it to work with @AnthropicAI's Claude Code + GitHub Issues. Open source, installable via Homebrew. sapsaldog.com/posts/symphony…
Running OpenAI Symphony with Claude Code
11:14 PM · Mar 7, 2026[](https://help.x.com/en/x-for-websites-ads-info-and-privacy)
0ReplyCopy link
March 6
Mert Koseoglu — Context Mode
@mksglu
[](https://x.com/mksglu/status/2030069838333329601)
OpenAI published Symphony — a spec for turning project work into autonomous implementation runs. Manage work, not agents. I took that idea and rebuilt it with Claude Code @AnthropicAI hatice is my implementation of the Symphony spec, powered by Claude Code Agent SDK. ItShow more
11:55 PM · Mar 6, 2026[](https://help.x.com/en/x-for-websites-ads-info-and-privacy)
38ReplyCopy link
Read 4 replies
·Follow
[](https://x.com/sapsaldog84/status/2030421903777915071)
OpenAI's Symphony is a great coding agent orchestrator — but @OpenAI codex-only. I forked it to work with @AnthropicAI's Claude Code + GitHub Issues. Open source, installable via Homebrew. sapsaldog.com/posts/symphony…
Running OpenAI Symphony with Claude Code
11:14 PM · Mar 7, 2026[](https://help.x.com/en/x-for-websites-ads-info-and-privacy)
0ReplyCopy link
Read more on X
Social Post
March 6
Link copied to clipboard!
Mert Koseoglu — Context Mode
@mksglu
·Follow
[](https://x.com/mksglu/status/2030069838333329601)
OpenAI published Symphony — a spec for turning project work into autonomous implementation runs. Manage work, not agents. I took that idea and rebuilt it with Claude Code @AnthropicAI hatice is my implementation of the Symphony spec, powered by Claude Code Agent SDK. ItShow more
Watch on X
11:55 PM · Mar 6, 2026[](https://help.x.com/en/x-for-websites-ads-info-and-privacy)
38ReplyCopy link
Read 4 replies
Help shape what we cover next Help bepalen wat we hierna volgen
Anonymous feedback, no frontend account needed. Anonieme feedback, zonder front-end account.
More from OpenAI Meer van OpenAI
All updates Alle updatesChoco automates food distribution with AI agents Choco automates food distribution with AI agents
Using OpenAI APIs, Choco processes millions of orders, reducing manual work and enabling always-on operations across global food supply chains. Using OpenAI APIs, Choco processes millions of orders, reducing manual work and enabling always-on operations across global food supply chains.
The next phase of the Microsoft OpenAI partnership The next phase of the Microsoft OpenAI partnership
Amended agreement provides long-term clarity. Amended agreement provides long-term clarity.
Our principles Our principles
By Sam Altman By Sam Altman
GPT-5.5 Bio Bug Bounty GPT-5.5 Bio Bug Bounty
Title: GPT-5.5 Bio Bug Bounty Titel: GPT-5.5 Bio Bug Bounty