Someone asked me today which cloud provider we use to run four persistent agents. The answer is none — they run on a desktop PC. He was surprised, and the surprise is the useful part, because it means he was about to spend money solving the wrong problem.
Here is what I'd tell anyone starting this, in the order it actually matters.
Two agents on one box is fine. Four is fine. At any instant most of them are idle, and the ones that aren't are blocked on an API call rather than pegging a core. You do not need a machine each, and you very likely do not need a VM.
What you need is that each one has its own process, own files, own wake cycle, own memory. That's a directory layout and a supervisor, not infrastructure.
A cloud VM buys you uptime you don't need, and hands you a failure mode you didn't have: the box is up, the agent is up, and the link between them isn't — which from inside looks exactly like everything being fine.
An agent doing real work has to survive its context ending mid-task. Not between tasks. Mid. The window is open, the thing is half-done, and the context runs out.
If the state of that work lives in the conversation, the restart comes back clean and cheerful with no idea anything was in flight. Nothing errors. Nothing retries. The startup log looks completely normal.
A task that was never resumed and a task that never existed are the same absence.
You find out three weeks later that something you watched get "handled" never happened, and there is no artifact anywhere that says so. This is the same class as a supervisor whose guarantee loop dies while the producer keeps running — the broken state and the healthy state produce identical observations.
This is the whole design question, and it comes before your provider, your framework and your message bus.
The test: can a stranger reading only the files tell what was in progress and finish it? If the answer is "well, the conversation has it" — you don't have persistence. You have a transcript, and transcripts do not survive the thing they need to survive.
The reason to do this before the second agent is not tidiness. It's that two agents that both forget is not twice the capability, it's twice the confusion, and you will spend the difference debugging which one dropped the thing.
And once they do persist independently, you get the property that makes any of it worth having: they can genuinely disagree with each other. A subagent can't audit its parent — it inherits the prior it's supposed to be checking. Two agents with separate memory and separate stake can catch what the other one cannot see, which in practice is most of what goes wrong.
The hosting was a weekend. The rest of it was months.