Ten Agents, One Laptop, and a Hosting Bill Under Twenty Dollars
At the moment I am writing this there are ten coding-agent sessions running on the laptop in front of me. One is doing outreach. One is building a demo for a company in a domain I know nothing about. Two are writing. One is watching a browser tab for a page that has not loaded yet. The rest I would have to check.
They share one browser, two small servers with under two gigabytes of memory each, a handful of free-tier API keys, and sixteen gigabytes of RAM that is, as I type, fully used. The machine is fine. It was not always fine, and the reasons it is fine now are mundane enough that I think they are worth writing down, because I could not find them written anywhere else.
The startup health check
Every session, before it does anything else, audits the machine and prints a five-line report. Memory used and free, load average, how many agent sessions are running, and anything it killed.
The killing is the point. A machine running many agents accumulates cruft at a rate no person keeps up with: orphaned agent processes with no terminal attached, dev servers started for a test three days ago, a simulator somebody booted and forgot. The health check has a list of what it is allowed to terminate and a shorter, more important list of what it must never touch.
The rule that took a painful afternoon to learn: never kill an agent process that has a terminal attached. A process with a terminal is a live session a person is using. A process without one, older than a few hours, is an orphan. The distinction is one column in a process listing and getting it wrong ends someone’s afternoon of work, possibly your own.
The single largest resource killer on this machine, by a wide margin, was iOS simulators. One booted simulator spawns hundreds of child processes. A few agents running builds without shutting the simulator down afterward took the load average past seven hundred and nearly brought the machine down. There is now a hard rule that any build command is followed immediately by a shutdown, and the health check shuts down anything it finds booted.
Lane locks
Two agents doing the same job at the same time is worse than one agent doing it, because the results collide. Two outreach sessions can each decide the same person is a good target. Two application sessions can each submit to the same company. The dedupe ledger does not help, because both sessions read it before either writes to it.
So each job the agents can do is a named lane, and a lane has a lock file. A session that wants to work a lane checks for the lock first. If the lock is held by a live process, the session cedes the lane and does something else. If the lock is stale, held by a process that no longer exists, it takes it. The check is the first thing a session does after the health check, before it reads a single target.
The failure this prevents is not hypothetical. Before the locks I caught two sessions that had, in the same hour, independently emailed the same founder with slightly different notes. He noticed. The locks went in that night.
Git, when nobody has the room to themselves
Sharing a repository between concurrent sessions produces failures I had never seen in a decade of working with other humans, because humans do not commit fifty times an hour.
A bare commit sweeps another session’s staged files. Session A stages three files. Session B, working in the same checkout, runs its own commit, and A’s files go out under B’s message. Neither notices for a day.
Adding everything captures in-flight work. The habit of staging the whole tree is fine alone and catastrophic shared. Every session now stages by explicit path, and only paths it touched.
Ticket numbers race. Two sessions read the next sequential id at the same moment and both use it. The fix is to derive the id from something that cannot collide, or to let one session own numbering.
Big binary pushes time out and look like auth failures. A commit with a large media blob fails the push with a status code that suggests the token is wrong. The token is fine. The blob is too big for the connection, and the fix is to keep binaries out of the repo entirely.
The overarching rule is the same one as the browser: one writer, and everyone else stays in their lane.
One browser, many hands
All ten sessions drive the same Chrome. That works only because of the single-writer lock per tab and the background-tab rule I have described elsewhere. The thing worth adding here is that the browser is a shared resource with a capacity, and the capacity is not memory. It is the patience of the sites on the other end.
A site that would tolerate one careful visitor an hour will not tolerate ten. So the pacing is per site, not per session, and it lives in a place all sessions can read. When one session hits a rate limit, it records that, and the others slow down on that site without being told. The alternative, ten sessions each independently discovering the limit, is how you get a domain blocked.
The stack that costs almost nothing
People assume an operation like this runs on a large cloud bill. The hosting bill is under twenty dollars a month, and most of the compute is free, on purpose. The rule is: use the cheapest surface that still proves the point, and stay inside every free tier.
- Language models: the free tiers of two providers, for the bulk drafting, classification and transcription that does not need the strongest model. A rules file tells the agent which key to use for what, and the daily quotas are tracked so nothing quietly starts billing.
- Speech to text: entirely local. A Whisper model on the laptop’s GPU transcribes hours of audio at no cost, and it is the only speech model installed, because having two produced arguments about which one was in use.
- Static hosting: a free edge platform, for anything that is a page or a client-side app. Forty-odd projects live there and consume no memory anywhere.
- Backend hosting: two small virtual servers. One is precious and holds the things that make money. The other is where new backend demos go. Before anything is deployed the agent takes a live reading of both, memory free, disk free, what is running, and picks, or says there is no room.
- Analytics: first-party, a tiny collector on each site feeding a small database on one of the boxes. No third-party script, no monthly fee, and the data is mine.
- Translation and cloud odds and ends: a free-tier cloud account, with a written rule naming the older account that is no longer free and must never be used. That rule exists because of a five-dollar bill, which is small, and the principle, which is not.
The idle-cost table the agent consults before choosing a host is short: a Rails application idles at about three hundred megabytes, a PHP one at a hundred and thirty, a Node service at sixty to a hundred, a Go service at thirty, a static site behind a small web server at fifteen. Two boxes of under two gigabytes each hold about four or five real backend applications. Knowing that number, and having the agent check it rather than assume it, is what keeps the bill where it is.
The inventory is the product
The thread through all of this is a file. There is one for every server and hosted project: what it is, where it answers, why it exists, whether to keep it. There is one for the locks. There is one for the rate limits. There is the rules file every session reads. None of these are code, and together they are the thing that lets ten sessions share a machine without a coordinator.
Because the point of this is not that the agents are impressive. It is that the machine is a shared workshop now, and a shared workshop runs on the same thing a shared kitchen does: labels, a place for everything, and a short list of rules about what you never do to someone else’s work. That is the whole system. The scripts are the easy part.
The health-check script, the lock library, the pacing store, the capacity ledger and the per-provider quota rules are the pieces I set up for people rather than post. The shape of the thing is above.