Here’s the detail most write-ups bury: when an OpenShell agent calls an approved API, the real key never lives inside the sandbox. The supervisor outside injects it only for that exact endpoint and binary. Steal the container, dump memory, scrape env – the secret still isn’t there.
NVIDIA/OpenShell is Apache-2.0 and sits around 17.1k stars / 1.8k forks as of early 2026 (0.1.x). It treats every agent as untrusted and runs Claude Code, OpenCode, Codex, Copilot CLI, or a custom image on your hardware. No per-run cloud meter. This guide skips the component lecture and gets you to a sandbox that actually boots under policy.
What OpenShell Actually Enforces
Think of the sandbox as an airlock, not a nicer Docker flag. A local gateway owns lifecycle. Inside: Landlock filesystem limits, seccomp-style process rules, deny-by-default egress. Outside: the supervisor holds credentials and only attaches them to matching outbound calls. Prompts cannot rewrite that boundary.
Per NVIDIA’s overview, filesystem and process rules lock at create time. Network rules hot-reload after approval. A policy prover checks proposed changes with logic – not another model voting on safety. Platforms called out in the support matrix: Linux amd64/arm64, macOS Apple Silicon, WSL2 experimental; Docker 28+, Podman 5.x, or MicroVM (KVM / Hypervisor.framework). Default workload image is nvcr.io/nvidia/base/ubuntu:24.04.
Pro tip: boot each agent on the tightest YAML that still starts, then approve narrow proposals one by one. You get an audit trail without extra tooling.
Step-by-Step: First Sandbox with a Real Agent
You need Docker (or Podman) running and a real model key. For Claude that means an Anthropic Console API key – subscription Pro/Max tokens get rejected by the provider profile.
- Install CLI + gateway (official quickstart path also documents
uv tool install openshell):curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh openshell statusConfirm the gateway reports healthy on the local port the install prints.
- Build an image that actually contains the agent. In 0.1.x the default Ubuntu base ships no agent CLIs, so bare catalog aliases are a trap. Minimal Claude Code Dockerfile:
FROM ubuntu:24.04 RUN apt-get update && apt-get install -y ca-certificates curl git iproute2 && curl -fsSL https://downloads.claude.ai/keys/claude-code.asc -o /etc/apt/keyrings/claude-code.asc && echo "deb [signed-by=/etc/apt/keyrings/claude-code.asc] https://downloads.claude.ai/claude-code/apt/stable stable main" > /etc/apt/sources.list.d/claude-code.list && apt-get update && apt-get install -y claude-code && rm -rf /var/lib/apt/lists/* RUN install -d -o ubuntu -g ubuntu /sandbox USER ubuntu WORKDIR /sandboxdocker build -t claude-agent:local . - Import the provider profile, stash the key once, then scrub the shell:
openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/claude-code.yaml export ANTHROPIC_API_KEY=sk-... openshell provider create --name claude --type claude-code --from-existing unset ANTHROPIC_API_KEY - Starter policy – grant the home path the agent writes on first run (FS will not hot-fix):
version: 1 filesystem_policy: include_workdir: true read_only: [/bin, /usr, /lib, /proc, /dev/urandom, /etc] read_write: [/sandbox, /tmp, /dev/null, /home/ubuntu] landlock: compatibility: best_effort network_policies: {}Schema shape matches the upstream quickstart policy example.
- Launch:
openshell sandbox create --name demo --from claude-agent:local --provider claude --policy ./policy.yaml -- claudeBlocked hosts show up as pending rules. Inspect, then
openshell rule approvethe ones you want – network updates live. Same loop works for OpenCode + an OpenRouter key: swap image, profile, and the command after--.
Common Pitfalls That Kill First Runs
openshell sandbox create -- claude with no --from? You land in a bare Ubuntu shell. 0.1.x dropped useful default agent images; the binary must already exist at the path the provider profile expects.
The catch is filesystem lock timing. Claude writes under the image user home. Omit /home/ubuntu (or your USER) from the initial YAML and the session dies before any network rule matters. Network you can fix live. Disk you cannot.
Plain --env ANTHROPIC_API_KEY=... stuffs the real secret inside the sandbox and defeats the whole supervisor model. Providers exist for a reason. Same class of failure: Pro/Max subscription material instead of a Console key.
Kernel check early: cat /sys/kernel/security/lsm should list landlock (ABI v3 needs a recent kernel, roughly 6.2+). Nested virt missing on a VPS? You stay on shared-kernel Docker isolation. MicroVM is the stronger box when KVM is actually there.
OpenShell vs Plain Docker or Cloud Sandboxes
| Aspect | OpenShell | Plain Docker | Typical cloud agent sandbox |
|---|---|---|---|
| Credentials | Supervisor injects per endpoint; not resident in sandbox | Env files / mounts | Often inside the workload |
| Policy | YAML + prover + hot network | Hand-rolled seccomp/AppArmor | Vendor-defined, often opaque |
| Cost | Your hardware, Apache 2.0 | Your hardware | Per-minute / per-run |
| Fleet control | Gateway + per-sandbox policies | DIY orchestration | Vendor dashboard |
| Audit | Allow/deny logged by design | You build it | Vendor logs |
OpenShell wins for long-running or self-evolving agents when you need reviewable boundaries on your own metal or Kubernetes. Plain containers stay lighter if basic isolation is enough and you trust the image. Cloud sandboxes bill you per run and hide the knobs.
One open question the docs still leave: how far the Sentry / BlueField hardware layer called out with the Reference Architecture (see NVIDIA’s architecture write-up) will shrink quarantine time versus pure software enforcement on commodity CPUs. Early adopters will measure that first – software-only is what you can run today.
FAQ
Does OpenShell require an NVIDIA GPU?
No. CPU-only Docker or Podman sandboxes work on ordinary Linux or macOS Apple Silicon.
Can I run multiple agents as a fleet?
Yes. One gateway, many named sandboxes, each with its own policy and provider bindings. Practical split: sandbox A for a long coding task with broad tooling hosts; sandbox B locked to internal endpoints only for research summaries. Scale-out is on you (K8s job per sandbox is the obvious pattern).
What happens if the agent tries to exfiltrate data?
Unauthorized hosts die at the network layer before the packet leaves. The agent may propose a rule; you approve – or you don’t – after the prover checks it. Landlock already blocked reads outside the paths you declared at create. A fully compromised agent process still cannot read host credential stores or open sockets you never allowed.
Next action: run the install script, build the tiny Claude image above, launch one sandbox, open pending rules, approve only what the task needs. That loop beats another architecture diagram.