From 43e5713be79d66ef80a371181ad67a26e68d4a0a Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 12:23:52 -0700 Subject: [PATCH 01/20] Removed network access docs --- .../network-access-rules.md | 290 ------------------ 1 file changed, 290 deletions(-) delete mode 100644 docs/safety-and-privacy/network-access-rules.md diff --git a/docs/safety-and-privacy/network-access-rules.md b/docs/safety-and-privacy/network-access-rules.md deleted file mode 100644 index 4ef9bd6558..0000000000 --- a/docs/safety-and-privacy/network-access-rules.md +++ /dev/null @@ -1,290 +0,0 @@ - - -# Network Access Rules - -Every outbound connection from a sandbox passes through OpenShell's transparent -proxy. Nothing leaves the sandbox directly. The proxy identifies which binary -initiated the connection, evaluates the active policy, and decides what happens -next. - -## How the Proxy Evaluates Connections - -Each outbound connection resolves to one of three outcomes: - -| Outcome | When it applies | What happens | -|------------------------|-----------------------------------------------------------------------------|-----------------------------------------------------------------------------| -| Allow | A `network_policies` entry matches the destination host *and* the calling binary. | Traffic flows directly to the destination. The agent's own API key is used. | -| InspectForInference| No network policy matches, but `inference.allowed_routes` is configured. | The proxy intercepts the connection and hands it to the privacy router, which reroutes it to a configured backend. The route's API key is used. | -| Deny | No network policy matches and no inference route applies. | The connection is blocked. The calling process receives a 403 or connection reset. | - -:::{note} -This is the most important distinction in OpenShell's network model. - -*Agent traffic* is the coding agent (Claude, OpenCode, Codex) calling its own API to get completions. This traffic matches a `network_policies` entry because the policy declares both the endpoint (for example, `api.anthropic.com:443`) and the binary (for example, `/usr/local/bin/claude`). The proxy allows it through directly. The agent's own API key (injected by the provider) is used as-is. - -*Userland traffic* is code that the agent *writes* making inference calls. A Python script calling the OpenAI-compatible API, a data pipeline hitting an LLM endpoint, a test harness querying a model. This traffic does *not* match any network policy because the calling binary (`/usr/bin/python3`) is not listed in the agent's policy entry. The proxy intercepts it, the privacy router reroutes it to a configured backend, and the route's API key is substituted in. The agent's code never touches your real API key. -::: - -```{mermaid} -flowchart TD - A["Outbound connection from sandbox"] --> B["Proxy resolves calling binary\n(/proc/pid/exe, ancestors, cmdline)"] - B --> C{"Network policy matches\n(endpoint + binary)?"} - C -- Yes --> D["Allow: forward directly\nto destination"] - C -- No --> E{"Inference routes\nconfigured?"} - E -- Yes --> F["InspectForInference:\nTLS terminate, check for\ninference pattern"] - F --> G{"Matches inference\npattern?"} - G -- Yes --> H["Route to configured\ninference backend"] - G -- No --> I["Deny: 403"] - E -- No --> I - - style A fill:#ffffff,stroke:#000000,color:#000000 - style B fill:#76b900,stroke:#000000,color:#000000 - style C fill:#76b900,stroke:#000000,color:#000000 - style D fill:#76b900,stroke:#000000,color:#000000 - style E fill:#76b900,stroke:#000000,color:#000000 - style F fill:#76b900,stroke:#000000,color:#000000 - style G fill:#76b900,stroke:#000000,color:#000000 - style H fill:#76b900,stroke:#000000,color:#000000 - style I fill:#ff4444,stroke:#000000,color:#ffffff - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -## Structure of a Network Policy Entry - -Each entry in the `network_policies` section pairs a set of endpoints with a set of binaries. Only the listed binaries can connect to the listed endpoints: - -```yaml -network_policies: - my_rule: - name: my-rule - endpoints: - - host: api.example.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/local/bin/my-agent -``` - -The key (`my_rule`) is a logical name for reference. The `name` field is the human-readable label that appears in logs and the OpenShell Terminal. - -## Endpoints - -Each endpoint entry controls access to a single host-port combination. Refer to [Endpoint Object](../reference/policy-schema.md#endpoint-object) for the full field reference. - -The `access` field provides presets: `full` (all methods), `read-only` (`GET`, `HEAD`, `OPTIONS`), or `read-write` (`GET`, `HEAD`, `OPTIONS`, `POST`, `PUT`, `PATCH`). - -### Custom Rules - -When access presets are not granular enough, define explicit allow rules. Each rule specifies a method and a path pattern: - -```yaml -endpoints: - - host: github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - rules: - - allow: - method: GET - path: /**/info/refs* - - allow: - method: POST - path: /**/git-upload-pack -``` - -This example allows Git fetch operations (read-only clone and pull) while blocking push operations. Path patterns use glob syntax. - -If a request does not match any rule, it is denied (in `enforce` mode) or logged (in `audit` mode). - -## Binaries - -The `binaries` list specifies which executables are permitted to use the endpoint. Each entry has a `path` field that the proxy matches against the calling process. - -The proxy resolves the calling binary through several mechanisms, evaluated in order: - -| Match type | Example | Description | -|-------------------|---------|-------------| -| Exact path | `/usr/local/bin/claude` | Matches the binary at exactly this path. | -| Ancestor process | `/usr/local/bin/claude` | Matches if any ancestor in the process tree has this path. A Node.js subprocess spawned by Claude matches a `claude` entry. | -| Cmdline path | `/usr/local/bin/opencode` | Matches against `/proc/pid/cmdline` for interpreted languages where the `exe` link points to the interpreter. | -| Glob pattern | `/sandbox/.vscode-server/**` | Matches any executable under the directory tree. | - -```yaml -binaries: - - path: /usr/local/bin/claude - - path: /usr/bin/node - - path: /sandbox/.vscode-server/** -``` - -## L7 Inspection - -To inspect HTTPS traffic at the HTTP level, you need both `protocol: rest` and `tls: terminate` on the endpoint: - -```yaml -endpoints: - - host: api.example.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full -``` - -With both fields set, the proxy terminates the TLS connection, decrypts the HTTP request, evaluates it against the `access` preset or custom `rules`, and re-encrypts before forwarding to the destination. - -:::{warning} -Without `tls: terminate` on port 443, the proxy cannot decrypt the traffic. L7 rules (`access`, `rules`) are not evaluated because the HTTP payload is encrypted. The connection is handled at L4 only: allowed or denied based on host and port, with no HTTP-level access control. -::: - -### Bare Endpoints (L4-Only) - -Endpoints declared without `protocol` or `tls` are L4-only: - -```yaml -endpoints: - - host: registry.npmjs.org - port: 443 -``` - -The proxy allows the TCP connection through to the destination without decrypting or inspecting the payload. Use L4-only entries for non-HTTP traffic, package registries where you need connectivity but not method-level control, or endpoints where TLS termination is not desired. - -:::{warning} -With L4-only rules, you have no control over *what* is sent to the endpoint: only *whether* the connection is allowed. Any binary listed in the entry can send any data to the host. If you need to restrict HTTP methods or paths, add `protocol: rest` and `tls: terminate`. -::: - -## Forward Proxy Mode - -The sandbox proxy supports two request modes: CONNECT tunnels (the default for -HTTPS) and forward proxy (for plain HTTP to private endpoints). - -When a client inside the sandbox sets `HTTP_PROXY` and makes a plain `http://` -request, standard HTTP libraries send a forward proxy request instead of a -CONNECT tunnel. The proxy handles these transparently. - -### Security Constraints - -Forward proxy mode is restricted to private IP endpoints that are explicitly -allowed by policy. Plain HTTP traffic never reaches the public internet. All -three conditions must be true: - -1. The network policy explicitly allows the destination. -2. The matched endpoint has `allowed_ips` configured. -3. All resolved IP addresses are RFC 1918 private (`10/8`, `172.16/12`, `192.168/16`). - -If any condition fails, the proxy returns 403. - -| Condition | Forward proxy | CONNECT | -|---|---|---| -| Public IP, no `allowed_ips` | 403 | Allowed (standard SSRF check) | -| Public IP, with `allowed_ips` | 403 (private-IP gate) | Allowed if IP in allowlist | -| Private IP, no `allowed_ips` | 403 | 403 (SSRF block) | -| Private IP, with `allowed_ips` | Allowed | Allowed | -| `https://` scheme | 403 (must use CONNECT) | N/A | - -### Policy Configuration - -No new policy fields are needed. The same `network_policies` entry that enables -CONNECT access to a private endpoint also enables forward proxy access. Add -`allowed_ips` to the endpoint: - -```yaml -network_policies: - internal_service: - name: internal-service - endpoints: - - host: 10.86.8.223 - port: 8000 - allowed_ips: - - "10.86.8.223/32" - binaries: - - path: /usr/local/bin/python3.12 -``` - -With this policy, both CONNECT and forward proxy requests to the endpoint work: - -```python -import httpx -resp = httpx.get("http://10.86.8.223:8000/api/", - proxy="http://10.200.0.1:3128") -``` - -### Limitations - -- Forward proxy v1 injects `Connection: close` (no keep-alive). Each connection handles exactly one request-response exchange. -- L7 inspection is not performed on forwarded traffic. -- `https://` URLs must use the CONNECT tunnel, not the forward proxy path. - -## Enforcement Modes - -Each endpoint can operate in one of two enforcement modes: - -| Mode | Behavior on violation | -|-----------|-----------------------| -| `enforce` | Blocks the request and returns HTTP 403 to the calling process. The violation is logged. | -| `audit` | Logs the violation but forwards the traffic to the destination. The agent is not interrupted. | - -:::{tip} -Start with `enforcement: audit` when developing a new policy. Audit mode shows you what *would* be blocked without actually breaking the agent. After the policy is correct and you have confirmed that no legitimate traffic is flagged, switch to `enforcement: enforce`. -::: - -## Putting It Together - -Here is a realistic policy snippet for an agent that needs to reach its own API, clone Git repositories (read-only), and install npm packages: - -```yaml -network_policies: - agent_api: - name: agent-api - endpoints: - - host: api.anthropic.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/local/bin/claude - - path: /usr/bin/node - - github: - name: github - endpoints: - - host: github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - rules: - - allow: - method: GET - path: /**/info/refs* - - allow: - method: POST - path: /**/git-upload-pack - binaries: - - path: /usr/bin/git - - npm_registry: - name: npm-registry - endpoints: - - host: registry.npmjs.org - port: 443 - binaries: - - path: /usr/bin/npm - - path: /usr/bin/node - - path: /usr/local/bin/npm - - path: /usr/local/bin/node -``` - -## Next Steps - -- [Write Sandbox Policies](policies.md): The full iterative workflow for authoring, testing, and updating policies. -- {doc}`security-model`: Threat scenarios and how the four protection layers work together. From 9e73227fbe893fa76c1638bffd38d0bedeed2be5 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 15:47:22 -0700 Subject: [PATCH 02/20] Simplified docs for sandboxes and inference --- docs/inference/configure-routes.md | 2 +- docs/sandboxes/community-sandboxes.md | 1 - docs/sandboxes/create-and-manage.md | 77 +++--------------- docs/sandboxes/custom-containers.md | 80 ------------------- docs/sandboxes/index.md | 19 +---- docs/sandboxes/providers.md | 37 --------- docs/sandboxes/terminal.md | 110 -------------------------- 7 files changed, 14 insertions(+), 312 deletions(-) delete mode 100644 docs/sandboxes/custom-containers.md delete mode 100644 docs/sandboxes/terminal.md diff --git a/docs/inference/configure-routes.md b/docs/inference/configure-routes.md index a76f904a5d..347b8dd559 100644 --- a/docs/inference/configure-routes.md +++ b/docs/inference/configure-routes.md @@ -8,7 +8,7 @@ This guide covers how to create and manage inference routes so that sandboxes can route AI API calls from userland code to policy-controlled backends. You will learn to create routes, connect them to sandboxes through policy, and manage routes across a cluster. :::{note} -Inference routes are for *userland code*, which are scripts and programs that the agent writes and executes inside the sandbox. The agent's own API traffic flows directly through network policies, not through inference routing. Refer to {doc}`../safety-and-privacy/network-access-rules` for the distinction between agent traffic and userland traffic. +Inference routes are for *user code*, which are scripts and programs that the agent writes and executes inside the sandbox. The agent's own API traffic flows directly through network policies, not through inference routing. Refer to {doc}`../safety-and-privacy/network-access-rules` for the distinction between agent traffic and user traffic. ::: ## Create a Route diff --git a/docs/sandboxes/community-sandboxes.md b/docs/sandboxes/community-sandboxes.md index f176abdf0d..0124f4506b 100644 --- a/docs/sandboxes/community-sandboxes.md +++ b/docs/sandboxes/community-sandboxes.md @@ -91,5 +91,4 @@ or anything else), consider contributing it back so others can use it. ## Next Steps - {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`custom-containers`: Build a fully custom container with BYOC - {doc}`../safety-and-privacy/policies`: Customize the policy applied to any sandbox diff --git a/docs/sandboxes/create-and-manage.md b/docs/sandboxes/create-and-manage.md index f9653d1b1e..cb0db002d8 100644 --- a/docs/sandboxes/create-and-manage.md +++ b/docs/sandboxes/create-and-manage.md @@ -16,18 +16,12 @@ Ensure the following are installed before creating sandboxes. ## Create a Sandbox -The simplest way to create a sandbox is to specify a trailing command: - ```console $ nemoclaw sandbox create -- claude ``` -The CLI bootstraps the runtime (if this is your first run), discovers your -credentials, applies the default policy, and drops you into the sandbox. +If you have an existing gateway, a sandbox will be created within that gateway or if you don't have one, one will be created for you. -You can customize creation with flags like `--name`, `--provider`, `--policy`, -`--upload`, `--keep`, `--forward`, and `--from`. Refer to the -[CLI Reference](../reference/cli.md) for the full flag list. A fully specified creation command might look like: @@ -75,17 +69,6 @@ Open an SSH session into a running sandbox: $ nemoclaw sandbox connect my-sandbox ``` -### VS Code Remote-SSH - -Export the sandbox SSH configuration and append it to your SSH config: - -```console -$ nemoclaw sandbox ssh-config my-sandbox >> ~/.ssh/config -``` - -Then open VS Code, install the Remote - SSH extension if you have not -already, and connect to the host named `my-sandbox`. - ## View Logs Stream and filter sandbox logs to monitor agent activity and diagnose policy decisions. @@ -105,17 +88,21 @@ Use flags to filter and follow output: | `--level` | Filter by severity | `--level warn` | | `--since` | Show logs from a time window | `--since 5m` | -Combine flags to narrow in on what you need: +## Monitor your Sandbox + +NemoClaw Terminal is a real-time dashboard that combines sandbox status and live logs in a single view. ```console -$ nemoclaw logs my-sandbox --tail --source sandbox --level warn --since 5m +$ nemoclaw term ``` -:::{tip} -For a real-time dashboard that combines sandbox status and logs in one view, -run `nemoclaw term`. Refer to {doc}`terminal` for details on reading log entries and -diagnosing blocked connections. -::: +The dashboard shows: + +- **Sandbox status** — name, phase, image, attached providers, age, and active port forwards. +- **Live log stream** — outbound connections, policy decisions, and inference interceptions as they happen. Logs are labeled by source: `sandbox` (proxy and policy events) or `gateway` (lifecycle events). + +Use the terminal to spot blocked connections (`action=deny` entries) and inference interceptions (`action=inspect_for_inference` entries). If a connection is blocked unexpectedly, add the host to your network policy — refer to {doc}`../safety-and-privacy/policies` for the workflow. + ## Transfer Files @@ -138,39 +125,6 @@ You can also upload files at creation time with the `--upload` flag on `nemoclaw sandbox create`. ::: -## Port Forwarding - -Forward a port from the sandbox to your host machine. This runs in the -foreground by default: - -```console -$ nemoclaw forward start 8080 my-sandbox -``` - -Add `-d` to run the forward in the background: - -```console -$ nemoclaw forward start 8080 my-sandbox -d -``` - -List active port forwards: - -```console -$ nemoclaw forward list -``` - -Stop a port forward: - -```console -$ nemoclaw forward stop 8080 my-sandbox -``` - -:::{note} -You can set up port forwarding at creation time with the `--forward` flag on -`nemoclaw sandbox create`, which is convenient when you know upfront that -your workload exposes a service. -::: - ## Delete Sandboxes Remove sandboxes when they are no longer needed. Deleting a sandbox stops all processes, releases cluster resources, and purges injected credentials. @@ -181,15 +135,8 @@ Delete a sandbox by name: $ nemoclaw sandbox delete my-sandbox ``` -You can delete multiple sandboxes in a single command: - -```console -$ nemoclaw sandbox delete sandbox-a sandbox-b sandbox-c -``` - ## Next Steps - {doc}`community-sandboxes`: Use pre-built sandboxes from the community catalog - {doc}`providers`: Create and attach credential providers -- {doc}`custom-containers`: Build and run your own container image - {doc}`../safety-and-privacy/policies`: Control what the agent can access \ No newline at end of file diff --git a/docs/sandboxes/custom-containers.md b/docs/sandboxes/custom-containers.md deleted file mode 100644 index 6eb1583a15..0000000000 --- a/docs/sandboxes/custom-containers.md +++ /dev/null @@ -1,80 +0,0 @@ - - -# Custom Containers - -Build a custom container image and run it as a OpenShell sandbox. - -## Prerequisites - -Ensure the following are installed before building custom container sandboxes. - -- OpenShell CLI installed (`pip install nemoclaw`) -- Docker running on your machine -- A Dockerfile for your workload - -## Step 1: Create a Sandbox from Your Dockerfile - -Point `--from` at the directory containing your Dockerfile: - -```console -$ nemoclaw sandbox create --from ./my-app --keep --name my-app -``` - -The CLI builds the image locally using Docker, pushes it into the cluster, and -creates the sandbox, all in one step. No external container registry is -needed. - -You can also pass a full container image reference if the image is already -built: - -```console -$ nemoclaw sandbox create --from my-registry.example.com/my-image:latest --keep --name my-app -``` - -## Step 2: Forward Ports - -If your container runs a service, forward the port to your host: - -```console -$ nemoclaw forward start 8080 my-app -d -``` - -The `-d` flag runs the forward in the background so you can continue using -your terminal. - -## Step 3: Iterate - -When you change your Dockerfile, delete the sandbox and recreate: - -```console -$ nemoclaw sandbox delete my-app && \ - nemoclaw sandbox create --from ./my-app --keep --name my-app -``` - -## Shortcut: Create with Forwarding and a Startup Command - -You can combine port forwarding and a startup command in a single step: - -```console -$ nemoclaw sandbox create --from ./my-app --forward 8080 --keep -- ./start-server.sh -``` - -This creates the sandbox, sets up port forwarding on port 8080, and runs -`./start-server.sh` as the sandbox command. - -:::{warning} -NemoClaw does not support distroless and `FROM scratch` images. The -supervisor requires glibc, `/proc`, and a shell to operate. Images missing -`iproute2` or required Linux capabilities will fail to start in proxy mode. -Ensure your base image includes these dependencies. -::: - -## Next Steps - -- {doc}`create-and-manage`: Full sandbox lifecycle commands -- {doc}`providers`: Attach credentials to your custom container -- {doc}`/safety-and-privacy/policies`: Write a policy tailored to your workload -- {doc}`/safety-and-privacy/security-model`: Understand the isolation layers applied to custom images \ No newline at end of file diff --git a/docs/sandboxes/index.md b/docs/sandboxes/index.md index 18a20d331c..1cf23a1058 100644 --- a/docs/sandboxes/index.md +++ b/docs/sandboxes/index.md @@ -26,20 +26,7 @@ inside a Docker container on your machine. You do not need to set this up manually. The first time you run a command that needs a cluster (such as `nemoclaw sandbox create`), the CLI provisions -one automatically. This is the "Runtime ready" line you see in the output. -Subsequent commands reuse the existing cluster. - -For teams or when you need more resources, you can deploy the cluster to a -remote host instead of your local machine: - -```console -$ nemoclaw gateway start --remote user@host -``` - -Refer to [Remote Deployment](../about/architecture.md) for -details. If you have multiple clusters (local and remote), switch between them -with `nemoclaw gateway select `. Refer to the -[CLI Reference](../reference/cli.md#gateway-commands) for the full command set. +one automatically. ## Next Steps @@ -47,9 +34,5 @@ with `nemoclaw gateway select `. Refer to the sandboxes. - {doc}`providers`: Create and attach credential providers so agents can authenticate with external services. -- {doc}`custom-containers`: Build and run your own container image inside a - sandbox. - {doc}`community-sandboxes`: Use pre-built sandboxes from the community catalog. -- {doc}`terminal`: Monitor sandbox status and live activity in a terminal - dashboard. diff --git a/docs/sandboxes/providers.md b/docs/sandboxes/providers.md index 1dc7d26f8d..4427ae5b79 100644 --- a/docs/sandboxes/providers.md +++ b/docs/sandboxes/providers.md @@ -102,42 +102,6 @@ $ nemoclaw sandbox create -- claude This detects `claude` as a known tool, finds your `ANTHROPIC_API_KEY`, creates a provider, attaches it to the sandbox, and launches Claude Code. -## How Credentials Flow - -Credentials follow a secure path from your machine into the agent process. - -```{mermaid} -flowchart LR - A["You create a provider"] --> B["Attach provider\nto sandbox at creation"] - B --> C["Sandbox starts"] - C --> D["Supervisor fetches\ncredentials from gateway"] - D --> E["Credentials injected into\nagent process + SSH sessions"] - - style A fill:#ffffff,stroke:#000000,color:#000000 - style B fill:#ffffff,stroke:#000000,color:#000000 - style C fill:#76b900,stroke:#000000,color:#000000 - style D fill:#76b900,stroke:#000000,color:#000000 - style E fill:#76b900,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -1. You create a provider with credentials from your environment or - specified explicitly. -2. You attach the provider to a sandbox at creation time using the - `--provider` flag (one or more providers can be attached). -3. The sandbox starts. The supervisor process initializes. -4. The supervisor fetches credentials from the OpenShell gateway at runtime. - The system does not store credentials in the sandbox specification. It retrieves them on demand. -5. Credentials are injected into the agent process as environment variables. - They are also available in SSH sessions when you connect to the sandbox. - -:::{warning} -The system does not store credentials in the sandbox container specification. The supervisor fetches them at runtime and holds them only in process memory. This -means you cannot find credentials in container inspection, image layers, or -environment dumps of the container spec. -::: - ## Supported Provider Types The following provider types are supported. @@ -161,5 +125,4 @@ environment variable names and values yourself with `--credential`. ## Next Steps - {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`custom-containers`: Use providers with custom container images - {doc}`../safety-and-privacy/security-model`: Why credential isolation matters \ No newline at end of file diff --git a/docs/sandboxes/terminal.md b/docs/sandboxes/terminal.md deleted file mode 100644 index 43888e767a..0000000000 --- a/docs/sandboxes/terminal.md +++ /dev/null @@ -1,110 +0,0 @@ - - -# Terminal - -NemoClaw Terminal is a terminal dashboard that displays sandbox status and live activity in a single view. Use it to monitor agent behavior, diagnose blocked connections, and observe inference interception in real time. - -```console -$ nemoclaw term -``` - -## Sandbox Status - -The status pane at the top of the dashboard displays the following sandbox metadata: - -- Name and phase (`Provisioning`, `Ready`, `Error`) -- Image running in the sandbox -- Providers attached and their available credentials -- Age since creation -- Port forwards currently active - -A phase other than `Ready` indicates the sandbox is still initializing or has encountered an error. Inspect the logs pane for details. - -## Live Log Stream - -The logs pane streams activity in real time. Outbound connections, policy decisions, and inference interceptions appear as they occur. - -Log entries originate from two sources: - -- sandbox: The sandbox supervisor (proxy decisions, policy enforcement, SSH connections, process lifecycle). -- gateway: The control plane (sandbox creation, phase changes, policy distribution). - -Press `f` to enable follow mode and auto-scroll to new entries. - -## Diagnosing Blocked Connections - -Entries with `action=deny` indicate connections blocked by policy: - -``` -22:35:19 sandbox INFO CONNECT action=deny dst_host=registry.npmjs.org dst_port=443 -``` - -Each deny entry contains the following fields: - -| Field | Description | -|---|---| -| `action=deny` | Connection was blocked by the network policy. | -| `dst_host` | Destination host the process attempted to reach. | -| `dst_port` | Destination port (typically 443 for HTTPS). | -| `src_addr` | Source address inside the sandbox. | -| `policy` | Policy rule that was evaluated, or `-` if no rule matched. | - -To resolve a blocked connection: - -1. Add the host to the network policy if the connection is legitimate. Refer to {doc}`../safety-and-privacy/policies` for the iteration workflow. -2. Leave it blocked if the connection is unauthorized. - -## Diagnosing Inference Interception - -Entries with `action=inspect_for_inference` indicate intercepted API calls: - -``` -22:35:37 sandbox INFO CONNECT action=inspect_for_inference dst_host=integrate.api.nvidia.com dst_port=443 -22:35:37 sandbox INFO Intercepted inference request, routing locally kind=chat_completion -``` - -This sequence indicates: - -- No network policy matched the connection (the endpoint and binary combination is not in the policy). -- Inference routing is configured (`allowed_routes` is non-empty), so the proxy intercepted the call instead of denying it. -- The proxy TLS-terminated the connection, detected an inference API pattern, and routed the request through the privacy router. - -:::{note} -If these calls should go directly to the destination rather than through inference routing, the most likely cause is a binary path mismatch. The process making the HTTP call does not match any binary listed in the network policy. - -Check the log entry for the binary path, then update the `binaries` list in the policy. Refer to {doc}`../safety-and-privacy/network-access-rules` for details on binary matching. -::: - -## Filtering and Navigation - -The dashboard provides filtering and navigation controls: - -- Press `s` to filter logs by source. Display only `sandbox` logs (policy decisions) or only `gateway` logs (lifecycle events). -- Press `f` to toggle follow mode. Auto-scroll to the latest entries. -- Press `Enter` on a log entry to open the detail view with the full message. -- Use `j` / `k` to navigate up and down the log list. - -## Keyboard Shortcuts - -The following keyboard shortcuts are available in the terminal dashboard. - -| Key | Action | -|---|---| -| `j` / `k` | Navigate down / up in the log list. | -| `Enter` | Open detail view for the selected entry. | -| `g` / `G` | Jump to top / bottom. | -| `f` | Toggle follow mode (auto-scroll to new entries). | -| `s` | Open source filter (sandbox, gateway, or all). | -| `Esc` | Return to the main view / close detail view. | -| `q` | Quit. | - -## Related Topics - -For deeper dives into topics covered by the terminal dashboard, refer to the following guides. - -- Blocked connections: Follow {doc}`../safety-and-privacy/policies` to pull the current policy, add the missing endpoint, and push an update without restarting the sandbox. -- Inference interception: Refer to {doc}`../safety-and-privacy/network-access-rules` for the distinction between agent traffic (routed directly) and userland traffic (routed through inference routing). -- Troubleshooting: Refer to {doc}`../troubleshooting` for troubleshooting tips and diagnostics. From 19322d1b1a08c2a7102225c8a5d9318e3679f33e Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 16:44:48 -0700 Subject: [PATCH 03/20] Fixed build --- docs/get-started/run-claude.md | 2 +- docs/get-started/run-opencode.md | 2 +- docs/index.md | 3 --- docs/inference/configure-routes.md | 4 ++-- docs/inference/index.md | 4 ++-- docs/reference/architecture.md | 3 +-- docs/reference/cli.md | 3 +-- 7 files changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/get-started/run-claude.md b/docs/get-started/run-claude.md index d09a237100..3abd231d36 100644 --- a/docs/get-started/run-claude.md +++ b/docs/get-started/run-claude.md @@ -116,4 +116,4 @@ This is useful when you plan to reconnect later or iterate on the policy while t - {doc}`../sandboxes/create-and-manage`: Learn the isolation model and sandbox lifecycle. - {doc}`../sandboxes/providers`: Understand how credentials are injected without exposing them to agent code. - {doc}`../safety-and-privacy/policies`: Customize the default policy or write your own. -- {doc}`../safety-and-privacy/network-access-rules`: Explore the network proxy and per-endpoint rules. +- {doc}`../safety-and-privacy/policies`: Explore network policies and per-endpoint rules. diff --git a/docs/get-started/run-opencode.md b/docs/get-started/run-opencode.md index 00a85bb9a8..e088ee4aa5 100644 --- a/docs/get-started/run-opencode.md +++ b/docs/get-started/run-opencode.md @@ -252,7 +252,7 @@ $ nemoclaw sandbox delete opencode-sandbox ## Next Steps - {doc}`../safety-and-privacy/policies`: Full reference on policy YAML structure, static and dynamic fields, and enforcement modes. -- {doc}`../safety-and-privacy/network-access-rules`: How the proxy evaluates network rules, L4 and L7 inspection, and TLS termination. +- {doc}`../safety-and-privacy/policies`: How the proxy evaluates network rules and policy enforcement. - {doc}`../inference/index`: Inference route configuration, protocol detection, and transparent rerouting. - {doc}`../sandboxes/providers`: Provider types, credential discovery, and manual and automatic creation. - {doc}`../safety-and-privacy/security-model`: The four protection layers and how they interact. diff --git a/docs/index.md b/docs/index.md index 7c9584fdf1..bb094a90db 100644 --- a/docs/index.md +++ b/docs/index.md @@ -204,9 +204,7 @@ get-started/tutorials sandboxes/index sandboxes/create-and-manage sandboxes/providers -sandboxes/custom-containers sandboxes/community-sandboxes -sandboxes/terminal ``` ```{toctree} @@ -216,7 +214,6 @@ sandboxes/terminal safety-and-privacy/index safety-and-privacy/security-model safety-and-privacy/policies -safety-and-privacy/network-access-rules ``` ```{toctree} diff --git a/docs/inference/configure-routes.md b/docs/inference/configure-routes.md index 347b8dd559..1b487743ba 100644 --- a/docs/inference/configure-routes.md +++ b/docs/inference/configure-routes.md @@ -8,7 +8,7 @@ This guide covers how to create and manage inference routes so that sandboxes can route AI API calls from userland code to policy-controlled backends. You will learn to create routes, connect them to sandboxes through policy, and manage routes across a cluster. :::{note} -Inference routes are for *user code*, which are scripts and programs that the agent writes and executes inside the sandbox. The agent's own API traffic flows directly through network policies, not through inference routing. Refer to {doc}`../safety-and-privacy/network-access-rules` for the distinction between agent traffic and user traffic. +Inference routes are for *user code*, which are scripts and programs that the agent writes and executes inside the sandbox. The agent's own API traffic flows directly through network policies, not through inference routing. Refer to {doc}`../safety-and-privacy/policies` for the distinction between agent traffic and user traffic. ::: ## Create a Route @@ -88,5 +88,5 @@ The `inference` section is a dynamic field, so you can add or remove routing hin ## Next Steps - {doc}`index`: understand the inference routing architecture, interception sequence, and routing hints. -- {doc}`../safety-and-privacy/network-access-rules`: configure the network policies that control agent traffic (as opposed to userland inference traffic). +- {doc}`../safety-and-privacy/policies`: configure the network policies that control agent traffic (as opposed to userland inference traffic). - {doc}`../safety-and-privacy/policies`: the full policy iteration workflow. diff --git a/docs/inference/index.md b/docs/inference/index.md index 67f47a308f..9e4cbd61dc 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -13,7 +13,7 @@ to backends you control. Inference routing applies to userland traffic: code that the agent writes or runs, not the agent itself. The agent's own API calls (for example, Claude calling `api.anthropic.com`) go directly through network policy. Refer to -{doc}`/safety-and-privacy/network-access-rules` for the distinction. +{doc}`/safety-and-privacy/policies` for the distinction. ::: ## How It Works @@ -79,5 +79,5 @@ If an intercepted request does not match any known pattern, it is denied. ## Next Steps - {doc}`configure-routes`: Create and manage inference routes. -- {doc}`/safety-and-privacy/network-access-rules`: Understand agent traffic versus +- {doc}`/safety-and-privacy/policies`: Understand agent traffic versus userland traffic and how network rules interact with inference routing. diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md index d36af1d060..2376ec9323 100644 --- a/docs/reference/architecture.md +++ b/docs/reference/architecture.md @@ -136,8 +136,7 @@ the proxy. For each connection, the proxy: binary path. 3. Acts on the decision: allow the connection directly, hand it to the privacy router for inference routing, or deny it. Refer to - [How the Proxy Evaluates Connections](../safety-and-privacy/network-access-rules.md#how-the-proxy-evaluates-connections) - for the full decision model. + {doc}`../safety-and-privacy/policies` for the full decision model. For endpoints configured with `protocol: rest` and `tls: terminate`, the proxy performs full L7 inspection: it decrypts TLS, reads the HTTP method and path, diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 9856ee5f47..d5e9a0af5d 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -159,8 +159,7 @@ Manage inference routes that intercept and reroute LLM API calls from userland c status, live logs, and policy decisions in a single view. Navigate with `j`/`k`, press `f` to follow live output, `s` to filter by source, and `q` to quit. -Refer to {doc}`/sandboxes/terminal` for the full guide, including how to read log -entries, diagnose blocked connections, and interpret inference interception. +Refer to {doc}`/sandboxes/create-and-manage` for more on monitoring sandboxes and reading log entries. ## Sandbox Name Fallback From 8341bd6bf657d90a41f3430d86ddcf877b6e363d Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Mon, 9 Mar 2026 19:55:54 -0700 Subject: [PATCH 04/20] docs(inference): clarify local inference routing --- docs/get-started/run-opencode.md | 53 ++++++------ docs/index.md | 2 +- docs/inference/configure-routes.md | 92 --------------------- docs/inference/configure.md | 100 +++++++++++++++++++++++ docs/inference/index.md | 127 +++++++++++++++-------------- docs/reference/cli.md | 38 +++++---- docs/reference/policy-schema.md | 23 +----- 7 files changed, 213 insertions(+), 222 deletions(-) delete mode 100644 docs/inference/configure-routes.md create mode 100644 docs/inference/configure.md diff --git a/docs/get-started/run-opencode.md b/docs/get-started/run-opencode.md index e088ee4aa5..731166e362 100644 --- a/docs/get-started/run-opencode.md +++ b/docs/get-started/run-opencode.md @@ -5,15 +5,15 @@ # Run OpenCode with NVIDIA Inference -This tutorial walks you through a realistic setup where you run [OpenCode](https://opencode.ai) inside a OpenShell sandbox with inference routed to NVIDIA API endpoints. Along the way, you will hit a policy denial, diagnose it from logs, write a custom policy, and configure inference routing. This is the full policy iteration loop that you will use whenever you onboard a new tool. +This tutorial walks you through a realistic setup where you run [OpenCode](https://opencode.ai) inside an OpenShell sandbox and configure private inference through `inference.local`. Along the way, you will hit a policy denial, diagnose it from logs, write a custom policy, and configure inference routing. This is the full policy iteration loop that you will use whenever you onboard a new tool. ## What You Will Learn - Create a provider manually using the `--from-existing` flag. - Write a custom policy to replace the default policy. - Read sandbox logs to diagnose denied actions. -- Distinguish between agent traffic and userland inference. -- Set up inference routes for code running inside the sandbox. +- Distinguish between agent traffic and sandbox inference traffic. +- Configure inference routing for code running inside the sandbox. ## Prerequisites @@ -22,7 +22,7 @@ This tutorial walks you through a realistic setup where you run [OpenCode](https ## Create the Provider -In the Claude Code tutorial, the CLI auto-discovered credentials. Here you create a provider explicitly, which gives you control over the provider name and type. +In the Claude Code tutorial, the CLI auto-discovers credentials. Here you create a provider explicitly, which gives you control over the provider name and type. ```console $ nemoclaw provider create --name nvidia --type nvidia --from-existing @@ -64,17 +64,16 @@ $ nemoclaw term Look for lines like these: -``` +```text action=deny host=integrate.api.nvidia.com binary=/usr/local/bin/opencode reason="no matching network policy" action=deny host=opencode.ai binary=/usr/bin/node reason="no matching network policy" -action=inspect_for_inference host=integrate.api.nvidia.com binary=/bin/bash ``` Each log entry tells you the exact host, binary, and reason for the denial. ## Understand the Denial -The default policy contains a `nvidia_inference` network policy entry, but it is configured for a narrow set of binaries — typically `/usr/local/bin/claude` and `/usr/bin/node`. When OpenCode makes HTTP calls through its own binary, `curl`, or a shell subprocess, those connections do not match any policy rule and get denied. +The default policy contains a `nvidia_inference` network policy entry, but it is configured for a narrow set of binaries - typically `/usr/local/bin/claude` and `/usr/bin/node`. When OpenCode makes HTTP calls through its own binary, `curl`, or a shell subprocess, those connections do not match any policy rule and get denied. Two separate problems are at play: @@ -89,9 +88,6 @@ Create a file called `opencode-policy.yaml` with the following content: ```yaml version: 1 -inference: - allowed_routes: - - nvidia filesystem_policy: include_workdir: true read_only: @@ -180,15 +176,14 @@ network_policies: - path: /usr/bin/git ``` -This policy differs from the default in four key ways: +This policy differs from the default in three key ways: - `opencode_api`: Allows OpenCode and Node.js to reach `opencode.ai:443`. - Broader `nvidia_inference` binaries: Adds `/usr/local/bin/opencode`, `/usr/bin/curl`, and `/bin/bash` so OpenCode's subprocesses can reach the NVIDIA endpoint. -- `inference.allowed_routes`: Includes `nvidia` so inference routing works for userland code. - GitHub access: Scoped to support OpenCode's git operations. :::{warning} -The `filesystem_policy`, `landlock`, and `process` sections are static. They are set at sandbox creation time and cannot be changed on a running sandbox. To modify these, delete and recreate the sandbox. The `network_policies` and `inference` sections are dynamic and can be hot-reloaded. +The `filesystem_policy`, `landlock`, and `process` sections are static. They are set at sandbox creation time and cannot be changed on a running sandbox. To modify these, delete and recreate the sandbox. The `network_policies` section is dynamic and can be hot-reloaded. ::: ## Apply the Policy @@ -209,24 +204,26 @@ $ nemoclaw policy list opencode-sandbox The latest revision should show status `loaded`. -## Set Up Inference Routing +## Configure Inference Routing -So far, you have allowed the OpenCode *agent* to reach `integrate.api.nvidia.com` directly through network policy. But code that OpenCode writes and runs inside the sandbox — scripts, notebooks, applications — uses a separate mechanism called the privacy router. +So far, you have allowed the OpenCode *agent* to reach `integrate.api.nvidia.com` directly through network policy. But code that OpenCode writes and runs inside the sandbox should use `https://inference.local`. -Create an inference route so userland code can access NVIDIA models: +Configure inference so `inference.local` routes to your NVIDIA provider: ```console -$ nemoclaw inference create \ - --routing-hint nvidia \ - --base-url https://integrate.api.nvidia.com \ - --model-id z-ai/glm5 \ - --api-key $NVIDIA_API_KEY +$ nemoclaw inference set \ + --provider nvidia \ + --model z-ai/glm5 ``` -The policy you wrote earlier already includes `nvidia` in `inference.allowed_routes`, so no policy update is needed. If you had omitted it, you would add the route to the policy and push again. +Verify the active configuration: + +```console +$ nemoclaw inference get +``` :::{note} -*Network policies* and *inference routes* are two separate enforcement points. Network policies control which hosts the agent binary can reach directly. Inference routes control where LLM API calls from userland code get routed through the privacy proxy. +*Network policies* and managed inference are two separate enforcement points. Network policies control which external hosts the agent binary can reach directly. Inference configuration controls where userland calls to `https://inference.local` are routed. ::: ## Verify the Policy @@ -237,7 +234,9 @@ Tail the logs again: $ nemoclaw logs opencode-sandbox --tail ``` -You should no longer see `action=deny` lines for the endpoints you added. Connections to `opencode.ai`, `integrate.api.nvidia.com`, and GitHub should show `action=allow`. +You should see `action=allow` lines for the endpoints you added. Connections to `opencode.ai`, `integrate.api.nvidia.com`, and GitHub should show `action=allow`. + +To verify userland inference, run code inside the sandbox that targets `https://inference.local/v1`. If you still see denials, read the log line carefully. It tells you the exact host, port, and binary that was blocked. Add the missing entry to your policy and push again with `nemoclaw policy set`. This observe-modify-push cycle is the normal workflow for onboarding any new tool in OpenShell. @@ -252,7 +251,7 @@ $ nemoclaw sandbox delete opencode-sandbox ## Next Steps - {doc}`../safety-and-privacy/policies`: Full reference on policy YAML structure, static and dynamic fields, and enforcement modes. -- {doc}`../safety-and-privacy/policies`: How the proxy evaluates network rules and policy enforcement. -- {doc}`../inference/index`: Inference route configuration, protocol detection, and transparent rerouting. +- {doc}`../safety-and-privacy/policies`: How network policy fits into the sandbox iteration workflow. +- {doc}`../inference/index`: `inference.local`, supported API patterns, and request routing. - {doc}`../sandboxes/providers`: Provider types, credential discovery, and manual and automatic creation. -- {doc}`../safety-and-privacy/security-model`: The four protection layers and how they interact. +- {doc}`../safety-and-privacy/security-model`: The protection layers and how they interact. diff --git a/docs/index.md b/docs/index.md index bb094a90db..1c7d1956e0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -221,7 +221,7 @@ safety-and-privacy/policies :hidden: inference/index -inference/configure-routes +inference/configure ``` ```{toctree} diff --git a/docs/inference/configure-routes.md b/docs/inference/configure-routes.md deleted file mode 100644 index 1b487743ba..0000000000 --- a/docs/inference/configure-routes.md +++ /dev/null @@ -1,92 +0,0 @@ - - -# Configure Inference Routes - -This guide covers how to create and manage inference routes so that sandboxes can route AI API calls from userland code to policy-controlled backends. You will learn to create routes, connect them to sandboxes through policy, and manage routes across a cluster. - -:::{note} -Inference routes are for *user code*, which are scripts and programs that the agent writes and executes inside the sandbox. The agent's own API traffic flows directly through network policies, not through inference routing. Refer to {doc}`../safety-and-privacy/policies` for the distinction between agent traffic and user traffic. -::: - -## Create a Route - -Use `nemoclaw inference create` to register a new inference backend: - -```console -$ nemoclaw inference create \ - --routing-hint local \ - --base-url https://my-llm.example.com \ - --model-id my-model-v1 \ - --api-key sk-abc123 -``` - -This creates a route named after the routing hint. Any sandbox whose policy includes `local` in its `inference.allowed_routes` list can use this route. If you omit `--protocol`, the CLI probes the endpoint and auto-detects the supported protocol (refer to [Supported API Patterns](index.md#supported-api-patterns)). Refer to the [CLI Reference](../reference/cli.md#inference-create-flags) for all flags. - -## Manage Routes - -### List all routes - -```console -$ nemoclaw inference list -``` - -### Update a route - -Change any field on an existing route: - -```console -$ nemoclaw inference update --base-url https://new-backend.example.com -``` - -```console -$ nemoclaw inference update --model-id updated-model-v2 --api-key sk-new-key -``` - -### Delete a route - -```console -$ nemoclaw inference delete -``` - -Deleting a route that is referenced by running sandboxes does not interrupt those sandboxes immediately. Future inference requests that would have matched the deleted route will be denied. - -## Connect a Sandbox to Routes - -Inference routes take effect only when a sandbox policy references the route's `routing_hint` in its `inference.allowed_routes` list. - -### Step 1: Add the routing hint to your policy - -```yaml -inference: - allowed_routes: - - local -``` - -### Step 2: Create or update the sandbox with that policy - -```console -$ nemoclaw sandbox create --policy ./my-policy.yaml --keep -- claude -``` - -Or, if the sandbox is already running, push an updated policy: - -```console -$ nemoclaw policy set --policy ./my-policy.yaml --wait -``` - -The `inference` section is a dynamic field, so you can add or remove routing hints on a running sandbox without recreating it. - -## Good to Know - -- Cluster-level: routes are shared across all sandboxes in the cluster, not scoped to one sandbox. -- Per-model: each route maps to one model. Create multiple routes with the same `--routing-hint` but different `--model-id` values to expose multiple models. -- Hot-reloadable: routes can be created, updated, or deleted at any time without restarting sandboxes. - -## Next Steps - -- {doc}`index`: understand the inference routing architecture, interception sequence, and routing hints. -- {doc}`../safety-and-privacy/policies`: configure the network policies that control agent traffic (as opposed to userland inference traffic). -- {doc}`../safety-and-privacy/policies`: the full policy iteration workflow. diff --git a/docs/inference/configure.md b/docs/inference/configure.md new file mode 100644 index 0000000000..b0a6b7e074 --- /dev/null +++ b/docs/inference/configure.md @@ -0,0 +1,100 @@ + + +# Configure Inference Routing + +OpenShell exposes one managed inference backend behind `https://inference.local` +for the active gateway. + +External inference endpoints still go through sandbox `network_policies`. This +page covers the special local inference endpoint only. + +That configuration consists of two values: + +- a provider record name +- a model ID + +## Step 1: Create a Provider + +Create a provider that holds the backend credentials you want OpenShell to use. + +```console +$ nemoclaw provider create --name nvidia-prod --type nvidia --from-existing +``` + +You can also use `openai` or `claude` providers. + +## Step 2: Set Inference Routing + +Point `inference.local` at that provider and choose the model to use: + +```console +$ nemoclaw inference set \ + --provider nvidia-prod \ + --model meta/llama-3.1-8b-instruct +``` + +This sets the managed inference configuration. + +## Step 3: Verify the Active Config + +```console +$ nemoclaw inference get +provider: nvidia-prod +model: meta/llama-3.1-8b-instruct +version: 1 +``` + +## Step 4: Update Part of the Config + +Use `update` when you want to change only one field: + +```console +$ nemoclaw inference update --model meta/llama-3.3-70b-instruct +``` + +Or switch providers without repeating the current model manually: + +```console +$ nemoclaw inference update --provider openai-prod +``` + +## Use It from a Sandbox + +Once inference is configured, userland code inside any sandbox can call +`https://inference.local` directly: + +```python +from openai import OpenAI + +client = OpenAI(base_url="https://inference.local/v1", api_key="dummy") + +response = client.chat.completions.create( + model="anything", + messages=[{"role": "user", "content": "Hello"}], +) +``` + +The client-supplied model is ignored for generation requests. OpenShell +rewrites it to the configured model before forwarding upstream. + +Use this endpoint when inference should stay local to the host for privacy and +security reasons. External providers that should be reached directly belong in +`network_policies` instead. + +## Good to Know + +- Gateway-scoped: every sandbox on the active gateway sees the same + `inference.local` backend. +- HTTPS only: `inference.local` is intercepted only for HTTPS traffic. + +## Next Steps + +- {doc}`index`: understand the interception flow and supported API patterns. +- [Network access rules](/safety-and-privacy/policies.md#network-access-rules): + configure direct access to external inference endpoints. +- {doc}`../sandboxes/providers`: create and manage provider records. +- {doc}`../reference/cli`: see the CLI reference for `nemoclaw inference` + commands. diff --git a/docs/inference/index.md b/docs/inference/index.md index 9e4cbd61dc..017b141a3e 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -5,79 +5,80 @@ # About Inference Routing -The inference routing system keeps your AI inference traffic private by -transparently intercepting API calls from sandboxed agents and rerouting them -to backends you control. - -:::{note} -Inference routing applies to userland traffic: code that the agent writes -or runs, not the agent itself. The agent's own API calls (for example, Claude calling -`api.anthropic.com`) go directly through network policy. Refer to -{doc}`/safety-and-privacy/policies` for the distinction. -::: - -## How It Works - -When userland code inside a sandbox makes an API call (for example, using the OpenAI -or Anthropic SDK), the request flows through the sandbox proxy. If the -destination does not match any explicit network policy but the sandbox has -inference routes configured, the proxy: - -1. TLS-terminates the connection using the sandbox's ephemeral CA. -2. Detects the inference API pattern (for example, `POST /v1/chat/completions`). -3. Strips authorization headers and forwards to a matching backend. -4. Rewrites the authorization with the route's API key and model ID. -5. Returns the response to the agent's code. The agent sees a normal HTTP - response as if it came from the original API. - -The agent's code needs zero changes. Standard OpenAI/Anthropic SDK calls work -transparently. - -```{mermaid} -sequenceDiagram - participant Code as Userland Code - participant Proxy as Sandbox Proxy - participant OPA as Policy Engine - participant Router as Privacy Router - participant Backend as Your Backend - - Code->>Proxy: CONNECT api.openai.com:443 - Proxy->>OPA: evaluate policy - OPA-->>Proxy: InspectForInference - Proxy-->>Code: 200 Connection Established - Proxy->>Proxy: TLS terminate - Code->>Proxy: POST /v1/chat/completions - Proxy->>Router: route to matching backend - Router->>Backend: forwarded request - Backend-->>Router: response - Router-->>Proxy: response - Proxy-->>Code: HTTP 200 OK -``` +OpenShell handles inference in two ways: + +- External inference endpoints are controlled by sandbox `network_policies`. +- Each sandbox also exposes `https://inference.local`, a special endpoint for + inference that should stay local to the host for privacy and security. + +## External Inference + +If sandbox code calls an external inference API like `api.openai.com` or +`api.anthropic.com`, that traffic is treated like any other outbound network +request. It is allowed or denied by `network_policies`. + +Refer to {doc}`/safety-and-privacy/policies` and the +[Network access rules](/safety-and-privacy/policies.md#network-access-rules) +section for details. + +## `inference.local` + +Every sandbox also exposes a special endpoint: `https://inference.local`. + +This endpoint exists so inference can be routed to a model running locally on +the same host. In the future, it can also route to a model managed by the +cluster. It is the special case for inference that should stay local for +privacy and security reasons. + +## Using `inference.local` + +When code inside a sandbox calls `https://inference.local`, OpenShell routes the +request to the configured backend for that gateway. + +The configured model is applied to generation requests, and provider +credentials are supplied by OpenShell rather than by code inside the sandbox. + +If code calls an external inference host directly, that traffic is evaluated +only by `network_policies`. ## Supported API Patterns -The proxy detects these inference patterns: +Supported request patterns depend on the provider configured for +`inference.local`. + +For OpenAI-compatible providers, these patterns are supported: + +| Pattern | Method | Path | +|---|---|---| +| OpenAI Chat Completions | `POST` | `/v1/chat/completions` | +| OpenAI Completions | `POST` | `/v1/completions` | +| OpenAI Responses | `POST` | `/v1/responses` | +| Model Discovery | `GET` | `/v1/models` | +| Model Discovery | `GET` | `/v1/models/*` | + +For Anthropic-compatible providers, this pattern is supported: | Pattern | Method | Path | |---|---|---| -| OpenAI Chat Completions | POST | `/v1/chat/completions` | -| OpenAI Completions | POST | `/v1/completions` | -| Anthropic Messages | POST | `/v1/messages` | +| Anthropic Messages | `POST` | `/v1/messages` | -If an intercepted request does not match any known pattern, it is denied. +Requests to `inference.local` that do not match the configured provider's +supported patterns are denied. ## Key Properties -- Zero code changes: standard SDK calls work transparently. -- Inference privacy: prompts and responses stay on your infrastructure. -- Credential isolation: the agent's code never sees your backend API key. -- Policy-controlled: `inference.allowed_routes` determines which routes a - sandbox can use. -- Hot-reloadable: update `allowed_routes` on a running sandbox without - restarting. +- External endpoints use `network_policies`. +- Explicit local endpoint: special local routing happens through + `inference.local`. +- No sandbox API keys: credentials come from the configured provider record. +- Single managed config: one provider and one model define sandbox inference. +- Provider-agnostic: OpenAI, Anthropic, and NVIDIA providers all work through + the same endpoint. +- Hot-refresh: provider credential changes and inference updates are picked up + without recreating sandboxes. ## Next Steps -- {doc}`configure-routes`: Create and manage inference routes. -- {doc}`/safety-and-privacy/policies`: Understand agent traffic versus - userland traffic and how network rules interact with inference routing. +- {doc}`configure`: configure the backend behind `inference.local`. +- [Network access rules](/safety-and-privacy/policies.md#network-access-rules): + understand how external endpoints are controlled. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index d5e9a0af5d..35e79ed8e8 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -44,10 +44,9 @@ nemoclaw │ ├── update │ └── delete ├── inference -│ ├── create -│ ├── update -│ ├── delete -│ └── list +│ ├── set +│ ├── update +│ └── get ├── term └── completions ``` @@ -133,25 +132,30 @@ Manage credential providers that inject secrets into sandboxes. ## Inference Commands -Manage inference routes that intercept and reroute LLM API calls from userland code. +Configure the backend used by `https://inference.local`. -| Command | Description | +### `nemoclaw inference set` + +Set the provider and model for managed inference. Both flags are required. + +| Flag | Description | |---|---| -| `nemoclaw inference create` | Create a new inference route. See flag reference below. | -| `nemoclaw inference update ` | Update an existing route's configuration. | -| `nemoclaw inference delete ` | Delete an inference route. | -| `nemoclaw inference list` | List all inference routes in the active cluster. | +| `--provider` | Provider record name to use for injected credentials. | +| `--model` | Model identifier to force on generation requests. | + +### `nemoclaw inference update` -### Inference Create Flags +Update only the fields you specify. | Flag | Description | |---|---| -| `--routing-hint` | Short label that identifies this route (for example, `local`, `nvidia`, `staging`). Referenced by `allowed_routes` in sandbox policies. | -| `--base-url` | Base URL of the inference backend (for example, `https://vllm.internal:8000`). | -| `--model-id` | Model identifier to send to the backend (for example, `meta/llama-3.1-8b`). | -| `--api-key` | API key for authenticating with the backend. | -| `--protocol` | API protocol: `openai` or `anthropic`. Defaults to `openai`. | -| `--disabled` | Create the route in a disabled state. | +| `--provider` | Replace the current provider record. | +| `--model` | Replace the current model ID. | + +### `nemoclaw inference get` + +Show the current inference configuration, including provider, model, and +version. ## OpenShell Terminal diff --git a/docs/reference/policy-schema.md b/docs/reference/policy-schema.md index 033d1b091d..5f626a87af 100644 --- a/docs/reference/policy-schema.md +++ b/docs/reference/policy-schema.md @@ -15,7 +15,6 @@ filesystem_policy: { ... } landlock: { ... } process: { ... } network_policies: { ... } -inference: { ... } ``` | Field | Type | Required | Category | Description | @@ -25,7 +24,6 @@ inference: { ... } | `landlock` | object | No | Static | Configures Landlock LSM enforcement behavior. | | `process` | object | No | Static | Sets the user and group the agent process runs as. | | `network_policies` | map | No | Dynamic | Declares which binaries can reach which network endpoints. | -| `inference` | object | No | Dynamic | Controls which inference routing backends are available. | Static fields are set at sandbox creation time. Changing them requires destroying and recreating the sandbox. Dynamic fields can be updated on a running sandbox with `nemoclaw policy set` and take effect without restarting. @@ -137,7 +135,7 @@ Each endpoint defines a reachable destination and optional inspection rules. | `protocol` | string | No | Set to `rest` to enable L7 (HTTP) inspection. Omit for L4-only (TCP passthrough). | | `tls` | string | No | TLS handling mode. `terminate` decrypts TLS at the proxy for inspection. `passthrough` forwards encrypted traffic without inspection. Only relevant when `protocol` is `rest`. | | `enforcement` | string | No | `enforce` actively blocks disallowed requests. `audit` logs violations but allows traffic through. | -| `access` | string | No | HTTP access level. One of `read-only`, `read-write`, or `full`. Refer to table below. Mutually exclusive with `rules`. | +| `access` | string | No | HTTP access level. One of `read-only`, `read-write`, or `full`. Mutually exclusive with `rules`. | | `rules` | list of rule objects | No | Fine-grained per-method, per-path allow rules. Mutually exclusive with `access`. | #### Access Levels @@ -203,22 +201,3 @@ network_policies: - path: /usr/bin/npm - path: /usr/bin/node ``` - -## Inference - -**Category:** Dynamic - -Controls which inference routing backends userland code can access. The `allowed_routes` list names route types that the privacy router will accept. Traffic matching an inference API pattern that targets a route type not in this list is denied. - -| Field | Type | Required | Description | -|---|---|---|---| -| `allowed_routes` | list of strings | No | Routing hint labels (e.g., `local`, `nvidia`, `staging`) that this sandbox can use. Must match the `routing_hint` of inference routes created with `nemoclaw inference create`. | - -Example: - -```yaml -inference: - allowed_routes: - - local - - nvidia -``` From e03cbbadb36edbe1404f7b23910d9798883679e0 Mon Sep 17 00:00:00 2001 From: Piotr Mlocek Date: Mon, 9 Mar 2026 20:03:59 -0700 Subject: [PATCH 05/20] docs(inference): update provider and model examples --- docs/inference/configure.md | 8 ++++---- examples/local-inference/README.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/inference/configure.md b/docs/inference/configure.md index b0a6b7e074..ad437be01c 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -24,7 +24,7 @@ Create a provider that holds the backend credentials you want OpenShell to use. $ nemoclaw provider create --name nvidia-prod --type nvidia --from-existing ``` -You can also use `openai` or `claude` providers. +You can also use `openai` or `anthropic` providers. ## Step 2: Set Inference Routing @@ -33,7 +33,7 @@ Point `inference.local` at that provider and choose the model to use: ```console $ nemoclaw inference set \ --provider nvidia-prod \ - --model meta/llama-3.1-8b-instruct + --model nvidia/nemotron-3-nano-30b-a3b ``` This sets the managed inference configuration. @@ -43,7 +43,7 @@ This sets the managed inference configuration. ```console $ nemoclaw inference get provider: nvidia-prod -model: meta/llama-3.1-8b-instruct +model: nvidia/nemotron-3-nano-30b-a3b version: 1 ``` @@ -52,7 +52,7 @@ version: 1 Use `update` when you want to change only one field: ```console -$ nemoclaw inference update --model meta/llama-3.3-70b-instruct +$ nemoclaw inference update --model nvidia/nemotron-3-nano-30b-a3b ``` Or switch providers without repeating the current model manually: diff --git a/examples/local-inference/README.md b/examples/local-inference/README.md index 814b4ae659..0a05ed603d 100644 --- a/examples/local-inference/README.md +++ b/examples/local-inference/README.md @@ -68,7 +68,7 @@ Then configure the cluster-managed `inference.local` route: # Example: use an existing provider record nemoclaw cluster inference set \ --provider openai-prod \ - --model gpt-4o-mini + --model nvidia/nemotron-3-nano-30b-a3b ``` Verify the active config: From db09c3e479a92213fbae9baf3662a56638e8730a Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 20:50:43 -0700 Subject: [PATCH 06/20] docs: add Docker prerequisite warning for connection-refused error Made-with: Cursor --- docs/sandboxes/create-and-manage.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/sandboxes/create-and-manage.md b/docs/sandboxes/create-and-manage.md index cb0db002d8..885a74245f 100644 --- a/docs/sandboxes/create-and-manage.md +++ b/docs/sandboxes/create-and-manage.md @@ -9,11 +9,17 @@ This page walks you through the full sandbox lifecycle: creating, inspecting, co ## Prerequisites -Ensure the following are installed before creating sandboxes. +Ensure the following are ready before creating sandboxes. - OpenShell CLI installed (`pip install nemoclaw`) - Docker running on your machine +:::{warning} +Docker must be running before you create a sandbox. If it isn't, the CLI +returns a connection-refused error (`os error 61`) without explaining +the cause. Start Docker and try again. +::: + ## Create a Sandbox ```console From 325fc631a0fbf2abf09654e425df7785d8a9f00a Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 21:47:19 -0700 Subject: [PATCH 07/20] Minor edits to quickstart safety and privacy --- docs/get-started/quickstart.md | 19 +-- docs/get-started/run-claude.md | 4 +- docs/get-started/run-opencode.md | 2 +- docs/inference/configure.md | 2 +- docs/inference/index.md | 4 +- docs/safety-and-privacy/index.md | 4 +- docs/safety-and-privacy/policies.md | 220 ++++++++++++++++------------ 7 files changed, 132 insertions(+), 123 deletions(-) diff --git a/docs/get-started/quickstart.md b/docs/get-started/quickstart.md index ce4c907f50..4fa85d89cb 100644 --- a/docs/get-started/quickstart.md +++ b/docs/get-started/quickstart.md @@ -67,26 +67,9 @@ The `--from` flag pulls a pre-built sandbox definition from the [NemoClaw Commun :::: -## What Happens Behind the Scenes - -When you create a sandbox, OpenShell activates the following protection layers. - -| Protection Layer | Description | -|------------------------|-----------------------------------------------------------------------------------------------| -| Filesystem isolation | The agent can only read and write paths that the policy explicitly permits. | -| Network enforcement | Outbound connections are denied by default. The policy allowlists specific hosts, ports, and binaries. | -| Process restrictions | The agent runs as a non-root user inside the container. | -| Inference privacy | LLM API traffic is routed through a privacy-aware proxy. Credentials never leak outside the sandbox. | - -A single YAML policy file controls all four layers. You can hot-reload network and inference rules on a running sandbox without restarting it. - -:::{note} -For OpenCode or Codex, the default policy does not cover the required endpoints. Follow the [Run OpenCode with NVIDIA Inference](run-opencode.md) tutorial for agent-specific setup. -::: - ## Next Steps -You now have a working sandbox. From here, you can: +You now have a working sandbox! From here, you can: - Follow the [Tutorials](tutorials.md) for step-by-step walkthroughs with Claude Code, OpenClaw, and OpenCode. - Learn how sandboxes work in [Sandboxes](../sandboxes/create-and-manage.md). diff --git a/docs/get-started/run-claude.md b/docs/get-started/run-claude.md index 6d217d8ac8..8559a1b9b4 100644 --- a/docs/get-started/run-claude.md +++ b/docs/get-started/run-claude.md @@ -115,5 +115,5 @@ This is useful when you plan to reconnect later or iterate on the policy while t - {doc}`../sandboxes/create-and-manage`: Learn the isolation model and sandbox lifecycle. - {doc}`../sandboxes/providers`: Understand how credentials are injected without exposing them to agent code. -- {doc}`../safety-and-privacy/default-policies`: What the built-in default policy allows and denies. -- {doc}`../safety-and-privacy/policies`: Write custom policies and configure network rules. +- {doc}`../safety-and-privacy/policies`: Customize the default policy or write your own. +- {doc}`../safety-and-privacy/default-policies`: Explore the built-in default policy and agent compatibility. diff --git a/docs/get-started/run-opencode.md b/docs/get-started/run-opencode.md index 731166e362..1604700e71 100644 --- a/docs/get-started/run-opencode.md +++ b/docs/get-started/run-opencode.md @@ -254,4 +254,4 @@ $ nemoclaw sandbox delete opencode-sandbox - {doc}`../safety-and-privacy/policies`: How network policy fits into the sandbox iteration workflow. - {doc}`../inference/index`: `inference.local`, supported API patterns, and request routing. - {doc}`../sandboxes/providers`: Provider types, credential discovery, and manual and automatic creation. -- {doc}`../safety-and-privacy/security-model`: The protection layers and how they interact. +- {doc}`../safety-and-privacy/index`: The protection layers and how they interact. diff --git a/docs/inference/configure.md b/docs/inference/configure.md index 32dfd1806d..0971a0aa33 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -93,7 +93,7 @@ security reasons. External providers that should be reached directly belong in ## Next Steps - {doc}`index`: understand the interception flow and supported API patterns. -- [Network policy evaluation](/safety-and-privacy/policies.md#network-policy-evaluation): +- [Network Access Rules](/safety-and-privacy/policies.md#network-access-rules): configure direct access to external inference endpoints. - {doc}`../sandboxes/providers`: create and manage provider records. - {doc}`../reference/cli`: see the CLI reference for `nemoclaw inference` diff --git a/docs/inference/index.md b/docs/inference/index.md index da8abe0858..fe227952bc 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -18,7 +18,7 @@ If sandbox code calls an external inference API like `api.openai.com` or request. It is allowed or denied by `network_policies`. Refer to {doc}`/safety-and-privacy/policies` and the -[Network policy evaluation](/safety-and-privacy/policies.md#network-policy-evaluation) +[Network Access Rules](/safety-and-privacy/policies.md#network-access-rules) section for details. ## `inference.local` @@ -80,5 +80,5 @@ supported patterns are denied. ## Next Steps - {doc}`configure`: configure the backend behind `inference.local`. -- [Network policy evaluation](/safety-and-privacy/policies.md#network-policy-evaluation): +- [Network Access Rules](/safety-and-privacy/policies.md#network-access-rules): understand how external endpoints are controlled. diff --git a/docs/safety-and-privacy/index.md b/docs/safety-and-privacy/index.md index f647b49e52..5be184c0b4 100644 --- a/docs/safety-and-privacy/index.md +++ b/docs/safety-and-privacy/index.md @@ -48,9 +48,9 @@ graph TB linkStyle default stroke:#76b900,stroke-width:2px ``` -## How the Layers Work Together +## Sandbox Policies -You control all four layers through a single YAML policy. +You control all four layers through a single YAML policy — a file you attach when creating a sandbox that declares which paths the agent can access, which hosts it can reach, and how inference calls are routed. | Layer | What It Protects | When It Applies | |---|---|---| diff --git a/docs/safety-and-privacy/policies.md b/docs/safety-and-privacy/policies.md index e491b2f10d..d2a5d64aec 100644 --- a/docs/safety-and-privacy/policies.md +++ b/docs/safety-and-privacy/policies.md @@ -3,13 +3,97 @@ SPDX-License-Identifier: Apache-2.0 --> -# Policy Configuration +# Customize Sandbox Policies -A policy is a single YAML document that controls what a sandbox can do: filesystem access, process identity, network access, and inference routing. You attach it when creating a sandbox; the network and inference sections can be updated on a running sandbox without restarting. +Use this page to apply and iterate policy changes on running sandboxes. For a full field-by-field YAML definition, use the [Policy Schema Reference](../reference/policy-schema.md). + +## Quick Start: Apply a Custom Policy + +Pass a policy YAML file when creating the sandbox: + +```console +$ openshell sandbox create --policy ./my-policy.yaml --keep -- claude +``` + +The `--keep` flag keeps the sandbox running after the initial command exits, which is useful when you plan to iterate on the policy. + +To avoid passing `--policy` every time, set a default policy with an environment variable: + +```console +$ export OPENSHELL_SANDBOX_POLICY=./my-policy.yaml +$ openshell sandbox create --keep -- claude +``` + +The CLI uses the policy from `OPENSHELL_SANDBOX_POLICY` whenever `--policy` is not explicitly provided. + +## Iterate on a Running Sandbox + +To change what the sandbox can access, pull the current policy, edit the YAML, and push the update. The workflow is iterative: create the sandbox, monitor logs for denied actions, pull the policy, modify it, push, and verify. + +```{mermaid} +flowchart TD + A["1. Create sandbox with initial policy"] --> B["2. Monitor logs for denied actions"] + B --> C["3. Pull current policy"] + C --> D["4. Modify the policy YAML"] + D --> E["5. Push updated policy"] + E --> F["6. Verify the new revision loaded"] + F --> B + + style A fill:#76b900,stroke:#000000,color:#000000 + style B fill:#76b900,stroke:#000000,color:#000000 + style C fill:#76b900,stroke:#000000,color:#000000 + style D fill:#ffffff,stroke:#000000,color:#000000 + style E fill:#76b900,stroke:#000000,color:#000000 + style F fill:#76b900,stroke:#000000,color:#000000 + + linkStyle default stroke:#76b900,stroke-width:2px +``` + +The following steps outline the hot-reload policy update workflow. + +1. Create the sandbox with your initial policy by following [Quick Start: Apply a Custom Policy](#quick-start-apply-a-custom-policy) above (or set `OPENSHELL_SANDBOX_POLICY`). + +2. Monitor denials — each log entry shows host, port, binary, and reason. Alternatively use `openshell term` for a live dashboard. + + ```console + $ openshell logs --tail --source sandbox + ``` + +3. Pull the current policy. Strip the metadata header (Version, Hash, Status) before reusing the file. + + ```console + $ openshell policy get --full > current-policy.yaml + ``` + +4. Edit the YAML: add or adjust `network_policies` entries, binaries, `access` or `rules`, or `inference.allowed_routes`. + +5. Push the updated policy. Exit codes: 0 = loaded, 1 = validation failed, 124 = timeout. + + ```console + $ openshell policy set --policy current-policy.yaml --wait + ``` + +6. Verify the new revision. If status is `loaded`, repeat from step 2 as needed; if `failed`, fix the policy and repeat from step 4. + + ```console + $ openshell policy list + ``` + +## Debug Denied Requests + +Check `openshell logs --tail --source sandbox` for the denied host, path, and binary. + +When triaging denied requests, check: + +- Destination host and port to confirm which endpoint is missing. +- Calling binary path to confirm which `binaries` entry needs to be added or adjusted. +- HTTP method and path (for REST endpoints) to confirm which `rules` entry needs to be added or adjusted. + +Then push the updated policy as described above. ## Policy Structure -A policy has five top-level sections: `version`, `filesystem_policy`, `landlock`, `process`, `network_policies`, and `inference`. Static sections (`filesystem_policy`, `landlock`, `process`) are locked at sandbox creation and require recreation to change. Dynamic sections (`network_policies`, `inference`) are hot-reloadable on a running sandbox. The `landlock` section configures [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforcement at the kernel level. +A policy has static sections (`filesystem_policy`, `landlock`, `process`) that are locked at sandbox creation, and dynamic sections (`network_policies`, `inference`) that are hot-reloadable on a running sandbox. ```yaml version: 1 @@ -47,24 +131,47 @@ inference: allowed_routes: [local] ``` -For the complete field reference, see the [Policy Schema Reference](../reference/policy-schema.md). +For the complete structure and every field, see the [Policy Schema Reference](../reference/policy-schema.md). -## Network Policy Evaluation +## Network Access Rules -Every outbound connection from the sandbox goes through the proxy. The proxy matches the destination such as host and port and the calling binary to an endpoint in one of the `network_policies` blocks. +Network access is controlled by policy blocks under `network_policies`. Each block has a **name**, a list of **endpoints** (host, port, protocol, and optional rules), and a list of **binaries** that are allowed to use those endpoints. -- If an endpoint matches the destination and the binary is listed in that block's `binaries`, the connection is allowed. -- For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is also checked against that endpoint's `rules` (method and path). +Every outbound connection from the sandbox goes through the proxy: + +- The proxy matches the **destination** (host and port) and the **calling binary** to an endpoint in one of your policy blocks. A connection is allowed only when both match. +- For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is checked against that endpoint's `rules` (method and path). - If no endpoint matches and inference routes are configured, the request may be rerouted for inference. -- Otherwise the connection is denied. +- Otherwise the connection is denied. Endpoints without `protocol` or `tls` (L4-only) allow TCP passthrough without payload inspection. -Endpoints without `protocol` or `tls` (L4-only) allow the TCP stream through without inspecting payloads. For the full endpoint schema, access presets, and binary matching, see the [Policy Schema Reference](../reference/policy-schema.md). +## Examples -## Example Policy for GitHub Repository Access +Add these blocks to the `network_policies` section of your sandbox policy. Apply with `openshell policy set --policy --wait`. +Use **Simple endpoint** for host-level allowlists and **Granular rules** for method/path control. -The following policy block allows Claude and the GitHub CLI to reach `api.github.com` with granular per-endpoint rules: read-only (GET, HEAD, OPTIONS) and GraphQL (POST) for all paths; full write access for `alpha-repo`; and create/edit issues only for `bravo-repo`. Replace `` with your GitHub org or username. +:::::{tab-set} -Add this block to the `network_policies` section of your sandbox policy. +::::{tab-item} Simple endpoint +Allow `pip install` and `uv pip install` to reach PyPI: + +```yaml + pypi: + name: pypi + endpoints: + - host: pypi.org + port: 443 + - host: files.pythonhosted.org + port: 443 + binaries: + - { path: /usr/bin/pip } + - { path: /usr/local/bin/uv } +``` + +Endpoints without `protocol` or `tls` use L4 passthrough — the proxy allows the TCP stream without inspecting payloads. +:::: + +::::{tab-item} Granular rules +Allow Claude and the GitHub CLI to reach `api.github.com` with per-path rules: read-only (GET, HEAD, OPTIONS) and GraphQL (POST) for all paths; full write access for `alpha-repo`; and create/edit issues only for `bravo-repo`. Replace `` with your GitHub org or username. ```yaml github_repos: @@ -76,7 +183,6 @@ Add this block to the `network_policies` section of your sandbox policy. tls: terminate enforcement: enforce rules: - # Read-only access to all GitHub API paths - allow: method: GET path: "/**" @@ -86,15 +192,12 @@ Add this block to the `network_policies` section of your sandbox policy. - allow: method: OPTIONS path: "/**" - # GraphQL API (used by gh CLI for most operations) - allow: method: POST path: "/graphql" - # alpha-repo: full write access - allow: method: "*" path: "/repos//alpha-repo/**" - # bravo-repo: create + edit issues - allow: method: POST path: "/repos//bravo-repo/issues" @@ -106,87 +209,10 @@ Add this block to the `network_policies` section of your sandbox policy. - { path: /usr/bin/gh } ``` -Apply with `openshell policy set --policy --wait`. - -## Debug Denied Requests - -Check `openshell logs --tail --source sandbox` for the denied host, path, and binary. Add or adjust the matching endpoint or rules in the relevant policy block (for example, add a new `allow` rule for the method and path, or add the binary to that block's `binaries` list). See [Hot-Reload Policy Updates](#hot-reload-policy-updates) for the full iteration workflow. - -## Apply a Custom Policy - -Pass a policy YAML file when creating the sandbox: - -```console -$ openshell sandbox create --policy ./my-policy.yaml --keep -- claude -``` - -The `--keep` flag keeps the sandbox running after the initial command exits, which is useful when you plan to iterate on the policy. - -To avoid passing `--policy` every time, set a default policy with an environment variable: - -```console -$ export OPENSHELL_SANDBOX_POLICY=./my-policy.yaml -$ openshell sandbox create --keep -- claude -``` - -The CLI uses the policy from `OPENSHELL_SANDBOX_POLICY` whenever `--policy` is not explicitly provided. - -## Hot-Reload Policy Updates - -To change what the sandbox can access, pull the current policy, edit the YAML, and push the update. The workflow is iterative: create the sandbox, monitor logs for denied actions, pull the policy, modify it, push, and verify. - -```{mermaid} -flowchart TD - A["1. Create sandbox with initial policy"] --> B["2. Monitor logs for denied actions"] - B --> C["3. Pull current policy"] - C --> D["4. Modify the policy YAML"] - D --> E["5. Push updated policy"] - E --> F["6. Verify the new revision loaded"] - F --> B +Endpoints with `protocol: rest` and `tls: terminate` enable L7 inspection — the proxy decrypts TLS and checks each HTTP request against the `rules` list. +:::: - style A fill:#76b900,stroke:#000000,color:#000000 - style B fill:#76b900,stroke:#000000,color:#000000 - style C fill:#76b900,stroke:#000000,color:#000000 - style D fill:#ffffff,stroke:#000000,color:#000000 - style E fill:#76b900,stroke:#000000,color:#000000 - style F fill:#76b900,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -The following steps outline the hot-reload policy update workflow. - -1. Create the sandbox with your initial policy (or set `OPENSHELL_SANDBOX_POLICY`). - - ```console - $ openshell sandbox create --policy ./my-policy.yaml --keep -- claude - ``` - -2. Monitor denials — each log entry shows host, port, binary, and reason. Alternatively use `openshell term` for a live dashboard. - - ```console - $ openshell logs --tail --source sandbox - ``` - -3. Pull the current policy. Strip the metadata header (Version, Hash, Status) before reusing the file. - - ```console - $ openshell policy get --full > current-policy.yaml - ``` - -4. Edit the YAML: add or adjust `network_policies` entries, binaries, `access` or `rules`, or `inference.allowed_routes`. - -5. Push the updated policy. Exit codes: 0 = loaded, 1 = validation failed, 124 = timeout. - - ```console - $ openshell policy set --policy current-policy.yaml --wait - ``` - -6. Verify the new revision. If status is `loaded`, repeat from step 2 as needed; if `failed`, fix the policy and repeat from step 4. - - ```console - $ openshell policy list - ``` +::::: ## Next Steps From cea2e7ed8db16eca8a81b2a0257c72fb552735e2 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 22:23:42 -0700 Subject: [PATCH 08/20] Doc restructured --- docs/about/architecture.md | 127 +++++++---- docs/about/overview.md | 67 +++--- docs/get-started/quickstart.md | 2 +- docs/get-started/run-claude.md | 4 +- docs/get-started/run-openclaw.md | 2 +- docs/get-started/run-opencode.md | 5 +- docs/index.md | 19 +- docs/inference/configure.md | 2 +- docs/inference/index.md | 6 +- docs/reference/architecture.md | 207 ------------------ docs/reference/policy-schema.md | 2 +- docs/safety-and-privacy/default-policies.md | 36 --- docs/safety-and-privacy/index.md | 90 -------- docs/sandboxes/community-sandboxes.md | 2 +- docs/sandboxes/create-and-manage.md | 4 +- docs/sandboxes/index.md | 35 ++- .../policies.md | 9 +- docs/sandboxes/providers.md | 2 +- docs/troubleshooting.md | 2 +- 19 files changed, 161 insertions(+), 462 deletions(-) delete mode 100644 docs/reference/architecture.md delete mode 100644 docs/safety-and-privacy/default-policies.md delete mode 100644 docs/safety-and-privacy/index.md rename docs/{safety-and-privacy => sandboxes}/policies.md (93%) diff --git a/docs/about/architecture.md b/docs/about/architecture.md index 706124d759..fa02641a00 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -1,8 +1,8 @@ --- title: - page: "Architecture Overview" - nav: "Architecture" -description: "High-level overview of the OpenShell architecture: gateway, sandboxes, policy engine, and privacy router." + page: "How OpenShell Works" + nav: "How It Works" +description: "OpenShell architecture: gateway, sandbox, policy engine, and privacy router." keywords: ["nemoclaw architecture", "sandbox architecture", "agent isolation", "k3s", "policy engine"] topics: ["generative_ai", "cybersecurity"] tags: ["ai_agents", "sandboxing", "security", "architecture"] @@ -19,63 +19,102 @@ content: # How OpenShell Works -NemoClaw runs as a [k3s](https://k3s.io/) Kubernetes cluster inside a Docker container. -Each sandbox is an isolated Kubernetes pod managed by the OpenShell control plane. -Four components work together to keep agents secure. +OpenShell runs as a [k3s](https://k3s.io/) Kubernetes cluster inside a Docker container. Each sandbox is an isolated Kubernetes pod managed through the gateway. Four components work together to keep agents secure. ```{mermaid} -flowchart LR - CLI["CLI"] -->|gRPC| GW["Gateway"] - GW --> SBX["Sandbox"] - - subgraph SBX["Sandbox"] - direction TB - AGENT["Agent Process"] -->|All traffic| PROXY["Network Proxy"] - PROXY -->|Evaluate| OPA["Policy Engine"] +graph TB + subgraph docker["Docker Container"] + subgraph k3s["k3s Cluster"] + gw["Gateway"] + pr["Privacy Router"] + + subgraph pod1["Sandbox"] + sup1["Supervisor"] + proxy1["Proxy"] + pe1["Policy Engine"] + agent1["Agent"] + + sup1 --> proxy1 + sup1 --> agent1 + proxy1 --> pe1 + end + + subgraph pod2["Sandbox"] + sup2["Supervisor"] + proxy2["Proxy"] + pe2["Policy Engine"] + agent2["Agent"] + + sup2 --> proxy2 + sup2 --> agent2 + proxy2 --> pe2 + end + + gw -- "credentials,
policies" --> sup1 + gw -- "credentials,
policies" --> sup2 + end end - PROXY -->|Allowed traffic| EXT["External Services"] - - style CLI fill:#ffffff,stroke:#000000,color:#000000 - style GW fill:#76b900,stroke:#000000,color:#000000 - style SBX fill:#f5f5f5,stroke:#000000,color:#000000 - style AGENT fill:#ffffff,stroke:#000000,color:#000000 - style PROXY fill:#76b900,stroke:#000000,color:#000000 - style OPA fill:#76b900,stroke:#000000,color:#000000 - style EXT fill:#ffffff,stroke:#000000,color:#000000 + cli["nemoclaw CLI"] -- "gRPC" --> gw + agent1 -- "all outbound
traffic" --> proxy1 + agent2 -- "all outbound
traffic" --> proxy2 + proxy1 -- "policy-approved
traffic" --> internet["External Services"] + proxy2 -- "policy-approved
traffic" --> internet + proxy1 -- "inference traffic" --> pr + proxy2 -- "inference traffic" --> pr + pr -- "routed requests" --> backend["LLM Backend"] + + style cli fill:#ffffff,stroke:#000000,color:#000000 + style gw fill:#76b900,stroke:#000000,color:#000000 + style pr fill:#76b900,stroke:#000000,color:#000000 + style sup1 fill:#76b900,stroke:#000000,color:#000000 + style proxy1 fill:#76b900,stroke:#000000,color:#000000 + style pe1 fill:#76b900,stroke:#000000,color:#000000 + style agent1 fill:#ffffff,stroke:#000000,color:#000000 + style sup2 fill:#76b900,stroke:#000000,color:#000000 + style proxy2 fill:#76b900,stroke:#000000,color:#000000 + style pe2 fill:#76b900,stroke:#000000,color:#000000 + style agent2 fill:#ffffff,stroke:#000000,color:#000000 + style internet fill:#ffffff,stroke:#000000,color:#000000 + style backend fill:#ffffff,stroke:#000000,color:#000000 + style docker fill:#f5f5f5,stroke:#000000,color:#000000 + style k3s fill:#e8e8e8,stroke:#000000,color:#000000 + style pod1 fill:#f5f5f5,stroke:#000000,color:#000000 + style pod2 fill:#f5f5f5,stroke:#000000,color:#000000 linkStyle default stroke:#76b900,stroke-width:2px ``` ## Components -NemoClaw consists of the following components. - -Gateway -: The control-plane API that manages sandbox lifecycle, stores encrypted credentials, distributes policies, and terminates SSH tunnels. The CLI communicates exclusively with the gateway—it never talks to sandbox pods directly. - -Sandbox -: An isolated pod that runs your agent. Each sandbox contains a **supervisor** (sets up isolation and starts the agent), an **L7 proxy** (intercepts and evaluates every outbound connection), and the agent process itself. +| Component | Role | +|---|---| +| **Gateway** | Control-plane API that coordinates sandbox lifecycle and state, acts as the auth boundary, and brokers requests across the platform. | +| **Sandbox** | Isolated runtime that includes container supervision and policy-enforced egress routing. | +| **Policy Engine** | Policy definition and enforcement layer for filesystem, network, and process constraints. Defense in depth enforces policies from the application layer down to infrastructure and kernel layers. | +| **Privacy Router** | Privacy-aware LLM routing layer that keeps sensitive context on sandbox compute and routes based on cost and privacy policy. | -Policy Engine -: Evaluates declarative YAML policies that define filesystem, network, and process constraints. The proxy queries the engine on every outbound connection. Policies can be hot-reloaded without restarting the agent. +## How a Request Flows -Privacy Router -: Intercepts LLM API calls and routes them to local or self-hosted backends based on your routing policy. Sensitive prompts and completions stay on infrastructure you control. +Every outbound connection from agent code passes through the same decision path: -## How a Request Flows +1. The agent process opens an outbound connection (API call, package install, git clone, etc.). +2. The proxy inside the sandbox intercepts the connection and identifies which binary opened it. +3. The proxy queries the policy engine with the destination, port, and calling binary. +4. The policy engine returns one of three decisions: + - **Allow** — the destination and binary match a policy block. Traffic flows directly to the external service. + - **Route for inference** — no policy block matched, but inference routing is configured. The privacy router intercepts the request, strips the original credentials, injects the configured backend credentials, and forwards to the managed model endpoint. + - **Deny** — no match and no inference route. The connection is blocked and logged. -NemoClaw works in the following way: +For REST endpoints with TLS termination enabled, the proxy also decrypts TLS and checks each HTTP request against per-method, per-path rules before allowing it through. -1. The agent makes an outbound connection (for example, an API call). -2. The L7 proxy intercepts the connection and identifies the calling process. -3. The proxy queries the policy engine with the destination and process identity. -4. Based on the policy decision, the proxy either allows the connection, routes it through the privacy router for inference, or denies it. +## Deployment Modes -## Remote Deployment +OpenShell can run locally or on a remote host. The architecture is identical in both cases — only the Docker container location changes. -NemoClaw can also run on a remote host. Deploy with `nemoclaw gateway start --remote user@host`, then set up a tunnel with `nemoclaw gateway tunnel`. The architecture is identical—only the Docker container location changes. +- **Local**: the k3s cluster runs inside Docker on your workstation. The CLI provisions it automatically on first use. +- **Remote**: the cluster runs on a remote host. Deploy with `nemoclaw gateway start --remote user@host`, then connect with `nemoclaw gateway tunnel`. All CLI commands route through the SSH tunnel transparently. ---- +## Next Steps -For detailed component internals, refer to the [Architecture Reference](../reference/architecture.md). +- [Sandbox Policies](../sandboxes/policies.md): Policy structure, network rules, and update workflow. diff --git a/docs/about/overview.md b/docs/about/overview.md index 90f8f12422..92cf7bbf5d 100644 --- a/docs/about/overview.md +++ b/docs/about/overview.md @@ -19,57 +19,42 @@ content: # Overview of NVIDIA OpenShell -NVIDIA OpenShell is an open-source runtime that executes autonomous AI agents inside sandboxed environments with kernel-level isolation. It prevents agents from accessing unauthorized files, exfiltrating data, leaking credentials, or making uncontrolled network requests. A single declarative YAML policy governs filesystem, network, process, and inference protections across all sandboxes and is hot-reloadable without restarting running agents. +NVIDIA OpenShell is an open-source runtime for executing autonomous AI agents in sandboxed environments with kernel-level isolation. It combines sandbox runtime controls and a declarative YAML policy so teams can run agents without giving them unrestricted access to local files, credentials, and external networks. -## Common Challenges with AI Agents +## Why OpenShell Exists -AI agents are most useful when they have broad access to reading files, installing packages, calling APIs, and using credentials. However, this same access makes them dangerous. An unrestricted agent can leak your API keys, send proprietary code to unauthorized endpoints, or reach infrastructure it was never meant to touch. +AI agents are most useful when they can read files, install packages, call APIs, and use credentials. That same access can create material risk. OpenShell is designed for this tradeoff: preserve agent capability while enforcing explicit controls over what the agent can access. -Conventional containers do not solve this. They isolate processes from the host, but they do not control what an agent does *inside* the container — which files it reads, which hosts it contacts, or where it sends your prompts. +## Common Risks and Controls -## Benefits of Using OpenShell +The table below summarizes common failure modes and how OpenShell mitigates them. -NemoClaw addresses these risks through defense-in-depth enforcement across four policy domains: filesystem, network, process, and inference. +| Threat | Without controls | With OpenShell | +|---|---|---| +| Data exfiltration | Agent uploads source code or internal files to unauthorized endpoints. | Network policies allow only approved destinations; other outbound traffic is denied. | +| Credential theft | Agent reads local secrets such as SSH keys or cloud credentials. | Filesystem restrictions (Landlock) confine access to declared paths only. | +| Unauthorized API usage | Agent sends prompts or data to unapproved model providers. | Privacy routing and network policies control where inference traffic can go. | +| Privilege escalation | Agent attempts `sudo`, setuid paths, or dangerous syscall behavior. | Unprivileged process identity and seccomp restrictions block escalation paths. | -:::{dropdown} 🛡️ Kernel-Level Isolation -NemoClaw enforces isolation at the Linux kernel level using Landlock for filesystem restrictions, seccomp for system call filtering, and network namespaces for traffic control. These mechanisms operate below the application layer, so agents cannot bypass them regardless of the tools or languages they use. -::: +## Protection Layers at a Glance -:::{dropdown} 📜 Declarative Policy Enforcement -A single YAML policy file defines all security boundaries for a sandbox: allowed filesystem paths, permitted network destinations, restricted processes, and inference routing rules. Policies are hot-reloadable, so you can tighten or relax rules on a running sandbox without restarting the agent. -::: +OpenShell applies defense in depth across four policy domains: -:::{dropdown} 🔐 Credential Containment -Credentials are injected into sandboxes as environment variables at startup and are scoped to the sandbox's isolated namespace. They cannot be read by processes outside the sandbox, and network policies prevent agents from transmitting them to unauthorized endpoints. -::: +| Layer | What it protects | When it applies | +|---|---|---| +| Filesystem | Prevents reads/writes outside allowed paths. | Locked at sandbox creation. | +| Network | Blocks unauthorized outbound connections. | Hot-reloadable at runtime. | +| Process | Blocks privilege escalation and dangerous syscalls. | Locked at sandbox creation. | +| Inference | Reroutes model API calls to controlled backends. | Hot-reloadable at runtime. | -:::{dropdown} 🔀 Private Inference Routing -The built-in inference router intercepts LLM API calls and redirects them to local or self-hosted backends based on your routing policy. Sensitive prompts and completions stay on infrastructure you control. Routes are configurable per sandbox and can be updated without restarting agents. -::: +For details, refer to [Built-in Default Policy](../sandboxes/index.md#built-in-default-policy) and [Customize Sandbox Policies](../sandboxes/policies.md). -:::{dropdown} 🔍 Full L7 Traffic Inspection -Every outbound TCP connection from a sandbox passes through an L7 proxy that resolves the calling process, evaluates the destination against the active policy, and either allows, denies, or reroutes the request. For REST endpoints, the proxy decrypts TLS, inspects HTTP method and path, and applies fine-grained access rules. -::: +## Common Use Cases -## Use Cases - -The following are common use cases for OpenShell. - -:::{dropdown} 💻 Secure Coding Agents -Run AI coding assistants such as Claude Code, OpenCode, or OpenClaw inside a sandbox where they can read and modify project files but cannot access SSH keys, cloud credentials, or files outside the project directory. Network policies restrict which package registries and APIs the agent can reach. -::: - -:::{dropdown} 🏢 Private Enterprise Development -Route all LLM inference through self-hosted NVIDIA NIM endpoints or private API backends. Proprietary source code and internal documentation stay on your infrastructure and are never sent to third-party LLM providers. -::: - -:::{dropdown} ✅ Compliance and Audit -Declarative policies serve as auditable security controls. Each sandbox runs under a well-defined policy that specifies exactly what the agent can access. Policy files can be version-controlled and reviewed as part of your security and compliance processes. -::: - -:::{dropdown} 📦 Community and Custom Sandbox Images -Use pre-built sandbox images from the [NemoClaw Community](https://github.com/NVIDIA/NemoClaw-Community) catalog or bring your own container. Community sandboxes bundle domain-specific tools, policies, and skills, while custom containers let you package any environment your agents need. -::: +- **Secure coding agents**: Run Claude Code, OpenCode, or OpenClaw with constrained file and network access. +- **Private enterprise development**: Route inference to self-hosted or private backends while keeping sensitive context under your control. +- **Compliance and audit**: Treat policy YAML as version-controlled security controls that can be reviewed and audited. +- **Reusable environments**: Use community sandbox images or bring your own containerized runtime. --- @@ -77,4 +62,4 @@ Use pre-built sandbox images from the [NemoClaw Community](https://github.com/NV - [Architecture Overview](architecture.md): Understand the components that make up the OpenShell runtime. - [Get Started](../index.md): Install the CLI and create your first sandbox. -- [Safety and Privacy](../safety-and-privacy/index.md): Learn how OpenShell enforces isolation across all protection layers. +- [Sandboxes](../sandboxes/index.md): Learn how OpenShell enforces isolation across all protection layers. diff --git a/docs/get-started/quickstart.md b/docs/get-started/quickstart.md index 4fa85d89cb..f64d14cfa4 100644 --- a/docs/get-started/quickstart.md +++ b/docs/get-started/quickstart.md @@ -73,4 +73,4 @@ You now have a working sandbox! From here, you can: - Follow the [Tutorials](tutorials.md) for step-by-step walkthroughs with Claude Code, OpenClaw, and OpenCode. - Learn how sandboxes work in [Sandboxes](../sandboxes/create-and-manage.md). -- Write your own policies in [Safety and Privacy](../safety-and-privacy/index.md). +- Write your own policies in [Customize Sandbox Policies](../sandboxes/policies.md). diff --git a/docs/get-started/run-claude.md b/docs/get-started/run-claude.md index 8559a1b9b4..967d2ec49d 100644 --- a/docs/get-started/run-claude.md +++ b/docs/get-started/run-claude.md @@ -115,5 +115,5 @@ This is useful when you plan to reconnect later or iterate on the policy while t - {doc}`../sandboxes/create-and-manage`: Learn the isolation model and sandbox lifecycle. - {doc}`../sandboxes/providers`: Understand how credentials are injected without exposing them to agent code. -- {doc}`../safety-and-privacy/policies`: Customize the default policy or write your own. -- {doc}`../safety-and-privacy/default-policies`: Explore the built-in default policy and agent compatibility. +- {doc}`../sandboxes/policies`: Customize the default policy or write your own. +- {doc}`../sandboxes/index`: Explore the built-in default policy and agent compatibility. diff --git a/docs/get-started/run-openclaw.md b/docs/get-started/run-openclaw.md index 97b50a3444..a27fc2974f 100644 --- a/docs/get-started/run-openclaw.md +++ b/docs/get-started/run-openclaw.md @@ -97,5 +97,5 @@ The OpenShell Community repository accepts contributions. If you build a sandbox ## Next Steps - {doc}`../sandboxes/community-sandboxes`: Full reference on community sandbox definitions, available images, and how to contribute your own. -- {doc}`../safety-and-privacy/policies`: Learn the policy format and how to customize what a sandbox can do. +- {doc}`../sandboxes/policies`: Learn the policy format and how to customize what a sandbox can do. - {doc}`../sandboxes/create-and-manage`: Understand the isolation model and lifecycle behind every sandbox. diff --git a/docs/get-started/run-opencode.md b/docs/get-started/run-opencode.md index 1604700e71..8c2b0e0ee5 100644 --- a/docs/get-started/run-opencode.md +++ b/docs/get-started/run-opencode.md @@ -250,8 +250,7 @@ $ nemoclaw sandbox delete opencode-sandbox ## Next Steps -- {doc}`../safety-and-privacy/policies`: Full reference on policy YAML structure, static and dynamic fields, and enforcement modes. -- {doc}`../safety-and-privacy/policies`: How network policy fits into the sandbox iteration workflow. +- {doc}`../sandboxes/policies`: Policy structure, network rules, and the sandbox iteration workflow. - {doc}`../inference/index`: `inference.local`, supported API patterns, and request routing. - {doc}`../sandboxes/providers`: Provider types, credential discovery, and manual and automatic creation. -- {doc}`../safety-and-privacy/index`: The protection layers and how they interact. +- {doc}`../sandboxes/index`: The protection layers and how they interact. diff --git a/docs/index.md b/docs/index.md index a96b6edf10..6b9f3b0bd1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -142,14 +142,14 @@ Create, manage, and customize sandboxes. Use community images or bring your own {bdg-secondary}`Concept` ::: -:::{grid-item-card} Safety and Privacy -:link: safety-and-privacy/index +:::{grid-item-card} Sandbox Policies +:link: sandboxes/policies :link-type: doc -Write policies that control what agents can access. Iterate on network rules in real time. +Customize sandbox policies and configure network access rules. +++ -{bdg-secondary}`Concept` +{bdg-secondary}`How-To` ::: :::{grid-item-card} Inference Routing @@ -203,19 +203,11 @@ get-started/tutorials sandboxes/index sandboxes/create-and-manage +sandboxes/policies sandboxes/providers sandboxes/community-sandboxes ``` -```{toctree} -:caption: Safety and Privacy -:hidden: - -safety-and-privacy/index -safety-and-privacy/default-policies -safety-and-privacy/policies -``` - ```{toctree} :caption: Inference Routing :hidden: @@ -231,7 +223,6 @@ inference/configure reference/cli reference/default-policy reference/policy-schema -reference/architecture ``` ```{toctree} diff --git a/docs/inference/configure.md b/docs/inference/configure.md index 0971a0aa33..b6a87f8e4c 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -93,7 +93,7 @@ security reasons. External providers that should be reached directly belong in ## Next Steps - {doc}`index`: understand the interception flow and supported API patterns. -- [Network Access Rules](/safety-and-privacy/policies.md#network-access-rules): +- [Network Access Rules](/sandboxes/policies.md#network-access-rules): configure direct access to external inference endpoints. - {doc}`../sandboxes/providers`: create and manage provider records. - {doc}`../reference/cli`: see the CLI reference for `nemoclaw inference` diff --git a/docs/inference/index.md b/docs/inference/index.md index fe227952bc..ee32f56323 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -17,8 +17,8 @@ If sandbox code calls an external inference API like `api.openai.com` or `api.anthropic.com`, that traffic is treated like any other outbound network request. It is allowed or denied by `network_policies`. -Refer to {doc}`/safety-and-privacy/policies` and the -[Network Access Rules](/safety-and-privacy/policies.md#network-access-rules) +Refer to {doc}`/sandboxes/policies` and the +[Network Access Rules](/sandboxes/policies.md#network-access-rules) section for details. ## `inference.local` @@ -80,5 +80,5 @@ supported patterns are denied. ## Next Steps - {doc}`configure`: configure the backend behind `inference.local`. -- [Network Access Rules](/safety-and-privacy/policies.md#network-access-rules): +- [Network Access Rules](/sandboxes/policies.md#network-access-rules): understand how external endpoints are controlled. diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md deleted file mode 100644 index 2376ec9323..0000000000 --- a/docs/reference/architecture.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -title: - page: "Architecture Reference" - nav: "Architecture" -description: "Detailed reference for OpenShell architecture: gateway, sandbox internals, policy engine, privacy router, and remote deployment." -keywords: ["nemoclaw architecture", "sandbox architecture", "agent isolation", "k3s", "policy engine"] -topics: ["generative_ai", "cybersecurity"] -tags: ["ai_agents", "sandboxing", "security", "architecture"] -content: - type: reference - difficulty: technical_advanced - audience: [engineer, data_scientist] ---- - - - -# Architecture Reference - -This page provides detailed technical information about each OpenShell component. -For a high-level summary, refer to the [Architecture Overview](../about/architecture.md). - -## Component Diagram - -```{mermaid} -graph TB - subgraph docker["Docker Container"] - subgraph k3s["k3s Cluster"] - gw["Gateway"] - pr["Privacy Router"] - - subgraph pod1["Sandbox"] - sup1["Supervisor"] - proxy1["L7 Proxy"] - pe1["Policy Engine"] - agent1["Agent"] - - sup1 --> proxy1 - sup1 --> agent1 - proxy1 --> pe1 - end - - subgraph pod2["Sandbox"] - sup2["Supervisor"] - proxy2["L7 Proxy"] - pe2["Policy Engine"] - agent2["Agent"] - - sup2 --> proxy2 - sup2 --> agent2 - proxy2 --> pe2 - end - - gw -- "credentials,
policies" --> sup1 - gw -- "credentials,
policies" --> sup2 - end - end - - cli["nemoclaw CLI"] -- "gRPC" --> gw - agent1 -- "all outbound
traffic" --> proxy1 - agent2 -- "all outbound
traffic" --> proxy2 - proxy1 -- "policy-approved
traffic" --> internet["External Services"] - proxy2 -- "policy-approved
traffic" --> internet - proxy1 -- "inference traffic" --> pr - proxy2 -- "inference traffic" --> pr - pr -- "routed requests" --> backend["LLM Backend"] - - style cli fill:#ffffff,stroke:#000000,color:#000000 - style gw fill:#76b900,stroke:#000000,color:#000000 - style pr fill:#76b900,stroke:#000000,color:#000000 - style sup1 fill:#76b900,stroke:#000000,color:#000000 - style proxy1 fill:#76b900,stroke:#000000,color:#000000 - style pe1 fill:#76b900,stroke:#000000,color:#000000 - style agent1 fill:#ffffff,stroke:#000000,color:#000000 - style sup2 fill:#76b900,stroke:#000000,color:#000000 - style proxy2 fill:#76b900,stroke:#000000,color:#000000 - style pe2 fill:#76b900,stroke:#000000,color:#000000 - style agent2 fill:#ffffff,stroke:#000000,color:#000000 - style internet fill:#ffffff,stroke:#000000,color:#000000 - style backend fill:#ffffff,stroke:#000000,color:#000000 - style docker fill:#f5f5f5,stroke:#000000,color:#000000 - style k3s fill:#e8e8e8,stroke:#000000,color:#000000 - style pod1 fill:#f5f5f5,stroke:#000000,color:#000000 - style pod2 fill:#f5f5f5,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -## Gateway - -The gateway is the central control-plane API. It coordinates sandbox lifecycle -and state, acts as the auth boundary, and brokers all requests across the -platform. It exposes a gRPC API consumed by the CLI and handles: - -- Sandbox lifecycle: creates, monitors, and deletes sandbox pods. -- Provider storage: stores encrypted provider credentials. -- Policy distribution: delivers policy YAML to sandboxes at startup and on - hot-reload. -- SSH termination: terminates SSH tunnels from the CLI and routes them to - the correct sandbox. - -The CLI never talks to sandbox pods directly. All commands go through the -gateway. - -## Sandbox - -Each sandbox is an isolated runtime that includes container supervision and -general L7 egress routing. It runs as a Kubernetes pod containing a supervisor -process, an L7 proxy, and the agent. - -### Supervisor - -The supervisor is the sandbox's init process. It establishes all isolation -boundaries before starting the agent: - -1. Fetch credentials from the gateway for all attached providers. -2. Set up the network namespace. The sandbox gets its own network stack - with no default route. All outbound traffic is redirected through the proxy. -3. Apply Landlock filesystem restrictions based on the policy. -4. Apply seccomp filters to restrict available system calls. -5. Start the L7 proxy in the sandbox's network namespace. -6. Start the SSH server for interactive access. -7. Start the agent as a child process with credentials injected as - environment variables. - -### L7 Proxy - -Every outbound TCP connection from any process in the sandbox is routed through -the proxy. For each connection, the proxy: - -1. Resolves the calling binary through `/proc//exe`, ancestor process - walking, and `/proc//cmdline`. -2. Queries the policy engine with the destination host, port, and resolved - binary path. -3. Acts on the decision: allow the connection directly, hand it to the - privacy router for inference routing, or deny it. Refer to - {doc}`../safety-and-privacy/policies` for the full decision model. - -For endpoints configured with `protocol: rest` and `tls: terminate`, the proxy -performs full L7 inspection: it decrypts TLS, reads the HTTP method and path, -evaluates access rules, then re-encrypts and forwards the request. - -## Policy Engine - -The policy engine is the definition and enforcement layer for filesystem, -network, and process constraints. Defense in depth enforces policies from the -application layer down to infrastructure and kernel layers. - -The engine evaluates policies compiled from the sandbox's policy YAML. It is -queried synchronously by the proxy on every outbound connection. Policy updates -delivered through hot-reload are compiled and loaded without restarting the proxy. - -## Privacy Router - -The privacy router is a privacy-aware LLM routing layer that keeps sensitive -context on sandbox compute and routes based on cost/privacy policy. - -When the policy engine determines that a connection should be inspected for -inference, the privacy router: - -1. Reads the intercepted HTTP request. -2. Checks whether the method and path match a recognized inference API pattern - (`/v1/chat/completions`, `/v1/completions`, `/v1/messages`). -3. Selects a route whose `routing_hint` appears in the sandbox policy's - `allowed_routes`. -4. Strips the original authorization header. -5. Injects the route's API key and model ID. -6. Forwards the request to the route's backend URL. - -The router refreshes its route list periodically from the gateway, so routes -created with `nemoclaw inference create` become available without restarting -sandboxes. - -## Remote Deployment - -NemoClaw can deploy the cluster to a remote host via SSH. This is useful for -shared team environments or running sandboxes on machines with more resources. - -### Deploy - -```console -$ nemoclaw gateway start --remote user@host --ssh-key ~/.ssh/id_rsa -``` - -The CLI connects to the remote machine over SSH, installs k3s, deploys the -NemoClaw control plane, and registers the cluster locally. The remote machine -needs Docker installed. - -### Tunnel - -After deploying to a remote host, set up a tunnel for CLI access: - -```console -$ nemoclaw gateway tunnel -``` - -This establishes an SSH tunnel from your local machine to the remote cluster's -API server. All subsequent CLI commands route through this tunnel transparently. - -### Remote Architecture - -The architecture is identical to a local deployment. The only difference is -that the Docker container runs on the remote host instead of your workstation. -The CLI communicates with the gateway over the SSH tunnel. Sandbox SSH -connections are also tunneled through the gateway. diff --git a/docs/reference/policy-schema.md b/docs/reference/policy-schema.md index 5f626a87af..a2157c1d3c 100644 --- a/docs/reference/policy-schema.md +++ b/docs/reference/policy-schema.md @@ -132,7 +132,7 @@ Each endpoint defines a reachable destination and optional inspection rules. |---|---|---|---| | `host` | string | Yes | Hostname or IP address. Supports wildcards: `*.example.com` matches any subdomain. | | `port` | integer | Yes | TCP port number. | -| `protocol` | string | No | Set to `rest` to enable L7 (HTTP) inspection. Omit for L4-only (TCP passthrough). | +| `protocol` | string | No | Set to `rest` to enable HTTP request inspection. Omit for TCP passthrough. | | `tls` | string | No | TLS handling mode. `terminate` decrypts TLS at the proxy for inspection. `passthrough` forwards encrypted traffic without inspection. Only relevant when `protocol` is `rest`. | | `enforcement` | string | No | `enforce` actively blocks disallowed requests. `audit` logs violations but allows traffic through. | | `access` | string | No | HTTP access level. One of `read-only`, `read-write`, or `full`. Mutually exclusive with `rules`. | diff --git a/docs/safety-and-privacy/default-policies.md b/docs/safety-and-privacy/default-policies.md deleted file mode 100644 index f32ef9195e..0000000000 --- a/docs/safety-and-privacy/default-policies.md +++ /dev/null @@ -1,36 +0,0 @@ - - -# Built-in Default Policy - -NVIDIA OpenShell ships a built-in policy that covers common agent workflows out of the box. -When you create a sandbox without `--policy`, OpenShell applies the default policy. This policy controls three things: - -- What the agent can access on disk. Filesystem paths are split into read-only and read-write sets. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. -- What the agent can reach on the network. Each network policy block pairs a set of allowed destinations (host and port) with a set of allowed binaries (executable paths inside the sandbox). The proxy resolves every outbound connection to the binary that opened it. A connection is allowed only when both the destination and the calling binary match an entry in the same block. Everything else is denied. -- What privileges the agent has. The agent runs as an unprivileged user with seccomp filters that block dangerous system calls. There is no `sudo`, no `setuid`, and no path to elevated privileges. - -## Agent Compatibility - -The following table shows the coverage of the default policy for common agents. - -| Agent | Coverage | Action Required | -|---|---|---| -| Claude Code | Full | None. Works out of the box. | -| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. See [Run OpenCode with NVIDIA Inference](../get-started/run-opencode.md). | -| Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | - -:::{important} -If you run a non-Claude agent without a custom policy, the agent's API calls are denied by the proxy. You must provide a policy that declares the agent's endpoints and binaries. -::: - -## What the Default Policy Allows - -The default policy defines six network policy blocks, plus filesystem isolation, Landlock enforcement, and process identity. For the full breakdown of each block, see {doc}`../reference/default-policy`. - -## Next Steps - -- {doc}`policies`: Write custom policies, configure network rules, and iterate on a running sandbox. -- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. diff --git a/docs/safety-and-privacy/index.md b/docs/safety-and-privacy/index.md deleted file mode 100644 index 5be184c0b4..0000000000 --- a/docs/safety-and-privacy/index.md +++ /dev/null @@ -1,90 +0,0 @@ - - -# About Safety and Privacy - -OpenShell wraps every sandbox in four independent protection layers. No single -point of failure can compromise your environment. Each layer covers gaps the -others cannot. - -```{mermaid} -graph TB - subgraph runtime["OpenShell Runtime"] - direction TB - - subgraph layers["Protection Layers"] - direction TB - - fs["Filesystem — Landlock LSM"] - net["Network — Proxy + Policy Engine"] - proc["Process — seccomp + Unprivileged User"] - inf["Inference — Privacy Router"] - - subgraph sandbox["Sandbox"] - agent(["AI Agent"]) - end - end - end - - agent -- "read /sandbox ✔" --> fs - agent -- "read /etc/shadow ✘" --> fs - agent -- "curl approved.com ✔" --> net - agent -- "curl evil.com ✘" --> net - agent -- "sudo install pkg ✘" --> proc - agent -- "call api.openai.com" --> inf - inf -- "reroute → your backend ✔" --> net - - style runtime fill:#f5f5f5,stroke:#000000,color:#000000 - style layers fill:#e8e8e8,stroke:#000000,color:#000000 - style sandbox fill:#f5f5f5,stroke:#000000,color:#000000 - style agent fill:#ffffff,stroke:#000000,color:#000000 - style fs fill:#76b900,stroke:#000000,color:#000000 - style net fill:#76b900,stroke:#000000,color:#000000 - style proc fill:#76b900,stroke:#000000,color:#000000 - style inf fill:#76b900,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -## Sandbox Policies - -You control all four layers through a single YAML policy — a file you attach when creating a sandbox that declares which paths the agent can access, which hosts it can reach, and how inference calls are routed. - -| Layer | What It Protects | When It Applies | -|---|---|---| -| **Filesystem** (Landlock LSM) | Prevents reads/writes outside allowed paths. | Locked at sandbox creation. | -| **Network** (Proxy + Policy Engine) | Blocks unauthorized outbound connections. | Hot-reloadable at runtime. | -| **Process** (seccomp + unprivileged user) | Blocks privilege escalation and dangerous syscalls. | Locked at sandbox creation. | -| **Inference** (Privacy Router) | Reroutes API calls to backends you control. | Hot-reloadable at runtime. | - -Filesystem and process restrictions are locked at creation time. Network and -inference rules are hot-reloadable on a running sandbox, so you can iterate on -access rules without recreating the sandbox. - -## Threat Scenarios - -When an AI agent runs with unrestricted access, it can read any file, reach any -network host, call any API with your credentials, and install arbitrary software. -The table below shows how the four layers address concrete threats. - -| Threat | Without Protection | With OpenShell | -|---|---|---| -| **Data exfiltration** | Agent uploads source code to an external server via `curl`. | Network policy blocks all outbound connections except explicitly approved hosts. | -| **Credential theft** | Agent reads `~/.ssh/id_rsa` or `~/.aws/credentials` and exfiltrates them. | [Landlock](https://docs.kernel.org/security/landlock.html) limits the agent to declared paths (`/sandbox`, `/tmp`, read-only system dirs). | -| **Unauthorized API calls** | Agent calls `api.openai.com` with your key, sending data to a third-party provider. | Privacy router intercepts and reroutes calls to a backend you control. | -| **Privilege escalation** | Agent runs `sudo apt install`, modifies `/etc/passwd`, or scans the internal network. | Agent runs as an unprivileged user with seccomp filters; no `sudo`, no `setuid`. | - -:::{important} -All four layers work together. No single layer is sufficient on its own. -Filesystem restrictions do not prevent network exfiltration. Network policies do -not prevent local privilege escalation. Process restrictions do not control -where inference traffic goes. Defense in depth means every layer covers gaps -that the others cannot. -::: - -## Next Steps - -- {doc}`default-policies`: The built-in policy that ships with OpenShell and what each block allows. -- {doc}`policies`: Write custom policies, configure network rules, and iterate on a running sandbox. diff --git a/docs/sandboxes/community-sandboxes.md b/docs/sandboxes/community-sandboxes.md index 0124f4506b..2c0c04e5ab 100644 --- a/docs/sandboxes/community-sandboxes.md +++ b/docs/sandboxes/community-sandboxes.md @@ -91,4 +91,4 @@ or anything else), consider contributing it back so others can use it. ## Next Steps - {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`../safety-and-privacy/policies`: Customize the policy applied to any sandbox +- {doc}`policies`: Customize the policy applied to any sandbox diff --git a/docs/sandboxes/create-and-manage.md b/docs/sandboxes/create-and-manage.md index 885a74245f..92655d3086 100644 --- a/docs/sandboxes/create-and-manage.md +++ b/docs/sandboxes/create-and-manage.md @@ -107,7 +107,7 @@ The dashboard shows: - **Sandbox status** — name, phase, image, attached providers, age, and active port forwards. - **Live log stream** — outbound connections, policy decisions, and inference interceptions as they happen. Logs are labeled by source: `sandbox` (proxy and policy events) or `gateway` (lifecycle events). -Use the terminal to spot blocked connections (`action=deny` entries) and inference interceptions (`action=inspect_for_inference` entries). If a connection is blocked unexpectedly, add the host to your network policy — refer to {doc}`../safety-and-privacy/policies` for the workflow. +Use the terminal to spot blocked connections (`action=deny` entries) and inference interceptions (`action=inspect_for_inference` entries). If a connection is blocked unexpectedly, add the host to your network policy — refer to {doc}`policies` for the workflow. ## Transfer Files @@ -145,4 +145,4 @@ $ nemoclaw sandbox delete my-sandbox - {doc}`community-sandboxes`: Use pre-built sandboxes from the community catalog - {doc}`providers`: Create and attach credential providers -- {doc}`../safety-and-privacy/policies`: Control what the agent can access \ No newline at end of file +- {doc}`policies`: Control what the agent can access \ No newline at end of file diff --git a/docs/sandboxes/index.md b/docs/sandboxes/index.md index 1cf23a1058..ac83917d7d 100644 --- a/docs/sandboxes/index.md +++ b/docs/sandboxes/index.md @@ -5,7 +5,7 @@ # About Sandboxes -A OpenShell sandbox is a safe, private execution environment for an AI agent. Each sandbox runs inside a Kubernetes pod with multiple layers of protection that prevent unauthorized data access, credential exposure, and network exfiltration. Protection layers include filesystem restrictions (Landlock), system call filtering (seccomp), network namespace isolation, and a privacy-enforcing HTTP CONNECT proxy. +An OpenShell sandbox is a safe, private execution environment for an AI agent. Each sandbox runs inside a Kubernetes pod with multiple layers of protection that prevent unauthorized data access, credential exposure, and network exfiltration. Protection layers include filesystem restrictions (Landlock), system call filtering (seccomp), network namespace isolation, and a privacy-enforcing HTTP CONNECT proxy. ## Sandbox Lifecycle @@ -18,21 +18,40 @@ Every sandbox moves through a defined set of phases: | Error | Something went wrong during provisioning or execution. Check logs with `nemoclaw logs` for details. | | Deleting | The sandbox is being torn down. The system releases resources and purges credentials. | -## The OpenShell Runtime +## Built-in Default Policy -Sandboxes run inside a lightweight runtime cluster that OpenShell manages for -you. The cluster runs as a [k3s](https://k3s.io/) Kubernetes distribution -inside a Docker container on your machine. +NVIDIA OpenShell ships a built-in policy that covers common agent workflows out of the box. +When you create a sandbox without `--policy`, OpenShell applies the default policy. This policy controls three things: -You do not need to set this up manually. The first time you run a command -that needs a cluster (such as `nemoclaw sandbox create`), the CLI provisions -one automatically. +- What the agent can access on disk. Filesystem paths are split into read-only and read-write sets. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. +- What the agent can reach on the network. Each network policy block pairs a set of allowed destinations (host and port) with a set of allowed binaries (executable paths inside the sandbox). The proxy resolves every outbound connection to the binary that opened it. A connection is allowed only when both the destination and the calling binary match an entry in the same block. Everything else is denied. +- What privileges the agent has. The agent runs as an unprivileged user with seccomp filters that block dangerous system calls. There is no `sudo`, no `setuid`, and no path to elevated privileges. + +### Agent Compatibility + +The following table shows the coverage of the default policy for common agents. + +| Agent | Coverage | Action Required | +|---|---|---| +| Claude Code | Full | None. Works out of the box. | +| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. See [Run OpenCode with NVIDIA Inference](../get-started/run-opencode.md). | +| Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | + +:::{important} +If you run a non-Claude agent without a custom policy, the agent's API calls are denied by the proxy. You must provide a policy that declares the agent's endpoints and binaries. +::: + +### What the Default Policy Allows + +The default policy defines six network policy blocks, plus filesystem isolation, Landlock enforcement, and process identity. For the full breakdown of each block, see {doc}`../reference/default-policy`. ## Next Steps - {doc}`create-and-manage`: Create, inspect, connect, monitor, and delete sandboxes. +- {doc}`policies`: Write custom policies, configure network rules, and iterate on a running sandbox. - {doc}`providers`: Create and attach credential providers so agents can authenticate with external services. - {doc}`community-sandboxes`: Use pre-built sandboxes from the community catalog. +- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. diff --git a/docs/safety-and-privacy/policies.md b/docs/sandboxes/policies.md similarity index 93% rename from docs/safety-and-privacy/policies.md rename to docs/sandboxes/policies.md index d2a5d64aec..31fd16fa38 100644 --- a/docs/safety-and-privacy/policies.md +++ b/docs/sandboxes/policies.md @@ -142,7 +142,7 @@ Every outbound connection from the sandbox goes through the proxy: - The proxy matches the **destination** (host and port) and the **calling binary** to an endpoint in one of your policy blocks. A connection is allowed only when both match. - For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is checked against that endpoint's `rules` (method and path). - If no endpoint matches and inference routes are configured, the request may be rerouted for inference. -- Otherwise the connection is denied. Endpoints without `protocol` or `tls` (L4-only) allow TCP passthrough without payload inspection. +- Otherwise the connection is denied. Endpoints without `protocol` or `tls` allow the TCP stream through without inspecting payloads. ## Examples @@ -167,7 +167,7 @@ Allow `pip install` and `uv pip install` to reach PyPI: - { path: /usr/local/bin/uv } ``` -Endpoints without `protocol` or `tls` use L4 passthrough — the proxy allows the TCP stream without inspecting payloads. +Endpoints without `protocol` or `tls` use TCP passthrough — the proxy allows the stream without inspecting payloads. :::: ::::{tab-item} Granular rules @@ -209,13 +209,12 @@ Allow Claude and the GitHub CLI to reach `api.github.com` with per-path rules: r - { path: /usr/bin/gh } ``` -Endpoints with `protocol: rest` and `tls: terminate` enable L7 inspection — the proxy decrypts TLS and checks each HTTP request against the `rules` list. +Endpoints with `protocol: rest` and `tls: terminate` enable HTTP request inspection — the proxy decrypts TLS and checks each HTTP request against the `rules` list. :::: ::::: ## Next Steps -- {doc}`default-policies`: The built-in policy that ships with OpenShell and what each block allows. +- {doc}`index`: The built-in policy that ships with OpenShell and what each block allows. - [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. -- [Safety and Privacy](index.md): Threat scenarios and protection layers. diff --git a/docs/sandboxes/providers.md b/docs/sandboxes/providers.md index f1c3b5089b..c44e1d5908 100644 --- a/docs/sandboxes/providers.md +++ b/docs/sandboxes/providers.md @@ -125,4 +125,4 @@ environment variable names and values yourself with `--credential`. ## Next Steps - {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`../safety-and-privacy/index`: Why credential isolation matters \ No newline at end of file +- {doc}`index`: Why credential isolation matters \ No newline at end of file diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 87d885f856..626e4642db 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -66,7 +66,7 @@ Troubleshoot problems with creating, connecting to, and configuring sandboxes. **Check:** 1. Stream sandbox logs: `nemoclaw logs --tail --source sandbox`. 2. Look for `deny` actions. They include the destination, binary, and reason. -3. Update the policy to allow the blocked endpoint. Refer to [](safety-and-privacy/policies.md). +3. Update the policy to allow the blocked endpoint. Refer to [](sandboxes/policies.md). ### Policy Update Fails From d772b0d1a8b8b358aacd68d8b5e1b1efc0823749 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 22:32:32 -0700 Subject: [PATCH 09/20] removed tutorials --- docs/about/architecture.md | 3 +- .../quickstart.md => about/get-started.md} | 7 +- docs/get-started/run-claude.md | 119 -------- docs/get-started/run-openclaw.md | 101 ------- docs/get-started/run-opencode.md | 256 ------------------ docs/get-started/tutorials.md | 66 ----- docs/index.md | 15 +- docs/sandboxes/index.md | 2 +- 8 files changed, 10 insertions(+), 559 deletions(-) rename docs/{get-started/quickstart.md => about/get-started.md} (92%) delete mode 100644 docs/get-started/run-claude.md delete mode 100644 docs/get-started/run-openclaw.md delete mode 100644 docs/get-started/run-opencode.md delete mode 100644 docs/get-started/tutorials.md diff --git a/docs/about/architecture.md b/docs/about/architecture.md index fa02641a00..2c3f7abb49 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -117,4 +117,5 @@ OpenShell can run locally or on a remote host. The architecture is identical in ## Next Steps -- [Sandbox Policies](../sandboxes/policies.md): Policy structure, network rules, and update workflow. +- [Get Started](get-started.md): Create your first sandbox. +- [Sandboxes](../sandboxes/index.md): Learn how OpenShell enforces isolation across all protection layers. diff --git a/docs/get-started/quickstart.md b/docs/about/get-started.md similarity index 92% rename from docs/get-started/quickstart.md rename to docs/about/get-started.md index f64d14cfa4..9698910329 100644 --- a/docs/get-started/quickstart.md +++ b/docs/about/get-started.md @@ -1,7 +1,7 @@ --- title: - page: "Quickstart" - nav: "Quickstart" + page: "Get Started" + nav: "Get Started" description: "Install the OpenShell CLI and create your first sandboxed AI agent in two commands." keywords: ["nemoclaw install", "quickstart", "sandbox create", "getting started"] topics: ["generative_ai", "cybersecurity"] @@ -17,7 +17,7 @@ content: SPDX-License-Identifier: Apache-2.0 --> -# Quickstart +# Get Started This page gets you from zero to a running, policy-enforced sandbox in two commands. @@ -71,6 +71,5 @@ The `--from` flag pulls a pre-built sandbox definition from the [NemoClaw Commun You now have a working sandbox! From here, you can: -- Follow the [Tutorials](tutorials.md) for step-by-step walkthroughs with Claude Code, OpenClaw, and OpenCode. - Learn how sandboxes work in [Sandboxes](../sandboxes/create-and-manage.md). - Write your own policies in [Customize Sandbox Policies](../sandboxes/policies.md). diff --git a/docs/get-started/run-claude.md b/docs/get-started/run-claude.md deleted file mode 100644 index 967d2ec49d..0000000000 --- a/docs/get-started/run-claude.md +++ /dev/null @@ -1,119 +0,0 @@ - - -# Run Claude Code Safely - -This tutorial walks you through the path to running Claude Code inside a OpenShell sandbox. By the end of this tutorial, you will have an isolated environment with credentials securely injected and a default policy controlling what the agent can access. - -## What You Will Learn - -- Create a sandbox with a single command. -- Understand how OpenShell auto-discovers provider credentials. -- Inspect what the default policy allows and denies. -- Connect to a running sandbox and work inside it. - -## Prerequisites - -- Met the prerequisites and installed the OpenShell CLI as described in the {doc}`quickstart` guide. -- `ANTHROPIC_API_KEY` environment variable set on your host machine. - -## Create the Sandbox - -Run the following command: - -```console -$ nemoclaw sandbox create -- claude -``` - -This single command performs four actions: - -1. Bootstraps the runtime. On first use, the CLI provisions a local k3s cluster inside Docker and deploys the OpenShell control plane. This happens once. Subsequent commands reuse the existing cluster. -2. Auto-discovers credentials. The CLI detects that `claude` is a recognized tool and reads the `ANTHROPIC_API_KEY` environment variable from your shell. It creates a provider automatically. -3. Creates the sandbox. The CLI provisions an isolated container and applies the default policy. This policy allows Claude Code to reach `api.anthropic.com` and a small set of supporting endpoints while blocking everything else. -4. Drops you into the sandbox. You land in an interactive SSH session, ready to work. - -:::{note} -The first bootstrap takes a few minutes depending on your network speed. The CLI prints progress as each component starts. Subsequent sandbox creations are much faster. -::: - -## Work Inside the Sandbox - -You are now inside the sandbox. Start Claude Code: - -```console -$ claude -``` - -Your credentials are available as environment variables. Verify this with: - -```console -$ echo $ANTHROPIC_API_KEY -sk-ant-... -``` - -The sandbox provides a working directory at `/sandbox` where you can create and edit files. Standard development tools — git, common language runtimes, and package managers — are available within the boundaries set by the policy. - -## Check Sandbox Status - -Open a second terminal on your host machine to inspect the sandbox from outside. - -1. In the second terminal, list all sandboxes: - - ```console - $ nemoclaw sandbox list - ``` - -2. Launch the OpenShell Terminal for a live dashboard that shows sandbox status, active network connections, and policy decisions in real time: - - ```console - $ nemoclaw term - ``` - -## Connect from VS Code (Optional) - -If you prefer a graphical editor, connect to the sandbox with VS Code Remote-SSH. - -Export the sandbox SSH configuration: - -```console -$ nemoclaw sandbox ssh-config >> ~/.ssh/config -``` - -Then open VS Code, install the Remote - SSH extension if needed, and connect to the host named after your sandbox. VS Code opens a full editor session inside the isolated environment. - -:::{tip} -Replace `` with your sandbox name. Run `nemoclaw sandbox list` to find it if you did not specify one at creation time. -::: - -## Clean Up - -Exit the sandbox shell: - -```console -$ exit -``` - -Delete the sandbox: - -```console -$ nemoclaw sandbox delete -``` - -:::{tip} -If you want the sandbox to persist after you disconnect, add the `--keep` flag at creation time: - -```console -$ nemoclaw sandbox create --keep -- claude -``` - -This is useful when you plan to reconnect later or iterate on the policy while the sandbox runs. -::: - -## Next Steps - -- {doc}`../sandboxes/create-and-manage`: Learn the isolation model and sandbox lifecycle. -- {doc}`../sandboxes/providers`: Understand how credentials are injected without exposing them to agent code. -- {doc}`../sandboxes/policies`: Customize the default policy or write your own. -- {doc}`../sandboxes/index`: Explore the built-in default policy and agent compatibility. diff --git a/docs/get-started/run-openclaw.md b/docs/get-started/run-openclaw.md deleted file mode 100644 index a27fc2974f..0000000000 --- a/docs/get-started/run-openclaw.md +++ /dev/null @@ -1,101 +0,0 @@ - - -# Run OpenClaw Safely - -This tutorial shows you how to launch a sandbox with OpenClaw from the [NemoClaw Community catalog](https://github.com/NVIDIA/NemoClaw-Community) using the `--from` flag. This is a pre-built sandbox configuration that includes a container image, a tailored policy, and optional skills. - -## What You Will Learn - -- Understand what community sandboxes are and how they differ from default sandboxes. -- Use the `--from` flag to pull and build a complete sandbox configuration. -- Inspect the bundled policy that ships with a community sandbox. - -## Prerequisites - -- Met the prerequisites and installed the OpenShell CLI as described in the {doc}`quickstart` guide. -- NVIDIA GPU with drivers installed. OpenClaw requires GPU acceleration. - -## Create the Sandbox - -Run the following command: - -```console -$ nemoclaw sandbox create --from openclaw --keep -``` - -The `--from` flag tells the CLI to pull a sandbox definition from the OpenShell Community catalog. Here is what happens behind the scenes: - -1. Fetches the definition. The CLI downloads the OpenClaw sandbox definition from the OpenShell-Community repository. This includes a Dockerfile, a policy YAML, and any bundled skills. -2. Builds the image. The CLI builds the Dockerfile locally using Docker. The resulting image includes all tools and dependencies that OpenClaw needs. -3. Applies the bundled policy. Instead of the generic default policy, the sandbox starts with a policy written specifically for the OpenClaw workload. It allows the endpoints and binaries that OpenClaw requires. -4. Creates and keeps the sandbox. The `--keep` flag ensures the sandbox stays running after creation so you can connect and disconnect freely. - -:::{note} -The first build takes longer because Docker needs to pull base layers and install dependencies. Subsequent creates reuse the cached image. -::: - -## Connect to the Sandbox - -After creation completes, connect to the running sandbox: - -```console -$ nemoclaw sandbox connect -``` - -Replace `` with the sandbox name shown in the creation output. If you did not specify a name with `--name`, the CLI assigns one automatically. Run `nemoclaw sandbox list` to find it. - -## Explore the Environment - -The sandbox comes pre-configured for the OpenClaw workload. The tools, runtimes, and libraries that OpenClaw needs are already installed in the container image. The policy is tuned to allow the specific network endpoints and operations that OpenClaw uses, so you can start working immediately without policy adjustments. - -## Inspect the Bundled Policy - -To see exactly what the sandbox is allowed to do, pull the full policy: - -```console -$ nemoclaw policy get --full -``` - -This outputs the complete policy YAML. Review it to understand the sandbox's permissions: - -- Network policies, which hosts and ports the sandbox can reach, and which binaries are allowed to initiate those connections. -- Filesystem policy, which paths are read-only and which are read-write. -- Process restrictions, which user and group the sandbox runs as. -- Inference rules, which inference routing hints are allowed. - -Reviewing the bundled policy is a good practice before you use a community sandbox for sensitive work. - -:::{tip} -Save the policy to a file for reference or as a starting point for customization: - -```console -$ nemoclaw policy get --full > openclaw-policy.yaml -``` -::: - -## Clean Up - -Exit the sandbox if you are connected: - -```console -$ exit -``` - -Delete the sandbox: - -```console -$ nemoclaw sandbox delete -``` - -:::{note} -The OpenShell Community repository accepts contributions. If you build a sandbox configuration that would be useful to others, submit it to the [NemoClaw-Community](https://github.com/NVIDIA/NemoClaw-Community) repository. -::: - -## Next Steps - -- {doc}`../sandboxes/community-sandboxes`: Full reference on community sandbox definitions, available images, and how to contribute your own. -- {doc}`../sandboxes/policies`: Learn the policy format and how to customize what a sandbox can do. -- {doc}`../sandboxes/create-and-manage`: Understand the isolation model and lifecycle behind every sandbox. diff --git a/docs/get-started/run-opencode.md b/docs/get-started/run-opencode.md deleted file mode 100644 index 8c2b0e0ee5..0000000000 --- a/docs/get-started/run-opencode.md +++ /dev/null @@ -1,256 +0,0 @@ - - -# Run OpenCode with NVIDIA Inference - -This tutorial walks you through a realistic setup where you run [OpenCode](https://opencode.ai) inside an OpenShell sandbox and configure private inference through `inference.local`. Along the way, you will hit a policy denial, diagnose it from logs, write a custom policy, and configure inference routing. This is the full policy iteration loop that you will use whenever you onboard a new tool. - -## What You Will Learn - -- Create a provider manually using the `--from-existing` flag. -- Write a custom policy to replace the default policy. -- Read sandbox logs to diagnose denied actions. -- Distinguish between agent traffic and sandbox inference traffic. -- Configure inference routing for code running inside the sandbox. - -## Prerequisites - -- Met the prerequisites and installed the OpenShell CLI as described in the {doc}`quickstart` guide. -- `NVIDIA_API_KEY` environment variable set on your host machine with a valid NVIDIA API key. - -## Create the Provider - -In the Claude Code tutorial, the CLI auto-discovers credentials. Here you create a provider explicitly, which gives you control over the provider name and type. - -```console -$ nemoclaw provider create --name nvidia --type nvidia --from-existing -``` - -The `--from-existing` flag tells the CLI to discover credentials from your local environment. It finds `NVIDIA_API_KEY` and stores it securely. The provider is now available to attach to any sandbox. - -Verify the provider exists: - -```console -$ nemoclaw provider list -``` - -## Create the Sandbox - -Create a sandbox with the NVIDIA provider attached and OpenCode as the startup command: - -```console -$ nemoclaw sandbox create --name opencode-sandbox --provider nvidia --keep -- opencode -``` - -The `--keep` flag keeps the sandbox alive after you exit, which you need for the iteration steps ahead. The CLI creates the sandbox with the default policy, injects the NVIDIA credentials, and starts OpenCode. - -## Hit a Policy Denial - -Try using OpenCode inside the sandbox. You will find that calls to NVIDIA inference endpoints fail. The default policy is designed around Claude Code, not OpenCode, so the required endpoints are not allowlisted. - -Open a second terminal and check the logs: - -```console -$ nemoclaw logs opencode-sandbox --tail -``` - -Alternatively, launch the OpenShell Terminal for a live view: - -```console -$ nemoclaw term -``` - -Look for lines like these: - -```text -action=deny host=integrate.api.nvidia.com binary=/usr/local/bin/opencode reason="no matching network policy" -action=deny host=opencode.ai binary=/usr/bin/node reason="no matching network policy" -``` - -Each log entry tells you the exact host, binary, and reason for the denial. - -## Understand the Denial - -The default policy contains a `nvidia_inference` network policy entry, but it is configured for a narrow set of binaries - typically `/usr/local/bin/claude` and `/usr/bin/node`. When OpenCode makes HTTP calls through its own binary, `curl`, or a shell subprocess, those connections do not match any policy rule and get denied. - -Two separate problems are at play: - -- OpenCode's own traffic. OpenCode contacts `opencode.ai` for its API and `integrate.api.nvidia.com` for inference. Neither endpoint has a matching rule for the binaries OpenCode uses. -- Missing endpoint. The default policy has no entry for `opencode.ai` at all. Even if the binary matched, the destination is not listed. - -This is expected behavior. OpenShell denies everything by default. You need to write a policy that explicitly allows what OpenCode needs. - -## Write a Custom Policy - -Create a file called `opencode-policy.yaml` with the following content: - -```yaml -version: 1 -filesystem_policy: - include_workdir: true - read_only: - - /usr - - /lib - - /proc - - /dev/urandom - - /app - - /etc - - /var/log - read_write: - - /sandbox - - /tmp - - /dev/null -landlock: - compatibility: best_effort -process: - run_as_user: sandbox - run_as_group: sandbox -network_policies: - opencode_api: - name: opencode-api - endpoints: - - host: opencode.ai - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/local/bin/opencode - - path: /usr/bin/node - nvidia_inference: - name: nvidia-inference - endpoints: - - host: integrate.api.nvidia.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/local/bin/opencode - - path: /usr/bin/node - - path: /usr/bin/curl - - path: /bin/bash - npm_registry: - name: npm-registry - endpoints: - - host: registry.npmjs.org - port: 443 - binaries: - - path: /usr/bin/npm - - path: /usr/bin/node - - path: /usr/local/bin/npm - - path: /usr/local/bin/node - github_rest_api: - name: github-rest-api - endpoints: - - host: api.github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: read-only - binaries: - - path: /usr/local/bin/opencode - - path: /usr/bin/node - - path: /usr/bin/gh - github_ssh_over_https: - name: github-ssh-over-https - endpoints: - - host: github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - rules: - - allow: - method: GET - path: "/**/info/refs*" - - allow: - method: POST - path: "/**/git-upload-pack" - binaries: - - path: /usr/bin/git -``` - -This policy differs from the default in three key ways: - -- `opencode_api`: Allows OpenCode and Node.js to reach `opencode.ai:443`. -- Broader `nvidia_inference` binaries: Adds `/usr/local/bin/opencode`, `/usr/bin/curl`, and `/bin/bash` so OpenCode's subprocesses can reach the NVIDIA endpoint. -- GitHub access: Scoped to support OpenCode's git operations. - -:::{warning} -The `filesystem_policy`, `landlock`, and `process` sections are static. They are set at sandbox creation time and cannot be changed on a running sandbox. To modify these, delete and recreate the sandbox. The `network_policies` section is dynamic and can be hot-reloaded. -::: - -## Apply the Policy - -Push your custom policy to the running sandbox: - -```console -$ nemoclaw policy set opencode-sandbox --policy opencode-policy.yaml --wait -``` - -The `--wait` flag blocks until the sandbox confirms the policy is loaded. - -Verify the policy revision was accepted: - -```console -$ nemoclaw policy list opencode-sandbox -``` - -The latest revision should show status `loaded`. - -## Configure Inference Routing - -So far, you have allowed the OpenCode *agent* to reach `integrate.api.nvidia.com` directly through network policy. But code that OpenCode writes and runs inside the sandbox should use `https://inference.local`. - -Configure inference so `inference.local` routes to your NVIDIA provider: - -```console -$ nemoclaw inference set \ - --provider nvidia \ - --model z-ai/glm5 -``` - -Verify the active configuration: - -```console -$ nemoclaw inference get -``` - -:::{note} -*Network policies* and managed inference are two separate enforcement points. Network policies control which external hosts the agent binary can reach directly. Inference configuration controls where userland calls to `https://inference.local` are routed. -::: - -## Verify the Policy - -Tail the logs again: - -```console -$ nemoclaw logs opencode-sandbox --tail -``` - -You should see `action=allow` lines for the endpoints you added. Connections to `opencode.ai`, `integrate.api.nvidia.com`, and GitHub should show `action=allow`. - -To verify userland inference, run code inside the sandbox that targets `https://inference.local/v1`. - -If you still see denials, read the log line carefully. It tells you the exact host, port, and binary that was blocked. Add the missing entry to your policy and push again with `nemoclaw policy set`. This observe-modify-push cycle is the normal workflow for onboarding any new tool in OpenShell. - -## Clean Up - -When you are finished, delete the sandbox: - -```console -$ nemoclaw sandbox delete opencode-sandbox -``` - -## Next Steps - -- {doc}`../sandboxes/policies`: Policy structure, network rules, and the sandbox iteration workflow. -- {doc}`../inference/index`: `inference.local`, supported API patterns, and request routing. -- {doc}`../sandboxes/providers`: Provider types, credential discovery, and manual and automatic creation. -- {doc}`../sandboxes/index`: The protection layers and how they interact. diff --git a/docs/get-started/tutorials.md b/docs/get-started/tutorials.md deleted file mode 100644 index c95cae8a3b..0000000000 --- a/docs/get-started/tutorials.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: - page: "NemoClaw Tutorials" - nav: "Tutorials" -description: "Step-by-step tutorials for running AI agents inside OpenShell sandboxes." -keywords: ["nemoclaw tutorials", "claude code sandbox", "opencode sandbox", "openclaw sandbox"] -topics: ["generative_ai", "cybersecurity"] -tags: ["ai_agents", "sandboxing", "tutorial"] -content: - type: tutorial - difficulty: technical_beginner - audience: [engineer, data_scientist] ---- - - - -# Tutorials - -Each tutorial below walks you through running a specific AI agent inside a OpenShell sandbox. Choose the tutorial that matches your agent. - -::::{grid} 1 1 2 2 -:gutter: 3 - -:::{grid-item-card} Run Claude Code Safely -:link: run-claude -:link-type: doc - -Create a sandbox with Claude Code. - -+++ -{bdg-secondary}`Tutorial` -::: - -:::{grid-item-card} Run OpenClaw Safely -:link: run-openclaw -:link-type: doc - -Launch a sandbox with OpenClaw from the OpenShell Community catalog using the `--from` flag. - -+++ -{bdg-secondary}`Tutorial` -::: - -:::{grid-item-card} Run OpenCode with NVIDIA Inference -:link: run-opencode -:link-type: doc - -Launch a sandbox with OpenCode with NVIDIA inference routed to NVIDIA API endpoints. - -+++ -{bdg-secondary}`Tutorial` -::: - -:::: - -```{toctree} -:hidden: -:maxdepth: 2 - -Run Claude Code Safely -Run OpenClaw Safely -Run OpenCode with NVIDIA Inference -``` diff --git a/docs/index.md b/docs/index.md index 6b9f3b0bd1..c2e0bbea63 100644 --- a/docs/index.md +++ b/docs/index.md @@ -103,7 +103,7 @@ Install the CLI and create your first sandbox in two commands. ``` -Refer to the [Quickstart](get-started/quickstart.md) for more details. +Refer to the [Get Started](about/get-started.md) for more details. --- @@ -123,10 +123,10 @@ Learn about OpenShell and its capabilities. ::: :::{grid-item-card} Get Started -:link: get-started/quickstart +:link: about/get-started :link-type: doc -Quickstart guide and tutorials for creating a OpenShell sandbox with Claude Code, OpenClaw, and OpenCode. +Quickstart guide for creating an OpenShell sandbox with Claude Code, OpenClaw, and OpenCode. +++ {bdg-secondary}`Tutorial` @@ -186,17 +186,10 @@ Home Overview How It Works +Get Started Release Notes ``` -```{toctree} -:caption: Get Started -:hidden: - -get-started/quickstart -get-started/tutorials -``` - ```{toctree} :caption: Sandboxes :hidden: diff --git a/docs/sandboxes/index.md b/docs/sandboxes/index.md index ac83917d7d..2a4680ad98 100644 --- a/docs/sandboxes/index.md +++ b/docs/sandboxes/index.md @@ -34,7 +34,7 @@ The following table shows the coverage of the default policy for common agents. | Agent | Coverage | Action Required | |---|---|---| | Claude Code | Full | None. Works out of the box. | -| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. See [Run OpenCode with NVIDIA Inference](../get-started/run-opencode.md). | +| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. | | Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | :::{important} From 3f102bdf1886f559b48f1efe099b0d9ed3e81021 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 23:03:27 -0700 Subject: [PATCH 10/20] Added tutorial --- docs/about/architecture.md | 2 +- docs/about/get-started.md | 11 +- docs/about/overview.md | 2 +- docs/index.md | 33 +-- docs/inference/configure.md | 4 +- docs/inference/index.md | 6 +- docs/reference/default-policy.md | 16 ++ docs/sandboxes/community-sandboxes.md | 4 +- docs/sandboxes/create-and-manage.md | 24 ++- docs/sandboxes/index.md | 87 +++++--- docs/sandboxes/policies.md | 62 +----- docs/sandboxes/providers.md | 7 +- docs/tutorials/github-sandbox.md | 300 ++++++++++++++++++++++++++ docs/tutorials/index.md | 29 +++ 14 files changed, 473 insertions(+), 114 deletions(-) create mode 100644 docs/tutorials/github-sandbox.md create mode 100644 docs/tutorials/index.md diff --git a/docs/about/architecture.md b/docs/about/architecture.md index 2c3f7abb49..0eda981a0a 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -117,5 +117,5 @@ OpenShell can run locally or on a remote host. The architecture is identical in ## Next Steps -- [Get Started](get-started.md): Create your first sandbox. +- [Quickstart](get-started.md): Create your first sandbox. - [Sandboxes](../sandboxes/index.md): Learn how OpenShell enforces isolation across all protection layers. diff --git a/docs/about/get-started.md b/docs/about/get-started.md index 9698910329..c7a9f31ab1 100644 --- a/docs/about/get-started.md +++ b/docs/about/get-started.md @@ -1,7 +1,7 @@ --- title: - page: "Get Started" - nav: "Get Started" + page: "Quickstart" + nav: "Quickstart" description: "Install the OpenShell CLI and create your first sandboxed AI agent in two commands." keywords: ["nemoclaw install", "quickstart", "sandbox create", "getting started"] topics: ["generative_ai", "cybersecurity"] @@ -17,7 +17,7 @@ content: SPDX-License-Identifier: Apache-2.0 --> -# Get Started +# Quickstart This page gets you from zero to a running, policy-enforced sandbox in two commands. @@ -71,5 +71,6 @@ The `--from` flag pulls a pre-built sandbox definition from the [NemoClaw Commun You now have a working sandbox! From here, you can: -- Learn how sandboxes work in [Sandboxes](../sandboxes/create-and-manage.md). -- Write your own policies in [Customize Sandbox Policies](../sandboxes/policies.md). +- **Follow a guided tutorial** — set up scoped GitHub repo access in {doc}`/tutorials/github-sandbox`. +- **Learn how sandboxes work** — see {doc}`/sandboxes/create-and-manage` for the full lifecycle. +- **Write your own policies** — see {doc}`/sandboxes/policies` for custom access rules. diff --git a/docs/about/overview.md b/docs/about/overview.md index 92cf7bbf5d..e28350953e 100644 --- a/docs/about/overview.md +++ b/docs/about/overview.md @@ -61,5 +61,5 @@ For details, refer to [Built-in Default Policy](../sandboxes/index.md#built-in-d ## Next Steps - [Architecture Overview](architecture.md): Understand the components that make up the OpenShell runtime. -- [Get Started](../index.md): Install the CLI and create your first sandbox. +- [Quickstart](get-started.md): Install the CLI and create your first sandbox. - [Sandboxes](../sandboxes/index.md): Learn how OpenShell enforces isolation across all protection layers. diff --git a/docs/index.md b/docs/index.md index c2e0bbea63..8299159086 100644 --- a/docs/index.md +++ b/docs/index.md @@ -103,7 +103,7 @@ Install the CLI and create your first sandbox in two commands. ``` -Refer to the [Get Started](about/get-started.md) for more details. +Refer to the [Quickstart](about/get-started.md) for more details. --- @@ -122,34 +122,34 @@ Learn about OpenShell and its capabilities. {bdg-secondary}`Concept` ::: -:::{grid-item-card} Get Started +:::{grid-item-card} Quickstart :link: about/get-started :link-type: doc -Quickstart guide for creating an OpenShell sandbox with Claude Code, OpenClaw, and OpenCode. +Install the CLI and create your first sandbox in two commands. +++ {bdg-secondary}`Tutorial` ::: -:::{grid-item-card} Sandboxes -:link: sandboxes/index +:::{grid-item-card} Tutorials +:link: tutorials/index :link-type: doc -Create, manage, and customize sandboxes. Use community images or bring your own container. +End-to-end guides: GitHub repo access, custom policies, and more. +++ -{bdg-secondary}`Concept` +{bdg-secondary}`Tutorial` ::: -:::{grid-item-card} Sandbox Policies -:link: sandboxes/policies +:::{grid-item-card} Sandboxes +:link: sandboxes/index :link-type: doc -Customize sandbox policies and configure network access rules. +Create, manage, and customize sandboxes. Configure policies, providers, and community images. +++ -{bdg-secondary}`How-To` +{bdg-secondary}`Concept` ::: :::{grid-item-card} Inference Routing @@ -186,18 +186,25 @@ Home Overview How It Works -Get Started Release Notes ``` +```{toctree} +:caption: Get Started +:hidden: + +Quickstart +tutorials/index +``` + ```{toctree} :caption: Sandboxes :hidden: sandboxes/index sandboxes/create-and-manage -sandboxes/policies sandboxes/providers +sandboxes/policies sandboxes/community-sandboxes ``` diff --git a/docs/inference/configure.md b/docs/inference/configure.md index b6a87f8e4c..5e260e6b24 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -24,7 +24,7 @@ Create a provider that holds the backend credentials you want OpenShell to use. $ nemoclaw provider create --name nvidia-prod --type nvidia --from-existing ``` -You can also use `openai` or `anthropic` providers. +You can also use `openai` or `anthropic` providers types. ## Step 2: Set Inference Routing @@ -93,7 +93,7 @@ security reasons. External providers that should be reached directly belong in ## Next Steps - {doc}`index`: understand the interception flow and supported API patterns. -- [Network Access Rules](/sandboxes/policies.md#network-access-rules): +- [Network Access Rules](/sandboxes/index.md#network-access-rules): configure direct access to external inference endpoints. - {doc}`../sandboxes/providers`: create and manage provider records. - {doc}`../reference/cli`: see the CLI reference for `nemoclaw inference` diff --git a/docs/inference/index.md b/docs/inference/index.md index ee32f56323..865650847f 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -18,7 +18,7 @@ If sandbox code calls an external inference API like `api.openai.com` or request. It is allowed or denied by `network_policies`. Refer to {doc}`/sandboxes/policies` and the -[Network Access Rules](/sandboxes/policies.md#network-access-rules) +[Network Access Rules](/sandboxes/index.md#network-access-rules) section for details. ## `inference.local` @@ -32,7 +32,7 @@ privacy and security reasons. ## Using `inference.local` -When code inside a sandbox calls `https://inference.local`, OpenShell routes the +When code inside a sandbox calls `https://inference.local`, the {doc}`privacy router ` routes the request to the configured backend for that gateway. The configured model is applied to generation requests, and provider @@ -80,5 +80,5 @@ supported patterns are denied. ## Next Steps - {doc}`configure`: configure the backend behind `inference.local`. -- [Network Access Rules](/sandboxes/policies.md#network-access-rules): +- [Network Access Rules](/sandboxes/index.md#network-access-rules): understand how external endpoints are controlled. diff --git a/docs/reference/default-policy.md b/docs/reference/default-policy.md index 3dee90189e..e64986b92e 100644 --- a/docs/reference/default-policy.md +++ b/docs/reference/default-policy.md @@ -2,6 +2,22 @@ The default policy is the policy applied when you create an OpenShell sandbox without `--policy`. It is defined in the [`deploy/docker/sandbox/dev-sandbox-policy.yaml`](https://github.com/NVIDIA/NemoClaw/blob/main/deploy/docker/sandbox/dev-sandbox-policy.yaml) file. +## Agent Compatibility + +The following table shows the coverage of the default policy for common agents. + +| Agent | Coverage | Action Required | +|---|---|---| +| Claude Code | Full | None. Works out of the box. | +| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. | +| Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | + +:::{important} +If you run a non-Claude agent without a custom policy, the agent's API calls are denied by the proxy. You must provide a policy that declares the agent's endpoints and binaries. +::: + +## Default Policy Blocks + The following tables show the default policy blocks pre-configured in the file. ```{policy-table} deploy/docker/sandbox/dev-sandbox-policy.yaml diff --git a/docs/sandboxes/community-sandboxes.md b/docs/sandboxes/community-sandboxes.md index 2c0c04e5ab..33241fd667 100644 --- a/docs/sandboxes/community-sandboxes.md +++ b/docs/sandboxes/community-sandboxes.md @@ -90,5 +90,5 @@ or anything else), consider contributing it back so others can use it. ## Next Steps -- {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`policies`: Customize the policy applied to any sandbox +- **Need to supply API keys or tokens?** Set up {doc}`providers` for credential management. +- **Want to customize the sandbox policy?** Write custom rules in {doc}`policies`. diff --git a/docs/sandboxes/create-and-manage.md b/docs/sandboxes/create-and-manage.md index 92655d3086..91b8b614c3 100644 --- a/docs/sandboxes/create-and-manage.md +++ b/docs/sandboxes/create-and-manage.md @@ -47,6 +47,23 @@ This is especially useful when you are iterating on a policy or want to reconnect later from another terminal or VS Code. ::: +## Create from a Community Sandbox or Custom Image + +Use `--from` to create a sandbox from a pre-built community package, a local directory, or a container image: + +```console +$ nemoclaw sandbox create --from openclaw +``` + +The CLI resolves the name against the [NemoClaw Community](https://github.com/NVIDIA/NemoClaw-Community) catalog, pulls the bundled Dockerfile and policy, builds the image locally, and creates the sandbox. For the full catalog and how to contribute your own, refer to {doc}`community-sandboxes`. + +You can also point `--from` at a local directory or a container image reference: + +```console +$ nemoclaw sandbox create --from ./my-sandbox-dir +$ nemoclaw sandbox create --from my-registry.example.com/my-image:latest +``` + ## List and Inspect Sandboxes Check the status of your sandboxes and retrieve detailed information about individual ones. @@ -143,6 +160,7 @@ $ nemoclaw sandbox delete my-sandbox ## Next Steps -- {doc}`community-sandboxes`: Use pre-built sandboxes from the community catalog -- {doc}`providers`: Create and attach credential providers -- {doc}`policies`: Control what the agent can access \ No newline at end of file +- **Want a complete end-to-end example?** Follow the {doc}`/tutorials/github-sandbox` tutorial. +- **Need to supply API keys or tokens?** Set up {doc}`providers` for credential management. +- **Want to control what the agent can access?** Write a custom policy in {doc}`policies`. +- **Want a pre-built environment?** Browse the {doc}`community-sandboxes` catalog. \ No newline at end of file diff --git a/docs/sandboxes/index.md b/docs/sandboxes/index.md index 2a4680ad98..9261a3e7f7 100644 --- a/docs/sandboxes/index.md +++ b/docs/sandboxes/index.md @@ -5,7 +5,7 @@ # About Sandboxes -An OpenShell sandbox is a safe, private execution environment for an AI agent. Each sandbox runs inside a Kubernetes pod with multiple layers of protection that prevent unauthorized data access, credential exposure, and network exfiltration. Protection layers include filesystem restrictions (Landlock), system call filtering (seccomp), network namespace isolation, and a privacy-enforcing HTTP CONNECT proxy. +An OpenShell sandbox is a safe, private execution environment for an AI agent. Each sandbox runs with multiple layers of protection that prevent unauthorized data access, credential exposure, and network exfiltration. Protection layers include filesystem restrictions (Landlock), system call filtering (seccomp), network namespace isolation, and a privacy-enforcing HTTP CONNECT proxy. ## Sandbox Lifecycle @@ -20,38 +20,73 @@ Every sandbox moves through a defined set of phases: ## Built-in Default Policy -NVIDIA OpenShell ships a built-in policy that covers common agent workflows out of the box. -When you create a sandbox without `--policy`, OpenShell applies the default policy. This policy controls three things: +OpenShell ships a built-in policy that covers common agent workflows out of the box. +When you create a sandbox without `--policy`, the default policy is applied. It controls three things: -- What the agent can access on disk. Filesystem paths are split into read-only and read-write sets. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. -- What the agent can reach on the network. Each network policy block pairs a set of allowed destinations (host and port) with a set of allowed binaries (executable paths inside the sandbox). The proxy resolves every outbound connection to the binary that opened it. A connection is allowed only when both the destination and the calling binary match an entry in the same block. Everything else is denied. -- What privileges the agent has. The agent runs as an unprivileged user with seccomp filters that block dangerous system calls. There is no `sudo`, no `setuid`, and no path to elevated privileges. +| Layer | What It Controls | How It Works | +|---|---|---| +| Filesystem | What the agent can access on disk | Paths are split into read-only and read-write sets. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. | +| Network | What the agent can reach on the network | Each policy block pairs allowed destinations (host and port) with allowed binaries (executable paths). The proxy matches every outbound connection to the binary that opened it. Both must match or the connection is denied. | +| Process | What privileges the agent has | The agent runs as an unprivileged user with seccomp filters that block dangerous system calls. No `sudo`, no `setuid`, no path to elevated privileges. | -### Agent Compatibility +For the full breakdown of each default policy block and agent compatibility details, see {doc}`../reference/default-policy`. -The following table shows the coverage of the default policy for common agents. +## Policy Structure -| Agent | Coverage | Action Required | -|---|---|---| -| Claude Code | Full | None. Works out of the box. | -| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. | -| Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | +A policy has static sections (`filesystem_policy`, `landlock`, `process`) that are locked at sandbox creation, and dynamic sections (`network_policies`, `inference`) that are hot-reloadable on a running sandbox. + +```yaml +version: 1 + +# Static: locked at sandbox creation. Paths the agent can read vs read/write. +filesystem_policy: + read_only: [/usr, /lib, /etc] + read_write: [/sandbox, /tmp] + +# Static: Landlock LSM kernel enforcement. best_effort uses highest ABI the host supports. +landlock: + compatibility: best_effort + +# Static: Unprivileged user/group the agent process runs as. +process: + run_as_user: sandbox + run_as_group: sandbox + +# Dynamic: hot-reloadable. Named blocks of endpoints + binaries allowed to reach them. +network_policies: + my_api: + name: my-api + endpoints: + - host: api.example.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + access: full + binaries: + - path: /usr/bin/curl + +# Dynamic: hot-reloadable. Routing hints this sandbox can use for inference (e.g. local, nvidia). +inference: + allowed_routes: [local] +``` + +For the complete structure and every field, see the [Policy Schema Reference](../reference/policy-schema.md). + +## Network Access Rules -:::{important} -If you run a non-Claude agent without a custom policy, the agent's API calls are denied by the proxy. You must provide a policy that declares the agent's endpoints and binaries. -::: +Network access is controlled by policy blocks under `network_policies`. Each block has a **name**, a list of **endpoints** (host, port, protocol, and optional rules), and a list of **binaries** that are allowed to use those endpoints. -### What the Default Policy Allows +Every outbound connection from the sandbox goes through the proxy: -The default policy defines six network policy blocks, plus filesystem isolation, Landlock enforcement, and process identity. For the full breakdown of each block, see {doc}`../reference/default-policy`. +- The proxy queries the {doc}`policy engine <../about/architecture>` with the **destination** (host and port) and the **calling binary**. A connection is allowed only when both match an entry in the same policy block. +- For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is checked against that endpoint's `rules` (method and path). +- If no endpoint matches and inference routes are configured, the request may be rerouted for inference. +- Otherwise the connection is denied. Endpoints without `protocol` or `tls` allow the TCP stream through without inspecting payloads. ## Next Steps -- {doc}`create-and-manage`: Create, inspect, connect, monitor, and delete - sandboxes. -- {doc}`policies`: Write custom policies, configure network rules, and iterate on a running sandbox. -- {doc}`providers`: Create and attach credential providers so agents can - authenticate with external services. -- {doc}`community-sandboxes`: Use pre-built sandboxes from the community - catalog. -- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. +- **Ready to create your first sandbox?** Start with {doc}`create-and-manage`. +- **Need to supply API keys or tokens?** Set up {doc}`providers` before creating. +- **Want to control what the agent can access?** Write a custom policy in {doc}`policies`. +- **Want a pre-built environment?** Browse the {doc}`community-sandboxes` catalog. diff --git a/docs/sandboxes/policies.md b/docs/sandboxes/policies.md index 31fd16fa38..02530c3df3 100644 --- a/docs/sandboxes/policies.md +++ b/docs/sandboxes/policies.md @@ -91,59 +91,6 @@ When triaging denied requests, check: Then push the updated policy as described above. -## Policy Structure - -A policy has static sections (`filesystem_policy`, `landlock`, `process`) that are locked at sandbox creation, and dynamic sections (`network_policies`, `inference`) that are hot-reloadable on a running sandbox. - -```yaml -version: 1 - -# Static: locked at sandbox creation. Paths the agent can read vs read/write. -filesystem_policy: - read_only: [/usr, /lib, /etc] - read_write: [/sandbox, /tmp] - -# Static: Landlock LSM kernel enforcement. best_effort uses highest ABI the host supports. -landlock: - compatibility: best_effort - -# Static: Unprivileged user/group the agent process runs as. -process: - run_as_user: sandbox - run_as_group: sandbox - -# Dynamic: hot-reloadable. Named blocks of endpoints + binaries allowed to reach them. -network_policies: - my_api: - name: my-api - endpoints: - - host: api.example.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/bin/curl - -# Dynamic: hot-reloadable. Routing hints this sandbox can use for inference (e.g. local, nvidia). -inference: - allowed_routes: [local] -``` - -For the complete structure and every field, see the [Policy Schema Reference](../reference/policy-schema.md). - -## Network Access Rules - -Network access is controlled by policy blocks under `network_policies`. Each block has a **name**, a list of **endpoints** (host, port, protocol, and optional rules), and a list of **binaries** that are allowed to use those endpoints. - -Every outbound connection from the sandbox goes through the proxy: - -- The proxy matches the **destination** (host and port) and the **calling binary** to an endpoint in one of your policy blocks. A connection is allowed only when both match. -- For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is checked against that endpoint's `rules` (method and path). -- If no endpoint matches and inference routes are configured, the request may be rerouted for inference. -- Otherwise the connection is denied. Endpoints without `protocol` or `tls` allow the TCP stream through without inspecting payloads. - ## Examples Add these blocks to the `network_policies` section of your sandbox policy. Apply with `openshell policy set --policy --wait`. @@ -173,6 +120,10 @@ Endpoints without `protocol` or `tls` use TCP passthrough — the proxy allows t ::::{tab-item} Granular rules Allow Claude and the GitHub CLI to reach `api.github.com` with per-path rules: read-only (GET, HEAD, OPTIONS) and GraphQL (POST) for all paths; full write access for `alpha-repo`; and create/edit issues only for `bravo-repo`. Replace `` with your GitHub org or username. +:::{tip} +For an end-to-end walkthrough that combines this policy with a GitHub credential provider and sandbox creation, see {doc}`/tutorials/github-sandbox`. +::: + ```yaml github_repos: name: github_repos @@ -216,5 +167,6 @@ Endpoints with `protocol: rest` and `tls: terminate` enable HTTP request inspect ## Next Steps -- {doc}`index`: The built-in policy that ships with OpenShell and what each block allows. -- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. +- **New to policies?** Read about {doc}`policy structure and network access rules ` first. +- **Need the full field reference?** See the [Policy Schema Reference](../reference/policy-schema.md). +- **Looking for the default policy breakdown?** See {doc}`../reference/default-policy`. diff --git a/docs/sandboxes/providers.md b/docs/sandboxes/providers.md index c44e1d5908..ea15deb74a 100644 --- a/docs/sandboxes/providers.md +++ b/docs/sandboxes/providers.md @@ -111,7 +111,7 @@ The following provider types are supported. | `claude` | `ANTHROPIC_API_KEY`, `CLAUDE_API_KEY` | Claude Code, Anthropic API | | `codex` | `OPENAI_API_KEY` | OpenAI Codex | | `opencode` | `OPENCODE_API_KEY`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY` | opencode tool | -| `github` | `GITHUB_TOKEN`, `GH_TOKEN` | GitHub API, `gh` CLI | +| `github` | `GITHUB_TOKEN`, `GH_TOKEN` | GitHub API, `gh` CLI — see {doc}`/tutorials/github-sandbox` | | `gitlab` | `GITLAB_TOKEN`, `GLAB_TOKEN`, `CI_JOB_TOKEN` | GitLab API, `glab` CLI | | `nvidia` | `NVIDIA_API_KEY` | NVIDIA API Catalog | | `generic` | User-defined | Any service with custom credentials | @@ -124,5 +124,6 @@ environment variable names and values yourself with `--credential`. ## Next Steps -- {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`index`: Why credential isolation matters \ No newline at end of file +- **Want to control what the agent can access?** Write a custom policy in {doc}`policies`. +- **Looking for a pre-built environment?** Browse the {doc}`community-sandboxes` catalog. +- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. \ No newline at end of file diff --git a/docs/tutorials/github-sandbox.md b/docs/tutorials/github-sandbox.md new file mode 100644 index 0000000000..3e50bde572 --- /dev/null +++ b/docs/tutorials/github-sandbox.md @@ -0,0 +1,300 @@ + + +# Set Up a Sandbox with GitHub Repo Access + +Agents often need to work across multiple repositories with different levels of trust. An agent might need full read-write access to a feature repo where it commits code, but only read access to a shared library repo that it references without modifying. OpenShell policies let you express this distinction — the agent can clone and push to one repo while treating another as a read-only dependency. + +This tutorial sets up exactly that scenario: + +- **alpha-repo** — the agent's working repo. Full read-write access: clone, push, create PRs and issues. +- **bravo-repo** — a reference repo. Read-only access: clone and browse, but push and write API calls are denied. + +Access is locked to these two repos. The agent cannot clone, fetch, or call the API for any other repository on GitHub. + +By the end you will have: + +- A GitHub credential provider injecting your token into the sandbox +- A policy that extends the default with scoped GitHub access to exactly two repos +- A running sandbox where Claude Code, OpenCode, and the `gh` CLI can all interact with GitHub + +## Prerequisites + +Before you begin, make sure you have: + +- OpenShell CLI installed (`pip install nemoclaw`) +- Docker running on your machine +- A GitHub personal access token (PAT) with `repo` scope, exported as `GITHUB_TOKEN` +- Your agent's API key set (e.g., `ANTHROPIC_API_KEY` for Claude Code) + +## Step 1: Create a GitHub Provider + +Create a provider that reads your GitHub token from the environment: + +```console +$ nemoclaw provider create --name my-github --type github --from-existing +``` + +This reads `GITHUB_TOKEN` (and `GH_TOKEN` if set) from your shell and stores them in the provider. The sandbox receives these as environment variables at runtime. + +For more on provider types, see {doc}`/sandboxes/providers`. + +## Step 2: Write the Policy + +Create a file called `github-policy.yaml`. This policy starts from the {doc}`default policy ` and replaces the GitHub blocks with scoped rules that grant read-write access to `alpha-repo` and read-only access to `bravo-repo`. + +Replace `` throughout with your GitHub organization or username. + +```yaml +version: 1 + +# ── Static (locked at sandbox creation) ────────────────────────── + +filesystem_policy: + include_workdir: true + read_only: + - /usr + - /lib + - /proc + - /dev/urandom + - /app + - /etc + - /var/log + read_write: + - /sandbox + - /tmp + - /dev/null + +landlock: + compatibility: best_effort + +process: + run_as_user: sandbox + run_as_group: sandbox + +# ── Dynamic (hot-reloadable) ───────────────────────────────────── + +network_policies: + + # Claude Code ↔ Anthropic API + claude_code: + name: claude-code + endpoints: + - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } + - { host: statsig.anthropic.com, port: 443 } + - { host: sentry.io, port: 443 } + - { host: raw.githubusercontent.com, port: 443 } + - { host: platform.claude.com, port: 443 } + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/bin/node } + + # NVIDIA inference endpoint + nvidia_inference: + name: nvidia-inference + endpoints: + - { host: integrate.api.nvidia.com, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /bin/bash } + - { path: /usr/local/bin/opencode } + + # ── GitHub: git operations (clone, fetch, push) ────────────── + + github_git: + name: github-git + endpoints: + - host: github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + # alpha-repo: clone, fetch, and push + - allow: + method: GET + path: "//alpha-repo.git/info/refs*" + - allow: + method: POST + path: "//alpha-repo.git/git-upload-pack" + - allow: + method: POST + path: "//alpha-repo.git/git-receive-pack" + # bravo-repo: clone and fetch only (no push) + - allow: + method: GET + path: "//bravo-repo.git/info/refs*" + - allow: + method: POST + path: "//bravo-repo.git/git-upload-pack" + binaries: + - { path: /usr/bin/git } + + # ── GitHub: REST API ───────────────────────────────────────── + + github_api: + name: github-api + endpoints: + - host: api.github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + # GraphQL API (used by gh CLI) + - allow: + method: POST + path: "/graphql" + # alpha-repo: full read-write (PRs, issues, comments, etc.) + - allow: + method: "*" + path: "/repos//alpha-repo/**" + # bravo-repo: read-only + - allow: + method: GET + path: "/repos//bravo-repo/**" + - allow: + method: HEAD + path: "/repos//bravo-repo/**" + - allow: + method: OPTIONS + path: "/repos//bravo-repo/**" + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/local/bin/opencode } + - { path: /usr/bin/gh } + - { path: /usr/bin/curl } + + # ── Package managers ───────────────────────────────────────── + + pypi: + name: pypi + endpoints: + - { host: pypi.org, port: 443 } + - { host: files.pythonhosted.org, port: 443 } + - { host: github.com, port: 443 } + - { host: objects.githubusercontent.com, port: 443 } + - { host: api.github.com, port: 443 } + - { host: downloads.python.org, port: 443 } + binaries: + - { path: /sandbox/.venv/bin/python } + - { path: /sandbox/.venv/bin/python3 } + - { path: /sandbox/.venv/bin/pip } + - { path: /app/.venv/bin/python } + - { path: /app/.venv/bin/python3 } + - { path: /app/.venv/bin/pip } + - { path: /usr/local/bin/uv } + - { path: "/sandbox/.uv/python/**" } + + # ── VS Code Remote ────────────────────────────────────────── + + vscode: + name: vscode + endpoints: + - { host: update.code.visualstudio.com, port: 443 } + - { host: "*.vo.msecnd.net", port: 443 } + - { host: vscode.download.prss.microsoft.com, port: 443 } + - { host: marketplace.visualstudio.com, port: 443 } + - { host: "*.gallerycdn.vsassets.io", port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /usr/bin/wget } + - { path: "/sandbox/.vscode-server/**" } + - { path: "/sandbox/.vscode-remote-containers/**" } +``` + +**What the GitHub blocks do:** + +| Block | Endpoint | Access | +|---|---|---| +| `github_git` | `github.com:443` | Git Smart HTTP with TLS termination. Clone and fetch allowed for both repos. Push (`git-receive-pack`) allowed only for `alpha-repo`. All other repos are denied. | +| `github_api` | `api.github.com:443` | REST API with TLS termination. Full read-write for `alpha-repo`. Read-only (GET, HEAD, OPTIONS) for `bravo-repo`. All other repos are denied. | + +The remaining blocks (`claude_code`, `nvidia_inference`, `pypi`, `vscode`) match the {doc}`default policy ` so the sandbox behaves the same as a standard sandbox for everything outside of GitHub. + +For background on how network policy blocks work, see [Network Access Rules](/sandboxes/index.md#network-access-rules). + +## Step 3: Create the Sandbox + +Create the sandbox with both the GitHub provider and your policy: + +```console +$ nemoclaw sandbox create \ + --provider my-github \ + --policy github-policy.yaml \ + --keep \ + -- claude +``` + +The `--keep` flag keeps the sandbox running after Claude Code exits, so you can reconnect or iterate on the policy. + +## Step 4: Verify Access + +Once Claude Code is running inside the sandbox, ask it to exercise both repos. The policy should allow writes to `alpha-repo` and block writes to `bravo-repo`. + +**Test read-write access** — ask Claude to clone, commit, and push to `alpha-repo`: + +```text +Clone https://github.com//alpha-repo.git, add a blank line to the +README, commit, and push. +``` + +Claude clones the repo, makes the edit, and pushes. The sandbox logs show `action=allow` for both `github.com` (git push) and `api.github.com` (any API calls Claude makes along the way). + +**Test read-only enforcement** — ask Claude to try the same thing with `bravo-repo`: + +```text +Clone https://github.com//bravo-repo.git, add a blank line to the +README, commit, and push. +``` + +Claude clones successfully (read is allowed), but the push fails. The proxy denies `git-receive-pack` for `bravo-repo` and Claude reports the error. You can confirm in the logs: + +```console +$ nemoclaw logs --tail --source sandbox +``` + +Look for an `action=deny` entry showing `host=github.com` and `path=//bravo-repo.git/git-receive-pack`. + +**Test API scoping** — ask Claude to create an issue on each repo: + +```text +Create a GitHub issue titled "Test from sandbox" on /alpha-repo. +Then try to create the same issue on /bravo-repo. +``` + +The first issue is created. The second is denied — the policy only allows GET/HEAD/OPTIONS for `bravo-repo`, so the POST to create an issue is blocked. + +## Step 5: Iterate on the Policy + +To grant access to additional repos or change access levels, edit `github-policy.yaml` and push the update to the running sandbox: + +```console +$ nemoclaw policy set --policy github-policy.yaml --wait +``` + +For example, to grant write access to `bravo-repo` as well, add another rule under `github_api`: + +```yaml + - allow: + method: "*" + path: "/repos//bravo-repo/**" +``` + +And add a push rule under `github_git`: + +```yaml + - allow: + method: POST + path: "//bravo-repo.git/git-receive-pack" +``` + +For the full iterate workflow (pull current policy, edit, push, verify), see {doc}`/sandboxes/policies`. + +## Next Steps + +- **Need other credentials?** See {doc}`/sandboxes/providers` for all supported provider types. +- **Want finer policy control?** See {doc}`/sandboxes/policies` for more examples and the iterate workflow. +- **Looking for the full YAML reference?** See the [Policy Schema Reference](/reference/policy-schema.md). diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md new file mode 100644 index 0000000000..5421ee61f3 --- /dev/null +++ b/docs/tutorials/index.md @@ -0,0 +1,29 @@ + + +# Tutorials + +Step-by-step guides that walk through complete workflows from start to finish. + +::::{grid} 1 1 2 2 +:gutter: 3 + +:::{grid-item-card} GitHub Repo Access +:link: github-sandbox +:link-type: doc + +Create a sandbox with scoped GitHub access — read-write to one repo, read-only to another. + ++++ +{bdg-secondary}`Sandbox` {bdg-secondary}`Policy` {bdg-secondary}`Provider` +::: + +:::: + +```{toctree} +:hidden: + +github-sandbox +``` From bfb7254821e86e18967efe20f37d9f286aa06c95 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 23:12:05 -0700 Subject: [PATCH 11/20] Inference section reformatting --- docs/inference/configure.md | 49 +++++++++------------- docs/inference/index.md | 81 +++++++++++++------------------------ 2 files changed, 48 insertions(+), 82 deletions(-) diff --git a/docs/inference/configure.md b/docs/inference/configure.md index 5e260e6b24..5469c9024d 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -5,16 +5,14 @@ # Configure Inference Routing -OpenShell exposes one managed inference backend behind `https://inference.local` -for the active gateway. +This page covers the managed local inference endpoint (`https://inference.local`). External inference endpoints go through sandbox `network_policies` — see [Network Access Rules](/sandboxes/index.md#network-access-rules) for details. -External inference endpoints still go through sandbox `network_policies`. This -page covers the special local inference endpoint only. +The configuration consists of two values: -That configuration consists of two values: - -- a provider record name -- a model ID +| Value | Description | +|---|---| +| Provider record | The credential backend OpenShell uses to authenticate with the upstream model host. | +| Model ID | The model to use for generation requests. | ## Step 1: Create a Provider @@ -24,7 +22,7 @@ Create a provider that holds the backend credentials you want OpenShell to use. $ nemoclaw provider create --name nvidia-prod --type nvidia --from-existing ``` -You can also use `openai` or `anthropic` providers types. +You can also use `openai` or `anthropic` provider types. ## Step 2: Set Inference Routing @@ -36,8 +34,6 @@ $ nemoclaw inference set \ --model nvidia/nemotron-3-nano-30b-a3b ``` -This sets the managed inference configuration. - ## Step 3: Verify the Active Config ```console @@ -55,7 +51,7 @@ Use `update` when you want to change only one field: $ nemoclaw inference update --model nvidia/nemotron-3-nano-30b-a3b ``` -Or switch providers without repeating the current model manually: +Or switch providers without repeating the current model: ```console $ nemoclaw inference update --provider openai-prod @@ -63,8 +59,7 @@ $ nemoclaw inference update --provider openai-prod ## Use It from a Sandbox -Once inference is configured, userland code inside any sandbox can call -`https://inference.local` directly: +Once inference is configured, code inside any sandbox can call `https://inference.local` directly: ```python from openai import OpenAI @@ -77,24 +72,18 @@ response = client.chat.completions.create( ) ``` -The client-supplied model is ignored for generation requests. OpenShell -rewrites it to the configured model before forwarding upstream. - -Use this endpoint when inference should stay local to the host for privacy and -security reasons. External providers that should be reached directly belong in -`network_policies` instead. +The client-supplied model is ignored for generation requests. OpenShell rewrites it to the configured model before forwarding upstream. -## Good to Know +Use this endpoint when inference should stay local to the host for privacy and security reasons. External providers that should be reached directly belong in `network_policies` instead. -- Gateway-scoped: every sandbox on the active gateway sees the same - `inference.local` backend. -- HTTPS only: `inference.local` is intercepted only for HTTPS traffic. +:::{note} +- **Gateway-scoped** — every sandbox on the active gateway sees the same `inference.local` backend. +- **HTTPS only** — `inference.local` is intercepted only for HTTPS traffic. +::: ## Next Steps -- {doc}`index`: understand the interception flow and supported API patterns. -- [Network Access Rules](/sandboxes/index.md#network-access-rules): - configure direct access to external inference endpoints. -- {doc}`../sandboxes/providers`: create and manage provider records. -- {doc}`../reference/cli`: see the CLI reference for `nemoclaw inference` - commands. +- **How does inference routing work?** See {doc}`index` for the interception flow and supported API patterns. +- **Need to control external endpoints?** See [Network Access Rules](/sandboxes/index.md#network-access-rules). +- **Managing provider records?** See {doc}`../sandboxes/providers`. +- **CLI reference?** See {doc}`../reference/cli` for `nemoclaw inference` commands. diff --git a/docs/inference/index.md b/docs/inference/index.md index 865650847f..531cdf4f35 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -7,78 +7,55 @@ OpenShell handles inference in two ways: -- External inference endpoints are controlled by sandbox `network_policies`. -- Each sandbox also exposes `https://inference.local`, a special endpoint for - inference that should stay local to the host for privacy and security. +| Path | How It Works | +|---|---| +| **External endpoints** | Traffic to hosts like `api.openai.com` or `api.anthropic.com` is treated like any other outbound request — allowed or denied by `network_policies`. See [Network Access Rules](/sandboxes/index.md#network-access-rules). | +| **`inference.local`** | A special endpoint exposed inside every sandbox for inference that should stay local to the host for privacy and security. The {doc}`privacy router ` strips the original credentials, injects the configured backend credentials, and forwards to the managed model endpoint. | -## External Inference +## How `inference.local` Works -If sandbox code calls an external inference API like `api.openai.com` or -`api.anthropic.com`, that traffic is treated like any other outbound network -request. It is allowed or denied by `network_policies`. +When code inside a sandbox calls `https://inference.local`, the privacy router routes the request to the configured backend for that gateway. The configured model is applied to generation requests, and provider credentials are supplied by OpenShell rather than by code inside the sandbox. -Refer to {doc}`/sandboxes/policies` and the -[Network Access Rules](/sandboxes/index.md#network-access-rules) -section for details. +If code calls an external inference host directly, that traffic is evaluated only by `network_policies`. -## `inference.local` - -Every sandbox also exposes a special endpoint: `https://inference.local`. - -This endpoint exists so inference can be routed to a model running locally on -the same host. In the future, it can also route to a model managed by the -cluster. It is the special case for inference that should stay local for -privacy and security reasons. - -## Using `inference.local` - -When code inside a sandbox calls `https://inference.local`, the {doc}`privacy router ` routes the -request to the configured backend for that gateway. - -The configured model is applied to generation requests, and provider -credentials are supplied by OpenShell rather than by code inside the sandbox. - -If code calls an external inference host directly, that traffic is evaluated -only by `network_policies`. +| Property | Detail | +|---|---| +| Credentials | No sandbox API keys needed — credentials come from the configured provider record. | +| Configuration | One provider and one model define sandbox inference. | +| Provider support | OpenAI, Anthropic, and NVIDIA providers all work through the same endpoint. | +| Hot-refresh | Provider credential changes and inference updates are picked up without recreating sandboxes. | ## Supported API Patterns -Supported request patterns depend on the provider configured for -`inference.local`. +Supported request patterns depend on the provider configured for `inference.local`. -For OpenAI-compatible providers, these patterns are supported: +:::::{tab-set} + +::::{tab-item} OpenAI-compatible | Pattern | Method | Path | |---|---|---| -| OpenAI Chat Completions | `POST` | `/v1/chat/completions` | -| OpenAI Completions | `POST` | `/v1/completions` | -| OpenAI Responses | `POST` | `/v1/responses` | +| Chat Completions | `POST` | `/v1/chat/completions` | +| Completions | `POST` | `/v1/completions` | +| Responses | `POST` | `/v1/responses` | | Model Discovery | `GET` | `/v1/models` | | Model Discovery | `GET` | `/v1/models/*` | -For Anthropic-compatible providers, this pattern is supported: +:::: + +::::{tab-item} Anthropic-compatible | Pattern | Method | Path | |---|---|---| -| Anthropic Messages | `POST` | `/v1/messages` | +| Messages | `POST` | `/v1/messages` | -Requests to `inference.local` that do not match the configured provider's -supported patterns are denied. +:::: -## Key Properties +::::: -- External endpoints use `network_policies`. -- Explicit local endpoint: special local routing happens through - `inference.local`. -- No sandbox API keys: credentials come from the configured provider record. -- Single managed config: one provider and one model define sandbox inference. -- Provider-agnostic: OpenAI, Anthropic, and NVIDIA providers all work through - the same endpoint. -- Hot-refresh: provider credential changes and inference updates are picked up - without recreating sandboxes. +Requests to `inference.local` that do not match the configured provider's supported patterns are denied. ## Next Steps -- {doc}`configure`: configure the backend behind `inference.local`. -- [Network Access Rules](/sandboxes/index.md#network-access-rules): - understand how external endpoints are controlled. +- **Ready to configure?** Set up the backend behind `inference.local` in {doc}`configure`. +- **Need to control external endpoints?** See [Network Access Rules](/sandboxes/index.md#network-access-rules). From 34b59fd0433f68dca5a53fdfcfbc7b03d2f6751b Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 23:15:16 -0700 Subject: [PATCH 12/20] Updated CLI ref --- docs/reference/cli.md | 74 +++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 35e79ed8e8..0b38bf56e3 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -13,14 +13,11 @@ Complete command reference for the `nemoclaw` CLI. Every subcommand, flag, and o nemoclaw ├── status ├── logs [name] +├── term ├── forward │ ├── start │ ├── stop │ └── list -├── policy -│ ├── set -│ ├── get -│ └── list ├── gateway │ ├── start │ ├── stop @@ -37,6 +34,10 @@ nemoclaw │ ├── upload [name] │ ├── download [name] │ └── ssh-config +├── policy +│ ├── set +│ ├── get +│ └── list ├── provider │ ├── create │ ├── get @@ -47,24 +48,22 @@ nemoclaw │ ├── set │ ├── update │ └── get -├── term └── completions ``` -## Top-Level Commands +:::{tip} +Commands that accept an optional `[name]` argument — such as `get`, `connect`, `upload`, `download`, and `logs` — fall back to the last-used sandbox when the name is omitted. The CLI records the sandbox name each time you create or connect, and prints a hint showing which sandbox was selected. +::: -Commands available directly under `nemoclaw` for common operations. +## Status, Logs, and Terminal | Command | Description | |---|---| | `nemoclaw status` | Show the health and status of the active gateway. | -| `nemoclaw logs [name]` | View sandbox logs. Use `--tail` for streaming, `--source` and `--level` to filter. When name is omitted, uses the last-used sandbox. | -| `nemoclaw forward start ` | Forward a sandbox port to the host. Add `-d` for background mode. | -| `nemoclaw forward stop ` | Stop an active port forward. | -| `nemoclaw forward list` | List all active port forwards. | -| `nemoclaw policy set ` | Apply or update a policy on a running sandbox. Pass `--policy `. | -| `nemoclaw policy get ` | Show the active policy for a sandbox. Add `--full` for the complete policy with metadata. | -| `nemoclaw policy list ` | List all policy versions applied to a sandbox, with status. | +| `nemoclaw logs [name]` | View sandbox logs. Use `--tail` for streaming, `--source` and `--level` to filter. | +| `nemoclaw term` | Launch the OpenShell Terminal — a dashboard showing sandbox status, live logs, and policy decisions in a single view. Navigate with `j`/`k`, press `f` to follow live output, `s` to filter by source, and `q` to quit. | + +Refer to {doc}`/sandboxes/create-and-manage` for more on monitoring sandboxes and reading log entries. ## Gateway Commands @@ -87,12 +86,12 @@ Create and manage isolated agent execution environments. | Command | Description | |---|---| | `nemoclaw sandbox create` | Create a new sandbox. See flag reference below. | -| `nemoclaw sandbox get [name]` | Show detailed information about a sandbox. When name is omitted, uses the last-used sandbox. | +| `nemoclaw sandbox get [name]` | Show detailed information about a sandbox. | | `nemoclaw sandbox list` | List all sandboxes in the active cluster. | | `nemoclaw sandbox delete ` | Delete one or more sandboxes by name. | -| `nemoclaw sandbox connect [name]` | Open an interactive SSH session into a running sandbox. When name is omitted, reconnects to the last-used sandbox. | -| `nemoclaw sandbox upload [name]` | Upload files from the host into a sandbox. When name is omitted, uses the last-used sandbox. | -| `nemoclaw sandbox download [name]` | Download files from a sandbox to the host. When name is omitted, uses the last-used sandbox. | +| `nemoclaw sandbox connect [name]` | Open an interactive SSH session into a running sandbox. | +| `nemoclaw sandbox upload [name]` | Upload files from the host into a sandbox. | +| `nemoclaw sandbox download [name]` | Download files from a sandbox to the host. | | `nemoclaw sandbox ssh-config ` | Print SSH config for a sandbox. Append to `~/.ssh/config` for VS Code Remote-SSH. | ### Sandbox Create Flags @@ -108,6 +107,26 @@ Create and manage isolated agent execution environments. | `--from` | Build from a community sandbox name, local Dockerfile directory, or container image reference. | | `-- ` | The command to run inside the sandbox. Everything after `--` is passed as the agent command. | +## Policy Commands + +Apply and inspect sandbox policies at runtime. + +| Command | Description | +|---|---| +| `nemoclaw policy set ` | Apply or update a policy on a running sandbox. Pass `--policy `. | +| `nemoclaw policy get ` | Show the active policy for a sandbox. Add `--full` for the complete policy with metadata. | +| `nemoclaw policy list ` | List all policy versions applied to a sandbox, with status. | + +## Port Forwarding Commands + +Forward sandbox ports to the host for local access. + +| Command | Description | +|---|---| +| `nemoclaw forward start ` | Forward a sandbox port to the host. Add `-d` for background mode. | +| `nemoclaw forward stop ` | Stop an active port forward. | +| `nemoclaw forward list` | List all active port forwards. | + ## Provider Commands Manage credential providers that inject secrets into sandboxes. @@ -154,22 +173,7 @@ Update only the fields you specify. ### `nemoclaw inference get` -Show the current inference configuration, including provider, model, and -version. - -## OpenShell Terminal - -`nemoclaw term` launches the OpenShell Terminal, a dashboard that shows sandbox -status, live logs, and policy decisions in a single view. Navigate with `j`/`k`, -press `f` to follow live output, `s` to filter by source, and `q` to quit. - -Refer to {doc}`/sandboxes/create-and-manage` for more on monitoring sandboxes and reading log entries. - -## Sandbox Name Fallback - -Commands that accept an optional `[name]` argument, such as `get`, `connect`, `upload`, `download`, and `logs`, fall back to the last-used sandbox when the name is omitted. The CLI records the sandbox name each time you create or connect to a sandbox. When falling back, the CLI prints a hint showing which sandbox was selected. - -If no sandbox has been used yet and no name is provided, the command exits with an error prompting you to specify a name. +Show the current inference configuration, including provider, model, and version. ## Environment Variables @@ -195,7 +199,7 @@ $ nemoclaw completions zsh >> ~/.zshrc $ source ~/.zshrc ``` -## Self-Teaching +## Built-in Help Every command and subcommand includes built-in help. Use `--help` at any level to see available subcommands, flags, and usage examples: From fb5ca5ef820288dbf2e0b33ff697bd33c55914cd Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Mon, 9 Mar 2026 23:18:29 -0700 Subject: [PATCH 13/20] removed troubleshooting --- docs/index.md | 7 --- docs/troubleshooting.md | 135 ---------------------------------------- 2 files changed, 142 deletions(-) delete mode 100644 docs/troubleshooting.md diff --git a/docs/index.md b/docs/index.md index 6040040f11..2098347df1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -225,13 +225,6 @@ reference/default-policy reference/policy-schema ``` -```{toctree} -:caption: Troubleshooting -:hidden: - -troubleshooting -``` - ```{toctree} :caption: Resources :hidden: diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md deleted file mode 100644 index 626e4642db..0000000000 --- a/docs/troubleshooting.md +++ /dev/null @@ -1,135 +0,0 @@ - - -# Troubleshooting - -Use this guide to troubleshoot problems with OpenShell. - -## Cluster Issues - -Troubleshoot problems with deploying, connecting to, and running OpenShell clusters. - -### Cluster Deploy Fails - -**Symptom:** `nemoclaw gateway start` exits with an error. - -**Check:** -1. Is Docker running? The cluster requires Docker to be active. -2. Is the port already in use? Try a different port: `--port 8081`. -3. Does a stale container exist? Destroy and redeploy: `nemoclaw gateway destroy && nemoclaw gateway start`. - -### Cluster Not Reachable - -**Symptom:** `nemoclaw status` fails to connect. - -**Check:** -1. Is the cluster container running? `docker ps | grep nemoclaw`. -2. Was the cluster stopped? Redeploy: `nemoclaw gateway start`. -3. For remote clusters, is the SSH connection working? - -### Health Check Fails During Deploy - -**Symptom:** Deploy hangs or times out waiting for health checks. - -**Check:** -1. View container logs: `docker logs nemoclaw-cluster`. -2. Check if k3s started: the bootstrap process waits up to 180 attempts (six minutes) for cluster readiness. -3. Look for resource constraints. k3s needs sufficient memory and disk. - -## Sandbox Issues - -Troubleshoot problems with creating, connecting to, and configuring sandboxes. - -### Sandbox Stuck in Provisioning - -**Symptom:** Sandbox shows `Provisioning` status and does not become `Ready`. - -**Check:** -1. View sandbox logs: `nemoclaw logs --source gateway`. -2. Check if the container image can be pulled. -3. For custom images, verify the image was pushed: `nemoclaw sandbox image push`. - -### Cannot Connect to Sandbox - -**Symptom:** `nemoclaw sandbox connect ` fails. - -**Check:** -1. Is the sandbox in `Ready` state? `nemoclaw sandbox get `. -2. Is SSH accessible? The tunnel goes through the gateway. Verify cluster connectivity first. - -### Network Requests Denied - -**Symptom:** The agent cannot reach a remote host. - -**Check:** -1. Stream sandbox logs: `nemoclaw logs --tail --source sandbox`. -2. Look for `deny` actions. They include the destination, binary, and reason. -3. Update the policy to allow the blocked endpoint. Refer to [](sandboxes/policies.md). - -### Policy Update Fails - -**Symptom:** `nemoclaw policy set` returns an error or the status shows `failed`. - -**Check:** -1. Are you changing a static field? `filesystem_policy`, `landlock`, and `process` cannot change after creation. -2. Are you adding/removing `network_policies` to change the network mode? This is not allowed. The mode is fixed at creation. -3. Check the error message in `nemoclaw policy list `. - -## Provider Issues - -Troubleshoot problems with provider credential discovery and injection into sandboxes. - -### Provider Discovery Finds No Credentials - -**Symptom:** `--from-existing` creates a provider with no credentials. - -**Check:** -1. Are the expected environment variables set? (for example, `ANTHROPIC_API_KEY` for Claude). -2. Do the expected config files exist? (for example, `~/.claude.json`). -3. Try explicit credentials: `--credential ANTHROPIC_API_KEY=sk-...`. - -### Sandbox Missing Credentials - -**Symptom:** Environment variables for a provider are not set inside the sandbox. - -**Check:** -1. Was the provider attached? `nemoclaw sandbox get `. Check the providers list. -2. Does the provider have credentials? `nemoclaw provider get `. -3. Are the credential keys valid env var names? Keys with dots, dashes, or spaces are silently skipped. - -## Custom Container Issues - -Troubleshoot problems with building and running custom container images in sandboxes. - -### Custom Image Fails to Start - -**Symptom:** Sandbox with `--from ` goes to `Error` state. - -**Check:** -1. Is the image pushed to the cluster? `nemoclaw sandbox image push --dockerfile ./Dockerfile --tag my-image`. -2. Does the image have glibc and `/proc`? Distroless / `FROM scratch` images are not supported. -3. For proxy mode, does the image have `iproute2`? Network namespace setup requires it. - -## Port Forwarding Issues - -Troubleshoot problems with forwarding local ports into sandbox services. - -### Port Forward Not Working - -**Symptom:** `localhost:` does not connect to the sandbox service. - -**Check:** -1. Is the forward running? `nemoclaw forward list`. -2. Is the service listening on that port inside the sandbox? -3. Is the sandbox still in `Ready` state? -4. Try stopping and restarting: `nemoclaw forward stop && nemoclaw forward start -d`. - -## Getting More Information - -Use these techniques to gather additional diagnostic detail when troubleshooting. - -- Increase CLI verbosity: `nemoclaw -vvv ` for trace-level output. -- View gateway-side logs: `nemoclaw logs --source gateway`. -- View sandbox-side logs: `nemoclaw logs --source sandbox --level debug`. From 4ee6ea490ca3a55284be8c544c348779868ca8c0 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 08:06:05 -0700 Subject: [PATCH 14/20] Updated inference --- docs/inference/configure.md | 49 ++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/inference/configure.md b/docs/inference/configure.md index 5469c9024d..771932dee7 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -18,11 +18,43 @@ The configuration consists of two values: Create a provider that holds the backend credentials you want OpenShell to use. +:::::{tab-set} + +::::{tab-item} NVIDIA API Catalog + ```console $ nemoclaw provider create --name nvidia-prod --type nvidia --from-existing ``` -You can also use `openai` or `anthropic` provider types. +This reads `NVIDIA_API_KEY` from your environment. + +:::: + +::::{tab-item} Local / self-hosted endpoint + +```console +$ nemoclaw provider create \ + --name my-local-model \ + --type openai \ + --credential OPENAI_API_KEY=empty-if-not-required \ + --config OPENAI_BASE_URL=http://192.168.10.15/v1 +``` + +Use `--config OPENAI_BASE_URL` to point to any OpenAI-compatible server running on your network. Set `OPENAI_API_KEY` to a dummy value if the server does not require authentication. + +:::: + +::::{tab-item} Anthropic + +```console +$ nemoclaw provider create --name anthropic-prod --type anthropic --from-existing +``` + +This reads `ANTHROPIC_API_KEY` from your environment. + +:::: + +::::: ## Step 2: Set Inference Routing @@ -76,6 +108,21 @@ The client-supplied model is ignored for generation requests. OpenShell rewrites Use this endpoint when inference should stay local to the host for privacy and security reasons. External providers that should be reached directly belong in `network_policies` instead. +### Verify the Endpoint from a Sandbox + +`nemoclaw inference get` confirms the configuration was saved, but does not verify the upstream endpoint is reachable. To confirm end-to-end connectivity, connect to a sandbox and run: + +```bash +curl https://inference.local/v1/responses \ + -H "Content-Type: application/json" \ + -d '{ + "instructions": "You are a helpful assistant.", + "input": "Hello!" + }' +``` + +A successful response confirms the privacy router can reach the configured backend and the model is serving requests. + :::{note} - **Gateway-scoped** — every sandbox on the active gateway sees the same `inference.local` backend. - **HTTPS only** — `inference.local` is intercepted only for HTTPS traffic. From f68ec6c33a1c1a048eb3eddae270b30e711d2a32 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 08:49:07 -0700 Subject: [PATCH 15/20] Updated pip install command for bug bash --- docs/about/get-started.md | 25 ++++++++++++++----------- docs/index.md | 2 +- docs/sandboxes/create-and-manage.md | 7 ------- docs/tutorials/github-sandbox.md | 3 +-- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/docs/about/get-started.md b/docs/about/get-started.md index c7a9f31ab1..d348592c86 100644 --- a/docs/about/get-started.md +++ b/docs/about/get-started.md @@ -26,12 +26,24 @@ This page gets you from zero to a running, policy-enforced sandbox in two comman Before you begin, make sure you have: - Python 3.12 or later +- [uv](https://docs.astral.sh/uv/) installed - Docker Desktop running on your machine ## Install the OpenShell CLI +Activate your virtual environment: + +```bash +uv venv && source .venv/bin/activate +``` + +Install the CLI: + ```bash -pip install nemoclaw +uv pip install nemoclaw \ + --upgrade \ + --pre \ + --index-url https://urm.nvidia.com/artifactory/api/pypi/nv-shared-pypi/simple ``` ## Create Your First OpenShell Sandbox @@ -45,16 +57,7 @@ Choose the tab that matches your agent: $ nemoclaw sandbox create -- claude ``` -```text -✓ Runtime ready -✓ Discovered Claude credentials (ANTHROPIC_API_KEY) -✓ Created sandbox: keen-fox -✓ Policy loaded (4 protection layers active) - -Connecting to keen-fox... -``` - -The CLI detects your `ANTHROPIC_API_KEY`, creates a provider, builds the sandbox, applies a default policy, and drops you into an interactive session. No additional configuration is required. +The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `ANTHROPIC_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. ::: :::{tab-item} Community Sandbox diff --git a/docs/index.md b/docs/index.md index 2098347df1..78c74ab326 100644 --- a/docs/index.md +++ b/docs/index.md @@ -97,7 +97,7 @@ Install the CLI and create your first sandbox in two commands.
-
$ pip install nemoclaw
+
$ uv pip install nemoclaw --upgrade --pre --index-url https://urm.nvidia.com/artifactory/api/pypi/nv-shared-pypi/simple
$ nemoclaw sandbox create -- claude--from openclaw
diff --git a/docs/sandboxes/create-and-manage.md b/docs/sandboxes/create-and-manage.md index 91b8b614c3..292620ed48 100644 --- a/docs/sandboxes/create-and-manage.md +++ b/docs/sandboxes/create-and-manage.md @@ -7,13 +7,6 @@ This page walks you through the full sandbox lifecycle: creating, inspecting, connecting to, monitoring, and deleting sandboxes. For background on what sandboxes are and how the runtime works, refer to [About Sandboxes](index.md). -## Prerequisites - -Ensure the following are ready before creating sandboxes. - -- OpenShell CLI installed (`pip install nemoclaw`) -- Docker running on your machine - :::{warning} Docker must be running before you create a sandbox. If it isn't, the CLI returns a connection-refused error (`os error 61`) without explaining diff --git a/docs/tutorials/github-sandbox.md b/docs/tutorials/github-sandbox.md index 3e50bde572..a66a740564 100644 --- a/docs/tutorials/github-sandbox.md +++ b/docs/tutorials/github-sandbox.md @@ -24,8 +24,7 @@ By the end you will have: Before you begin, make sure you have: -- OpenShell CLI installed (`pip install nemoclaw`) -- Docker running on your machine +- Completed the {doc}`Quickstart
` (CLI installed, Docker running) - A GitHub personal access token (PAT) with `repo` scope, exported as `GITHUB_TOKEN` - Your agent's API key set (e.g., `ANTHROPIC_API_KEY` for Claude Code) From 8010ea6405a2fd94d7e1680df8172c66fb096033 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 09:03:14 -0700 Subject: [PATCH 16/20] Updated arch diagram --- docs/about/architecture.md | 65 ++----------------------------------- docs/about/architecture.svg | 1 + 2 files changed, 4 insertions(+), 62 deletions(-) create mode 100644 docs/about/architecture.svg diff --git a/docs/about/architecture.md b/docs/about/architecture.md index 0eda981a0a..c417c3b62b 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -21,68 +21,9 @@ content: OpenShell runs as a [k3s](https://k3s.io/) Kubernetes cluster inside a Docker container. Each sandbox is an isolated Kubernetes pod managed through the gateway. Four components work together to keep agents secure. -```{mermaid} -graph TB - subgraph docker["Docker Container"] - subgraph k3s["k3s Cluster"] - gw["Gateway"] - pr["Privacy Router"] - - subgraph pod1["Sandbox"] - sup1["Supervisor"] - proxy1["Proxy"] - pe1["Policy Engine"] - agent1["Agent"] - - sup1 --> proxy1 - sup1 --> agent1 - proxy1 --> pe1 - end - - subgraph pod2["Sandbox"] - sup2["Supervisor"] - proxy2["Proxy"] - pe2["Policy Engine"] - agent2["Agent"] - - sup2 --> proxy2 - sup2 --> agent2 - proxy2 --> pe2 - end - - gw -- "credentials,
policies" --> sup1 - gw -- "credentials,
policies" --> sup2 - end - end - - cli["nemoclaw CLI"] -- "gRPC" --> gw - agent1 -- "all outbound
traffic" --> proxy1 - agent2 -- "all outbound
traffic" --> proxy2 - proxy1 -- "policy-approved
traffic" --> internet["External Services"] - proxy2 -- "policy-approved
traffic" --> internet - proxy1 -- "inference traffic" --> pr - proxy2 -- "inference traffic" --> pr - pr -- "routed requests" --> backend["LLM Backend"] - - style cli fill:#ffffff,stroke:#000000,color:#000000 - style gw fill:#76b900,stroke:#000000,color:#000000 - style pr fill:#76b900,stroke:#000000,color:#000000 - style sup1 fill:#76b900,stroke:#000000,color:#000000 - style proxy1 fill:#76b900,stroke:#000000,color:#000000 - style pe1 fill:#76b900,stroke:#000000,color:#000000 - style agent1 fill:#ffffff,stroke:#000000,color:#000000 - style sup2 fill:#76b900,stroke:#000000,color:#000000 - style proxy2 fill:#76b900,stroke:#000000,color:#000000 - style pe2 fill:#76b900,stroke:#000000,color:#000000 - style agent2 fill:#ffffff,stroke:#000000,color:#000000 - style internet fill:#ffffff,stroke:#000000,color:#000000 - style backend fill:#ffffff,stroke:#000000,color:#000000 - style docker fill:#f5f5f5,stroke:#000000,color:#000000 - style k3s fill:#e8e8e8,stroke:#000000,color:#000000 - style pod1 fill:#f5f5f5,stroke:#000000,color:#000000 - style pod2 fill:#f5f5f5,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px +```{image} architecture.svg +:alt: OpenShell architecture diagram showing the NemoClaw component layout +:align: center ``` ## Components diff --git a/docs/about/architecture.svg b/docs/about/architecture.svg new file mode 100644 index 0000000000..b0bcd4d5df --- /dev/null +++ b/docs/about/architecture.svg @@ -0,0 +1 @@ + \ No newline at end of file From d2d8a4146317ff2e46969fa48141b0b9c032b3bd Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 09:23:03 -0700 Subject: [PATCH 17/20] Updated tutorial --- docs/about/get-started.md | 25 +++++++++++++++++++++++++ docs/tutorials/github-sandbox.md | 9 +++++++++ 2 files changed, 34 insertions(+) diff --git a/docs/about/get-started.md b/docs/about/get-started.md index d348592c86..cfe630d941 100644 --- a/docs/about/get-started.md +++ b/docs/about/get-started.md @@ -46,6 +46,31 @@ uv pip install nemoclaw \ --index-url https://urm.nvidia.com/artifactory/api/pypi/nv-shared-pypi/simple ``` +## Connect to a Gateway + +:::::{tab-set} + +::::{tab-item} Local (Docker) + +If Docker is running on your machine, the CLI creates a local gateway automatically when you create your first sandbox. No additional setup is needed — skip to the next step. + +:::: + +::::{tab-item} Remote (Brev) + +Deploy an OpenShell gateway on Brev with the [OpenShell Launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3AaK9NmCzWp3pVyUDNNFBt805FT), then connect to it: + +```console +$ nemoclaw gateway add +$ nemoclaw status +``` + +Once `nemoclaw status` shows the gateway as healthy, all subsequent commands target that remote instance. + +:::: + +::::: + ## Create Your First OpenShell Sandbox Choose the tab that matches your agent: diff --git a/docs/tutorials/github-sandbox.md b/docs/tutorials/github-sandbox.md index a66a740564..64b311c9cd 100644 --- a/docs/tutorials/github-sandbox.md +++ b/docs/tutorials/github-sandbox.md @@ -30,6 +30,15 @@ Before you begin, make sure you have: ## Step 1: Create a GitHub Provider +:::{admonition} Already have a sandbox running? +:class: tip + +If you followed the Quickstart and already have a sandbox without a GitHub provider, you have two options: + +1. **Add a provider to a new sandbox** — delete the existing sandbox, create the provider below, and recreate the sandbox with `--provider my-github` in Step 3. +2. **Set the token inside the sandbox** — connect with `nemoclaw sandbox connect ` and run `export GITHUB_TOKEN=`. This skips the provider workflow but the token is not persisted across sandbox recreations. +::: + Create a provider that reads your GitHub token from the environment: ```console From 48b2bc563f91cb45fa9c663d173ddd1435428d98 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 11:08:21 -0700 Subject: [PATCH 18/20] Updated install commands --- docs/about/architecture.md | 6 +++++- docs/about/get-started.md | 5 +---- docs/index.md | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/about/architecture.md b/docs/about/architecture.md index c417c3b62b..2b8467f314 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -54,7 +54,11 @@ For REST endpoints with TLS termination enabled, the proxy also decrypts TLS and OpenShell can run locally or on a remote host. The architecture is identical in both cases — only the Docker container location changes. - **Local**: the k3s cluster runs inside Docker on your workstation. The CLI provisions it automatically on first use. -- **Remote**: the cluster runs on a remote host. Deploy with `nemoclaw gateway start --remote user@host`, then connect with `nemoclaw gateway tunnel`. All CLI commands route through the SSH tunnel transparently. +- **Remote**: the cluster runs on a remote host. Deploy with `nemoclaw gateway start --remote user@host`. For example, connect to your DGX Spark + ```console + $ nemoclaw gateway start --remote @.local + $ nemoclaw status + ``` ## Next Steps diff --git a/docs/about/get-started.md b/docs/about/get-started.md index cfe630d941..8f40a078c5 100644 --- a/docs/about/get-started.md +++ b/docs/about/get-started.md @@ -40,10 +40,7 @@ uv venv && source .venv/bin/activate Install the CLI: ```bash -uv pip install nemoclaw \ - --upgrade \ - --pre \ - --index-url https://urm.nvidia.com/artifactory/api/pypi/nv-shared-pypi/simple +uv pip install nemoclaw ``` ## Connect to a Gateway diff --git a/docs/index.md b/docs/index.md index 78c74ab326..eec20c0b6d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -97,7 +97,7 @@ Install the CLI and create your first sandbox in two commands.
-
$ uv pip install nemoclaw --upgrade --pre --index-url https://urm.nvidia.com/artifactory/api/pypi/nv-shared-pypi/simple
+
$ uv pip install nemoclaw
$ nemoclaw sandbox create -- claude--from openclaw
From 4023cd1f00518d8040fce3f92eea4fd211712e91 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 11:29:12 -0700 Subject: [PATCH 19/20] Updated getting started --- docs/about/get-started.md | 45 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/docs/about/get-started.md b/docs/about/get-started.md index 8f40a078c5..88580651b2 100644 --- a/docs/about/get-started.md +++ b/docs/about/get-started.md @@ -43,26 +43,41 @@ Install the CLI: uv pip install nemoclaw ``` -## Connect to a Gateway +## Connect to a Remote Gateway (Optional) + +If you're running locally, skip this step — the CLI creates a gateway automatically when you create your first sandbox. :::::{tab-set} -::::{tab-item} Local (Docker) +::::{tab-item} Brev + +:::{note} +Deploy an OpenShell gateway on Brev by hitting **Deploy** on the [OpenShell Launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3AaK9NmCzWp3pVyUDNNFBt805FT). +::: -If Docker is running on your machine, the CLI creates a local gateway automatically when you create your first sandbox. No additional setup is needed — skip to the next step. +Once the instance is running, connect to it: + +```console +$ nemoclaw gateway add +$ nemoclaw status +``` :::: -::::{tab-item} Remote (Brev) +::::{tab-item} DGX Spark -Deploy an OpenShell gateway on Brev with the [OpenShell Launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3AaK9NmCzWp3pVyUDNNFBt805FT), then connect to it: +:::{note} +Set up your Spark with NVIDIA Sync first, or make sure SSH access is configured (e.g., SSH keys added to the host). +::: + +Deploy to a DGX Spark machine over SSH: ```console -$ nemoclaw gateway add +$ nemoclaw gateway start --remote @.local $ nemoclaw status ``` -Once `nemoclaw status` shows the gateway as healthy, all subsequent commands target that remote instance. +Once `nemoclaw status` shows the gateway as healthy, all subsequent commands route through the SSH tunnel. :::: @@ -82,6 +97,22 @@ $ nemoclaw sandbox create -- claude The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `ANTHROPIC_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. ::: +:::{tab-item} OpenCode +```console +$ nemoclaw sandbox create -- opencode +``` + +The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `OPENAI_API_KEY` or `OPENROUTER_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. +::: + +:::{tab-item} Codex +```console +$ nemoclaw sandbox create -- codex +``` + +The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `OPENAI_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. +::: + :::{tab-item} Community Sandbox ```console $ nemoclaw sandbox create --from openclaw From bd5a96a6b43aea5b0d6d9daf71dc6e6e42274949 Mon Sep 17 00:00:00 2001 From: Kirit93 Date: Tue, 10 Mar 2026 11:31:33 -0700 Subject: [PATCH 20/20] Updated brev link --- docs/about/get-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/about/get-started.md b/docs/about/get-started.md index 88580651b2..01ac2bb775 100644 --- a/docs/about/get-started.md +++ b/docs/about/get-started.md @@ -55,10 +55,10 @@ If you're running locally, skip this step — the CLI creates a gateway automati Deploy an OpenShell gateway on Brev by hitting **Deploy** on the [OpenShell Launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3AaK9NmCzWp3pVyUDNNFBt805FT). ::: -Once the instance is running, connect to it: +Once the instance is running, find the gateway URL in the Brev console under **Using Secure Links**. Copy the shareable URL for **port 8080** — this is the gateway endpoint. ```console -$ nemoclaw gateway add +$ nemoclaw gateway add https://.brevlab.com $ nemoclaw status ```