In May I wrote a spec called Main Chat. The factory I run had been taking specs and returning pull requests for four months, and I wanted a place to sit above it: one conversation that knew every project, could open a spec, could start a round, and remembered what we said yesterday. The spec was merged on 3 May. The first version was running on 4 May: durable sessions in the orchestrator database, a chat handler on the runner, every turn of the conversation executed as a factory task.
It worked. I used it. In June the factory learned to spawn coding sessions of its own and keep a row for each. In July every spawned session got its Remote Control deep link stored next to it, so I could open any of them from my phone. In August the toolkit grew a write tier: a session could draft a spec as a pull request and launch a round, with a per-host token, an hourly quota, and a pause switch on the server side.
Then, on 2 September, I sent a message from a Claude Code session on volo-server to a session on a rented server in another country. It came back with the server’s hostname. The message went over the same channel my phone uses. No code of mine was involved.
What changed
The thing I had built in May was a control room inside one application. The thing that exists now is a control room made of the environment itself. The difference is small in a diagram and large in practice.
Every session runs inside tmux on whichever machine it belongs to, and it does not die when I close the laptop. The machines differ on purpose: volo-server has a GPU and enough memory to run local models, so personal work stays on hardware I own, and it is reachable only over a private VPN; the rented cloud servers run the factory’s rounds and coding sessions. The portfolio session is nine days old and remembers thirteen hard-won lessons about its own AWS account. The astrology project session is nineteen days old. Fourteen such sessions are alive on volo-server this morning; the youngest is twelve hours old. Each has a name, and any of them can be addressed by that name from any other session on my account.
Above them sits one more session. I call it the command post. It is the one I talk to. It does not write code. It dispatches work to the others by message, opens specs into the factory, reads what comes back, checks it against the disk and the git history rather than against the report, and tells me what it found. When something needs a decision, the decision is mine and it is made in that one window.
The factory kept the part it does best. It only takes work in one form, a spec merged as its own pull request, and it only returns work in one form, a pull request with a review already on it. The command post cannot push code into it and neither can any other session. They can write, and they can ask.
The May version was not wrong
I want to be precise here, because the easy story is “I built the wrong thing”. I did not. In May there was no other way to have a persistent conversation that could drive the factory, so I wrote one, and it carried four months of real work. What happened is that the platform under it moved faster than I could have, and moved in the right direction. Claude Code sessions learned to message each other by name; I only tested it across machines on 2 September. Remote Control had already made every session reachable from a phone. The write rail I had built for my own chat turned out to be exactly what any session needed, so it was already in place when the sessions could talk.
The right response to a better solution arriving on time is to take it. The chat handler can retire. The session rows, the deep links, and the toolkit stay, because they were never about the chat; they were about the factory being reachable on rails.
And that layer is where the next work goes, not into the archive. Three steps, in order. First, the toolkit gets a session rail: list, spawn, stop, wrapping the routes the orchestrator has had since June, so a session can open another session on any runner, bound to a project, and get its Remote Control link back. Second, the factory adopts Microsoft’s Agent Host Protocol as the session substrate instead of tmux and transcript scraping. That spec has been in the repo since 29 July; the reconnaissance said go, and the re-check on 25 August found the host demanding interactive authentication even on a box with working logins, so phase one starts with headless auth rather than with handler code. Third, my voice client stops reading the local tmux and reads the factory’s session list instead, so the phone sees every host.
Where it fails
A control room made of talking sessions has a specific failure mode, and I hit it twice in one week.
On 30 August the command post told me where my résumé was. The path it gave did not exist. It had derived the filename from a naming convention I use for everything else in that folder, and the résumé was the one file that did not follow it. A second session, asked to attach the file, looked at the disk and said so. Rule since then: a path is a fact from the disk, never an inference from a pattern.
On 1 September the command post wrote a spec for the portfolio project from that project’s status document. The document had a list of open items inside a dated entry, and the list had been true on the day it was written and false since. The spec described work that was already in production. The portfolio session, which had shipped that work, caught it, and the spec was amended the next day. Rule since then: open work is read from the live plan section only; dated entries describe what shipped and nothing else.
Both times the catch came from another session with its own memory. That is the argument for the shape. A single mind fanning out into disposable workers cannot be caught by its workers, because they know only what it told them. Sessions that remember their own history can disagree with the one giving orders, and sometimes they are right.
The receipt
On the morning of 2 September I asked the command post to submit the spec for a page describing all of this through the toolkit’s write rail. The factory refused it: unknown session token. Nothing was written. The token I had minted the night before did not match what the session was sending, and the factory did not care why. The spec went in by hand as pull request 492, and the refusal is now the first receipt on the page, because a guardrail that fires on its owner is the only kind worth publishing.
Six months of the factory, a little over a year of building with agents, and this is the current shape: many sessions that never die, one that never writes code, a factory that only reads specs and only returns pull requests, and a person who decides in one place and presses merge. The chat I wrote in May was the first draft of that. The second draft was written by the platform, and it was better, and it came in time. The third is already specced, and it is mine again.