Symphony (OpenAI)
Overview
Symphony is an OpenAI daemon that turns issue trackers into autonomous coding runs. It polls Linear for tickets, provisions isolated workspaces, dispatches coding agents, and manages the full lifecycle — retries, concurrency limits, CI, PR submission, and human-review handoffs. Workflow policy lives in WORKFLOW.md alongside your code.
Ravi slots into Symphony as the credential and identity layer. Instead of hardcoding API tokens in WORKFLOW.md front matter or injecting them via environment variables at CI time, Symphony agents pull secrets from Ravi at dispatch — with full audit trails of which agent touched which credential during which run.
Why Ravi
Symphony’s Config Layer reads env declarations from WORKFLOW.md front matter. That’s clean architecture, but it pushes a question upstream: where do those secrets actually come from? Env vars in a CI pipeline mean rotation is manual, leakage is invisible, and you can’t tell which of 50 parallel runs consumed which credential.
Ravi replaces that gap with:
- Vault-backed secret resolution —
LINEAR_API_KEY,GITHUB_TOKEN, and any other declared var is fetched from Ravi at dispatch time, not baked into config files - Per-run audit trail — every fetch is logged to the identity that pulled it; proof of work at the credential layer, not just the code layer
- Real email identities — agents that send PR notifications or email stakeholders get a live Ravi mailbox per identity, not a throwaway alias
- Autonomous OTP handling — if a run hits an email or SMS verification gate mid-task, Ravi closes the loop without human intervention
Setup
1. Store secrets in Ravi
Add your Symphony-required credentials to the Ravi vault before runs begin:
# Store via Ravi CLI or the agent tool
ravi secrets set LINEAR_API_KEY=lin_api_...
ravi secrets set GITHUB_TOKEN=ghp_...
Or via the Ravi plugin tool in your agent:
ravi_secrets_set key=LINEAR_API_KEY value=lin_api_...
2. Declare env vars in WORKFLOW.md
In your repo’s WORKFLOW.md front matter, list the required keys:
---
env:
- LINEAR_API_KEY
- GITHUB_TOKEN
- SERVICE_API_KEY
---
3. Inject at dispatch
Write a Symphony pre-dispatch hook (or wrap the dispatcher) to fetch each declared key from Ravi and inject it into the workspace env:
from ravi import RaviClient
client = RaviClient()
def resolve_env(declared_keys: list[str]) -> dict:
env = {}
for key in declared_keys:
secret = client.secrets.get(key)
if secret:
env[key] = secret.value
return env
Pass the resolved dict to Symphony’s workspace environment before launching the agent process.
4. Provision per-run identities (optional)
For runs that need a real sender address — PR comment emails, stakeholder notifications, service signups — provision a Ravi identity per agent or per issue:
identity = client.identities.create(name=f"symphony-agent-{issue_id}")
# identity.email → symphony-agent-ISSUE-123@yourdomain.ravi.app
Inject AGENT_EMAIL and AGENT_PHONE into the workspace env. The agent can send, receive, and verify using those channels natively.
Multi-Team Isolation
Symphony’s workspace isolation maps cleanly to Ravi’s identity model. Each team or project can have its own Ravi identity with its own scoped vault. A run in the payments workspace uses the payments identity’s secrets; a run in infra uses infra’s. No credential bleed across projects, even with high concurrency.
Audit Trail
Every ravi_secrets_get call is logged against the identity that made it. After a Symphony run completes, you can pull the fetch log for that identity and see exactly which credential was accessed at which timestamp. This is the “proof of work at the identity layer” that WORKFLOW.md handoffs produce at the code layer.
Resources
- Symphony on GitHub
- Symphony SPEC.md — language-agnostic porting spec
- Ravi Secrets API
- Ravi Identities