← Back to the workbench

Agent systems

Symphony

A workspace for running coding agents, following their work, and carrying changes through review and delivery.

ElixirOrchestrationReliability

Symphony carries coding work from an issue through implementation, review, and a decision about delivery. It gives me a place to see what the agents are doing, stop them, and take a closer look.

I built it from OpenAI’s original specification. That release provided the spec. I wrote an independent implementation and have since changed both the system and its specification.

A workflow picks up an issue and assigns a lead agent. The lead can ask helpers to investigate or make changes. Helpers that write code get separate worktrees. Codex, Claude, and Pi connect through their own protocols, and workers can run locally or over SSH.

Before a merge, Symphony checks the required reviews, the risk rules, and CI for the commit in question. If the branch changes, it has to be checked again. The cockpit shows the queue, individual runs, retries, and usage, with controls to pause, inspect, or rerun work.

The control plane runs on one node. I’m working on recovery when providers fail and testing the delivery path from end to end, including optional deployment and rollback.

How it works / Explore the workflow

From an issue to a merge

An issue gets a workspace and a lead agent. When a pull request is ready, Symphony checks the required reviews and can read CI for that commit. The operator can inspect or pause the work. When merging is enabled, only the checked commit can be merged.

Follow the middle column from a tracker issue to merge authority. Orange boxes are checks and decisions the runtime owns. In enforce mode, unmerged work returns as rework for the next attempt. Services on the right sit outside the runtime; dated notes mark when two checks changed. Open full size ↗

Learnings

“Finished” is a surprisingly expensive word in an agent interface. It can mean that a process stopped, a message ended, or the requested work succeeded. The next system in the chain needs to know which one happened. In Symphony, a completed Codex turn could contain an authentication failure; a Pi end event could arrive before retry or compaction had settled.

The broader problem is translating between systems that divide work differently. Each provider has its own idea of a turn, an error, and a chance to continue. An adapter has to preserve those distinctions long enough for the caller to make a sound decision. Giving unlike events the same name only moves the confusion downstream.

Review and CI bring time into the problem. Approval applies to a particular change. A passing check applies to the code it ran against. When another commit arrives, those facts still exist, but their scope has not grown with the branch. Automation needs to carry that scope all the way to the merge decision, especially when several agents can change the work.

Explore the other projects →