Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ work instead of supervising coding agents.

_In this [demo video](https://player.vimeo.com/video/1186371009?h=5626e4b899), Symphony monitors a Linear board for work and spawns agents to handle the tasks. The agents complete the tasks and provide proof of work: CI status, PR review feedback, complexity analysis, and walkthrough videos. When accepted, the agents land the PR safely. Engineers do not need to supervise Codex; they can manage the work at a higher level._

The reference implementation can also keep the Codex thread attached to the issue lifecycle: it
surfaces thread links, resumes from human Linear comments, and archives threads after terminal
issues are cleaned up.

> [!WARNING]
> Symphony is a low-key engineering preview for testing in trusted environments.

Expand Down
39 changes: 5 additions & 34 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,8 @@ stricter approvals or sandboxing.
Important boundary:

- Symphony is a scheduler/runner and tracker reader.
- Most ticket writes (state transitions, progress comments, PR links) are typically performed by
the coding agent using tools available in the workflow/runtime environment. Implementations MAY
also perform narrowly scoped service comments that are part of orchestration, such as asking for
missing human input.
- Ticket writes (state transitions, comments, PR links) are typically performed by the coding agent
using tools available in the workflow/runtime environment.
- A successful run can end at a workflow-defined handoff state (for example `Human Review`), not
necessarily `Done`.

Expand All @@ -52,8 +50,6 @@ Important boundary:
- Create deterministic per-issue workspaces and preserve them across runs.
- Stop active runs when issue state changes make them ineligible.
- Recover from transient failures with exponential backoff.
- Carry fresh tracker comments into continuation turns when an implementation supports human input
through the issue tracker.
- Load runtime behavior from a repository-owned `WORKFLOW.md` contract.
- Expose operator-visible observability (at minimum structured logs).
- Support tracker/filesystem-driven restart recovery without requiring a persistent database; exact
Expand Down Expand Up @@ -88,7 +84,6 @@ Important boundary:
- Fetches candidate issues in active states.
- Fetches current states for specific issue IDs (reconciliation).
- Fetches terminal-state issues during startup cleanup.
- Fetches issue comments when the implementation uses tracker comments as human input.
- Normalizes tracker payloads into a stable issue model.

4. `Orchestrator`
Expand Down Expand Up @@ -178,15 +173,6 @@ Fields:
- `id` (string or null)
- `identifier` (string or null)
- `state` (string or null)
- `comments` (list of comment refs, OPTIONAL)
- Present when the tracker adapter fetches comments for human input.
- Each comment ref contains:
- `id` (string)
- `body` (string)
- `author_id` (string or null)
- `author_name` (string or null)
- `created_at` (timestamp or null)
- `updated_at` (timestamp or null)
- `created_at` (timestamp or null)
- `updated_at` (timestamp or null)

Expand Down Expand Up @@ -646,14 +632,9 @@ Important nuance:
- The first turn SHOULD use the full rendered task prompt.
- Continuation turns SHOULD send only continuation guidance to the existing thread, not resend the
original task prompt that is already present in thread history.
- If new human tracker comments are available, continuation guidance SHOULD include those comments
as fresh input and keep using the existing coding-agent thread/workspace.
- Once the worker exits normally, the orchestrator still schedules a short continuation retry
(about 1 second) so it can re-check whether the issue remains active and needs another worker
session.
- If the agent stops because it needs human input, an implementation MAY retain the workspace and
thread metadata in the retry queue, post a tracker comment asking for the input, and resume the
same thread when a newer human comment appears.

### 7.2 Run Attempt Lifecycle

Expand Down Expand Up @@ -814,8 +795,6 @@ Part B: Tracker state refresh
- If tracker state is terminal: terminate worker and clean workspace.
- If tracker state is still active: update the in-memory issue snapshot.
- If tracker state is neither active nor terminal: terminate worker without workspace cleanup.
- If tracker comments are used as human input, reconciliation MAY also capture newer human comments
for the running worker or for a blocked retry entry.
- If state refresh fails, keep workers running and try again on the next tick.

### 8.6 Startup Terminal Workspace Cleanup
Expand Down Expand Up @@ -986,10 +965,6 @@ Session identifiers:
- Extract `turn_id` from each turn identity returned by the targeted Codex app-server protocol.
- Emit `session_id = "<thread_id>-<turn_id>"`
- Reuse the same `thread_id` for all continuation turns inside one worker run
- If the targeted coding-agent surface supports thread URLs, status surfaces SHOULD expose a link
derived from `thread_id`.
- If the targeted coding-agent surface supports archiving threads, implementations MAY archive the
thread when the associated issue reaches a terminal state.

### 10.3 Streaming Turn Processing

Expand Down Expand Up @@ -1200,8 +1175,6 @@ Additional normalization details:

- `labels` -> lowercase strings
- `blocked_by` -> derived from inverse relations where relation type is `blocks`
- `comments` -> chronological tracker comments when fetched; implementation-defined filters MAY
exclude service-owned workpad or orchestration marker comments from human-input handling
- `priority` -> integer only (non-integers become null)
- `created_at` and `updated_at` -> parse ISO-8601 timestamps

Expand All @@ -1226,15 +1199,13 @@ Orchestrator behavior on tracker errors:

### 11.5 Tracker Writes (Important Boundary)

Symphony does not require broad first-class tracker write APIs in the orchestrator.
Symphony does not require first-class tracker write APIs in the orchestrator.

- Ticket mutations (state transitions, comments, PR metadata) are typically handled by the coding
agent using tools defined by the workflow prompt.
- The service remains a scheduler/runner and tracker reader.
- Workflow-specific success often means "reached the next handoff state" (for example
`Human Review`) rather than tracker terminal state `Done`.
- Implementations MAY use narrowly scoped tracker writes for orchestration-only notices, such as a
marked comment requesting human input before resuming the same thread.
- If the `linear_graphql` client-side tool extension is implemented, it is still part of the agent
toolchain rather than orchestrator business logic.

Expand Down Expand Up @@ -2124,8 +2095,8 @@ Use the same validation profiles as Section 17:
- TODO: Persist retry queue and session metadata across process restarts.
- TODO: Make observability settings configurable in workflow front matter without prescribing UI
implementation details.
- TODO: Add broader first-class tracker write APIs (state transitions, PR metadata, editable
progress comments) in the orchestrator instead of only via agent tools.
- TODO: Add first-class tracker write APIs (comments/state transitions) in the orchestrator instead
of only via agent tools.
- TODO: Add pluggable issue tracker adapters beyond Linear.

### 18.3 Operational Validation Before Production (RECOMMENDED)
Expand Down
35 changes: 5 additions & 30 deletions elixir/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,20 @@ This directory contains the current Elixir/OTP implementation of Symphony, based
1. Polls Linear for candidate work
2. Creates a workspace per issue
3. Launches Codex in [App Server mode](https://developers.openai.com/codex/app-server/) inside the
workspace, or connects to an existing app-server through `codex app-server proxy`
workspace
4. Sends a workflow prompt to Codex
5. Keeps Codex working on the issue until the work is done

During app-server sessions, Symphony also serves a client-side `linear_graphql` tool so that repo
skills can make raw Linear GraphQL calls.

If a claimed issue moves to a terminal state (`Done`, `Closed`, `Cancelled`, or `Duplicate`),
Symphony stops the active agent for that issue, archives the matching Codex thread when known, and
cleans up matching workspaces.
Symphony stops the active agent for that issue and cleans up matching workspaces.

If Codex reports that operator input, approval, or MCP elicitation is required, Symphony keeps the
issue claimed and exposes it as blocked in the runtime state, JSON API, and dashboard. Blocked
entries keep the Codex `thread_id`, workspace path, and a Linear comment cursor. Symphony posts a
marked "Codex needs input" comment on the issue when possible. When a new non-workpad Linear
comment appears after the cursor, Symphony resumes the same Codex thread and worktree with that
comment as fresh human input.

Linear comments added while a turn is actively running are queued in memory and included in the
next retry/continuation that Symphony starts. The Codex app remains the rich console for taking over
directly; Linear is the async conversation surface for issue-specific feedback.
entries are in memory only; restarting the orchestrator clears that blocked map, so any still-active
Linear issue can become a dispatch candidate again after restart.

## How to use it

Expand Down Expand Up @@ -112,9 +105,6 @@ agent:
max_turns: 20
codex:
command: codex app-server
model: gpt-5
reasoning_effort: high
service_tier: fast
---

You are working on a Linear issue {{ issue.identifier }}.
Expand All @@ -131,12 +121,6 @@ Notes:
- `codex.turn_sandbox_policy` defaults to a `workspaceWrite` policy rooted at the current issue workspace
- Supported `codex.approval_policy` values depend on the targeted Codex app-server version. In the current local Codex schema, string values include `untrusted`, `on-failure`, `on-request`, and `never`, and object-form `reject` is also supported.
- Supported `codex.thread_sandbox` values: `read-only`, `workspace-write`, `danger-full-access`.
- Optional `codex.model`, `codex.reasoning_effort`, and `codex.service_tier` values are sent on
`thread/start` or `turn/start`, which is useful when `codex.command` is a proxy to an already
running shared app-server and cannot rely on CLI `--config` flags.
- Set `codex.attach_worktree_owner: true` for local Git workspaces to write Codex's
`codex-thread.json` owner metadata after `thread/start`; this lets the Codex app associate the
worktree with the created thread.
- When `codex.turn_sandbox_policy` is set explicitly, Symphony passes the map through to Codex
unchanged. Compatibility then depends on the targeted Codex app-server version rather than local
Symphony validation.
Expand All @@ -163,16 +147,7 @@ hooks:
after_create: |
git clone --depth 1 "$SOURCE_REPO_URL" .
codex:
command: codex app-server proxy --sock "${CODEX_HOME:-$HOME/.codex}/app-server-control/app-server-control.sock"
model: gpt-5.5
reasoning_effort: xhigh
service_tier: fast
approval_policy: never
thread_sandbox: danger-full-access
turn_sandbox_policy:
type: dangerFullAccess
attach_worktree_owner: true
read_timeout_ms: 60000
command: "$CODEX_BIN --config 'model=\"gpt-5.5\"' app-server"
```

- If `WORKFLOW.md` is missing or has invalid YAML at startup, Symphony does not boot.
Expand Down
57 changes: 20 additions & 37 deletions elixir/WORKFLOW.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
tracker:
kind: linear
project_slug: "yansen-symphony-b1cf2e8198aa"
project_slug: "symphony-0c79b11b75ea"
active_states:
- Todo
- In Progress
Expand All @@ -16,39 +16,24 @@ tracker:
polling:
interval_ms: 5000
workspace:
root: ~/.codex/worktrees/symphony
root: ~/code/symphony-workspaces
hooks:
timeout_ms: 900000
after_create: |
set -eu
repo=/home/dev-user/code/openai
issue="$(basename "$PWD")"
branch="codex/symphony-${issue}"

git -C "$repo" fetch origin master
git -C "$repo" worktree prune

if git -C "$repo" show-ref --verify --quiet "refs/heads/$branch"; then
git -C "$repo" worktree add "$PWD" "$branch"
else
git -C "$repo" worktree add -b "$branch" "$PWD" origin/master
git clone --depth 1 https://github.com/openai/symphony .
if command -v mise >/dev/null 2>&1; then
cd elixir && mise trust && mise exec -- mix deps.get
fi
before_remove: |
git -C /home/dev-user/code/openai worktree remove --force "$PWD" || true
cd elixir && mise exec -- mix workspace.before_remove
agent:
max_concurrent_agents: 10
max_turns: 20
codex:
command: codex app-server proxy --sock "${CODEX_HOME:-$HOME/.codex}/app-server-control/app-server-control.sock"
model: gpt-5.5
reasoning_effort: xhigh
service_tier: fast
command: codex --config shell_environment_policy.inherit=all --config 'model="gpt-5.5"' --config model_reasoning_effort=xhigh app-server
approval_policy: never
thread_sandbox: danger-full-access
thread_sandbox: workspace-write
turn_sandbox_policy:
type: dangerFullAccess
attach_worktree_owner: true
read_timeout_ms: 60000
type: workspaceWrite
---

You are working on a Linear ticket `{{ issue.identifier }}`
Expand Down Expand Up @@ -78,10 +63,9 @@ No description provided.

Instructions:

1. This is an asynchronous orchestration session. Work autonomously, but ask concise questions in Linear when human judgment, missing context, secrets, or permissions are required.
2. Treat new human Linear comments as fresh instructions for the current thread and worktree. Re-read them before continuing after any pause or continuation.
3. Only stop early for a true blocker. If blocked, record the question/blocker in the workpad and leave a clear Linear comment that explains exactly what input is needed.
4. Final message must report completed actions and blockers only.
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".

Work only in the provided repository copy. Do not touch any other path.

Expand All @@ -106,16 +90,15 @@ The agent should be able to talk to Linear, either via a configured Linear MCP s
current issue as `related`, and use `blockedBy` when the follow-up depends on
the current issue.
- Move status only when the matching quality bar is met.
- Operate autonomously end-to-end unless blocked by missing requirements, secrets, permissions, or an explicit human product/technical decision.
- Operate autonomously end-to-end unless blocked by missing requirements, secrets, or permissions.
- Use the blocked-access escape hatch only for true external blockers (missing required tools/auth) after exhausting documented fallbacks.
- If a human replies in Linear, treat that reply as authoritative follow-up context for the same Codex thread. Update the workpad before resuming implementation.

## Related skills

- `linear`: interact with Linear.
- `commit`: produce clean, logical commits during implementation.
- `push`: keep remote branch current and publish updates.
- `pull`: keep branch updated with latest `origin/master` before handoff.
- `pull`: keep branch updated with latest `origin/main` before handoff.
- `land`: when ticket reaches `Merging`, explicitly open and follow `.codex/skills/land/SKILL.md`, which includes the `land` loop.

## Status map
Expand Down Expand Up @@ -144,7 +127,7 @@ The agent should be able to talk to Linear, either via a configured Linear MCP s
- `Done` -> do nothing and shut down.
4. Check whether a PR already exists for the current branch and whether it is closed.
- If a branch PR exists and is `CLOSED` or `MERGED`, treat prior branch work as non-reusable for this run.
- Create a fresh branch from `origin/master` and restart execution flow as a new attempt.
- Create a fresh branch from `origin/main` and restart execution flow as a new attempt.
5. For `Todo` tickets, do startup sequencing in this exact order:
- `update_issue(..., state: "In Progress")`
- find/create `## Codex Workpad` bootstrap comment
Expand All @@ -167,15 +150,15 @@ The agent should be able to talk to Linear, either via a configured Linear MCP s
4. Start work by writing/updating a hierarchical plan in the workpad comment.
5. Ensure the workpad includes a compact environment stamp at the top as a code fence line:
- Format: `<host>:<abs-workdir>@<short-sha>`
- Example: `devbox-01:/home/dev-user/.codex/worktrees/symphony/MT-32@7bdde33bc`
- Example: `devbox-01:/home/dev-user/code/symphony-workspaces/MT-32@7bdde33bc`
- Do not include metadata already inferable from Linear issue fields (`issue ID`, `status`, `branch`, `PR link`).
6. Add explicit acceptance criteria and TODOs in checklist form in the same comment.
- If changes are user-facing, include a UI walkthrough acceptance criterion that describes the end-to-end user path to validate.
- If changes touch app files or app behavior, add explicit app-specific flow checks to `Acceptance Criteria` in the workpad (for example: launch path, changed interaction path, and expected result path).
- If the ticket description/comment context includes `Validation`, `Test Plan`, or `Testing` sections, copy those requirements into the workpad `Acceptance Criteria` and `Validation` sections as required checkboxes (no optional downgrade).
7. Run a principal-style self-review of the plan and refine it in the comment.
8. Before implementing, capture a concrete reproduction signal and record it in the workpad `Notes` section (command/output, screenshot, or deterministic UI behavior).
9. Run the `pull` skill to sync with latest `origin/master` before any code edits, then record the pull/sync result in the workpad `Notes`.
9. Run the `pull` skill to sync with latest `origin/main` before any code edits, then record the pull/sync result in the workpad `Notes`.
- Include a `pull skill evidence` note with:
- merge source(s),
- result (`clean` or `conflicts resolved`),
Expand Down Expand Up @@ -234,7 +217,7 @@ Use this only when completion is blocked by missing required tools or missing au
7. Before every `git push` attempt, run the required validation for your scope and confirm it passes; if it fails, address issues and rerun until green, then commit and push changes.
8. Attach PR URL to the issue (prefer attachment; use the workpad comment only if attachment is unavailable).
- Ensure the GitHub PR has label `symphony` (add it if missing).
9. Merge latest `origin/master` into branch, resolve conflicts, and rerun checks.
9. Merge latest `origin/main` into branch, resolve conflicts, and rerun checks.
10. Update the workpad comment with final checklist status and validation notes.
- Mark completed plan/acceptance/validation checklist items as checked.
- Add final handoff notes (commit + validation summary) in the same workpad comment.
Expand Down Expand Up @@ -270,7 +253,7 @@ Use this only when completion is blocked by missing required tools or missing au
2. Re-read the full issue body and all human comments; explicitly identify what will be done differently this attempt.
3. Close the existing PR tied to the issue.
4. Remove the existing `## Codex Workpad` comment from the issue.
5. Create a fresh branch from `origin/master`.
5. Create a fresh branch from `origin/main`.
6. Start over from the normal kickoff flow:
- If current issue state is `Todo`, move it to `In Progress`; otherwise keep the current state.
- Create a new bootstrap `## Codex Workpad` comment.
Expand All @@ -289,7 +272,7 @@ Use this only when completion is blocked by missing required tools or missing au
## Guardrails

- If the branch PR is already closed/merged, do not reuse that branch or prior implementation state for continuation.
- For closed/merged branch PRs, create a new branch from `origin/master` and restart from reproduction/planning as if starting fresh.
- For closed/merged branch PRs, create a new branch from `origin/main` and restart from reproduction/planning as if starting fresh.
- If issue state is `Backlog`, do not modify it; wait for human to move to `Todo`.
- Do not edit the issue body/description for planning or progress tracking.
- Use exactly one persistent workpad comment (`## Codex Workpad`) per issue.
Expand Down
Loading
Loading