Essay · 10 min read
Hands on with NVIDIA OpenShell
Governance infrastructure for AI agents, framed from the developer’s side: the commands you’d actually run, and the output you’d see come back.
TL;DR
- OpenShell is NVIDIA’s policy-driven sandbox runtime for AI agents. Apache 2.0, alpha (v0.0.36), runs on Docker.
- Frame it as governance infrastructure, not a security scanner: it sits between your agent and the host and decides what each binary can actually do, per process. Sane defaults ship out of the box, so you don’t write YAML on day one.
- Four use cases below: drop containment under your existing agent with no policy work, audit an unfamiliar MCP server in five minutes, run parallel agent evals without state collisions, and build a multi-agent debug rig where each agent has its own lane.
- It’s alpha, with rough edges: see the “what to know” section near the end before you put it in front of real data.
Why this matters
Most agent code today runs with the same privileges as the developer who started it. Same shell, same filesystem, same network. That worked when agents made one or two tool calls per session. It doesn’t work as well when an agent runs for thirty minutes, calls forty tools, and reads files from sources you don’t fully trust.
OpenShell (5.6k stars, 649 forks at time of writing) is NVIDIA’s bid at a runtime layer between the agent and the host. A small CLI, a Docker-based gateway, declarative YAML policies you only write when the defaults aren’t enough. Apache 2.0. Alpha (v0.0.36, released April 2026).
The framing the early adopters keep landing on isn’t “another sandbox,” it’s governance infrastructure. Sandboxes ask “did the agent do something bad?” Governance asks “could the agent have done that in the first place?” The interesting trick is per-binary policies: python3 can reach api.anthropic.com while curl on the same machine can’t reach anything at all. The model can hallucinate any tool call it likes; the runtime decides what actually executes.
Below are four concrete situations where I’d reach for it, framed from the developer’s side: what you type, what comes back, and what you do with it.
Use case 1
Drop containment under your existing agent without writing any YAML
The situation. You have an agent running today (Claude Code, Cursor, Codex, Copilot, or your own loop). You want default-deny network and read-only filesystem under it before something goes wrong, but you don’t have a free afternoon to learn a new policy DSL.
Before OpenShell
You had three bad options. Wrap your agent in Docker, but Claude Code, Cursor, and most coding agents were never designed to run inside a container, so you’d lose IDE integration, host filesystem access, or LSP features. Hand-roll an AppArmor or seccomp profile, but that needs root, a learning curve, and a willingness to debug kernel deny messages at 2 a.m. Or just trust the agent’s built-in allowlist, which buys you nothing the moment the model decides to curl somewhere new.
With OpenShell. The default OpenShell policy already ships with rules pre-baked for claude_code, codex, copilot, and cursor. You don’t write a policy file. You just create a sandbox and run your agent inside it.
What you see. Inspect what’s protecting you with one command:
That’s it. Filesystem locked to system paths, network locked to the hosts each major harness actually needs. The first time you try anything outside that envelope, the request dies at the kernel:
One sandbox, one flag, default-deny everywhere your agent shouldn’t go. You can graduate to writing custom YAML later if you need it.
Use case 2
Audit an unfamiliar MCP server in five minutes
The situation. You found a useful-looking MCP server on GitHub. Twelve stars, zero issues. The README says it’s a Slack tool, but the code is 800 lines you haven’t read. You’d like to wire it into your agent today, but giving someone else’s binary your shell privileges is a bad way to find out what it does.
Before OpenShell
Your options for vetting a sketchy MCP server were all bad in their own way. Clone the repo and read 800 lines line by line, hoping you’d spot the egress calls. Run it in a throwaway VM, which solves containment but kills the iteration loop. Or grep for http. and requests. and pray you caught everything. None of these tell you what the binary actually does at runtime — only what the source claims.
With OpenShell. Launch the server inside a fresh sandbox and let your harness talk to it via stdio. The MCP transport doesn’t care that there’s a sandbox in the middle. From any agent framework that supports stdio MCPs, the wiring looks like:
What you see. First time the server tries to phone home, it shows up as a denied request:
What you do next. Read which host it tried, decide whether you trust it, add it to a small custom policy if you do, repeat. After three or four iterations you have an explicit allowlist of every host the server actually needs. The README doesn’t have to be honest. You don’t have to read 800 lines. The runtime tells you what the code actually wants.
Use case 3
Run parallel agent evals without state collisions
The situation. You have eight prompts and four model variants. That’s thirty-two agent runs and you’d like them in parallel. On a single host they’d collide on ports, scratch files, environment variables, and whatever the agent decides to write into ~/.cache. You could spin up thirty-two Docker containers, but each one takes seconds to boot and gigabytes to image.
Before OpenShell
Fan-out at this scale meant Docker Compose with 32 services, each with its own port mapping, volume mount, and environment block. Boot time was measured in tens of seconds per container. Disk usage in gigabytes per image. And one stray write to a shared host path could contaminate every other run.
With OpenShell. Each sandbox gets its own filesystem view, its own working directory, its own network namespace, and boots in milliseconds. Fan-out is a bash loop:
What you see. Thirty-two output files in results/, one per (prompt, model) pair. No port conflicts because each sandbox has its own network namespace. No scratch-file collisions because each one writes to its own /sandbox/. No leaked env vars because the sandbox process doesn’t inherit your shell environment by default.
What you do next. Diff the results, drop the losers, tear down all thirty-two sandboxes with one openshell sandbox prune. Your host is exactly as you left it.
Use case 4
Build a multi-agent debug rig where each agent has its own lane
The situation. You’re building a multi-agent system. A planner emits a task graph, an executor runs each task, a critic reviews the output. Three agents that need different things: the planner needs LLM API access only, the executor needs filesystem write and a few external APIs, the critic needs read access to the executor’s outputs and nothing else. Running all three in one process means a bug in any one can corrupt the others.
Before OpenShell
Multi-agent systems meant one Python process or a thread pool, with all three agents sharing your shell. A bug in the executor that ate /? It ate your /. A planner that hung the event loop? Critic stopped too. Process isolation existed in theory; in practice everyone shared CPU, memory, environment variables, and the filesystem.
With OpenShell. Each agent gets its own sandbox. You wire them together with shared volumes for the artifacts they need to pass and nothing else.
What you see. Three sandboxes, three policies, three independent processes. When the executor goes haywire and tries to rm -rf something, it hits its own filesystem boundary, not yours. When the planner’s API call hangs, the critic and executor keep running. Attach a shell to any one of them mid-run:
What you do next. Restart any one sandbox without killing the other two: openshell sandbox restart executor. The planner’s still up, the critic’s still up, the executor comes back fresh and picks up from plan.json. Multi-agent systems get a lot more pleasant to debug when each agent is its own process you can hold separately.
What to know before you reach for it
OpenShell is alpha software in a hot category. The dev-experience write-ups so far are positive on the architecture and honest about the rough edges. A few worth flagging before you put it in front of anything sensitive:
- DNS over UDP/53 is currently unenforced. The gateway proxies TCP/HTTP egress; DNS queries go straight to the system resolver. Issue #1169 shows a working data-exfiltration PoC where
/etc/passwdescapes a strict policy via subdomain-encoded DNS lookups. Open as of v0.0.36. If you’re sandboxing against real PII, treat this as a known gap and front the sandbox with an outbound DNS firewall until it’s patched. - K3s overhead is real. The gateway runs k3s in Docker, which is a lot of machinery for a single-developer laptop sandboxing one Claude Code instance. Above three or four sandboxes the overhead amortizes; below that, you’re paying for capability you may not need.
- Don’t ship credentials into the sandbox as env vars. The community pattern that’s emerging: keep secrets out of the sandbox process entirely and expose them only via a connection API or short-lived ticket. An LLM running inside the sandbox can read its own environment trivially; the runtime won’t save you from that.
- Static vs dynamic policy.
filesystem_policy,landlock, andprocessare locked at sandbox creation; onlynetwork_policieshot-reloads. Plan filesystem layout up front; iterate on network rules.
None of these are dealbreakers for the use cases above. They are reasons to read the issue tracker before you bet a production workflow on it.
Where it sits next to Claude Code, Cursor, and MCP
OpenShell is not a coding agent. It’s the runtime under one. Three layers, three jobs:
- The harness is your Claude Code, Cursor, Aider, OpenCode, or your own agent loop. It owns the agent loop and decides which tools to call.
- The protocol is MCP. It’s how the harness talks to the tools.
- The runtime is OpenShell. The sandboxed OS the harness and the tools run inside.
If you’ve read the Prompt → Context → Harness post, OpenShell is the fourth layer underneath: Prompt → Context → Harness → Runtime. The agent loop confines the model to a finite set of moves. The runtime confines the moves themselves to what’s actually allowed.
It’s worth saying explicitly that OpenShell isn’t competing with e2b, Daytona, or Blaxel. Those are sandbox-as-a-service: cold-start a fresh VM in 25–150ms, run untrusted code, throw it away. Different category, different optimizations. e2b is north of two hundred million sandboxes served. OpenShell isn’t trying to win that race; it’s trying to be the policy and governance layer you’d run under any of them, or under your own agent on your own host. If your problem is “I need to spin up a thousand throwaway envs an hour for user-submitted code,” reach for e2b. If your problem is “I need to constrain what my own agent can do, with policies I can read in a YAML file and version in git,” reach for OpenShell.

About the author
Archit Dwivedi builds AI agents and ships them into production. More at /about · what I’m working on · say hi.
Archit · May 2026
Leave a comment