Uma especificação open source para orquestração do Codex: Symphony
Por Alex Kotliarskyi, Victor Zhu e Zach Brock
Há seis meses, enquanto trabalhava em uma ferramenta interna de produtividade, nossa equipe tomou uma decisão controversa (na época): construiríamos nosso repositório sem nenhum código escrito por humanos. Cada linha no nosso repositório de projeto precisava ser gerada pelo Codex.
Para fazer isso funcionar, redesenhamos nosso fluxo de engenharia do zero. Construímos um repositório amigável para agentes, investimos pesado em testes automatizados e guardrails e tratamos o Codex como um colega de equipe completo. Documentamos essa jornada em nosso post anterior no blog sobre harness engineering.
E funcionou, mas então esbarramos no próximo gargalo: troca de contexto.
Para resolver esse novo problema, criamos um sistema chamado Symphony. O Symphony(abre em uma nova janela) é um orquestrador de agentes que transforma um quadro de gerenciamento de projetos como o Linear em um plano de controle para agentes de programação. Cada tarefa aberta recebe um agente, os agentes rodam continuamente, e humanos revisam os resultados.
Este post explica como criamos o Symphony — resultando em um aumento de 500% em pull requests concluídos em algumas equipes — e como usá-lo para transformar seu próprio rastreador de issues em um orquestrador de agentes sempre ativo.
O teto dos agentes de programação interativos
Mesmo ficando mais fáceis de usar, os agentes de programação — sejam acessados por aplicativos web ou CLI — ainda são ferramentas interativas.
À medida que a escala do trabalho agentivo aumentava na OpenAI, encontramos um novo tipo de sobrecarga. Cada engenheiro abria algumas sessões do Codex, atribuía tarefas, revisava a saída, orientava o agente e repetia. Na prática, a maioria das pessoas conseguia gerenciar confortavelmente de três a cinco sessões ao mesmo tempo antes que a troca de contexto se tornasse dolorosa. Além disso, a produtividade caía. Esquecíamos o que cada sessão estava fazendo, pulávamos entre terminais para recolocar agentes nos trilhos e depurávamos tarefas de longa duração que travavam no meio do caminho.
Os agentes eram rápidos, mas tínhamos um gargalo no sistema: a atenção humana. Na prática, havíamos montado uma equipe de engenheiros juniores extremamente capazes e depois designado nossos engenheiros humanos para microgerenciá-los. Isso não ia escalar.
Uma mudança de perspectiva
Percebemos que estávamos otimizando a coisa errada. Estávamos orientando nosso sistema em torno de sessões de programação e PRs mescladas, quando PRs e sessões na verdade são um meio para um fim. Os fluxos de trabalho de software são amplamente organizados em torno de entregáveis: issues, tarefas, tickets, marcos.
Então nos perguntamos o que aconteceria se parássemos de supervisionar os agentes diretamente e, em vez disso, deixássemos que eles puxassem trabalho do nosso rastreador de tarefas.
Essa ideia se tornou o Symphony, uma especificação escrita que funciona como um supervisor para orquestrar trabalho agentivo.
Transformando nosso rastreador de issues em um orquestrador de agentes
O Symphony começou com um conceito simples: qualquer tarefa aberta deve ser assumida e concluída por um agente. Em vez de gerenciar sessões do Codex em várias abas, transformamos nosso rastreador de issues no plano de controle.
Nessa configuração, cada issue aberta no Linear corresponde a um workspace dedicado de agente. O Symphony monitora continuamente o quadro de tarefas e garante que toda tarefa ativa tenha um agente rodando no loop até ser concluída. Se um agente falhar ou travar, o Symphony o reinicia. Se surgir trabalho novo, o Symphony o assume e começa a organizar o trabalho.
Construímos nosso fluxo de trabalho com base nos status dos tickets, usando o gerenciador de tarefas Linear como uma máquina de estados.
Na prática, o Symphony desacopla o trabalho das sessões e das pull requests. Algumas issues produzem várias PRs em diferentes repositórios; outras são pura investigação ou análise e nunca tocam a base de código.
Quando o trabalho é abstraído dessa forma, os tickets podem representar unidades de trabalho muito maiores.
Usamos regularmente o Symphony para orquestrar recursos complexos e migrações de infraestrutura. Por exemplo, podemos abrir uma tarefa pedindo ao agente que analise a base de código, o Slack ou o Notion e produza um plano de implementação. Quando estamos satisfeitos com o plano, o agente gera uma árvore de tarefas, dividindo o trabalho em etapas e definindo dependências entre elas.
Os agentes só começam a trabalhar em tarefas que não estão bloqueadas, então a execução se desenrola naturalmente e de forma ideal em paralelo para esse DAG (uma sequência de etapas de execução). No exemplo abaixo, marcamos a atualização do React como bloqueada por uma migração para Vite. Como esperado, os agentes começaram a atualizar o React somente depois que a migração para Vite foi concluída.
Os agentes também podem criar trabalho por conta própria. Durante a implementação ou revisão, eles frequentemente percebem melhorias que ficam fora do escopo da tarefa atual: um problema de desempenho, uma oportunidade de refatoração ou uma arquitetura melhor. Quando isso acontece, eles simplesmente registram uma nova issue que podemos avaliar e agendar depois — muitas dessas tarefas de acompanhamento também são assumidas por agentes. Embora supervisionemos esse processo, os agentes se mantêm organizados e fazem o trabalho avançar.
Essa forma de trabalhar reduz drasticamente o custo cognitivo de iniciar um trabalho ambíguo. Se o agente errar alguma coisa, isso ainda é uma informação útil, e o custo para nós é quase zero. Podemos abrir tickets muito barato para o agente prototipar e explorar, e descartar quaisquer explorações de que não gostarmos.
Como o orquestrador roda em devboxes e nunca dorme, podemos adicionar tarefas de qualquer lugar e saber que um agente vai assumi-las. Por exemplo, um engenheiro da nossa equipe fez três mudanças significativas pelo app do Linear no celular, de uma cabana aconchegante com um wifi ruim.
Um aumento na exploração ao trabalhar dessa forma
Ao observar os efeitos de trabalhar com o Symphony, a mudança mais óbvia foi a produção. Em algumas equipes da OpenAI, vimos o número de PRs concluídas aumentar 6x nas primeiras três semanas. Fora da OpenAI, o fundador da Linear, Karri Saarinen, destacou um pico na criação de workspaces(abre em uma nova janela) quando lançamos o Symphony. No entanto, a mudança mais profunda está em como as equipes pensam sobre o trabalho.
Quando nossos engenheiros deixam de gastar tempo supervisionando sessões do Codex, a economia das mudanças de código muda completamente. O custo percebido de cada mudança cai porque não estamos mais investindo esforço humano para conduzir a implementação em si.
Isso mudou nosso comportamento. Tornou-se trivial iniciar tarefas especulativas no Symphony. Tente uma ideia, explore uma refatoração, teste uma hipótese e mantenha apenas os resultados que parecerem promissores.
Isso também amplia quem pode iniciar trabalho. Nosso gerente de produto e nosso designer agora podem abrir solicitações de recursos diretamente no Symphony. Eles não precisam fazer checkout do repositório nem gerenciar uma sessão do Codex. Eles descrevem o recurso e recebem de volta um pacote de revisão que inclui um vídeo demonstrando o recurso funcionando dentro do produto real.
O Symphony também se destaca em monorepos grandes (como o que temos na OpenAI), nos quais a etapa final para concluir uma PR é lenta e frágil. O sistema observa o CI, faz rebase quando necessário, resolve conflitos, tenta novamente verificações instáveis e, de modo geral, conduz as mudanças pelo pipeline. Quando um ticket chega a Merging, temos alta confiança de que a mudança entrará no branch principal sem babá humana.
O progresso vem com problemas novos e diferentes
Operar nesse nível envolve trade-offs. Quando passamos de orientar agentes de forma interativa para lhes atribuir trabalho no nível do ticket, perdemos a capacidade de ajustá-los constantemente no meio do caminho e corrigir a rota quando necessário. Às vezes, o agente produzia algo que errava completamente o alvo. Isso foi útil — essas falhas revelaram lacunas no sistema e nos ajudaram a torná-lo mais robusto.
Em vez de corrigir o resultado manualmente, adicionamos guardrails e skills para que os agentes pudessem ter sucesso na próxima vez. Com o tempo, isso nos levou a adicionar novos recursos ao nosso harness, como executar testes de ponta a ponta, operar o app via Chrome DevTools e gerenciar testes rápidos de QA. Melhoramos significativamente nossa documentação e deixamos mais claro o que é considerado bom.
Nem toda tarefa se encaixa no estilo de trabalho do Symphony. Alguns problemas ainda exigem engenheiros trabalhando diretamente com sessões interativas do Codex, especialmente problemas ambíguos ou trabalhos que exigem forte julgamento e expertise. Na prática, essas costumam ser as tarefas mais interessantes e agradáveis para nossos engenheiros dedicarem tempo.
A diferença é que o Symphony consegue lidar com o grosso do trabalho rotineiro de implementação. Isso permite que os engenheiros foquem em um único problema difícil por vez, em vez de alternar constantemente o contexto entre tarefas menores.
Também aprendemos que tratar agentes como nodes rígidos em uma máquina de estados não funciona bem. Os modelos ficam mais inteligentes e conseguem resolver problemas maiores do que a caixa em que tentamos colocá-los. Por exemplo, as primeiras versões tinham todas as integrações com o GitHub como parte do harness externo — por exemplo, as versões iniciais esperavam que o Codex apenas fizesse alterações de código, especificando o restante do processo (enviar mudanças, executar testes) no código. Nossas primeiras versões de trabalho agentivo apenas pediam ao Codex para implementar a tarefa. Essa abordagem se mostrou limitada demais. O Codex é perfeitamente capaz de criar várias PRs, além de ler feedback de revisão e resolvê-lo. Então demos a ele ferramentas — CLI gh, skills para ler logs de CI etc. — e agora podemos pedir ao Codex para fazer mais, como fechar PRs antigas ou gerar relatórios sobre trabalho concluído versus abandonado. Esses tipos de tarefa ficavam muito fora da caixa inicial de implementação de recurso.
Então, com o tempo, passamos a dar aos agentes objetivos em vez de transições estritas, muito parecido com a forma como um bom gerente atribuiria uma meta a um liderado de sua equipe. O poder dos modelos vem da sua capacidade de raciocínio, então dê a eles ferramentas e contexto e deixe que façam seu trabalho.
Usando o Symphony para construir o Symphony
Quando você abre o repositório do Symphony, a primeira coisa que percebe é que o Symphony é tecnicamente apenas um arquivo SPEC.md — uma definição do problema e da solução pretendida. Em vez de construir um sistema complexo de supervisão, definimos o problema e as soluções pretendidas, dando aos agentes orientação de alto nível.
A implementação de referência foi escrita em Elixir — porque, quando código é efetivamente gratuito, você finalmente pode escolher linguagens por seus pontos fortes, como a concorrência do Elixir —, mas a ideia central pode ser expressa em um simples documento Markdown. Incentivamos você a apontar seu agente de programação favorito para a especificação e fazer com que ele implemente sua própria versão.
A primeira versão do Symphony era apenas uma sessão do Codex rodando em tmux, consultando o Linear e criando subagentes para novas tarefas. Funcionava, mas não era particularmente confiável. A segunda versão passou a viver dentro do nosso principal repositório de projeto, que foi construído pensando em agentes. Já tínhamos criado o harness de agentes para dar aos agentes as habilidades e o contexto necessários para fazer um trabalho de alta qualidade neste repositório, então o Symphony simplesmente conecta tudo isso.
Depois que a funcionalidade básica passou a existir, usamos o Symphony para construir o Symphony.
Quando demonstramos internamente o sistema gerenciando tarefas e anexando seu vídeo de comprovação de trabalho, a reação foi extremamente positiva: nosso canal do projeto Symphony cresceu, e equipes de toda a organização começaram a usá-lo organicamente. Product-market fit interno é um pré-requisito para lançar externamente na OpenAI. Com base no uso que vimos na OpenAI, ficou claro que deveríamos compartilhar o Symphony além dos muros da empresa.
Então extraímos a ideia para um SPEC.md independente e pedimos ao Codex que a implementasse. Para a implementação de referência, escolhemos Elixir, uma linguagem relativamente de nicho com excelentes primitivas para orquestrar e supervisionar processos concorrentes. O Codex construiu a implementação em Elixir de primeira, e continuamos iterando tanto na especificação quanto na implementação a partir daí. Para lapidar a especificação, até pedimos ao Codex que a implementasse em várias outras linguagens — TypeScript, Go, Rust, Java, Python — e usasse os resultados para identificar ambiguidades e simplificar o sistema. Ele teve sucesso em todas as linguagens.
Ao longo do processo de construir o Codex, removemos muita complexidade incidental, como dependências de repositórios específicos ou do Linear MCP. O Symphony não depende mais dos nossos repositórios ou fluxos de trabalho internos. A abordagem central ficou simples:
Para cada tarefa aberta, garanta que um agente esteja rodando em seu próprio workspace.
Além de ajudar no trabalho ativo, o fluxo de desenvolvimento agora é algo que os agentes conhecem e seguem. O fluxo de desenvolvimento — trabalhar em uma issue, fazer checkout de um repositório, colocá-la em andamento para que o PM saiba que está sendo trabalhada, adicionar a PR, movê-la para o status Review, anexar vídeos etc. — agora está capturado em um simples arquivo WORKFLOW.md. Tudo isso era um processo que os humanos seguiam, mas nunca havia sido documentado. Em vez de depender desse conjunto implícito de etapas, agora o documentamos, e o Symphony garante que os agentes o sigam. Isso nos permite criar agentes que trabalham ao nosso lado. Se decidirmos que os agentes também devem anexar uma autorreflexão ao trabalho finalizado, adicionaremos isso ao WORKFLOW.md, e o Symphony guiará os agentes até essa etapa.
Também pudemos usar o Codex no modo app server(abre em uma nova janela), um modo headless nativo do Codex. Esse modo nos permitiu executar o Codex e nos comunicar com ele programaticamente por meio de uma API JSON-RPC bem documentada para coisas como iniciar uma thread ou reagir a turnos. É uma forma muito mais conveniente e escalável do que tentar interagir com o Codex via CLI ou sessões ao vivo de tmux.
O Codex App Server foi uma combinação perfeita para o nosso caso de uso: aproveitamos o harness que o Codex fornece, ao mesmo tempo que temos knobs e hooks para integrar. Por exemplo, para evitar expor o token de acesso do Linear a subagentes, usamos dynamic tool calls(abre em uma nova janela) para expor a função bruta linear_graphql, que executa requisições arbitrárias contra o Linear, sem depender de MCP nem expor o token de acesso aos contêineres.
O que vem a seguir
O Symphony é uma camada de orquestração intencionalmente minimalista. Estamos abrindo seu código para demonstrar o poder do Codex App Server quando combinado com diferentes ferramentas de fluxo de trabalho, como o Linear. Sendo assim, não planejamos manter o Symphony como um produto independente. Pense nele como uma implementação de referência. Assim como muitos desenvolvedores apontaram seus agentes de programação para o post sobre harness engineering para estruturar seus repositórios, esperamos que você aponte seu agente de programação favorito para a especificação(abre em uma nova janela) e o repositório(abre em uma nova janela) do Symphony para criar suas próprias versões adaptadas aos seus ambientes.
O poder vem do Codex e do seu app server. O Symphony foi uma forma de conectar o Codex ao Linear, duas coisas que já usávamos, para resolver o problema de gerenciamento de trabalho. À medida que os agentes de programação ficam melhores em raciocínio e em seguir instruções, suspeitamos que o gargalo em outras empresas também vai deixar de ser escrever código e passar a ser gerenciar trabalho agentivo. A parte empolgante é que a barreira para experimentar esses sistemas de agentes de programação agora está surpreendentemente baixa. Você pode simplesmente construir coisas com Codex.
Destaques da comunidade
Estamos muito felizes em ver a comunidade de engenharia usando o Symphony nas semanas desde o lançamento, acumulando mais de 15 mil estrelas no GitHub(abre em uma nova janela) em 23 de abril.