Architecture#
NemoClaw has two main components: a TypeScript plugin that integrates with the OpenClaw CLI, and a Python blueprint that orchestrates OpenShell resources.
System Overview#
NVIDIA OpenShell is a general-purpose agent runtime. It provides sandbox containers, a credential-storing gateway, inference proxying, and policy enforcement, but has no opinions about what runs inside. NemoClaw is an opinionated reference stack built on OpenShell that handles what goes in the sandbox and makes the setup accessible.
graph LR
classDef nemoclaw fill:#76b900,stroke:#5a8f00,color:#fff,stroke-width:2px,font-weight:bold
classDef openshell fill:#1a1a1a,stroke:#1a1a1a,color:#fff,stroke-width:2px,font-weight:bold
classDef sandbox fill:#444,stroke:#76b900,color:#fff,stroke-width:2px,font-weight:bold
classDef agent fill:#f5f5f5,stroke:#e0e0e0,color:#1a1a1a,stroke-width:1px
classDef external fill:#f5f5f5,stroke:#e0e0e0,color:#1a1a1a,stroke-width:1px
classDef user fill:#fff,stroke:#76b900,color:#1a1a1a,stroke-width:2px,font-weight:bold
USER(["π€ User"]):::user
subgraph EXTERNAL["External Services"]
INFERENCE["Inference Provider<br/><small>NVIDIA Endpoints Β· OpenAI<br/>Anthropic Β· Ollama Β· vLLM</small>"]:::external
MSGAPI["Messaging Platforms<br/><small>Telegram Β· Discord Β· Slack</small>"]:::external
INTERNET["Internet<br/><small>PyPI Β· npm Β· GitHub Β· APIs</small>"]:::external
end
subgraph HOST["Host Machine"]
subgraph NEMOCLAW["NemoClaw"]
direction TB
NCLI["CLI + Onboarding<br/><small>Guided setup Β· provider selection<br/>credential validation Β· deploy</small>"]:::nemoclaw
BP["Blueprint<br/><small>Hardened Dockerfile<br/>Network policies Β· Presets<br/>Security configuration</small>"]:::nemoclaw
MIGRATE["State Management<br/><small>Migration snapshots<br/>Credential stripping<br/>Integrity verification</small>"]:::nemoclaw
end
subgraph OPENSHELL["OpenShell"]
direction TB
GW["Gateway<br/><small>Credential store<br/>Inference proxy<br/>Policy engine<br/>Device auth</small>"]:::openshell
OSCLI["openshell CLI<br/><small>provider Β· sandbox<br/>gateway Β· policy</small>"]:::openshell
CHMSG["Channel messaging<br/><small>OpenShell-managed<br/>Telegram Β· Discord Β· Slack</small>"]:::openshell
subgraph SANDBOX["Sandbox Container π"]
direction TB
AGENT["Agent<br/><small>OpenClaw or any<br/>compatible agent</small>"]:::agent
PLUG["NemoClaw Plugin<br/><small>Extends agent with<br/>managed configuration</small>"]:::sandbox
end
end
end
USER -->|"nemoclaw onboard<br/>nemoclaw connect"| NCLI
USER -->|"Chat messages"| MSGAPI
NCLI -->|"Orchestrates"| OSCLI
BP -->|"Defines sandbox<br/>shape + policies"| SANDBOX
MIGRATE -->|"Safe state<br/>transfer"| SANDBOX
AGENT -->|"Inference requests<br/><small>no credentials</small>"| GW
GW -->|"Proxied with<br/>credential injected"| INFERENCE
MSGAPI -->|"Platform APIs"| CHMSG
CHMSG -->|"Deliver to agent"| AGENT
AGENT -.->|"Policy-gated"| INTERNET
GW -.->|"Enforced by<br/>gateway"| INTERNET
Deployment Topology#
The logical diagram above shows how components relate. This section shows what actually runs where on the host. NemoClaw uses a Docker daemon. The OpenShell gateway runs as a container that embeds a k3s cluster. The sandbox runs as a Kubernetes pod inside that embedded cluster.
graph TB
classDef host fill:#fff,stroke:#76b900,stroke-width:2px,color:#1a1a1a,font-weight:bold
classDef cli fill:#76b900,stroke:#5a8f00,color:#fff,stroke-width:2px,font-weight:bold
classDef docker fill:#2496ed,stroke:#1577c2,color:#fff,stroke-width:2px,font-weight:bold
classDef gateway fill:#1a1a1a,stroke:#1a1a1a,color:#fff,stroke-width:2px,font-weight:bold
classDef k3s fill:#ffc61c,stroke:#c89a00,color:#1a1a1a,stroke-width:2px,font-weight:bold
classDef pod fill:#444,stroke:#76b900,color:#fff,stroke-width:2px
classDef external fill:#f5f5f5,stroke:#e0e0e0,color:#1a1a1a,stroke-width:1px
subgraph HOST["Host machine Β· Linux / macOS / WSL2 / DGX Spark"]
direction TB
CLI["nemoclaw CLI<br/><small>bin/nemoclaw.js β dist/<br/>onboard Β· connect Β· status Β· logs</small>"]:::cli
subgraph DOCKER["Docker daemon"]
direction TB
subgraph GWCON["OpenShell gateway container"]
direction TB
PROXY["OpenShell L7 proxy<br/><small>rewrites Authorization headers<br/>and URL-path segments at egress<br/>(credential injection)</small>"]:::gateway
subgraph K3S["Embedded k3s cluster"]
direction TB
subgraph POD["Sandbox pod π<br/><small>Landlock + seccomp + netns</small>"]
direction TB
AGENT["OpenClaw agent<br/>+ NemoClaw plugin"]:::pod
end
end
end
end
end
INFER["Inference provider<br/><small>NVIDIA Endpoints Β· OpenAI<br/>Anthropic Β· Ollama Β· vLLM</small>"]:::external
CLI -->|"openshell CLI<br/>(orchestrates)"| GWCON
AGENT -->|"inference requests<br/><small>placeholder credentials</small>"| PROXY
PROXY -->|"egress with real credentials<br/>injected at the L7 proxy"| INFER
class HOST host
class DOCKER docker
class GWCON gateway
class K3S k3s
class POD pod
Layering from top to bottom:
Layer |
Runs as |
Role |
|---|---|---|
Host CLI |
Host process ( |
Orchestrates OpenShell via |
Docker daemon |
Host service |
Runs the OpenShell gateway container. |
Gateway container |
Docker container |
Hosts the credential store, the L7 proxy, and the embedded k3s control plane. |
k3s |
Process tree inside the gateway container |
Kubernetes control plane that schedules the sandbox pod. |
Sandbox pod |
Pod in the embedded k3s cluster |
Runs the OpenClaw agent and the NemoClaw plugin under Landlock + seccomp + netns. |
OpenShell L7 proxy |
Process in the gateway container |
Intercepts agent egress and rewrites |
NemoClaw never gives the sandbox a raw provider key.
At onboard time it registers credentials with OpenShellβs provider/placeholder system, and the L7 proxy substitutes the real value into outbound requests at egress.
The CLI helper isInferenceRouteReady (in src/lib/onboard.ts) is a host-side readiness check used by the resume flow to decide whether the active route already covers the chosen provider and model β it is not a runtime component.
For the DGX Spark-specific variant of this topology (cgroup v2, aarch64, unified memory), refer to the NVIDIA Spark playbook.
NemoClaw Plugin#
The plugin is a thin TypeScript package that registers an inference provider and the /nemoclaw slash command.
It runs in-process with the OpenClaw gateway inside the sandbox.
nemoclaw/
βββ src/
β βββ index.ts Plugin entry: registers all commands
β βββ cli.ts Commander.js subcommand wiring
β βββ commands/
β β βββ launch.ts Fresh install into OpenShell
β β βββ connect.ts Interactive shell into sandbox
β β βββ status.ts Blueprint run state + sandbox health
β β βββ logs.ts Stream blueprint and sandbox logs
β β βββ slash.ts /nemoclaw chat command handler
β βββ blueprint/
β βββ resolve.ts Version resolution, cache management
β βββ fetch.ts Download blueprint from OCI registry
β βββ verify.ts Digest verification, compatibility checks
β βββ exec.ts Subprocess execution of blueprint runner
β βββ state.ts Persistent state (run IDs)
βββ openclaw.plugin.json Plugin manifest
βββ package.json Commands declared under openclaw.extensions
NemoClaw Blueprint#
The blueprint is a versioned Python artifact with its own release stream. The plugin resolves, verifies, and executes the blueprint as a subprocess. The blueprint drives all interactions with the OpenShell CLI.
nemoclaw-blueprint/
βββ blueprint.yaml Manifest: version, profiles, compatibility
βββ policies/
β βββ openclaw-sandbox.yaml Default network + filesystem policy
The blueprint runtime (TypeScript) lives in the plugin source tree:
nemoclaw/src/blueprint/
βββ runner.ts CLI runner: plan / apply / status / rollback
βββ ssrf.ts SSRF endpoint validation (IP + DNS checks)
βββ snapshot.ts Migration snapshot / restore lifecycle
βββ state.ts Persistent run state management
Blueprint Lifecycle#
flowchart LR
A[resolve] --> B[verify digest]
B --> C[plan]
C --> D[apply]
D --> E[status]
Resolve. The plugin locates the blueprint artifact and checks the version against
min_openshell_versionandmin_openclaw_versionconstraints inblueprint.yaml.Verify. The plugin checks the artifact digest against the expected value.
Plan. The runner determines what OpenShell resources to create or update, such as the gateway, providers, sandbox, inference route, and policy.
Apply. The runner executes the plan by calling
openshellCLI commands.Status. The runner reports current state.
Sandbox Environment#
The sandbox runs the
ghcr.io/nvidia/openshell-community/sandboxes/openclaw
container image. Inside the sandbox:
OpenClaw runs with the NemoClaw plugin pre-installed.
Inference calls are routed through OpenShell to the configured provider.
Network egress is restricted by the baseline policy in
openclaw-sandbox.yaml.Filesystem access is confined to
/sandboxand/tmpfor read-write access, with system paths read-only.
Inference Routing#
Inference requests from the agent never leave the sandbox directly. OpenShell intercepts them and routes to the configured provider:
Agent (sandbox) βββΆ OpenShell gateway βββΆ NVIDIA Endpoint (build.nvidia.com)
Refer to Inference Options for provider configuration details.
Provider Credential Storage#
Provider credentials live in the OpenShell gateway store, not on the host filesystem. NemoClaw never writes them to host disk; the OpenShell L7 proxy injects values at egress. See Credential Storage for the inspection, rotation, and migration flow.
Host-Side State and Config#
NemoClaw keeps non-secret operator-facing state on the host rather than inside the sandbox.
Path |
Purpose |
|---|---|
|
Registered sandbox metadata, including the default sandbox selection. |
|
Host OpenClaw configuration that NemoClaw snapshots or restores during migration flows. |
The following environment variables configure optional services and local access.
Variable |
Purpose |
|---|---|
|
Telegram bot token you provide before |
|
Comma-separated Telegram user or chat IDs for allowlists when onboarding applies channel restrictions. |
|
URL for the optional chat UI endpoint. |
|
Build-time-only toggle that disables gateway device pairing when set to |
For normal setup and reconfiguration, prefer nemoclaw onboard over editing these files by hand.
Do not treat NEMOCLAW_DISABLE_DEVICE_AUTH as a runtime setting for an already-created sandbox.