NVIDIA OpenShell sandbox backend for LangChain Deep Agents
Project description
langchain-nvidia-openshell
NVIDIA OpenShell sandbox backend for LangChain Deep Agents.
⚠️ Alpha. NVIDIA OpenShell itself is alpha software ("single-player mode") and this integration tracks its API closely. Expect breakage.
OpenShellSandbox adapts NVIDIA's OpenShell — a policy-enforced, sandboxed
runtime for autonomous agents — to the LangChain BaseSandbox interface, so
your ChatNVIDIA-driven agent (running on the host) can dispatch shell
commands, file uploads, and file downloads into a hardened sandbox without
ever placing the agent itself inside.
This is the sandbox-as-tool pattern: the agent stays out, the tools go in.
┌──────────────────────────────┐
│ Host (your agent) │
│ │
│ ChatNVIDIA(...) │
│ │ │
│ ▼ │
│ create_deep_agent( │
│ model=..., │
│ backend=OpenShellSandbox │
│ ) │
└──────────────┬───────────────┘
│ gRPC (mTLS)
▼
┌──────────────────────────────┐
│ OpenShell Gateway │
└──────────────┬───────────────┘
│ ExecSandbox stream
▼
┌──────────────────────────────┐
│ Sandbox compute driver │
│ Docker/Podman/K8s/MicroVM │
│ policy-enforced execution │
└──────────────────────────────┘
Install
pip install langchain-nvidia-openshell
You also need the OpenShell CLI / gateway, pinned to match the SDK:
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh \
| OPENSHELL_VERSION=v0.0.72 sh
Confirm with openshell --version; this integration is tested against
OpenShell 0.0.72+.
Quickstart (local)
There are three moving parts:
- Start or connect to an OpenShell gateway.
- Create an OpenShell sandbox.
- Attach a Deep Agent to that sandbox through
OpenShellSandbox.
First, make sure the gateway is reachable:
openshell status
openshell sandbox list
Then choose how the sandbox lifecycle should work.
Option A: Python-owned sandbox
Use this when each Python process should create its own short-lived sandbox.
openshell.Sandbox(...) uses the active OpenShell gateway configuration and
the OpenShell SDK defaults unless you pass explicit SDK options. The adapter
does not choose an image, policy, driver, or provider profile.
import openshell
from langchain_nvidia_openshell import OpenShellSandbox
with openshell.Sandbox(delete_on_exit=True) as sb:
backend = OpenShellSandbox(sandbox=sb)
print(backend.execute("uname -a").output)
backend.upload_files([("/sandbox/hello.py", b"print('hello from openshell')\n")])
print(backend.execute("python3 /sandbox/hello.py").output)
print(backend.download_files(["/sandbox/hello.py"])[0].content)
Option B: CLI-created sandbox by name
Use this when you want an explicit policy, image, or long-lived sandbox that can be reused across agent runs. Create it once with the OpenShell CLI:
openshell sandbox create \
--name langchain-demo \
--policy ./example-policy.yaml \
--keep --no-tty -- bash
Then attach Python to the named sandbox:
import openshell
from langchain_nvidia_openshell import OpenShellSandbox
client = openshell.SandboxClient.from_active_cluster()
try:
backend = OpenShellSandbox(sandbox=client.get_session("langchain-demo"))
print(backend.execute("pwd").output)
finally:
client.close()
A named sandbox keeps running until you delete it with
openshell sandbox delete langchain-demo, so it can be reused by later Python
processes. That is convenient for demos and debugging; for production agent
runs, prefer a clear cleanup policy so stale state does not leak between runs.
Policies & security model
OpenShell policy controls the sandbox process, filesystem, and network
surface. OpenShellSandbox is policy-agnostic: the sandbox you pass in
already carries its policy, and this adapter only forwards Deep Agent tool
calls into that sandbox.
| Layer | What it controls | Enforced by | Set at create | Hot-reloadable |
|---|---|---|---|---|
| Filesystem | RO/RW mounts inside the sandbox | Linux Landlock LSM | ✅ | ❌ locked once running |
| Network | Outbound hosts, ports, HTTP methods/paths | In-sandbox HTTP CONNECT proxy + OPA/Rego | ✅ | ✅ via openshell policy set |
| Process | Run-as user/group, syscall filter | seccomp BPF + dropped privileges | ✅ | ❌ locked once running |
The stock community base image ships a default policy, but agent coverage is
not universal: NVIDIA's current default policy reference lists Claude Code as
fully covered, OpenCode as partially covered, and Codex as requiring a custom
policy. For LangChain Deep Agents, prefer an explicit policy that permits the
runtime tools you need (bash, python3, curl, package managers, and exact
network destinations) rather than depending on an agent preset.
Inference routing is adjacent gateway configuration, not network-policy CRUD.
If code inside the sandbox calls https://inference.local, policy can allow or
deny that hostname, but the provider credentials and model route are set with
OpenShell provider and inference commands.
Policy and inference workflows
1. Apply policy at create time. This is the only path that can change locked Filesystem and Process settings:
openshell sandbox create \
--policy ./example-policy.yaml \
--keep --no-tty -- bash
2. Hot-reload network policy. This works for Network rules without recreating the sandbox:
openshell policy set <sandbox-name> --policy ./tighten.yaml --wait
3. Configure managed inference separately. Create a provider record, then
point inference.local at the model you want:
openshell provider create --name nvidia-prod --type nvidia --from-existing
openshell inference set \
--provider nvidia-prod \
--model nvidia/nemotron-3-nano-30b-a3b
openshell inference get
--from-existing reads NVIDIA_API_KEY from the host environment. The key
stays with the gateway; the sandbox reaches it through inference.local only
when its network policy allows that route.
A complete example policy ships in
docs/sandboxes/example-policy.yaml.
Copy it, edit it, and pass it to openshell sandbox create --policy ....
To change locked Filesystem or Process defaults, recreate the sandbox with a
new policy or bake /etc/openshell/policy.yaml into a custom image.
Further reading
- OpenShell docs — top-level.
- Security controls & defaults — what each setting protects against.
- Policy schema reference — every YAML field.
security-policy.md— design doc with locked-vs-hot-reloadable rationale.sandbox-policy-quickstart— runnable demo of the create-then-tighten workflow.
Use with Deep Agents + ChatNVIDIA
import openshell
from deepagents import create_deep_agent
from langchain_nvidia_ai_endpoints import ChatNVIDIA
from langchain_nvidia_openshell import OpenShellSandbox
with openshell.Sandbox() as sb:
backend = OpenShellSandbox(sandbox=sb)
agent = create_deep_agent(
model=ChatNVIDIA(model="nvidia/nemotron-3-nano-30b-a3b"),
system_prompt="You are a careful coding agent.",
backend=backend,
)
print(agent.invoke({"messages": [{"role": "user",
"content": "Compute the sha256 of '/etc/hostname' inside the sandbox."}]}))
Deployment support matrix
OpenShell 0.0.72 has two relevant compatibility layers: the gateway/CLI host
matrix from NVIDIA, and the Python SDK wheels required by this notebook.
| Target | Gateway status | Notebook SDK status | Required runtime |
|---|---|---|---|
| Linux Debian/Ubuntu amd64 | Supported | Requires a host that can install manylinux_2_39_x86_64 wheels; Ubuntu 24.04+ is the expected floor |
Docker Engine/Desktop 28.04+, Podman 5.x, Kubernetes 1.29+, or MicroVM host virtualization |
| Linux Debian/Ubuntu arm64 | Supported | Requires a host that can install manylinux_2_39_aarch64 wheels; Ubuntu 24.04+ is the expected floor |
Docker Engine/Desktop 28.04+, Podman 5.x, Kubernetes 1.29+, or MicroVM host virtualization |
| macOS Apple Silicon | Supported | Requires macOS 13+ for the macosx_13_0_arm64 OpenShell SDK wheel |
Docker Desktop for container-backed sandboxes or Hypervisor.framework for MicroVM |
| Windows WSL 2 amd64 | Experimental | Not automated by this notebook setup | Docker Desktop through WSL 2 |
Compute drivers are selected at the gateway layer: docker, podman,
kubernetes, or vm for MicroVM-backed sandboxes. The OpenShell gateway image
is published for linux/amd64 and linux/arm64; sandbox images are maintained
separately in the NVIDIA OpenShell Community repository.
On macOS with the vm driver, the gateway may need explicit driver selection
when Docker/Podman is unavailable:
OPENSHELL_DRIVERS=vm openshell-gateway
OpenShell 0.0.72 also expects mkfs.ext4 from e2fsprogs while preparing
MicroVM root filesystems. With Homebrew, install e2fsprogs and make sure
mkfs.ext4 is visible under the prefix used by the gateway service.
For the notebook, run the setup script from the sandbox docs directory. It
validates the OS, OpenShell release, Python SDK wheel tag, grpcio runtime,
driver readiness, Poetry environment, and Jupyter kernel registration:
cd libs/openshell/docs/sandboxes
./setup_openshell.sh --openshell-version 0.0.72
API
class OpenShellSandbox(BaseSandbox):
def __init__(
self,
*,
sandbox: openshell.Sandbox | openshell.SandboxSession,
timeout: int = 30 * 60,
shell: tuple[str, ...] = ("bash", "-c"),
max_output_bytes: int = 1 << 20, # 1 MiB
max_upload_chunk_bytes: int = 512 * 1024, # 512 KiB
) -> None: ...
@property
def id(self) -> str: ...
def execute(self, command: str, *, timeout: int | None = None) -> ExecuteResponse: ...
def upload_files(self, files: list[tuple[str, bytes]]) -> list[FileUploadResponse]: ...
def download_files(self, paths: list[str]) -> list[FileDownloadResponse]: ...
# `aexecute`, `aupload_files`, `adownload_files`, and all other file ops
# (`ls`, `read`, `write`, `edit`, `glob`, `grep`) are inherited from
# `BaseSandbox`.
OpenShellSandbox does not own the lifecycle of the underlying OpenShell
sandbox. It accepts either an SDK-created sandbox/session or a session returned
from SandboxClient.get_session("<name>").
Use a Python context manager when you want per-run isolation and automatic cleanup. Use a named CLI-created sandbox when you need to set a specific image or policy before Python attaches, or when you want to reuse the same sandbox across multiple Deep Agent runs. Reused sandboxes keep filesystem and process state until deleted, so they are best for demos, debugging, and workflows that intentionally preserve state.
For OpenShell 0.0.72, multiline shell commands are sent through shell stdin
instead of bash -c argv because the VM driver rejects newline-bearing command
argv payloads. File uploads are chunked to 512 KiB raw payloads to stay within
the observed stdin transport limit after base64 encoding.
Notebook walkthrough
See docs/sandboxes/nvidia_openshell_sandbox.ipynb
for a step-by-step tutorial including local-only setup, ChatNVIDIA agent
integration, file transfer, and policy-enforced behavior demos.
Compatibility
| Layer | Version |
|---|---|
| Python | 3.12 – 3.14 (the OpenShell SDK requires 3.12+) |
deepagents |
>=0.5.0,<0.6.0 |
openshell (NVIDIA SDK + CLI) |
>=0.0.68,<0.1 — both ship from the same openshell package; verify with openshell --version |
grpcio |
>=1.78,<2; OpenShell's wheel metadata currently declares >=1.60, but generated gRPC stubs require >=1.78.0 at import time |
LangChain Deep Agents BaseSandbox |
follows deepagents |
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langchain_nvidia_openshell-0.1.0.tar.gz.
File metadata
- Download URL: langchain_nvidia_openshell-0.1.0.tar.gz
- Upload date:
- Size: 15.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
685bd5672a2c4d5a72a42030b5d69c170b4f843a09048e597d511d4b1753a2a8
|
|
| MD5 |
3a6889f95fb330c7ed47c43eead2cd76
|
|
| BLAKE2b-256 |
7d1c9b22db5780c8e3b0d8637229b57d115487860fbcfec50bac13b695e16cc8
|
File details
Details for the file langchain_nvidia_openshell-0.1.0-py3-none-any.whl.
File metadata
- Download URL: langchain_nvidia_openshell-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1d8c444841797159164d72f84e5b4e26cf24796aa2890c0aa13286b94a8c0b6
|
|
| MD5 |
34cb96f706adac332979534a3cb9c57f
|
|
| BLAKE2b-256 |
d5d4bbf9f816ac15a9f5752296630500f0609568b6cb2720123b2471c0c6b4a4
|