Skip to content

Two agents

Andrea de Ruvo edited this page Aug 18, 2026 · 6 revisions

Two agents on one job

Handing work from one session to the next is a baton: one sentence, one pointer, one direction. This page is about the other shape — two agents working towards one goal over time, with roles.

It is one button: Two agents, in the desk's toolbar, on any desk with two terminals open in it.

There is no protocol, and that is the design

Two agents on the same machine already share a filesystem. What you can arbitrate with is a file both of them can read, so that is what this is. The button writes two files into the desk's folder — PLAN.argus.md, what they are trying to do, and BRIDGE.argus.md, what they say to each other — and sends each agent a prompt that points at them.

Nothing is installed inside the agent. Nothing is asked of it that it cannot already do — read a file, write a file, end on a sentence. That is why the same two patterns work with Claude Code, Codex, Gemini, Aider or a script that reads its own instructions, and why there is no integration to break when one of them changes.

The rules live in the prompts because there is nowhere else to put them: you cannot enforce anything on an agent you do not control, you can only give it an instruction simple enough that it cannot be misread.

The two patterns

Together, without stepping on each other

Both work towards one goal. The plan file carries:

## Goal      one paragraph, agreed
## Files     every file that will be touched, each with one owner
## Doing     what each of you is on right now
## Done      finished, with what changed
## Blocked   what you need from the other, and why

Two rules do the work. Ownership is by file, not by task — two agents can agree on who does what and still both edit the same module. And if you need something that is not yours, write it down and stop, which turns a collision into a line in a file instead of a lost afternoon.

One prompt goes to both, through the chain — chained on for the send and off immediately, because leaving it on is the one way this could quietly ruin an afternoon. The two agents differ only in which name the plan gives work to, so there is nothing to word differently.

They talk through the bridge as well, the same file the reviewing pattern uses, with the same markers and the same rules. Between peers the statuses mean what you would expect: DONE for a finished piece, ASK for something you need from the other one — and then you get on with something else rather than waiting — BLOCKED, and OK when you think the whole goal is met, which the other answers with its own OK or with what is still missing. Nobody owns the turn: they work at once, and the file is where they say what they have finished and what they need. Turns are signed with each agent's own tmux session name rather than WORKER and REVIEWER.

One builds, the other reviews

One writes and never marks its own work correct. The other reads the diff — the diff, not the description of it — and never edits the work.

They talk through a file. BRIDGE.argus.md, beside the plan, append-only. This is the question the pattern has to answer and it is worth being blunt about why: the two agents cannot see each other's terminals. A review printed into the reviewer's pane is a review nobody reads.

@TURN who=WORKER at=2026-08-18T09:14:02Z status=DONE
Added the cache and a test for the empty case. 48 tests pass.
@END at=2026-08-18T09:15:30Z

@TURN who=REVIEWER at=2026-08-18T09:21:40Z status=REDO round=2
src/pipeline.py:88 — the cache key ignores the scheme version, so a stale entry
survives an update. The test passes because it never updates the scheme.
@END at=2026-08-18T09:26:02Z

Timestamp, actor, status, text — all four inside the opening marker, named rather than positional, so a field left out is visible instead of shifting the others along. Extra fields are allowed and ignored: round=2, tests=16/0, whatever a pair finds worth carrying. The last turn says whose move it is, so there is no state anywhere else — not in Argus, not in either agent's head.

It began as a markdown heading, ## <timestamp> WORKER: DONE, and the first real run showed why that is not enough: the agent wrote ## WORKER: DONE, without the timestamp. A heading is prose a parser reads over its shoulder, so every part of it looks optional; a sentinel is a line you either wrote or did not. The shape is FASTQ's, and so is the reason for it.

status written by means
DONE worker a pass is finished — the reviewer's turn
REDO reviewer not right yet, and why — the worker's turn
OK reviewer it is right. Both stop.
ASK either a question for the other one, which answers before doing anything else
BLOCKED either stuck, or a person is needed. Both stop.
STOP argus out of rounds or out of time. Both stop.

ASK is worth its own line. Neither of them can see the other's screen, so a review that was misread becomes a REDO for something that is not broken, and an afternoon spent solving different problems. A question costs one round; a wrong guess costs the afternoon.

Three rules make it work, and all three are written into the top of the file itself, so an agent that reads it cold needs nothing else:

  • A turn is finished only when it says so. The @END line is the difference between "they have said their piece" and "they are halfway through typing it". Act only on a finished turn; otherwise wait and read again.
  • Append, never rewrite. One command per turn — heading, text and end line together — so nothing is lost when both write at once.
  • There is a deadline, in the first turn. Two agents who cannot agree will not start agreeing at three in the morning. Past it, whoever notices adds a BLOCKED turn and stops.

