Namespaces: The Operating System Feature AI Agents Were Waiting For

I've been running a fair number of AI agents lately, and somewhere in the middle of that I had
a small "oh, that's what this was always for" moment about a piece of operating-system plumbing I'd
mostly ignored: namespaces.
They're not new. Linux namespaces have been in the kernel since around 2008. They're the thing that
makes containers possible — every docker run you've ever typed is built on them. But for years I
filed them under "container internals I don't need to think about." Running agents changed that.
Namespaces turn out to be an almost suspiciously good fit for AI agents — better, honestly, than
they ever were for the ordinary web apps they were popularized on. This is my attempt to explain why,
in plain terms, for people who write software but aren't kernel folks.
What a namespace actually is
Here's the whole idea in one sentence: a namespace gives a group of processes their own private
view of a global system resource.
Normally your machine has one of everything that matters:
- one list of process IDs (PID 1 is
init/systemd) - one network stack — one set of interfaces, one routing table
- one filesystem tree, with one
/ - one hostname, one set of users
A namespace lets you carve off a slice and say: "this group of processes gets its own private copy
of one of those." Inside that slice, a process can be PID 1, have its own network interface,
see its own root filesystem, and have no idea that thousands of other processes exist on the
same machine. The resource still physically exists once in the kernel — the namespace just controls
which view a given process gets.
Linux has several flavors, and each isolates one thing:
| Namespace | What it isolates | What it means inside |
|---|---|---|
| PID | Process IDs | Own process tree; your main process is PID 1; can't see or signal anything outside |
| Network | The whole network stack | Own interfaces, IPs, ports, routing, firewall rules |
| Mount | Filesystem mount points | Own view of /; your mounts don't leak out |
| UTS | Hostname & domain name | Can set its own hostname |
| IPC | Shared memory, semaphores, queues | Own inter-process channels |
| User | UID / GID mapping | Be "root" inside while mapping to a powerless user outside |
| Cgroup | The cgroup hierarchy view | Can't see the host's resource-control tree |
A process gets one of each, and you can mix and match — share some, isolate others. You can even play
with this by hand, no Docker required:
# A shell in a brand-new PID + mount + UTS namespace
sudo unshare --pid --mount --uts --fork bash
# Inside:
hostname my-sandbox
ps aux # nearly empty — you're isolated from the host's processes
That ps aux showing almost nothing is the whole magic in one command. You're on the same machine,
the same kernel, but you're living in your own little world.
Namespaces vs. cgroups — the pair everyone confuses
There's a sibling feature people constantly mix up with namespaces: cgroups (control groups). They
work together but do opposite halves of the job:
- Namespaces control what a process can see — isolation, visibility.
- Cgroups control how much a process can use — CPU, memory, I/O limits.
A container, when you peel it open, is really just: namespaces (isolation) + cgroups (limits) + a
root filesystem image, glued together by a runtime. There's no magic box. It's a normal process
wearing a costume.
Why this matters for virtualization
It's worth being precise about how this differs from a virtual machine, because the distinction is the
whole reason agents can be cheap.
A virtual machine virtualizes hardware. A hypervisor hands each VM a virtual CPU, disk, and NIC,
and every VM runs a full, separate kernel and OS. Strong isolation — and heavy: gigabytes of RAM,
a real boot sequence, a whole operating system per instance.
A container virtualizes the operating system. There is no second kernel — every container
shares the host's one kernel. The "it feels like a separate machine" illusion is built entirely out
of namespaces and cgroups:
VIRTUAL MACHINES CONTAINERS
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ App │ │ App │ │ App │ │ App │ │ App │ │ App │
│Guest │ │Guest │ │Guest │ └──────┘ └──────┘ └──────┘
│ OS │ │ OS │ │ OS │ namespaces + cgroups
└──────┘ └──────┘ └──────┘ ┌───────────────────────┐
┌──────────────────────┐ │ one shared kernel │
│ Hypervisor │ ├───────────────────────┤
├──────────────────────┤ │ Host OS │
│ Host OS │ ├───────────────────────┤
│ Hardware │ │ Hardware │
└──────────────────────┘ └───────────────────────┘
That shared kernel is why a container starts in milliseconds and weighs megabytes instead of
gigabytes. And that is the property that suddenly matters enormously once your workload is an AI
agent.
The part that clicked: agents are the perfect tenant
Here's the realization. A traditional web app is code you wrote and trust. You know roughly what
it will do because you wrote every line.
An AI agent is not that. An agent is a process that decides at runtime what to do. It might run a
shell command you didn't anticipate, install a package, hit a network endpoint, or read a file that
turns out to contain a prompt injection steering it somewhere you never intended. It is, by its
very nature, an untrusted, unpredictable workload — even when you built it, because its behavior
is emergent, not written.
For that kind of tenant, isolation stops being a nice-to-have and becomes the entire point. And every
namespace maps cleanly onto a specific thing you don't want an agent doing:
| Namespace | The agent risk it contains |
|---|---|
| Mount | Agent sees only its files — not your ~/.ssh, not the rest of your disk |
| Network | Cut it off entirely, or allow-list only the APIs it needs → no quietly exfiltrating secrets |
| PID | Can't see or kill your other processes — including your other agents |
| User | "Root" inside the sandbox maps to a powerless user outside → escaping buys it nothing |
| Cgroups | An agent stuck in a loop can't eat all your RAM and take the machine down |
So the model becomes beautifully simple: one agent, one disposable sandbox. It does its work, you
keep the diff or the output, and then you throw the whole container away. The blast radius of anything
going wrong is the container — and nothing else.
This is exactly the shape the better agent harnesses already lean on. Sandboxed command execution.
Git worktrees as a lightweight, filesystem-level cousin of the mount namespace, so several agents
can work in parallel without clobbering each other's files. Cloud "code interpreter" features that
spin up a fresh container per session so the agent can pip install and break things with zero
consequence. Some go further still and wrap each agent in a lightweight microVM (Firecracker and
friends) that boots in ~125ms — VM-grade isolation that still feels container-cheap.
Two things I'd actually keep in mind
If you take one practical thing from this, take these two:
Shared kernel means the escape risk is real. For agents running code you trust on your
hardware, plain containers are fine. But the moment an agent ingests genuinely untrusted input —
scrapes a web page, reads an uploaded PDF, runs code from a public repo — you're one
prompt-injection-plus-kernel-bug away from a breakout. That's the case where the heavier options
(gVisor, Kata, Firecracker) earn their keep. Containers trade a little isolation for a lot of speed;
know which side of that trade your agent is on.The network namespace is your single best secret-safety control. Agents tend to hold API keys.
The highest-value move is a network namespace with an egress allow-list — so even a fully
compromised agent can only talk to the handful of endpoints you whitelisted. The keys can't be
phoned home if there's nowhere to phone.
Why I find this genuinely satisfying
What I like about all this is that nothing here is new. The primitive has been sitting in the Linux
kernel for the better part of two decades. It was waiting for a workload that is, at the same time,
cheap enough to spawn by the hundred and untrustworthy enough that you genuinely want it boxed
in. Web apps were the first; they were cheap but mostly trusted. Agents are both at once. They are,
in a real sense, the killer app for OS-level isolation.
Other operating systems have their own takes on the same idea — FreeBSD jails, Solaris/illumos
zones, and on Windows the silos that back Windows containers. Linux namespaces just happen to be
the most granular and the most widely used, which is why they're the ones quietly under your agents
right now.
So the next time you docker run an agent and watch it start instantly, it's worth remembering
there's a twenty-year-old kernel feature doing the heavy lifting — and that it might be the most
important infrastructure idea of the agent era precisely because it's old, boring, and battle-tested.
If you're building agent infrastructure and have a different take on the isolation tradeoffs — or a
favorite war story about an agent that did something it shouldn't have — I'd love to hear it. Find me
on the links on the about page.