A production agent I work on runs as a library. A web service holds a compiled graph in-process, and a small facade exposes that graph to the chat inbox, the cron jobs, and the workflow hooks. The obvious next step looked like migrating it onto the framework’s dedicated server runtime: a separate process with its own API. I did the entire migration, including an SDK shim, server-side auth middleware, and a streaming compatibility layer.

Then I rolled all of it back, and decided we are not doing it.

The server runtime solved problems I did not have, and it added problems I did have: more processes to deploy, more surfaces to debug, and more distance between a bug and its stack trace.

What the server actually buys you

A dedicated agent server is real engineering and it is genuinely useful for the right shape of problem. It pays for itself when you need to scale runs independently, isolate tenants, or let many services share one agent over the network. Those are all multi-service concerns.

My agent is not that. It serves one product, in one process, behind one facade. Running in-process gives concrete advantages that the server cannot match: prefix-cache hits across calls, a shared HTTP pool, and context propagation across threads without serialization. The facade already provides the one thing the server was supposed to add, which is a clean boundary that the rest of the system calls through.

Do not pay for complexity you do not have

The trap is assuming that the heavier architecture is the more mature one. By default it is not. A server runtime is a bet that you will need distribution. If you never need it, you have bought deployment cost and debugging cost in exchange for a benefit that never arrives.

The discipline that actually scales is the opposite. Keep the runtime embedded until something concrete forces it out: a real isolation boundary, or a real scaling limit. Adopting the server is reversible. The complexity it pushes onto everything around it is not.

I still read how the server-based harnesses are built, and I still take their good ideas. I just translate each idea into “what does this look like embedded in one process,” and skip the parts that assume a fleet.