Both agents start at the same time and poll the file every sixty seconds. Nothing here needs a browser: close the tab and they carry on.

What Argus does, and what it does not

It writes the plan and the bridge, sends each agent its prompt, and then it is a reader — one more thing looking at the same file:

  • the pair note shows the last status, or worker is writing… while a turn is unfinished;
  • it rings when the reviewer says OK, and when either says BLOCKED;
  • it adds ARGUS: STOP when the rounds you allowed are used up, or the deadline passes;
  • clicking the note shows the last few turns, and offers to open the bridge, open the plan, or tell them to stop — which is itself a turn in the file, because that is the only instruction the two of them are listening for.

It does not pass the work along any more, and does not read what the review says. The turn-taking belongs to the agents; a program that started interpreting the content would be a third opinion nobody asked for.

An earlier version of this had Argus watching both terminals for VERDICT: and HANDOVER: lines and sending the next prompt itself. It worked, and it needed the tab open, guessed the state of the conversation from what was on screen, and left nothing behind to read. The file is better in all three ways.

Prior art

Worth knowing, because none of this is new and one of them may suit you better:

  • claude-codex-handoff — the same idea in JSONL, two directional streams, per-session cursors, atomic claims. More machinery, less readable by a person.
  • llm-handoff — markdown files for state, backlog and handoffs, with validators as the authority.
  • FIPA-ACL and Google's A2A — where the field set comes from: who, when, what, and what state that leaves the task in.

The bridge is the small readable end of that family: one file, both directions, markdown.

Both of them write at once — what stops that from being a mess

Nothing takes a lock, and nothing needs to. Every writer appends, and the kernel will not let two appends land on top of each other: whoever gets there first is first, the other follows, and the timestamps say which was which. Nobody's turn can overwrite anybody's.

What is not safe is writing a turn in pieces. The other one's turn can land in the middle of yours, and then the tail of yours belongs to nothing — the parser drops it rather than attributing it to the wrong agent, which is the least bad outcome and still a loss. Hence the rule the header states and the command it gives: one append per turn, both markers and the text together. If what you have to say is long, build it in a scratch file and cat it in between the markers in that one append.

The other race is creating the file. In the reviewing pattern the worker creates it and the reviewer waits; between peers either may find it missing, so they are told to create it with the shell's noclobber (set -C, then a plain >) and, if that fails because it now exists, to read what the other one wrote instead of overwriting it.

The prompts are yours

They arrive in your prompt library in two groups — Two agents · together and Two agents · one reviews — and they are ordinary templates. Open them, read exactly what your agents are being told, change the wording, keep your own version.

One prompt per pattern, plus a nudge: Start (send to both) for peers, and You build / You review for the reviewing pair. There is no "answer the review", no "your turn" and no "converge" — all three were ways of saying out loud something the file now says, back when a person had to notice whose move it was. The nudge is for the one case left: one of them has stopped reading the file and you want to point at it.

Four numbers reach the prompts as placeholders, so none of them is written into a sentence: {every} how often they read the bridge, {limit} how long the whole run may take, {tries} how many reads before giving up on something that is not coming, and {bridge} and {plan} themselves. The durations carry their unit — "every 60 seconds", "30 minutes" — because "every 60" is an instruction with a hole in it.

One thing to keep if you rewrite them: never put a runnable command at the start of a line. Argus types a prompt into a terminal, and if that terminal is a shell rather than an agent, the shell runs it. The stock prompts point at the command in the bridge's own header instead of repeating it, and they do so because a shell dutifully ran the example and invented two turns.

The set it ships with cannot be deleted, so the button always has something to send. Editing one clears its stock mark, and that is also how an unedited copy gets brought up to date when a wording improves: only untouched ones are refreshed, so your words are never overwritten.

If you rewrite the reviewing prompt, keep the verdict line — it is the one sentence the loop reads.

Before you use it in anger

  • The referee that matters is not the other model. An LLM judging an LLM is a weak judge. Ground the round in something that cannot be talked round: your test suite, the diff, a script that either exits zero or does not.
  • Watch the first few rounds. The loop is worth switching on once the wording has proved itself, not before — a wrong prompt repeated six times is a faster way to be wrong.
  • Read the bridge, not the terminals. The terminals show two agents thinking out loud; the bridge is what they actually committed to each other, and it is a tenth as long.
  • Two agents editing one repository is still two agents editing one repository. The plan is an agreement, not a lock.

Clone this wiki locally