Working with multiple coding agents
From one agent to three
If you are a software engineer today, you already know that using coding agents is table stakes now. I, too, have been a naysayer for long, considering coding agents unsuitable for all but the most mundane code refactoring tasks. As their capabilities improved, my list of use cases for them improved, and I almost fully converted when Opus 4 landed. At the time of writing, claude-code is not only my daily driver, but also I have lost all capability of writing code by hand. Syntaxes which I could have written verbatim from my memory, all compiled and correct in first write, no longer come naturally to me, and I am having agents generate even the simplest snippets for me.1
When you start using agents, your workflow evolves hard & fast. I started from cursor, which I let go for two reasons: token-based pricing is too expensive (I burned ~800$ of my employer's money one month), and it's not easy to inter-operate with other agents (subject of this blog post). Eventually I switched to claude-code, which was all the rage at the time, and guess what, merely a 100$ subscription is more than enough for me. Nowadays codex has caught up quite a bit, but the auto mode of claude code is one feature I can not live without (I am not a person who can ever do --dangerously-skip-permissions) so that left me stuck with claude-code. Running one claude code session at a time feels natural when you want to be in control. But I soon realised a serious flaw. I would thoroughly review the code agent wrote, and then leave a couple of comments, and then I found myself staring at screen for the agent to complete thinking and spit more code. Better models also tend to be slower, and I initially tried best-fitting (using Sonnet instead of Opus for low-effort tasks) to reduce the thinking time, but that is an uphill battle as what you conceive as low-effort can quickly turn out to be high-effort as the unknown unknowns start catching up. Then, I naturally progressed to running claude sessions in parallel, 2-3 is what I mentally max out at. Usually, while claude is crunching on some implementation, you can in parallel start thinking about the other project you wanted to do (ofc use claude for this as well), by the time I am done typing the prompt with some thoughts for this, the other agent is done implementing which is now ready for my review attention, and by the time I am done leaving a review for the agent to address, the other agent is done writing up a plan for me to review. And so back and forth I go, on a fully productive day.
The cracks
This workflow of running 2-3 independent agents served me quite well until I hit two realisations:
- I am sometimes working on related projects where some context transfer between agents can be useful
- Code review generates a lot of mental fatigue, and usually coding agents tend to write a bad first pass (that is, if you care about your code deeply enough), so I have to sometimes do 3+ rounds of review. Goal: cut rounds of review to <= 2.
There are various tiny optimisations you do to make coding agents write a good first pass2. Code review then reduces to making sure that the code produced adheres the guidelines, as well as correct (evaluate against spec/plan). Once you objectify it enough, it turns out you can also have another agent do the first-pass on review. Intuition here is that another agent replaces me as the reviewer, and my main agent resolves the reviewer agent's concerns before pinging me for review. However, ultimately the goal is to bring down the number of review cycles needed, and if this does not help in that, it is just wasted tokens. So the review also has to be optimal, which needs some tweaking and work, but that is not the subject here.
Now, both of my realisations (agents needing to share context, and agentic review) consolidate into a single primitive: agent-to-agent communication. There are a couple of existing solutions:
- Something literally called agent communication protocol but that went nowhere
- Claude code conveniently launched this feature called Teams which is pretty cool
- There are countless number of skills, plugins etc. where people just invoke
codex reviewfrom claude or vice versa
Honestly, claude code teams is probably all you need except that my colleagues & friends tell me that codex is quite good at rigor, and catching edge cases which makes it a good reviewer agent in general, and some day I may just switch to codex as my main agent. So if I am being slightly more ambitious: I probably need something which is agent-agnostic. As I got more ambitious, I also realised a few other good-to-haves:
- Human in the loop: even if two agents are communicating, I want to potentially view the conversation happening realtime, possibly steering one or more agents along the way or asking an agent why it replied what it replied, etc.
- Shared sessions: why not share a single codex reviewer agent session across multiple implementer agents if they are working on related items?
None of these were possible in the more raw codex review style workflows. The vision I have in my mind is that in my terminal I have two tabs open one running claude, another running codex, and I can just use ACP to enable agents to send messages to each other. I can see both the screen, and possibly interject as necessary. Claude code teams cuts really really close.
Making them talk
It turns out there is a really simple workaround. If you run agents in tmux, since they are just TUI, you can use tmux send-keys to send arbitrary key strokes programatically to any tmux pane. It is then theoretically possible to ask an agent to send a message to another agent open on a different pane just by simulating keystrokes to literally type a message, and then pressing Return key like a human would do. All that is left to solve now is discovery (how do agents discover each other) and agent ergonomics (don't want agents wasting thousands of tokens learning how to use tmux send-keys on the fly). So I decided to write a small CLI called ax (agent-exchange) that is a light-weight wrapper over tmux management CLI to solve for both fronts. I did explore some existing solutions, and some like cmux do come close, but all of them either do too much (looking at you h2), or too little. And since the solution is just so simple (literal wrapper over tmux), I just decided to roll my own thing (FYI I absolutely hate rolling out my own stuff because I hate maintenance). Because it's so simple, it's also a little troublesome:
- Sending keystrokes has the problem of keystrokes getting lost if the other pane is not in a capacity to receive keystrokes (example: stuck at some permission prompt)
- Because this is tmux-based, you have to use tmux, which is not so bad, but the worse part is that you can not use claude or codex's desktop apps. I don't use them, so it doesn't bother me
I open sourced ax today, after trying it out for a couple of months and being thoroughly satisfied with it. Here's what a typical claude-codex review pair looks like, end to end.
- Start the session.
ax initlaunches a tmux session and drops me in it. - Join as the implementer.
ax join --role implementer --label claude-1marks the pane as hosting me, thenclaude --enable-auto-modestarts the agent. Theax joinbit is what enables discovery. All the other tmux panes can discover other joined panes viaax who. - Bring in codex. Two options. Either I ask claude in plain English ("spawn a codex reviewer agent to the right half of my screen") and let it run
ax spawn, or I just hit<C-b>"myself and run codex in the new pane. The hand-spawning route gives me a bit more control over the layout. - The
/axskill kicks in on both sides. Both agents have the/axskill installed (viaax skill), so they already know how to send messages, recognize[ax sms from ...]lines as inbound requests, and respond. I never have to teach them the protocol mid-session. - My
/agent-peer-reviewskill shapes claude's review requests. This is a custom skill I wrote that sits on top of/ax. It tells claude to formulate reviews as PR descriptions in the ax comms directory, include the right file references, and ask codex to use its own/reviewskill (also custom).
A typical request that codex receives looks like:
[ax sms from claude-1 (implementer)]: can you /review my code at $AX_SESSION_DIR/comms/claude-1/review-request.md feel free to ask any questions by sending me an ax sms and let me know when done
When codex sees that, its /ax skill teaches it what $AX_SESSION_DIR means and how to reply; /review shapes how it reviews. Sometimes I bypass claude and tell codex directly to "ignore X in your review"; other times I have claude pass the instruction along. Either works, and that's the nice part. I'm not yet confident enough to let claude automatically act on codex's feedback — feels like a spiral risk — so I usually have claude refactor based on the merged review (mine + codex's) and then ask codex for another pass, which inherits the prior conversation as context. I'll also use the pair for brainstorming when claude runs out of ideas.
Although the ax CLI is much more ambitious, and is designed for multi-agent workflows, so far I have not found the need to do communication between more than two agents. I also think if ACP eventually evolves into a more mature protocol, it would be much nicer as this evolve out of tmux-bound to a more generic client-agnostic variant. But until either of that happens, this remains my go-to tool for cross-agent coordination.
There are serious downsides to this which I will reserve for another day.↩
such as I have a
/code-writing-guidelinesskill that encodes some of my programming philosophy as well as common mistakes that I see agents make, I am now thinking of expanding it into language-specific skills as well such as/golang-code-writing-guidelines. I also have a/plannerskill which is a modified version of plan mode, and for anything serious I usually follow the spec-plan-implementation lifecycle sincerely (more on that in a separate post).↩