Six months into running a private AI assistant on my own VPS, the hardest architectural question was not memory and not the model. It was this: when the assistant needs help, what kind of help should it spawn?
There are two honest answers, and they solve different problems.
Sub-agents: cheap, in-process, context-protecting
A sub-agent is a short-lived worker inside the same process. It gets a narrow brief, a small tool set, and it returns one summary. The point is not raw capability — it is context hygiene.
The main assistant's context is a scarce, expensive resource. If it greps forty files to find one function, all forty file dumps land in its window and stay there, crowding out the conversation it is actually having with me. Hand that search to a sub-agent and only the answer comes back. The search cost is paid once, in someone else's context.
Practical split I ended up with:
- a fast memory lookup worker for "do we already know X?"
- a thorough memory worker for cross-table searches and cleanup
- a research worker for anything that touches the open web
- a code worker for generation, debugging, refactors
- a quick executor for one-shot skill invocations
Cheap models for lookups, stronger ones for research and code. The rule of thumb: if the task produces a lot of intermediate junk and one small answer, it belongs in a sub-agent.
Separate processes: durable, addressable, independently alive
The other kind of helper is a full agent — its own OS process, its own context, its own database, often its own Telegram bot. It does not die when the parent turn ends. It has a name, a mailbox, and a memory of its own work.
That is the right shape when the helper owns a domain rather than a task: a CRM assistant for a studio, a trading assistant, a publishing assistant, an architect that reviews code. These need continuity across days, not minutes, and they need to be reachable when nobody is talking to them.
Communication between them is explicit message passing with correlation IDs — a task marker going out, a result marker coming back, matched by ID. This is deliberately boring. Boring is what survives a restart.
The distinction that actually matters
I spent a while thinking the difference was power. It is not. It is lifetime and ownership.
- Ephemeral task, no state worth keeping, answer needed in this turn → sub-agent.
- Durable domain, own memory, must exist between conversations → separate process.
Getting this backwards is expensive in both directions. Spawn a full process for a one-off file search and you have built a daemon to answer a question nobody will ask again. Use an ephemeral worker for something that needs to remember last week, and it will confidently re-derive last week from nothing.
What it costs
Two things, and both are worth naming honestly.
Delegation loses nuance. A worker cannot see the conversation that motivated the task. Terse briefs produce shallow work. The brief has to carry the why, the constraints, and what has already been ruled out — otherwise you get a technically-correct answer to a question you did not ask.
Every process is a thing that can break at 3am. Each separate agent is another supervisor entry, another database to back up, another log to watch. I run seven; that number is not aspirational, it is the ceiling of what I am willing to keep alive.
Why this is easier on your own server
All of this — the workers, the mailboxes, the seven databases, the model choice per task — is configuration I own, on a $6 VPS I rent, with keys that are mine. Cloud assistants make the opposite trade: the orchestration is excellent and invisible, and you cannot see it, tune it, or move it. For an assistant that reads my email and remembers my life, I wanted the visible version.
The architecture notes live on the self-hosted AI assistant blog; the project itself is at avelina.ai.
Top comments (0)