This directory contains a Python implementation of Symphony, based on
SPEC.md at the repository root.
Warning
Prototype software intended for evaluation. Not hardened for production use.
- Polls Linear for candidate work.
- Creates a workspace per issue.
- Launches Codex in App Server mode inside the workspace.
- Sends a workflow prompt to Codex.
- 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 and cleans up matching workspaces.
- Make sure your codebase is set up to work well with agents: see Harness engineering.
- Get a new personal token in Linear via Settings → Security & access → Personal API keys, and
set it as the
LINEAR_API_KEYenvironment variable. - Create a
WORKFLOW.mdin your repo (see example below). - Customize the workflow file for your project:
tracker.project_slug— your Linear project slug (from the project URL).workspace.root— where per-issue workspaces are created.hooks.after_create— optional script to bootstrap new workspaces (e.g.,git clone).
- Install dependencies and start the service.
- Python 3.12+
- Codex CLI for agent execution
cd python
pip install -e ".[server]" # include --port support for the HTTP dashboardcd python
python -m symphony /path/to/WORKFLOW.md --port 8080If no workflow path is given, defaults to ./WORKFLOW.md. Optional flags:
--port— enables the FastAPI dashboard and JSON API on that port.--logs-root— directory for log files (default:./log).
Symphony is configured through a WORKFLOW.md file with YAML front matter and a Markdown prompt
body. Example:
---
tracker:
kind: linear
project_slug: my-project
workspace:
root: ~/symphony_workspaces
hooks:
after_create: |
git clone git@github.com:my-org/my-repo.git .
agent:
max_concurrent_agents: 5
max_turns: 20
codex:
command: codex app-server
---
You are working on {{ issue.identifier }}: {{ issue.title }}.python/
├── pyproject.toml
├── src/symphony/
│ ├── __main__.py # CLI entry point
│ ├── cli.py # Argument parsing
│ ├── models.py # Domain models (Issue, Workspace, OrchestratorState)
│ ├── config.py # Typed config with defaults + $VAR resolution
│ ├── workflow.py # WORKFLOW.md loader
│ ├── workflow_store.py # File watching and reload
│ ├── orchestrator.py # Poll loop, dispatch, retry, reconciliation
│ ├── workspace.py # Per-issue workspace lifecycle and hooks
│ ├── agent_runner.py # Codex app-server subprocess client
│ ├── prompt_builder.py # Jinja2 strict template rendering
│ ├── path_safety.py # Path sanitization and containment
│ ├── hooks.py # Shell hook execution with timeout
│ ├── log.py # Structured logging (structlog)
│ ├── status.py # Runtime snapshot builder
│ ├── exceptions.py # All error classes
│ ├── tracker/
│ │ ├── base.py # Abstract tracker adapter
│ │ ├── linear.py # Linear GraphQL client
│ │ └── memory.py # In-memory tracker for testing
│ └── server/
│ ├── app.py # FastAPI app
│ └── router.py # /api/v1/* endpoints
└── tests/ # 100+ tests
cd python
python -m pytest tests/ -vStart with --port to enable the HTTP server:
python -m symphony WORKFLOW.md --port 8080
GET /— HTML dashboard showing running/retrying sessions and aggregate metrics.GET /api/v1/state— JSON snapshot of current system state.GET /api/v1/<issue_identifier>— Per-issue debug details.POST /api/v1/refresh— Trigger an immediate poll cycle.
Apache License 2.0 — see LICENSE.