Technical memorandum

File
TM-26-0922
From
Charlie O'Donoghue
Date
Reading
5 min
Subject
AI agents · Software architecture · Complex systems · Clojure

Termites solved agent orchestration in 1959

Two agents handing work to each other should not message each other. A 1959 paper about termites explains why, and a mud wasp shows what goes wrong.

First published on LinkedIn

A tall, rust-red termite mound built around the trunk of a tree, in long grass.
Photo by Random Institute on Unsplash

Boris Cherny’s line about not prompting Claude any more, writing the loops that do, was the coolest sentence I read this year. The follow-on is already here: wire the loops into graphs, with nodes, edges and state. Even cooler.

Yuval Noah Harari’s line in Homo Deus is that organisms are algorithms. A wasp, a baboon, a person: processes tuned by selection rather than written down anywhere. Take that as an engineering claim rather than a philosophical one and we can look at it in two ways. Biology has been running algorithms far longer than we have, so its answers to coordination, termination and error recovery are prior art.

I built something in July without knowing it had a name. Two agents, different repos, handing work to each other. The obvious design is to have them message each other, especially since Claude Code now ships exactly that in cross-session messaging. That approach is limited, and a 1959 paper about termites explains why.

Pierre-Paul Grassé had a paradox to solve. A termite nest looks planned. No termite directs the work. His answer was stigmergy: insects don’t message each other about the build, they modify a shared environment, and its configuration is the next instruction. An action changes the configuration, and the new configuration triggers the next action, often by a different individual (Grassé 1959; Theraulaz and Bonabeau have the modern treatment, 1999). I.e. one insect does something that leaves a trace in the environment, and another insect can come along and pick up where the other left off.

What I’d built was an append-only log both agents wrote to and neither owned. Each reads it at the start of a turn and works out what’s open for it. No messages, no queue, no delivery. That’s a termite arriving at the site.

Two ways to coordinate. On the right, the configuration of the record is the next instruction.

Two things follow that are not obvious from the graph advice.

State is a medium, not a message bus. Agents messaging each other couples them, and the coupling dies with the session. A durable shared record doesn’t. Anything that never landed in the record didn’t happen. Rich Hickey’s word for that coupling is complect. It means braiding two things together so you can’t reason about one without the other (Simple Made Easy, Strange Loop 2011).

While you’re there: CultRepo’s documentary on Clojure, the language those ideas came out of, is worth an hour of your evening (Clojure: The Documentary, 2026).

A loop needs a quantity that only moves one wayTwo loops on the same task, the measure plotted against iterations. One measure falls every turn, by less each time, and reaches the stop condition: it settles. The other rises and falls with no steady direction and never reaches it: it spins.e.g. findings open, tests failing, slices leftthe measureiterations →stop conditionit spinsit settlesfalls every turnno steady direction
A Lyapunov function, in one picture. The loop that spins is not failing. It may be doing good work. It just cannot tell you, or itself, when to stop.

Every loop needs a quantity that only moves one way, or it never stops cycling. A Lyapunov function, something with a definite sign of change, is what makes a system settle instead of wander (Prigogine 1978). His sharper point: near equilibrium, the same laws hold whatever the system is made of, so a generic check works. Far from equilibrium that stops being true. What counts as progress depends on the specific system, so a measure that works for one loop proves nothing about another. Routine work can share a verifier. Novel work needs its own, or a person. See the Turing post linked below for why a human is still involved.

Further to this, insects “editing” their physical world is like a kind of immutable surface. Immutability in software is how to do the same and is what makes that measure mentioned above checkable. For example, Datomic and XTDB never overwrite a fact, so change becomes an audit log that you can query rather than argue about. A record you can overwrite is not helpful at all.

Stigmergy works because there is a mechanism in-built for handling failure. Any worker can pick up any stage, because the structure says what to do next. Lose one and the work carries on.

A mud wasp builds its funnel in five stages, with no plan anywhere. Each stage leaves the exact condition that triggers the next: a stem of a certain height says curve me, a bell says widen the flange, a flange says build the sides down. The wasp does not hold the funnel in its head. The funnel holds it.

That is also the weakness. It reads the state in front of it and keeps no record of what it did, so a state resembling an earlier one gets the earlier response. Nothing counts the stages.

Smith proved it with a hole, the stimulus that means build a funnel here. He punched one into the neck of a funnel just after stage 3 of 5, and the wasp built a second complete funnel on top of the first (Smith 1978).

It never malfunctioned. It applied the right rule to what it saw. Nothing had recorded that the work was done.

Smith's experiment. The wasp applied the right rule to what it saw, and built a second funnel on top of the first.

That is your agent redoing finished work. We can do better than the wasp, though, because we choose what the state says. Every completed stage needs a marker that differs in kind from earlier triggers, never in amount. A counter off to one side will not save you, because nothing reads it. Put it in the record the agent reads and it stops being a counter and starts being a marker.

# A counter. Starting stage 3 and having finished stage 3
# leave the same record, so nothing can tell them apart.
{ "stage": 3 }
{ "stage": 3 }

# Markers. Different in kind, and the second names what it
# closes, so no reading of it can start the first.
{ "stage": "migrate", "state": "open" }
{ "stage": "migrate", "state": "closed", "closes": "…-014" }

For the record, none of this is my field. I build things, read too much, and write it down so I stop forgetting it. I built the log before I read the papers. The papers only told me why it worked. If you’re wiring agents together, read Grassé before you read another framework doc.

The setup itself is on GitHub as agent-mailbox.

Sources