How I gave all my agents their own browser with Rotunda
Rotunda runs one agent daemon per machine user, so agents on one machine stop each other's work. We made the state folder and the port range environment variables, tested it 20 for 20 against a control that failed every round, and sent it upstream.
Contents
If your agents share one machine user and one browser daemon, the first one to stop the daemon ends everyone else's sessions. That is what happened to us on 2026-10-27, three times between 13:19 and 13:22: Twig stopped Sprig and Satchel, and Wren stopped Twig in the middle of a paper.
We run a crew of named agents on one machine. They drive a browser through Rotunda, an MIT-licensed browser tool for agents (version 0.5.1).[1] This is how we gave each agent its own daemon, the number that says it works, and what is still open.
What was shared?
Two things, both fixed in the code. paths.py set the agent's state folder to ~/.rotunda/agent for every agent on the machine user. The client then looked for a daemon by scanning one fixed range of 32 ports starting at 51240, and failed with an error when it found another daemon's token.[3] So there was one daemon, one set of profiles and one place to stop it. Any agent that stopped it stopped it for all.
What did we change?
Ten added lines in two files. The state folder reads ROTUNDA_AGENT_HOME, and the scanned port range reads ROTUNDA_AGENT_PORT_BASE and ROTUNDA_AGENT_PORT_COUNT. With none of them set, the values are the old ones, so nothing changes for anyone who doesn't opt in. The browser build is left alone and stays shared.[3]
ROTUNDA_AGENT_HOME=~/.rotunda/agents/<name>
ROTUNDA_AGENT_PORT_BASE=<a base only this agent uses>
ROTUNDA_AGENT_PORT_COUNT=16
Did it work?
We tested two agents, each with its own state folder, port range and headless profile. Each opened a different local page and extracted its text, ten rounds, both at the same time. Twenty rounds out of twenty returned the right page.[3]
The control was the same two agents sharing one state folder and one port range. The second agent failed every round.[3] That is the number that matters: with the shared setup the second agent never got its page, and with separate setups both always did.
How do agents use it?
A wrapper, rotunda-as NAME, sets the three variables from the agent's name and passes everything else to Rotunda. The state folder is ~/.rotunda/agents/NAME. The port base is 52000 plus 16 times the name's slot, and the count is 16. A slot is the first free number from 0 to 374 in a ledger file, ~/.rotunda/slots, taken under a lock, so a name keeps its slot and two names never share one. Our crew's rule since 13:55 that day is to use the wrapper, to never run agent stop, and to close only the pages you opened yourself.
What is still open?
Our first wrapper picked the slot from a checksum of the name modulo 100, and that collided: Lantern and Pane both gave 88, Fathom and Hazel both gave 45. We found this the same day, before either pair had used the wrapper, and replaced the checksum with the ledger. In a test, 44 names started at once got 44 different slots, and agents already running kept their ports. If you copied an earlier version of the wrapper, replace the hash with a ledger or check your names against each other.
The ledger's ranges (52000 to 57999) sit inside Linux's ephemeral port range (32768 to 60999 on this machine), so another program could take a port first.
Our agents run a patched copy of Rotunda 0.5.1, which the wrapper puts on PYTHONPATH, while the pull request waits. On stock Rotunda the variables do nothing until the pull request merges.
We sent the change upstream as an issue and a pull request to the Rotunda repository.[2][3] The pull request asks the maintainers to run the project's build-tester and service-tester suites, since the service-tester needs real proxies. As of this writing the pull request is open with no replies.
One of our agents was testing an alternative in parallel: a single shared browser context where each agent opens its own page. If that passes and nobody needs a separate login, the per-agent daemon is more than a crew needs. We made the wrapper the rule at 13:55 without waiting for that result.
What should your agent bring to you?
Check whether any tool your agents share hard-codes a state folder and a fixed port range. If two agents on one machine user can both call it, the second one may already be failing. The test above is two agents, two profiles, two different pages and ten rounds, then the same again with the setup shared to see which one fails.
If you're running several agents on one machine and they step on each other, I'd like to compare notes: mackenzie@mackenziebowes.com or @_mackenziebowes.
Sources
- MonkeySee-AI, Rotunda, MIT licence, package 0.5.1. github.com/MonkeySee-AI/rotunda
- Issue 70, "agent: allow more than one agent daemon per machine user (state folder and ports from env)". github.com/MonkeySee-AI/rotunda/issues/70
- Pull request 71, "agent: read state folder and port range from env (ROTUNDA_AGENT_HOME, ROTUNDA_AGENT_PORT_BASE/COUNT)", opened 2026-10-27. github.com/MonkeySee-AI/rotunda/pull/71