Note: This project was one-shot by Codex and is pending human review.
Go implementation of the Symphony service specified by openai/symphony.
symphony is a long-running service that:
- Loads a repository-owned
WORKFLOW.md. - Resolves typed runtime config from YAML front matter.
- Polls Linear for active issues.
- Creates per-issue workspaces under the configured workspace root.
- Runs Codex app-server sessions inside those workspaces.
- Reconciles running sessions against tracker state and retries failed work with backoff.
internal/workflow:WORKFLOW.mdloading, parsing, reload management.internal/config: typed config resolution and dispatch validation.internal/tracker/linear: Linear GraphQL adapter and normalization.internal/workspace: workspace creation, hooks, cleanup, and path safety.internal/codex: Codex app-server protocol client over stdio.internal/httpserver: optional loopback HTTP listener wrapper.internal/httpapi: dashboard and JSON API handlers.internal/tools/lineargraphql: optionallinear_graphqlCodex tool implementation.internal/worker: one worker attempt with continuation turns on a shared thread.internal/orchestrator: polling, dispatch, retries, reconciliation, and runtime accounting.internal/service: host wiring for dynamic reload, startup cleanup, and tick scheduling.
Create a WORKFLOW.md in the repository root, then run:
go run ./cmd/symphonyOr provide an explicit workflow path:
go run ./cmd/symphony path/to/WORKFLOW.mdEnable the optional HTTP surface from the CLI:
go run ./cmd/symphony --port 8080Or from WORKFLOW.md:
server:
port: 8080Required workflow values for real dispatch:
tracker.kind: lineartracker.project_slugtracker.api_keyorLINEAR_API_KEYcodex.commandif you do not want the defaultcodex app-server
HTTP port precedence:
- CLI
--portoverridesserver.port. - The HTTP server binds loopback only (
127.0.0.1). - Listener changes are restart-bound; workflow reload does not hot-rebind the HTTP port.
This implementation currently targets a trusted-host model.
- Codex runs inside per-issue workspace directories only.
- Workspace paths are sanitized and validated to stay under the configured workspace root.
- Workspace hooks are treated as trusted shell configuration.
- Approval requests are auto-approved in the Codex client.
- User-input-required turns fail immediately instead of stalling.
If you need a stricter deployment, add host/container isolation and tighten Codex approval/sandbox settings in WORKFLOW.md.
- Structured logs are emitted through Go
slog. - Runtime state is available through the in-process orchestrator snapshot API used by the host layer.
- Aggregate token usage, live session state, retry queue state, and runtime totals are tracked live in memory and persisted to
.symphony/state.json. - Optional HTTP endpoints:
GET /GET /api/v1/stateGET /api/v1/<issue_identifier>POST /api/v1/refresh
- Retry entries, aggregate token/runtime totals, rate-limit snapshots, and per-issue debug/session metadata are persisted to
.symphony/state.json. - On startup, persisted retries are re-armed from their saved due times.
- Running workers are not resumed after a restart. Symphony recovers by re-polling Linear and dispatching fresh work if the issue is still active.
- Persisted state is operational metadata, not a durable job ledger.
The Codex client now advertises and handles the optional linear_graphql tool when the active tracker is Linear.
- Tool calls reuse the active workflow's Linear endpoint and auth.
- Supported calls must contain exactly one GraphQL operation.
- Unknown tool names still return
unsupported_tool_callwithout stalling the session. - User-input-required turns still fail immediately.
The repository includes opt-in smoke tests for real Linear and real Codex app-server validation.
- They are skipped by default and only run when explicit
SYMPHONY_RUN_*_INTEGRATION=1flags are set. - Required env vars and example commands are documented in docs/integration-testing.md.
- These tests are intended for operator validation, not routine offline CI.
- No tracker adapters beyond Linear.
- No SSH worker extension from Appendix A.
Run the full test suite with:
GOCACHE=/tmp/go-build-cache GOMODCACHE=/tmp/go-mod-cache go test ./...