Una especificación de código abierto para la orquestación de Codex: Symphony
Por Alex Kotliarskyi, Victor Zhu y Zach Brock
Six months ago, while working on an internal productivity tool, our team made a controversial (at the time) decision: we’d build our repo with no human-written code. Every line in our project repository had to be generated by Codex.
To make that work, we redesigned our engineering workflow from the ground up. We built an agent-friendly repository, invested heavily in automated tests and guardrails, and treated Codex as a full-fledged teammate. We documented that journey in our previous blog post on harness engineering.
And it worked, but then we ran into the next bottleneck: context switching.
To solve this new problem, we built a system called Symphony. Symphony(se abre en una ventana nueva) is an agent orchestrator that turns a project-management board like Linear into a control plane for coding agents. Every open task gets an agent, agents run continuously, and humans review the results.
This post explains how we created Symphony—resulting in a 500% increase in landed pull requests on some teams—and how to use it to turn your own issue tracker into an always-on agent orchestrator.
The ceiling of interactive coding agents
Even as they get easier to use, coding agents—whether accessed through web apps or CLI—are still interactive tools.
As the scale of agentic work increased at OpenAI, we found a new kind of burden. Each engineer would open a few Codex sessions, assign tasks, review the output, steer the agent, and repeat. In practice, most people could comfortably manage three to five sessions at a time before context switching became painful. Beyond that, productivity dropped. We'd forget which session was doing what, jump between terminals to nudge agents back on track, and debug long-running tasks that stalled halfway through.
The agents were fast, but we had a system bottleneck: human attention. We had effectively built a team of extremely capable junior engineers, then assigned our human engineers to micromanaging them. That wasn’t going to scale.
A shift in perspective
We realized we were optimizing the wrong thing. We were orienting our system around coding sessions and merged PRs, when PRs and sessions are really a means to an end. Software workflows are largely organized around deliverables: issues, tasks, tickets, milestones.
So we asked ourselves what would happen if we stopped supervising agents directly and instead let them pull work from our task tracker.
That idea became Symphony, a written spec that functions as a supervisor to orchestrate agentic work.
Turning our issue tracker into an agent orchestrator
Symphony started with a simple concept: any open task should get picked up and completed by an agent. Instead of managing Codex sessions in multiple tabs, we made our issue tracker the control plane.
En esta configuración, cada incidencia abierta en Linear se asigna a un área de trabajo específica para un agente. Symphony supervisa continuamente el tablero de tareas y se asegura de que cada tarea activa tenga un agente ejecutándose en el bucle hasta que esté terminada. Si un agente falla o se queda bloqueado, Symphony lo reinicia. Si aparece trabajo nuevo, Symphony lo detecta y empieza a organizarlo.
Creamos nuestro flujo de trabajo basándonos en los estados de los tickets, usando el gestor de tareas Linear como una máquina de estados.
En la práctica, Symphony desacopla el trabajo de las sesiones y de las pull requests. Algunas incidencias generan varias pull requests en distintos repositorios; otras son pura investigación o análisis y nunca tocan la base de código.
Una vez que el trabajo se abstrae de esta manera, los tickets pueden representar unidades de trabajo mucho mayores.
Usamos Symphony con frecuencia para orquestar funciones complejas y migraciones de infraestructura. Por ejemplo, podemos crear una tarea pidiendo al agente que analice la base de código, Slack o Notion y produzca un plan de implementación. Una vez que estamos satisfechos con el plan, el agente genera un árbol de tareas, dividiendo el trabajo en etapas y definiendo dependencias entre tareas.
Los agentes solo empiezan a trabajar en tareas que no están bloqueadas, por lo que la ejecución se desarrolla de forma natural y óptima en paralelo para este DAG (una secuencia de pasos de ejecución). En el ejemplo de abajo, marcamos la actualización de React como bloqueada por una migración a Vite. Como era de esperar, los agentes empezaron a actualizar React solo después de que la migración a Vite se completara.
Los agentes también pueden crear trabajo por sí mismos. Durante la implementación o la revisión, a menudo detectan mejoras que quedan fuera del alcance de la tarea actual: un problema de rendimiento, una oportunidad de refactorización o una mejor arquitectura. Cuando eso ocurre, simplemente crean una nueva incidencia que podemos evaluar y programar más adelante; muchas de estas tareas de seguimiento también las asumen agentes. Aunque supervisamos este proceso, los agentes organizan su trabajo y lo hacen avanzar.
Esta forma de trabajar reduce drásticamente el coste cognitivo de poner en marcha trabajo ambiguo. Si el agente se equivoca en algo, eso sigue siendo información útil y el coste para nosotros es casi nulo. Podemos crear tickets a muy bajo coste para que el agente haga prototipos y explore, y descartar cualquier exploración que no nos guste.
Como el orquestador se ejecuta en devboxes y nunca duerme, podemos añadir tareas desde cualquier lugar y saber que un agente las asumirá. Por ejemplo, un ingeniero de nuestro equipo hizo tres cambios importantes desde la app de Linear de su teléfono, sentadito en una cabaña acogedora con una conexión wifi pésima.
Mayor exploración por trabajar de esta manera
Al observar los efectos de trabajar con Symphony, el cambio más evidente fue la producción. En algunos equipos de OpenAI, vimos que el número de pull requests integradas aumentó 6 veces en las primeras tres semanas. Fuera de OpenAI, Karri Saarinen, fundador de Linear, destacó un aumento en las áreas de trabajo creadas(se abre en una ventana nueva) cuando lanzamos Symphony. Sin embargo, el cambio más profundo es la forma en que los equipos conciben el trabajo.
Cuando nuestros ingenieros ya no dedican tiempo a supervisar sesiones de Codex, la economía de los cambios de código cambia por completo. El coste percibido de cada cambio baja porque ya no estamos invirtiendo esfuerzo humano en impulsar la implementación en sí.
Eso cambió nuestra forma de trabajar. Ahora es muy fácil poner en marcha tareas experimentales en Symphony. Prueba una idea, explora una refactorización, comprueba una hipótesis y quédate solo con los resultados que parezcan prometedores.
Además, amplía el número de personas que pueden iniciar un trabajo. Nuestro responsable de producto y nuestro diseñador ahora pueden crear solicitudes de funciones directamente en Symphony. No necesitan consultar el repositorio ni gestionar una sesión de Codex. Describen la función y reciben un paquete de revisión que incluye un vídeo en el que se muestra la función dentro del producto real.
Symphony también destaca en monorepositorios grandes (como el que tenemos en OpenAI), donde la última etapa para integrar una pull request es lenta y delicada. El sistema supervisa la integración continua, hace rebase cuando es necesario, resuelve conflictos, vuelve a intentar las comprobaciones que fallan y, en general, guía los cambios a lo largo del flujo. Para cuando un ticket llega a Merging, confiamos plenamente en que el cambio se incorporará a la rama principal sin necesidad de supervisión humana constante.
El progreso trae consigo problemas nuevos y diferentes
Operar a este nivel tiene sus pros y sus contras. Cuando pasamos de dirigir a los agentes de forma interactiva a asignarles tareas a nivel de ticket, perdimos la capacidad de guiarlos constantemente sobre la marcha y corregir el rumbo cuando fuera necesario. A veces, el agente producía algo que se desviaba por completo del objetivo. Eso fue útil: esos fallos revelaron las deficiencias del sistema y nos ayudaron a hacerlo más robusto.
En lugar de arreglar el resultado a mano, añadimos medidas de seguridad y herramientas para que los agentes pudieran hacerlo bien la próxima vez. Con el tiempo, esto nos llevó a añadir nuevas funciones a nuestro arnés, como ejecutar pruebas integrales, controlar la aplicación a través de Chrome DevTools y gestionar las pruebas de control de calidad básicas. Mejoramos significativamente nuestra documentación y dejamos claro qué es lo que se espera.
No todas las tareas encajan en el estilo de trabajo de Symphony. Algunos problemas siguen requiriendo que los ingenieros trabajen directamente con sesiones interactivas de Codex, sobre todo los problemas ambiguos o las tareas que exigen un buen criterio y experiencia. En la práctica, estas suelen ser las tareas más interesantes y gratificantes en las que nuestros ingenieros invierten su tiempo.
La diferencia es que Symphony se encarga de la mayor parte del trabajo rutinario de implementación. Eso permite a los ingenieros centrarse en un solo problema complejo cada vez, en lugar de tener que cambiar constantemente de un contexto a otro para realizar tareas más pequeñas.
También aprendimos que tratar a los agentes como nodos rígidos en una máquina de estados no funciona bien. Los modelos se vuelven más inteligentes y pueden resolver problemas más complejos de lo que nos permite el marco en el que intentamos encajarlos. Por ejemplo, las primeras versiones tenían todas las integraciones de GitHub como parte del arnés externo; de hecho, las primeras versiones esperaban que Codex solo realizara cambios en el código, especificando el resto del proceso (enviar cambios, ejecutar pruebas) en el código. Nuestras primeras versiones del trabajo con agentes solo le pedían a Codex que implementara la tarea. Ese enfoque resultó demasiado limitante. Codex es perfectamente capaz de crear varias pull requests, así como de leer los comentarios de las revisiones y abordarlos. Así que le dimos herramientas (CLI de gh, habilidades para leer registros de integración continua, etc.) y ahora podemos pedirle a Codex que haga más cosas, como cerrar pull requests antiguas o generar informes sobre el trabajo completado frente al abandonado. Este tipo de tareas quedaban totalmente fuera del marco inicial de implementación de funciones.
Así que al final decidimos dar a los agentes objetivos en lugar de transiciones estrictas, igual que un buen gerente asignaría una meta a un subordinado directo de su equipo. El poder de los modelos reside en su capacidad de razonar, así que hay que darles herramientas y contexto, y dejar que hagan su trabajo.
Usar Symphony para crear Symphony
Cuando abres el repositorio de Symphony, lo primero que notarás es que Symphony técnicamente es solo un archivo SPEC.md: una definición del problema y de la solución prevista. En lugar de crear un sistema complejo de supervisión, definimos el problema y las soluciones previstas, dando a los agentes una guía de alto nivel.
La implementación de referencia está escrita en Elixir —porque cuando el código es prácticamente gratis, por fin puedes elegir lenguajes por sus puntos fuertes, como la concurrencia de Elixir—, pero la idea central puede expresarse en un sencillo documento Markdown. Te animamos a apuntar tu agente de programación favorito a la especificación y hacer que implemente su propia versión.
La primera versión de Symphony era simplemente una sesión de Codex ejecutándose en tmux, que consultaba a Linear y creaba subagentes para nuevas tareas. Funcionaba, pero no era especialmente fiable. La segunda versión vivía dentro de nuestro repositorio principal del proyecto, que se había diseñado pensando en los agentes. Ya habíamos creado el arneses de agentes para darles las capacidades y el contexto necesarios para hacer trabajo de alta calidad en este repositorio, así que Symphony simplemente lo conecta todo.
Una vez que existió la funcionalidad básica, usamos Symphony para crear Symphony.
Cuando internamente hicimos una demo del sistema gestionando tareas y adjuntando su vídeo de prueba de trabajo, la reacción fue abrumadoramente positiva: nuestro canal del proyecto Symphony creció y equipos de toda la organización empezaron a usarlo de forma orgánica. Que un producto encaje en el mercado interno es un requisito imprescindible para lanzarlo al mercado externo en OpenAI. Basándonos en el uso que vimos en OpenAI, quedó claro que debíamos compartir Symphony más allá de los muros de la empresa.
Así que extrajimos la idea a un SPEC.md independiente y le pedimos a Codex que lo implementara. Para la implementación de referencia, elegimos Elixir, un lenguaje relativamente especializado con excelentes primitivas para orquestar y supervisar procesos concurrentes. Codex creó la implementación en Elixir con un ejemplo, y desde ahí seguimos iterando tanto en la especificación como en la implementación. Para pulir la especificación, incluso le pedimos a Codex que la implementara en otros lenguajes —TypeScript, Go, Rust, Java, Python— y que usara los resultados para identificar ambigüedades y simplificar el sistema. Funcionó en todos los lenguajes.
Durante el proceso de crear Codex, eliminamos mucha complejidad accidental, como las dependencias de repositorios específicos o de Linear MCP. Symphony ya no depende de nuestros repositorios internos ni de nuestros flujos de trabajo. El enfoque principal se simplificó:
Para cada tarea abierta, garantiza que haya un agente ejecutándose en su propia área de trabajo.
Además de ayudar con el trabajo activo, el flujo de trabajo de desarrollo es ahora algo que los agentes conocen y siguen. El flujo de trabajo de desarrollo —trabajar en una incidencia, consultar un repositorio, marcarla como «en curso» para que el gestor de proyectos sepa que se está trabajando en ello, añadir la pull request, pasarla al estado «En revisión», adjuntar vídeos, etc.— ahora está recogido en un sencillo archivo WORKFLOW.md. Todo esto es un proceso que los humanos seguían, pero que nunca se había documentado. En lugar de basarnos en este conjunto implícito de pasos, ahora lo documentamos, y Symphony se asegura de que los agentes lo sigan. Esto nos permite crear agentes que trabajen en equipo con nosotros. Si decidimos que los agentes también deben adjuntar una autorreflexión al trabajo terminado, lo añadiremos al WORKFLOW.md, y Symphony guiará a los agentes hacia ese paso.
También pudimos usar Codex en modo de servidor de la aplicación(se abre en una ventana nueva), un modo sin interfaz integrado en Codex. Este modo nos permitió ejecutar Codex y comunicarnos con él de forma programática a través de una API JSON-RPC bien documentada para cosas como iniciar un hilo o reaccionar a los turnos. Es una forma mucho más cómoda y escalable que intentar interactuar con Codex a través de la CLI o de sesiones de tmux en directo.
El App Server de Codex encajaba perfectamente con nuestro caso de uso: aprovechamos el arnés que proporciona Codex y, al mismo tiempo, disponemos de controles y hooks a los que recurrir. Por ejemplo, para evitar exponer el token de acceso de Linear a los subagentes, usamos dynamic tool calls(se abre en una ventana nueva) para exponer la función linear_graphql sin procesar, que ejecuta solicitudes arbitrarias contra Linear, sin depender de MCP ni exponer el token de acceso a los contenedores.
Qué viene ahora
Symphony es una capa de orquestación intencionadamente mínima. La hemos convertido en código abierto para demostrar el poder del App Server de Codex cuando se combina con distintas herramientas del flujo de trabajo, como Linear. Por eso, no tenemos previsto continuar con Symphony como producto independiente. Piensa en ello como una implementación de referencia. Del mismo modo que muchos desarrolladores apuntaron sus agentes de programación a la publicación sobre ingeniería de arneses para estructurar sus repositorios, esperamos que apuntes tu agente de programación favorito a la especificación(se abre en una ventana nueva) y al repositorio(se abre en una ventana nueva) de Symphony para crear tus propias versiones adaptadas a tus entornos.
La potencia viene de Codex y de su servidor de la aplicación. Symphony fue una forma de conectar Codex con Linear, dos elementos que ya usábamos, para resolver el problema de la gestión del trabajo. A medida que los agentes de programación mejoren en su capacidad de razonamiento y de seguir instrucciones, es probable que el cuello de botella en otras empresas pase de la escritura de código a la gestión del trabajo de los agentes. Lo emocionante es que ahora la barrera para experimentar con estos sistemas de agentes de programación es sorprendentemente baja. Basta con crear cosas con Codex.
Menciones a la comunidad
Estamos encantados de ver que la comunidad de ingenieros está usando Symphony desde su lanzamiento, y que ya ha conseguido más de 15 000 estrellas en GitHub(se abre en una ventana nueva) hasta el 23 de abril.