Nyílt forráskódú specifikáció a Codex-orchesztrációhoz: Symphony
Szerzők: Alex Kotliarskyi, Victor Zhu és Zach Brock
Hat hónappal ezelőtt, miközben egy belső produktivitási eszközön dolgoztunk, a csapatunk egy akkoriban vitatott döntést hozott: úgy építjük meg az adattárunkat, hogy abban nem lesz ember által írt kód. A projektadattárunk minden sorát a Codexnek kellett generálnia.
Hogy ez működjön, az alapoktól újraterveztük a mérnöki munkafolyamatunkat. Létrehoztunk egy ügynökbarát adattárat, komolyan befektettünk az automatizált tesztekbe és védőkorlátokba, és a Codexet teljes jogú csapattársként kezeltük. Ezt az utat korábbi blogbejegyzésünkben, a harness engineeringről dokumentáltuk.
És működött, de aztán beleütköztünk a következő szűk keresztmetszetbe: a kontextusváltásba.
Ennek az új problémának a megoldására építettünk egy Symphony nevű rendszert. A Symphony(új ablakban nyílik meg) egy ügynökorchesztrátor, amely egy projektmenedzsment-táblát, például a Lineart, a kódoló ügynökök vezérlősíkjává alakítja. Minden nyitott feladathoz jut egy ügynök, az ügynökök folyamatosan futnak, az emberek pedig átnézik az eredményeket.
Ez a cikk bemutatja, hogyan hoztuk létre a Symphonyt — aminek eredményeként egyes csapatoknál 500%-kal nőtt a beolvasztott lekéréses kérelmek száma —, és hogyan használhatod arra, hogy a saját issue trackeredből folyamatosan működő ügynökorchesztrátort csinálj.
Az interaktív kódoló ügynökök korlátja
Még ahogy egyre könnyebb is használni őket, a kódoló ügynökök — akár webes alkalmazásokon, akár CLI-n keresztül érjük el őket — továbbra is interaktív eszközök.
Ahogy az ügynökalapú munka léptéke nőtt az OpenAI-nál, egy újfajta teherrel szembesültünk. Minden mérnök megnyitott néhány Codex-menetet, kiosztotta a feladatokat, átnézte a kimenetet, irányította az ügynököt, majd ismételte. A gyakorlatban a legtöbben kényelmesen három-öt menetet tudtak egyszerre kezelni, mielőtt a kontextusváltás fájdalmassá vált volna. E fölött csökkent a produktivitás. Elfelejtettük, melyik menet min dolgozik, terminálok között ugráltunk, hogy visszatereljük az ügynököket a helyes útra, és hibát kerestünk az olyan hosszú futású feladatokban, amelyek félúton elakadtak.
Az ügynökök gyorsak voltak, de rendszerszintű szűk keresztmetszetünk volt: az emberi figyelem. Gyakorlatilag felépítettünk egy csapat rendkívül rátermett junior mérnököt, majd az emberi mérnökeinkre bíztuk a mikromenedzselésüket. Ez nem volt skálázható.
Nézőpontváltás
Rájöttünk, hogy rossz dolgot optimalizálunk. A rendszerünket kódolási menetek és beolvasztott PR-ek köré szerveztük, holott a PR-ek és a menetek valójában csak eszközök egy cél eléréséhez. A szoftveres munkafolyamatok nagyrészt leszállítandók köré szerveződnek: issue-k, feladatok, jegyek, mérföldkövek.
Ezért feltettük magunknak a kérdést, mi történne, ha nem közvetlenül felügyelnénk az ügynököket, hanem hagynánk, hogy a feladatkövetőnkből húzzák be a munkát.
Ebből az ötletből lett a Symphony, egy írott specifikáció, amely felügyelőként működik az ügynökalapú munka összehangolására.
Az issue trackerünk átalakítása ügynökorchesztrátorrá
A Symphony egy egyszerű elképzeléssel indult: minden nyitott feladatot fel kell vennie és be kell fejeznie egy ügynöknek. Ahelyett, hogy több lapon menedzseltük volna a Codex-meneteit, az issue trackerünket tettük meg vezérlősíknak.
Ebben a felállásban minden nyitott Linear-issue egy dedikált ügynök-munkaterülethez van rendelve. A Symphony folyamatosan figyeli a feladattáblát, és biztosítja, hogy minden aktív feladathoz tartozzon egy, a körben futó ügynök egészen addig, amíg a feladat el nem készül. Ha egy ügynök összeomlik vagy elakad, a Symphony újraindítja. Ha új munka jelenik meg, a Symphony felveszi, és elkezdi megszervezni a munkát.
A munkafolyamatunkat a jegyek állapotaira építettük, a Linear feladatkezelőt állapotgépként használva.
A gyakorlatban a Symphony leválasztja a munkát a menetekről és a lekéréses kérelmekről. Egyes issue-k több PR-t eredményeznek több adattárban; mások tisztán vizsgálati vagy elemzési munkák, amelyek soha nem érintik a kódbázist.
Ha a munkát így absztraháljuk, a jegyek sokkal nagyobb munkegységeket is képviselhetnek.
We regularly use Symphony to orchestrate complex features and infrastructure migrations. For example, we might file a task asking the agent to analyze the codebase, Slack, or Notion and produce an implementation plan. Once we’re happy with the plan, the agent generates a tree of tasks, breaking the work into stages and defining dependencies between tasks.
Agents only start working on tasks that aren’t blocked, so execution unfolds naturally and optimally in parallel for this DAG (a sequence of execution steps). For example, we marked the React upgrade as blocked on a migration to Vite. As expected, agents started upgrading React only after the migration to Vite was complete.
Agents can also create work themselves. During implementation or review, they often notice improvements that fall outside the scope of the current task: a performance issue, a refactoring opportunity, or a better architecture. When that happens, they simply file a new issue that we can evaluate and schedule later—many of these follow-up tasks also get picked up by agents. While we oversee this process, agents stay organized and keep work moving forward.
This way of working dramatically reduces the cognitive cost of kicking off ambiguous work. If the agent gets something wrong, that’s still useful information, and the cost to us is near zero. We can very cheaply file tickets for the agent to go prototype and explore, and throw away any explorations we don’t like.
Because the orchestrator runs on devboxes and never sleeps, we can add tasks from anywhere and know an agent will pick it up. For instance, one engineer on our team made three significant changes from the Linear app on his phone from a cozy cabin on shoddy wifi.
An increase in exploration from working this way
When observing the effects of working with Symphony, the most obvious change was output. Among some teams at OpenAI, we saw the number of landed PRs increase by 500% in the first three weeks. Outside of OpenAI, Linear founder Karri Saarinen highlighted a spike in workspaces created(új ablakban nyílik meg) as we released Symphony. However, the deeper shift is how teams think about work.
When our engineers no longer spend time supervising Codex sessions, the economics of code changes completely. The perceived cost of each change drops because we’re no longer investing human effort in driving the implementation itself.
That changed our behavior. It's become trivial to spin up speculative tasks in Symphony. Try an idea, explore a refactor, test a hypothesis, and only keep the results that look promising.
It also broadens who can initiate work. Our product manager and designer can now file feature requests directly into Symphony. They don’t need to check out the repo or manage a Codex session. They describe the feature and get back a review packet that includes a video walkthrough of the feature working inside the real product.
Symphony also shines in large monorepos (like the one we have at OpenAI) where the last mile of landing a PR is slow and fragile. The system watches CI, rebases when needed, resolves conflicts, retries flaky checks, and generally shepherds changes through the pipeline. By the time a ticket reaches Merging, we have high confidence the change will make it into the main branch without human babysitting.
A fejlődés új, másfajta problémákkal jár
Az ilyen szintű működés kompromisszumokkal jár. Amikor az ügynökök interaktív irányításáról áttértünk arra, hogy jegyszinten adjunk nekik munkát, elvesztettük annak lehetőségét, hogy menet közben folyamatosan finoman terelgessük őket, és szükség esetén korrigáljuk az irányt. Néha az ügynök valami olyat készített, ami teljesen félrement. Ez hasznos volt — ezek a kudarcok feltárták a rendszer hiányosságait, és segítettek robusztusabbá tenni.
Ahelyett, hogy kézzel javítottuk volna az eredményt, védőkorlátokat és készségeket adtunk hozzá, hogy az ügynökök legközelebb sikerrel járjanak. Idővel ez oda vezetett, hogy új képességeket adtunk a hámunkhoz, például végpontok közötti tesztek futtatását, az alkalmazás vezérlését Chrome DevTools segítségével és QA smoke tesztek kezelését. Jelentősen javítottuk a dokumentációnkat, és tisztáztuk, mit jelent a jó eredmény.
Nem minden feladat illik a Symphony-féle munkastílushoz. Egyes problémák továbbra is megkövetelik, hogy a mérnökök közvetlenül interaktív Codex-menetekkel dolgozzanak, különösen a kétértelmű problémák vagy az erős ítélőképességet és szakértelmet igénylő munka esetén. A gyakorlatban általában ezek a legérdekesebb és legélvezetesebb feladatok a mérnökeink számára.
A különbség az, hogy a Symphony képes kezelni a rutinszerű megvalósítási munka zömét. Ez lehetővé teszi, hogy a mérnökök egyszerre egyetlen nehéz problémára összpontosítsanak, ahelyett hogy folyamatosan kisebb feladatok között váltanának kontextust.
Arra is rájöttünk, hogy nem működik jól, ha az ügynököket merev csomópontokként kezeljük egy állapotgépben. A modellek egyre okosabbak, és nagyobb problémákat is képesek megoldani, mint amekkora dobozba megpróbáljuk bezárni őket. Például a korai verziókban az összes GitHub-integráció a külső hám része volt — vagyis a korai verziók azt várták el a Codextől, hogy csak kódmódosításokat végezzen, miközben a folyamat többi részét (módosítások beküldése, tesztek futtatása) kódban határoztuk meg. Az ügynökalapú munka korai verzióiban csak arra kértük a Codexet, hogy valósítsa meg a feladatot. Ez a megközelítés túl korlátozónak bizonyult. A Codex tökéletesen képes több PR létrehozására, valamint a felülvizsgálati visszajelzések elolvasására és kezelésére is. Ezért eszközöket adtunk neki — gh CLI-t, készségeket a CI-naplók olvasásához stb. —, és most már többre kérhetjük a Codexet, például régi PR-ek lezárására vagy jelentések készítésére a befejezett és az elhagyott munkáról. Az ilyen típusú feladatok messze kívül estek az eredeti funkciómegvalósítási dobozon.
Végül tehát abba az irányba mozdultunk, hogy az ügynököknek inkább célokat adjunk, ne szigorú átmeneteket, nagyjából úgy, ahogy egy jó vezető célt ad a csapatában dolgozó közvetlen beosztottnak. A modellek ereje az érvelési képességükből fakad, ezért adj nekik eszközöket és kontextust, aztán hagyd őket dolgozni.
Symphonyval Symphonyt építeni
Amikor megnyitod a Symphony adattárat, az első dolog, amit észreveszel, hogy a Symphony technikailag csak egy SPEC.md fájl — a probléma és a tervezett megoldás definíciója. Ahelyett, hogy összetett felügyeleti rendszert építettünk volna, definiáltuk a problémát és a tervezett megoldásokat, így magas szintű iránymutatást adtunk az ügynököknek.
A referenciaimplementáció Elixirben íródott — mert amikor a kód gyakorlatilag ingyen van, végre az erősségeik alapján választhatsz nyelvet, például az Elixir konkurenciakezelése miatt —, de az alapötlet egy egyszerű Markdown-dokumentumban is kifejezhető. Arra biztatunk, hogy irányítsd a kedvenc kódoló ügynöködet a specifikációra, és valósíttasd meg vele a saját verzióját.
A Symphony első verziója csupán egy tmux-ban futó Codex-menet volt, amely lekérdezte a Lineart, és új feladatokhoz alügynököket indított. Működött, de nem volt különösebben megbízható. A második verzió a fő projektadattárunkban kapott helyet, amelyet eleve ügynökökre tervezve építettünk. Már korábban megépítettük az ügynök-hámot, hogy az ügynökök megkapják a magas színvonalú munkához szükséges készségeket és kontextust ebben az adattárban, így a Symphony egyszerűen mindezt összekapcsolja.
Amint megvolt az alapfunkcionalitás, a Symphonyt használtuk a Symphony felépítésére.
Amikor belsőleg bemutattuk a rendszert, ahogy feladatokat kezel és csatolja a proof-of-work videóját, a reakciók rendkívül pozitívak voltak: nőtt a Symphony projektcsatornánk, és a szervezet különböző csapatai természetes módon elkezdték használni. A belső product-market fit előfeltétele a külső indulásnak az OpenAI-nál. Az OpenAI-nál látott használat alapján egyértelművé vált, hogy a Symphonyt a vállalati falakon túl is meg kell osztanunk.
Ezért különálló SPEC.md-vé emeltük ki az ötletet, és megkértük a Codexet, hogy valósítsa meg. A referenciaimplementációhoz az Elixirt választottuk, egy viszonylag rétegnyelvet, amely kiváló primitíveket kínál konkurens folyamatok összehangolására és felügyeletére. A Codex egyetlen nekifutásra megépítette az Elixir-implementációt, mi pedig onnan tovább iteráltunk a specifikáción és a megvalósításon is. A specifikáció csiszolásához még azt is kértük a Codextől, hogy több más nyelven is valósítsa meg — TypeScript, Go, Rust, Java, Python —, majd az eredmények alapján azonosítsa a kétértelműségeket és egyszerűsítse a rendszert. Minden nyelven sikerrel járt.
A Codex építése során sok járulékos komplexitást eltávolítottunk, például a konkrét adattáraktól vagy a Linear MCP-től való függéseket. A Symphony már nem függ a belső adattárainktól vagy munkafolyamatainktól. Az alapmegközelítés egyszerűvé vált:
Minden nyitott feladathoz legyen garantáltan egy ügynök a saját munkaterületén.
Amellett, hogy segít az aktív munkában, a fejlesztési munkafolyamat mára olyasmivé vált, amit az ügynökök ismernek és követnek. A fejlesztési munkafolyamat — dolgozni egy issue-n, kikérni egy adattárat, folyamatban lévőre állítani, hogy a PM tudja, hogy dolgoznak rajta, hozzáadni a PR-t, áthelyezni Review állapotba, videókat csatolni stb. — most már egy egyszerű WORKFLOW.md fájlban van rögzítve. Mindez egy olyan folyamat, amelyet korábban emberek követtek, de soha nem dokumentáltunk. Ahelyett, hogy erre a hallgatólagos lépéssorra támaszkodnánk, most dokumentáljuk, és a Symphony gondoskodik róla, hogy az ügynökök kövessék. Ez lehetővé teszi, hogy olyan ügynököket építsünk, amelyek mellettünk dolgoznak. Ha úgy döntünk, hogy az ügynököknek önreflexiót is csatolniuk kell a befejezett munkához, ezt hozzáadjuk a WORKFLOW.md-hez, és a Symphony elvezeti az ügynököket ehhez a lépéshez.
Lehetőségünk nyílt arra is, hogy a Codexet app server módban(új ablakban nyílik meg) használjuk, ami a Codex beépített, headless módja. Ez a mód lehetővé tette, hogy futtassuk a Codexet, és egy jól dokumentált JSON-RPC API-n keresztül programozottan kommunikáljunk vele olyan dolgokhoz, mint egy szál indítása vagy a fordulókra adott reakciók. Ez sokkal kényelmesebb és jobban skálázható megoldás, mint CLI-n vagy élő tmux-meneteken keresztül próbálni interakcióba lépni a Codexszel.
A Codex App Server tökéletesen illeszkedett a felhasználási esetünkhöz: kihasználjuk a Codex által biztosított hámot, miközben vannak állítópontjaink és csatlakozási lehetőségeink. Például azért, hogy a Linear hozzáférési tokenjét ne tegyük elérhetővé az alügynökök számára, dinamikus eszközhívásokat(új ablakban nyílik meg) használunk arra, hogy elérhetővé tegyük a nyers linear_graphql függvényt, amely tetszőleges kéréseket hajt végre a Linear ellen, anélkül hogy MCP-re támaszkodnánk vagy a hozzáférési tokent konténereknek tennénk ki.
Mi következik
A Symphony szándékosan minimális orkesztrációs réteg. Azért tesszük nyílt forráskódúvá, hogy bemutassuk a Codex App Server erejét, ha különböző munkafolyamat-eszközökkel, például a Linearrel párosítjuk. Ennek megfelelően nem tervezzük, hogy a Symphonyt önálló termékként karbantartjuk. Tekints rá referenciaimplementációként. Ahogy sok fejlesztő a harness engineeringről szóló bejegyzésre irányította a kódoló ügynökeit, hogy felépítse az adattárait, reméljük, te is a Symphony specifikációjára(új ablakban nyílik meg) és adattárára(új ablakban nyílik meg) irányítod majd a kedvenc kódoló ügynöködet, hogy a saját környezetedre szabott verziókat építsen.
Az erő a Codexből és annak app serveréből jön. A Symphony arra szolgált, hogy összekösse a Codexet a Linearrel, két olyan dologgal, amelyet már amúgy is használtunk, hogy megoldjuk a munkamenedzsment problémáját. Ahogy a kódoló ügynökök egyre jobbak lesznek az érvelésben és az utasítások követésében, azt gyanítjuk, hogy más cégeknél is a kódírásról az ügynökalapú munka menedzselésére fog áttevődni a szűk keresztmetszet. Az izgalmas az, hogy ezekkel a kódolóügynök-rendszerekkel való kísérletezés küszöbe most meglepően alacsony. Egyszerűen csak lehet dolgokat építeni a Codexszel.
Közösségi említések
Örömmel látjuk, hogy a mérnöki közösség a megjelenés óta eltelt hetekben használja a Symphonyt, amely április 23-ig már több mint 15 ezer GitHub-csillagot(új ablakban nyílik meg) gyűjtött.