diff --git a/.agents/skills/nemoclaw-contributor-update-docs/SKILL.md b/.agents/skills/nemoclaw-contributor-update-docs/SKILL.md index a7366b8a64..aa9bf6f911 100644 --- a/.agents/skills/nemoclaw-contributor-update-docs/SKILL.md +++ b/.agents/skills/nemoclaw-contributor-update-docs/SKILL.md @@ -166,7 +166,7 @@ If the user invoked this skill for release prep, finish the release-specific doc 3. Refresh the NemoClaw user skills: ```bash - python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user + python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx ``` ## Step 9: Build and Verify @@ -214,7 +214,7 @@ User says: "Catch up the docs for everything merged since v0.1.0." 4. Read the commit diffs and current doc pages. 5. Draft doc updates reflecting the source code changes in the commits following the style guide. 6. **Release prep only:** Apply release-prep version bumps if the user requested release prep. -7. **Release prep only:** Run `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user`. +7. **Release prep only:** Run `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx`. 8. Present the summary. 9. Build with `make docs` to verify. 10. **Release prep only:** Commit changes and open a pull request with the `documentation` label and the corresponding `vX.Y.Z` release label. Include a concise summary of the doc updates and a source summary that links each identified merged PR to its matching doc page. Include the PR number, affected doc page, links, and description of the doc change in this shape: diff --git a/.agents/skills/nemoclaw-user-configure-inference/SKILL.md b/.agents/skills/nemoclaw-user-configure-inference/SKILL.md index cca533c855..cbf3030f06 100644 --- a/.agents/skills/nemoclaw-user-configure-inference/SKILL.md +++ b/.agents/skills/nemoclaw-user-configure-inference/SKILL.md @@ -8,6 +8,10 @@ description: "Connects NemoClaw to a local inference server. Use when setting up # Use a Local Inference Server with NemoClaw +## Gotchas + +- Ollama is convenient for local chat, but some model/template combinations can return tool calls as plain text under realistic agent load. + ## Prerequisites - NemoClaw installed. @@ -62,13 +66,11 @@ If the daemon does not become reachable, onboarding prints PowerShell commands y Use one Ollama instance on port `11434` at a time. If both WSL and Windows-host Ollama are running, pick the intended menu entry during onboarding so NemoClaw validates and pulls models against the right daemon. -:::{caution} -Ollama is convenient for local chat, but some model/template combinations can -return tool calls as plain text under realistic agent load. If the TUI shows raw -JSON such as `{"name":"memory_search","arguments":{...}}` instead of running a -tool, switch to vLLM with `--enable-auto-tool-choice` and the correct -`--tool-call-parser`. See Tool-Calling Reliability (use the `nemoclaw-user-configure-inference` skill). -::: +> **Warning:** Ollama is convenient for local chat, but some model/template combinations can +> return tool calls as plain text under realistic agent load. If the TUI shows raw +> JSON such as `{"name":"memory_search","arguments":{...}}` instead of running a +> tool, switch to vLLM with `--enable-auto-tool-choice` and the correct +> `--tool-call-parser`. See Tool-Calling Reliability (use the `nemoclaw-user-configure-inference` skill). ### Authenticated Reverse Proxy diff --git a/.agents/skills/nemoclaw-user-configure-inference/references/inference-options.md b/.agents/skills/nemoclaw-user-configure-inference/references/inference-options.md index 0c1ed457dc..a4fb1b8058 100644 --- a/.agents/skills/nemoclaw-user-configure-inference/references/inference-options.md +++ b/.agents/skills/nemoclaw-user-configure-inference/references/inference-options.md @@ -1,6 +1,6 @@ -# Inference Options +# NemoClaw Inference Options NemoClaw supports multiple inference providers. During onboarding, the `nemoclaw onboard` wizard presents a numbered list of providers to choose from. @@ -19,7 +19,6 @@ NemoClaw uses provider-specific local tokens for those routes, and rebuilds of l ## Provider Status - | Provider | Status | Endpoint type | Notes | |----------|--------|---------------|-------| | NVIDIA Endpoints | Tested | OpenAI-compatible | Hosted models on integrate.api.nvidia.com | @@ -32,7 +31,6 @@ NemoClaw uses provider-specific local tokens for those routes, and rebuilds of l | Local Ollama | Caveated | Local Ollama API | Available when Ollama is installed or running on the host | | Local NVIDIA NIM | Experimental | Local OpenAI-compatible | Requires `NEMOCLAW_EXPERIMENTAL=1` and a NIM-capable GPU | | Local vLLM | Experimental | Local OpenAI-compatible | Requires `NEMOCLAW_EXPERIMENTAL=1` and a server already running on `localhost:8000` | - ## Provider Options diff --git a/.agents/skills/nemoclaw-user-configure-inference/references/set-up-sub-agent.md b/.agents/skills/nemoclaw-user-configure-inference/references/set-up-sub-agent.md index c88799775a..3694ddf323 100644 --- a/.agents/skills/nemoclaw-user-configure-inference/references/set-up-sub-agent.md +++ b/.agents/skills/nemoclaw-user-configure-inference/references/set-up-sub-agent.md @@ -1,6 +1,6 @@ -# Set Up Task-Specific Sub-Agents +# Set up a Task-Specific Sub-Agent OpenClaw documents the sub-agent behavior, `sessions_spawn` tool, `agents.list` configuration, tool policy, nesting, and auth model in [Sub-Agents](https://docs.openclaw.ai/tools/subagents). Use that page as the source of truth for how OpenClaw sub-agents work. diff --git a/.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md b/.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md index 87a0440d71..60dd63e15b 100644 --- a/.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md +++ b/.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md @@ -1,6 +1,6 @@ -# Switch Inference Models at Runtime +# Switch NemoClaw Inference Models at Runtime Change the active inference model while the sandbox is running. No restart is required. diff --git a/.agents/skills/nemoclaw-user-configure-security/references/best-practices.md b/.agents/skills/nemoclaw-user-configure-security/references/best-practices.md index 5a1a17bee9..643d2af012 100644 --- a/.agents/skills/nemoclaw-user-configure-security/references/best-practices.md +++ b/.agents/skills/nemoclaw-user-configure-security/references/best-practices.md @@ -1,6 +1,6 @@ -# Security Best Practices +# NemoClaw Security Best Practices: Controls, Risks, and Posture Profiles NemoClaw ships with deny-by-default security controls across four layers: network, filesystem, process, and inference. You can tune every control, but each change shifts the risk profile. @@ -8,13 +8,6 @@ This page documents every configurable knob, its default, what it protects, the For background on how the layers fit together, refer to How It Works (use the `nemoclaw-user-overview` skill). - - ## Protection Layers at a Glance NemoClaw enforces security at four layers. @@ -72,44 +65,17 @@ flowchart TB style GW fill:#2a2a2a,stroke:#76b900,stroke-width:2px,color:#fff ``` -:::{list-table} -:header-rows: 1 -:widths: 20 30 20 30 - -* - Layer - - What it protects - - Enforcement point - - Changeable at runtime - -* - Network - - Unauthorized outbound connections and data exfiltration. - - OpenShell gateway - - Yes. Use `openshell policy set` or operator approval. - -* - Filesystem - - System binary tampering, credential theft, config manipulation. - - Landlock LSM + container mounts - - Landlock layout: no. Requires sandbox re-creation. Config lockdown posture: yes, with host-side shields commands. - -* - Process - - Privilege escalation, fork bombs, syscall abuse. - - Container runtime (Docker/K8s `securityContext`) - - No. Requires sandbox re-creation. - -* - Inference - - Credential exposure, unauthorized model access, cost overruns. - - OpenShell gateway - - Yes. Use `nemoclaw inference set`. - -::: +| Layer | What it protects | Enforcement point | Changeable at runtime | +| --- | --- | --- | --- | +| Network | Unauthorized outbound connections and data exfiltration. | OpenShell gateway | Yes. Use `openshell policy set` or operator approval. | +| Filesystem | System binary tampering, credential theft, config manipulation. | Landlock LSM + container mounts | Landlock layout: no. Requires sandbox re-creation. Config lockdown posture: yes, with host-side shields commands. | +| Process | Privilege escalation, fork bombs, syscall abuse. | Container runtime (Docker/K8s `securityContext`) | No. Requires sandbox re-creation. | +| Inference | Credential exposure, unauthorized model access, cost overruns. | OpenShell gateway | Yes. Use `nemoclaw inference set`. | ## Network Controls NemoClaw controls which hosts, ports, and HTTP methods the sandbox can reach, and lets operators approve or deny requests in real time. - - ### Deny-by-Default Egress The sandbox blocks all outbound connections unless you explicitly list the endpoint in the policy file `nemoclaw-blueprint/policies/openclaw-sandbox.yaml`. @@ -194,9 +160,6 @@ NemoClaw ships preset policy files in `nemoclaw-blueprint/policies/presets/` for NemoClaw restricts which paths the agent can read and write, protecting system binaries, configuration files, and gateway credentials. - - ### Read-Only System Paths The container mounts system directories read-only to prevent the agent from modifying binaries, libraries, or configuration files. @@ -256,9 +219,6 @@ Landlock is a Linux Security Module that enforces filesystem access rules at the NemoClaw limits the capabilities, user privileges, and resource quotas available to processes inside the sandbox. - - ### Capability Drops The entrypoint drops dangerous Linux capabilities from the bounding set at startup using `capsh`. @@ -549,4 +509,3 @@ The following patterns weaken security without providing meaningful benefit. - Sandbox Hardening (use the `nemoclaw-user-deploy-remote` skill) for container-level security measures. - Inference Options (use the `nemoclaw-user-configure-inference` skill) for provider configuration details. - How It Works (use the `nemoclaw-user-overview` skill) for the protection layer architecture. - diff --git a/.agents/skills/nemoclaw-user-configure-security/references/credential-storage.md b/.agents/skills/nemoclaw-user-configure-security/references/credential-storage.md index 24b520cb1d..3983a1e219 100644 --- a/.agents/skills/nemoclaw-user-configure-security/references/credential-storage.md +++ b/.agents/skills/nemoclaw-user-configure-security/references/credential-storage.md @@ -1,6 +1,6 @@ -# Credential Storage +# NemoClaw Credential Storage NemoClaw does not persist provider credentials to host disk. The OpenShell gateway is the only system of record for stored credentials. diff --git a/.agents/skills/nemoclaw-user-deploy-remote/references/brev-web-ui.md b/.agents/skills/nemoclaw-user-deploy-remote/references/brev-web-ui.md index 27a3638c75..35421cfbad 100644 --- a/.agents/skills/nemoclaw-user-deploy-remote/references/brev-web-ui.md +++ b/.agents/skills/nemoclaw-user-deploy-remote/references/brev-web-ui.md @@ -90,10 +90,10 @@ Provider: NVIDIA Cloud Click **Chat With Agent** to open the OpenClaw dashboard. -:> **Note:** The dashboard might initially show a **Pairing required** warning. +> **Note:** The dashboard might initially show a **Pairing required** warning. > This means the gateway is still completing pairing in the background. > Wait for about a few minutes for pairing to finish automatically. Refresh the dashboard to see if the warning is resolved and the connection is established. -> If pairing does not finish, go to the **Overview** page in the OpenClaw UI, find the **Gateway Access** panel, and click **Connect**.: +> If pairing does not finish, go to the **Overview** page in the OpenClaw UI, find the **Gateway Access** panel, and click **Connect**. ## Start a Chat diff --git a/.agents/skills/nemoclaw-user-get-started/SKILL.md b/.agents/skills/nemoclaw-user-get-started/SKILL.md index 69dc59dcf5..34bd1ba4dc 100644 --- a/.agents/skills/nemoclaw-user-get-started/SKILL.md +++ b/.agents/skills/nemoclaw-user-get-started/SKILL.md @@ -85,155 +85,117 @@ The Model Router option appears when the blueprint router profile is enabled. > For example, run `export NVIDIA_API_KEY=` before `curl ... | bash`. > If you entered a key incorrectly, refer to Reset a Stored Credential (use the `nemoclaw-user-manage-sandboxes` skill) to clear and re-enter it. -:::{dropdown} Option 1: NVIDIA Endpoints -:icon: server - -Routes inference to models hosted on [build.nvidia.com](https://build.nvidia.com). - -Use `NVIDIA_API_KEY` for the API key. Get one from the [NVIDIA build API keys page](https://build.nvidia.com/settings/api-keys). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, press Enter (or type `1`) to select **NVIDIA Endpoints**. -2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [1]:` prompt, pick a curated model from the list (for example, `Nemotron 3 Super 120B`, `GLM-5`, `MiniMax M2.7`, `GPT-OSS 120B`, or `DeepSeek V4 Pro`), or pick `Other...` to enter any model ID from the [NVIDIA Endpoints catalog](https://build.nvidia.com). - -NemoClaw validates the model against the catalog API before creating the sandbox. - -> **Tip:** Use this option for Nemotron and other models hosted on `build.nvidia.com`. If you run NVIDIA Nemotron from a self-hosted NIM, an enterprise gateway, or any other endpoint, choose **Option 3** instead, since all Nemotron models expose OpenAI-compatible APIs. -::: - -:::{dropdown} Option 2: OpenAI -:icon: server - -Routes inference to the OpenAI API at `https://api.openai.com/v1`. - -Use `OPENAI_API_KEY` for the API key. Get one from the [OpenAI API keys page](https://platform.openai.com/api-keys). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `2` to select **OpenAI**. -2. At the `OPENAI_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [1]:` prompt, pick a curated model (for example, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, or `gpt-5.4-pro-2026-03-05`), or pick **Other...** to enter any OpenAI model ID. -::: - -:::{dropdown} Option 3: Other OpenAI-Compatible Endpoint -:icon: link-external - -Routes inference to any server that implements `/v1/chat/completions`, including OpenRouter, LocalAI, llama.cpp, vLLM behind a proxy, and any compatible gateway. - -Use `COMPATIBLE_API_KEY` for the API key. Set it to whatever credential your endpoint expects. If your endpoint does not require auth, use any non-empty placeholder. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `3` to select **Other OpenAI-compatible endpoint**. -2. At the `OpenAI-compatible base URL` prompt, enter the provider's base URL. Find the exact value in your provider's API documentation. NemoClaw appends `/v1` automatically, so leave that suffix off. -3. At the `COMPATIBLE_API_KEY:` prompt, paste your key if it is not already exported. -4. At the `Other OpenAI-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your provider's model catalog. - -For example, when you use NVIDIA's OpenAI-compatible inference endpoint, enter `https://inference-api.nvidia.com` as the base URL and the model ID your endpoint exposes, such as `openai/openai/gpt-5.5`. - -NemoClaw sends a real inference request to validate the endpoint and model. -If the endpoint does not return the streaming events OpenClaw needs from the Responses API, NemoClaw falls back to the chat completions API and configures OpenClaw to use `openai-completions`. - -> **Tip:** NVIDIA Nemotron models expose OpenAI-compatible APIs, so this option is the right choice for any Nemotron deployment that does not live on `build.nvidia.com`. Common examples include a self-hosted NIM container, an enterprise NVIDIA AI Enterprise gateway, or a vLLM/SGLang server running Nemotron weights. Point the base URL at your endpoint and enter the Nemotron model ID exactly as your server reports it. -::: - -:::{dropdown} Option 4: Anthropic -:icon: server - -Routes inference to the Anthropic Messages API at `https://api.anthropic.com`. - -Use `ANTHROPIC_API_KEY` for the API key. Get one from the [Anthropic console keys page](https://console.anthropic.com/settings/keys). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `4` to select **Anthropic**. -2. At the `ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [1]:` prompt, pick a curated model (for example, `claude-sonnet-4-6`, `claude-haiku-4-5`, or `claude-opus-4-6`), or pick **Other...** to enter any Claude model ID. -::: - -:::{dropdown} Option 5: Other Anthropic-Compatible Endpoint -:icon: link-external - -Routes inference to any server that implements the Anthropic Messages API at `/v1/messages`, including Claude proxies, Bedrock-compatible gateways, and self-hosted Anthropic-compatible servers. - -Use `COMPATIBLE_ANTHROPIC_API_KEY` for the API key. Set it to whatever credential your endpoint expects. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `5` to select **Other Anthropic-compatible endpoint**. -2. At the `Anthropic-compatible base URL` prompt, enter the proxy or gateway's base URL from its documentation. -3. At the `COMPATIBLE_ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. -4. At the `Other Anthropic-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your gateway's model catalog. -::: - -:::{dropdown} Option 6: Google Gemini -:icon: server - -Routes inference to Google's OpenAI-compatible Gemini endpoint at `https://generativelanguage.googleapis.com/v1beta/openai/`. - -Use `GEMINI_API_KEY` for the API key. Get one from [Google AI Studio API keys](https://aistudio.google.com/app/apikey). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `6` to select **Google Gemini**. -2. At the `GEMINI_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [5]:` prompt, pick a curated model (for example, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, or `gemini-2.5-flash-lite`), or pick **Other...** to enter any Gemini model ID. -::: - -:::{dropdown} Option 7: Local Ollama -:icon: cpu - -Routes inference to a local Ollama instance. Depending on your platform, the wizard can use an existing daemon, start an installed daemon, or offer an install action. - -No API key is required. On non-WSL hosts, NemoClaw generates a token and starts an authenticated proxy so containers can reach Ollama without exposing the daemon directly to your network. -On WSL, NemoClaw can also use Ollama on the Windows host through `host.docker.internal`. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `7` to select **Local Ollama**. -2. At the `Choose model [1]:` prompt, pick from **Ollama models** if any are already installed. If none are installed, pick a **starter model** to pull and load now, or pick **Other...** to enter any Ollama model ID. - -For setup details, including GPU recommendations and starter model choices, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). - -::: - -:::{dropdown} Option 8: Model Router -:icon: git-compare - -Starts a host-side model router and routes sandbox inference through OpenShell to that router. -The router chooses from the model pool in `nemoclaw-blueprint/router/pool-config.yaml` for each request. - -Use `NVIDIA_API_KEY` for the model pool credentials. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `8` to select **Model Router (experimental)**. -2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. -3. Review the configuration summary and continue with the sandbox build. - -For scripted setup, set: - -```console -$ NEMOCLAW_PROVIDER=routed NVIDIA_API_KEY= nemoclaw onboard --non-interactive -``` - -The router listens on the host at port `4000`. -The sandbox still calls `https://inference.local/v1`, so do not point in-sandbox tools at the host router port directly. - -::: - -:::{dropdown} Experimental: Local NIM and Local vLLM -:icon: beaker - -These options appear when `NEMOCLAW_EXPERIMENTAL=1` is set and the prerequisites are met. - -- **Local NVIDIA NIM** requires a NIM-capable GPU. NemoClaw pulls and manages a NIM container. -- **Local vLLM** uses a vLLM server already running on `localhost:8000`, or installs and starts a managed vLLM container on supported DGX Spark, DGX Station, and Linux NVIDIA GPU hosts. NemoClaw auto-detects the loaded model. - -For setup, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). -::: +> **Option 1: NVIDIA Endpoints:** Routes inference to models hosted on [build.nvidia.com](https://build.nvidia.com). +> +> Use `NVIDIA_API_KEY` for the API key. Get one from the [NVIDIA build API keys page](https://build.nvidia.com/settings/api-keys). +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, press Enter (or type `1`) to select **NVIDIA Endpoints**. +> 2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. +> 3. At the `Choose model [1]:` prompt, pick a curated model from the list (for example, `Nemotron 3 Super 120B`, `GLM-5`, `MiniMax M2.7`, `GPT-OSS 120B`, or `DeepSeek V4 Pro`), or pick `Other...` to enter any model ID from the [NVIDIA Endpoints catalog](https://build.nvidia.com). +> +> NemoClaw validates the model against the catalog API before creating the sandbox. +> +> > **Tip:** Use this option for Nemotron and other models hosted on `build.nvidia.com`. If you run NVIDIA Nemotron from a self-hosted NIM, an enterprise gateway, or any other endpoint, choose **Option 3** instead, since all Nemotron models expose OpenAI-compatible APIs. + +> **Option 2: OpenAI:** Routes inference to the OpenAI API at `https://api.openai.com/v1`. +> +> Use `OPENAI_API_KEY` for the API key. Get one from the [OpenAI API keys page](https://platform.openai.com/api-keys). +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `2` to select **OpenAI**. +> 2. At the `OPENAI_API_KEY:` prompt, paste your key if it is not already exported. +> 3. At the `Choose model [1]:` prompt, pick a curated model (for example, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, or `gpt-5.4-pro-2026-03-05`), or pick **Other...** to enter any OpenAI model ID. + +> **Option 3: Other OpenAI-Compatible Endpoint:** Routes inference to any server that implements `/v1/chat/completions`, including OpenRouter, LocalAI, llama.cpp, vLLM behind a proxy, and any compatible gateway. +> +> Use `COMPATIBLE_API_KEY` for the API key. Set it to whatever credential your endpoint expects. If your endpoint does not require auth, use any non-empty placeholder. +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `3` to select **Other OpenAI-compatible endpoint**. +> 2. At the `OpenAI-compatible base URL` prompt, enter the provider's base URL. Find the exact value in your provider's API documentation. NemoClaw appends `/v1` automatically, so leave that suffix off. +> 3. At the `COMPATIBLE_API_KEY:` prompt, paste your key if it is not already exported. +> 4. At the `Other OpenAI-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your provider's model catalog. +> +> For example, when you use NVIDIA's OpenAI-compatible inference endpoint, enter `https://inference-api.nvidia.com` as the base URL and the model ID your endpoint exposes, such as `openai/openai/gpt-5.5`. +> +> NemoClaw sends a real inference request to validate the endpoint and model. +> If the endpoint does not return the streaming events OpenClaw needs from the Responses API, NemoClaw falls back to the chat completions API and configures OpenClaw to use `openai-completions`. +> +> > **Tip:** NVIDIA Nemotron models expose OpenAI-compatible APIs, so this option is the right choice for any Nemotron deployment that does not live on `build.nvidia.com`. Common examples include a self-hosted NIM container, an enterprise NVIDIA AI Enterprise gateway, or a vLLM/SGLang server running Nemotron weights. Point the base URL at your endpoint and enter the Nemotron model ID exactly as your server reports it. + +> **Option 4: Anthropic:** Routes inference to the Anthropic Messages API at `https://api.anthropic.com`. +> +> Use `ANTHROPIC_API_KEY` for the API key. Get one from the [Anthropic console keys page](https://console.anthropic.com/settings/keys). +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `4` to select **Anthropic**. +> 2. At the `ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. +> 3. At the `Choose model [1]:` prompt, pick a curated model (for example, `claude-sonnet-4-6`, `claude-haiku-4-5`, or `claude-opus-4-6`), or pick **Other...** to enter any Claude model ID. + +> **Option 5: Other Anthropic-Compatible Endpoint:** Routes inference to any server that implements the Anthropic Messages API at `/v1/messages`, including Claude proxies, Bedrock-compatible gateways, and self-hosted Anthropic-compatible servers. +> +> Use `COMPATIBLE_ANTHROPIC_API_KEY` for the API key. Set it to whatever credential your endpoint expects. +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `5` to select **Other Anthropic-compatible endpoint**. +> 2. At the `Anthropic-compatible base URL` prompt, enter the proxy or gateway's base URL from its documentation. +> 3. At the `COMPATIBLE_ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. +> 4. At the `Other Anthropic-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your gateway's model catalog. + +> **Option 6: Google Gemini:** Routes inference to Google's OpenAI-compatible Gemini endpoint at `https://generativelanguage.googleapis.com/v1beta/openai/`. +> +> Use `GEMINI_API_KEY` for the API key. Get one from [Google AI Studio API keys](https://aistudio.google.com/app/apikey). +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `6` to select **Google Gemini**. +> 2. At the `GEMINI_API_KEY:` prompt, paste your key if it is not already exported. +> 3. At the `Choose model [5]:` prompt, pick a curated model (for example, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, or `gemini-2.5-flash-lite`), or pick **Other...** to enter any Gemini model ID. + +> **Option 7: Local Ollama:** Routes inference to a local Ollama instance. Depending on your platform, the wizard can use an existing daemon, start an installed daemon, or offer an install action. +> +> No API key is required. On non-WSL hosts, NemoClaw generates a token and starts an authenticated proxy so containers can reach Ollama without exposing the daemon directly to your network. +> On WSL, NemoClaw can also use Ollama on the Windows host through `host.docker.internal`. +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `7` to select **Local Ollama**. +> 2. At the `Choose model [1]:` prompt, pick from **Ollama models** if any are already installed. If none are installed, pick a **starter model** to pull and load now, or pick **Other...** to enter any Ollama model ID. +> +> For setup details, including GPU recommendations and starter model choices, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). + +> **Option 8: Model Router:** Starts a host-side model router and routes sandbox inference through OpenShell to that router. +> The router chooses from the model pool in `nemoclaw-blueprint/router/pool-config.yaml` for each request. +> +> Use `NVIDIA_API_KEY` for the model pool credentials. +> +> Respond to the wizard as follows. +> +> 1. At the `Choose [1]:` prompt, type `8` to select **Model Router (experimental)**. +> 2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. +> 3. Review the configuration summary and continue with the sandbox build. +> +> For scripted setup, set: +> +> ```console +> $ NEMOCLAW_PROVIDER=routed NVIDIA_API_KEY= nemoclaw onboard --non-interactive +> ``` +> +> The router listens on the host at port `4000`. +> The sandbox still calls `https://inference.local/v1`, so do not point in-sandbox tools at the host router port directly. + +> **Experimental: Local NIM and Local vLLM:** These options appear when `NEMOCLAW_EXPERIMENTAL=1` is set and the prerequisites are met. +> +> - **Local NVIDIA NIM** requires a NIM-capable GPU. NemoClaw pulls and manages a NIM container. +> - **Local vLLM** uses a vLLM server already running on `localhost:8000`, or installs and starts a managed vLLM container on supported DGX Spark, DGX Station, and Linux NVIDIA GPU hosts. NemoClaw auto-detects the loaded model. +> +> For setup, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). ### Review the Configuration Before the Sandbox Build diff --git a/.agents/skills/nemoclaw-user-get-started/references/prerequisites.md b/.agents/skills/nemoclaw-user-get-started/references/prerequisites.md index be8dba0cbb..c8854f57b8 100644 --- a/.agents/skills/nemoclaw-user-get-started/references/prerequisites.md +++ b/.agents/skills/nemoclaw-user-get-started/references/prerequisites.md @@ -1,6 +1,6 @@ -# Prerequisites +# NemoClaw Prerequisites Before getting started, check the prerequisites to ensure you have the necessary software and hardware to run NemoClaw. @@ -32,16 +32,12 @@ On Debian and Ubuntu, NemoClaw installs `zstd` with `apt-get` if it is missing; On macOS, NemoClaw uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. You do not need to install or sign a separate OpenShell VM driver helper for standard macOS onboarding. -:::{warning} OpenShell Lifecycle -For NemoClaw-managed environments, use `nemoclaw onboard` when you need to create or recreate the OpenShell gateway or sandbox. -Avoid `openshell self-update`, `npm update -g openshell`, `openshell gateway start --recreate`, or `openshell sandbox create` directly unless you intend to manage OpenShell separately and then rerun `nemoclaw onboard`. -::: +> **OpenShell Lifecycle:** For NemoClaw-managed environments, use `nemoclaw onboard` when you need to create or recreate the OpenShell gateway or sandbox. +> Avoid `openshell self-update`, `npm update -g openshell`, `openshell gateway start --recreate`, or `openshell sandbox create` directly unless you intend to manage OpenShell separately and then rerun `nemoclaw onboard`. -:::{note} Docker storage driver -On Linux hosts running Docker 26 or later with the [containerd image store](https://docs.docker.com/engine/storage/containerd/) enabled (the install-time default for fresh `docker-ce` installations on Ubuntu 24.04 and similar distros), `nemoclaw onboard` transparently builds a `fuse-overlayfs`-enabled cluster image to bypass a kernel-level nested-overlay limitation in k3s. -No manual setup is required. -See the troubleshooting guide (use the `nemoclaw-user-reference` skill) for the override knobs and a manual `daemon.json` alternative. -::: +> **Docker storage driver:** On Linux hosts running Docker 26 or later with the [containerd image store](https://docs.docker.com/engine/storage/containerd/) enabled (the install-time default for fresh `docker-ce` installations on Ubuntu 24.04 and similar distros), `nemoclaw onboard` transparently builds a `fuse-overlayfs`-enabled cluster image to bypass a kernel-level nested-overlay limitation in k3s. +> No manual setup is required. +> See the troubleshooting guide (use the `nemoclaw-user-reference` skill) for the override knobs and a manual `daemon.json` alternative. ## Platforms diff --git a/.agents/skills/nemoclaw-user-manage-policy/references/approve-network-requests.md b/.agents/skills/nemoclaw-user-manage-policy/references/approve-network-requests.md index f0bd668ec8..a4f904430a 100644 --- a/.agents/skills/nemoclaw-user-manage-policy/references/approve-network-requests.md +++ b/.agents/skills/nemoclaw-user-manage-policy/references/approve-network-requests.md @@ -1,6 +1,6 @@ -# Approve or Deny Agent Network Requests +# Approve or Deny NemoClaw Agent Network Requests Review and act on network requests that the agent makes to endpoints not listed in the sandbox policy. OpenShell intercepts these requests and presents them in the TUI for operator approval. diff --git a/.agents/skills/nemoclaw-user-manage-sandboxes/SKILL.md b/.agents/skills/nemoclaw-user-manage-sandboxes/SKILL.md index 5805876d2a..cc2fb830fc 100644 --- a/.agents/skills/nemoclaw-user-manage-sandboxes/SKILL.md +++ b/.agents/skills/nemoclaw-user-manage-sandboxes/SKILL.md @@ -231,14 +231,13 @@ When a backup command reports partial archive output, NemoClaw keeps the usable See Backup and Restore (use the `nemoclaw-user-manage-sandboxes` skill) for the full list of state-preservation guarantees, snapshot retention, and instructions for manual backups when the auto-flow is not enough. -:::{note} If the rebuild aborts with `Missing credential: ` -The rebuild preflight reads the provider credential recorded by your last `nemoclaw onboard` session. -If you have switched providers since onboarding, for example from a remote API to a local Ollama setup, the preflight may still reference the old key and fail before any destroy step runs. - -To recover, re-run `nemoclaw onboard` and select your current provider. -This refreshes the session metadata. -Your existing container keeps serving traffic until the new image is ready. -::: +> **Note:** `"> +> The rebuild preflight reads the provider credential recorded by your last `nemoclaw onboard` session. +> If you have switched providers since onboarding, for example from a remote API to a local Ollama setup, the preflight may still reference the old key and fail before any destroy step runs. +> +> To recover, re-run `nemoclaw onboard` and select your current provider. +> This refreshes the session metadata. +> Your existing container keeps serving traffic until the new image is ready. ## Step 9: Uninstall diff --git a/.agents/skills/nemoclaw-user-manage-sandboxes/references/messaging-channels.md b/.agents/skills/nemoclaw-user-manage-sandboxes/references/messaging-channels.md index a9c8c6c9fc..05a9a8edc4 100644 --- a/.agents/skills/nemoclaw-user-manage-sandboxes/references/messaging-channels.md +++ b/.agents/skills/nemoclaw-user-manage-sandboxes/references/messaging-channels.md @@ -1,6 +1,6 @@ -# Messaging Channels +# Set Up Messaging Channels with NemoClaw and OpenShell Telegram, Discord, and Slack reach your agent through OpenShell-managed processes and gateway constructs. NemoClaw registers channel tokens with OpenShell providers, bakes the selected channel configuration into the sandbox image, and keeps runtime delivery under OpenShell control. diff --git a/.agents/skills/nemoclaw-user-overview/references/ecosystem.md b/.agents/skills/nemoclaw-user-overview/references/ecosystem.md index 1fc6ea0025..49e8121b1d 100644 --- a/.agents/skills/nemoclaw-user-overview/references/ecosystem.md +++ b/.agents/skills/nemoclaw-user-overview/references/ecosystem.md @@ -1,6 +1,6 @@ -# Ecosystem +# NemoClaw Ecosystem: Stack, Placement, and When to Use NemoClaw or OpenShell NemoClaw provides onboarding, lifecycle management, and OpenClaw operations within OpenShell containers. diff --git a/.agents/skills/nemoclaw-user-overview/references/how-it-works.md b/.agents/skills/nemoclaw-user-overview/references/how-it-works.md index 6e3571ce06..c9b4fbbafd 100644 --- a/.agents/skills/nemoclaw-user-overview/references/how-it-works.md +++ b/.agents/skills/nemoclaw-user-overview/references/how-it-works.md @@ -1,6 +1,6 @@ -# NemoClaw Architecture Overview +# NemoClaw Architecture Overview: Plugin, Blueprint, and Sandbox Lifecycle This page explains how NemoClaw runs OpenClaw inside an OpenShell sandbox and how the gateway connects the agent to inference, integrations, and policy. @@ -14,13 +14,9 @@ NemoClaw keeps the user workflow on the host while OpenShell enforces the sandbo The gateway sits between NemoClaw control, the sandbox, inference providers, and external integrations. That placement lets NemoClaw configure the environment without giving the agent direct access to host credentials or uncontrolled network egress. -```{figure} images/nemoclaw-highlevel-component-diagram.png -:alt: NemoClaw High-Level Component Diagram -:width: 100% -:align: center +![NemoClaw High-Level Component Diagram](https://docs.nvidia.com/nemoclaw/latest/about/images/nemoclaw-highlevel-component-diagram.html) -NemoClaw High-Level Component Diagram -``` +_NemoClaw High-Level Component Diagram_ The diagram has the following components: diff --git a/.agents/skills/nemoclaw-user-overview/references/overview.md b/.agents/skills/nemoclaw-user-overview/references/overview.md index 330cc0c740..613b52fb21 100644 --- a/.agents/skills/nemoclaw-user-overview/references/overview.md +++ b/.agents/skills/nemoclaw-user-overview/references/overview.md @@ -1,6 +1,6 @@ -# Overview of NVIDIA NemoClaw +# NemoClaw Overview: What It Is NVIDIA NemoClaw is an open-source reference stack that simplifies running [OpenClaw](https://openclaw.ai) always-on assistants more safely. NemoClaw provides onboarding, lifecycle management, and OpenClaw operations within OpenShell containers. diff --git a/.agents/skills/nemoclaw-user-overview/references/release-notes.md b/.agents/skills/nemoclaw-user-overview/references/release-notes.md index 6e7910522a..3370c4cd21 100644 --- a/.agents/skills/nemoclaw-user-overview/references/release-notes.md +++ b/.agents/skills/nemoclaw-user-overview/references/release-notes.md @@ -1,6 +1,6 @@ -# Release Notes +# NemoClaw Release Notes NVIDIA NemoClaw is available in early preview starting March 16, 2026. Use this page to track changes. diff --git a/.agents/skills/nemoclaw-user-reference/references/architecture.md b/.agents/skills/nemoclaw-user-reference/references/architecture.md index d0464cf652..f38e6f24c7 100644 --- a/.agents/skills/nemoclaw-user-reference/references/architecture.md +++ b/.agents/skills/nemoclaw-user-reference/references/architecture.md @@ -1,6 +1,6 @@ -# Architecture +# NemoClaw Architecture: Plugin, Blueprint, and Sandbox Structure NemoClaw combines a host CLI, a TypeScript plugin that runs with OpenClaw inside the sandbox, and a versioned YAML blueprint that defines the sandbox image, policies, and inference profiles applied through OpenShell. diff --git a/.agents/skills/nemoclaw-user-reference/references/commands.md b/.agents/skills/nemoclaw-user-reference/references/commands.md index 106c2656b3..b8c613120a 100644 --- a/.agents/skills/nemoclaw-user-reference/references/commands.md +++ b/.agents/skills/nemoclaw-user-reference/references/commands.md @@ -1,6 +1,6 @@ -# CLI Commands Reference +# NemoClaw CLI Commands Reference The `nemoclaw` CLI is the primary interface for managing NemoClaw sandboxes. It is installed automatically by the installer (`curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash`). diff --git a/.agents/skills/nemoclaw-user-reference/references/network-policies.md b/.agents/skills/nemoclaw-user-reference/references/network-policies.md index ac18bbbb90..b3be6782bd 100644 --- a/.agents/skills/nemoclaw-user-reference/references/network-policies.md +++ b/.agents/skills/nemoclaw-user-reference/references/network-policies.md @@ -1,6 +1,6 @@ -# Network Policies +# NemoClaw Network Policies: Baseline Rules and Operator Approval NemoClaw runs with a deny-by-default network policy. The sandbox can only reach endpoints that are explicitly allowed. @@ -26,41 +26,13 @@ Landlock LSM enforcement applies on a best-effort basis. The following endpoint groups are allowed by default: -:::{list-table} -:header-rows: 1 -:widths: 20 30 20 30 - -* - Policy - - Endpoints - - Binaries - - Rules - -* - `nvidia` - - `integrate.api.nvidia.com:443`, `inference-api.nvidia.com:443` - - `/usr/local/bin/openclaw` - - POST to inference and embedding paths, GET to model listings - -* - `clawhub` - - `clawhub.ai:443` - - `/usr/local/bin/openclaw`, `/usr/local/bin/node` - - GET, POST - -* - `openclaw_api` - - `openclaw.ai:443` - - `/usr/local/bin/openclaw`, `/usr/local/bin/node` - - GET, POST - -* - `openclaw_docs` - - `docs.openclaw.ai:443` - - `/usr/local/bin/openclaw` - - GET only - -* - `npm_registry` - - `registry.npmjs.org:443` - - `/usr/local/bin/openclaw` only (openclaw plugins install) - - GET only - -::: +| Policy | Endpoints | Binaries | Rules | +| --- | --- | --- | --- | +| `nvidia` | `integrate.api.nvidia.com:443`, `inference-api.nvidia.com:443` | `/usr/local/bin/openclaw` | POST to inference and embedding paths, GET to model listings | +| `clawhub` | `clawhub.ai:443` | `/usr/local/bin/openclaw`, `/usr/local/bin/node` | GET, POST | +| `openclaw_api` | `openclaw.ai:443` | `/usr/local/bin/openclaw`, `/usr/local/bin/node` | GET, POST | +| `openclaw_docs` | `docs.openclaw.ai:443` | `/usr/local/bin/openclaw` | GET only | +| `npm_registry` | `registry.npmjs.org:443` | `/usr/local/bin/openclaw` only (openclaw plugins install) | GET only | All endpoints use TLS termination and are enforced at port 443. @@ -71,7 +43,7 @@ All endpoints use TLS termination and are enforced at port 443. > Messaging endpoints for Telegram, Discord, and Slack are not included in the baseline policy. > Enable the channel during onboarding or apply the matching messaging preset so the sandbox can reach that platform. -(policy-tiers)= + ## Policy Tiers diff --git a/.agents/skills/nemoclaw-user-reference/references/troubleshooting.md b/.agents/skills/nemoclaw-user-reference/references/troubleshooting.md index 113a7d8e73..e25933f6b8 100644 --- a/.agents/skills/nemoclaw-user-reference/references/troubleshooting.md +++ b/.agents/skills/nemoclaw-user-reference/references/troubleshooting.md @@ -992,7 +992,7 @@ $ nemoclaw logs Use `--follow` to stream logs in real time while debugging. -(dgx-spark)= + ## DGX Spark @@ -1080,7 +1080,7 @@ $ pip install ... NVIDIA AI Workbench's Traefik proxy binds ports 3000 and 10000. If you run other services on Spark that expect port 3000, bind them to a different port. -(windows-wsl-2)= + ## Windows Subsystem for Linux diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 42a33385a8..423cd0eb5d 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -55,8 +55,9 @@ reviews: inline `code` formatting. - CLI code blocks must use the `console` language tag with `$` prompt prefix. Flag ```bash or ```shell for CLI examples. - - Use MyST admonitions (:::{tip}, :::{note}, :::{warning}) for callouts, - not bold text or blockquotes. + - Use Fern callout components (, , ) for callouts + in MDX pages, not bold text or blockquotes. MyST admonitions are + acceptable only in legacy .md pages that have not migrated yet. - No nested admonitions. - Do not number section titles. Flag "Section 1: ...", "Step 3: ...", etc. - No colons in titles. Flag "Inference: Cloud and Local" — should be diff --git a/.github/workflows/docs-links-pr.yaml b/.github/workflows/docs-links-pr.yaml index ca8a8da6e3..9a17580d10 100644 --- a/.github/workflows/docs-links-pr.yaml +++ b/.github/workflows/docs-links-pr.yaml @@ -9,6 +9,7 @@ on: types: [opened, reopened, synchronize] paths: - "**/*.md" + - "**/*.mdx" - ".github/workflows/docs-links-pr.yaml" - "test/e2e/e2e-cloud-experimental/check-docs.sh" @@ -25,16 +26,17 @@ jobs: with: fetch-depth: 0 - - name: Determine changed markdown files + - name: Determine changed documentation files id: changed shell: bash run: | set -euo pipefail base="${{ github.event.pull_request.base.sha }}" head="${{ github.event.pull_request.head.sha }}" - mapfile -t md_files < <( + mapfile -t doc_files < <( git diff --name-only --diff-filter=ACMR "$base" "$head" -- \ '*.md' \ + '*.mdx' \ ':(exclude)node_modules/**' \ ':(exclude)dist/**' \ ':(exclude)vendor/**' \ @@ -42,7 +44,7 @@ jobs: | LC_ALL=C sort -u ) - if [[ "${#md_files[@]}" -eq 0 ]]; then + if [[ "${#doc_files[@]}" -eq 0 ]]; then echo "has_files=false" >> "$GITHUB_OUTPUT" exit 0 fi @@ -50,7 +52,7 @@ jobs: echo "has_files=true" >> "$GITHUB_OUTPUT" { echo "files<> "$GITHUB_OUTPUT" @@ -59,5 +61,5 @@ jobs: shell: bash run: | set -euo pipefail - mapfile -t md_files <<< "${{ steps.changed.outputs.files }}" - bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-links --local-only "${md_files[@]}" + mapfile -t doc_files <<< "${{ steps.changed.outputs.files }}" + bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-links --local-only "${doc_files[@]}" diff --git a/.github/workflows/docs-preview-deploy.yaml b/.github/workflows/docs-preview-deploy.yaml deleted file mode 100644 index 1072fcd8b1..0000000000 --- a/.github/workflows/docs-preview-deploy.yaml +++ /dev/null @@ -1,106 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -# Step 2 of 2: Deploy (or clean up) the docs preview built by docs-preview-pr.yaml. -# Runs via workflow_run so it always has write access to gh-pages. -# Only deploys previews for same-repo PRs to prevent fork PRs from -# publishing arbitrary content to the GitHub Pages domain. - -name: Docs / Preview Deploy - -on: - workflow_run: - workflows: ["Docs / Preview Build"] - types: [completed] - -permissions: - contents: write - pull-requests: write - actions: read - -jobs: - deploy: - if: github.event.workflow_run.conclusion == 'success' - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - # Checkout first so subsequent artifact downloads are not clobbered. - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Download PR metadata - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: docs-preview-metadata - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Read PR metadata - id: meta - run: | - echo "pr-number=$(cat pr-number.txt)" >> "$GITHUB_OUTPUT" - if [ -f pr-action.txt ]; then - echo "action=$(cat pr-action.txt)" >> "$GITHUB_OUTPUT" - else - echo "action=deploy" >> "$GITHUB_OUTPUT" - fi - if [ -f same-repo.txt ]; then - echo "same-repo=$(cat same-repo.txt)" >> "$GITHUB_OUTPUT" - else - echo "same-repo=false" >> "$GITHUB_OUTPUT" - fi - - - name: Skip fork PRs - if: steps.meta.outputs.action != 'closed' && steps.meta.outputs.same-repo != 'true' - run: | - echo "::notice::Skipping preview deploy for fork PR #${{ steps.meta.outputs.pr-number }}" - exit 0 - - - name: Download docs artifact - if: steps.meta.outputs.action != 'closed' && steps.meta.outputs.same-repo == 'true' - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: docs-preview - path: docs-preview-html/ - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Deploy preview - if: steps.meta.outputs.action != 'closed' && steps.meta.outputs.same-repo == 'true' - uses: rossjrw/pr-preview-action@ffa7509e91a3ec8dfc2e5536c4d5c1acdf7a6de9 # v1 - with: - source-dir: ./docs-preview-html/ - preview-branch: gh-pages - umbrella-dir: pr-preview - action: deploy - pr-number: ${{ steps.meta.outputs.pr-number }} - comment: false - - - name: Post preview comment - if: steps.meta.outputs.action != 'closed' && steps.meta.outputs.same-repo == 'true' - uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 # v3.0.2 - with: - header: pr-preview - number: ${{ steps.meta.outputs.pr-number }} - message: | - :rocket: **Docs preview ready!** - - https://NVIDIA.github.io/NemoClaw/pr-preview/pr-${{ steps.meta.outputs.pr-number }}/ - - - name: Remove preview - if: steps.meta.outputs.action == 'closed' - uses: rossjrw/pr-preview-action@ffa7509e91a3ec8dfc2e5536c4d5c1acdf7a6de9 # v1 - with: - preview-branch: gh-pages - umbrella-dir: pr-preview - action: remove - pr-number: ${{ steps.meta.outputs.pr-number }} - comment: false - - - name: Remove preview comment - if: steps.meta.outputs.action == 'closed' - uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 # v3.0.2 - with: - header: pr-preview - number: ${{ steps.meta.outputs.pr-number }} - delete: true diff --git a/.github/workflows/docs-preview-pr.yaml b/.github/workflows/docs-preview-pr.yaml index d1ebb1a59e..c46836ebff 100644 --- a/.github/workflows/docs-preview-pr.yaml +++ b/.github/workflows/docs-preview-pr.yaml @@ -1,101 +1,99 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -# Step 1 of 2: Build docs on the PR and upload as an artifact. -# Step 2 (deploy) runs in docs-preview-deploy.yaml via workflow_run, -# which has write access to gh-pages regardless of PR origin. - -name: Docs / Preview Build +name: Docs / Fern Preview on: pull_request: branches: [main] - types: [opened, reopened, synchronize, closed] + types: [opened, reopened, synchronize] paths: - "docs/**" + - "fern/**" - "README.md" - - "pyproject.toml" - - "uv.lock" + - "package.json" + - "package-lock.json" - ".github/workflows/docs-preview-pr.yaml" - - ".github/workflows/docs-preview-deploy.yaml" concurrency: - group: preview-${{ github.ref }} + group: fern-preview-${{ github.ref }} cancel-in-progress: true permissions: contents: read + pull-requests: write jobs: - build: - if: github.event.action != 'closed' + preview: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - name: Checkout + - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 - with: - python-version: "3.11" - - - name: Install uv - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - - - name: Install doc dependencies - run: uv sync --group docs - - - name: Build documentation - run: uv run --group docs sphinx-build -W -b html docs docs/_build/html - - - name: Clean build artifacts + - name: Check Fern preview availability + id: fern-preview + env: + FERN_TOKEN: ${{ secrets.FERN_TOKEN }} run: | - find docs/_build -name .doctrees -prune -exec rm -rf {} \; - find docs/_build -name .buildinfo -exec rm {} \; - touch docs/_build/html/.nojekyll + if [ -n "$FERN_TOKEN" ]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "::notice::Skipping Fern docs preview because FERN_TOKEN is unavailable. This is expected for fork PRs and repos without Fern preview credentials configured." + fi - - name: Upload preview artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: - name: docs-preview - path: docs/_build/html/ - retention-days: 3 + node-version: "24" - - name: Save PR metadata + - name: Install Fern CLI run: | - echo "${{ github.event.pull_request.number }}" > pr-number.txt - if [ "${{ github.event.pull_request.head.repo.full_name }}" = "${{ github.repository }}" ]; then - echo "true" > same-repo.txt - else - echo "false" > same-repo.txt + FERN_VERSION=$(node -p "require('./fern/fern.config.json').version") + npm install -g "fern-api@${FERN_VERSION}" + + - name: Validate docs + working-directory: ./fern + run: fern check + + - name: Generate preview URL + if: ${{ steps.fern-preview.outputs.enabled == 'true' }} + id: generate-docs + env: + FERN_TOKEN: ${{ secrets.FERN_TOKEN }} + PREVIEW_ID: pr-${{ github.event.pull_request.number }} + working-directory: ./fern + run: | + OUTPUT=$(fern generate --docs --preview --id "$PREVIEW_ID" 2>&1) + echo "$OUTPUT" + URL=$(echo "$OUTPUT" | grep -oP 'Published docs to \K.*(?= \()') + if [ -z "$URL" ]; then + echo "::error::Failed to generate preview URL. See fern output above." + exit 1 fi + echo "preview_url=$URL" >> "$GITHUB_OUTPUT" + + - name: Post or update PR comment + if: ${{ steps.fern-preview.outputs.enabled == 'true' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PREVIEW_URL: ${{ steps.generate-docs.outputs.preview_url }} + run: | + BODY=":herb: **Preview your docs:** <${PREVIEW_URL}>" + MARKER="" + BODY="${BODY} - - name: Upload PR metadata - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: docs-preview-metadata - path: | - pr-number.txt - same-repo.txt - retention-days: 3 + ${MARKER}" - # On PR close, trigger the deploy workflow to clean up the preview. - close: - if: github.event.action == 'closed' - runs-on: ubuntu-latest - timeout-minutes: 2 - steps: - - name: Save PR metadata - run: | - echo "${{ github.event.pull_request.number }}" > pr-number.txt - echo "closed" > pr-action.txt + COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + --jq ".[] | select(.body | contains(\"${MARKER}\")) | .id" | head -1) - - name: Upload PR metadata - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 - with: - name: docs-preview-metadata - path: | - pr-number.txt - pr-action.txt - retention-days: 3 + if [ -n "$COMMENT_ID" ]; then + gh api "repos/${{ github.repository }}/issues/comments/${COMMENT_ID}" \ + -X PATCH -f body="$BODY" + else + gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ + -f body="$BODY" + fi diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index be59273d12..c368828e74 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -201,9 +201,9 @@ repos: hooks: - id: docs-to-skills-dry-run name: Verify docs-to-skills output - entry: python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run + entry: python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx --dry-run language: system - files: ^(docs/.*\.md$|docs/conf\.py$|ci/platform-matrix\.json$|scripts/docs-to-skills\.py$|scripts/generate-platform-docs\.py$) + files: ^(docs/.*\.mdx?$|docs/conf\.py$|ci/platform-matrix\.json$|scripts/docs-to-skills\.py$|scripts/generate-platform-docs\.py$) pass_filenames: false priority: 10 @@ -281,7 +281,7 @@ repos: bash -c 'node -e "require(\"node:fs\").rmSync(\"dist\", { recursive: true, force: true })" && npm run build:cli && npx tsx scripts/check-dist-sourcemaps.ts dist && npx vitest run --project cli --coverage --coverage.reporter=text-summary --coverage.reporter=json-summary --coverage.reportsDirectory=coverage/cli --coverage.include="bin/**/*.js" --coverage.include="dist/lib/**/*.js" --coverage.exclude="test/**/*.js" --coverage.exclude="test/**/*.ts" && npx tsx scripts/check-coverage-ratchet.ts coverage/cli/coverage-summary.json ci/coverage-threshold-cli.json "CLI coverage"' language: system pass_filenames: false - files: ^(bin/|src/|test/) + files: ^(bin/|src/.*\.(ts|tsx|js|mjs|cjs)$|test/.*\.(ts|tsx|js|mjs|cjs)$) priority: 20 - id: test-plugin @@ -305,7 +305,7 @@ repos: entry: npx vitest run test/skills-frontmatter.test.ts language: system pass_filenames: false - files: ^(\.agents/skills/|docs/.*\.md$|scripts/docs-to-skills\.py$|test/skills-frontmatter\.test\.js$) + files: ^(\.agents/skills/|docs/.*\.mdx?$|scripts/docs-to-skills\.py$|test/skills-frontmatter\.test\.js$) priority: 20 default_language_version: diff --git a/AGENTS.md b/AGENTS.md index 655f602918..ea315b8773 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,7 +28,8 @@ This repo ships agent skills under `.agents/skills/`, organized into three audie | `scripts/` | Bash/JS/TS | Install helpers, setup, automation, E2E tooling | | `test/` | JavaScript (ESM) | Root-level integration tests (Vitest) | | `test/e2e/` | Bash/JS/TS | End-to-end tests, scenario-based runner (see `test/e2e/README.md`) | -| `docs/` | Markdown (MyST) | User-facing docs (Sphinx) | +| `docs/` | MDX/Markdown | User-facing docs (Fern MDX plus legacy MyST source during migration) | +| `fern/` | YAML/CSS/SVG | Fern site configuration and shared assets | ## Quick Reference @@ -52,7 +53,7 @@ This repo ships agent skills under `.agents/skills/`, organized into three audie - **CLI and plugin**: TypeScript (`src/`, `nemoclaw/src/`) with a small CommonJS launcher in `bin/`; ESM in `test/` - **Blueprint**: YAML configuration (`nemoclaw-blueprint/`) -- **Docs**: Sphinx/MyST Markdown +- **Docs**: Fern MDX for migrated pages; legacy MyST Markdown remains during the transition for generated skills and parity checks - **Tooling scripts**: Bash and Python The `bin/` directory uses CommonJS intentionally for the launcher and a few compatibility helpers so the CLI still has a stable executable entry point. The main CLI implementation lives in `src/` and compiles to `dist/`. The `nemoclaw/` plugin uses TypeScript and requires compilation. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c60e91f424..e8a176e09a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,8 +76,8 @@ These are the primary `make` and `npm` targets for day-to-day development: | `npm run typecheck:cli` | Type-check CLI TypeScript using `tsconfig.cli.json` (`bin/`, `scripts/`, `src/`, `test/`, `nemoclaw-blueprint/scripts/`) | | `npm test` | Run root-level tests (`test/*.test.js`) | | `cd nemoclaw && npm test` | Run plugin unit tests (Vitest) | -| `make docs` | Build documentation (Sphinx/MyST) | -| `make docs-live` | Serve docs locally with auto-rebuild | +| `make docs` | Validate Fern documentation | +| `make docs-live` | Serve Fern docs locally with auto-rebuild | | `npx prek run --all-files` | Run all hooks from `.pre-commit-config.yaml` — see below | ### Git hooks (prek) @@ -123,7 +123,8 @@ The repository is organized as follows. | `bin/` | CLI entry point (`nemoclaw.js`) | | `scripts/` | Install helpers and automation scripts | | `test/` | Root-level integration tests | -| `docs/` | User-facing documentation (Sphinx/MyST) | +| `docs/` | User-facing documentation (Fern MDX plus legacy MyST source during migration) | +| `fern/` | Fern site configuration, theme, and assets | ## Language Policy @@ -142,9 +143,9 @@ During release prep, run that skill first, make any doc version bumps, regenerat To build and preview docs locally: -```bash -make docs # build the docs -make docs-live # serve locally with auto-rebuild +```console +$ make docs # validate the Fern docs +$ make docs-live # serve Fern docs locally with auto-rebuild ``` See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for the full style guide and writing conventions. diff --git a/Makefile b/Makefile index 4211f08836..999a63d0ab 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: check lint format format-biome lint-ts format-ts check-installer-hash docs docs-strict docs-live docs-clean +.PHONY: check lint format format-biome lint-ts format-ts check-installer-hash docs docs-deps docs-strict docs-live docs-clean check: npm run check @@ -29,6 +29,9 @@ check-installer-hash: docs: npm run docs +docs-deps: + npm run docs:deps + docs-strict: npm run docs:strict diff --git a/README.md b/README.md index 375dec33c8..1fe76b9781 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,8 @@ NemoClaw/ │ └── llm-router/ # LLM Router v3 submodule (prefill routing engine) ├── scripts/ # Install helpers, setup, automation ├── test/ # Integration and E2E tests -└── docs/ # User-facing docs (Sphinx/MyST) +├── fern/ # Fern site configuration and shared assets +└── docs/ # User-facing docs (Fern MDX plus legacy MyST source during migration) ``` ## Community diff --git a/biome.json b/biome.json index 255251fcc9..a8505e3f80 100644 --- a/biome.json +++ b/biome.json @@ -17,6 +17,7 @@ "src/**/*.ts", "bin/**/*.js", "scripts/**/*.js", + "scripts/**/*.mjs", "scripts/**/*.ts", "test/**/*.js", "docs/_ext/**/*.js", @@ -92,6 +93,7 @@ "bin/**/*.js", "commitlint.config.js", "scripts/**/*.js", + "scripts/**/*.mjs", "test/**/*.js", "docs/_ext/**/*.js" ], diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 18cd86d286..27273a9995 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -40,16 +40,16 @@ The current generated skills and their source pages are: | Skill | Source docs | |---|---| -| `nemoclaw-user-overview` | `docs/about/overview.md`, `docs/about/ecosystem.md`, `docs/about/how-it-works.md`, `docs/about/release-notes.md` | -| `nemoclaw-user-agent-skills` | `docs/resources/agent-skills.md` | -| `nemoclaw-user-deploy-remote` | `docs/deployment/deploy-to-remote-gpu.md`, `docs/deployment/install-openclaw-plugins.md`, `docs/deployment/sandbox-hardening.md` | -| `nemoclaw-user-get-started` | `docs/get-started/prerequisites.md`, `docs/get-started/quickstart.md`, `docs/get-started/quickstart-hermes.md`, `docs/get-started/windows-preparation.md` | -| `nemoclaw-user-configure-inference` | `docs/inference/inference-options.md`, `docs/inference/use-local-inference.md`, `docs/inference/switch-inference-providers.md`, `docs/inference/set-up-sub-agent.md` | -| `nemoclaw-user-manage-sandboxes` | `docs/manage-sandboxes/lifecycle.md`, `docs/manage-sandboxes/messaging-channels.md`, `docs/manage-sandboxes/workspace-files.md`, `docs/manage-sandboxes/backup-restore.md` | -| `nemoclaw-user-monitor-sandbox` | `docs/monitoring/monitor-sandbox-activity.md` | -| `nemoclaw-user-manage-policy` | `docs/network-policy/customize-network-policy.md`, `docs/network-policy/integration-policy-examples.md`, `docs/network-policy/approve-network-requests.md` | -| `nemoclaw-user-reference` | `docs/reference/architecture.md`, `docs/reference/commands.md`, `docs/reference/cli-selection-guide.md`, `docs/reference/network-policies.md`, `docs/reference/troubleshooting.md` | -| `nemoclaw-user-configure-security` | `docs/security/best-practices.md`, `docs/security/credential-storage.md`, `docs/security/openclaw-controls.md` | +| `nemoclaw-user-overview` | `docs/about/overview.mdx`, `docs/about/ecosystem.mdx`, `docs/about/how-it-works.mdx`, `docs/about/release-notes.mdx` | +| `nemoclaw-user-agent-skills` | `docs/resources/agent-skills.mdx` | +| `nemoclaw-user-deploy-remote` | `docs/deployment/deploy-to-remote-gpu.mdx`, `docs/deployment/install-openclaw-plugins.mdx`, `docs/deployment/sandbox-hardening.mdx` | +| `nemoclaw-user-get-started` | `docs/get-started/prerequisites.mdx`, `docs/get-started/quickstart.mdx`, `docs/get-started/quickstart-hermes.mdx`, `docs/get-started/windows-preparation.mdx` | +| `nemoclaw-user-configure-inference` | `docs/inference/inference-options.mdx`, `docs/inference/use-local-inference.mdx`, `docs/inference/switch-inference-providers.mdx`, `docs/inference/set-up-sub-agent.mdx` | +| `nemoclaw-user-manage-sandboxes` | `docs/manage-sandboxes/lifecycle.mdx`, `docs/manage-sandboxes/messaging-channels.mdx`, `docs/manage-sandboxes/workspace-files.mdx`, `docs/manage-sandboxes/backup-restore.mdx` | +| `nemoclaw-user-monitor-sandbox` | `docs/monitoring/monitor-sandbox-activity.mdx` | +| `nemoclaw-user-manage-policy` | `docs/network-policy/customize-network-policy.mdx`, `docs/network-policy/integration-policy-examples.mdx`, `docs/network-policy/approve-network-requests.mdx` | +| `nemoclaw-user-reference` | `docs/reference/architecture.mdx`, `docs/reference/commands.mdx`, `docs/reference/cli-selection-guide.mdx`, `docs/reference/network-policies.mdx`, `docs/reference/troubleshooting.mdx` | +| `nemoclaw-user-configure-security` | `docs/security/best-practices.mdx`, `docs/security/credential-storage.mdx`, `docs/security/openclaw-controls.mdx` | ### Regenerating NemoClaw User Skills after Doc Changes @@ -62,13 +62,13 @@ For daily release prep, the NemoClaw maintainers use this sequence: 1. Run the `nemoclaw-contributor-update-docs` skill for the day's release prep. 2. Make doc version bumps by updating `versions1.json` and `project.json` in the `docs/` directory. -3. Run `python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user`. +3. Run `python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx`. 4. Create the PR with both docs and generated user skills. To regenerate skills manually during release prep, run from the repo root: ```bash -python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user +python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx ``` Always use this exact output path (`.agents/skills/`) and prefix (`nemoclaw-user`) so skill names and locations stay consistent. @@ -76,7 +76,7 @@ Always use this exact output path (`.agents/skills/`) and prefix (`nemoclaw-user Preview what would change before writing files: ```bash -python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run +python scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx --dry-run ``` Other useful flags: @@ -84,8 +84,9 @@ Other useful flags: | Flag | Purpose | |------|---------| | `--strategy ` | Grouping strategy: `smart` (default), `grouped`, or `individual`. | +| `--doc-platform ` | Source format: `fern-mdx` for migrated Fern pages or `myst-md` for legacy Markdown. | | `--name-map CAT=NAME` | Override a generated skill name (e.g. `--name-map about=overview`). | -| `--exclude ` | Skip specific files (e.g. `--exclude "release-notes.md"`). | +| `--exclude ` | Skip specific files (e.g. `--exclude "release-notes.mdx"`). | ### How the Script Works @@ -94,7 +95,7 @@ Within each group, the procedure page (`how_to`, `get_started`, or `tutorial`) w Sibling procedure pages, concept pages, and reference pages go into a `references/` subdirectory for progressive disclosure, keeping `SKILL.md` concise while preserving access to the full docs. Cross-references between doc pages are rewritten as skill-to-skill pointers so agents can navigate between skills. -MyST/Sphinx directives are converted to standard markdown. +Fern MDX components and MyST/Sphinx directives are converted to standard markdown. For full usage details and all flags, see the docstring at the top of `scripts/docs-to-skills.py`. @@ -102,26 +103,28 @@ For full usage details and all flags, see the docstring at the top of `scripts/d Verify the docs are built correctly by building them and checking the output. -To build the docs, run: +The public site is built with Fern. To validate the Fern configuration and migrated MDX pages, run: -```bash -make docs +```console +$ make docs ``` To serve the docs locally and automatically rebuild on changes, run: -```bash -make docs-live +```console +$ make docs-live ``` +Fern `.mdx` pages are the source for generated user skills. Legacy `.md` pages may remain temporarily for parity checks, but release-prep skill generation should pass `--doc-platform fern-mdx`. + ## Doc-Only PR Verification Doc-only pull requests do not need the full test suite by default. Before opening a doc-only PR, run: -```bash -npx prek run --all-files -make docs +```console +$ npx prek run --all-files +$ make docs ``` Leave `npm test` unchecked in the PR verification checklist unless you actually ran it. @@ -131,18 +134,39 @@ Run the full tests only when the change also touches code, generated behavior, o ### Format -- Docs use [MyST Markdown](https://myst-parser.readthedocs.io/), a Sphinx-compatible superset of CommonMark. -- Every page starts with YAML frontmatter (title, description.main, description.agent, topics, tags, content type). -- Include the SPDX license header after frontmatter: - - ```html - +- Fern pages use MDX with YAML frontmatter. Use a flat `title`, `description`, optional `sidebar-title`, `description-agent`, `keywords`, and `position`. +- Do not duplicate the page title as a body H1 in MDX pages because Fern renders the title from frontmatter. +- The docs-to-skills pipeline treats Fern `description-agent` as the equivalent of legacy MyST `description.agent`. +- Include the SPDX license header in MDX frontmatter as comments: + + ```yaml + --- + # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + # SPDX-License-Identifier: Apache-2.0 + title: "NemoClaw Page Title" + description: "One-sentence summary for readers, SEO, and doc search snippets." + description-agent: "Third-person verb summary for agent routing. Add 'Use when...' with trigger phrases." + --- ``` -### Frontmatter Template +### MDX Frontmatter Template + +```yaml +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Page Title: Subtitle with Context" +sidebar-title: "Short Nav Title" +description: "One-sentence summary for readers, SEO, and doc search snippets." +description-agent: "Third-person verb summary for agent routing. Add 'Use when...' with trigger phrases." +keywords: "primary keyword, secondary keyword phrase" +position: 1 +--- +``` + +### Legacy Skill Frontmatter Template + +Use this nested shape only for legacy `.md` pages when running the pipeline with `--doc-platform myst-md`. ```yaml --- @@ -171,10 +195,10 @@ For example, set the OpenClaw quickstart to `10` and the Hermes quickstart to `2 ### Page Structure -1. H1 heading matching the `title.page` value. -2. A one- or two-sentence introduction stating what the page covers. -3. Sections organized by task or concept, using H2 and H3. Start each section with an introductory sentence that orients the reader. -4. A "Next Steps" section at the bottom linking to related pages. +1. Start MDX pages with a one- or two-sentence introduction stating what the page covers. +2. Organize sections by task or concept, using H2 and H3. Start each section with an introductory sentence that orients the reader. +3. Use Fern components like ``, ``, ``, ``, and `` for callouts and landing-page navigation. +4. Add a "Next Steps" or "Related Topics" section at the bottom when it helps users continue. ## Style Guide @@ -212,7 +236,8 @@ These patterns are common in LLM-generated text and erode trust with technical r ``` - Use tables for structured comparisons. Keep tables simple (no nested formatting). -- Use MyST admonitions (`:::{tip}`, `:::{note}`, `:::{warning}`) for callouts, not bold text. +- Use Fern callout components (``, ``, ``) for callouts in MDX pages, not bold text. +- Use MyST admonitions (`:::{tip}`, `:::{note}`, `:::{warning}`) only in legacy `.md` pages that have not migrated yet. - Avoid nested admonitions. - Do not number section titles. Write "Deploy a Gateway" not "Section 1: Deploy a Gateway" or "Step 3: Verify." - Do not use colons in titles. Write "Deploy and Manage Gateways" not "Gateways: Deploy and Manage." diff --git a/docs/about/ecosystem.mdx b/docs/about/ecosystem.mdx new file mode 100644 index 0000000000..7c39551222 --- /dev/null +++ b/docs/about/ecosystem.mdx @@ -0,0 +1,101 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Ecosystem: Stack, Placement, and When to Use NemoClaw or OpenShell" +sidebar-title: "Ecosystem" +description: "How the OpenClaw, OpenShell, and NemoClaw projects form one stack, where NemoClaw sits, what it adds beyond the OpenShell community sandbox, and when to use the reference integration versus OpenShell alone." +description-agent: "Explains how OpenClaw, OpenShell, and NemoClaw form the ecosystem, NemoClaw's position in the stack, what NemoClaw adds beyond the community sandbox, and when to prefer NemoClaw versus integrating OpenShell and OpenClaw directly. Use when users ask about the relationship between OpenClaw, OpenShell, and NemoClaw, or when to use NemoClaw versus OpenShell." +keywords: ["nemoclaw ecosystem", "openclaw openshell", "nemoclaw vs openshell", "sandboxed openclaw"] +content: + type: "concept" +--- +NemoClaw provides onboarding, lifecycle management, and OpenClaw operations within OpenShell containers. + +This page describes how the ecosystem is formed across projects, where NemoClaw sits relative to [OpenShell](https://github.com/NVIDIA/OpenShell) and [OpenClaw](https://openclaw.ai), and how to choose between NemoClaw and OpenShell. + +## How the Stack Fits Together + +There are three pieces that are put together in a NemoClaw deployment: OpenClaw, OpenShell, and NemoClaw, each with a distinct scope. +The following diagram shows how they fit together. + +```mermaid +flowchart TB + NC["🦞 NVIDIA NemoClaw
CLI, plugin, blueprint"] + OS["🐚 NVIDIA OpenShell
Gateway, policy, inference routing"] + OC["🦞 OpenClaw
Assistant in sandbox"] + + NC -->|orchestrates| OS + OS -->|isolates and runs| OC + + classDef nv fill:#76b900,stroke:#333,color:#fff + classDef nvLight fill:#e6f2cc,stroke:#76b900,color:#1a1a1a + classDef nvDark fill:#333,stroke:#76b900,color:#fff + + class NC nv + class OS nv + class OC nvDark + + linkStyle 0 stroke:#76b900,stroke-width:2px + linkStyle 1 stroke:#76b900,stroke-width:2px +``` + +NemoClaw sits above OpenShell in the operator workflow. +It drives OpenShell APIs and CLI to create and configure the sandbox that runs OpenClaw. +Models and endpoints sit behind OpenShell's inference routing. +NemoClaw onboarding wires provider choice into that routing. + +The following table shows the scope of each component in the stack. + +| Project | Scope | +|---------|--------| +| [OpenClaw](https://openclaw.ai) | The assistant: runtime, tools, memory, and behavior inside the container. It does not define the sandbox or the host gateway. | +| [OpenShell](https://github.com/NVIDIA/OpenShell) | The execution environment: sandbox lifecycle, network, filesystem, and process policy, inference routing, and the operator-facing `openshell` CLI for those primitives. | +| NemoClaw | The NVIDIA reference stack that implements the definition above on the host: `nemoclaw` CLI and plugin, versioned blueprint, channel messaging configured for OpenShell-managed delivery, and state migration helpers so OpenClaw runs inside OpenShell in a documented, repeatable way. | + +## NemoClaw Path versus OpenShell Path + +Both paths assume OpenShell can sandbox a workload. +The difference is who owns the integration work. + +| Path | What it means | +|------|---------------| +| **NemoClaw path** | You adopt the reference stack. NemoClaw's blueprint encodes a hardened image, default policies, and orchestration so `nemoclaw onboard` can stand up a known-good OpenClaw-on-OpenShell setup with less custom glue. | +| **OpenShell path** | You use OpenShell as the platform and supply your own container, install steps for OpenClaw, policy YAML, provider setup, and any host bridges. OpenShell stays the sandbox and policy engine; nothing requires NemoClaw's blueprint or CLI. | + +## What NemoClaw Adds Beyond the OpenShell Community Sandbox + +OpenShell ships a community sandbox for OpenClaw. +Running `openshell sandbox create --from openclaw` pulls that package, builds the image, applies the bundled policy, and starts a working sandbox. +This is a valid path, and it produces a running OpenClaw environment with OpenShell isolation. + +NemoClaw builds on that foundation with additional security hardening, automation, and lifecycle tooling. +The following table compares the two paths. + +| Capability | `openshell sandbox create --from openclaw` | `nemoclaw onboard` | +|---|---|---| +| Sandbox isolation | Yes. OpenShell applies seccomp filters, Landlock filesystem restrictions, privilege dropping, network namespace isolation, and no-new-privileges enforcement. The community sandbox bundles its own policy tailored for OpenClaw. | Yes. NemoClaw applies these through the blueprint and layers a more restrictive policy on top (see rows below). | +| Credential handling | OpenShell's provider system replaces real credentials with placeholder tokens in the sandbox environment. The L7 proxy resolves placeholders to real values at egress. You create providers manually with `openshell provider create`. | NemoClaw creates OpenShell providers automatically during onboarding. It also filters sensitive host environment variables (provider API keys, `DISCORD_BOT_TOKEN`, `SLACK_BOT_TOKEN`, `TELEGRAM_BOT_TOKEN`) from the sandbox creation command to prevent accidental leakage through build args. | +| Image hardening | The community image includes standard system tools for general-purpose use. | NemoClaw strips build toolchains (`gcc`, `g++`, `make`) and network probes (`netcat`) from the runtime image to reduce attack surface. | +| Filesystem policy | The community sandbox bundles a policy for OpenClaw. | NemoClaw defines a targeted read-only and read-write layout. System paths (`/usr`, `/lib`, `/etc`) are read-only. The agent's home directory (`/sandbox`) and config directory (`/sandbox/.openclaw`) are writable by default so the agent can manage config, install skills, and write to standard paths natively. | +| Inference setup | The community sandbox includes an `openclaw-start` script that runs OpenClaw's onboarding wizard inside the sandbox. You can also create providers and configure OpenShell inference routing manually from the host. | NemoClaw's onboarding wizard validates your credential from the host, lets you select a provider (NVIDIA Endpoints, OpenAI, Anthropic, Google Gemini, Ollama, and compatible endpoints), and configures OpenShell's inference routing automatically. Credentials stay on the host and are delivered through OpenShell's provider system. | +| Channel messaging | OpenShell provides the credential provider system and L7 proxy that delivers channel tokens securely (including path-based resolution for Telegram's `/bot/` URL pattern). You create providers and configure OpenClaw's channel settings manually. | NemoClaw automates channel setup during onboarding: it collects bot tokens, registers them as OpenShell providers, and bakes OpenClaw channel config with placeholder tokens that OpenShell's proxy resolves at egress. No separate bridge process runs on the host. | +| Blueprint versioning | No blueprint. The community sandbox uses whatever image version is currently published. | NemoClaw downloads the blueprint artifact, checks version compatibility, and verifies its digest before applying. Running `nemoclaw onboard` on different machines produces the same sandbox. | +| State migration | Not included. | NemoClaw migrates agent state across machines with credential stripping and integrity verification. | +| Process count limits | OpenShell applies seccomp and privilege dropping. You set process count limits manually with `--ulimit` or orchestrator config. | NemoClaw applies `ulimit -u 512` in the container entrypoint to cap the process count and mitigate fork-bomb attacks, on top of OpenShell's seccomp and privilege dropping. | + +## When to Use Which + +Use the following table to decide when to use NemoClaw versus OpenShell. + +| Situation | Prefer | +|-----------|--------| +| You want OpenClaw with minimal assembly, NVIDIA defaults, and the documented install and onboard flow. | NemoClaw | +| You need maximum flexibility for custom images, a layout that does not match the NemoClaw blueprint, or a workload outside this reference stack. | OpenShell with your own integration | +| You are standardizing on the NVIDIA reference for always-on assistants with policy and inference routing. | NemoClaw | +| You are building internal platform abstractions where the NemoClaw CLI or blueprint is not the right fit. | OpenShell (and your orchestration) | + +## Related topics + +- [Overview](/about/overview) contains what NemoClaw is, capabilities, benefits, and use cases. +- [How It Works](/about/how-it-works) describes how NemoClaw runs, plugin, blueprint, sandbox creation, routing, protection layers. +- [Architecture](/reference/architecture) shows the repository structure and technical diagrams. diff --git a/docs/about/how-it-works.mdx b/docs/about/how-it-works.mdx new file mode 100644 index 0000000000..b937c9000c --- /dev/null +++ b/docs/about/how-it-works.mdx @@ -0,0 +1,113 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Architecture Overview: Plugin, Blueprint, and Sandbox Lifecycle" +sidebar-title: "How It Works" +description: "Learn how NemoClaw combines a host CLI, sandbox plugin, and versioned blueprint to move OpenClaw into a controlled sandbox." +description-agent: "Describes how NemoClaw works internally: CLI, plugin, blueprint runner, OpenShell orchestration, inference routing, and protection layers. Use for sandbox lifecycle and architecture mechanics; not for product definition (Overview) or multi-project placement (Ecosystem)." +keywords: ["how nemoclaw works", "nemoclaw sandbox lifecycle blueprint"] +content: + type: "concept" +--- +This page explains how NemoClaw runs OpenClaw inside an OpenShell sandbox and how the gateway connects the agent to inference, integrations, and policy. + +NemoClaw does not replace OpenClaw or OpenShell. +It packages them into a repeatable setup with a host CLI, a versioned blueprint, default policies, inference setup, plugin configuration, and state helpers. +You can use that setup directly or adapt it for your own OpenShell integration. + +## High-Level Flow + +NemoClaw keeps the user workflow on the host while OpenShell enforces the sandbox boundary. +The gateway sits between NemoClaw control, the sandbox, inference providers, and external integrations. +That placement lets NemoClaw configure the environment without giving the agent direct access to host credentials or uncontrolled network egress. + +![NemoClaw High-Level Component Diagram](images/nemoclaw-highlevel-component-diagram.png) + +_NemoClaw High-Level Component Diagram_ + +The diagram has the following components: + +| Component | Role in the flow | +|-------|------------------| +| Users and operators | Start from the CLI, installer, dashboard, or an end-user channel. | +| NemoClaw control | Collects configuration, runs onboarding, prepares the blueprint, and asks OpenShell to create or update resources. | +| OpenShell gateway | Owns sandbox lifecycle, networking, policy enforcement, inference routing, and integration egress. | +| NemoClaw sandbox | Runs OpenClaw with the NemoClaw plugin, the selected blueprint contents, and supporting tools. | +| Inference | Receives model requests through the gateway, using NVIDIA endpoints, NIM, or compatible APIs. | +| Integrations | Reach messaging services, MCP servers, GitHub, package indexes, or model hubs through gateway-managed egress. | +| State and artifacts | Store configuration, credentials, logs, workspace files, policies, and transcripts outside the running agent process. | + +For repository layout, file paths, and deeper diagrams, see [Architecture](/reference/architecture). + +## Design Principles + +NemoClaw architecture follows the following principles. + +Thin plugin, versioned blueprint +: The sandbox plugin stays small and stable. Host-side orchestration uses a versioned blueprint and runner that can evolve on its own release cadence. + +Respect CLI boundaries +: The `nemoclaw` CLI is the primary interface for sandbox management. + +Supply chain safety +: Blueprint artifacts are immutable, versioned, and digest-verified before execution. + +OpenShell-backed lifecycle +: NemoClaw orchestrates OpenShell resources under the hood, but `nemoclaw onboard` + is the supported operator entry point for creating or recreating NemoClaw-managed sandboxes. + +Reproducible setup +: Running setup again recreates the sandbox from the same blueprint and policy definitions. + +## CLI, Plugin, and Blueprint + +NemoClaw is split into three integration pieces: + +- The *host CLI* runs onboarding, validates provider choices, stores configuration, and calls OpenShell commands for gateway, provider, sandbox, and policy operations. +- The *plugin* is a TypeScript package that runs with OpenClaw inside the sandbox. + It registers the managed inference provider metadata, the `/nemoclaw` slash command, and runtime context hooks. +- The *blueprint* is a versioned YAML package with the sandbox image, policy, inference profile, and supporting assets. + The runner resolves and verifies the blueprint before applying it through OpenShell. + +This separation keeps the sandbox plugin small while allowing host orchestration and blueprint contents to evolve on their own release cadence. + +## Sandbox Creation + +When you run `nemoclaw onboard`, NemoClaw creates an OpenShell sandbox that runs OpenClaw in an isolated container. +The host CLI and blueprint runner orchestrate this process through the OpenShell CLI: + +1. NemoClaw resolves the blueprint, checks version compatibility, and verifies the digest. +2. The onboarding flow determines which OpenShell resources to create or update, such as the gateway, inference providers, sandbox, and network policy. +3. The runner calls OpenShell CLI commands to create the sandbox and configure each resource. + +After the sandbox starts, the agent runs inside it with all network, filesystem, and inference controls in place. + +## Inference Routing + +Inference requests from the agent never leave the sandbox directly. +OpenShell intercepts every inference call and routes it to the configured provider. +During onboarding, NemoClaw validates the selected provider and model, configures the OpenShell route, and bakes the matching model reference into the sandbox image. +The sandbox then talks to `inference.local`, while the host owns the actual provider credential and upstream endpoint. +If you select the Model Router provider, `inference.local` routes to a host-side router that chooses from the configured NVIDIA model pool for each request. + +## Protection Layers + +The sandbox starts with a default policy that controls network egress, filesystem access, process privileges, and inference routing. + +| Layer | What it protects | When it applies | +|---|---|---| +| Network | Blocks unauthorized outbound connections. | Hot-reloadable at runtime. | +| Filesystem | Restricts system paths to read-only; `/sandbox` and `/tmp` are writable. | Locked at sandbox creation. | +| Process | Blocks privilege escalation and dangerous syscalls. | Locked at sandbox creation. | +| Inference | Reroutes model API calls to controlled backends. | Hot-reloadable at runtime. | + +When the agent tries to reach an unlisted host, OpenShell blocks the request and surfaces it in the TUI for operator approval. Approved endpoints persist for the current session but are not saved to the baseline policy file. + +For details on the baseline rules, refer to [Network Policies](/reference/network-policies). For container-level hardening, refer to [Sandbox Hardening](/deployment/sandbox-hardening). + +## Next Steps + +- Read [Ecosystem](/about/ecosystem) for stack-level relationships and NemoClaw versus OpenShell-only paths. +- Follow the [Quickstart](/get-started/quickstart) to launch your first sandbox. +- Refer to the [Architecture](/reference/architecture) for the full technical structure, including file layouts and the blueprint lifecycle. +- Refer to [Inference Options](/inference/inference-options) for detailed provider configuration. diff --git a/docs/about/overview.mdx b/docs/about/overview.mdx new file mode 100644 index 0000000000..0b598a23a2 --- /dev/null +++ b/docs/about/overview.mdx @@ -0,0 +1,70 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Overview: What It Is" +sidebar-title: "Overview" +description: "NemoClaw is an open-source reference stack that simplifies running OpenClaw always-on assistants more safely." +description-agent: "Explains what NemoClaw covers: onboarding, lifecycle management, and OpenClaw operations within OpenShell containers, plus capabilities and why it exists. Use when users ask what NemoClaw is or what the project provides. For ecosystem placement or OpenShell-only paths, use the Ecosystem page; for internal mechanics, use How It Works." +keywords: ["nemoclaw overview", "openclaw always-on assistants", "nvidia openshell", "nvidia nemotron"] +content: + type: "concept" +--- +NVIDIA NemoClaw is an open-source reference stack that simplifies running [OpenClaw](https://openclaw.ai) always-on assistants more safely. +NemoClaw provides onboarding, lifecycle management, and OpenClaw operations within OpenShell containers. +It incorporates policy-based privacy and security guardrails, giving you control over your agents’ behavior and data handling. +This enables self-evolving claws to run more safely in clouds, on prem, RTX PCs and DGX Spark. + +NemoClaw pairs hosted models on inference providers or local endpoints with a hardened sandbox, routed inference, and declarative egress policy so deployment stays safer and more repeatable. +The sandbox runtime comes from [NVIDIA OpenShell](https://github.com/NVIDIA/OpenShell); NemoClaw adds the blueprint, `nemoclaw` CLI, onboarding, and related tooling as the reference way to run OpenClaw there. + +| Capability | Description | +|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------| +| Sandbox OpenClaw | Creates an OpenShell sandbox pre-configured for OpenClaw, with filesystem and network policies applied from the first boot. | +| Route inference | Configures OpenShell inference routing so agent traffic goes to the provider and model you chose during onboarding (NVIDIA Endpoints, OpenAI, Anthropic, Gemini, compatible endpoints, local Ollama, and others). The agent uses `inference.local` inside the sandbox; credentials stay on the host. | +| Manage the lifecycle | Handles blueprint versioning, digest verification, and sandbox setup. | + +## Key Features + +NemoClaw provides the following product capabilities. + +| Feature | Description | +|---------|-------------| +| Guided onboarding | Validates credentials, selects providers, and creates a working sandbox in one command. | +| Hardened blueprint | A security-first Dockerfile with capability drops, least-privilege network rules, and declarative policy. | +| State management | Safe migration of agent state across machines with credential stripping and integrity verification. | +| Messaging channels | OpenShell-managed processes connect Telegram, Discord, Slack, and similar platforms to the sandboxed agent. NemoClaw configures channels during onboarding; OpenShell supplies the native constructs, credential flow, and runtime supervision. | +| Routed inference | Provider-routed model calls through the OpenShell gateway, transparent to the agent. Supports NVIDIA Endpoints, OpenAI, Anthropic, Google Gemini, compatible endpoints, local Ollama, local vLLM, and the Model Router. | +| Layered protection | Network, filesystem, process, and inference controls that can be hot-reloaded or locked at creation. | + +## Benefits of Using NemoClaw + +Autonomous AI agents can make arbitrary network requests, access the host filesystem, and call any inference endpoint. Without guardrails, this creates security, cost, and compliance risks that grow as agents run unattended. + +NemoClaw provides the following benefits to mitigate these risks. + +| Benefit | Description | +|----------------------------|------------------------------------------------------------------------------------------------------------------------| +| Sandboxed execution | Every agent runs inside an OpenShell sandbox with Landlock, seccomp, and network namespace isolation. No access is granted by default. | +| Routed inference | Model traffic is routed through the OpenShell gateway to your selected provider, transparent to the agent. You can switch providers or models. Refer to [Inference Options](/inference/inference-options). | +| Declarative network policy | Egress rules are defined in YAML. Unknown hosts are blocked and surfaced to the operator for approval. | +| Single CLI | The `nemoclaw` command orchestrates the full stack: gateway, sandbox, inference provider, and network policy. | +| Blueprint lifecycle | Versioned blueprints handle sandbox creation, digest verification, and reproducible setup. | + +## Use Cases + +You can use NemoClaw for various use cases including the following. + +| Use Case | Description | +|---------------------------|----------------------------------------------------------------------------------------------| +| Always-on assistant | Run an OpenClaw assistant with controlled network access and operator-approved egress. | +| Sandboxed testing | Test agent behavior in a locked-down environment before granting broader permissions. | +| Remote GPU deployment | Deploy a sandboxed agent to a remote GPU instance for persistent operation. | + +## Next Steps + +Navigate to the following topics to learn more about NemoClaw and how to install and use it. + +- [Architecture Overview](/about/how-it-works) to understand how NemoClaw works. +- [Ecosystem](/about/ecosystem) to understand how OpenClaw, OpenShell, and NemoClaw relate in the wider stack, and when to use NemoClaw versus OpenShell. +- [Quickstart](/get-started/quickstart) to install NemoClaw and run your first sandboxed agent. +- [Inference Options](/inference/inference-options) to check the inference providers that NemoClaw supports and how inference routing works. diff --git a/docs/about/release-notes.mdx b/docs/about/release-notes.mdx new file mode 100644 index 0000000000..77738d4df8 --- /dev/null +++ b/docs/about/release-notes.mdx @@ -0,0 +1,128 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Release Notes" +sidebar-title: "Release Notes" +description: "Changelog and feature history for NemoClaw releases." +description-agent: "Includes the NemoClaw release notes. Use when users ask about recent changes, the release cadence, or where to track versioned assets on GitHub." +keywords: ["nemoclaw release notes", "nemoclaw changelog"] +content: + type: "reference" +--- +NVIDIA NemoClaw is available in early preview starting March 16, 2026. Use this page to track changes. + +## v0.0.44 + +NemoClaw v0.0.44 improves onboarding reliability, GPU sandbox networking, local inference verification, messaging recovery, and remote dashboard access: + +- `nemoclaw onboard` handles DGX Spark and Jetson hosts more conservatively. Unified-memory GPU detection works for Spark, Jetson defaults to CPU-only sandbox passthrough unless you opt in, and local Ollama validation tolerates slow unified-memory model loads that still fit host memory. +- Linux Docker-driver GPU sandboxes preserve `host.openshell.internal` during recreation and inject a reachable DNS resolver when the host uses a systemd-resolved loopback nameserver, which keeps local inference and external DNS working after GPU patching. +- Onboarding and sandbox builds fail less often on first run. Preflight can guide missing NVIDIA Container Toolkit setup, Docker builds force BuildKit for Dockerfile bind mounts, npm installs retry transient registry resets, and compatible-endpoint onboarding runs a final inference smoke check before reporting success. +- `nemoclaw connect` repairs stale `inference.local` routes before opening the shell, reports local Ollama backend and auth-proxy diagnostics when repair fails, and `--probe-only` keeps dashboard and process recovery from failing just because inference repair needs follow-up. +- `nemoclaw channels add ` applies the matching built-in network policy preset before rebuild, and rebuilds preserve paused channel state so stopped messaging channels stay disabled after destroy and recreate. +- Remote hosts can opt into dashboard forwarding on all interfaces with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0`, and gateway drift checks now stop backup, status, rebuild, recover, and upgrade flows before they trust stale OpenShell state. +- Workspace restore uploads backed-up directories file by file, dashboard forwards retry while stopped ports are still releasing, and the in-sandbox OpenClaw gateway respawns after unexpected exits. + +## v0.0.43 + +NemoClaw v0.0.43 improves GPU onboarding and uninstall cleanup on Linux Docker-driver hosts: + +- The standard installer can repair missing NVIDIA CDI device specs before onboarding by enabling the NVIDIA CDI refresh service, then falling back to direct `nvidia-ctk` spec generation when needed. +- Linux Docker-driver GPU onboarding handles the Docker flags and sandbox policy needed for NVIDIA GPU proof writes to `/proc//task//comm`, which fixes DGX Spark installs that previously failed with a permission error during direct GPU proof. +- `nemoclaw uninstall` removes the Linux gateway state directory under `~/.local/state/nemoclaw`, including gateway PID, SQLite, audit log, and VM-driver state left by Docker-driver gateways. + +## v0.0.42 + +NemoClaw v0.0.42 improves onboarding, status diagnostics, local inference checks, and messaging setup: + +- `nemoclaw onboard` uses the Docker-driver OpenShell gateway path on macOS and no longer requires VM driver helper assets for standard macOS onboarding. +- Dashboard port selection probes occupied ports more thoroughly, including root-owned listeners on macOS, and rolls back a newly-created sandbox if the dashboard forward cannot start after the image build. +- `nemoclaw status` shows `Inference` and `Connected` fields for each listed sandbox, and cloudflared service output now distinguishes stopped, invalid PID file, and stale PID states with a `nemoclaw tunnel start` recovery hint. +- Local Ollama status and doctor checks now probe the authenticated proxy in addition to the backend, so a broken proxy is reported separately from a healthy `127.0.0.1:11434` backend. +- Compatible OpenAI endpoint validation retries reasoning-only smoke responses with a larger output budget before classifying the setup as a model output budget problem instead of a route failure. +- `channels add` and `channels remove` normalize channel names before saving or rebuilding, and `channels add` hints when a matching built-in policy preset exists but is not applied yet. +- GPU recovery and uninstall output now use registry-aware recovery commands and clearer gateway removal wording. +- Onboarding applies selected built-in policy presets in a single policy update when possible, while preserving the final live policy and registry state. +- The installer handles unchanged user-local CLI shims idempotently, avoiding duplicate shim-creation messages during install-plus-verify flows. + +## v0.0.41 + +NemoClaw v0.0.41 improves Docker-driver onboarding and release compatibility: + +- `nemoclaw onboard` can pin fresh OpenShell installs to a published release that fits the blueprint's tested version range, while retaining the installer fallback when release metadata is unavailable. +- Docker-driver gateway startup verifies that sandbox containers can reach `host.openshell.internal` before reporting the gateway healthy, and Linux firewall failures include a targeted `ufw` remediation. +- Local Ollama setup probes sandbox-to-proxy reachability before it commits the inference route, so blocked `11435` traffic stops onboarding with a rerun-safe fix instead of leaving a broken route. +- Linux Docker-driver GPU onboarding can recreate the OpenShell-managed sandbox container with NVIDIA GPU access and leaves diagnostics plus cleanup guidance when GPU readiness fails. +- `nemoclaw uninstall` removes all installer-managed OpenShell helper binaries unless you pass `--keep-openshell`. + +## v0.0.40 + +NemoClaw v0.0.40 improves onboarding reliability, local inference setup, and sandbox recovery: + +- `nemoclaw onboard` uses the Docker-driver OpenShell gateway path on macOS with OpenShell 0.0.37, repairs incomplete Docker-driver installs before startup, and installs the platform-specific gateway asset it needs. +- The Docker-driver gateway startup check waits for the gateway port to accept TCP connections before it reports the gateway as healthy, and startup failures now include child process exit details. +- Local Ollama setup requires the authenticated reverse proxy token on every native Ollama API route, including `GET /api/tags`. +- The Linux Ollama install path preflights `zstd` before running the official installer and explains why each sudo-backed setup step needs elevated privileges. +- The onboarding provider menu offers an already-running local vLLM server directly when `localhost:8000` responds, while managed vLLM install and start options remain behind the experimental opt-in. +- Policy tier defaults are filtered by active agent support, so presets such as Brave Search are not reapplied to agents that do not support that integration. +- `nemoclaw connect` checks dashboard forward reachability with a TCP probe before it reports a forward as stale. +- Sandbox startup captures a known-good OpenClaw config baseline and restores it on restart if `/sandbox/.openclaw/openclaw.json` becomes empty. +- The NemoClaw OpenClaw plugin package declares compatibility metadata for OpenClaw package tooling. + +## v0.0.39 + +NemoClaw v0.0.39 improves several day-two workflows: + +- The installer checks Docker earlier on Linux, can install and start Docker when needed, and stops with `newgrp docker` guidance when the current shell has not picked up the `docker` group yet. +- DGX Spark and DGX Station users can accept an express install prompt that preselects the local inference path and suggested policy defaults. +- NemoClaw now creates GPU-capable OpenShell Docker sandboxes by default when an NVIDIA GPU is available, with explicit `--sandbox-gpu`, `--no-sandbox-gpu`, and `--sandbox-gpu-device` controls. +- `nemohermes` supports Hermes Provider onboarding and runtime model switches through `nemohermes inference set`. +- `nemoclaw hosts-add`, `hosts-list`, and `hosts-remove` manage sandbox host aliases for LAN-only services. +- `nemoclaw update` checks and runs the maintained installer flow, while `nemoclaw upgrade-sandboxes` remains responsible for rebuilding existing sandboxes. +- `nemoclaw destroy` preserves the shared gateway by default unless `--cleanup-gateway` is selected. +- `nemoclaw connect` repairs stale `inference.local` DNS proxy routes before opening the session. +- Windows-host Ollama onboarding relaunches the daemon with the reachable binding after install or restart. +- Local NVIDIA NIM onboarding passes `NGC_API_KEY` or `NVIDIA_API_KEY` into the managed container without putting the secret in process arguments, detects early container exits during health checks, and prints a per-GPU preflight breakdown on mixed-model hosts. +- The sandbox startup path strips additional Linux capabilities before and during privilege step-down. +- OpenClaw workspace template files are seeded when bootstrap is skipped and the workspace is still empty. +- Kimi K2.6 and related NVIDIA-hosted chat-completions paths include model-specific compatibility handling for reasoning output. + +## v0.0.38 + +NemoClaw v0.0.38 improves several day-two workflows: + +- `nemoclaw status` shows the gateway's active policy version in the displayed policy YAML when OpenShell reports one. +- `nemoclaw uninstall` stops matching Local Ollama auth proxy processes before it removes `~/.nemoclaw`, which prevents stale listeners from blocking a later reinstall. +- Local Ollama onboarding validates structured chat-completions tool calls and rejects models that leak tool-call payloads as plain text. +- Blueprint policy additions under `components.policy.additions` are validated, merged into the live policy, applied through OpenShell, and recorded in run metadata. +- Rebuild backups tolerate partial archive output when usable data was produced, then report only the manifest-defined paths that could not be archived. +- NemoHermes uninstall output uses NemoHermes-specific help, progress, and completion text. + +## v0.0.34 + +Starting with NemoClaw v0.0.34, the `curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash` installer pipeline no longer auto-accepts the third-party software notice when stdin is piped and `/dev/tty` is unavailable (for example, deeply detached SSH sessions or some container shells). +In environments without a TTY, accept upfront in the pipe: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 bash +``` + +Or pass the flag through to the installer: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -s -- --yes-i-accept-third-party-software +``` + +Or re-run from a terminal with a controlling TTY: + +```console +$ bash <(curl -fsSL https://www.nvidia.com/nemoclaw.sh) +``` + +The installer error message in v0.0.35+ surfaces all three invocations directly so users can copy-paste a recovery without leaving the terminal. + +## Component Version Policy + +NemoClaw pins the OpenClaw version inside the sandbox at build time via `min_openclaw_version` in `nemoclaw-blueprint/blueprint.yaml`; existing sandboxes do not auto-upgrade. +Run `nemoclaw status` to see the OpenClaw version currently running in a sandbox, and `nemoclaw rebuild` to pick up a newer pin from a NemoClaw upgrade. +See [Checking the OpenClaw version](/reference/commands#checking-the-openclaw-version) for the full policy. diff --git a/docs/deployment/brev-web-ui.mdx b/docs/deployment/brev-web-ui.mdx new file mode 100644 index 0000000000..256482e16c --- /dev/null +++ b/docs/deployment/brev-web-ui.mdx @@ -0,0 +1,162 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Launch NemoClaw with the Brev Web UI" +sidebar-title: "Brev Web UI" +description: "Launch a hosted NemoClaw sandbox from the Brev web interface without installing the CLI or using a local GPU." +description-agent: "Guides users through deploying NemoClaw with the Brev web UI. Use when a user wants to try NemoClaw without installing the CLI, or asks how to get started on Brev." +keywords: ["nemoclaw brev web ui", "nemoclaw getting started", "brev quickstart", "nvidia nemotron agent"] +content: + type: "get_started" +--- +Use the Brev web UI to launch a hosted NemoClaw sandbox from your browser. +This flow provisions a remote VM, configures inference, starts OpenClaw inside an OpenShell sandbox, and opens the OpenClaw dashboard. + + +Use this guide when you want to try NemoClaw without installing the CLI or using a local GPU. +If you want to manage the remote host from a terminal, see [Deploy to a Remote GPU Instance](/deployment/deploy-to-remote-gpu). + + +## What This Flow Creates + +The Brev web flow creates the following resources: + +- A Brev-managed Linux VM. +- Docker and the OpenShell runtime on that VM. +- A NemoClaw sandbox running OpenClaw. +- Inference routing for the provider you select during setup. +- A browser-accessible OpenClaw dashboard. + +## Prerequisites + +- An NVIDIA Brev account at [brev.nvidia.com](https://brev.nvidia.com). +- An NVIDIA API key from [build.nvidia.com](https://build.nvidia.com/settings/api-keys) if you use the default NVIDIA Cloud provider. + +You do not need to install local software for this flow. + +## Get Your NVIDIA API Key + +If you already have an NVIDIA API key skip this section. Otherwise, follow these steps to generate a new key: + +1. Go to [build.nvidia.com](https://build.nvidia.com). +2. Sign in or create an account. +3. Click your profile icon in the top right. +4. Select **API Keys**. +5. Click **Generate API Key**. +6. Copy the key. It starts with `nvapi-`. + +Keep this key ready for the next step. + +## Launch NemoClaw from Brev + +Use the [NemoClaw Brev launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3Azt0aYgVNFEuz7opyx3gscmowS) to launch a NemoClaw sandbox from your browser. + +1. Open the [NemoClaw Brev launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3Azt0aYgVNFEuz7opyx3gscmowS) and sign in if prompted. +2. Review the instance type, cloud provider, and estimated hourly cost on the NemoClaw setup page. +3. Click **Deploy NemoClaw**. + +The right-side deployment panel shows progress while Brev deploys the CPU instance and prepares VM mode. +Keep this page open until the deployment completes. +When the panel shows the **NemoClaw** button, click it to open the agent setup page. + +## Configure Your Agent + +The setup page walks you through three stages: **Configure**, **Setup**, and **Launch**. + +### Configure + +The Configure stage opens the **Connect to AI** screen. +Use the NVIDIA Cloud provider shown on this screen. + +1. Leave **NVIDIA Cloud** selected. +2. Paste your `nvapi-` API key. +3. Click **Create Agent**. + + +The **Show Other Providers** dropdown appears below the **NVIDIA Cloud** card and can be easy to miss. +Click it to expand the provider list. +The expanded list includes **OpenAI**, **Anthropic**, and **Google Gemini**. +For these providers, get the API key from the provider's own console before you create the agent. + + +### Setup + +NemoClaw configures the remote host and sandbox automatically. +This stage usually takes about 5 minutes. + +During setup, NemoClaw installs the runtime, prepares the sandboxed agent environment, and configures inference routing for the provider you selected. + +### Launch + +When setup finishes, Brev shows the following confirmation: + +```text +AGENT CREATED SUCCESSFULLY +Your agent is running in a secure sandbox and ready to use. + +Agent: agent +Model: nemotron-3-super-120b +Provider: NVIDIA Cloud +``` + +Click **Chat With Agent** to open the OpenClaw dashboard. + + +The dashboard might initially show a **Pairing required** warning. +This means the gateway is still completing pairing in the background. +Wait for about a few minutes for pairing to finish automatically. Refresh the dashboard to see if the warning is resolved and the connection is established. +If pairing does not finish, go to the **Overview** page in the OpenClaw UI, find the **Gateway Access** panel, and click **Connect**. + + +## Start a Chat + +Use the dashboard chat box to send your first message: + +```text +Hello! What can you do for me? What skills do you have available? +``` + +The agent reads its workspace files and introduces itself. +The starter workspace includes example skills such as: + +- **Weather** gets current weather and forecasts. +- **Healthcheck** runs security audit and hardening checks. +- **Skill-Creator** creates new custom skills. + +## Personalize Agent Memory + +The agent starts with an empty `USER.md` file. +Ask the agent to add details that help it personalize future responses. + +In the chat, type the following: + +```text +Please update my USER.md file with the following: +Name: [your name] +Timezone: [your timezone, such as "America/New_York"] +Notes: [what you are working on] +``` + +The agent writes this information to its workspace so it can use it across sessions on the same sandbox. + +## Stop Your Instance When Done + +Brev continues billing while the instance runs. +Stop the instance when you finish experimenting. + +1. Go back to [brev.nvidia.com](https://brev.nvidia.com). +2. Click **GPUs** in the nav bar. +3. Find your NemoClaw instance. +4. Click **Stop**. + +Check the Brev UI for the current hourly price before leaving the instance running. + +## Next Steps + +After your agent is running, explore these related tasks: + +- [Set Up Messaging Channels](/manage-sandboxes/messaging-channels) to learn how to connect Telegram, Slack, or Discord. +- [Switch Inference Providers](/inference/switch-inference-providers) to learn how to change the model provider after setup. +- [Monitor Sandbox Activity](/monitoring/monitor-sandbox-activity) to learn how to inspect sandbox health and logs. +- [Deploy to a Remote GPU Instance](/deployment/deploy-to-remote-gpu) to learn how to deploy NemoClaw to a remote GPU instance using the CLI. +- [Troubleshooting](/reference/troubleshooting) to learn how to fix common setup and runtime issues. diff --git a/docs/deployment/deploy-to-remote-gpu.mdx b/docs/deployment/deploy-to-remote-gpu.mdx new file mode 100644 index 0000000000..a6b2386b62 --- /dev/null +++ b/docs/deployment/deploy-to-remote-gpu.mdx @@ -0,0 +1,168 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Deploy NemoClaw to a Remote GPU Instance with Brev" +sidebar-title: "Deploy to Remote GPU" +description: "Run NemoClaw on a remote GPU instance and understand the legacy Brev compatibility flow." +description-agent: "Explains how to run NemoClaw on a remote GPU instance, including the deprecated Brev compatibility path and the preferred installer plus onboard flow. Use when deploying NemoClaw to a remote VM, onboarding a Brev instance, or migrating away from the legacy `nemoclaw deploy` wrapper." +keywords: ["deploy nemoclaw remote gpu", "nemoclaw brev cloud deployment"] +content: + type: "how_to" +skill: + priority: 10 +--- +Run NemoClaw on a remote GPU instance through [Brev](https://brev.nvidia.com). +The preferred path is to provision the VM, run the standard NemoClaw installer on that host, and then run `nemoclaw onboard`. + +## Quick Start + +If your Brev instance is already up and has already been onboarded with a sandbox, start with the standard sandbox chat flow: + +```console +$ nemoclaw my-assistant connect +$ openclaw tui +``` + +This gets you into the sandbox shell first and opens the OpenClaw chat UI right away. +If the VM is fresh, run the standard installer on that host and then run `nemoclaw onboard` before trying `nemoclaw my-assistant connect`. + +If you are connecting from your local machine and still need to provision the remote VM, you can still use `nemoclaw deploy ` as the legacy compatibility path described below. + +## Prerequisites + +- The [Brev CLI](https://brev.nvidia.com) installed and authenticated. +- A provider credential for the inference backend you want to use during onboarding. +- `HF_TOKEN` or `HUGGING_FACE_HUB_TOKEN` exported when your remote vLLM or Hugging Face workflow needs access to gated models. +- NemoClaw installed locally if you plan to use the deprecated `nemoclaw deploy` wrapper. Otherwise, install NemoClaw directly on the remote host after provisioning it. + +## Deploy the Instance + + +The `nemoclaw deploy` command is deprecated. +Prefer provisioning the remote host separately, then running the standard NemoClaw installer and `nemoclaw onboard` on that host. + + +Create a Brev instance and run the legacy compatibility flow: + +```console +$ nemoclaw deploy +``` + +Replace `` with a name for your remote instance, for example `my-gpu-box`. +The sandbox created on the remote VM uses `NEMOCLAW_SANDBOX_NAME`, or `my-assistant` when the variable is unset. +Sandbox names must be lowercase, start with a letter, contain only letters, numbers, and internal hyphens, and end with a letter or number. +The deploy wrapper validates the sandbox name before it provisions the Brev instance, opens SSH, or starts the remote installer. + +The legacy compatibility flow performs the following steps on the VM: + +1. Installs Docker and the NVIDIA Container Toolkit if a GPU is present. +2. Installs the OpenShell CLI. +3. Runs `nemoclaw onboard` (the setup wizard) to create the gateway, register providers, and launch the sandbox. +4. Starts optional host auxiliary services (for example the cloudflared tunnel) when `cloudflared` is available. Channel messaging is configured during onboarding and runs through OpenShell-managed processes, not through `nemoclaw tunnel start`. + +By default, the compatibility wrapper asks Brev to provision on `gcp`. Override this with `NEMOCLAW_BREV_PROVIDER` if you need a different Brev cloud provider. +If you export `HF_TOKEN` or `HUGGING_FACE_HUB_TOKEN`, the wrapper forwards those values to the VM so remote setup can pull gated Hugging Face model repositories. + +## Connect to the Remote Sandbox + +After deployment finishes, the deploy command opens an interactive shell inside the remote sandbox. +To reconnect after closing the session, run the command again: + +```console +$ nemoclaw deploy +``` + +## Monitor the Remote Sandbox + +SSH to the instance and run the OpenShell TUI to monitor activity and approve network requests: + +```console +$ ssh 'cd ~/nemoclaw && set -a && . .env && set +a && openshell term' +``` + +## Verify Inference + +Run a test agent prompt inside the remote sandbox: + +```console +$ openclaw agent --agent main --local -m "Hello from the remote sandbox" --session-id test +``` + +## Remote Dashboard Access + +The NemoClaw dashboard validates the browser origin against an allowlist baked +into the sandbox image at build time. By default the allowlist only contains +`http://127.0.0.1:18789`. When accessing the dashboard from a remote browser +(for example through a Brev public URL or an SSH port-forward), set +`CHAT_UI_URL` to the origin the browser will use **before** running setup: + +```console +$ export CHAT_UI_URL="https://openclaw0-.brevlab.com" +$ nemoclaw deploy +``` + +For SSH port-forwarding, the origin is typically `http://127.0.0.1:18789` (the +default), so no extra configuration is needed. + + +On Brev, set `CHAT_UI_URL` in the launchable environment configuration so it is +available when the installer builds the sandbox image. If `CHAT_UI_URL` is not +set on a headless host, the compatibility wrapper prints a warning. + +`NEMOCLAW_DISABLE_DEVICE_AUTH` is also evaluated at image build time. +When `CHAT_UI_URL` points at a non-loopback origin, NemoClaw disables OpenClaw device pairing in the generated sandbox configuration because browser-only remote users cannot complete terminal-based pairing. +Any device that can reach the configured dashboard origin can connect without pairing, so avoid exposing that origin on internet-reachable or shared-network deployments. + + +## First-Run Readiness Budget + +On a remote GPU host, the first `nemoclaw onboard` typically does the slowest work of the lifecycle: the sandbox image is built locally and uploaded into the OpenShell gateway, which can stream hundreds of MiB over the VM's link before the readiness wait even starts. +The post-create readiness wait defaults to 180 seconds (`NEMOCLAW_SANDBOX_READY_TIMEOUT`), which is sized for warm-cache, workstation-class onboarding and can be exceeded on: + +- DGX Station first runs with large quantised models (70B+ parameter footprints, NVFP4 weights). +- Cloud VMs where the local image-build cache is cold and the upload runs over the public network. +- Hosts onboarding the Brave Web Search preset on the first run (the egress policy stack adds boot work). + +Raise the budget before re-running onboard: + +```console +$ export NEMOCLAW_SANDBOX_READY_TIMEOUT=600 +$ nemoclaw onboard +``` + +If onboard ends with `Sandbox '' was created but did not become ready within 180s`, onboard deletes the partially-created sandbox first, so the next attempt with the raised budget starts from a clean state. +For the inference-probe budget that runs earlier in onboarding, see [`NEMOCLAW_LOCAL_INFERENCE_TIMEOUT`](/inference/use-local-inference#timeout-configuration). + +## Proxy Configuration + +NemoClaw routes sandbox traffic through a gateway proxy that defaults to `10.200.0.1:3128`. +If your network requires a different proxy, set `NEMOCLAW_PROXY_HOST` and `NEMOCLAW_PROXY_PORT` before onboarding: + +```console +$ export NEMOCLAW_PROXY_HOST=proxy.example.com +$ export NEMOCLAW_PROXY_PORT=8080 +$ nemoclaw onboard +``` + +These values are baked into the sandbox image at build time. +They are also forwarded into the runtime container during sandbox creation, so `/tmp/nemoclaw-proxy-env.sh` uses the same host and port that the image build used. +Only alphanumeric characters, dots, hyphens, and colons are accepted for the host. +The port must be numeric (0-65535). +Changing the proxy after onboarding requires re-running `nemoclaw onboard`. + +## GPU Configuration + +The deploy script uses the `NEMOCLAW_GPU` environment variable to select the GPU type. +The default value is `a2-highgpu-1g:nvidia-tesla-a100:1`. +Set this variable before running `nemoclaw deploy` to use a different GPU configuration: + +```console +$ export NEMOCLAW_GPU="a2-highgpu-1g:nvidia-tesla-a100:2" +$ nemoclaw deploy +``` + +## Related Topics + +- [Set Up Messaging Channels](/manage-sandboxes/messaging-channels) to connect Telegram, Discord, or Slack through OpenShell-managed channel messaging. +- [Monitor Sandbox Activity](/monitoring/monitor-sandbox-activity) for sandbox monitoring tools. +- [Commands](/reference/commands) for the full `deploy` command reference. diff --git a/docs/deployment/install-openclaw-plugins.mdx b/docs/deployment/install-openclaw-plugins.mdx new file mode 100644 index 0000000000..d0223ce7df --- /dev/null +++ b/docs/deployment/install-openclaw-plugins.mdx @@ -0,0 +1,102 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Install OpenClaw Plugins" +sidebar-title: "OpenClaw Plugins" +description: "How to install OpenClaw plugins in a NemoClaw-managed sandbox today." +description-agent: "Explains the difference between OpenClaw plugins and agent skills, and shows the current Dockerfile-based workflow for baking a plugin into a NemoClaw sandbox. Use when users ask how to install, build, or configure OpenClaw plugins under NemoClaw." +keywords: ["nemoclaw plugins", "openclaw plugins", "install openclaw plugin", "nemoclaw onboard from dockerfile"] +content: + type: "how_to" +skill: + priority: 20 +--- +OpenClaw plugins extend the OpenClaw runtime with hooks, services, tools, or +provider integrations. They are different from NemoClaw-managed agent skills: + +- **Plugins** are code packages loaded by OpenClaw. +- **Skills** are `SKILL.md` directories that teach an agent how to perform a task. +- **Policy presets** are network-egress rules that control what sandboxed code can reach. + +Today, the supported NemoClaw path for OpenClaw plugins is to bake the plugin +into a custom sandbox image and onboard from that Dockerfile. + +## Prepare a Build Directory + +Put the Dockerfile and everything it needs to `COPY` in one directory. +`nemoclaw onboard --from ` uses the Dockerfile's parent directory as +the Docker build context. + +```text +my-plugin-sandbox/ +├── Dockerfile +└── my-plugin/ + ├── package.json + └── src/ +``` + +## Example Dockerfile + +Use the custom image to copy the plugin into the OpenClaw extensions directory +and let OpenClaw refresh its config before NemoClaw starts the sandbox. + +```dockerfile +ARG SANDBOX_BASE=ghcr.io/nvidia/nemoclaw/sandbox-base:latest +FROM ${SANDBOX_BASE} + +COPY my-plugin/ /opt/my-plugin/ +WORKDIR /opt/my-plugin +RUN npm ci --no-audit --no-fund && npm run build + +RUN mkdir -p /sandbox/.openclaw/extensions \ + && cp -a /opt/my-plugin /sandbox/.openclaw/extensions/my-plugin \ + && openclaw doctor --fix + +WORKDIR /opt/nemoclaw +``` + +If the plugin needs configuration in `openclaw.json`, apply it after +`openclaw doctor --fix` so the base config exists first. + +## Create the Sandbox + +Point `nemoclaw onboard --from` at the Dockerfile in the build directory. + +```console +$ nemoclaw onboard --from ./my-plugin-sandbox/Dockerfile +``` + +If you need a second sandbox alongside an existing one, use a dedicated build +directory and rerun onboarding with the sandbox name and ports you intend to +use. + +## Network Access + +Plugins still run inside the sandbox policy boundary. If a plugin needs network +egress, add or update a policy preset for the required hostnames and binaries +before rebuilding the sandbox. + +For example, see [Network Policies](/reference/network-policies) for +policy concepts and [Customize Network Policy](/network-policy/customize-network-policy) +for custom preset workflows. + +## Common Mistakes + +These are the most common places where plugin installation gets mixed up with +other NemoClaw extension paths. + +- Do not use `nemoclaw skill install` for OpenClaw plugins. That + command only installs `SKILL.md` agent skills. +- Do not put a Dockerfile in a broad directory such as `/tmp` unless you intend + to send that whole directory as the Docker build context. +- Keep plugin dependencies in the build stage or plugin directory; avoid copying + unrelated host files into the sandbox image. + +## Next Steps + +- Review [Sandbox Hardening](/deployment/sandbox-hardening) before adding plugin code to a + shared or long-lived sandbox. +- Review [Network Policies](/reference/network-policies) to plan plugin + egress rules. +- Follow [Customize Network Policy](/network-policy/customize-network-policy) + if the plugin needs a custom preset. diff --git a/docs/deployment/sandbox-hardening.mdx b/docs/deployment/sandbox-hardening.mdx new file mode 100644 index 0000000000..7528910252 --- /dev/null +++ b/docs/deployment/sandbox-hardening.mdx @@ -0,0 +1,134 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Sandbox Image Hardening" +sidebar-title: "Sandbox Hardening" +description: "Security hardening measures applied to the NemoClaw sandbox container image." +description-agent: "Includes the sandbox container image hardening reference, covering Docker capabilities and process limits. Use when reviewing sandbox image security controls, auditing capability drops, or looking up the runtime resource limits." +keywords: ["nemoclaw sandbox hardening", "container security", "docker capabilities", "process limits"] +content: + type: "reference" +--- +The NemoClaw sandbox image applies several security measures to reduce attack +surface and limit the blast radius of untrusted workloads. + +## Removed Unnecessary Tools + +Build toolchains (`gcc`, `g++`, `make`) and network probes (`netcat`) are +explicitly purged from the runtime image. These tools are not needed at runtime +and would unnecessarily widen the attack surface. + +The runtime image keeps a small set of operational utilities for normal sandbox +workflows, including `vi`, `jq`, and `dos2unix`. Use these for lightweight +inspection and file cleanup inside the sandbox, but make durable image or policy +changes in the NemoClaw source tree and rebuild the sandbox. + +If you need a compiler during build, use the existing multi-stage build +(the `builder` stage has full Node.js tooling) and copy only artifacts into the +runtime stage. + +## Process Limits + +The container ENTRYPOINT sets `ulimit -u 512` to cap the number of processes +a sandbox user can spawn. This mitigates fork-bomb attacks. The startup script +(`nemoclaw-start.sh`) applies the same limit. + +Adjust the value via the `--ulimit nproc=512:512` flag if launching with +`docker run` directly. + +## Dropping Linux Capabilities + +The NemoClaw entrypoint drops dangerous capabilities from the process bounding +set before it starts agent services. +It removes `CAP_SYS_ADMIN`, `CAP_SYS_PTRACE`, `CAP_NET_RAW`, +`CAP_DAC_OVERRIDE`, `CAP_SYS_CHROOT`, `CAP_FSETID`, `CAP_SETFCAP`, +`CAP_MKNOD`, `CAP_AUDIT_WRITE`, and `CAP_NET_BIND_SERVICE`. +When `setpriv` is available, the entrypoint also removes the remaining +privilege-separation capabilities during the switch from root to the +`sandbox` and `gateway` users. + +For defense-in-depth, also drop all Linux capabilities at the container runtime +when you launch the image directly: + +```console +$ docker run --rm \ + --cap-drop=ALL \ + --ulimit nproc=512:512 \ + nemoclaw-sandbox +``` + +### Docker Compose Example + +```yaml +services: + nemoclaw-sandbox: + image: nemoclaw-sandbox:latest + cap_drop: + - ALL + cap_add: + - NET_BIND_SERVICE + ulimits: + nproc: + soft: 512 + hard: 512 + security_opt: + - no-new-privileges:true + read_only: true + tmpfs: + - /tmp:size=64m +``` + +> **Note:** The `Dockerfile` itself cannot enforce `--cap-drop`. That is a +> runtime concern controlled by the container orchestrator. Always configure +> capability dropping in your `docker run` flags, Compose file, or Kubernetes +> `securityContext`. + +## Filesystem Layout + +The sandbox Landlock policy declares which paths are writable. +The agent's home directory (`/sandbox`) is writable by default: + +| Path | Access | Purpose | +|------|--------|---------| +| `/sandbox` | read-write | Home directory — agents can create files and use standard home paths | +| `/sandbox/.openclaw` | read-write | Agent config, state, workspace, plugins | +| `/sandbox/.nemoclaw` | read-write | Plugin state and config; blueprints within are DAC-protected (root-owned) | +| `/tmp` | read-write | Temporary files and logs | + +This writable default is intentional. +Seeing the sandbox user create files under `/sandbox` or `/sandbox/.openclaw` in a fresh sandbox does not mean Landlock failed. +Landlock still enforces the fixed read-only system paths below. + +System paths remain read-only to prevent agents from: + +- Replacing system binaries with trojanized versions +- Modifying DNS resolution or TLS trust stores +- Tampering with libraries or shell configuration outside `/sandbox` + +The image build pre-creates shell init files `.bashrc` and `.profile`. +These files source runtime proxy configuration from `/tmp/nemoclaw-proxy-env.sh`. + +### Landlock Kernel Requirements + +Landlock LSM requires Linux kernel 5.13 or later with `CONFIG_SECURITY_LANDLOCK=y`. +The NemoClaw sandbox policy uses `compatibility: best_effort`, which means Landlock enforcement is silently skipped on kernels that do not support it. + +On such kernels, protection falls back to DAC (file ownership and permissions) only. +Files outside the writable paths would be inaccessible to the agent regardless of DAC permissions. + +Operators should verify Landlock availability: + +```console +$ ls /sys/kernel/security/landlock +``` + +For production deployments, kernel 5.13+ with Landlock enabled is strongly recommended. +The `test/e2e/e2e-cloud-experimental/checks/04-landlock-readonly.sh` script validates enforcement at runtime. + +## References + +- [#804](https://github.com/NVIDIA/NemoClaw/issues/804): Filesystem layout and Landlock policy +- [#807](https://github.com/NVIDIA/NemoClaw/issues/807): gcc in sandbox image +- [#808](https://github.com/NVIDIA/NemoClaw/issues/808): netcat in sandbox image +- [#809](https://github.com/NVIDIA/NemoClaw/issues/809): No process limit +- [#797](https://github.com/NVIDIA/NemoClaw/issues/797): Drop Linux capabilities diff --git a/docs/get-started/prerequisites.mdx b/docs/get-started/prerequisites.mdx new file mode 100644 index 0000000000..e08b2636fb --- /dev/null +++ b/docs/get-started/prerequisites.mdx @@ -0,0 +1,69 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Prerequisites" +sidebar-title: "Prerequisites" +description: "Hardware, software, and supported platforms for running NemoClaw." +description-agent: "Lists the hardware, software, and container runtime requirements for running NemoClaw. Use when verifying prerequisites before installation." +keywords: ["nemoclaw prerequisites", "nemoclaw supported platforms", "nemoclaw hardware software"] +content: + type: "reference" +--- +Before getting started, check the prerequisites to ensure you have the necessary software and hardware to run NemoClaw. + +## Hardware + +| Resource | Minimum | Recommended | +|----------|----------------|------------------| +| CPU | 4 vCPU | 4+ vCPU | +| RAM | 8 GB | 16 GB | +| Disk | 20 GB free | 40 GB free | + +The sandbox image is approximately 2.4 GB compressed. During image push, the Docker daemon, k3s, and the OpenShell gateway run alongside the export pipeline. The pipeline buffers decompressed layers in memory. On machines with less than 8 GB of RAM, this combined usage can trigger the OOM killer. If you cannot add memory, configuring at least 8 GB of swap can work around the issue at the cost of slower performance. + +## Software + +| Dependency | Version | +|------------|----------------------------------| +| Node.js | 22.16 or later | +| npm | 10 or later | +| Docker | Docker Engine, Docker Desktop, or Colima on a tested platform | +| Platform | See [Platforms](#platforms) below | + +On Linux, the installer can install Docker, start the Docker service, and add your user to the `docker` group. +If the group change is not active in the current shell, the installer exits with `newgrp docker` guidance before it starts onboarding. +If you choose the native Linux Ollama install path, the onboard wizard also requires `zstd` for Ollama archive extraction. + +On Debian and Ubuntu, NemoClaw installs `zstd` with `apt-get` if it is missing; on other Linux distributions, install `zstd` before onboarding. + +On macOS, NemoClaw uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. +You do not need to install or sign a separate OpenShell VM driver helper for standard macOS onboarding. + + +For NemoClaw-managed environments, use `nemoclaw onboard` when you need to create or recreate the OpenShell gateway or sandbox. +Avoid `openshell self-update`, `npm update -g openshell`, `openshell gateway start --recreate`, or `openshell sandbox create` directly unless you intend to manage OpenShell separately and then rerun `nemoclaw onboard`. + + + +On Linux hosts running Docker 26 or later with the [containerd image store](https://docs.docker.com/engine/storage/containerd/) enabled (the install-time default for fresh `docker-ce` installations on Ubuntu 24.04 and similar distros), `nemoclaw onboard` transparently builds a `fuse-overlayfs`-enabled cluster image to bypass a kernel-level nested-overlay limitation in k3s. +No manual setup is required. +See the [troubleshooting guide](/reference/troubleshooting) for the override knobs and a manual `daemon.json` alternative. + + +## Platforms + +The following table lists tested platform and runtime combinations. +Availability is not limited to these entries, but untested configurations can have issues. +The table is generated from [`ci/platform-matrix.json`](https://github.com/NVIDIA/NemoClaw/blob/main/ci/platform-matrix.json), the single source of truth kept in sync by CI and QA. + +| OS | Container runtime | Status | Notes | +|----|-------------------|--------|-------| +| Linux | Docker | Tested | Primary tested path. | +| macOS (Apple Silicon) | Colima, Docker Desktop | Tested with limitations | Install Xcode Command Line Tools (`xcode-select --install`) and start the runtime before running the installer. | +| DGX Spark | Docker | Tested | Use the standard installer and `nemoclaw onboard`. For an end-to-end walkthrough with local Ollama inference, see the [NVIDIA Spark playbook](https://build.nvidia.com/spark/nemoclaw). | +| Windows WSL2 | Docker Desktop (WSL backend) | Tested with limitations | Requires WSL2 with Docker Desktop backend. | + +## Next Steps + +- [Prepare Windows for NemoClaw](/get-started/windows-preparation) if you are using Windows. +- [Quickstart](/get-started/quickstart) to install NemoClaw and launch your first sandbox. diff --git a/docs/get-started/quickstart-hermes.mdx b/docs/get-started/quickstart-hermes.mdx new file mode 100644 index 0000000000..f9fb0beba0 --- /dev/null +++ b/docs/get-started/quickstart-hermes.mdx @@ -0,0 +1,168 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Quickstart with Hermes" +sidebar-title: "NemoClaw Quickstart with Hermes" +description: "Install NemoClaw, select the Hermes agent, and launch a sandboxed Hermes API endpoint." +description-agent: "Installs NemoClaw, selects the Hermes agent, and launches a sandboxed Hermes API endpoint. Use when users ask for Hermes setup, NemoHermes onboarding, or running Hermes inside OpenShell." +keywords: ["nemohermes quickstart", "hermes agent nemoclaw", "run hermes openshell sandbox"] +content: + type: "get_started" +skill: + priority: 20 +--- +Use NemoHermes when you want NemoClaw to create an OpenShell sandbox that runs Hermes instead of the default OpenClaw agent. +The `nemohermes` command is an alias for `nemoclaw` with the Hermes agent pre-selected. + + +The Hermes agent option is experimental. +Interfaces, defaults, and supported features may change without notice, and it is not recommended for production use. + + +Review the [Prerequisites](/get-started/prerequisites) before starting. +The first Hermes build can take several minutes because NemoClaw builds the Hermes sandbox base image if it is not already cached. + +## Install and Onboard + +Start the installer with `NEMOCLAW_AGENT=hermes` set in your shell. +The installer installs the CLI, selects the `nemohermes` alias, and runs the guided onboarding flow. + +```console +$ export NEMOCLAW_AGENT=hermes +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +If NemoClaw is already installed, start Hermes onboarding directly. + +```console +$ nemohermes onboard +``` + +## Respond to the Wizard + +The onboard wizard asks for a sandbox name, inference provider, model, credentials, and network policy preset. +At any prompt, press Enter to accept the default shown in `[brackets]`, type `back` to return to the previous prompt, or type `exit` to quit. + +The default Hermes sandbox name is `hermes`. +Use a distinct sandbox name, such as `my-hermes`, so you can run Hermes and OpenClaw sandboxes side by side. +NemoClaw prevents same-name reuse when an existing sandbox uses a different agent. + +```text +Sandbox name [hermes]: my-hermes +``` + +Choose the inference provider that matches where you want Hermes model traffic to go. +The provider options and credential environment variables are the same as the standard NemoClaw quickstart. +For provider-specific prompts, refer to the [Respond to the Onboard Wizard](/get-started/quickstart#respond-to-the-onboard-wizard) section and the [Inference Options](/inference/inference-options) page. +The Hermes wizard does not ask for Brave Web Search because Hermes does not use NemoClaw's OpenClaw web-search configuration. + +After provider and policy selection, review the summary and confirm the build. +NemoClaw writes Hermes configuration into `/sandbox/.hermes`, routes model traffic through `inference.local`, and starts the Hermes gateway inside the sandbox. +The Hermes image includes runtime dependencies for the supported NemoClaw messaging integrations, API service, and health endpoint. +The base image does not include unsupported Hermes integrations. + + +Hermes uses an agent-specific baseline policy that allows the Hermes binary and Python runtime to reach the required Nous Research service endpoints, PyPI, NVIDIA inference endpoints, and selected messaging APIs. + + +## Use Non-Interactive Setup + +For CI or scripted installs, set the required environment variables before running the installer. +The example below uses NVIDIA Endpoints and creates a sandbox named `my-hermes`. + +```console +$ export NEMOCLAW_AGENT=hermes +$ export NEMOCLAW_NON_INTERACTIVE=1 +$ export NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 +$ export NEMOCLAW_SANDBOX_NAME=my-hermes +$ export NVIDIA_API_KEY= +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +Use the provider variables from [Inference Options](/inference/inference-options) when you choose a different provider. + +## Connect to Hermes + +When onboarding completes, NemoClaw prints the sandbox name, model, lifecycle commands, and Hermes API endpoint. +Hermes exposes an OpenAI-compatible API on port `8642`, not a browser dashboard. + +```text +────────────────────────────────────────────────── +Sandbox my-hermes (Landlock + seccomp + netns) +Model nvidia/nemotron-3-super-120b-a12b (NVIDIA Endpoints) +────────────────────────────────────────────────── +Run: nemohermes my-hermes connect +Status: nemohermes my-hermes status +Logs: nemohermes my-hermes logs --follow + +Hermes Agent OpenAI-compatible API +Port 8642 must be forwarded before connecting. +http://127.0.0.1:8642/v1 +────────────────────────────────────────────────── +``` + +To chat with the agent from a terminal, follow these steps: + +1. Connect to the sandbox and start the Hermes CLI. + + ```console + $ nemohermes my-hermes connect + ``` + +2. Inside the sandbox, run the Hermes CLI. + + ```console + $ hermes + ``` + +## Check the API Endpoint + +The onboard flow starts the port forward automatically. +Check the health endpoint from the host to confirm that the Hermes API is reachable. + +```console +$ curl -sf http://127.0.0.1:8642/health +``` + +If the command cannot connect after a reboot or terminal restart, start the forward again. + +```console +$ openshell forward start --background 8642 my-hermes +``` + +Configure an OpenAI-compatible client with the base URL `http://127.0.0.1:8642/v1`. +Hermes uses API header authentication for client requests. +Do not append an OpenClaw `#token=` URL fragment to the Hermes endpoint. + +## Manage the Sandbox + +Use the same lifecycle commands as a standard NemoClaw sandbox. +The `nemohermes` alias keeps help text and recovery messages aligned with Hermes, while targeting the same registered sandbox. +`nemoclaw list` shows the agent type for each sandbox so you can distinguish Hermes and OpenClaw entries. + +```console +$ nemohermes my-hermes status +$ nemohermes my-hermes logs --follow +$ nemohermes my-hermes snapshot create --name before-change +$ nemohermes my-hermes rebuild +``` + +To change the active model or provider without rebuilding the sandbox, use `nemohermes inference set`. +It updates the OpenShell inference route and patches `/sandbox/.hermes/config.yaml` without restarting Hermes. + +```console +$ nemohermes inference set --model --provider +``` + +To remove the sandbox when you are done, destroy it explicitly. + +```console +$ nemohermes my-hermes destroy +``` + +## Next Steps + +- [Inference Options](/inference/inference-options) to choose a provider and model. +- [Commands](/reference/commands) to see the full `nemohermes` alias behavior. +- [Backup and Restore](/manage-sandboxes/backup-restore) to preserve sandbox state before destructive operations. +- [Monitor Sandbox Activity](/monitoring/monitor-sandbox-activity) to inspect OpenShell events and sandbox logs. diff --git a/docs/get-started/quickstart.mdx b/docs/get-started/quickstart.mdx new file mode 100644 index 0000000000..3b015c9b9e --- /dev/null +++ b/docs/get-started/quickstart.mdx @@ -0,0 +1,367 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Quickstart with OpenClaw" +sidebar-title: "Quickstart with OpenClaw" +description: "Install NemoClaw, launch a sandbox, and run your first agent prompt." +description-agent: "Installs NemoClaw, launches a sandbox, and runs the first agent prompt. Use when onboarding, installing, or launching a NemoClaw sandbox for the first time." +keywords: ["nemoclaw quickstart", "install nemoclaw openclaw sandbox"] +content: + type: "get_started" +skill: + priority: 10 +--- +Follow these steps to get started with NemoClaw and your first sandboxed OpenClaw agent. + + +Make sure you have completed reviewing the [Prerequisites](/get-started/prerequisites) before following this guide. + + +## Install NemoClaw and Onboard OpenClaw Agent + +Download and run the installer script. +The script installs Node.js if it is not already present, then runs the guided onboard wizard to create a sandbox, configure inference, and apply security policies. + + +NemoClaw creates a fresh OpenClaw instance inside the sandbox during the onboarding process. + + +```bash +curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +The piped installer prompts through your terminal. In headless scripts or CI, +pass explicit acceptance to the `bash` side of the pipe: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 bash +``` + +If you use nvm or fnm to manage Node.js, the installer might not update your current shell's PATH. +If `nemoclaw` is not found after install, run `source ~/.bashrc` (or `source ~/.zshrc` for zsh) or open a new terminal. + +On Linux, the installer checks Docker before it installs NemoClaw. +If Docker is missing, the installer downloads the official Docker convenience script, asks for `sudo`, installs Docker, and starts the Docker service when systemd is available. +If Docker is installed but your current shell cannot use the Docker socket yet, the installer adds your user to the `docker` group when needed and exits with a recovery command. + +On macOS, the installer uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. + +```console +$ newgrp docker +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +On DGX Spark and DGX Station, an interactive installer can offer express install after you accept the third-party software notice. +Express install switches onboarding to non-interactive mode, allows `sudo` password prompts for required host changes, applies the suggested security policy, and selects the managed local inference path for that platform. +Set `NEMOCLAW_NO_EXPRESS=1` to skip the express prompt, or set `NEMOCLAW_PROVIDER` before launching the installer when you want to choose a provider yourself. + +The installer auto-launches `nemoclaw onboard` when it can locate the freshly-installed binary. +If it cannot locate the binary, or if blocking host preflight checks fail, it does not launch the wizard automatically. +In that case, the installer prints the relevant diagnostics and a `To finish setup, run:` block with the explicit `nemoclaw onboard` command. + + +The onboard flow builds the sandbox image with `NEMOCLAW_DISABLE_DEVICE_AUTH=1` so the dashboard is immediately usable during setup. +This is a build-time setting baked into the sandbox image, not a runtime knob. +If you export `NEMOCLAW_DISABLE_DEVICE_AUTH` after onboarding finishes, it has no effect on an existing sandbox. + + +### Respond to the Onboard Wizard + +After the installer launches `nemoclaw onboard`, the wizard runs preflight checks, starts or reuses the OpenShell gateway, and asks for an inference provider, sandbox name, optional web search, optional messaging channels, and network policy presets. +At any prompt, press Enter to accept the default shown in `[brackets]`, type `back` to return to the previous prompt, or type `exit` to quit. +If existing sandbox sessions are running, the installer warns before onboarding because the setup can rebuild or upgrade sandboxes after the new sandbox launches. + +The inference provider prompt presents a numbered list. + +```text + 1) NVIDIA Endpoints + 2) OpenAI + 3) Other OpenAI-compatible endpoint + 4) Anthropic + 5) Other Anthropic-compatible endpoint + 6) Google Gemini + 7) Local Ollama (localhost:11434) + 8) Model Router (experimental) + Choose [1]: +``` + +Pick the option that matches where you want inference traffic to go, then expand the matching helper below for the follow-up prompts and the API key environment variable to set. +For the full list of providers and validation behavior, refer to [Inference Options](/inference/inference-options). +Local Ollama appears when NemoClaw detects a usable local Ollama path or can offer an install or start action for your platform. +The Model Router option appears when the blueprint router profile is enabled. + + +Export the API key before launching the installer so the wizard does not have to ask for it. +For example, run `export NVIDIA_API_KEY=` before `curl ... | bash`. +If you entered a key incorrectly, refer to [Reset a Stored Credential](/manage-sandboxes/lifecycle#reset-a-stored-credential) to clear and re-enter it. + + + + +Routes inference to models hosted on [build.nvidia.com](https://build.nvidia.com). + +Use `NVIDIA_API_KEY` for the API key. Get one from the [NVIDIA build API keys page](https://build.nvidia.com/settings/api-keys). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, press Enter (or type `1`) to select **NVIDIA Endpoints**. +2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [1]:` prompt, pick a curated model from the list (for example, `Nemotron 3 Super 120B`, `GLM-5`, `MiniMax M2.7`, `GPT-OSS 120B`, or `DeepSeek V4 Pro`), or pick `Other...` to enter any model ID from the [NVIDIA Endpoints catalog](https://build.nvidia.com). + +NemoClaw validates the model against the catalog API before creating the sandbox. + + +Use this option for Nemotron and other models hosted on `build.nvidia.com`. If you run NVIDIA Nemotron from a self-hosted NIM, an enterprise gateway, or any other endpoint, choose **Option 3** instead, since all Nemotron models expose OpenAI-compatible APIs. + + + + + +Routes inference to the OpenAI API at `https://api.openai.com/v1`. + +Use `OPENAI_API_KEY` for the API key. Get one from the [OpenAI API keys page](https://platform.openai.com/api-keys). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `2` to select **OpenAI**. +2. At the `OPENAI_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [1]:` prompt, pick a curated model (for example, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, or `gpt-5.4-pro-2026-03-05`), or pick **Other...** to enter any OpenAI model ID. + + + + +Routes inference to any server that implements `/v1/chat/completions`, including OpenRouter, LocalAI, llama.cpp, vLLM behind a proxy, and any compatible gateway. + +Use `COMPATIBLE_API_KEY` for the API key. Set it to whatever credential your endpoint expects. If your endpoint does not require auth, use any non-empty placeholder. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `3` to select **Other OpenAI-compatible endpoint**. +2. At the `OpenAI-compatible base URL` prompt, enter the provider's base URL. Find the exact value in your provider's API documentation. NemoClaw appends `/v1` automatically, so leave that suffix off. +3. At the `COMPATIBLE_API_KEY:` prompt, paste your key if it is not already exported. +4. At the `Other OpenAI-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your provider's model catalog. + +For example, when you use NVIDIA's OpenAI-compatible inference endpoint, enter `https://inference-api.nvidia.com` as the base URL and the model ID your endpoint exposes, such as `openai/openai/gpt-5.5`. + +NemoClaw sends a real inference request to validate the endpoint and model. +If the endpoint does not return the streaming events OpenClaw needs from the Responses API, NemoClaw falls back to the chat completions API and configures OpenClaw to use `openai-completions`. + + +NVIDIA Nemotron models expose OpenAI-compatible APIs, so this option is the right choice for any Nemotron deployment that does not live on `build.nvidia.com`. Common examples include a self-hosted NIM container, an enterprise NVIDIA AI Enterprise gateway, or a vLLM/SGLang server running Nemotron weights. Point the base URL at your endpoint and enter the Nemotron model ID exactly as your server reports it. + + + + + +Routes inference to the Anthropic Messages API at `https://api.anthropic.com`. + +Use `ANTHROPIC_API_KEY` for the API key. Get one from the [Anthropic console keys page](https://console.anthropic.com/settings/keys). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `4` to select **Anthropic**. +2. At the `ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [1]:` prompt, pick a curated model (for example, `claude-sonnet-4-6`, `claude-haiku-4-5`, or `claude-opus-4-6`), or pick **Other...** to enter any Claude model ID. + + + + +Routes inference to any server that implements the Anthropic Messages API at `/v1/messages`, including Claude proxies, Bedrock-compatible gateways, and self-hosted Anthropic-compatible servers. + +Use `COMPATIBLE_ANTHROPIC_API_KEY` for the API key. Set it to whatever credential your endpoint expects. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `5` to select **Other Anthropic-compatible endpoint**. +2. At the `Anthropic-compatible base URL` prompt, enter the proxy or gateway's base URL from its documentation. +3. At the `COMPATIBLE_ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. +4. At the `Other Anthropic-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your gateway's model catalog. + + + + +Routes inference to Google's OpenAI-compatible Gemini endpoint at `https://generativelanguage.googleapis.com/v1beta/openai/`. + +Use `GEMINI_API_KEY` for the API key. Get one from [Google AI Studio API keys](https://aistudio.google.com/app/apikey). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `6` to select **Google Gemini**. +2. At the `GEMINI_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [5]:` prompt, pick a curated model (for example, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, or `gemini-2.5-flash-lite`), or pick **Other...** to enter any Gemini model ID. + + + + +Routes inference to a local Ollama instance. Depending on your platform, the wizard can use an existing daemon, start an installed daemon, or offer an install action. + +No API key is required. On non-WSL hosts, NemoClaw generates a token and starts an authenticated proxy so containers can reach Ollama without exposing the daemon directly to your network. +On WSL, NemoClaw can also use Ollama on the Windows host through `host.docker.internal`. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `7` to select **Local Ollama**. +2. At the `Choose model [1]:` prompt, pick from **Ollama models** if any are already installed. If none are installed, pick a **starter model** to pull and load now, or pick **Other...** to enter any Ollama model ID. + +For setup details, including GPU recommendations and starter model choices, refer to [Use a Local Inference Server](/inference/use-local-inference). + + + + + +Starts a host-side model router and routes sandbox inference through OpenShell to that router. +The router chooses from the model pool in `nemoclaw-blueprint/router/pool-config.yaml` for each request. + +Use `NVIDIA_API_KEY` for the model pool credentials. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `8` to select **Model Router (experimental)**. +2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. +3. Review the configuration summary and continue with the sandbox build. + +For scripted setup, set: + +```console +$ NEMOCLAW_PROVIDER=routed NVIDIA_API_KEY= nemoclaw onboard --non-interactive +``` + +The router listens on the host at port `4000`. +The sandbox still calls `https://inference.local/v1`, so do not point in-sandbox tools at the host router port directly. + + + + + +These options appear when `NEMOCLAW_EXPERIMENTAL=1` is set and the prerequisites are met. + +- **Local NVIDIA NIM** requires a NIM-capable GPU. NemoClaw pulls and manages a NIM container. +- **Local vLLM** uses a vLLM server already running on `localhost:8000`, or installs and starts a managed vLLM container on supported DGX Spark, DGX Station, and Linux NVIDIA GPU hosts. NemoClaw auto-detects the loaded model. + +For setup, refer to [Use a Local Inference Server](/inference/use-local-inference). + + +### Review the Configuration Before the Sandbox Build + +After you enter the sandbox name, the wizard prints a review summary and asks for final confirmation before registering the provider, prompting for optional integrations, and building the sandbox image. +For example, if you picked an OpenAI-compatible endpoint, the summary looks like the following: + +```text + ────────────────────────────────────────────────── + Review configuration + ────────────────────────────────────────────────── + Provider: compatible-endpoint + Model: openai/openai/gpt-5.5 + API key: COMPATIBLE_API_KEY (staged for OpenShell gateway registration) + Web search: disabled + Messaging: none + Sandbox name: my-gpt-claw + Note: Sandbox build typically takes 5–15 minutes on this host. + ────────────────────────────────────────────────── + Web search and messaging channels will be prompted next. + Apply this configuration? [Y/n]: +``` + +The default is `Y`, so you can press Enter once to continue. Answer `n` to abort cleanly, fix the entries, and re-run `nemoclaw onboard`. + +Non-interactive runs (`NEMOCLAW_NON_INTERACTIVE=1`) print the summary for log clarity but skip the prompt. + +### Configure Web Search and Messaging + +After you confirm the summary, NemoClaw registers the selected provider with the OpenShell gateway and sets the `inference.local` route. +The wizard then asks whether to enable Brave Web Search. +If you enable it, enter a Brave Search API key when prompted. + +The wizard also offers messaging channels such as Telegram, Discord, and Slack. +Press a channel number to toggle it, then press Enter to continue. +If you select a channel, NemoClaw validates the token format before it bakes the channel configuration into the sandbox. +For example, Slack bot tokens must start with `xoxb-`. + +### Choose Network Policy Presets + +After the sandbox image builds and OpenClaw starts inside the sandbox, NemoClaw asks which network policy tier to apply. +The default **Balanced** tier includes common development presets such as npm, PyPI, Hugging Face, Homebrew, and Brave Search when the selected agent supports web search. +Use the arrow keys or `j` and `k` to move, Space to select, and Enter to confirm. + +The preset selector lets you include more destinations, such as GitHub, Jira, Slack, Telegram, or local inference. +Press `r` to toggle a selected preset between read-only and read-write when the preset supports both modes. + +When the install completes, a summary confirms the running environment. +Before printing the summary, NemoClaw verifies that the sandbox gateway and dashboard port forward are reachable. +Inference route and messaging bridge checks are reported as warnings when they need more time or additional configuration. +The `Model` and provider line reflects the inference option you picked during onboarding. +The example below shows the result if you picked an OpenAI-compatible endpoint during onboarding. + +```text +────────────────────────────────────────────────── +Sandbox my-gpt-claw (Landlock + seccomp + netns) +Model openai/openai/gpt-5.5 (Other OpenAI-compatible endpoint) +────────────────────────────────────────────────── +Run: nemoclaw my-gpt-claw connect +Status: nemoclaw my-gpt-claw status +Logs: nemoclaw my-gpt-claw logs --follow +────────────────────────────────────────────────── + +To change settings later: + Model: nemoclaw inference get + nemoclaw inference set --model --provider --sandbox my-gpt-claw + +[INFO] === Installation complete === +``` + +If you picked a different option, the `Model` line shows that provider's model and label instead. For example, you might see `gpt-5.4 (OpenAI)`, `claude-sonnet-4-6 (Anthropic)`, `gemini-2.5-flash (Google Gemini)`, `llama3.1:8b (Local Ollama)`, `nvidia-routed (Model Router)`, or ` (Other OpenAI-compatible endpoint)`. + +## Run Your First Agent Prompt + +You can chat with the agent from the terminal or the browser. + +### Open the OpenClaw UI in a Browser to Chat with the Agent + +The onboard wizard starts a background port forward to the sandbox dashboard, then prints the dashboard URL in the install summary. +The default host port is `18789`. +If that port is already taken, NemoClaw uses the next free dashboard port, such as `18790`, and prints that port in the final URL. +If the chosen port becomes occupied after the sandbox build starts, onboarding rolls back the newly-created sandbox and asks you to retry instead of printing an unreachable dashboard URL. +The gateway token is redacted from displayed output; retrieve it explicitly when the browser asks for authentication. + +```text +────────────────────────────────────────────────── +OpenClaw UI (auth token redacted from displayed URLs) +Port 18790 must be forwarded before opening these URLs. +Dashboard: http://127.0.0.1:18790/ +Token: nemoclaw my-gpt-claw gateway-token --quiet + append #token= locally if the browser asks for auth. +────────────────────────────────────────────────── +``` + +Open the dashboard URL in your browser. +If the browser asks for authentication, run the printed `gateway-token --quiet` command and append `#token=` locally. +Treat the token like a password. + +### Chat with the Agent from the Terminal + +Connect to the sandbox and use the OpenClaw CLI. + +```bash +nemoclaw my-assistant connect +``` + +In the sandbox shell, send a single message and print the response. + +```bash +openclaw agent --agent main --local -m "hello" --session-id test +``` + +## Next Steps + +Navigate to the following topics to learn more about NemoClaw. + +- [NemoClaw Overview](/about/overview) to learn what NemoClaw is and its capabilities. +- [Architecture Overview](/about/how-it-works) to understand how NemoClaw works. +- [Ecosystem](/about/ecosystem) to understand how OpenClaw, OpenShell, and NemoClaw relate in the wider stack, and when to use NemoClaw versus OpenShell. + +Use the following topics to learn how to use NemoClaw. + +- [Manage NemoClaw sandboxes](/manage-sandboxes/lifecycle) for port forwards, rebuilds, upgrades, and uninstall. +- [Inference Options](/inference/inference-options) to use a different model or endpoint. +- [Network Policies](/network-policy/approve-network-requests) to manage egress approvals. +- [Troubleshooting](/reference/troubleshooting) for common error messages and resolution steps. diff --git a/docs/get-started/windows-preparation.mdx b/docs/get-started/windows-preparation.mdx new file mode 100644 index 0000000000..11672c6178 --- /dev/null +++ b/docs/get-started/windows-preparation.mdx @@ -0,0 +1,111 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Prepare Windows for NemoClaw" +sidebar-title: "Prepare Windows" +description: "Prepare a Windows machine for NemoClaw before running the Quickstart: enable WSL 2, install Ubuntu, and configure Docker Desktop." +description-agent: "Covers Windows-only preparation steps required before the Quickstart. Use when preparing a Windows machine for NemoClaw, enabling WSL 2, configuring Docker Desktop for Windows, or troubleshooting a Windows-specific install error." +keywords: ["nemoclaw windows wsl2 setup", "nemoclaw install windows docker desktop"] +content: + type: "reference" +--- +You can run NemoClaw inside Windows Subsystem for Linux (WSL 2) on Windows. +Complete these steps before following the [Quickstart](/get-started/quickstart). +Linux and macOS users do not need this page and can go directly to the Quickstart. + + +This guide has been tested on x86-64. + + +## Prerequisites + +Verify the following before you begin: + +- Windows 10 (build 19041 or later) or Windows 11. +- Hardware requirements are the same as the [Quickstart](/get-started/quickstart). + +## Enable WSL 2 + +Open an elevated PowerShell (Run as Administrator): + +```console +$ wsl --install --no-distribution +``` + +This enables both the Windows Subsystem for Linux and Virtual Machine Platform features. + +Reboot if prompted. + +## Install and Register Ubuntu + +After reboot, open an elevated PowerShell again: + +```console +$ wsl --install -d Ubuntu +``` + +Let the distribution launch and complete first-run setup (pick a Unix username and password), then type `exit` to return to PowerShell. + + +Do not use the `--no-launch` flag. +The `--no-launch` flag downloads the package but does not register the distribution with WSL. +Commands like `wsl -d Ubuntu` fail with "There is no distribution with the supplied name" until the distribution has been launched at least once. + + +Verify the distribution is registered and running WSL 2: + +```console +$ wsl -l -v +``` + +Expected output: + +```text + NAME STATE VERSION +* Ubuntu Running 2 +``` + +## Install Docker Desktop + +Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) with the WSL 2 backend (the default on Windows 11). + +After installation, open Docker Desktop Settings and confirm that WSL integration is enabled for your Ubuntu distribution (Settings > Resources > WSL integration). + +Verify from inside WSL: + +```console +$ wsl +$ docker info +``` + +`docker info` prints server information. +If you see "Cannot connect to the Docker daemon", confirm that Docker Desktop is running and that WSL integration is enabled. + +## Set Up Local Inference with Ollama (Optional) + +If you plan to select Ollama as your inference provider during onboarding, use one Ollama instance that WSL can reach. +You can install Ollama inside WSL yourself: + +```console +$ curl -fsSL https://ollama.com/install.sh | sh +``` + +If Ollama is installed but not already running in WSL, the onboarding process starts it for you. +You can also start it yourself beforehand with `ollama serve`. + +You can also use Ollama for Windows. +During onboarding, NemoClaw can use an already-running Windows-host daemon, start or restart an installed daemon, or install Ollama on the Windows host. +When Ollama runs on the Windows host, NemoClaw detects it from WSL through `host.docker.internal` and pulls missing models through the Ollama HTTP API. +Do not run both the Windows and WSL Ollama instances on port `11434` at the same time. +Use one instance, or move one of them to a different port before running `nemoclaw onboard`. + +## Next Step + +Your Windows environment is ready. +Open a WSL terminal (type `wsl` in PowerShell, or open Ubuntu from Windows Terminal) and continue with the [Quickstart](/get-started/quickstart) to install NemoClaw and launch your first sandbox. + +All NemoClaw commands run inside WSL, not in PowerShell. + +## Troubleshooting + +For Windows-specific troubleshooting, refer to the [Windows Subsystem for Linux section](/reference/troubleshooting#windows-subsystem-for-linux) in the Troubleshooting guide. diff --git a/docs/index.mdx b/docs/index.mdx new file mode 100644 index 0000000000..1aa6fb8b82 --- /dev/null +++ b/docs/index.mdx @@ -0,0 +1,98 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NVIDIA NemoClaw Developer Guide" +description: "NemoClaw is an open-source reference stack that simplifies running OpenClaw always-on assistants more safely, with a single command." +keywords: "NemoClaw, OpenClaw, OpenShell, AI agents, sandboxing, inference routing" +position: 1 +--- + +NVIDIA NemoClaw is an open-source reference stack that simplifies running [OpenClaw](https://openclaw.ai) always-on assistants more safely. +NemoClaw provides onboarding, lifecycle management, and OpenClaw operations within OpenShell containers. +It installs the [NVIDIA OpenShell](https://github.com/NVIDIA/OpenShell) runtime, part of NVIDIA Agent Toolkit, setting up an environment designed for executing agents with additional security and inference routing capabilities. + +## Get Started + +Install NemoClaw and run your first sandboxed agent. + + + +
+
+ + + +
+
+
+ $ + curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +
+
+
+ +
+ + + +```shell +curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + + + +The Fern migration is starting with the About section while the remaining MyST pages stay in place as the legacy source for generated user skills and parity checks. + +--- + +## Explore + +
+ + + + +Learn what NemoClaw is, what capabilities it provides, and when to use it. + +Concept + + + + +Understand the host CLI, plugin, blueprint, sandbox lifecycle, and protection layers. + +Concept + + + + +Learn how OpenClaw, OpenShell, and NemoClaw fit together. + +Concept + + + + +Track NemoClaw release changes and component version policy. + +Reference + + + +
+ +--- + + + This software automatically retrieves, accesses or interacts with external + materials. Those retrieved materials are not distributed with this software + and are governed solely by separate terms, conditions and licenses. You are + solely responsible for finding, reviewing and complying with all applicable + terms, conditions, and licenses, and for verifying the security, integrity and + suitability of any retrieved materials for your specific use case. This + software is provided "AS IS", without warranty of any kind. The author makes + no representations or warranties regarding any retrieved materials, and + assumes no liability for any losses, damages, liabilities or legal + consequences from your use or inability to use this software or any retrieved + materials. Use this software and the retrieved materials at your own risk. + diff --git a/docs/index.yml b/docs/index.yml new file mode 100644 index 0000000000..be40b80024 --- /dev/null +++ b/docs/index.yml @@ -0,0 +1,146 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +landing-page: + page: "Home" + path: index.mdx + +navigation: + - section: "About NemoClaw" + slug: about + contents: + - page: "Overview" + path: about/overview.mdx + slug: overview + - page: "How It Works" + path: about/how-it-works.mdx + slug: how-it-works + - page: "Ecosystem" + path: about/ecosystem.mdx + slug: ecosystem + - page: "Release Notes" + path: about/release-notes.mdx + slug: release-notes + - section: "Get Started" + slug: get-started + contents: + - section: "Prerequisites" + path: get-started/prerequisites.mdx + slug: prerequisites + contents: + - page: "Windows Preparation" + path: get-started/windows-preparation.mdx + slug: windows-preparation + - page: "Quickstart with OpenClaw" + path: get-started/quickstart.mdx + slug: quickstart + - page: "Quickstart with Hermes" + path: get-started/quickstart-hermes.mdx + slug: quickstart-hermes + - section: "Inference" + slug: inference + contents: + - page: "Inference Options" + path: inference/inference-options.mdx + slug: inference-options + - page: "Use Local Inference" + path: inference/use-local-inference.mdx + slug: use-local-inference + - page: "Tool-Calling Reliability" + path: inference/tool-calling-reliability.mdx + slug: tool-calling-reliability + - page: "Switch Inference Providers" + path: inference/switch-inference-providers.mdx + slug: switch-inference-providers + - page: "Set Up Task-Specific Sub-Agents" + path: inference/set-up-sub-agent.mdx + - section: "Manage Sandboxes" + slug: manage-sandboxes + contents: + - page: "Manage Sandbox Lifecycle" + path: manage-sandboxes/lifecycle.mdx + slug: lifecycle + - page: "Set Up Messaging Channels" + path: manage-sandboxes/messaging-channels.mdx + slug: messaging-channels + - page: "Workspace Files" + path: manage-sandboxes/workspace-files.mdx + slug: workspace-files + - page: "Backup and Restore" + path: manage-sandboxes/backup-restore.mdx + slug: backup-restore + - section: "Network Policy" + slug: network-policy + contents: + - page: "Approve or Deny Network Requests" + path: network-policy/approve-network-requests.mdx + slug: approve-network-requests + - page: "Customize the Network Policy" + path: network-policy/customize-network-policy.mdx + slug: customize-network-policy + - page: "Integration Policy Examples" + path: network-policy/integration-policy-examples.mdx + slug: integration-policy-examples + - section: "Deployment" + slug: deployment + contents: + - page: "Deploy to a Remote GPU Instance" + path: deployment/deploy-to-remote-gpu.mdx + - page: "Brev Web UI" + path: deployment/brev-web-ui.mdx + slug: brev-web-ui + - page: "Install OpenClaw Plugins" + path: deployment/install-openclaw-plugins.mdx + slug: install-openclaw-plugins + - page: "Sandbox Hardening" + path: deployment/sandbox-hardening.mdx + slug: sandbox-hardening + - section: "Monitoring" + slug: monitoring + contents: + - page: "Monitor Sandbox Activity" + path: monitoring/monitor-sandbox-activity.mdx + slug: monitor-sandbox-activity + - section: "Security" + slug: security + contents: + - page: "Security Best Practices" + path: security/best-practices.mdx + slug: best-practices + - page: "Credential Storage" + path: security/credential-storage.mdx + slug: credential-storage + - page: "OpenClaw Controls" + path: security/openclaw-controls.mdx + slug: openclaw-controls + - section: "Reference" + slug: reference + contents: + - page: "Architecture" + path: reference/architecture.mdx + slug: architecture + - page: "CLI Commands Reference" + path: reference/commands.mdx + slug: commands + - page: "CLI Selection Guide" + path: reference/cli-selection-guide.mdx + slug: cli-selection-guide + - page: "Network Policies" + path: reference/network-policies.mdx + slug: network-policies + - page: "Troubleshooting" + path: reference/troubleshooting.mdx + slug: troubleshooting + - section: "Resources" + slug: resources + contents: + - page: "Agent Skills" + path: resources/agent-skills.mdx + slug: agent-skills + - page: "License" + path: resources/license.mdx + slug: license + - link: "Report Vulnerabilities" + href: https://github.com/NVIDIA/NemoClaw/blob/main/SECURITY.md + - link: "Discord" + href: https://discord.gg/XFpfPv9Uvx diff --git a/docs/inference/inference-options.mdx b/docs/inference/inference-options.mdx new file mode 100644 index 0000000000..df59c98177 --- /dev/null +++ b/docs/inference/inference-options.mdx @@ -0,0 +1,127 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Inference Options" +sidebar-title: "Inference Options" +description: "Inference providers available during NemoClaw onboarding and how the routed inference model works." +description-agent: "Lists all inference providers offered during NemoClaw onboarding. Use when explaining which providers are available, what the onboard wizard presents, or how inference routing works." +keywords: ["nemoclaw inference options", "nemoclaw onboarding providers", "nemoclaw inference routing"] +content: + type: "concept" +--- +NemoClaw supports multiple inference providers. +During onboarding, the `nemoclaw onboard` wizard presents a numbered list of providers to choose from. +Your selection determines where the agent's inference traffic is routed. + +## How Inference Routing Works + +The agent inside the sandbox talks to `inference.local`. +It never connects to a provider directly. +OpenShell intercepts inference traffic on the host and forwards it to the provider you selected. + +Provider credentials stay on the host. +The sandbox does not receive your API key. +Local Ollama and local vLLM do not require your host `OPENAI_API_KEY`. +NemoClaw uses provider-specific local tokens for those routes, and rebuilds of legacy local-inference sandboxes migrate away from stale OpenAI credential requirements. + +## Provider Status + +{/* provider-status:begin */} +| Provider | Status | Endpoint type | Notes | +|----------|--------|---------------|-------| +| NVIDIA Endpoints | Tested | OpenAI-compatible | Hosted models on integrate.api.nvidia.com | +| OpenAI | Tested | Native OpenAI-compatible | Uses OpenAI model IDs | +| Other OpenAI-compatible endpoint | Tested | Custom OpenAI-compatible | For compatible proxies and gateways | +| Anthropic | Tested | Native Anthropic | Uses anthropic-messages | +| Other Anthropic-compatible endpoint | Tested | Custom Anthropic-compatible | For Claude proxies and compatible gateways | +| Google Gemini | Tested | OpenAI-compatible | Uses Google's OpenAI-compatible endpoint | +| Hermes Provider | Hermes only | OpenAI-compatible route | Available when onboarding Hermes Agent through `nemohermes` | +| Local Ollama | Caveated | Local Ollama API | Available when Ollama is installed or running on the host | +| Local NVIDIA NIM | Experimental | Local OpenAI-compatible | Requires `NEMOCLAW_EXPERIMENTAL=1` and a NIM-capable GPU | +| Local vLLM | Experimental | Local OpenAI-compatible | Requires `NEMOCLAW_EXPERIMENTAL=1` and a server already running on `localhost:8000` | +{/* provider-status:end */} + +## Provider Options + +The onboard wizard presents the following provider options by default. +The first six are always available. +Ollama appears when it is installed or running on the host. +Experimental local vLLM appears when NemoClaw detects a running vLLM server. +The managed install/start vLLM entry appears when you opt in and NemoClaw detects a supported NVIDIA GPU host profile. + +| Option | Description | Curated models | +|--------|-------------|----------------| +| NVIDIA Endpoints | Routes to models hosted on [build.nvidia.com](https://build.nvidia.com). You can also enter any model ID from the catalog. Set `NVIDIA_API_KEY`. | Nemotron 3 Super 120B, GLM-5.1, MiniMax M2.7, GPT-OSS 120B, DeepSeek V4 Pro | +| OpenAI | Routes to the OpenAI API. Set `OPENAI_API_KEY`. | `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, `gpt-5.4-pro-2026-03-05` | +| Other OpenAI-compatible endpoint | Routes to any server that implements `/v1/chat/completions`. If the endpoint also supports `/responses` with OpenClaw-style tool calling, NemoClaw can use that path; otherwise it falls back to `/chat/completions`. The wizard prompts for a base URL and model name. Works with OpenRouter, LocalAI, llama.cpp, or any compatible proxy. When you enable Telegram messaging, onboarding also runs a bounded sandbox-side smoke check through `https://inference.local/v1/chat/completions`. Set `COMPATIBLE_API_KEY`. | You provide the model name. | +| Anthropic | Routes to the Anthropic Messages API. Set `ANTHROPIC_API_KEY`. | `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-6` | +| Other Anthropic-compatible endpoint | Routes to any server that implements the Anthropic Messages API (`/v1/messages`). The wizard prompts for a base URL and model name. Set `COMPATIBLE_ANTHROPIC_API_KEY`. | You provide the model name. | +| Google Gemini | Routes to Google's OpenAI-compatible endpoint. NemoClaw prefers `/responses` only when the endpoint proves it can handle tool calling in a way OpenClaw uses; otherwise it falls back to `/chat/completions`. Set `GEMINI_API_KEY`. | `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.5-flash-lite` | +| Hermes Provider | Routes Hermes Agent through the host OpenShell provider registered by NemoClaw when onboarding Hermes Agent. | Curated Hermes Provider models such as `moonshotai/kimi-k2.6`, `openai/gpt-5.4-mini`, and `z-ai/glm-5.1`. | +| Local Ollama | Routes to a local Ollama instance on `localhost:11434`. NemoClaw detects installed models, offers starter models if none are present, pulls and warms the selected model, and validates it. | Selected during onboarding. For more information, refer to [Use a Local Inference Server](/inference/use-local-inference). | +| Model Router | Starts a host-side router on port `4000`, registers it as an OpenAI-compatible provider, and keeps the sandbox pointed at `inference.local`. Set `NEMOCLAW_PROVIDER=routed` for non-interactive setup. | The router pool defines the model names. | + +## Choosing the Right Option for Nemotron + +NVIDIA Nemotron models expose OpenAI-compatible APIs across every supported deployment surface, so two onboarding options can route to Nemotron. + +| Where Nemotron is hosted | Onboard wizard option | Why | +|---|---|---| +| `build.nvidia.com` (NVIDIA-hosted) | **Option 1: NVIDIA Endpoints** | NemoClaw sets the base URL to `https://integrate.api.nvidia.com/v1` for you and validates the model against the build catalog. | +| Self-hosted NIM container | **Option 3: Other OpenAI-compatible endpoint** | NIM exposes an OpenAI-compatible `/v1/chat/completions` route. Point the base URL at your NIM service and enter the Nemotron model ID. | +| Enterprise NVIDIA AI Enterprise gateway | **Option 3: Other OpenAI-compatible endpoint** | Enterprise gateways front Nemotron with the same OpenAI-compatible contract. Use the gateway's base URL and your enterprise token. | +| vLLM, SGLang, or TRT-LLM serving Nemotron weights | **Option 3: Other OpenAI-compatible endpoint** | Each runtime exposes Nemotron through `/v1/chat/completions`. Use the runtime's base URL and the model ID it reports. | +| Local NIM started by the wizard | **Local NVIDIA NIM** (experimental) | Requires `NEMOCLAW_EXPERIMENTAL=1` and a NIM-capable GPU. NemoClaw pulls and manages the container for you. | + +For Option 3, the API key environment variable is `COMPATIBLE_API_KEY`. Set it to whatever credential your endpoint expects, or any non-empty placeholder if your endpoint does not require auth. + +## Model Router + +The Model Router option uses the `routed` inference profile in `nemoclaw-blueprint/blueprint.yaml`. +When you select it, NemoClaw starts the router proxy on the host, waits for its health endpoint, registers the `nvidia-router` provider with OpenShell, and creates the sandbox with the same `inference.local` route the agent uses for other providers. +The sandbox does not call the router port directly. + +The router model pool lives in `nemoclaw-blueprint/router/pool-config.yaml`. +The default pool routes between NVIDIA-hosted Nemotron models and uses the `tolerance` value to choose the lowest-cost model whose predicted quality stays within the configured threshold. +To use the router in scripted setup, set: + +```console +$ NEMOCLAW_PROVIDER=routed NVIDIA_API_KEY= nemoclaw onboard --non-interactive +``` + +## Experimental Options + +The following local inference options are experimental. +Local NIM and managed vLLM install/start require `NEMOCLAW_EXPERIMENTAL=1`; an already-running vLLM server appears directly in the onboarding selection list. + +| Option | Condition | Notes | +|--------|-----------|-------| +| Local NVIDIA NIM | NIM-capable GPU detected | Pulls and manages a NIM container. | +| Local vLLM | vLLM running on `localhost:8000`, or a supported DGX Spark, DGX Station, or Linux NVIDIA GPU profile | Auto-detects the loaded model when vLLM is already running. Can install or start a managed vLLM container for supported profiles after experimental opt-in. | + +For setup instructions, refer to [Use a Local Inference Server](/inference/use-local-inference). + +## Validation + +NemoClaw validates the selected provider and model before creating the sandbox. +If credential validation fails, the wizard asks whether to re-enter the API key, choose a different provider, retry, or exit. +Transient upstream validation failures are retried before the wizard reports a provider failure. +The `nvapi-` prefix check applies only to `NVIDIA_API_KEY`. +Other provider credentials, such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, and compatible endpoint keys, use provider-aware validation during retry. + +| Provider type | Validation method | +|---|---| +| OpenAI | Tries `/responses` first, then `/chat/completions`. | +| NVIDIA Endpoints | Tries `/responses` first with a tool-calling probe that matches OpenClaw behavior. Falls back to `/chat/completions` if the endpoint does not return a compatible tool call. | +| Google Gemini | Tries `/responses` first with a tool-calling probe that matches OpenClaw behavior. Falls back to `/chat/completions` if the endpoint does not return a compatible tool call. | +| Other OpenAI-compatible endpoint | Tries `/responses` first with a tool-calling probe that matches OpenClaw behavior. Falls back to `/chat/completions` if the endpoint does not return a compatible tool call. | +| Anthropic-compatible | Tries `/v1/messages`. | +| NVIDIA Endpoints (manual model entry) | Validates the model name against the catalog API. | +| Compatible endpoints | Sends a real inference request because many proxies do not expose a `/models` endpoint. For OpenAI-compatible endpoints, the probe includes tool calling before NemoClaw favors `/responses`. | +| Local NVIDIA NIM | Uses the same validation behavior as NVIDIA Endpoints and skips the `/v1/responses` probe for endpoints that do not expose it. | + +## Next Steps + +- [Use a Local Inference Server](/inference/use-local-inference) for Ollama, vLLM, NIM, and compatible-endpoint setup details. +- [Tool-Calling Reliability](/inference/tool-calling-reliability) for deciding when Ollama is enough and when vLLM with a parser is safer. +- [Switch Inference Models](/inference/switch-inference-providers) for changing the model at runtime without re-onboarding. diff --git a/docs/inference/set-up-sub-agent.mdx b/docs/inference/set-up-sub-agent.mdx new file mode 100644 index 0000000000..7562d6350c --- /dev/null +++ b/docs/inference/set-up-sub-agent.mdx @@ -0,0 +1,129 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Set up a Task-Specific Sub-Agent" +sidebar-title: "Task-Specific Sub-Agent" +description: "Where NemoClaw stores OpenClaw sub-agent model configuration, credentials, and workspace files inside the sandbox." +description-agent: "Shows the NemoClaw-specific file paths and update flow for adding an auxiliary OpenClaw sub-agent model. Use when users ask how to add a second model, configure a sub-agent model, use Omni for vision tasks, configure agents.list, or use sessions_spawn in NemoClaw." +keywords: ["nemoclaw additional model", "nemoclaw sub-agent model", "openclaw sub-agent", "agents.list", "sessions_spawn", "vlm-demo"] +content: + type: "how_to" +skill: + priority: 30 +--- +OpenClaw documents the sub-agent behavior, `sessions_spawn` tool, `agents.list` configuration, tool policy, nesting, and auth model in [Sub-Agents](https://docs.openclaw.ai/tools/subagents). +Use that page as the source of truth for how OpenClaw sub-agents work. + +This NemoClaw page covers the sandbox-specific pieces: where the OpenClaw config lives, where to put per-agent credentials, which writable workspace path agents should use, and how the Omni VLM demo maps onto those paths. + +## NemoClaw Sandbox Paths + +NemoClaw runs OpenClaw inside an OpenShell sandbox. +When adapting an OpenClaw sub-agent setup, use these paths inside the sandbox: + +| Path | Purpose | +|---|---| +| `/sandbox/.openclaw/openclaw.json` | OpenClaw config, including `models.providers`, `agents.defaults`, and `agents.list`. | +| `/sandbox/.openclaw/.config-hash` | Hash for `openclaw.json`. Keep it in sync after manual config edits; it becomes a startup-enforced trust anchor only after the file is root-owned and read-only. | +| `/sandbox/.openclaw/agents//agent/auth-profiles.json` | Per-agent provider credentials. Use this when a sub-agent calls an auxiliary provider directly. | +| `/sandbox/.openclaw/workspace/` | Writable shared workspace path for files the primary agent passes to the sub-agent. | +| `/tmp/gateway.log` | OpenClaw gateway log. Use it to confirm config reloads and diagnose sub-agent failures. | + +For file-based tasks, instruct agents to use `/sandbox/.openclaw/workspace/`. +Avoid relying on legacy `.openclaw-data` paths or read-only OpenClaw paths in delegation instructions. + +## Omni Vision Sub-Agent Example + +The [`vlm-demo`](https://github.com/brevdev/nemoclaw-demos/tree/main/vlm-demo) applies the OpenClaw sub-agent pattern to a vision task. +It keeps the primary `main` agent on the normal NemoClaw inference route and adds a `vision-operator` sub-agent backed by an Omni vision model. + +| OpenClaw field | Omni example value | +|---|---| +| Primary agent | `main` | +| Primary model | `inference/nvidia/nemotron-3-super-120b-a12b` | +| Auxiliary provider | `nvidia-omni` | +| Sub-agent | `vision-operator` | +| Sub-agent model | `nvidia-omni/private/nvidia/nemotron-3-nano-omni-reasoning-30b-a3b` | +| Delegation tool | `sessions_spawn` | + +Omni is used as the specialist model for image tasks. +The primary orchestration model remains responsible for conversation, planning, and deciding when to delegate. + +## Update the Sandbox Config + +Fetch the current OpenClaw config from the sandbox, patch it with your auxiliary provider and `agents.list` changes, then upload it back. + +```console +$ export SANDBOX=my-assistant +$ export DOCKER_CTR=openshell-cluster-nemoclaw +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- cat /sandbox/.openclaw/openclaw.json > /tmp/openclaw.json +``` + +Create `/tmp/openclaw.updated.json` with the OpenClaw sub-agent config. +For the Omni example, the demo provides `vlm-demo/vlm-subagent/openclaw-patch.py`. + +Upload the patched config and refresh the hash. +In the default mutable state, this keeps the local hash consistent but does not make it tamper-proof; lock the config root-owned and read-only afterward if the sandbox should enforce config integrity at startup. + +```console +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- chmod 644 /sandbox/.openclaw/openclaw.json +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- chmod 644 /sandbox/.openclaw/.config-hash +$ cat /tmp/openclaw.updated.json | docker exec -i "$DOCKER_CTR" kubectl exec -i -n openshell "$SANDBOX" -c agent -- sh -c 'cat > /sandbox/.openclaw/openclaw.json' +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- /bin/bash -c "cd /sandbox/.openclaw && sha256sum openclaw.json > .config-hash" +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- chmod 444 /sandbox/.openclaw/openclaw.json +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- chmod 444 /sandbox/.openclaw/.config-hash +``` + +Check `/tmp/gateway.log` after upload and confirm the gateway hot-reloaded the provider or `agents.list` change. + +## Add Sub-Agent Credentials + +If the auxiliary model uses a provider key outside the normal NemoClaw inference route, put that key in the sub-agent auth profile. +For the Omni example: + +```text +/sandbox/.openclaw/agents/vision-operator/agent/auth-profiles.json +``` + +Use the same provider ID that appears in `models.providers`, such as `nvidia-omni`. +After uploading the auth profile, make sure the sub-agent directory is owned by the sandbox user: + +```console +$ docker exec "$DOCKER_CTR" kubectl exec -n openshell "$SANDBOX" -c agent -- chown -R sandbox:sandbox /sandbox/.openclaw/agents/vision-operator +``` + +## Allow Auxiliary Provider Egress + +If the sub-agent calls a provider directly, update the OpenShell network policy for the binary that makes the request. +In the Omni demo, the OpenClaw gateway runs as `/usr/local/bin/node`, so the NVIDIA endpoint policy must allow that binary. + +Refer to [Customize the Network Policy](/network-policy/customize-network-policy) for policy update workflows. + +## Add Delegation Instructions + +OpenClaw handles `sessions_spawn`, but the primary agent still needs task instructions. +Place those instructions in the writable workspace, for example: + +```text +/sandbox/.openclaw/workspace/TOOLS.md +``` + +The Omni demo includes `vlm-demo/vlm-subagent/TOOLS.md`, which tells `main` to delegate image tasks to `vision-operator` and tells the sub-agent to read the image path it receives. +Adapt that file for other task-specific models. + +## Demo Assets + +Use the [`vlm-demo`](https://github.com/brevdev/nemoclaw-demos/tree/main/vlm-demo) repository for runnable Omni example assets: + +- `vlm-subagent-guide.md` for a command-by-command walkthrough. +- `vlm-subagent/openclaw-patch.py` for patching `openclaw.json`. +- `vlm-subagent/auth-profiles.template.json` for the sub-agent auth profile. +- `vlm-subagent/TOOLS.md` for delegation instructions. + +## Next Steps + +Use the following resources for more information: + +- Refer to [OpenClaw Sub-Agents](https://docs.openclaw.ai/tools/subagents) for `sessions_spawn`, `agents.list`, nesting, tool policy, and auth behavior. +- Refer to [Switch Inference Providers](/inference/switch-inference-providers) to change the primary orchestration model instead of adding a sub-agent model. +- Refer to [Workspace Files](/manage-sandboxes/workspace-files) to understand per-agent workspace directories. diff --git a/docs/inference/switch-inference-providers.mdx b/docs/inference/switch-inference-providers.mdx new file mode 100644 index 0000000000..df02a26dc7 --- /dev/null +++ b/docs/inference/switch-inference-providers.mdx @@ -0,0 +1,205 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Switch NemoClaw Inference Models at Runtime" +sidebar-title: "Switch Inference Models" +description: "Change the active inference model without restarting the sandbox." +description-agent: "Changes the active inference model without restarting the sandbox. Use when switching inference providers, changing the model runtime, or reconfiguring inference routing." +keywords: ["switch nemoclaw inference model", "change inference runtime"] +content: + type: "how_to" +skill: + priority: 20 +--- +Change the active inference model while the sandbox is running. +No restart is required. + +## Prerequisites + +- A running NemoClaw sandbox. +- The OpenShell CLI on your `PATH`, which NemoClaw uses under the hood. + +## Switch to a Different Model + +Use `nemoclaw inference set` with the provider and model that match the upstream you want to use. +The command updates the OpenShell inference route and synchronizes the running agent config. +For OpenClaw, it updates `agents.defaults.model.primary` and the matching provider namespace. +For Hermes, it updates `/sandbox/.hermes/config.yaml` (`model.default`, `model.base_url`, and `model.provider: custom`) without rebuilding or restarting Hermes. + +Pass `--sandbox ` when you do not want to use the default registered sandbox. +Under `nemohermes`, pass `--sandbox ` when more than one Hermes sandbox is registered. + +### NVIDIA Endpoints + +```console +$ nemoclaw inference set --provider nvidia-prod --model nvidia/nemotron-3-super-120b-a12b +``` + +### OpenAI + +```console +$ nemoclaw inference set --provider openai-api --model gpt-5.4 +``` + +### Anthropic + +```console +$ nemoclaw inference set --provider anthropic-prod --model claude-sonnet-4-6 +``` + +### Google Gemini + +```console +$ nemoclaw inference set --provider gemini-api --model gemini-2.5-flash +``` + +### Compatible Endpoints + +If you onboarded a custom compatible endpoint, switch models with the provider created for that endpoint: + +```console +$ nemoclaw inference set --provider compatible-endpoint --model +``` + +```console +$ nemoclaw inference set --provider compatible-anthropic-endpoint --model +``` + +### Hermes Provider + +For a NemoClaw-managed Hermes sandbox, use the Hermes alias with the registered Hermes Provider route: + +```console +$ nemohermes inference set --provider hermes-provider --model openai/gpt-5.4-mini +``` + +#### Switching from Responses API to Chat Completions + +If onboarding selected `/v1/responses` but the agent fails at runtime (for +example, because the backend does not emit the streaming events OpenClaw +requires), re-run onboarding so the wizard re-probes the endpoint and bakes +the correct API path into the image: + +```console +$ nemoclaw onboard +``` + +Select the same provider and endpoint again. +The updated streaming probe will detect incomplete `/v1/responses` support +and select `/v1/chat/completions` automatically. + +For the compatible-endpoint provider, NemoClaw uses `/v1/chat/completions` by +default, so no env var is required to keep the safe path. +To opt in to `/v1/responses` for a backend you have verified end to end, set +`NEMOCLAW_PREFERRED_API` before onboarding: + +```console +$ NEMOCLAW_PREFERRED_API=openai-responses nemoclaw onboard +``` + + +`NEMOCLAW_INFERENCE_API_OVERRIDE` patches the config at container startup but +does not update the Dockerfile ARG baked into the image. +If you recreate the sandbox without the override env var, the image reverts to +the original API path. +A fresh `nemoclaw onboard` is the reliable fix because it updates both the +session and the baked image. + + +## Cross-Provider Switching + +Switching to a different provider family (for example, from NVIDIA Endpoints to Anthropic) also uses `nemoclaw inference set`. +The command updates both the gateway route and the OpenClaw provider namespace in the running sandbox config. + +```console +$ nemoclaw inference set --provider anthropic-prod --model claude-sonnet-4-6 --no-verify +``` + +Use `--no-verify` only when OpenShell cannot verify the provider at switch time but you have already confirmed the provider and credential. + +## Tune Model Metadata + +The sandbox image bakes model metadata (context window, max output tokens, reasoning mode, and accepted input modalities) into `openclaw.json` at build time. +To change these values, set the corresponding environment variables before running `nemoclaw onboard` so they patch into the Dockerfile before the image builds. + +| Variable | Values | Default | +|---|---|---| +| `NEMOCLAW_CONTEXT_WINDOW` | Positive integer (tokens) | `131072` | +| `NEMOCLAW_MAX_TOKENS` | Positive integer (tokens) | `4096` | +| `NEMOCLAW_REASONING` | `true` or `false` | `false` | +| `NEMOCLAW_INFERENCE_INPUTS` | `text` or `text,image` | `text` | +| `NEMOCLAW_AGENT_TIMEOUT` | Positive integer (seconds) | `600` | +| `NEMOCLAW_AGENT_HEARTBEAT_EVERY` | Go-style duration (`30m`, `1h`, `0m` to disable) | `unset` (OpenClaw default) | + +Invalid values are ignored, and the default bakes into the image. +Use `NEMOCLAW_INFERENCE_INPUTS=text,image` only for a model that accepts image input through the selected provider. + +```console +$ export NEMOCLAW_CONTEXT_WINDOW=65536 +$ export NEMOCLAW_MAX_TOKENS=8192 +$ export NEMOCLAW_REASONING=true +$ export NEMOCLAW_INFERENCE_INPUTS=text,image +$ export NEMOCLAW_AGENT_TIMEOUT=1800 +$ export NEMOCLAW_AGENT_HEARTBEAT_EVERY=0m +$ nemoclaw onboard +``` + +`NEMOCLAW_AGENT_TIMEOUT` controls the per-request inference timeout baked into +`agents.defaults.timeoutSeconds`. Increase it for slow local inference (for +example, CPU-only Ollama or vLLM on modest hardware). NemoClaw writes this +value into `openclaw.json` during onboarding. The default sandbox may keep that +file writable for agent state, but direct in-sandbox edits are not the supported +or durable way to change NemoClaw-managed defaults. Rebuild the sandbox via +`nemoclaw onboard` to apply a new value. + +`NEMOCLAW_AGENT_HEARTBEAT_EVERY` sets `agents.defaults.heartbeat.every`. +This controls OpenClaw's periodic main-session agent turn. +Each interval, the agent wakes up to review follow-ups and read `HEARTBEAT.md` if present in the workspace. +The OpenClaw default is 30 minutes (1 hour for Anthropic OAuth / Claude CLI reuse). +Tune the cadence with a duration string like `5m` or `2h`, or set `0m` to disable the periodic turns entirely. +Disabling also drops `HEARTBEAT.md` from normal-run bootstrap context per upstream behavior, so the model no longer sees heartbeat-only instructions. +NemoClaw writes this value into `openclaw.json` during onboarding. +The in-sandbox `openclaw config set` command is not the supported path for +NemoClaw-managed build-time defaults, and direct file edits are overwritten by a +rebuild. Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new value. + +These variables are build-time settings. +If you change them on an existing sandbox, recreate the sandbox so the new values bake into the image: + +```console +$ nemoclaw onboard --resume --recreate-sandbox +``` + +## Verify the Active Model + +Run the inference command to confirm the live gateway route: + +```console +$ nemoclaw inference get +``` + +Add `--json` for machine-readable output: + +```console +$ nemoclaw inference get --json +``` + +Run the status command when you also need sandbox, service, and messaging health: + +```console +$ nemoclaw status +``` + +The status output includes the active provider, model, and endpoint with the rest of the sandbox state. + +## Notes + +- The host keeps provider credentials. +- The sandbox continues to use `inference.local`. +- `nemoclaw inference set` patches the selected running OpenClaw or Hermes sandbox config and recomputes its config hash. +- Use `nemoclaw onboard --resume --recreate-sandbox` for build-time settings such as context window, max tokens, reasoning mode, heartbeat cadence, or image contents. +- Local Ollama and local vLLM routes use local provider tokens rather than `OPENAI_API_KEY`. Rebuilds of older local-inference sandboxes clear the stale OpenAI credential requirement automatically. + +## Related Topics + +- [Inference Options](/inference/inference-options) for the full list of providers available during onboarding. diff --git a/docs/inference/tool-calling-reliability.mdx b/docs/inference/tool-calling-reliability.mdx new file mode 100644 index 0000000000..1f3a0d4b96 --- /dev/null +++ b/docs/inference/tool-calling-reliability.mdx @@ -0,0 +1,171 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Tool-Calling Reliability for Local Inference" +sidebar-title: "Tool-Calling Reliability" +description: "Diagnose local inference setups where tool calls leak as plain text and choose when to use Ollama or vLLM." +description-agent: "Explains Ollama tool-call leak symptoms, when vLLM with a tool-call parser is recommended, and how to repoint NemoClaw to a parser-aware local endpoint." +keywords: ["nemoclaw tool calling", "ollama tool calls", "vllm tool-call-parser", "raw json in tui"] +content: + type: "troubleshooting" +--- +Local inference is useful for privacy, cost control, and offline development, but +tool-calling agents place stricter demands on the model server than simple chat. +The model server must return structured `tool_calls`, not a JSON-looking string +inside normal assistant text. + +Use this page when the TUI shows raw JSON such as: + +```json +{"arguments":{"query":"robotics"},"name":"memory_search"} +``` + +If that appears as text in the assistant reply, OpenClaw cannot dispatch the +tool because the inference response did not include a structured tool call. + +## Quick Choice Guide + +| Workload | Ollama is usually sufficient | Prefer vLLM with a parser | +|---|---|---| +| Plain chat | Yes | Optional | +| Embeddings-only or retrieval setup | Yes | Optional | +| One simple tool with short prompts | Often | Optional | +| Agent loops with several tools | Risky | Yes | +| Long system prompts or sender metadata | Risky | Yes | +| Multi-turn tool dispatch | Risky | Yes | + +Ollama can work well for lightweight local chat and some simple tool surfaces. +For OpenClaw-style agent loops with multiple tools, long instructions, or +multi-turn dispatch, use a server that exposes OpenAI-compatible +`/v1/chat/completions` with a tool-call parser. vLLM is the common local choice. + +## Symptom + +The common failure mode is: + +- The model emits text that looks like a tool call. +- The response does not include a structured `tool_calls` field. +- The gateway treats the response as normal text. +- No tool runs, and the user sees raw JSON in the TUI. + +This is different from a network or policy block. `nemoclaw status`, +`nemoclaw logs`, and `nemoclaw debug --quick` can all look healthy while +tool dispatch still fails inside the conversation. + +## Recommended Fix + +For persistent NemoClaw use, start vLLM with auto tool choice and the parser that +matches your model family, then rerun onboarding and select **Local vLLM +[experimental]** or **Other OpenAI-compatible endpoint**. + +For Hermes 3 style models, a known-good vLLM command shape is: + +```console +$ vllm serve /models/Hermes-3-Llama-3.1-8B \ + --served-model-name hermes-3-llama-3.1-8b \ + --enable-auto-tool-choice \ + --tool-call-parser hermes \ + --port 8000 +``` + +For a Docker Compose setup: + +```yaml +services: + vllm-nemoclaw: + image: vllm/vllm-openai:latest + container_name: vllm-nemoclaw + restart: unless-stopped + ports: + - "8002:8000" + volumes: + - /path/to/models:/models:ro + - /path/to/hf-cache:/root/.cache/huggingface + ipc: host + deploy: + resources: + reservations: + devices: + - capabilities: [gpu] + count: all + command: > + --model /models/Hermes-3-Llama-3.1-8B + --served-model-name hermes-3-llama-3.1-8b + --enable-auto-tool-choice + --tool-call-parser hermes + --gpu-memory-utilization 0.20 + --max-model-len 32768 + --api-key ${VLLM_API_KEY} +``` + +Then onboard against that endpoint: + +```console +$ NEMOCLAW_PROVIDER=custom \ + NEMOCLAW_ENDPOINT_URL=http://localhost:8002/v1 \ + NEMOCLAW_MODEL=hermes-3-llama-3.1-8b \ + COMPATIBLE_API_KEY=$VLLM_API_KEY \ + nemoclaw onboard --non-interactive +``` + +If the endpoint does not require authentication, set `COMPATIBLE_API_KEY` to any +non-empty placeholder, such as `dummy`. + +## Advanced Temporary Repointing + +NemoClaw-managed sandboxes normally block direct `openclaw config set` writes +inside the sandbox because those edits do not survive rebuilds. Prefer rerunning +`nemoclaw onboard` for a persistent provider change. + +If you are intentionally testing a mutable OpenClaw config, prepare a batch file +like this: + +```json +{ + "models": { + "providers": { + "vllm-local": { + "baseUrl": "http://host.openshell.internal:8002/v1", + "api": "openai", + "apiKey": "${VLLM_API_KEY}" + } + } + }, + "agents": { + "defaults": { + "model": { + "primary": "vllm-local/hermes-3-llama-3.1-8b" + } + } + } +} +``` + +Apply it only in environments where OpenClaw config writes are allowed: + +```console +$ openclaw config set --batch-file /sandbox/.openclaw/vllm-tool-calls.json +``` + +After testing, persist the working provider through `nemoclaw onboard` so the +sandbox image, OpenShell inference route, and host-managed credentials stay in +sync. + +## Verify the Fix + +After switching to vLLM, ask for an action that should use a tool. Good signs: + +- The TUI does not show JSON blobs as assistant text. +- The gateway log shows tool dispatch and a follow-up answer. +- `nemoclaw status` reports the local vLLM or compatible endpoint as the + active provider. + +If JSON still appears as text, confirm that vLLM was started with both +`--enable-auto-tool-choice` and the correct `--tool-call-parser` value for your +model. + +## Next Steps + +- [Use a Local Inference Server](/inference/use-local-inference) +- [Inference Options](/inference/inference-options) +- [Switch Inference Models](/inference/switch-inference-providers) diff --git a/docs/inference/use-local-inference.mdx b/docs/inference/use-local-inference.mdx new file mode 100644 index 0000000000..437412b558 --- /dev/null +++ b/docs/inference/use-local-inference.mdx @@ -0,0 +1,389 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Use a Local Inference Server with NemoClaw" +sidebar-title: "Use Local Inference" +description: "Connect NemoClaw to a local model server such as Ollama, vLLM, TensorRT-LLM, or any OpenAI-compatible endpoint." +description-agent: "Connects NemoClaw to a local inference server. Use when setting up Ollama, vLLM, TensorRT-LLM, NIM, or any OpenAI-compatible local model server with NemoClaw." +keywords: ["nemoclaw local inference", "ollama nemoclaw", "vllm nemoclaw", "local model server", "openai compatible endpoint"] +content: + type: "how_to" +skill: + priority: 10 +--- +NemoClaw can route inference to a model server running on your machine instead of a cloud API. +This page covers Ollama, compatible-endpoint paths for other servers, and experimental managed options for vLLM and NVIDIA NIM. + +All approaches use the same `inference.local` routing model. +The agent inside the sandbox never connects to your model server directly. +OpenShell intercepts inference traffic and forwards it to the local endpoint you configure. + +## Prerequisites + +- NemoClaw installed. + Refer to the [Quickstart](/get-started/quickstart) if you have not installed yet. +- A local model server running, or a supported Ollama, vLLM, or NIM setup that the NemoClaw onboard wizard can use, start, or install. + +## Ollama + +Ollama is the default local inference option. +The onboard wizard detects Ollama automatically when it is installed or running on the host. + +If Ollama is installed but not running, NemoClaw starts it for you. +On macOS and Linux, the wizard can also offer to install Ollama when it is not present. +On WSL, the wizard can use, start, restart, or install Ollama on the Windows host through PowerShell interop. +On Debian and Ubuntu, the native Linux install path checks for `zstd` before it runs the Ollama installer. +If `zstd` is missing, NemoClaw installs it with `apt-get` and explains the sudo prompt before continuing. +On non-apt Linux distributions, install `zstd` first, then rerun onboarding. + +Run the onboard wizard. + +```console +$ nemoclaw onboard +``` + +Select **Local Ollama** from the provider list. +NemoClaw lists installed models or offers starter models if none are installed. +On hosts with at least 32 GiB of detected GPU memory, the starter list includes `qwen3.6:35b` and selects it by default. +It pulls the selected model, loads it into memory, and validates it before continuing. +If the selected model declares that it does not support tool calling, onboarding stops with guidance to choose a model whose `ollama show ` capabilities include `tools`. +The validation also requires structured chat-completions tool calls. +If the model leaks tool-call JSON as plain message text, onboarding stops so you can choose a model that returns tool calls in the expected response field. +On WSL, if you choose the Windows-host Ollama path, NemoClaw uses `host.docker.internal:11434` and pulls missing models through the Ollama HTTP API instead of requiring the `ollama` CLI inside WSL. + +### WSL with Windows-Host Ollama + +When NemoClaw runs inside WSL, the provider menu can include Windows-host Ollama actions: + +- **Use Ollama on Windows host** when the Windows daemon is already reachable. +- **Restart Ollama on Windows host** when the daemon is installed but only bound to Windows loopback. +- **Start Ollama on Windows host** when Ollama is installed but not running. +- **Install Ollama on Windows host** when Windows does not have Ollama installed. + +The install and restart paths set `OLLAMA_HOST=0.0.0.0:11434` on the Windows side so Docker and WSL can reach the daemon through `host.docker.internal`. +After an install or restart action, NemoClaw relaunches Ollama from the detected Windows tray app or verified `ollama.exe` path and waits until `host.docker.internal:11434` responds. +If the daemon does not become reachable, onboarding prints PowerShell commands you can run to inspect the Windows-side process and port state. +Use one Ollama instance on port `11434` at a time. +If both WSL and Windows-host Ollama are running, pick the intended menu entry during onboarding so NemoClaw validates and pulls models against the right daemon. + + +Ollama is convenient for local chat, but some model/template combinations can +return tool calls as plain text under realistic agent load. If the TUI shows raw +JSON such as `{"name":"memory_search","arguments":{...}}` instead of running a +tool, switch to vLLM with `--enable-auto-tool-choice` and the correct +`--tool-call-parser`. See [Tool-Calling Reliability](/inference/tool-calling-reliability). + + +### Authenticated Reverse Proxy + +On non-WSL hosts, NemoClaw keeps Ollama bound to `127.0.0.1:11434` and starts a token-gated reverse proxy on `0.0.0.0:11435`. +The native install/start paths also reset NemoClaw-managed systemd launches to the loopback binding. +Containers and other hosts on the local network reach Ollama only through the +proxy, which validates a Bearer token before forwarding requests. +On that native path, NemoClaw never exposes Ollama without authentication. + +WSL Ollama paths do not use this proxy. +Windows-host Ollama uses the Windows daemon through `host.docker.internal`. + +For non-WSL Ollama setups, the onboard wizard manages the proxy automatically: + +- Generates a random 24-byte token on first run and stores it in + `~/.nemoclaw/ollama-proxy-token` with `0600` permissions. +- Starts the proxy after Ollama and verifies it before continuing. +- Cleans up stale proxy processes from previous runs. +- Probes the sandbox Docker network path to the proxy before committing the inference route. +- Stops matching proxy processes during uninstall before deleting NemoClaw state. +- Reuses the persisted token after a host reboot so you do not need to re-run + onboard. + +On native Linux hosts, a firewall can allow the host proxy health check while still blocking sandbox containers on the OpenShell Docker bridge. +When the sandbox-side proxy probe fails with a TCP error, onboarding exits before it saves the inference route and prints a command like: + +```console +$ sudo ufw allow from to any port 11435 proto tcp +$ nemoclaw onboard +``` + +If the probe cannot run, for example because Docker Desktop or WSL uses a different host routing model, onboarding continues and relies on the regular proxy health check. + +The sandbox provider is configured to use proxy port `11435` with the generated +token as its `OPENAI_API_KEY` credential. +OpenShell's L7 proxy injects the token at egress, so the agent inside the +sandbox never sees the token directly. + +All proxy endpoints require the Bearer token, including `GET /api/tags`. +Internal health and reachability checks run via the proxy treat any HTTP +response (including `401`) as proof the proxy is alive — they only fail +when nothing answers at all. + +If Ollama is already running on a non-loopback address when you start onboard, +the wizard restarts it on `127.0.0.1:11434` so the proxy is the only network +path to the model server. + +### GPU Memory Cleanup + +When you switch away from Ollama, stop host services, or destroy an Ollama-backed sandbox, NemoClaw asks Ollama to unload currently loaded models from GPU memory. +The cleanup sends `keep_alive: 0` for each model reported by Ollama and runs on a best-effort basis, so shutdown continues if Ollama is already stopped. +This does not delete downloaded model files. + +### Non-Interactive Setup + +```console +$ NEMOCLAW_PROVIDER=ollama \ + NEMOCLAW_MODEL=qwen2.5:14b \ + nemoclaw onboard --non-interactive --yes +``` + +If `NEMOCLAW_MODEL` is not set, NemoClaw selects a default model based on available memory. + +`--yes` (or `NEMOCLAW_YES=1`) authorises the Ollama model download without an interactive confirmation prompt. +Under `--non-interactive`, `--yes` (or `NEMOCLAW_YES=1`) is required to authorise the download — onboard exits otherwise, since it cannot prompt. +Run onboard without `--non-interactive` to get the interactive `[y/N]` prompt that shows the model size before downloading. + +| Variable | Purpose | +|---|---| +| `NEMOCLAW_PROVIDER` | Set to `ollama`. | +| `NEMOCLAW_MODEL` | Ollama model tag to use. Optional. | +| `NEMOCLAW_YES` | Set to `1` to auto-accept the model-download confirmation prompt. Optional. | + +## OpenAI-Compatible Server + +This option works with any server that implements `/v1/chat/completions`, including vLLM, TensorRT-LLM, llama.cpp, LocalAI, and others. +For compatible endpoints, NemoClaw uses `/v1/chat/completions` by default. +This avoids a class of failures where local backends accept `/v1/responses` requests but silently drop the system prompt and tool definitions. +To opt in to `/v1/responses`, set `NEMOCLAW_PREFERRED_API=openai-responses` before running onboard. + +Start your model server. +The examples below use vLLM, but any OpenAI-compatible server works. + +```console +$ vllm serve meta-llama/Llama-3.1-8B-Instruct --port 8000 +``` + +Run the onboard wizard. + +```console +$ nemoclaw onboard +``` + +When the wizard asks you to choose an inference provider, select **Other OpenAI-compatible endpoint**. +Enter the base URL of your local server, for example `http://localhost:8000/v1`. + +The wizard prompts for an API key. +If your server does not require authentication, enter any non-empty string (for example, `dummy`). + +NemoClaw validates the endpoint by sending a test inference request before continuing. +The wizard probes `/v1/chat/completions` by default for the compatible-endpoint provider. +If you set `NEMOCLAW_PREFERRED_API=openai-responses`, NemoClaw probes `/v1/responses` instead and only selects it when the response includes the streaming events OpenClaw requires. +If a reasoning model returns only reasoning content before producing a final answer, NemoClaw retries the smoke request with a larger response budget. +Route, configuration, and authentication failures still fail immediately. + +### Non-Interactive Setup + +Set the following environment variables for scripted or CI/CD deployments. + +```console +$ NEMOCLAW_PROVIDER=custom \ + NEMOCLAW_ENDPOINT_URL=http://localhost:8000/v1 \ + NEMOCLAW_MODEL=meta-llama/Llama-3.1-8B-Instruct \ + COMPATIBLE_API_KEY=dummy \ + nemoclaw onboard --non-interactive +``` + +| Variable | Purpose | +|---|---| +| `NEMOCLAW_PROVIDER` | Set to `custom` for an OpenAI-compatible endpoint. | +| `NEMOCLAW_ENDPOINT_URL` | Base URL of the local server. | +| `NEMOCLAW_MODEL` | Model ID as reported by the server. | +| `COMPATIBLE_API_KEY` | API key for the endpoint. Use any non-empty value if authentication is not required. | + +### Selecting the API Path + +For the compatible-endpoint provider, `/v1/chat/completions` is the default. +NemoClaw tests streaming events during onboarding and uses chat completions +without probing the Responses API. + +To opt in to `/v1/responses`, set `NEMOCLAW_PREFERRED_API` before running onboard: + +```console +$ NEMOCLAW_PREFERRED_API=openai-responses nemoclaw onboard +``` + +The wizard then probes `/v1/responses` and only selects it when streaming +support is complete. +If the probe fails, the wizard falls back to `/v1/chat/completions` +automatically. +You can use this variable in both interactive and non-interactive mode. + +| Variable | Values | Default | +|---|---|---| +| `NEMOCLAW_PREFERRED_API` | `openai-completions`, `openai-responses` | `openai-completions` for compatible endpoints | + +If you already onboarded and the sandbox is failing at runtime, re-run +`nemoclaw onboard` to re-probe the endpoint and bake the correct API path +into the image. +Refer to [Switch Inference Models](/inference/switch-inference-providers) for details. + +## Anthropic-Compatible Server + +If your local server implements the Anthropic Messages API (`/v1/messages`), choose **Other Anthropic-compatible endpoint** during onboarding instead. + +```console +$ nemoclaw onboard +``` + +For non-interactive setup, use `NEMOCLAW_PROVIDER=anthropicCompatible` and set `COMPATIBLE_ANTHROPIC_API_KEY`. + +```console +$ NEMOCLAW_PROVIDER=anthropicCompatible \ + NEMOCLAW_ENDPOINT_URL=http://localhost:8080 \ + NEMOCLAW_MODEL=my-model \ + COMPATIBLE_ANTHROPIC_API_KEY=dummy \ + nemoclaw onboard --non-interactive +``` + +## vLLM (Experimental) + +When vLLM is already running on `localhost:8000`, NemoClaw can detect it automatically and query the `/v1/models` endpoint to determine the loaded model. +On supported Linux hosts with NVIDIA GPUs, the onboard wizard can also install or start a managed vLLM container for you. + +For an already-running vLLM server, run `nemoclaw onboard` and select **Local vLLM [experimental]** from the provider list. + +```console +$ nemoclaw onboard +``` + +If vLLM is already running, NemoClaw detects the running model and validates the endpoint. +If vLLM is not running and your host matches a managed profile, set `NEMOCLAW_EXPERIMENTAL=1`, rerun `nemoclaw onboard`, and select the **Install vLLM** or **Start vLLM** entry. +NemoClaw pulls the vLLM image, downloads model weights into `~/.cache/huggingface`, starts the `nemoclaw-vllm` container on `localhost:8000`, and prints progress markers while the model loads. +The first run can take 10 to 30 minutes. +Later runs reuse the cached image and model weights. + +Managed vLLM uses these profiles: + +| Host profile | Default model | +|---|---| +| DGX Spark | `Qwen/Qwen3.6-27B-FP8` | +| DGX Station | `Qwen/Qwen3.6-27B-FP8` | +| Linux with an NVIDIA GPU | `nvidia/NVIDIA-Nemotron-3-Nano-4B-FP8` | + + +NemoClaw forces the `chat/completions` API path for vLLM. +The vLLM `/v1/responses` endpoint does not run the `--tool-call-parser`, so tool calls arrive as raw text. + + +### Non-Interactive Setup + +Use an already-running vLLM server: + +```console +$ NEMOCLAW_PROVIDER=vllm \ + nemoclaw onboard --non-interactive +``` + +Install or start managed vLLM when a supported profile is detected: + +```console +$ NEMOCLAW_EXPERIMENTAL=1 \ + NEMOCLAW_PROVIDER=install-vllm \ + nemoclaw onboard --non-interactive +``` + +NemoClaw records the model returned by vLLM's `/v1/models` endpoint. +Start vLLM with the model you want before onboarding if you manage the server yourself. + +## NVIDIA NIM (Experimental) + +NemoClaw can pull, start, and manage a NIM container on hosts with a NIM-capable NVIDIA GPU. + +Set the experimental flag and run onboard. + +```console +$ NEMOCLAW_EXPERIMENTAL=1 nemoclaw onboard +``` + +Select **Local NVIDIA NIM [experimental]** from the provider list. +NemoClaw filters available models by GPU VRAM, pulls the NIM container image, starts it, and waits for it to become healthy before continuing. +On hosts with mixed NVIDIA GPU models, the preflight summary shows each detected GPU model and the total VRAM so you can confirm which device class the model selection used. + +NIM container images are hosted on `nvcr.io` and require NGC registry authentication before `docker pull` succeeds. +If Docker is not already logged in to `nvcr.io`, onboard prompts for an [NGC API key](https://org.ngc.nvidia.com/setup/api-key) and runs `docker login nvcr.io` over `--password-stdin` so the key is never written to disk or shell history. +The prompt masks the key during input and retries once on a bad key before failing. +In non-interactive mode, onboard exits with login instructions if Docker is not already authenticated; run `docker login nvcr.io` yourself, then re-run `nemoclaw onboard --non-interactive`. +If `NGC_API_KEY` or `NVIDIA_API_KEY` is already exported, NemoClaw passes it into the managed NIM container through the process environment instead of command-line arguments. +If the NIM container exits before the health endpoint becomes ready, onboarding stops early and prints the last container log lines. + + +NIM uses vLLM internally. +The same `chat/completions` API path restriction applies. + + +### Non-Interactive Setup + +```console +$ NEMOCLAW_EXPERIMENTAL=1 \ + NEMOCLAW_PROVIDER=nim \ + nemoclaw onboard --non-interactive +``` + +To select a specific model, set `NEMOCLAW_MODEL`. + +## Timeout Configuration + +Local inference requests use a default timeout of 180 seconds. +Large prompts on hardware such as DGX Spark can exceed shorter timeouts, so NemoClaw sets a higher default for Ollama, vLLM, NIM, and compatible-endpoint setup. + +To override the timeout, set the `NEMOCLAW_LOCAL_INFERENCE_TIMEOUT` environment variable before onboarding: + +```console +$ export NEMOCLAW_LOCAL_INFERENCE_TIMEOUT=300 +$ nemoclaw onboard +``` + +The value is in seconds. +This setting is baked into the sandbox at build time. +Changing it after onboarding requires re-running `nemoclaw onboard`. + +`NEMOCLAW_LOCAL_INFERENCE_TIMEOUT` only governs the inference-server validation probe. +The post-create readiness wait (image build, gateway upload, in-sandbox boot) has its own budget, `NEMOCLAW_SANDBOX_READY_TIMEOUT`, also defaulting to 180 seconds. +On hosts where the sandbox image takes minutes to build or upload — large quantised models, DGX Station first runs, or remote VMs over a slow link — raise both together: + +```console +$ export NEMOCLAW_LOCAL_INFERENCE_TIMEOUT=300 +$ export NEMOCLAW_SANDBOX_READY_TIMEOUT=600 +$ nemoclaw onboard +``` + +If onboard ends with `Sandbox '' was created but did not become ready within 180s`, refer to [Troubleshooting](/reference/troubleshooting#sandbox-onboard-times-out-with-did-not-become-ready-within-ns). + +## Verify the Configuration + +After onboarding completes, confirm the active provider and model. + +```console +$ nemoclaw status +``` + +The output shows the provider label (for example, "Local vLLM" or "Other OpenAI-compatible endpoint") and the active model. +For Local Ollama, status also checks the authenticated proxy when a proxy token is available. +If `Inference` is healthy but `Inference (auth proxy)` is not, rerun onboarding to repair the proxy path that sandbox requests use. + +## Switch Models at Runtime + +You can change the model without re-running onboard. +Refer to [Switch Inference Models](/inference/switch-inference-providers) for the full procedure. + +For compatible endpoints, the command is: + +```console +$ nemoclaw inference set --provider compatible-endpoint --model +``` + +If the provider itself needs to change (for example, switching from vLLM to a cloud API), pass the new provider to `nemoclaw inference set`. + +## Next Steps + +- [Inference Options](/inference/inference-options) for the full list of providers available during onboarding. +- [Tool-Calling Reliability](/inference/tool-calling-reliability) for diagnosing raw JSON tool-call output with local models. +- [Switch Inference Models](/inference/switch-inference-providers) for runtime model switching. +- [Quickstart](/get-started/quickstart) for first-time installation. diff --git a/docs/manage-sandboxes/backup-restore.mdx b/docs/manage-sandboxes/backup-restore.mdx new file mode 100644 index 0000000000..19d72f6c69 --- /dev/null +++ b/docs/manage-sandboxes/backup-restore.mdx @@ -0,0 +1,167 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Backup and Restore Workspace Files" +sidebar-title: "Backup and Restore" +description: "How to back up and restore OpenClaw workspace files before destructive operations." +description-agent: "Backs up and restores OpenClaw workspace files before destructive operations such as sandbox rebuilds. Use when downloading workspace files from a sandbox, uploading restored files into a new sandbox, or preserving sandbox state across rebuilds." +keywords: ["nemoclaw backup", "nemoclaw restore", "workspace backup", "openshell sandbox download upload"] +content: + type: "how_to" +skill: + priority: 20 +--- +Workspace files define your agent's personality, memory, and user context. +They persist across sandbox restarts but are **permanently deleted** when you run `nemoclaw destroy`. + +This guide covers snapshot commands, manual backup with CLI commands, and an automated script. + +## When to Back Up + +- **Before running `nemoclaw destroy`** +- Before major NemoClaw version upgrades +- Periodically, if you've invested time customizing your agent + +## Snapshot Commands + +The fastest way to back up and restore sandbox state is with the built-in snapshot commands. +Snapshots capture all workspace state directories defined in the agent manifest and store them in `~/.nemoclaw/rebuild-backups//`. +Agent manifests may also declare durable top-level state files. For Hermes, +snapshots include `SOUL.md` and the SQLite database behind `.hermes/state.db` +using SQLite's online backup API, then restore that database through SQLite +instead of copying a live raw database file. +Treat snapshot directories as private local data: the Hermes database can +contain session metadata and message history needed for a faithful restore. + +```console +$ nemoclaw my-assistant snapshot create +$ nemoclaw my-assistant snapshot list +$ nemoclaw my-assistant snapshot restore +``` + +`snapshot list` prints a table of version, name, timestamp, and path. Versions (`v1`, `v2`, ..., `vN`) are computed from the timestamp order, so `vN` is always the newest snapshot. + +To tag a snapshot with a human-readable label, pass `--name`: + +```console +$ nemoclaw my-assistant snapshot create --name before-upgrade +``` + +To restore a specific snapshot instead of the latest, pass a version, name, or timestamp prefix: + +```console +$ nemoclaw my-assistant snapshot restore v3 +$ nemoclaw my-assistant snapshot restore before-upgrade +$ nemoclaw my-assistant snapshot restore 2026-04-14T +``` + +The `nemoclaw rebuild` command uses the same snapshot mechanism automatically. +Snapshot restore performs a targeted repair for legacy `.openclaw-data` symlinks that were created by older images. +Unsafe symlinks and hard links inside sandbox state are rejected during backup creation before they can enter a snapshot. +Credential-bearing Hermes files such as `auth.json` are intentionally excluded +from snapshots. NemoClaw-regenerated Hermes config files (`config.yaml` and +`.env`) are also excluded; model/provider and messaging credentials are +recreated from host-side onboarding and OpenShell provider state during rebuild. +For full details, see the [Commands reference](/reference/commands). + +## Manual Backup + +Use `openshell sandbox download` to copy files from the sandbox to your host. + +```console +$ SANDBOX=my-assistant +$ BACKUP_DIR=~/.nemoclaw/backups/$(date +%Y%m%d-%H%M%S) +$ mkdir -p "$BACKUP_DIR" + +$ openshell sandbox download "$SANDBOX" /sandbox/.openclaw/workspace/SOUL.md "$BACKUP_DIR/" +$ openshell sandbox download "$SANDBOX" /sandbox/.openclaw/workspace/USER.md "$BACKUP_DIR/" +$ openshell sandbox download "$SANDBOX" /sandbox/.openclaw/workspace/IDENTITY.md "$BACKUP_DIR/" +$ openshell sandbox download "$SANDBOX" /sandbox/.openclaw/workspace/AGENTS.md "$BACKUP_DIR/" +$ openshell sandbox download "$SANDBOX" /sandbox/.openclaw/workspace/MEMORY.md "$BACKUP_DIR/" +$ openshell sandbox download "$SANDBOX" /sandbox/.openclaw/workspace/memory/ "$BACKUP_DIR/memory/" +``` + +## Manual Restore + +Use `openshell sandbox upload` to push files back into a sandbox. + +```console +$ SANDBOX=my-assistant +$ BACKUP_DIR=~/.nemoclaw/backups/20260320-120000 # pick a timestamp + +$ openshell sandbox upload "$SANDBOX" "$BACKUP_DIR/SOUL.md" /sandbox/.openclaw/workspace/ +$ openshell sandbox upload "$SANDBOX" "$BACKUP_DIR/USER.md" /sandbox/.openclaw/workspace/ +$ openshell sandbox upload "$SANDBOX" "$BACKUP_DIR/IDENTITY.md" /sandbox/.openclaw/workspace/ +$ openshell sandbox upload "$SANDBOX" "$BACKUP_DIR/AGENTS.md" /sandbox/.openclaw/workspace/ +$ openshell sandbox upload "$SANDBOX" "$BACKUP_DIR/MEMORY.md" /sandbox/.openclaw/workspace/ +$ openshell sandbox upload "$SANDBOX" "$BACKUP_DIR/memory/" /sandbox/.openclaw/workspace/memory/ +``` + +## Using the Backup Script + +The repository includes a convenience script at `scripts/backup-workspace.sh`. + +### Backup + +```console +$ ./scripts/backup-workspace.sh backup my-assistant +Backing up workspace from sandbox 'my-assistant'... +Backup saved to /home/user/.nemoclaw/backups/20260320-120000/ (6 items) +``` + +### Restore + +Restore from the most recent backup: + +```console +$ ./scripts/backup-workspace.sh restore my-assistant +``` + +Restore from a specific timestamp: + +```console +$ ./scripts/backup-workspace.sh restore my-assistant 20260320-120000 +``` + +## Verifying a Backup + +List backed-up files to confirm completeness: + +```console +$ ls -la ~/.nemoclaw/backups/20260320-120000/ +AGENTS.md +IDENTITY.md +MEMORY.md +SOUL.md +USER.md +memory/ +``` + +## Multi-Agent Deployments + +When OpenClaw is configured with multiple named agents, each agent has its own +workspace directory (`workspace-main/`, `workspace-support/`, `workspace-ops/`, +and so on — see [Multi-Agent Deployments](/manage-sandboxes/workspace-files#multi-agent-deployments)). + +`nemoclaw snapshot create` automatically discovers every `workspace-*/` +directory under the sandbox state tree and includes it in the snapshot bundle +alongside the default `workspace/`. `snapshot restore` re-applies the full +per-agent set. No manual per-workspace backup pattern is needed. + +The sandbox entrypoint ensures every per-agent workspace lives directly under +the persistent `.openclaw/` tree, so state also survives `openshell sandbox restart`. + +### Shared files across agents + +Files that operators typically want consistent across every per-agent workspace +(`AGENTS.md`, shared skills, common templates) are **not** synced automatically. +Each workspace is independent; changes in one don't propagate. Operators that +need this either copy the shared files explicitly to each workspace after +editing, or maintain a host-side sync layer. Tracking shared-file tooling +(shared mount, `workspaces list` command) in +[#1260](https://github.com/NVIDIA/NemoClaw/issues/1260). + +## Next Steps + +- [Workspace Files overview](/manage-sandboxes/workspace-files) to learn what each file does +- [Commands reference](/reference/commands) diff --git a/docs/manage-sandboxes/lifecycle.mdx b/docs/manage-sandboxes/lifecycle.mdx new file mode 100644 index 0000000000..cea058b104 --- /dev/null +++ b/docs/manage-sandboxes/lifecycle.mdx @@ -0,0 +1,275 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Manage Sandbox Lifecycle" +sidebar-title: "Manage Sandbox Lifecycle" +description: "List sandboxes, check health, inspect logs, manage dashboard ports, reconfigure providers, rebuild safely, upgrade sandboxes, and uninstall NemoClaw." +description-agent: "Explains operational tasks after the quickstart: listing sandboxes, status and health checks, logs, diagnostics, port forwards, multiple sandboxes, credential reset, rebuilds, network presets, upgrades, and uninstall." +keywords: ["manage nemoclaw sandboxes", "nemoclaw status", "nemoclaw list", "nemoclaw dashboard port", "nemoclaw rebuild", "nemoclaw upgrade sandboxes", "nemoclaw uninstall"] +content: + type: "how_to" +skill: + priority: 10 +--- +Use this guide after you finish the [OpenClaw quickstart](/get-started/quickstart). +It covers day-two sandbox operations such as listing sandboxes, checking health, managing ports, rebuilding safely, upgrading, and uninstalling. +When a workflow uses the lower-level OpenShell CLI, see [CLI Selection Guide](/reference/cli-selection-guide) for the boundary between `nemoclaw` and `openshell`. + +## List Sandboxes + +List every sandbox registered on this host: + +```console +$ nemoclaw list +``` + +The list shows each sandbox's model, provider, policy presets, active SSH session indicator, and dashboard URL when a dashboard port is recorded. +Use JSON output for scripts: + +```console +$ nemoclaw list --json +``` + +## Check Sandbox Health + +Check a specific sandbox's health, inference route, active connections, live policy, update status, and messaging-channel overlap warnings: + +```console +$ nemoclaw my-assistant status +``` + +Use the host-level status command when you want the sandbox inventory plus host auxiliary service state, such as cloudflared: + +```console +$ nemoclaw status +``` + +## Inspect Logs + +View recent sandbox logs: + +```console +$ nemoclaw my-assistant logs +``` + +Stream logs while you reproduce a problem: + +```console +$ nemoclaw my-assistant logs --follow +``` + +The log command reads both OpenClaw gateway output and OpenShell audit events, so policy denials appear beside gateway logs. + +## Collect Diagnostics + +Collect diagnostics for bug reports or support handoff: + +```console +$ nemoclaw debug --sandbox my-assistant --output nemoclaw-debug.tar.gz +``` + +Use `--quick` for a smaller local summary: + +```console +$ nemoclaw debug --quick --sandbox my-assistant +``` + +The debug command gathers system information, Docker state, gateway logs, and sandbox status. + +## Manage Dashboard Ports + +If the forward stopped, or the installer reported that no active forward was found and the URL does not load, restart it manually with the port from the install summary. + +```console +$ openshell forward start --background my-gpt-claw +``` + +To list active forwards across all sandboxes, run the following command. + +```console +$ openshell forward list +``` + +## Run Multiple Sandboxes + +Each sandbox needs its own dashboard port, since `openshell forward` refuses to bind a port that another sandbox is already using. +When the default port is already held by another sandbox, `nemoclaw onboard` scans ports `18789` through `18799` and uses the next free port. + +```console +$ nemoclaw onboard # first sandbox uses 18789 +$ nemoclaw onboard # second sandbox uses the next free port, such as 18790 +``` + +To choose a specific port, pass `--control-ui-port`: + +```console +$ nemoclaw onboard --control-ui-port 19000 +``` + +You can also set `CHAT_UI_URL` or `NEMOCLAW_DASHBOARD_PORT` before onboarding: + +```console +$ CHAT_UI_URL=http://127.0.0.1:19000 nemoclaw onboard +$ NEMOCLAW_DASHBOARD_PORT=19000 nemoclaw onboard +``` + +For full details on port conflicts and overrides, refer to [Port already in use](/reference/troubleshooting#port-already-in-use). + +## Reconfigure or Recover + +Recover from a misconfigured sandbox without re-running the full onboard wizard or destroying workspace state. + +### Change Inference Model or API + +Change the active model or provider at runtime without rebuilding the sandbox: + +```console +$ nemoclaw inference set --model --provider +``` + +Refer to [Switch Inference Providers](/inference/switch-inference-providers) for provider-specific model IDs and API compatibility notes. + +### Restart the Gateway and Port Forward + +If `nemoclaw status` reports the sandbox is alive but the gateway is not running, run the recover command instead of opening a shell. + +```console +$ nemoclaw recover +``` + +The command restarts the in-sandbox gateway and re-establishes the dashboard port-forward in one step. +It is idempotent and safe to script. +Refer to [`nemoclaw recover`](/reference/commands#nemoclaw-name-recover) for details. + +### Reset a Stored Credential + +If a provider credential was entered incorrectly during onboarding, clear the gateway-registered value and re-enter it on the next onboard run: + +```console +$ nemoclaw credentials list # see which providers are registered +$ nemoclaw credentials reset # clear a single provider, for example nvidia-prod +$ nemoclaw onboard # re-run to re-enter the cleared provider +``` + +The credentials command is documented in full at [`nemoclaw credentials reset `](/reference/commands#nemoclaw-credentials-reset-provider). + +### Rebuild a Sandbox While Preserving Workspace State + +If you changed the underlying Dockerfile, upgraded OpenClaw, or want to pick up a new base image without losing your sandbox's workspace files, use `rebuild` instead of destroying and recreating: + +```console +$ nemoclaw rebuild +``` + +Rebuild preserves the mounted workspace and registered policies while recreating the container. +If NemoClaw cannot archive any requested state path, it reports the backup failure and stops before deleting the original sandbox. +Refer to [`nemoclaw rebuild`](/reference/commands#nemoclaw-name-rebuild) for flag details. + +### Add a Network Preset After Onboarding + +Apply an additional preset, such as Telegram or GitHub, to a running sandbox without re-onboarding: + +```console +$ nemoclaw policy-add +``` + +Refer to [`nemoclaw policy-add`](/reference/commands#nemoclaw-name-policy-add) for usage details and flags. + +Non-interactive re-onboards in the default `suggested` policy mode preserve presets added this way. +To make a re-onboard authoritative, set `NEMOCLAW_POLICY_MODE=custom` and provide `NEMOCLAW_POLICY_PRESETS` with the exact list to apply; onboarding removes anything else. +See [`NEMOCLAW_POLICY_MODE`](/reference/commands#nemoclaw-onboard) for the full table. + +## Update to the Latest Version + +When a new NemoClaw release becomes available, update the `nemoclaw` CLI on your host and check existing sandboxes for stale agent/runtime versions. + +### Update the NemoClaw CLI + +Re-run the installer. +Before it onboards anything, the installer calls [`nemoclaw backup-all`](/reference/commands#nemoclaw-backup-all) automatically, storing a snapshot of each running sandbox in `~/.nemoclaw/rebuild-backups/` as a safety net. +If your existing gateway is from OpenShell earlier than `0.0.37`, the installer prompts before it runs the new automatic gateway upgrade path. +The automatic path is offered only when the existing `nemoclaw` CLI supports `backup-all`; older installs must preserve sandbox state manually before retiring the gateway. +For unattended installs, set `NEMOCLAW_ACCEPT_EXPERIMENTAL_OPENSHELL_UPGRADE=1`, or manually run `nemoclaw backup-all` and `openshell gateway destroy -g nemoclaw || openshell gateway destroy` before rerunning the installer as `curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_OPENSHELL_UPGRADE_PREPARED=1 bash`. + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +### Upgrade Sandboxes with Stale Agent and Runtime Versions + +The installer checks registered sandboxes after onboarding succeeds and runs `nemoclaw upgrade-sandboxes --auto` for stale running sandboxes. +Use `upgrade-sandboxes` directly to verify the result, rebuild when you skipped the installer or onboarding step, or handle sandboxes that were stopped or could not be version-checked. +The upgrade flow is non-destructive by default because NemoClaw preserves manifest-defined workspace state, but a manual snapshot before any major upgrade gives you a state restore point. + +```console +$ nemoclaw snapshot create --name pre-upgrade # optional, recommended +$ nemoclaw update --yes # updates CLI through the maintained installer flow +$ nemoclaw upgrade-sandboxes --check # verify or list remaining stale/unknown sandboxes +$ nemoclaw upgrade-sandboxes # manually rebuild remaining stale running sandboxes +``` + +`nemoclaw update` is the CLI wrapper around the same installer path as `curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash`. +Use `nemoclaw update --check` when you only want to inspect version state and see the maintained update command. + +For scripted manual rebuilds, use `nemoclaw upgrade-sandboxes --auto` to skip the confirmation prompt. + +If the upgraded sandbox needs its workspace state reverted, restore the pre-upgrade snapshot into the running sandbox. +This restores saved state directories only; it does not downgrade the sandbox image or agent/runtime: + +```console +$ nemoclaw snapshot restore pre-upgrade +``` + +### What Changes During a Rebuild + +Each rebuild destroys the existing container and creates a new one. +NemoClaw protects your data through the same backup-and-restore flow as [`nemoclaw rebuild`](/reference/commands#nemoclaw-name-rebuild): + +- NemoClaw preserves manifest-defined workspace state. Before deleting the old container, NemoClaw snapshots the state directories and durable state files defined in the agent manifest, typically `/sandbox/.openclaw/workspace/`; for Hermes this also includes `SOUL.md` and the SQLite database behind `.hermes/state.db`. Stored credentials (`~/.nemoclaw/credentials.json`) and registered policy presets live on the host and are re-applied to the new sandbox automatically. +- NemoClaw does not preserve runtime changes outside the workspace state directories. This includes packages installed inside the running container with `apt` or `pip`, files in non-workspace paths, and in-memory or process state. If you have customized the running container at runtime, capture that as `Dockerfile` changes for `nemoclaw onboard --from` or a manual `openshell sandbox download` before the rebuild starts. + +Aborts before the destroy step are non-destructive. +The flow refuses to proceed past preflight if a credential is missing or past backup if required manifest-defined state cannot be copied, so a failed run leaves the original sandbox intact and ready to retry. +When a backup command reports partial archive output, NemoClaw keeps the usable entries and reports only the manifest-defined paths that could not be archived. + +See [Backup and Restore](/manage-sandboxes/backup-restore) for the full list of state-preservation guarantees, snapshot retention, and instructions for manual backups when the auto-flow is not enough. + + +The rebuild preflight reads the provider credential recorded by your last `nemoclaw onboard` session. +If you have switched providers since onboarding, for example from a remote API to a local Ollama setup, the preflight may still reference the old key and fail before any destroy step runs. + +To recover, re-run `nemoclaw onboard` and select your current provider. +This refreshes the session metadata. +Your existing container keeps serving traffic until the new image is ready. + + +## Uninstall + +To remove NemoClaw and all resources created during setup, run the CLI's built-in uninstall command: + +```bash +nemoclaw uninstall +``` + +| Flag | Effect | +|--------------------|------------------------------------------------------| +| `--yes` | Skip the confirmation prompt. | +| `--keep-openshell` | Leave OpenShell binaries installed. | +| `--delete-models` | Also remove NemoClaw-pulled Ollama models. | + +`nemoclaw uninstall` runs the version-pinned `uninstall.sh` that shipped with your installed CLI, so it does not fetch anything over the network at uninstall time. + +If the `nemoclaw` CLI is missing or broken, fall back to the hosted script: + +```bash +curl -fsSL https://raw.githubusercontent.com/NVIDIA/NemoClaw/refs/heads/main/uninstall.sh | bash +``` + +For a full comparison of the two forms, including what they fetch, what they trust, and when to prefer each, see [`nemoclaw uninstall` vs. the hosted `uninstall.sh`](/reference/commands#nemoclaw-uninstall-vs-the-hosted-uninstallsh). + +## Related Topics + +- [Set Up Messaging Channels](/manage-sandboxes/messaging-channels) to connect Telegram, Discord, or Slack. +- [Workspace Files](/manage-sandboxes/workspace-files) for persistent OpenClaw files inside the sandbox. +- [Backup and Restore](/manage-sandboxes/backup-restore) for snapshot and restore workflows. +- [Monitor Sandbox Activity](/monitoring/monitor-sandbox-activity) for observability tools. diff --git a/docs/manage-sandboxes/messaging-channels.mdx b/docs/manage-sandboxes/messaging-channels.mdx new file mode 100644 index 0000000000..075d5fd0ca --- /dev/null +++ b/docs/manage-sandboxes/messaging-channels.mdx @@ -0,0 +1,177 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Set Up Messaging Channels with NemoClaw and OpenShell" +sidebar-title: "Set Up Messaging Channels" +description: "Connect Telegram, Discord, or Slack to your sandboxed OpenClaw agent using OpenShell-managed channel messaging." +description-agent: "Explains how Telegram, Discord, and Slack reach the sandboxed OpenClaw agent through OpenShell-managed processes and NemoClaw channel commands. Use when setting up messaging channels, chat interfaces, or integrations without relying on nemoclaw tunnel start for bridges." +keywords: ["nemoclaw messaging channels", "nemoclaw telegram", "nemoclaw discord", "nemoclaw slack", "openshell channel messaging"] +content: + type: "how_to" +skill: + priority: 30 +--- +Telegram, Discord, and Slack reach your agent through OpenShell-managed processes and gateway constructs. +NemoClaw registers channel tokens with OpenShell providers, bakes the selected channel configuration into the sandbox image, and keeps runtime delivery under OpenShell control. + +You can enable channels during `nemoclaw onboard` or add them later with host-side `nemoclaw channels` commands. +Do not run `openclaw channels add` or `openclaw channels remove` inside the sandbox because `/sandbox/.openclaw/openclaw.json` is generated at image build time and changes inside the running container do not persist across rebuilds. + +`nemoclaw tunnel start` does not start Telegram, Discord, Slack, or other chat bridges. +It only starts optional host services such as the cloudflared tunnel when that binary is present. (`nemoclaw start` is kept as a deprecated alias.) +For details, refer to [Commands](/reference/commands). + +## Prerequisites + +- A machine where you can run `nemoclaw onboard` (local or remote host that runs the gateway and sandbox). +- A token for each messaging platform you want to enable. +- A network policy preset for each enabled channel, or equivalent custom egress rules. + +## Channel Requirements + +| Channel | Required tokens | Optional settings | +|---------|-----------------|-------------------| +| Telegram | `TELEGRAM_BOT_TOKEN` | `TELEGRAM_ALLOWED_IDS` for DM allowlisting, `TELEGRAM_REQUIRE_MENTION` for group-chat replies | +| Discord | `DISCORD_BOT_TOKEN` | `DISCORD_SERVER_ID`, `DISCORD_USER_ID`, `DISCORD_REQUIRE_MENTION` | +| Slack | `SLACK_BOT_TOKEN`, `SLACK_APP_TOKEN` | None | + +Telegram uses a bot token from [BotFather](https://t.me/BotFather). +Open Telegram, send `/newbot` to [@BotFather](https://t.me/BotFather), follow the prompts, and copy the token. +`TELEGRAM_ALLOWED_IDS` is a comma-separated list of Telegram user IDs for DM access. +Group chats stay open by default so rebuilt sandboxes do not silently drop Telegram group messages because of an empty group allowlist. +Set `TELEGRAM_REQUIRE_MENTION=1` to make the bot reply in Telegram groups only when users mention it. +Pairing and `TELEGRAM_ALLOWED_IDS` still govern direct messages. + +Discord uses a bot token from the Discord Developer Portal. +For server channels, enable Developer Mode in Discord, right-click the server, and copy the Server ID into `DISCORD_SERVER_ID`. +By default, NemoClaw configures the bot to reply only when mentioned. +Set `DISCORD_REQUIRE_MENTION=0` if you want it to reply to all messages in the configured server. +Set `DISCORD_USER_ID` to restrict access to one user; otherwise, any member of the configured server can message the bot. + +Slack uses Socket Mode and requires two tokens. +Use `SLACK_BOT_TOKEN` for the bot user OAuth token (`xoxb-...`) and `SLACK_APP_TOKEN` for the app-level Socket Mode token (`xapp-...`). + +## Enable Channels During Onboarding + +When the wizard reaches **Messaging channels**, it lists Telegram, Discord, and Slack. +Press a channel number to toggle it on or off, then press **Enter** when done. +If a token is not already in the environment or credential store, the wizard prompts for it and saves it. +NemoClaw also selects the matching network policy preset during policy setup so the channel can reach its provider API. + +For scripted setup, export the credentials and optional settings for the channels you want to enable before you run onboarding: + +```console +$ export TELEGRAM_BOT_TOKEN= +$ export TELEGRAM_REQUIRE_MENTION=1 +$ export DISCORD_BOT_TOKEN= +$ export DISCORD_SERVER_ID= +$ export SLACK_BOT_TOKEN= +$ export SLACK_APP_TOKEN= +``` + +Then run onboarding: + +```console +$ nemoclaw onboard +``` + +Complete the rest of the wizard so the blueprint can create OpenShell providers (for example `-telegram-bridge`), bake channel configuration into the image (`NEMOCLAW_MESSAGING_CHANNELS_B64`), and start the sandbox. + +## Add Channels After Onboarding + +Run channel commands from the host, not from inside the sandbox. +Use `channels list` to see the supported channel names: + +```console +$ nemoclaw my-assistant channels list +``` + +Add the channel you want: + +```console +$ nemoclaw my-assistant channels add telegram +$ nemoclaw my-assistant channels add discord +$ nemoclaw my-assistant channels add slack +``` + +`channels add` prompts for missing credentials, registers the bridge with the OpenShell gateway, updates the sandbox registry, and asks whether to rebuild immediately. +The command accepts mixed-case input such as `Telegram`, then stores and prints the canonical lowercase channel name. +If the matching built-in network policy preset exists but is not applied yet, the command prints a `policy-add ` hint after it registers the channel. +Choose the rebuild so the running sandbox image picks up the new channel. +If you need optional channel settings such as `TELEGRAM_ALLOWED_IDS`, `TELEGRAM_REQUIRE_MENTION`, `DISCORD_SERVER_ID`, `DISCORD_USER_ID`, or `DISCORD_REQUIRE_MENTION`, export them before the rebuild starts. +If you defer the rebuild, apply the change later: + +```console +$ nemoclaw my-assistant rebuild +``` + +In non-interactive mode, set the required environment variables before running `channels add`. +Missing credentials fail fast, and the command queues the change for a manual rebuild: + +```console +$ NEMOCLAW_NON_INTERACTIVE=1 TELEGRAM_BOT_TOKEN= \ + nemoclaw my-assistant channels add telegram +$ nemoclaw my-assistant rebuild +``` + +For Discord server access after onboarding, include the server settings when you add the channel and rebuild: + +```console +$ DISCORD_BOT_TOKEN= \ + DISCORD_SERVER_ID= \ + DISCORD_REQUIRE_MENTION=1 \ + nemoclaw my-assistant channels add discord +``` + +## Rotate or Remove Credentials + +Running `channels add` for a channel that is already configured overwrites the stored tokens and registers the updated bridge provider. +Rebuild the sandbox after the update so the image reflects the current channel set. + +To remove a channel and clear its stored credentials, run: + +```console +$ nemoclaw my-assistant channels remove telegram +``` + +Use `channels stop` when you want to pause a bridge without deleting credentials: + +```console +$ nemoclaw my-assistant channels stop telegram +$ nemoclaw my-assistant channels start telegram +``` + +Telegram, Discord, and Slack each allow only one active consumer per channel credential. +Multiple sandboxes can use the same channel type at the same time when each sandbox uses a distinct bot/app token. +For example, two Telegram sandboxes can DM the same `TELEGRAM_ALLOWED_IDS` account as long as they use different `TELEGRAM_BOT_TOKEN` values. +If you enable a messaging channel and another sandbox already uses the same token, onboarding prompts you to confirm before continuing in interactive mode and exits non-zero in non-interactive mode. +If NemoClaw only has legacy channel metadata and cannot compare credential hashes, it keeps the conservative warning; re-run `channels add ` with the intended token to refresh the stored non-secret hash. +`nemoclaw status` reports cross-sandbox overlaps so you can resolve duplicates before messages start dropping. + +## Stop Messaging Delivery + +Use `channels stop` when you want to pause one bridge and keep the sandbox running. +Use `nemoclaw tunnel stop` or its deprecated alias `nemoclaw stop` when you want to stop host auxiliary services and also ask NemoClaw to stop the OpenClaw gateway inside the selected sandbox. +Stopping the in-sandbox gateway stops Telegram, Discord, and Slack polling for that sandbox until you restart the sandbox or gateway. + +## Confirm Delivery + +After the sandbox is running, send a message to the configured bot or app. +If delivery fails, use `openshell term` on the host, check gateway logs, and verify network policy allows the channel API. +Use the matching policy preset (`telegram`, `discord`, or `slack`) or review [Common Integration Policy Examples](/network-policy/integration-policy-examples). + +## Tunnel Command + +When the host has `cloudflared`, `nemoclaw tunnel start` starts a cloudflared tunnel that can expose the dashboard with a public URL. +`nemoclaw tunnel stop` stops the tunnel and asks NemoClaw to stop the in-sandbox gateway for the selected or default sandbox. +The older `nemoclaw start` still works as a deprecated alias. + +```console +$ nemoclaw tunnel start +``` + +## Related Topics + +- [Deploy NemoClaw to a Remote GPU Instance](/deployment/deploy-to-remote-gpu) for remote deployment with messaging. +- [Architecture](/reference/architecture) for how providers, the gateway, and the sandbox fit together. +- [Commands](/reference/commands) for `channels add`, `channels remove`, `channels start`, `channels stop`, `tunnel start`, `tunnel stop`, and `status`. diff --git a/docs/manage-sandboxes/runtime-controls.mdx b/docs/manage-sandboxes/runtime-controls.mdx new file mode 100644 index 0000000000..c779273ae2 --- /dev/null +++ b/docs/manage-sandboxes/runtime-controls.mdx @@ -0,0 +1,107 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Runtime Controls and Sandbox Mutability" +sidebar-title: "Runtime Controls" +description: "Consolidated reference for what you can change on a running NemoClaw sandbox, what requires rebuild or re-onboard, and the operator-only `shields up` / `shields down` / `shields status` commands." +description-agent: "Single page that answers 'what can I change at runtime vs. what requires a rebuild' for NemoClaw sandboxes, and documents the operator-only shields lockdown commands (shields up, shields down with timeout/reason/policy, shields status). Use when an operator needs to temporarily lower or restore the sandbox security posture, or when a user is trying to figure out whether a config change needs a rebuild." +keywords: ["nemoclaw shields", "shields up", "shields down", "shields status", "sandbox mutability", "sandbox runtime configuration", "sandbox lockdown"] +content: + type: "how_to" +skill: + priority: 10 +--- +This page is the single reference for two related operator questions about a running NemoClaw sandbox: + +1. *Which parts of my sandbox can I change while it is running, and which require a rebuild or re-onboard?* +2. *How do I temporarily lower or restore the sandbox security posture for an operator session?* + +The mutability table below answers question 1. +The shields commands answer question 2. + +## What you can change at runtime + +NemoClaw applies its security posture in three layers — what is baked into the sandbox image at onboard, what is hot-reloadable on the running sandbox, and what requires a rebuild or re-onboard. +The table below maps each commonly changed item to the layer that owns it and the command that changes it. + +| Item | When the change takes effect | How to change it | +|---|---|---| +| Inference provider (cloud, NVIDIA Endpoints, local Ollama / vLLM, compatible-endpoint, …) | Rebuild required (`openclaw.json` is locked at sandbox creation) | `nemoclaw rebuild` after picking a different provider via `nemoclaw inference set` | +| Inference model on the current provider | Rebuild required for OpenClaw; hot-reloadable for managed routers | `nemoclaw rebuild` (OpenClaw) or `nemoclaw inference set` (router-based) | +| Sub-agent (Hermes / OpenClaw / …) | Re-onboard required (the sub-agent and its workspace are baked at onboard) | `nemoclaw onboard --recreate-sandbox` | +| Network policy preset (slack, discord, telegram, brave, …) | Runtime — applies on the next request; rebuild only required if the preset adds bind-mounted secrets | `nemoclaw policy-add ` / `policy-remove ` | +| Network allow-list (custom hosts) | Runtime — picks up at next request | `openshell policy set` or interactive approval prompt at the gateway | +| Channel tokens (Slack / Discord / Telegram bot credentials) | Rebuild required (tokens are baked into the sandbox image at onboard so they never leave the host clear-text) | `nemoclaw channels add ` then accept the rebuild prompt | +| Channel enable/disable (turn a configured channel off without removing the token) | Rebuild required (`openclaw.json` is the source of truth at runtime, see #3453) | `nemoclaw channels stop ` then rebuild | +| Dashboard forward port | Runtime — port is re-resolved on next `connect` | `NEMOCLAW_DASHBOARD_PORT= nemoclaw connect` | +| Dashboard bind address (loopback vs all interfaces) | Runtime — applies on next `connect` | `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 nemoclaw connect` (see #3259) | +| Web search backend (Brave, Tavily, etc.) | Runtime via `web.backend` config flag; rebuild only if `web.fetchEnabled` flips | `nemoclaw config set --key web.backend --value tavily` | +| Filesystem layout (Landlock zones, read-only mounts, container caps) | **Locked at creation** — no runtime change | Re-onboard with `nemoclaw onboard --recreate-sandbox` | +| Sandbox name | **Locked at creation** | Re-onboard with a different `--name` | +| GPU passthrough enable / device selector | **Locked at creation** | Re-onboard with `--gpu` / `--sandbox-gpu-device` | +| Shields posture (locked ↔ default mutable) | Runtime (operator-only) | `nemoclaw shields up` / `shields down` — see the next section | +| Agents allow-list (`agents.list` in `openclaw.json`) | Runtime — hot-reloaded by OpenClaw on config change | Edit `openclaw.json` while shields are down | +| `openclaw.json` keys (general — model, agents.list, web.backend, channel config, etc.) | Mixed: locked under `shields up`, runtime-editable under `shields down`. Individual keys still follow the rebuild rules in the rows above (e.g. provider switch requires rebuild even after editing the JSON). | `nemoclaw shields down`, edit `/opt/nemoclaw/openclaw.json` inside the sandbox, then `nemoclaw shields up` | + +If a row above conflicts with what you observe, the runtime source of truth inside the sandbox is `/opt/nemoclaw/openclaw.json`; the host registry caches metadata but the image and OpenClaw read from the in-sandbox file. + +## Shields commands + +Shields are an operator-only switch that toggles the sandbox between its default mutable state and a locked-down posture. +The sandbox itself cannot raise or lower its own shields — every transition is initiated from the host so a compromised agent cannot escape its policy by editing config. + +Three commands manage the posture. +The commands are hidden from the standard `--help` output because they are operator workflows, not developer workflows; everything below documents the full surface. + +### `shields status` + +Print the current shields mode (`mutable_default`, `locked`, or `temporarily_unlocked`), the active policy preset, and any pending automatic restore timer. + +```console +$ nemoclaw my-assistant shields status +Shields: locked +Policy: strict +Auto-restore: not scheduled (use `shields down --timeout 10m` to schedule) +``` + +### `shields up` + +Raise shields: lock `openclaw.json` (and other mutable config files) against in-sandbox edits and apply the restrictive network policy that was captured the last time the sandbox was shielded. +This is the default expected state for a sandbox the operator has handed off to an agent. + +```console +$ nemoclaw my-assistant shields up +✓ Shields raised: config locked, restrictive policy applied +``` + +`shields up` takes no flags. +If no saved snapshot exists yet (a fresh sandbox), the snapshot is taken from the current state. + +### `shields down` + +Lower shields: unlock config and apply a permissive (or operator-named) network policy so the operator can edit `openclaw.json`, swap presets, or run interactive maintenance. + +```console +$ nemoclaw my-assistant shields down --timeout 10m --reason "rotating slack token" +✓ Shields lowered for 10m (policy: permissive); auto-restore at 14:32 UTC +``` + +| Flag | Default | Effect | +|---|---|---| +| `--timeout ` | *no auto-restore* | After the duration elapses, a detached host-side timer re-runs `shields up` automatically. Accepts `5m`, `30s`, `1h`, etc. | +| `--reason ` | *empty* | Recorded in the shields audit log on the host. Required by some org policies; recommended for any cross-team session. | +| `--policy ` | `permissive` | Apply this named policy preset while shields are down instead of the default permissive set. Use a tighter preset (e.g. `messaging-only`) when the maintenance window only needs a subset of egress. | + +The auto-restore timer is detached from the `shields down` invocation — closing your terminal does not cancel the restore. +If the timer process is killed before the deadline (e.g. host reboot), `shields status` will surface the inconsistency on the next check (see #3112 for the fail-open fix). + +## See also + +The mutability table above is a consolidated index of information that lives in more detail on per-topic pages: + +- [Manage Sandbox Lifecycle](/manage-sandboxes/lifecycle) — full rebuild / re-onboard / upgrade workflow. +- [Switch Inference Providers](/inference/switch-inference-providers) — the rebuild path for provider and model changes. +- [Customize Network Policy](/network-policy/customize-network-policy) and [Approve Network Requests](/network-policy/approve-network-requests) — runtime policy editing and operator approval flow. +- [Security Best Practices](/security/best-practices) — the per-attack-surface posture table that this page complements. +- [OpenClaw Security Controls](/security/openclaw-controls) — application-layer controls that operate independently of NemoClaw. +- [CLI Commands Reference](/reference/commands) — full flag surface for every `nemoclaw` command, including the env vars that affect runtime behavior. diff --git a/docs/manage-sandboxes/workspace-files.mdx b/docs/manage-sandboxes/workspace-files.mdx new file mode 100644 index 0000000000..5e099cb5c6 --- /dev/null +++ b/docs/manage-sandboxes/workspace-files.mdx @@ -0,0 +1,112 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Workspace Files" +sidebar-title: "Workspace Files" +description: "What workspace personality and configuration files are, where they live, and how they persist across sandbox restarts." +description-agent: "Explains what workspace personality and configuration files are, where they live, and how they persist across sandbox restarts. Use when users ask about `SOUL.md`, `USER.md`, `IDENTITY.md`, `AGENTS.md`, or other workspace files, or when preparing to back up or restore workspace state." +keywords: ["nemoclaw workspace files", "soul.md", "user.md", "identity.md", "agents.md", "sandbox persistence"] +content: + type: "concept" +--- +OpenClaw stores its personality, user context, and behavioral configuration in a set of Markdown files inside the sandbox. +These files live at `/sandbox/.openclaw/workspace/` and are collectively called **workspace files**. + +## File Reference + +| File | Purpose | +|---|---| +| `SOUL.md` | Defines the agent's persona, tone, and communication style. | +| `USER.md` | Stores information about the human the agent assists. | +| `IDENTITY.md` | Short identity card — name, language, emoji, creature type. | +| `AGENTS.md` | Behavioral rules, memory conventions, safety guidelines, and session workflow. | +| `MEMORY.md` | Curated long-term memory distilled from daily notes. | +| `memory/` | Directory of daily note files (`YYYY-MM-DD.md`) for session continuity. | + +## Where They Live + +All workspace files reside inside the sandbox filesystem: + +```text +/sandbox/.openclaw/workspace/ +├── AGENTS.md +├── IDENTITY.md +├── MEMORY.md +├── SOUL.md +├── USER.md +└── memory/ + ├── 2026-03-18.md + └── 2026-03-19.md +``` + +## Multi-Agent Deployments + +A single NemoClaw sandbox can host more than one OpenClaw agent. +When OpenClaw is configured with multiple named agents (e.g., a shared `main` agent +plus per-user agents for a Teams-integrated deployment), each agent gets its own +workspace directory alongside the default `workspace/`: + +```text +/sandbox/.openclaw/ +├── workspace/ # default agent (single-agent deployments) +├── workspace-main/ # named agent "main" +├── workspace-support/ # named agent "support" +└── workspace-ops/ # named agent "ops" +``` + +Each per-agent workspace contains the same Markdown file structure as the default +(`SOUL.md`, `USER.md`, `IDENTITY.md`, `AGENTS.md`, `MEMORY.md`, `memory/`). +Files are per-agent — changes in `workspace-main/AGENTS.md` are not visible to +`workspace-support/`. + +Persistence and snapshots are handled automatically for per-agent workspaces: +the sandbox entrypoint provisions each `workspace-/` directly under the +writable `.openclaw/` tree so state survives sandbox restart, and +`nemoclaw snapshot create` discovers every `workspace-/` directory +and includes it in the snapshot bundle alongside the default `workspace/`. + + +Files that operators typically want consistent across every agent workspace +(`AGENTS.md`, shared skills, common templates) are not synced automatically. +Each workspace is independent; changes in one don't propagate. Tracking +shared-file tooling (shared mount, `workspaces list` command) in +[#1260](https://github.com/NVIDIA/NemoClaw/issues/1260). + + +## Persistence Behavior + +Workspace files live in the sandbox's persistent state volume, not in the container image. +This means they survive normal container restarts, but they are deleted when you destroy the sandbox. + +### Preserved During Restart, Rebuild, and Upgrade + +Sandbox restarts preserve workspace files because the persistent state volume outlives individual container restarts. + +The `nemoclaw rebuild` command and the sandbox upgrade flow also preserve workspace state. +Before replacing the container, NemoClaw snapshots the workspace state directories and restores them into the rebuilt sandbox. +If NemoClaw cannot archive any requested state file or directory, it reports the backup failure and stops before replacing the sandbox. +It does not continue with a partial backup. + +### Deleted During Sandbox Destroy + +Running `nemoclaw destroy` deletes the sandbox and its persistent state volume. +Workspace files are removed from the sandbox unless you created a snapshot or backup first. + + +Back up your workspace files before running `nemoclaw destroy`. +See [Backup and Restore](/manage-sandboxes/backup-restore) for instructions. + + +## Editing Workspace Files + +The agent reads these files at the start of every session. +You can edit them in two ways: + +1. Ask your agent to update its persona, memory, or user context. +2. Use `nemoclaw connect` to open a terminal inside the sandbox and edit files directly, or use `openshell sandbox upload` to push edited files from your host. + +## Next Steps + +- [Set Up Task-Specific Sub-Agents](/inference/set-up-sub-agent) +- [Backup and Restore workspace files](/manage-sandboxes/backup-restore) +- [Commands reference](/reference/commands) diff --git a/docs/monitoring/monitor-sandbox-activity.mdx b/docs/monitoring/monitor-sandbox-activity.mdx new file mode 100644 index 0000000000..0c88bb525f --- /dev/null +++ b/docs/monitoring/monitor-sandbox-activity.mdx @@ -0,0 +1,96 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Monitor NemoClaw Sandbox Activity and Debug Issues" +sidebar-title: "Monitor Sandbox Activity" +description: "Inspect sandbox health, trace agent behavior, and diagnose problems." +description-agent: "Inspects sandbox health, traces agent behavior, and diagnoses problems. Use when monitoring a running sandbox, debugging agent issues, or checking sandbox logs." +keywords: ["monitor nemoclaw sandbox", "debug nemoclaw agent issues"] +content: + type: "how_to" +skill: + priority: 10 +--- +Use the NemoClaw status, logs, and TUI tools together to inspect sandbox health, trace agent behavior, and diagnose problems. + +## Prerequisites + +- A running NemoClaw sandbox. +- The OpenShell CLI on your `PATH`. + +## Check Sandbox Health + +Run the status command to view the sandbox state, gateway health, and active inference configuration: + +```console +$ nemoclaw status +``` + +For local Ollama and local vLLM routes, `nemoclaw status` also probes the host-side health endpoint directly. +This catches a stopped local backend before you retry `inference.local` from inside the sandbox. + +Key fields in the output include the following: + +- Sandbox details, which show the configured model, provider, GPU mode, and applied policy presets. +- Gateway and process health, which show whether NemoClaw can still reach the OpenShell gateway and whether the in-sandbox agent process is running. +- Inference health for local Ollama and local vLLM, which shows `healthy` or `unreachable` together with the probed local URL. +- NIM status, which shows whether a NIM container is running and healthy when that path is in use. + +Run `nemoclaw status` on the host to check sandbox state. +Use `openshell sandbox list` for the underlying sandbox details. + +## View Blueprint and Sandbox Logs + +Stream the most recent log output from the blueprint runner and sandbox: + +```console +$ nemoclaw logs +``` + +To follow the log output in real time: + +```console +$ nemoclaw logs --follow +``` + +## Monitor Network Activity in the TUI + +Open the OpenShell terminal UI for a live view of sandbox network activity and egress requests: + +```console +$ openshell term +``` + +For a remote sandbox, SSH to the instance and run `openshell term` there. + +The TUI shows the following information: + +- Active network connections from the sandbox. +- Blocked egress requests awaiting operator approval. +- Inference routing status. + +Refer to [Approve or Deny Agent Network Requests](/network-policy/approve-network-requests) for details on handling blocked requests. + +## Test Inference + +Run a test inference request to verify that the provider is responding: + +```console +$ nemoclaw my-assistant connect +$ openclaw agent --agent main --local -m "Test inference" --session-id debug +``` + +If the request fails, check the following: + +1. Run `nemoclaw status` to confirm the active provider and endpoint. + For local Ollama and local vLLM, check the `Inference` line first. + If it shows `unreachable`, restart the local backend before retrying from inside the sandbox. +2. Run `nemoclaw logs --follow` to view error messages from the blueprint runner. +3. Verify that the inference endpoint is reachable from the host. + +## Related Topics + +- [Troubleshooting](/reference/troubleshooting) for common issues and resolution steps. +- [Commands](/reference/commands) for the full CLI reference. +- [Approve or Deny Agent Network Requests](/network-policy/approve-network-requests) for the operator approval flow. +- [Switch Inference Providers](/inference/switch-inference-providers) to change the active provider. diff --git a/docs/network-policy/approve-network-requests.mdx b/docs/network-policy/approve-network-requests.mdx new file mode 100644 index 0000000000..ecb951a8b4 --- /dev/null +++ b/docs/network-policy/approve-network-requests.mdx @@ -0,0 +1,72 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Approve or Deny NemoClaw Agent Network Requests" +sidebar-title: "Approve Network Requests" +description: "Review and approve blocked agent network requests in the TUI." +description-agent: "Reviews and approves blocked agent network requests in the TUI. Use when approving or denying sandbox egress requests, managing blocked network calls, or using the approval TUI." +keywords: ["nemoclaw approve network requests", "sandbox egress approval tui"] +content: + type: "how_to" +skill: + priority: 20 +--- +Review and act on network requests that the agent makes to endpoints not listed in the sandbox policy. +OpenShell intercepts these requests and presents them in the TUI for operator approval. + +## Prerequisites + +- A running NemoClaw sandbox. +- The OpenShell CLI on your `PATH`. + +## Open the TUI + +Start the OpenShell terminal UI to monitor sandbox activity: + +```console +$ openshell term +``` + +For a remote sandbox, pass the instance name: + +```console +$ ssh my-gpu-box 'cd ~/nemoclaw && . .env && openshell term' +``` + +The TUI displays the sandbox state, active inference provider, and a live feed of network activity. + +## Trigger a Blocked Request + +When the agent attempts to reach an endpoint that is not in the baseline policy, OpenShell blocks the connection and displays the request in the TUI. +The blocked request includes the following details: + +- **Host and port** of the destination. +- **Binary** that initiated the request. +- **HTTP method** and path, if available. + +## Approve or Deny the Request + +The TUI presents an approval prompt for each blocked request. + +- **Approve** the request to add the endpoint to the running policy for the current session. +- **Deny** the request to keep the endpoint blocked. + +Approved endpoints remain in the running policy until the sandbox stops. +They are not persisted to the baseline policy file. + +## Run the Walkthrough + +To observe the approval flow in a guided session, run the walkthrough script: + +```console +$ ./scripts/walkthrough.sh +``` + +This script opens a split tmux session with the TUI on the left and the agent on the right. +The walkthrough requires tmux and the `NVIDIA_API_KEY` environment variable. + +## Related Topics + +- [Customize the Sandbox Network Policy](/network-policy/customize-network-policy) to add endpoints permanently. +- [Network Policies](/reference/network-policies) for the full baseline policy reference. +- [Monitor Sandbox Activity](/monitoring/monitor-sandbox-activity) for general sandbox monitoring. diff --git a/docs/network-policy/customize-network-policy.mdx b/docs/network-policy/customize-network-policy.mdx new file mode 100644 index 0000000000..e2b1e013e6 --- /dev/null +++ b/docs/network-policy/customize-network-policy.mdx @@ -0,0 +1,305 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Customize the NemoClaw Sandbox Network Policy" +sidebar-title: "Customize Network Policy" +description: "Add, remove, or modify allowed endpoints in the sandbox policy." +description-agent: "Adds, removes, or modifies allowed endpoints in the sandbox policy. Use when customizing network policy, changing egress rules, or configuring sandbox endpoint access." +keywords: ["customize nemoclaw network policy", "sandbox egress policy configuration"] +content: + type: "how_to" +skill: + priority: 10 +--- +Add, remove, or modify the endpoints that the sandbox is allowed to reach. + +The sandbox policy is defined in a declarative YAML file in the NemoClaw repository and enforced at runtime by [NVIDIA OpenShell](https://github.com/NVIDIA/OpenShell). +NemoClaw supports both static policy changes that persist across restarts and dynamic updates applied to a running sandbox through the OpenShell CLI. + + +If the sandbox needs to reach an HTTP service running on the host, expose the service on a host IP that the OpenShell gateway can reach. +Apply a custom NemoClaw preset with `nemoclaw policy-add --from-file`. +Do not rely on `host.docker.internal` as a general host-service path because it bypasses the OpenShell policy path and may not be reachable in every sandbox runtime. +See [Agent cannot reach a host-side HTTP service](/reference/troubleshooting#agent-cannot-reach-a-host-side-http-service). + + +## Prerequisites + +- A running NemoClaw sandbox for dynamic changes, or the NemoClaw source repository for static changes. +- The OpenShell CLI on your `PATH`. + +> [!IMPORTANT] +> Make static policy edits on the host, not inside the sandbox. +> The sandbox image includes a small set of operational tools such as `vi`, `jq`, and `dos2unix`, but host-side policy files remain the durable source of truth. +> Changes made only inside the sandbox are also ephemeral and are lost when the sandbox is recreated. + +## Static Changes + +Static changes modify the baseline policy file and take effect after the next sandbox creation. + +### Edit the Policy File + +Open `nemoclaw-blueprint/policies/openclaw-sandbox.yaml` and add or modify endpoint entries. + +If you only need one of the built-in presets, use `nemoclaw policy-add` instead of editing YAML by hand: + +```console +$ nemoclaw my-assistant policy-add +``` + +To remove a previously applied preset, use `nemoclaw policy-remove`: + +```console +$ nemoclaw my-assistant policy-remove +``` + +Use a manual YAML edit when you need to allow custom hosts that are not covered by a preset, such as an internal API or a weather service. + +Each entry in the `network` section defines an endpoint group with the following fields: + +`endpoints` +: Host and port pairs that the sandbox can reach. + +`binaries` +: Executables allowed to use this endpoint. + +`rules` +: HTTP methods and paths that are permitted. + +### Re-Run Onboard + +Apply the updated policy by re-running the onboard wizard: + +```console +$ nemoclaw onboard +``` + +The wizard picks up the modified policy file and applies it to the sandbox. + +### Verify the Policy + +Check that the sandbox is running with the updated policy: + +```console +$ nemoclaw status +``` + +### Add Blueprint Policy Additions + +If you maintain a custom blueprint, you can add extra policy entries under `components.policy.additions` in `nemoclaw-blueprint/blueprint.yaml`. +NemoClaw validates those entries with the same policy schema used by preset files, fetches the live policy during sandbox creation, merges the additions into `network_policies`, and applies the merged policy through OpenShell. +The applied additions are recorded in the run metadata so you can audit which blueprint-level policy entries were active for that sandbox run. + +## Dynamic Changes + +Dynamic changes apply a policy update to a running sandbox without restarting it. + +> [!WARNING] +> `openshell policy set` **replaces** the sandbox's live policy with the contents of the file you provide; it does not merge. +> A running sandbox's live policy is the baseline from `openclaw-sandbox.yaml` plus every preset that was layered on during onboarding. +> Applying a file that contains only the baseline (or only a single preset) silently drops every other preset that was in effect. + +### Option 1: Drop a Preset File and Use `policy-add` (Recommended) + +This is the non-destructive path and the only flow NemoClaw supports out of the box for merging new entries into a running policy. + +1. Create a preset-format YAML file under `nemoclaw-blueprint/policies/presets/`, for example `nemoclaw-blueprint/policies/presets/influxdb.yaml`: + + ```yaml + preset: + name: influxdb + description: "InfluxDB time-series database" + network_policies: + influxdb: + name: influxdb + endpoints: + - host: influxdb.internal.example.com + port: 8086 + protocol: rest + enforcement: enforce + rules: + - allow: { method: GET, path: "/**" } + - allow: { method: POST, path: "/api/v2/write" } + binaries: + - { path: /usr/bin/curl } + ``` + +2. Apply it to the running sandbox: + + ```console + $ nemoclaw my-assistant policy-add + ``` + + NemoClaw reads the live policy via `openshell policy get --full`, structurally merges your preset's `network_policies` into it, and writes the merged result back. + Existing presets and the baseline remain in place. + The preset file under `presets/` also persists across sandbox recreations. + +### Option 2: Snapshot, Edit, and Set via OpenShell + +Use this path only when you cannot add a file under the NemoClaw source tree. +You must start from the **live** policy, not from `openclaw-sandbox.yaml`, so the presets layered on at onboarding are preserved in the file you apply. + +```console +$ openshell policy get --full my-assistant > live-policy.yaml +``` + +Edit `live-policy.yaml` to add your entries under `network_policies:`, keeping the existing `version` field intact, then apply: + +```console +$ openshell policy set --policy live-policy.yaml my-assistant +``` + +### Scope of Dynamic Changes + +Dynamic changes apply only to the current session. +When the sandbox stops, the running policy resets to the baseline composed from `openclaw-sandbox.yaml` plus the presets recorded for the sandbox. +To make a custom policy survive a sandbox recreation, ship the preset file in the repository (Option 1 above — the file under `presets/` persists) or edit `openclaw-sandbox.yaml` and re-run `nemoclaw onboard`. + +### Approve Requests Interactively + +For one-off access, you can approve blocked requests in the OpenShell TUI instead of editing the baseline policy: + +```console +$ openshell term +``` + +This is useful when you want to test a destination before deciding whether it belongs in a permanent preset or custom policy file. + +## Policy Presets + +NemoClaw ships preset policy files for common integrations in `nemoclaw-blueprint/policies/presets/`. +Apply a preset as-is or use it as a starting template for a custom policy. +For guided post-install examples, see [Common Integration Policy Examples](/network-policy/integration-policy-examples). + +During onboarding, the [policy tier](/reference/network-policies#policy-tiers) you select determines which presets are enabled by default. +You can add or remove individual presets in the interactive preset screen that follows tier selection. + +Available presets: + +| Preset | Endpoints | +|--------|-----------| +| `brave` | Brave Search API | +| `brew` | Homebrew (Linuxbrew) package manager | +| `discord` | Discord API, gateway, and CDN access | +| `github` | GitHub and GitHub REST API | +| `huggingface` | Hugging Face Hub (download-only) and inference router | +| `jira` | Atlassian Jira API | +| `local-inference` | Local Ollama and vLLM through the host gateway | +| `npm` | npm and Yarn registries | +| `outlook` | Microsoft 365 and Outlook | +| `pypi` | Python Package Index | +| `slack` | Slack API and webhooks | +| `telegram` | Telegram Bot API | + +To apply a preset to a running sandbox: + +```console +$ nemoclaw policy-add +``` + + +Preset selection is interactive when you omit a preset name. +Pass a preset name with `--yes` for scripted workflows. + + +For example, to interactively add PyPI access to a running sandbox: + +```console +$ nemoclaw my-assistant policy-add +``` + +To list which presets are applied to a sandbox: + +```console +$ nemoclaw policy-list +``` + +To include a preset in the baseline, merge its entries into `openclaw-sandbox.yaml` and re-run `nemoclaw onboard`. + + +The `openshell policy set --policy ` command operates on raw policy files and does not +accept the `preset:` metadata block used in preset YAML files. Use `nemoclaw policy-add` for +presets. + + +For scripted workflows, `policy-add` and `policy-remove` accept the preset name as a positional argument: + +```console +$ nemoclaw my-assistant policy-add pypi --yes +$ nemoclaw my-assistant policy-remove pypi --yes +``` + +Set `NEMOCLAW_NON_INTERACTIVE=1` instead of `--yes` to drive the same flow from an environment variable. +See [Commands](/reference/commands#nemoclaw-name-policy-add) for the full flag reference. + +`nemoclaw rebuild` reapplies every policy preset to the recreated sandbox, so presets survive an agent-version upgrade without manual reapplication. + +## Custom Preset Files + +Apply a user-authored preset YAML to a running sandbox without editing the baseline or dropping to `openshell policy set`. + +### Authoring + +A custom preset follows the same shape as the built-in ones under `nemoclaw-blueprint/policies/presets/`: + +```yaml +preset: + name: my-internal-api + description: "Internal service" +network_policies: + my-internal-api: + name: my-internal-api + endpoints: + - host: api.example.internal + port: 443 + protocol: rest + enforcement: enforce + rules: + - allow: { method: GET, path: "/**" } + binaries: + - { path: /usr/local/bin/node } +``` + +The top-level `preset.name` must be a lowercase RFC 1123 label (letters, digits, hyphens) and must not collide with a built-in preset name such as `slack` or `pypi`. +Rename `preset.name` if NemoClaw refuses to apply the file because of a collision. + +### Apply a Single File + +```console +$ nemoclaw my-assistant policy-add --from-file ./presets/my-internal-api.yaml +``` + +Preview the endpoints without applying with `--dry-run`, and skip the confirmation prompt with `--yes` or by exporting `NEMOCLAW_NON_INTERACTIVE=1`. + +### Apply Every File in a Directory + +```console +$ nemoclaw my-assistant policy-add --from-dir ./presets/ --yes +``` + +Files are processed in lexicographic order. +Processing stops at the first failure; presets already applied are not rolled back. +Fix the failing file and re-run the command to continue. + + +Custom preset hosts bypass NemoClaw's review process and can widen sandbox egress to arbitrary destinations. +Review every host in a custom preset before applying it, especially when the file originates outside your team. + + +### Remove a Custom Preset + +Custom presets applied with `--from-file` or `--from-dir` are recorded in the NemoClaw sandbox registry alongside their full YAML content, so they can be removed by name — the original file does not need to be kept on disk: + +```console +$ nemoclaw my-assistant policy-remove my-internal-api --yes +``` + +`policy-remove` accepts both built-in and custom preset names. Run `nemoclaw policy-list` to see every preset currently applied to the sandbox. + +## Related Topics + +- [Approve or Deny Agent Network Requests](/network-policy/approve-network-requests) for real-time operator approval. +- [Common Integration Policy Examples](/network-policy/integration-policy-examples) for maintained preset examples such as Outlook, messaging, GitHub, Jira, Brave Search, package managers, Hugging Face, and local inference. +- [Network Policies](/reference/network-policies) for the full baseline policy reference. +- OpenShell [Policy Schema](https://docs.nvidia.com/openshell/latest/reference/policy-schema.html) for the full YAML policy schema reference. +- OpenShell [Sandbox Policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.html) for applying, iterating, and debugging policies at the OpenShell layer. diff --git a/docs/network-policy/integration-policy-examples.mdx b/docs/network-policy/integration-policy-examples.mdx new file mode 100644 index 0000000000..217dd20253 --- /dev/null +++ b/docs/network-policy/integration-policy-examples.mdx @@ -0,0 +1,274 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Common NemoClaw Integration Policy Examples" +sidebar-title: "Integration Policy Examples" +description: "Guided examples for adding post-install integration policy access to a NemoClaw sandbox." +description-agent: "Guides users through common post-install integration policy setup for maintained NemoClaw policy presets, including Outlook, messaging channels, GitHub, Jira, Brave Search, package managers, Hugging Face, local inference, and OpenShell approval workflows." +keywords: ["nemoclaw integration policy examples", "post-install policy setup", "openshell approval workflow", "policy preset"] +content: + type: "how_to" +skill: + priority: 15 +--- + +{/* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */} +{/* SPDX-License-Identifier: Apache-2.0 */} + +# Common NemoClaw Integration Policy Examples + +Use these examples when a sandbox is already installed and an integration needs network access. +This page covers only integrations that NemoClaw currently ships as maintained policy preset YAML under `nemoclaw-blueprint/policies/presets/`. +Integration setup usually has two separate parts: + +- Configure the integration itself, such as a bot token, OAuth credential, or agent plugin setting. +- Allow the sandbox to reach the integration's network endpoints through NemoClaw and OpenShell policy. + +Prefer NemoClaw commands for policy changes that should be tracked with the sandbox. +Use OpenShell directly when you need to inspect blocked requests or approve a one-off request in the TUI. + +## Before You Start + +Replace `my-assistant` with your sandbox name in the examples. + +Check the current policy state first: + +```console +$ nemoclaw my-assistant policy-list +``` + +For a live view of blocked requests, open the OpenShell TUI in a separate host terminal: + +```console +$ openshell term +``` + +When the agent reaches an endpoint that is not in policy, the TUI shows the host, port, requesting binary, method, and path when available. +Approve a request only when you understand why the integration needs it. +An approval updates the running policy, but it does not create a NemoClaw preset entry that can be reviewed and replayed like `policy-add`. + +## Supported Integration Presets + +NemoClaw ships maintained policy presets for common services in `nemoclaw-blueprint/policies/presets/`. + +| Workflow | Preset | +|----------|--------| +| Brave Search | `brave` | +| Homebrew packages | `brew` | +| Discord messaging | `discord` | +| GitHub and GitHub API | `github` | +| Hugging Face Hub and Inference API | `huggingface` | +| Jira and Atlassian Cloud | `jira` | +| Local Ollama or vLLM through the host gateway | `local-inference` | +| npm and Yarn packages | `npm` | +| Microsoft 365, Outlook, and Graph API | `outlook` | +| Python Package Index | `pypi` | +| Slack messaging | `slack` | +| Telegram Bot API | `telegram` | + +Preview the endpoints before applying: + +```console +$ nemoclaw my-assistant policy-add outlook --dry-run +``` + +Apply the preset: + +```console +$ nemoclaw my-assistant policy-add outlook --yes +``` + +Remove it later if the sandbox no longer needs that access: + +```console +$ nemoclaw my-assistant policy-remove outlook --yes +``` + +## Email and Calendar With Microsoft 365 + +Use the `outlook` preset for Microsoft 365 email and calendar workflows that use Microsoft Graph or Outlook endpoints. +The preset allows `graph.microsoft.com`, Microsoft login, and Outlook service endpoints. + +```console +$ nemoclaw my-assistant policy-add outlook --dry-run +$ nemoclaw my-assistant policy-add outlook --yes +``` + +Then configure the email or calendar tool credentials through the integration you are running in the sandbox. +Keep OAuth client secrets and refresh tokens out of policy files. + +If the tool still fails, run `openshell term`, trigger the workflow again, and inspect the blocked request. +If the blocked endpoint is not covered by the maintained `outlook` preset, treat it as a separate policy review instead of assuming it is part of the supported preset. + +## Telegram Bot Messaging + +Telegram needs both channel configuration and egress policy. +If you already enabled Telegram during onboarding but did not include the preset, add it to the running sandbox: + +```console +$ nemoclaw my-assistant policy-add telegram --yes +``` + +To add Telegram after onboarding, set the token on the host, add the channel, rebuild so the image picks up the channel config, and make sure the policy preset is applied: + +```console +$ export TELEGRAM_BOT_TOKEN= +$ NEMOCLAW_NON_INTERACTIVE=1 nemoclaw my-assistant channels add telegram +$ nemoclaw my-assistant rebuild +$ nemoclaw my-assistant policy-add telegram --yes +``` + +If delivery fails, open the TUI and send a test message to the bot: + +```console +$ openshell term +``` + +The matching preset for each supported messaging channel is the channel name (`telegram`, `discord`, or `slack`). + +## Slack or Discord Messaging + +Slack and Discord also need both channel configuration and egress policy. +Use the matching policy preset after you configure the channel credentials. + +For Slack: + +```console +$ export SLACK_BOT_TOKEN= +$ export SLACK_APP_TOKEN= +$ NEMOCLAW_NON_INTERACTIVE=1 nemoclaw my-assistant channels add slack +$ nemoclaw my-assistant rebuild +$ nemoclaw my-assistant policy-add slack --yes +``` + +For Discord: + +```console +$ export DISCORD_BOT_TOKEN= +$ export DISCORD_SERVER_ID= +$ NEMOCLAW_NON_INTERACTIVE=1 nemoclaw my-assistant channels add discord +$ nemoclaw my-assistant rebuild +$ nemoclaw my-assistant policy-add discord --yes +``` + +If you enabled Slack or Discord during onboarding, apply only the matching preset: + +```console +$ nemoclaw my-assistant policy-add slack --yes +$ nemoclaw my-assistant policy-add discord --yes +``` + +## GitHub and Jira + +Use `github` when the agent needs GitHub API or Git access. +Use `jira` when the agent needs Atlassian Jira access. + +Preview first: + +```console +$ nemoclaw my-assistant policy-add github --dry-run +$ nemoclaw my-assistant policy-add jira --dry-run +``` + +Apply the preset that matches the workflow: + +```console +$ nemoclaw my-assistant policy-add github --yes +$ nemoclaw my-assistant policy-add jira --yes +``` + +Remove access when the task is done: + +```console +$ nemoclaw my-assistant policy-remove github --yes +$ nemoclaw my-assistant policy-remove jira --yes +``` + +## Brave Search + +The default Balanced policy tier includes `brave`. +If you chose Restricted during onboarding or removed the preset later, add it before enabling Brave Search workflows: + +```console +$ nemoclaw my-assistant policy-add brave --dry-run +$ nemoclaw my-assistant policy-add brave --yes +``` + +The Brave Search API key is still configured separately during onboarding or through the web search setup flow. + +## Package and Model Tooling + +Use these presets when an agent workflow installs packages or downloads model assets: + +| Workflow | Preset | +|----------|--------| +| npm or Yarn packages | `npm` | +| Python packages from PyPI | `pypi` | +| Homebrew packages | `brew` | +| Hugging Face model or dataset access | `huggingface` | + +Add only the preset required for the task: + +```console +$ nemoclaw my-assistant policy-add npm --yes +$ nemoclaw my-assistant policy-add pypi --yes +$ nemoclaw my-assistant policy-add brew --yes +$ nemoclaw my-assistant policy-add huggingface --yes +``` + +Remove package access after a one-time setup task if the sandbox no longer needs it: + +```console +$ nemoclaw my-assistant policy-remove npm --yes +$ nemoclaw my-assistant policy-remove pypi --yes +$ nemoclaw my-assistant policy-remove brew --yes +$ nemoclaw my-assistant policy-remove huggingface --yes +``` + +## Local Inference + +Use `local-inference` when the sandbox needs access to host-side local inference services such as Ollama or vLLM through the OpenShell host gateway. +Onboarding auto-suggests this preset when you choose a local provider. +If you need to add it after onboarding: + +```console +$ nemoclaw my-assistant policy-add local-inference --dry-run +$ nemoclaw my-assistant policy-add local-inference --yes +``` + +Then verify the sandbox status: + +```console +$ nemoclaw my-assistant status +``` + +## Inspect or Replace the Live Policy + +Use `policy-list` for normal preset state: + +```console +$ nemoclaw my-assistant policy-list +``` + +Use OpenShell when you need the full enforced YAML: + +```console +$ openshell policy get --full my-assistant > live-policy.yaml +``` + +If you must replace the live policy, edit the full policy file and set it back: + +```console +$ openshell policy set --policy live-policy.yaml my-assistant --wait +``` + +`openshell policy set` replaces the live policy with the file you provide. +It does not accept a preset file that starts with a `preset:` block, and it does not merge a single endpoint into the existing policy. +Use `nemoclaw my-assistant policy-add` for maintained NemoClaw presets. + +## Next Steps + +- [Approve or Deny Agent Network Requests](/network-policy/approve-network-requests) for the interactive OpenShell TUI flow. +- [Customize the Sandbox Network Policy](/network-policy/customize-network-policy) for static policy edits and raw OpenShell policy files. +- [Messaging Channels](/manage-sandboxes/messaging-channels) for Telegram, Discord, and Slack channel configuration. +- [Commands](/reference/commands) for the full `policy-add`, `policy-list`, `policy-remove`, and `channels` command reference. diff --git a/docs/reference/architecture.mdx b/docs/reference/architecture.mdx new file mode 100644 index 0000000000..4a94d4c476 --- /dev/null +++ b/docs/reference/architecture.mdx @@ -0,0 +1,271 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw Architecture: Plugin, Blueprint, and Sandbox Structure" +sidebar-title: "Architecture" +description: "Learn how NemoClaw combines a host CLI, sandbox plugin, and versioned blueprint to move OpenClaw into a controlled sandbox." +description-agent: "Describes the NemoClaw plugin and blueprint architecture and how they orchestrate the OpenClaw sandbox. Use when looking up architecture, plugin structure, or blueprint design." +keywords: ["nemoclaw architecture", "nemoclaw plugin blueprint structure"] +content: + type: "reference" +--- +NemoClaw combines a host CLI, a TypeScript plugin that runs with OpenClaw inside the sandbox, and a versioned YAML blueprint that defines the sandbox image, policies, and inference profiles applied through OpenShell. + +## System Overview + +NVIDIA OpenShell is a general-purpose agent runtime. It provides sandbox containers, a credential-storing gateway, inference proxying, and policy enforcement, but has no opinions about what runs inside. NemoClaw is an opinionated reference stack built on OpenShell that handles what goes in the sandbox and makes the setup accessible. + +```mermaid +graph LR + classDef nemoclaw fill:#76b900,stroke:#5a8f00,color:#fff,stroke-width:2px,font-weight:bold + classDef openshell fill:#1a1a1a,stroke:#1a1a1a,color:#fff,stroke-width:2px,font-weight:bold + classDef sandbox fill:#444,stroke:#76b900,color:#fff,stroke-width:2px,font-weight:bold + classDef agent fill:#f5f5f5,stroke:#e0e0e0,color:#1a1a1a,stroke-width:1px + classDef external fill:#f5f5f5,stroke:#e0e0e0,color:#1a1a1a,stroke-width:1px + classDef user fill:#fff,stroke:#76b900,color:#1a1a1a,stroke-width:2px,font-weight:bold + + USER(["👤 User"]):::user + + subgraph EXTERNAL["External Services"] + INFERENCE["Inference Provider
NVIDIA Endpoints · OpenAI
Anthropic · Ollama · vLLM · Model Router
"]:::external + MSGAPI["Messaging Platforms
Telegram · Discord · Slack"]:::external + INTERNET["Internet
PyPI · npm · GitHub · APIs"]:::external + end + + subgraph HOST["Host Machine"] + + subgraph NEMOCLAW["NemoClaw"] + direction TB + NCLI["CLI + Onboarding
Guided setup · provider selection
credential validation · deploy
"]:::nemoclaw + BP["Blueprint
Hardened Dockerfile
Network policies · Presets
Security configuration
"]:::nemoclaw + MIGRATE["State Management
Migration snapshots
Credential stripping
Integrity verification
"]:::nemoclaw + end + + subgraph OPENSHELL["OpenShell"] + direction TB + GW["Gateway
Credential store
Inference proxy
Policy engine
Device auth
"]:::openshell + OSCLI["openshell CLI
provider · sandbox
gateway · policy
"]:::openshell + CHMSG["Channel messaging
OpenShell-managed
Telegram · Discord · Slack
"]:::openshell + + subgraph SANDBOX["Sandbox Container 🔒"] + direction TB + AGENT["Agent
OpenClaw or any
compatible agent
"]:::agent + PLUG["NemoClaw Plugin
Extends agent with
managed configuration
"]:::sandbox + end + end + end + + USER -->|"nemoclaw onboard
nemoclaw connect"| NCLI + USER -->|"Chat messages"| MSGAPI + + NCLI -->|"Orchestrates"| OSCLI + BP -->|"Defines sandbox
shape + policies"| SANDBOX + MIGRATE -->|"Safe state
transfer"| SANDBOX + + AGENT -->|"Inference requests
no credentials"| GW + GW -->|"Proxied with
credential injected"| INFERENCE + + MSGAPI -->|"Platform APIs"| CHMSG + CHMSG -->|"Deliver to agent"| AGENT + + AGENT -.->|"Policy-gated"| INTERNET + GW -.->|"Enforced by
gateway"| INTERNET +``` + +## Deployment Topology + +The logical diagram above shows how components relate. +This section shows what actually runs where on the host. +NemoClaw uses a Docker daemon. +The OpenShell gateway runs as a container that embeds a k3s cluster. +The sandbox runs as a Kubernetes pod inside that embedded cluster. + +```mermaid +graph TB + classDef host fill:#fff,stroke:#76b900,stroke-width:2px,color:#1a1a1a,font-weight:bold + classDef cli fill:#76b900,stroke:#5a8f00,color:#fff,stroke-width:2px,font-weight:bold + classDef docker fill:#2496ed,stroke:#1577c2,color:#fff,stroke-width:2px,font-weight:bold + classDef gateway fill:#1a1a1a,stroke:#1a1a1a,color:#fff,stroke-width:2px,font-weight:bold + classDef k3s fill:#ffc61c,stroke:#c89a00,color:#1a1a1a,stroke-width:2px,font-weight:bold + classDef pod fill:#444,stroke:#76b900,color:#fff,stroke-width:2px + classDef external fill:#f5f5f5,stroke:#e0e0e0,color:#1a1a1a,stroke-width:1px + + subgraph HOST["Host machine · Linux / macOS / WSL2 / DGX Spark / DGX Station"] + direction TB + CLI["nemoclaw CLI
bin/nemoclaw.js → dist/
onboard · connect · status · logs
"]:::cli + + subgraph DOCKER["Docker daemon"] + direction TB + + subgraph GWCON["OpenShell gateway container"] + direction TB + PROXY["OpenShell L7 proxy
rewrites Authorization headers
and URL-path segments at egress
(credential injection)
"]:::gateway + + subgraph K3S["Embedded k3s cluster"] + direction TB + + subgraph POD["Sandbox pod 🔒
Landlock + seccomp + netns"] + direction TB + AGENT["OpenClaw agent
+ NemoClaw plugin"]:::pod + end + end + end + end + end + + INFER["Inference provider
NVIDIA Endpoints · OpenAI
Anthropic · Ollama · vLLM · Model Router
"]:::external + + CLI -->|"openshell CLI
(orchestrates)"| GWCON + AGENT -->|"inference requests
placeholder credentials"| PROXY + PROXY -->|"egress with real credentials
injected at the L7 proxy"| INFER + + class HOST host + class DOCKER docker + class GWCON gateway + class K3S k3s + class POD pod +``` + +Layering from top to bottom: + +| Layer | Runs as | Role | +|---|---|---| +| Host CLI | Host process (`nemoclaw` on Node.js) | Orchestrates OpenShell via `openshell` CLI calls. | +| Docker daemon | Host service | Runs the OpenShell gateway container. | +| Gateway container | Docker container | Hosts the credential store, the L7 proxy, and the embedded k3s control plane. | +| k3s | Process tree inside the gateway container | Kubernetes control plane that schedules the sandbox pod. | +| Sandbox pod | Pod in the embedded k3s cluster | Runs the OpenClaw agent and the NemoClaw plugin under Landlock + seccomp + netns. | +| OpenShell L7 proxy | Process in the gateway container | Intercepts agent egress and rewrites `Authorization` headers (Bearer/Bot) and URL-path segments to inject the real credential at the network boundary. | + +NemoClaw never gives the sandbox a raw provider key. +At onboard time it registers credentials with OpenShell's provider/placeholder system, and the L7 proxy substitutes the real value into outbound requests at egress. +The CLI helper `isInferenceRouteReady` (in `src/lib/onboard.ts`) is a host-side readiness check used by the resume flow to decide whether the active route already covers the chosen provider and model — it is not a runtime component. + +For the DGX Spark-specific variant of this topology (cgroup v2, aarch64, unified memory), refer to the [NVIDIA Spark playbook](https://build.nvidia.com/spark/nemoclaw). + +## NemoClaw Plugin + +The plugin is a thin TypeScript package that registers an inference provider and the `/nemoclaw` slash command. +It runs in-process with the OpenClaw gateway inside the sandbox. +It also registers runtime hooks that keep the agent aware of its environment. +Before an agent turn starts, the plugin prepends a short context block with the active sandbox name, sandbox phase, network policy summary, and filesystem policy summary. +When the policy or phase changes during a session, the plugin sends a smaller update block instead of repeating the full context. + +```text +nemoclaw/ +├── src/ +│ ├── index.ts Plugin entry: registers all commands +│ ├── cli.ts Commander.js subcommand wiring +│ ├── runtime-context.ts Sandbox and policy context injection +│ ├── commands/ +│ │ ├── launch.ts Fresh install into OpenShell +│ │ ├── connect.ts Interactive shell into sandbox +│ │ ├── status.ts Blueprint run state + sandbox health +│ │ ├── logs.ts Stream blueprint and sandbox logs +│ │ └── slash.ts /nemoclaw chat command handler +│ └── blueprint/ +│ ├── resolve.ts Version resolution, cache management +│ ├── fetch.ts Download blueprint from OCI registry +│ ├── verify.ts Digest verification, compatibility checks +│ ├── exec.ts Subprocess execution of blueprint runner +│ └── state.ts Persistent state (run IDs) +├── openclaw.plugin.json Plugin manifest +└── package.json Commands declared under openclaw.extensions +``` + +## NemoClaw Blueprint + +The blueprint is a versioned YAML package with its own release stream. +The runner resolves, verifies, and applies the blueprint through the OpenShell CLI. +The blueprint defines the sandbox shape, default policies, and inference profiles; the runner performs the OpenShell operations. + +```text +nemoclaw-blueprint/ +├── blueprint.yaml Manifest: version, profiles, compatibility +├── model-specific-setup/ Agent-scoped model/provider compatibility manifests +├── router/ Model Router config and routing engine +├── policies/ +│ └── openclaw-sandbox.yaml Default network + filesystem policy +``` + +The blueprint runtime (TypeScript) lives in the plugin source tree: + +```text +nemoclaw/src/blueprint/ +├── runner.ts CLI runner: plan / apply / status / rollback +├── ssrf.ts SSRF endpoint validation (IP + DNS checks) +├── snapshot.ts Migration snapshot / restore lifecycle +├── state.ts Persistent run state management +``` + +### Blueprint Lifecycle + +```mermaid +flowchart LR + A[resolve] --> B[verify digest] + B --> C[plan] + C --> D[apply] + D --> E[status] +``` + +1. Resolve. The plugin locates the blueprint artifact and checks the version against `min_openshell_version` and `min_openclaw_version` constraints in `blueprint.yaml`. +2. Verify. The plugin checks the artifact digest against the expected value. +3. Plan. The runner determines what OpenShell resources to create or update, such as the gateway, providers, sandbox, inference route, and policy. +4. Apply. The runner executes the plan by calling `openshell` CLI commands. +5. Status. The runner reports current state. + +## Sandbox Environment + +The sandbox runs the +[`ghcr.io/nvidia/openshell-community/sandboxes/openclaw`](https://github.com/NVIDIA/OpenShell-Community) +container image. Inside the sandbox: + +- OpenClaw runs with the NemoClaw plugin pre-installed. +- Inference calls are routed through OpenShell to the configured provider. +- Network egress is restricted by the baseline policy in `openclaw-sandbox.yaml`. +- Filesystem access is confined to `/sandbox` and `/tmp` for read-write access, with system paths read-only. +- The NemoClaw plugin injects sandbox and policy context into agent turns so the agent can report policy blocks accurately. + +## Inference Routing + +Inference requests from the agent never leave the sandbox directly. +OpenShell intercepts them and routes to the configured provider: + +```text +Agent (sandbox) ──▶ OpenShell gateway ──▶ NVIDIA Endpoint (build.nvidia.com) +``` + +When you select the Model Router provider, the OpenShell gateway routes to a host-side router process instead of a single upstream model. +The router selects from the configured pool, then calls the upstream NVIDIA endpoint with the credential held outside the sandbox. + +Some model and provider combinations need agent-specific compatibility setup. +NemoClaw keeps those declarations under `nemoclaw-blueprint/model-specific-setup//` so OpenClaw and Hermes fixes can be tested and reviewed independently. + +Refer to [Inference Options](/inference/inference-options) for provider configuration details. + +## Provider Credential Storage + +Provider credentials live in the OpenShell gateway store, not on the host filesystem. +NemoClaw never writes them to host disk; the OpenShell L7 proxy injects values at egress. +See [Credential Storage](/security/credential-storage) for the inspection, rotation, and migration flow. + +## Host-Side State and Config + +NemoClaw keeps non-secret operator-facing state on the host rather than inside the sandbox. + +| Path | Purpose | +|---|---| +| `~/.nemoclaw/sandboxes.json` | Registered sandbox metadata, including the default sandbox selection. | +| `~/.openclaw/openclaw.json` | Host OpenClaw configuration that NemoClaw snapshots or restores during migration flows. | + +The following environment variables configure optional services and local access. + +| Variable | Purpose | +|---|---| +| `TELEGRAM_BOT_TOKEN` | Telegram bot token you provide before `nemoclaw onboard`. OpenShell stores it in a provider; the sandbox receives placeholders, not the raw secret. | +| `TELEGRAM_ALLOWED_IDS` | Comma-separated Telegram user or chat IDs for allowlists when onboarding applies channel restrictions. | +| `CHAT_UI_URL` | URL for the optional chat UI endpoint. | +| `NEMOCLAW_DISABLE_DEVICE_AUTH` | Build-time-only toggle that disables gateway device pairing when set to `1` before the sandbox image is created. | + +For normal setup and reconfiguration, prefer `nemoclaw onboard` over editing these files by hand. +Do not treat `NEMOCLAW_DISABLE_DEVICE_AUTH` as a runtime setting for an already-created sandbox. diff --git a/docs/reference/cli-selection-guide.mdx b/docs/reference/cli-selection-guide.mdx new file mode 100644 index 0000000000..88536fd92b --- /dev/null +++ b/docs/reference/cli-selection-guide.mdx @@ -0,0 +1,210 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "CLI Selection Guide" +sidebar-title: "CLI Selection Guide" +description: "Choose between the NemoClaw CLI and the OpenShell CLI for common sandbox operations." +description-agent: "Explains when to use `nemoclaw` versus `openshell` for NemoClaw-managed sandboxes, including lifecycle, inference, policy, monitoring, file transfer, and gateway operations." +keywords: ["nemoclaw vs openshell", "which cli", "nemoclaw cli", "openshell cli", "sandbox commands"] +content: + type: "reference" +--- +NemoClaw uses two host-side CLIs. +Use `nemoclaw` for NemoClaw-managed workflows. +Use `openshell` when you need a lower-level OpenShell operation that NemoClaw intentionally exposes. + +## Rule of Thumb + +If the task changes how NemoClaw creates, rebuilds, preserves, or configures a sandbox, start with `nemoclaw`. + +If the task inspects or changes the live OpenShell gateway, TUI, raw policy, port forwarding, inference route, or sandbox file transfer, use `openshell`. + +Do not create or recreate NemoClaw-managed sandboxes directly with `openshell sandbox create` unless you intend to manage OpenShell yourself. +Run `nemoclaw onboard` afterward if you need to return to a NemoClaw-managed environment. + +## Use `nemoclaw` For NemoClaw Workflows + +Use `nemoclaw` for operations where NemoClaw adds product-specific state, safety checks, backup behavior, credential handling, or OpenClaw configuration. + +- Install, onboard, or recreate a NemoClaw sandbox: + + ```console + $ nemoclaw onboard + $ nemoclaw onboard --resume --recreate-sandbox + ``` + +- List, connect to, check, or delete NemoClaw-managed sandboxes: + + ```console + $ nemoclaw list + $ nemoclaw my-assistant connect + $ nemoclaw my-assistant status + $ nemoclaw my-assistant logs --follow + $ nemoclaw my-assistant destroy + ``` + +- Rebuild or upgrade while preserving workspace state: + + ```console + $ nemoclaw my-assistant rebuild + $ nemoclaw upgrade-sandboxes --check + ``` + +- Snapshot, restore, or mount sandbox state: + + ```console + $ nemoclaw my-assistant snapshot create --name before-change + $ nemoclaw my-assistant snapshot restore before-change + $ nemoclaw my-assistant share mount + ``` + +- Add or remove NemoClaw policy presets: + + ```console + $ nemoclaw my-assistant policy-add pypi --yes + $ nemoclaw my-assistant policy-list + $ nemoclaw my-assistant policy-remove pypi --yes + ``` + +- Manage NemoClaw messaging channels, credentials, diagnostics, and cleanup: + + ```console + $ nemoclaw my-assistant channels add slack + $ nemoclaw credentials list + $ nemoclaw credentials reset nvidia-prod + $ nemoclaw debug --sandbox my-assistant + $ nemoclaw gc --dry-run + ``` + +## Use `openshell` For OpenShell Operations + +Use `openshell` when the docs explicitly call for a live OpenShell gateway operation or when you need a lower-level view beneath the NemoClaw wrapper. + +- Open the OpenShell TUI for network approvals and live activity: + + ```console + $ openshell term + ``` + +- Manage dashboard or service port forwards: + + ```console + $ openshell forward start --background + $ openshell forward list + ``` + +- Inspect the underlying sandbox state: + + ```console + $ openshell sandbox list + $ openshell sandbox get + $ openshell logs --tail + ``` + +- Run one-off commands or move files without starting a NemoClaw chat session: + + ```console + $ openshell sandbox exec -n -- ls -la /sandbox + $ openshell sandbox upload ./local-file /sandbox/ + $ openshell sandbox download /sandbox/output ./output + ``` + +- Inspect or replace raw OpenShell policy: + + ```console + $ openshell policy get --full > live-policy.yaml + $ openshell policy update --add-endpoint api.example.com:443:read-only:rest:enforce + $ openshell policy set --policy live-policy.yaml + ``` + +`openshell policy update` merges specific endpoint and rule changes into the live sandbox policy. +`openshell policy set` replaces the live policy with the file you provide. +For normal NemoClaw network access changes, prefer `nemoclaw policy-add` so NemoClaw preserves presets and records the change for rebuilds. + +## Common Decisions + +This section covers common decisions when using the NemoClaw CLI and the OpenShell CLI. + +### First Setup or Full Recreate + +Use `nemoclaw onboard`. +It starts the OpenShell gateway when needed, registers providers, builds the OpenClaw sandbox image, applies NemoClaw policy choices, and creates the sandbox. + +Avoid running `openshell gateway start --recreate` or `openshell sandbox create` directly for NemoClaw-managed sandboxes. +Those commands do not update NemoClaw's registry, session metadata, workspace-preservation flow, or OpenClaw-specific configuration. + +### Connect to the Sandbox + +Use `nemoclaw connect` for an interactive NemoClaw sandbox shell. +It waits for readiness, handles stale SSH host keys after gateway restarts, and prints agent-specific hints. + +Use `openshell sandbox connect ` only when you intentionally want the raw OpenShell connection path. + +For a one-off command, use `openshell sandbox exec` instead of opening an interactive shell. + +```console +$ openshell sandbox exec -n my-assistant -- cat /tmp/gateway.log +``` + +### Check Health or Logs + +Use `nemoclaw status` and `nemoclaw logs` first. +They combine NemoClaw registry data, OpenShell state, OpenClaw process health, inference health, policy details, and messaging-channel warnings. + +Use `openshell sandbox list`, `openshell sandbox get`, or `openshell logs` when debugging lower-level OpenShell behavior. + +### Approve Blocked Network Requests + +Use `openshell term`. +The OpenShell TUI owns live network activity and operator approval prompts. + +Approved endpoints are session-scoped unless you also add them to the policy through a NemoClaw preset or raw OpenShell policy update. + +### Change Models or Providers + +Use the NemoClaw commands for model or provider inspection and switches so the OpenShell route and the running agent config stay consistent: + +```console +$ nemoclaw inference get +$ nemoclaw inference set --provider nvidia-prod --model nvidia/nemotron-3-super-120b-a12b +``` + +For Hermes sandboxes, use the alias; it updates the route and `/sandbox/.hermes/config.yaml` without a rebuild or restart: + +```console +$ nemohermes inference set --provider hermes-provider --model openai/gpt-5.4-mini +``` + +For a build-time agent setting change, rerun onboarding so the sandbox configuration is recreated consistently: + +```console +$ nemoclaw onboard --resume --recreate-sandbox +``` + +Verify either path with: + +```console +$ nemoclaw status +``` + +### Update Network Policy + +Use `nemoclaw policy-add` or `policy-remove` for NemoClaw presets and custom preset files. +NemoClaw merges the new policy with the live policy and reapplies presets during rebuilds. + +Use `openshell policy update` for precise live endpoint or REST rule changes. +Use `openshell policy get --full` and `openshell policy set` only when you need to edit and replace the raw policy file. + +### Move Workspace Files + +Use `nemoclaw snapshot create`, `snapshot restore`, or `share mount` for normal workspace preservation and editing. + +Use `openshell sandbox upload` and `openshell sandbox download` for manual file copies when you need exact control over source and destination paths. + +## Related Topics + +- [Commands](/reference/commands) for the full NemoClaw command reference. +- [Manage Sandbox Lifecycle](/manage-sandboxes/lifecycle) for day-two operations. +- [Switch Inference Models](/inference/switch-inference-providers) for inference route examples. +- [Customize the Network Policy](/network-policy/customize-network-policy) for persistent network access changes. +- [Approve or Deny Network Requests](/network-policy/approve-network-requests) for the OpenShell TUI approval flow. diff --git a/docs/reference/commands.mdx b/docs/reference/commands.mdx new file mode 100644 index 0000000000..fc8f0a82d1 --- /dev/null +++ b/docs/reference/commands.mdx @@ -0,0 +1,1228 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "NemoClaw CLI Commands Reference" +sidebar-title: "Commands" +description: "Full CLI reference for slash commands and standalone NemoClaw commands." +description-agent: "Includes the full CLI reference for slash commands and standalone NemoClaw commands. Use when looking up a specific `nemoclaw` or `/nemoclaw` subcommand, flag, argument, or exit code." +keywords: ["nemoclaw cli commands", "nemoclaw command reference"] +content: + type: "reference" +--- +The `nemoclaw` CLI is the primary interface for managing NemoClaw sandboxes. +It is installed automatically by the installer (`curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash`). +For guidance on when to use `nemoclaw` versus the underlying `openshell` CLI, see [CLI Selection Guide](/reference/cli-selection-guide). + +## `/nemoclaw` Slash Command + +The `/nemoclaw` slash command is available inside the OpenClaw chat interface for quick actions: + +| Subcommand | Description | +|---|---| +| `/nemoclaw` | Show slash-command help and host CLI pointers | +| `/nemoclaw status` | Show sandbox and inference state | +| `/nemoclaw onboard` | Show onboarding status and reconfiguration guidance | +| `/nemoclaw eject` | Show rollback instructions for returning to the host installation | + +## Standalone Host Commands + +The `nemoclaw` binary handles host-side operations that run outside the OpenClaw plugin context. + +### `nemoclaw help`, `nemoclaw --help`, `nemoclaw -h` + +Show the top-level usage summary and command groups. +Running `nemoclaw` with no arguments shows the same help output. + +```console +$ nemoclaw help +``` + +### `nemoclaw --version`, `nemoclaw -v` + +Print the installed NemoClaw CLI version. + +```console +$ nemoclaw --version +``` + +### `nemoclaw onboard` + +Run the interactive setup wizard (recommended for new installs). +The wizard creates an OpenShell gateway, registers inference providers, builds the sandbox image, and creates the sandbox. +Use this command for new installs and for recreating a sandbox after changes to policy or configuration. + +```console +$ nemoclaw onboard [--non-interactive] [--resume | --fresh] [--recreate-sandbox] [--gpu | --no-gpu] [--from ] [--name ] [--sandbox-gpu | --no-sandbox-gpu] [--sandbox-gpu-device ] [--agent ] [--control-ui-port ] [--yes | -y] [--yes-i-accept-third-party-software] +``` + + +For NemoClaw-managed environments, use `nemoclaw onboard` when you need to create or recreate the OpenShell gateway or sandbox. +Avoid `openshell self-update`, `npm update -g openshell`, `openshell gateway start --recreate`, or `openshell sandbox create` directly unless you intend to manage OpenShell separately and then rerun `nemoclaw onboard`. + + +The installer detects existing sandbox sessions before onboarding and prints a warning if any are found. +To make the installer abort instead of continuing, set `NEMOCLAW_SINGLE_SESSION=1`: + +```console +$ NEMOCLAW_SINGLE_SESSION=1 curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +When existing sandboxes were created with OpenShell earlier than `0.0.37`, the installer prompts before running the new automatic gateway upgrade path. +For scripted installs, set `NEMOCLAW_ACCEPT_EXPERIMENTAL_OPENSHELL_UPGRADE=1` to allow the installer to back up registered sandbox state, retire the old gateway, install the current supported OpenShell release, and restore state during onboarding. +The automatic path is disabled if the existing `nemoclaw` CLI does not advertise `backup-all`; preserve sandbox state manually before retiring the old gateway in that case. +To perform those steps manually, run `nemoclaw backup-all`, retire the old gateway with `openshell gateway destroy -g nemoclaw || openshell gateway destroy`, then rerun the installer as `curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_OPENSHELL_UPGRADE_PREPARED=1 bash`. + +The wizard prompts for a provider first, then collects the provider credential if needed. +Supported non-experimental choices include NVIDIA Endpoints, OpenAI, Anthropic, Google Gemini, and compatible OpenAI or Anthropic endpoints. +Credentials are registered with the OpenShell gateway and never persisted to host disk. See [Credential Storage](/security/credential-storage) for details on inspection, rotation, and migration from earlier releases. +The legacy `nemoclaw setup` command is deprecated; use `nemoclaw onboard` instead. + +After provider selection, the wizard prompts for a **policy tier** that controls the default set of network policy presets applied to the sandbox. +Three tiers are available: + +| Tier | Description | +|------|-------------| +| Restricted | Base sandbox only. No third-party network access beyond inference and core agent tooling. | +| Balanced (default) | Full dev tooling and web search when the active agent supports web search. Package installs, model downloads, and inference. No messaging platform access. | +| Open | Broad access across third-party services including messaging and productivity. Agent-specific unsupported presets are filtered out. | + +After selecting a tier, the wizard shows a combined preset and access-mode screen where you can include or exclude individual presets and toggle each between read and read-write access. +For details on tiers and the presets each includes, see [Network Policies](/reference/network-policies#policy-tiers). + +In non-interactive mode, set the tier with `NEMOCLAW_POLICY_TIER` (default: `balanced`): + +```console +$ NEMOCLAW_POLICY_TIER=restricted nemoclaw onboard --non-interactive --yes-i-accept-third-party-software +``` + +`NEMOCLAW_POLICY_MODE` controls how non-interactive onboarding reconciles the tier-derived suggestions against the sandbox's currently-applied presets. +The default is `suggested`, which is *additive*. +Onboarding applies tier defaults and preserves any presets you previously added with [`nemoclaw policy-add`](#nemoclaw-name-policy-add) across re-onboards. +Use `custom` with `NEMOCLAW_POLICY_PRESETS` when you want the explicit list to be authoritative. +Onboarding removes any preset that is not in the list. +`skip` leaves the applied set untouched and does not apply tier defaults. +NemoClaw filters tier suggestions and resume selections by active agent support, so unsupported presets such as Brave Search are not reapplied to agents that do not support them. + +| Value | Behaviour | +|-------|-----------| +| `suggested` (default) | Apply tier defaults and preserve any extra presets already applied. Aliases: `default`, `auto`. | +| `custom` | Apply exactly `NEMOCLAW_POLICY_PRESETS`. Previously-applied presets not in the list are removed. Alias: `list`. | +| `skip` | Skip the policy step entirely. Aliases: `none`, `no`. | + +If you enable Brave Search during onboarding, NemoClaw currently stores the Brave API key in the sandbox's OpenClaw configuration. +That means the OpenClaw agent can read the key. +NemoClaw explores an OpenShell-hosted credential path first, but the current OpenClaw Brave runtime does not consume that path end to end yet. +Treat Brave Search as an explicit opt-in and use a dedicated low-privilege Brave key. + +For non-interactive onboarding, you must explicitly accept the third-party software notice: + +```console +$ nemoclaw onboard --non-interactive --yes-i-accept-third-party-software +``` + +or: + +```console +$ NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 nemoclaw onboard --non-interactive +``` + +For scripted installer runs, pass explicit acceptance to the `bash` side of the installer pipe: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 bash +``` + +If the installer cannot prompt for the notice in a terminal and no explicit acceptance is set, it exits before installing Node.js or the NemoClaw CLI. + +To enable Brave Search in non-interactive mode, set: + +```console +$ BRAVE_API_KEY=... \ + nemoclaw onboard --non-interactive +``` + +`BRAVE_API_KEY` enables Brave Search in non-interactive mode and also enables `web_fetch`. +If Brave Search key validation fails in non-interactive mode, onboarding prints a warning, skips web search setup, and continues with the rest of the sandbox setup. +After fixing the key, re-enable web search with `nemoclaw config web-search`. + +The wizard prompts for a sandbox name. +Names must be lowercase, start with a letter, contain only letters, numbers, and internal hyphens, and end with a letter or number. +Uppercase letters are automatically lowercased. +Names that match global CLI commands (`status`, `list`, `debug`, etc.) are rejected to avoid routing conflicts. +Use `--agent ` to target a specific installed agent profile during onboarding. + +Use `--control-ui-port ` to choose the host dashboard port for a sandbox. +The value must be an integer from `1024` through `65535`. +This flag takes precedence over `CHAT_UI_URL`, `NEMOCLAW_DASHBOARD_PORT`, the previous registry value, and the default port. + +If you enable Slack during onboarding, the wizard collects both the Bot Token (`SLACK_BOT_TOKEN`) and the App-Level Token (`SLACK_APP_TOKEN`). +Socket Mode requires both tokens. +The app-level token is stored in a dedicated `slack-app` OpenShell provider and forwarded to the sandbox alongside the bot token. + +If you enable Discord during onboarding, the wizard can also prompt for a Discord Server ID, whether the bot should reply only to `@mentions` or to all messages in that server, and an optional Discord User ID. +NemoClaw bakes those values into the sandbox image as Discord guild workspace config so the bot can respond in the selected server, not just in DMs. +If you leave the Discord User ID blank, the guild config omits the user allowlist and any member of the configured server can message the bot. +Guild responses remain mention-gated by default unless you opt into all-message replies. + +If you enable Telegram during onboarding, the wizard can also prompt for whether group chats should reply only to `@mentions` or to all group messages. +Set `TELEGRAM_REQUIRE_MENTION=1` for non-interactive onboarding when you want mention-only group replies. +Pairing and `TELEGRAM_ALLOWED_IDS` still govern direct messages. + +If you run onboarding again with the same sandbox name and choose a different inference provider or model, NemoClaw detects the drift and recreates the sandbox so the running OpenClaw UI matches your selection. +In interactive mode, the wizard asks for confirmation before delete and recreate. +In non-interactive mode, NemoClaw recreates automatically when the stored selection is readable and differs; if NemoClaw cannot read the stored selection, NemoClaw reuses by default. +Set `NEMOCLAW_RECREATE_SANDBOX=1` to force recreation even when no drift is detected. + +Before creating the gateway, the wizard runs preflight checks. +It verifies that Docker is reachable, warns on untested runtimes such as Podman, and prints host remediation guidance when prerequisites are missing. +The preflight also enforces the OpenShell version range declared in the blueprint (`min_openshell_version` and `max_openshell_version`). +If the installed OpenShell version falls outside this range, onboarding exits with an actionable error and a link to compatible releases. +For fresh OpenShell installs, NemoClaw queries published OpenShell releases and asks the installer to use a release that fits the blueprint range. +If release metadata is unavailable, the installer uses its bundled fallback pin and the post-install version gate still enforces the range. + +When NemoClaw finds an existing gateway to reuse, it probes the host gateway HTTP endpoint before declaring the gateway reusable. +If the container is running but the upstream is still warming up (for example, immediately after a Docker daemon restart), NemoClaw rebuilds the gateway instead of trusting stale metadata. +For Linux Docker-driver gateways, onboarding also checks that a helper container on the OpenShell Docker network can reach `host.openshell.internal:`. +If a host firewall blocks that sandbox path, onboarding exits with a `sudo ufw allow from to any port proto tcp` command before it reports the gateway healthy. +Tune the wait via `NEMOCLAW_REUSE_HEALTH_POLL_COUNT` (default `6`) and `NEMOCLAW_REUSE_HEALTH_POLL_INTERVAL` (default `5` seconds). +The poll count is clamped to a minimum of `1` so the probe always runs at least once, and the interval is clamped to a minimum of `0` (no sleep between attempts). + +#### `--from ` + +Build the sandbox image from a custom Dockerfile instead of the stock NemoClaw image. +The entire parent directory of the specified file is used as the Docker build context, so any files your Dockerfile references (scripts, config, etc.) must live alongside it. +Onboarding skips common large directories (`node_modules`, `.git`, `.venv`, and `__pycache__`) while staging this context. +It also skips credential-style files and directories such as `.env*`, `.ssh/`, `.aws/`, `.netrc`, `.npmrc`, `secrets/`, `*.pem`, and `*.key`. +Other build outputs such as `dist/`, `target/`, or `build/` are still included. +If the staged context is larger than 100 MB, onboarding prints a warning before the Docker build starts. +If the directory contains unreadable files (for example, Windows system files visible in WSL), onboarding exits with an error suggesting you move the Dockerfile to a dedicated directory. + +```console +$ nemoclaw onboard --from path/to/Dockerfile +``` + +The Dockerfile path must exist. +Missing paths fail during command parsing before preflight, gateway setup, inference setup, or sandbox creation starts. + +The file can have any name; if it is not already named `Dockerfile`, onboard copies it to `Dockerfile` inside the staged build context automatically. +To create an isolated build context, create a dedicated directory that contains only the Dockerfile and the files it needs: + +```text +build-dir/ +├── Dockerfile +└── files-used-by-COPY/ +``` + +All NemoClaw build arguments (`NEMOCLAW_MODEL`, `NEMOCLAW_PROVIDER_KEY`, `NEMOCLAW_INFERENCE_BASE_URL`, etc.) are injected as `ARG` overrides at build time, so declare them in your Dockerfile if you need to reference them. + +In non-interactive mode, the path can also be supplied via the `NEMOCLAW_FROM_DOCKERFILE` environment variable. +You must also supply a sandbox name via `--name ` or `NEMOCLAW_SANDBOX_NAME` so a `--from` build cannot silently clobber the default `my-assistant` sandbox. + +```console +$ NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_FROM_DOCKERFILE=path/to/Dockerfile NEMOCLAW_SANDBOX_NAME=my-build nemoclaw onboard +``` + +If a `--resume` is attempted with a different `--from` path than the original session, onboarding exits with a conflict error rather than silently building from the wrong image. + +#### `--name ` + +Set the sandbox name without going through the interactive prompt. +The same name format and reserved-name rules that the wizard enforces apply here too. Names must be lowercase, start with a letter, contain only letters, numbers, and internal hyphens, and end with a letter or number. +Names that match a NemoClaw CLI command (`status`, `list`, `debug`, etc.) are rejected up front. + +```console +$ nemoclaw onboard --non-interactive --name my-build --from path/to/Dockerfile +``` + +The flag wins over `NEMOCLAW_SANDBOX_NAME`. +When prompting is possible, `NEMOCLAW_SANDBOX_NAME` fills the interactive default so you can press Enter to accept it. +When prompting is impossible (no TTY or `--non-interactive`), the env var is also honoured so existing CI scripts keep working. +Combining `--from ` with non-interactive onboarding requires one of `--name` or `NEMOCLAW_SANDBOX_NAME`; otherwise onboarding exits rather than silently defaulting to `my-assistant` and clobbering the default sandbox. + +### `nemoclaw onboard --from` + +Use a custom Dockerfile for the sandbox image. +This variant of `nemoclaw onboard` accepts a `--from ` argument to build the sandbox from a user-supplied Dockerfile instead of the default NemoClaw image. + +```console +$ nemoclaw onboard --from ./Dockerfile.custom +``` + +### GPU passthrough + +When `nemoclaw onboard` detects an NVIDIA GPU on the host (`nvidia-smi` succeeds), it enables OpenShell GPU passthrough at both the gateway and sandbox level by default. +Use `--no-gpu` to opt out when you want host-side inference providers only and do not need direct GPU access inside the sandbox. +Use `--gpu` to require GPU passthrough and fail fast if an NVIDIA GPU is not detected. +Use `--sandbox-gpu` or `--no-sandbox-gpu` to control only direct NVIDIA GPU access inside the sandbox. +Use `--sandbox-gpu-device ` to pass a specific OpenShell GPU device selector to `openshell sandbox create`. +On Linux Docker-driver gateways, NemoClaw can create the sandbox first and then recreate the OpenShell-managed Docker container with NVIDIA GPU access when that compatibility path is needed. +If the patch fails, onboarding keeps diagnostics and prints a manual cleanup command rather than deleting the failed sandbox automatically. + +Prerequisites: + +- NVIDIA GPU drivers installed and working (`nvidia-smi` must succeed). +- NVIDIA Container Toolkit configured for Docker. + +When GPU passthrough is enabled and a gateway already exists without it, onboarding exits with guidance to destroy and re-onboard. +To add GPU to an existing sandbox, rerun with `--recreate-sandbox`. +Set `NEMOCLAW_DOCKER_GPU_PATCH=0` only when you need to bypass the Linux Docker-driver compatibility patch during troubleshooting. + +### `nemoclaw list` + +List all registered sandboxes with their model, provider, and policy presets. +Pass `--json` for machine-readable output that includes a `schemaVersion`, the default sandbox, recovery metadata, and the sandbox inventory. +Sandboxes with an active SSH session are marked with a `●` indicator so you can tell at a glance which sandbox you are already connected to in another terminal. +When a sandbox has a recorded dashboard port, the output includes its local dashboard URL. + +```console +$ nemoclaw list [--json] +$ nemoclaw list --json +``` + +### `nemoclaw deploy` + + +The `nemoclaw deploy` command is deprecated. +Prefer provisioning the remote host separately, then running the standard NemoClaw installer and `nemoclaw onboard` on that host. + + +Deploy NemoClaw to a remote GPU instance through [Brev](https://brev.nvidia.com). +This command remains as a compatibility wrapper for the older Brev-specific bootstrap flow. +The Brev instance name is the positional argument. +The sandbox name comes from `NEMOCLAW_SANDBOX_NAME` and defaults to `my-assistant`; invalid sandbox names fail before Brev provisioning starts. + +```console +$ nemoclaw deploy +``` + +### `nemoclaw connect` + +Connect to a sandbox by name. +If the sandbox is not yet in the `Ready` phase, `connect` polls `openshell sandbox list` every few seconds and prints the current phase. This gives you progress output right after onboarding, when the 2.4 GB image is still pulling, instead of a silent hang. +Control the wait budget with `NEMOCLAW_CONNECT_TIMEOUT` (integer seconds, default `120`). When the deadline expires, `connect` exits non-zero with the last-seen phase. + +On a TTY, a one-shot hint prints before dropping into the sandbox shell. +The hint is agent-aware. It names the correct TUI command for the sandbox's agent and reminds you to use `/exit` to leave the chat before `exit` returns you to the host shell. +Set `NEMOCLAW_NO_CONNECT_HINT=1` to suppress the hint in scripted workflows. +If the sandbox is running an outdated agent version, a non-blocking warning prints before connecting with a `nemoclaw rebuild` hint. +If another terminal is already connected to the sandbox, `connect` prints a note with the number of existing sessions before proceeding. Multiple concurrent sessions are allowed. + +After a host reboot, the OpenShell gateway rotates its SSH host keys. +`connect` detects the resulting identity drift, prunes stale `openshell-*` entries from `~/.ssh/known_hosts`, and retries automatically. +You no longer need to re-run `nemoclaw onboard` after a reboot in this case. + +```console +$ nemoclaw my-assistant connect [--probe-only] +``` + +The `--probe-only` flag verifies the sandbox is reachable over SSH and exits without opening a shell. +Use it for health checks and scripted readiness probes. + +### `nemoclaw recover` + +Restart the in-sandbox gateway and re-establish the host-side dashboard port-forward without opening an SSH session. +Use this after a sandbox pod restart, a sandbox crash, or whenever `nemoclaw status` reports the gateway is not running but the sandbox is alive. + +`recover` runs the same recovery the `connect` command performs as a side effect, but without dropping into a shell, so it is safe to call from scripts and automation. +It is idempotent. +If the gateway is already running, the command exits zero with a probe message and makes no changes. + +```console +$ nemoclaw my-assistant recover +``` + +### `nemoclaw status` + +Show sandbox status, health, and inference configuration. + +The command probes every inference provider and reports one of three states on the `Inference` line: + +| State | Meaning | +|-------|---------| +| `healthy` | The provider endpoint returned a reachable response. | +| `unreachable` | The probe failed. The output includes the endpoint URL and a remediation hint. | +| `not probed` | The endpoint URL is not known (for example, `compatible-*` providers). | +| `not verified` | NemoClaw could not verify the sandbox or gateway state, so it skips inference probing. | + +Local providers (Ollama, vLLM) probe the host-side health endpoint. +Remote providers (NVIDIA Endpoints, OpenAI, Anthropic, Gemini) use a lightweight reachability check; any HTTP response, including `401` or `403`, counts as reachable. +No API keys are sent. + +For Local Ollama, the command also probes the authenticated proxy and prints an `Inference (auth proxy)` line when a proxy token is available. +Use that line to distinguish a healthy backend from a broken proxy path that the sandbox uses for inference. + +For cloud-only providers, the output omits the NIM status line unless a NIM container is registered or an unexpected NIM container is running. + +If the sandbox or gateway cannot be verified, the command exits non-zero instead of reporting healthy inference from stale registry state. +Gateway and dashboard health checks treat HTTP `401` from device auth as a live service, not as an offline gateway. + +A `Connected` line reports whether the sandbox has any active SSH sessions and, if so, how many. +The sandbox list in the status output includes the dashboard port suffix for sandboxes with a recorded dashboard port. + +The Policy section displays the live enforced policy (fetched via `openshell policy get --full`), which reflects presets added or removed after sandbox creation. +When OpenShell reports an active policy version, the displayed YAML `version` line uses that active version instead of the static schema version. +If the sandbox is running an outdated agent version, the output includes an `Update` line with the available version and a `nemoclaw rebuild` hint. + +When other sandboxes have the same messaging channel enabled (Telegram, Discord, or Slack) with the same bot token, the output includes a cross-sandbox overlap warning so you can resolve the conflict before messages start dropping. +The command also tails `/tmp/gateway.log` inside the default sandbox and flags Telegram `409 Conflict` errors that indicate a duplicate consumer for the bot token. + +```console +$ nemoclaw my-assistant status +``` + +#### Checking the OpenClaw version + +NemoClaw pins the OpenClaw version inside the sandbox at build time, not at runtime. +The minimum version comes from `min_openclaw_version` in `nemoclaw-blueprint/blueprint.yaml`, and the sandbox image upgrades OpenClaw to that version during `docker build` if the cached base image is older. +Existing sandboxes do not auto-upgrade when a newer NemoClaw release ships a newer pin — you upgrade by rebuilding the sandbox. + +`nemoclaw status` prints the running OpenClaw version on the `Agent` line: + +```console +$ nemoclaw my-assistant status +... + Agent: OpenClaw v2026.4.24 +... +``` + +If the sandbox is running an OpenClaw older than the version this NemoClaw release pins, `status` and `connect` add an `Update` line pointing at `nemoclaw rebuild` to pick up the newer version. +The rebuild reuses the existing sandbox name and persisted credentials, so messaging tokens and provider keys carry over. + +### `nemoclaw doctor` + +Run a focused health check for one sandbox and the host services it depends on. +The command checks the local CLI build, Docker daemon, OpenShell CLI, NemoClaw gateway container, gateway port mapping, live sandbox state, inference route, provider reachability, messaging channel conflicts, Ollama reachability, and the cloudflared tunnel state. + +Warnings do not make the command fail. +Failed checks exit non-zero so scripts can use `doctor` as a readiness gate. +Use `--json` for machine-readable output. + +```console +$ nemoclaw my-assistant doctor [--json] +``` + +### `nemoclaw logs` + +View sandbox logs. +Use `--follow` to stream output in real time. +Use `--tail ` or `-n ` to limit the number of returned lines. +Use `--since ` to show recent logs only, such as `5m`, `1h`, or `30s`. +The command reads both OpenClaw gateway output and OpenShell audit events, so policy denials appear alongside the gateway log stream. +If one log source is unavailable, NemoClaw prints a warning and keeps reading the remaining source. + +```console +$ nemoclaw my-assistant logs [--follow] [--tail |-n ] [--since ] +``` + +### `nemoclaw gateway-token` + +Print the OpenClaw gateway auth token for a running sandbox to stdout. +The token is required by `openclaw tui` and the OpenClaw dashboard URL, but onboarding only prints it once. +Pipe it into automation or capture it into an environment variable: + +```console +$ TOKEN=$(nemoclaw my-assistant gateway-token --quiet) +$ export OPENCLAW_GATEWAY_TOKEN="$TOKEN" +``` + +The token is written to stdout with no surrounding text. +A one-line security warning is written to stderr; pass `--quiet` (or `-q`) to suppress it. +The command exits non-zero with a diagnostic on stderr when the sandbox is not registered or when the token cannot be retrieved (for example, if the sandbox is not running). + + +Treat the gateway token like a password. +Do not log it, share it, or commit it to version control. + + +### `nemoclaw destroy` + +Stop the NIM container, remove the host-side Docker image built during onboard, and delete the sandbox. +This removes the sandbox from the registry. +For Ollama-backed sandboxes, `destroy` also asks Ollama to unload currently loaded models and clears stale auth proxy state on a best-effort basis. + + +This command permanently deletes the sandbox **and its persistent volume**. +All [workspace files](/manage-sandboxes/workspace-files) (SOUL.md, USER.md, IDENTITY.md, AGENTS.md, MEMORY.md, and daily memory notes) are lost. +Back up your workspace first with `nemoclaw snapshot create` or see [Backup and Restore](/manage-sandboxes/backup-restore). +If you want to upgrade the sandbox while preserving state, use `nemoclaw rebuild` instead. + + +If another terminal has an active SSH session to the sandbox, `destroy` prints an active-session warning and requires a second confirmation before it proceeds. +Pass `--yes`, `-y`, or `--force` to skip the prompt in scripted workflows. +By default, `destroy` preserves the shared NemoClaw gateway. +Pass `--cleanup-gateway` to remove the shared gateway when destroying the last sandbox, or `--no-cleanup-gateway` to force preservation when environment defaults request cleanup. + +```console +$ nemoclaw my-assistant destroy [--yes|-y|--force] [--cleanup-gateway|--no-cleanup-gateway] +``` + +### `nemoclaw policy-add` + +Add a policy preset to a sandbox. +Presets extend the baseline network policy with additional endpoints. +Before applying, the command shows which endpoints the preset would open and prompts for confirmation. + +```console +$ nemoclaw my-assistant policy-add +``` + +To apply a specific preset without the interactive picker, pass its name as a positional argument: + +```console +$ nemoclaw my-assistant policy-add pypi --yes +``` + +The positional form is required in scripted workflows. +Set `NEMOCLAW_NON_INTERACTIVE=1` instead of `--yes` if you want the same behavior from an environment variable. +If the preset name is unknown or already applied, the command exits non-zero with a clear error. + +| Flag | Description | +|------|-------------| +| `--from-file ` | Apply a custom preset YAML file instead of a built-in preset | +| `--from-dir ` | Apply every custom preset YAML file in a directory in lexicographic order | +| `--yes`, `--force` | Skip the confirmation prompt (requires a preset name, `--from-file`, or `--from-dir`) | +| `--dry-run` | Preview the endpoints a preset would open without applying changes | + +Use `--dry-run` to audit a preset before applying it: + +```console +$ nemoclaw my-assistant policy-add --dry-run +``` + +Apply a custom preset file when you need to grant access to an endpoint that is not covered by a built-in preset: + +```console +$ nemoclaw my-assistant policy-add --from-file ./presets/my-internal-api.yaml +``` + +For batch workflows, apply all preset files from a directory: + +```console +$ nemoclaw my-assistant policy-add --from-dir ./presets/ --yes +``` + +Review every host in custom preset files before applying them. +Custom presets bypass the built-in preset review process and can widen sandbox egress. + +### `nemoclaw policy-list` + +List available policy presets and show which ones are applied to the sandbox. +The command cross-references the local registry against the live gateway state (via `openshell policy get`), so it flags presets that are applied in one place but not the other. +This catches desync caused by external edits to the gateway policy or stale registry entries after a manual rollback. + +```console +$ nemoclaw my-assistant policy-list +``` + +### `nemoclaw policy-remove` + +Remove a previously applied policy preset from a sandbox. +The command lists only the presets currently applied, prompts you to select one, shows the endpoints that would be removed, and asks for confirmation before narrowing egress. + +```console +$ nemoclaw my-assistant policy-remove +``` + +To remove a specific preset non-interactively, pass its name as a positional argument: + +```console +$ nemoclaw my-assistant policy-remove pypi --yes +``` + +Set `NEMOCLAW_NON_INTERACTIVE=1` as an alternative to `--yes`. +If the preset is unknown or not currently applied, the command exits non-zero with a clear error. + +| Flag | Description | +|------|-------------| +| `--yes`, `--force` | Skip the confirmation prompt (requires a preset name) | +| `--dry-run` | Preview which endpoints would be removed without applying changes | + +Unchecking a preset in the onboard TUI checkbox also removes it from the sandbox. + +### `nemoclaw hosts-add` + +Add a host alias to the sandbox pod template. +Use this when a sandbox needs a stable LAN-only name, such as a local SearXNG or internal model endpoint, without dropping to `docker exec` and `kubectl patch`. + +```console +$ nemoclaw my-assistant hosts-add searxng.local 192.168.1.105 +``` + +The command validates the hostname and IP address, rejects duplicate hostnames, and patches `spec.podTemplate.spec.hostAliases` on the sandbox resource. + +| Flag | Description | +|------|-------------| +| `--dry-run` | Print the JSON patch for the resulting `hostAliases` list without applying it | + +### `nemoclaw hosts-list` + +List host aliases configured on the sandbox resource. + +```console +$ nemoclaw my-assistant hosts-list +``` + +### `nemoclaw hosts-remove` + +Remove a hostname from the sandbox `hostAliases` list. + +```console +$ nemoclaw my-assistant hosts-remove searxng.local +``` + +| Flag | Description | +|------|-------------| +| `--dry-run` | Print the JSON patch for the resulting `hostAliases` list without applying it | + +### `nemoclaw channels list` + +List the messaging channels NemoClaw knows about (`telegram`, `discord`, `slack`) with a short description. +The command is a static reference; it does not consult credentials or the running sandbox. + +```console +$ nemoclaw my-assistant channels list +``` + +### `nemoclaw channels add ` + +Store credentials for a messaging channel (`telegram`, `discord`, or `slack`) and rebuild the sandbox so the image picks up the new channel. +The command prompts for any missing token, registers it with the OpenShell gateway, then asks whether to rebuild immediately. +Running `add` for an already-configured channel simply overwrites the stored tokens — the operation is idempotent. +Channel names are trimmed and lowercased before NemoClaw stores credentials, names bridge providers, or prints rebuild messages. +After a successful add, NemoClaw prints a `policy-add ` hint when a matching built-in network policy preset exists but is not applied to the sandbox yet. + +```console +$ nemoclaw my-assistant channels add telegram +``` + +| Flag | Description | +|------|-------------| +| `--dry-run` | Validate the channel and token inputs without saving credentials or rebuilding | + +Slack requires both `SLACK_BOT_TOKEN` (bot user OAuth) and `SLACK_APP_TOKEN` (app-level Socket Mode token); the command prompts for each in turn. +When `NEMOCLAW_NON_INTERACTIVE=1` is set, any missing token fails fast and no rebuild prompt is shown — instead, the change is queued and you are told to run `nemoclaw rebuild` manually. + +### `nemoclaw channels remove ` + +Clear the stored credentials for a messaging channel and rebuild the sandbox so the image drops the channel. +Running `remove` for a channel that was never configured is a no-op against the credentials file and still triggers the rebuild prompt. + +```console +$ nemoclaw my-assistant channels remove telegram +``` + +| Flag | Description | +|------|-------------| +| `--dry-run` | Report the channel that would be removed without clearing credentials or rebuilding | + +As with `channels add`, `NEMOCLAW_NON_INTERACTIVE=1` skips the rebuild prompt and queues the change for a manual `nemoclaw rebuild`. + +Host-side removal is the supported path because `/sandbox/.openclaw/openclaw.json` is baked into the container image at build time; `openclaw channels remove` inside the sandbox would modify the running config but not persist changes across rebuilds. + +### `nemoclaw channels stop ` + +Pause a single messaging bridge (`telegram`, `discord`, or `slack`) without clearing its credentials. +The channel is marked disabled in the per-sandbox registry, and the sandbox is rebuilt so the onboard step skips registering the bridge with the gateway. +The provider stays registered with the OpenShell gateway, so a later `channels start` brings the bridge back without re-entering tokens. + +```console +$ nemoclaw my-assistant channels stop telegram +``` + +| Flag | Description | +|------|-------------| +| `--dry-run` | Report the channel that would be disabled without updating the registry or rebuilding | + +Use `channels stop` instead of `channels remove` when you want to pause a bridge temporarily. `channels remove` is destructive to credentials; `channels stop` is not. + +### `nemoclaw channels start ` + +Re-enable a channel previously paused with `channels stop`. The channel is removed from the disabled list, the sandbox is rebuilt, and the bridge registers with the gateway again using the stored credentials. + +```console +$ nemoclaw my-assistant channels start telegram +``` + +| Flag | Description | +|------|-------------| +| `--dry-run` | Report the channel that would be re-enabled without updating the registry or rebuilding | + +### `nemoclaw skill install ` + +Deploy a skill directory to a running sandbox. +The command validates the `SKILL.md` frontmatter (a `name` field is required), uploads all non-dot files preserving subdirectory structure, and performs agent-specific post-install steps. + +```console +$ nemoclaw my-assistant skill install ./my-skill/ +``` + +The skill directory must contain a `SKILL.md` file with YAML frontmatter that includes a `name` field. +Skill names must contain only alphanumeric characters, dots, hyphens, and underscores. +OpenClaw plugins are a different kind of extension. To install an OpenClaw plugin, see [Install OpenClaw Plugins](/deployment/install-openclaw-plugins). +Run `nemoclaw skill install --help` to print usage for this subcommand. +If you pass a plugin-shaped directory to `skill install`, the CLI prints a plugin-specific hint instead of treating it as a missing skill file. + +Files with names starting with `.` (dotfiles) are skipped and listed in the output. +Files with unsafe path characters are rejected to prevent shell injection. + +If the skill already exists on the sandbox, the command updates it in place and preserves chat history. +For new installs, the agent session index is refreshed so the agent discovers the skill on the next session. + +### `nemoclaw rebuild` + +Upgrade a sandbox to the current agent version while preserving workspace state. +The command backs up workspace state, destroys the old sandbox (including its host-side Docker image), recreates it with the current image via `onboard --resume`, and restores workspace state into the new sandbox. +Credentials are stripped from backups before storage. +Policy presets applied to the old sandbox are reapplied to the new one so your egress rules survive the rebuild. + +```console +$ nemoclaw my-assistant rebuild [--yes|-y|--force] [--verbose|-v] +``` + +| Flag | Description | +|------|-------------| +| `--yes`, `-y`, `--force` | Skip the confirmation prompt | +| `--verbose`, `-v` | Log SSH commands, exit codes, and session state (also enabled by `NEMOCLAW_REBUILD_VERBOSE=1`) | + +If another terminal has an active SSH session to the sandbox, `rebuild` prints an active-session warning and requires confirmation before destroying the sandbox. +Pass `--yes`, `-y`, or `--force` to skip the prompt in scripted workflows. + +The sandbox must be running for the backup step to succeed. +If an archive command reports partial output while still producing usable data, `rebuild` keeps the captured backup entries and reports only the manifest-defined paths that could not be archived. +If any required state path still cannot be backed up, `rebuild` exits before destroying the original sandbox. +After restore, the command runs `openclaw doctor --fix` for cross-version structure repair. + +### `nemoclaw update` + +Check for a NemoClaw CLI update and, when requested, run the maintained installer flow. +This command is a discoverable CLI wrapper around the supported installer path: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +```console +$ nemoclaw update [--check] [--yes|-y] +``` + +| Flag | Description | +|------|-------------| +| `--check` | Show the current version, latest maintained version, install type, and maintained update command without changing anything | +| `--yes`, `-y` | Skip the confirmation prompt and run the maintained installer flow | + +`nemoclaw update` updates the host-side NemoClaw installation. +It does not replace `nemoclaw upgrade-sandboxes`; use that command to inspect or rebuild existing sandboxes after the CLI has been updated. +When the command is running from a source checkout, it reports that state and does not replace the checkout with a global package install. + +### `nemoclaw upgrade-sandboxes` + +Rebuild sandboxes whose base image is older than the one currently pinned by NemoClaw. +NemoClaw resolves the digest of `ghcr.io/nvidia/nemoclaw/sandbox-base:latest` from the registry, then compares it against the digest each sandbox was created with. +Sandboxes that match the current digest are left alone. + +```console +$ nemoclaw upgrade-sandboxes [--check] [--auto] [--yes|-y] +``` + +| Flag | Description | +|------|-------------| +| `--check` | List stale sandboxes without rebuilding any of them. Exits non-zero if any are stale. | +| `--auto` | Rebuild every stale sandbox without prompting. Used by the installer to upgrade in place. | +| `--yes`, `-y` | Skip the confirmation prompt for the rebuild plan. | + +Each rebuild reuses the same workspace backup-and-restore flow as `nemoclaw rebuild`, so workspace files survive the upgrade. +If the registry is unreachable (offline or firewalled hosts), NemoClaw falls back to the unpinned `:latest` tag and reports that the digest could not be resolved instead of failing. + +### `nemoclaw backup-all` + +Back up all registered running sandboxes to `~/.nemoclaw/rebuild-backups/`. +Sandboxes that are not running are skipped. + +```console +$ nemoclaw backup-all +``` + +The installer calls `backup-all` automatically before onboarding to protect against data loss during OpenShell upgrades. + +### `nemoclaw snapshot create` + +Create a timestamped snapshot of sandbox state. +Snapshots are stored in `~/.nemoclaw/rebuild-backups//`. + +```console +$ nemoclaw my-assistant snapshot create +``` + +| Flag | Description | +|------|-------------| +| `--name
`; + }, + ); + + return converted; +} + +function directiveComponent(kind, title) { + switch (kind) { + case "tip": + return { name: "Tip", title: title.trim() }; + case "warning": + case "caution": + return { name: "Warning", title: title.trim() }; + case "dropdown": + return { name: "Accordion", title: title.trim() || "Details" }; + case "admonition": + return { name: "Warning", title: title.trim() }; + case "seealso": + case "note": + default: + return { name: "Note", title: title.trim() }; + } +} + +function parseListTable(block) { + const rows = []; + let currentRow = null; + let currentCell = null; + + for (const rawLine of block.split("\n")) { + if (!rawLine.trim() || rawLine.trim().startsWith(":")) { + continue; + } + const rowMatch = rawLine.match(/^\s*\*\s+-\s*(.*)$/); + if (rowMatch) { + currentRow = [rowMatch[1].trim()]; + rows.push(currentRow); + currentCell = 0; + continue; + } + const cellMatch = rawLine.match(/^\s+-\s*(.*)$/); + if (cellMatch && currentRow) { + currentRow.push(cellMatch[1].trim()); + currentCell = currentRow.length - 1; + continue; + } + if (currentRow && currentCell !== null) { + currentRow[currentCell] = `${currentRow[currentCell]} ${rawLine.trim()}`.trim(); + } + } + + if (rows.length === 0) { + return ""; + } + const width = Math.max(...rows.map((row) => row.length)); + const normalized = rows.map((row) => [...row, ...Array(width - row.length).fill("")]); + const header = normalized[0]; + const separator = Array(width).fill("---"); + return [header, separator, ...normalized.slice(1)] + .map((row) => `| ${row.map((cell) => cell.replace(/\|/g, "\\|")).join(" | ")} |`) + .join("\n"); +} + +function convertColonDirectives(body) { + const lines = body.split("\n"); + const output = []; + const stack = []; + let skipOptions = false; + + for (let index = 0; index < lines.length; index += 1) { + const line = lines[index]; + const listTable = line.match(/^:{3,}\{list-table\}/); + if (listTable) { + const block = []; + index += 1; + while (index < lines.length && !/^:{3,}\s*$/.test(lines[index])) { + block.push(lines[index]); + index += 1; + } + output.push(parseListTable(block.join("\n"))); + continue; + } + + const open = line.match(/^:{3,}\{([A-Za-z-]+)\}\s*(.*)$/); + if (open) { + const component = directiveComponent(open[1], open[2]); + if (component.title) { + output.push(`<${component.name} title=${esc(component.title)}>`); + } else { + output.push(`<${component.name}>`); + } + stack.push(component.name); + skipOptions = true; + continue; + } + + if (/^:{3,}\s*$/.test(line) && stack.length > 0) { + output.push(``); + skipOptions = false; + continue; + } + + if (skipOptions && /^:\w[\w-]*:/.test(line.trim())) { + continue; + } + if (skipOptions && line.trim() === "") { + skipOptions = false; + output.push(""); + continue; + } + + output.push(line); + } + + while (stack.length > 0) { + output.push(``); + } + + return output.join("\n"); +} + +function routeForLink(sourcePath, target) { + const [withoutFragment, fragment = ""] = target.split("#", 2); + const [withoutQuery, query = ""] = withoutFragment.split("?", 2); + if (!withoutQuery.endsWith(".md")) { + return target; + } + const resolved = path.resolve(path.dirname(sourcePath), withoutQuery); + const relative = path.relative(docsRoot, resolved).replaceAll(path.sep, "/"); + if (relative.startsWith("..")) { + return target; + } + let route = `/${relative.replace(/\.md$/, "")}`; + route = route.replace(/\/index$/, ""); + return `${route}${query ? `?${query}` : ""}${fragment ? `#${fragment}` : ""}`; +} + +function convertLinks(sourcePath, body) { + return body.replace( + /(!?)\[([^\]]*)\]\(([^)\s]+)(\s+["'][^)"']*["'])?\)/g, + (match, bang, label, target, title) => { + if ( + bang || + target.startsWith("http://") || + target.startsWith("https://") || + target.startsWith("mailto:") || + target.startsWith("#") + ) { + return match; + } + return `[${label}](${routeForLink(sourcePath, target)})${title ?? ""}`; + }, + ); +} + +function convert(sourcePath) { + const text = fs.readFileSync(sourcePath, "utf8"); + const [metadata, rawBody] = splitFrontmatter(text); + let body = stripSpdxComment(rawBody); + body = stripInitialH1(body); + body = convertFencedDirectives(sourcePath, body); + body = convertColonDirectives(body); + body = convertLinks(sourcePath, body); + body = convertHtmlComments(body); + body = body.replace(/^\(([A-Za-z0-9_-]+)\)=\s*$/gm, ''); + body = body.replace(/\n{3,}/g, "\n\n").trimEnd(); + return `${frontmatterFor(sourcePath, metadata, rawBody)}${body}\n`; +} + +const files = walk(docsRoot).filter((file) => { + const relative = path.relative(docsRoot, file).replaceAll(path.sep, "/"); + const [top] = relative.split("/"); + return file.endsWith(".md") && !skipFiles.has(relative) && !skipDirs.has(top); +}); + +for (const file of files) { + const target = file.replace(/\.md$/, ".mdx"); + fs.writeFileSync(target, convert(file)); + console.log(path.relative(repoRoot, target)); +} diff --git a/scripts/docs-to-skills.py b/scripts/docs-to-skills.py index 9857912e39..c2da4dd860 100755 --- a/scripts/docs-to-skills.py +++ b/scripts/docs-to-skills.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 """Convert documentation files into Agent Skills (agentskills.io spec). -Reads a directory of Markdown documentation, parses YAML frontmatter and -content structure, groups related pages into coherent skill units, and +Reads a directory of Markdown or Fern MDX documentation, parses YAML frontmatter +and content structure, groups related pages into coherent skill units, and generates SKILL.md files following the Agent Skills specification: https://agentskills.io/specification @@ -11,11 +11,11 @@ Make sure to run this script using the following command to generate the skills and keep the locations and names consistent. ```bash -python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user +python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx ``` What it does: - 1. Scans a docs directory for Markdown files with YAML frontmatter. + 1. Scans a docs directory for Markdown or Fern MDX files with YAML frontmatter. 2. Classifies each page by content type (how_to, concept, reference, get_started) using the frontmatter `content.type` field. 3. Groups pages into skills using one of three strategies: @@ -46,11 +46,11 @@ override specific names when the heuristic doesn't produce the right result. Usage: - python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user - python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run - python3 scripts/docs-to-skills.py docs/ .agents/skills/ --strategy individual --prefix nemoclaw-user - python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --name-map about=overview - python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --exclude "release-notes.md" + python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx + python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx --dry-run + python3 scripts/docs-to-skills.py docs/ .agents/skills/ --strategy individual --prefix nemoclaw-user --doc-platform fern-mdx + python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --name-map about=overview --doc-platform fern-mdx + python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --exclude "release-notes.mdx" --doc-platform fern-mdx """ from __future__ import annotations @@ -140,13 +140,24 @@ def normalize_heading_levels(text: str) -> str: old_prefix = m.group(1) lines[idx] = "#" * new_level + lines[idx][len(old_prefix) :] - return "\n".join(lines) + return space_anchor_headings("\n".join(lines)) + + +def space_anchor_headings(text: str) -> str: + """Keep standalone HTML anchors from tripping heading spacing lint.""" + return re.sub(r'(?m)^()\n(#{1,6}\s)', r"\1\n\n\2", text) # --------------------------------------------------------------------------- # Frontmatter / doc parsing # --------------------------------------------------------------------------- +DOC_PLATFORMS = ("myst-md", "fern-mdx") +DOC_EXTENSIONS = { + "myst-md": ".md", + "fern-mdx": ".mdx", +} + @dataclass class DocPage: @@ -252,45 +263,147 @@ def _current_dict(root: dict, stack: list[tuple[str, dict, int]]) -> dict: return d -def parse_doc(path: Path) -> DocPage: - """Parse a documentation file into a DocPage.""" - raw = path.read_text(encoding="utf-8") - fm, body = parse_yaml_frontmatter(raw) +def _as_string(value: object) -> str: + """Return a stripped string for scalar frontmatter values.""" + return str(value or "").strip() - page = DocPage(path=path, raw=raw, frontmatter=fm, body=body) - # Extract metadata from frontmatter +def _as_list(value: object) -> list[str]: + """Normalize YAML scalar/list frontmatter values into a string list.""" + if isinstance(value, list): + return [str(item).strip() for item in value if str(item).strip()] + if isinstance(value, str): + return [item.strip() for item in value.split(",") if item.strip()] + return [] + + +def _title_from_body(body: str, fallback: str) -> str: + """Read the first H1 from a page body, falling back to the file stem.""" + match = re.search(r"^#\s+(.+)$", body, flags=re.MULTILINE) + return match.group(1).strip() if match else fallback + + +def strip_commented_out_blocks(text: str) -> str: + """Remove hidden Markdown/MDX comments while preserving fenced examples.""" + chunks: list[tuple[bool, str]] = [] + current: list[str] = [] + in_fence = False + + for line in text.splitlines(keepends=True): + if line.lstrip().startswith("```"): + if not in_fence: + if current: + chunks.append((False, "".join(current))) + current = [] + in_fence = True + current.append(line) + if in_fence and len(current) > 1: + chunks.append((True, "".join(current))) + current = [] + in_fence = False + continue + current.append(line) + + if current: + chunks.append((in_fence, "".join(current))) + + def _strip(chunk: str) -> str: + chunk = re.sub(r"", "", chunk, flags=re.DOTALL) + chunk = re.sub(r"\{/\*.*?\*/\}", "", chunk, flags=re.DOTALL) + chunk = re.sub(r"", "", text, flags=re.DOTALL) - text = re.sub(r"", "", text, flags=re.DOTALL) - # Strip "Contents" TOC sections (navigation artifacts, not content) text = re.sub( r"^#{2,3}\s+Contents\s*\n+(?:- [^\n]+\n?)+\n*", @@ -433,6 +546,45 @@ def _format_admonition(title: str, body: str) -> str: return text.strip() +def _mdx_title_attr(attrs: str, default: str) -> str: + """Extract a simple Fern component title attr.""" + match = re.search( + r"""\btitle=(?:"([^"]+)"|'([^']+)'|\{["']([^"']+)["']\})""", + attrs, + ) + if not match: + return default + for group in match.groups(): + if group: + return group + return default + + +def clean_fern_mdx(text: str) -> str: + """Convert Fern MDX components to portable markdown equivalents.""" + text = strip_commented_out_blocks(text) + + for component, default_title in ( + ("Warning", "Warning"), + ("Tip", "Tip"), + ("Note", "Note"), + ("Info", "Note"), + ("Accordion", "Details"), + ): + text = re.sub( + rf"<{component}\b([^>]*)>\s*(.*?)\s*", + lambda m, default=default_title: _format_admonition( + _mdx_title_attr(m.group(1), default), m.group(2) + ), + text, + flags=re.DOTALL, + ) + + # Collapse excess blank lines. + text = re.sub(r"\n{3,}", "\n\n", text) + return text.strip() + + def resolve_includes(text: str, source_dir: Path) -> str: """Resolve MyST {include} directives by inlining referenced file content. @@ -492,6 +644,7 @@ def rewrite_doc_paths( docs_dir: Path, doc_to_skill: dict[str, str], html_baseurl: str | None = None, + doc_platform: str = "myst-md", ) -> str: """Resolve relative doc paths to skill cross-refs or published URLs. @@ -500,8 +653,8 @@ def rewrite_doc_paths( repo). Rewrite precedence for each Markdown link ``[text](path)``: 1. If the target is an external URL, an anchor, or a ``mailto:`` - reference, or the target is not a ``.md`` / ``.html`` file, leave - it untouched. + reference, or the target is not a recognized doc link for the selected + platform, leave it untouched. 2. If the target resolves to a doc that has a generated skill, replace the whole link with ``text (use the `` skill)``. 3. If the target is a page inside ``docs/``, emit @@ -517,6 +670,8 @@ def rewrite_doc_paths( repo_root = docs_dir.parent source_dir = source_page.path.parent + doc_extension = DOC_EXTENSIONS.get(doc_platform, ".md") + def _to_html_url(resolved: Path, frag: str) -> str | None: """Published URL for a doc under ``docs/``; ``None`` otherwise.""" if not html_baseurl: @@ -528,6 +683,32 @@ def _to_html_url(resolved: Path, frag: str) -> str | None: html_path = rel_to_docs.with_suffix(".html").as_posix() return f"{html_baseurl}{html_path}{frag}" + def _candidate_doc_paths(path_no_frag: str) -> list[Path]: + """Resolve a Markdown/Fern link target to possible source files.""" + if doc_platform == "fern-mdx": + route = path_no_frag.lstrip("/") + if path_no_frag.startswith("/"): + if not route: + return [] + base = docs_dir / route + else: + base = source_dir / path_no_frag + if base.suffix: + return [base.resolve()] + return [ + base.with_suffix(doc_extension).resolve(), + (base / f"index{doc_extension}").resolve(), + ] + + suffix = Path(path_no_frag).suffix + if suffix not in {".md", ".mdx", ".html"}: + return [] + + resolved = (source_dir / path_no_frag).resolve() + if suffix == ".html": + return [resolved.with_suffix(doc_extension)] + return [resolved] + def _resolve_link(match: re.Match) -> str: link_text = match.group(1) raw_path = match.group(2) @@ -544,27 +725,29 @@ def _resolve_link(match: re.Match) -> str: path_no_frag = raw_path frag = "" - # Skip non-doc files - if not path_no_frag.endswith(".md") and not path_no_frag.endswith(".html"): - return match.group(0) + if "?" in path_no_frag: + path_no_frag, _, _query = path_no_frag.partition("?") - # Resolve relative path against the source doc's directory - resolved = (source_dir / path_no_frag).resolve() - try: - rel_to_repo = resolved.relative_to(repo_root) - except ValueError: + candidates = _candidate_doc_paths(path_no_frag) + if not candidates: return match.group(0) # Check if target doc maps to a generated skill - rel_str = str(rel_to_repo) - if rel_str in doc_to_skill: - skill_name = doc_to_skill[rel_str] - return f"{link_text} (use the `{skill_name}` skill)" + for resolved in candidates: + try: + rel_to_repo = resolved.relative_to(repo_root) + except ValueError: + continue + rel_str = rel_to_repo.as_posix() + if rel_str in doc_to_skill: + skill_name = doc_to_skill[rel_str] + return f"{link_text} (use the `{skill_name}` skill)" # Self-contained fallback: published URL or strip the hyperlink. - url = _to_html_url(resolved, frag) - if url is not None: - return f"[{link_text}]({url})" + for resolved in candidates: + url = _to_html_url(resolved, frag) + if url is not None: + return f"[{link_text}]({url})" return link_text # Rewrite markdown links: [text](path) @@ -669,14 +852,29 @@ def _split_description_trigger(desc: str) -> tuple[str, str]: return covers, trigger -_WARNING_BLOCK_RE = re.compile( - r":::\{warning\}(?:[ \t]+([^\n]+))?\n(.*?)\n:::", +_MYST_WARNING_BLOCK_RE = re.compile( + r":{3,}\{warning\}(?:[ \t]+([^\n]+))?\n(.*?)\n:{3,}", re.DOTALL, ) +_FERN_WARNING_BLOCK_RE = re.compile(r"]*)>(.*?)
", re.DOTALL) + + +def _warning_blocks(page: DocPage, doc_platform: str) -> list[tuple[str, str]]: + """Return ``(title, body)`` pairs for warning-like source blocks.""" + body = strip_commented_out_blocks(page.body) + if doc_platform == "fern-mdx": + return [ + (_mdx_title_attr(m.group(1), ""), m.group(2)) + for m in _FERN_WARNING_BLOCK_RE.finditer(body) + ] + return [ + ((m.group(1) or "").strip(), m.group(2)) + for m in _MYST_WARNING_BLOCK_RE.finditer(body) + ] -def _extract_gotchas(pages: list[DocPage]) -> list[str]: - """Pull ``:::{warning}`` admonitions out of the source pages. +def _extract_gotchas(pages: list[DocPage], doc_platform: str = "myst-md") -> list[str]: + """Pull warning admonitions out of the source pages. Returns a list of markdown bullets suitable for a top-level ``## Gotchas`` section. The admonition stays in place inline, but @@ -692,9 +890,9 @@ def _extract_gotchas(pages: list[DocPage]) -> list[str]: bullets: list[str] = [] seen: set[str] = set() for page in pages: - for m in _WARNING_BLOCK_RE.finditer(page.body): - title = (m.group(1) or "").strip().rstrip(".!?") - body = m.group(2).strip() + for raw_title, raw_body in _warning_blocks(page, doc_platform): + title = raw_title.strip().rstrip(".!?") + body = raw_body.strip() # Strip any directive metadata lines such as ``:class: ...`` body_lines = [ ln @@ -1145,6 +1343,7 @@ def generate_skill( docs_dir: Path | None = None, doc_to_skill: dict[str, str] | None = None, html_baseurl: str | None = None, + doc_platform: str = "myst-md", dry_run: bool = False, ) -> dict: """Generate a complete skill directory from a group of doc pages. @@ -1159,7 +1358,10 @@ def generate_skill( """ def _clean(text: str, source: DocPage) -> str: """Apply directive cleanup and path rewriting for a source page.""" - result = clean_myst_directives(text) + if doc_platform == "fern-mdx": + result = clean_fern_mdx(text) + else: + result = clean_myst_directives(text) if docs_dir and doc_to_skill is not None: result = rewrite_doc_paths( result, @@ -1167,6 +1369,7 @@ def _clean(text: str, source: DocPage) -> str: docs_dir, doc_to_skill, html_baseurl=html_baseurl, + doc_platform=doc_platform, ) return result @@ -1207,7 +1410,7 @@ def _clean(text: str, source: DocPage) -> str: # pages at the top so the agent sees non-obvious corrections before it # commits to a path through the steps. The warnings stay in place # inline; this section is a directed summary, not a replacement. - gotchas = _extract_gotchas(procedures) + gotchas = _extract_gotchas(procedures, doc_platform=doc_platform) if gotchas: lines.append("## Gotchas") lines.append("") @@ -1334,7 +1537,10 @@ def _clean(text: str, source: DocPage) -> str: ref_files: dict[str, str] = {} for rp in deferred_procedures + reference_pages + context_pages: ref_name = rp.path.stem + ".md" - body = normalize_heading_levels(_clean(rp.body, rp)) + body = _clean(rp.body, rp) + if doc_platform == "fern-mdx" and rp.title and not body.startswith("# "): + body = f"# {rp.title}\n\n{body}".rstrip() + body = normalize_heading_levels(body) ref_files[ref_name] = body # --- Write output --- @@ -1436,33 +1642,43 @@ def group_by_content_type(pages: list[DocPage]) -> dict[str, list[DocPage]]: } -def scan_docs(docs_dir: Path) -> list[DocPage]: +def _is_excluded_doc(path: Path, doc_platform: str) -> bool: + """Return whether a page should be skipped for the selected source format.""" + if path.name in EXCLUDED_PATTERNS: + return True + if doc_platform == "fern-mdx" and path.with_suffix(".md").name in EXCLUDED_PATTERNS: + return True + return False + + +def scan_docs(docs_dir: Path, doc_platform: str = "myst-md") -> list[DocPage]: """Recursively scan a directory for documentation markdown files.""" pages: list[DocPage] = [] - docs_root_index = (docs_dir / "index.md").resolve() - for md_path in sorted(docs_dir.rglob("*.md")): + doc_extension = DOC_EXTENSIONS[doc_platform] + docs_root_index = (docs_dir / f"index{doc_extension}").resolve() + for doc_path in sorted(docs_dir.rglob(f"*{doc_extension}")): # Skip excluded files - if md_path.name in EXCLUDED_PATTERNS: + if _is_excluded_doc(doc_path, doc_platform): continue # Skip the top-level docs/index.md (Sphinx landing page — mostly # boilerplate). Subdirectory index.md files (for example # docs/get-started/platform-setup/index.md) are hub pages with # real content and should be included so links to them can # resolve to a generated skill instead of a file path. - if md_path.resolve() == docs_root_index: + if doc_path.resolve() == docs_root_index: continue # Skip include fragments and templates - if md_path.parent.name.startswith("_"): + if doc_path.parent.name.startswith("_"): continue # Skip build artifacts - if "_build" in md_path.parts: + if "_build" in doc_path.parts: continue try: - page = parse_doc(md_path) + page = parse_doc(doc_path, doc_platform=doc_platform) pages.append(page) except Exception as e: - print(f" warning: failed to parse {md_path}: {e}", file=sys.stderr) + print(f" warning: failed to parse {doc_path}: {e}", file=sys.stderr) return pages @@ -1484,10 +1700,10 @@ def main(): defer siblings Examples: - %(prog)s docs/ .agents/skills/ --prefix nemoclaw-user - %(prog)s docs/ .agents/skills/ --strategy individual --prefix nemoclaw-user - %(prog)s docs/ .agents/skills/ --prefix nemoclaw-user --name-map about=overview - %(prog)s docs/ .agents/skills/ --prefix nemoclaw-user --dry-run + %(prog)s docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx + %(prog)s docs/ .agents/skills/ --strategy individual --prefix nemoclaw-user --doc-platform fern-mdx + %(prog)s docs/ .agents/skills/ --prefix nemoclaw-user --name-map about=overview --doc-platform fern-mdx + %(prog)s docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx --dry-run """), ) parser.add_argument( @@ -1505,6 +1721,12 @@ def main(): default="smart", help="Grouping strategy (default: smart)", ) + parser.add_argument( + "--doc-platform", + choices=DOC_PLATFORMS, + default="myst-md", + help="Documentation source format to parse (default: myst-md)", + ) parser.add_argument( "--dry-run", action="store_true", @@ -1555,8 +1777,8 @@ def main(): PROJECT_STOP.update(args.prefix.lower().split("-")) PROJECT_STOP.update(args.prefix.lower().split("_")) - print(f"Scanning {args.docs_dir}...") - pages = scan_docs(args.docs_dir) + print(f"Scanning {args.docs_dir} as {args.doc_platform}...") + pages = scan_docs(args.docs_dir, doc_platform=args.doc_platform) print(f" Found {len(pages)} documentation pages") # Resolve {include} directives so inlined content is available for @@ -1603,7 +1825,7 @@ def main(): for page in group_pages: try: rel = page.path.resolve().relative_to(repo_root) - doc_to_skill[str(rel)] = sname + doc_to_skill[rel.as_posix()] = sname except ValueError: pass @@ -1633,6 +1855,7 @@ def main(): docs_dir=docs_dir_resolved, doc_to_skill=doc_to_skill, html_baseurl=html_baseurl, + doc_platform=args.doc_platform, dry_run=args.dry_run, ) summaries.append(summary) diff --git a/test/docs-to-skills-comments.test.ts b/test/docs-to-skills-comments.test.ts new file mode 100644 index 0000000000..7f44d695ff --- /dev/null +++ b/test/docs-to-skills-comments.test.ts @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { spawnSync } from "node:child_process"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, ".."); +const converterPath = path.join(repoRoot, "scripts", "docs-to-skills.py"); + +function listMarkdownFiles(root: string): string[] { + const files: string[] = []; + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + const fullPath = path.join(root, entry.name); + if (entry.isDirectory()) { + files.push(...listMarkdownFiles(fullPath)); + continue; + } + if (entry.isFile() && entry.name.endsWith(".md")) { + files.push(fullPath); + } + } + return files.sort(); +} + +describe("docs-to-skills comments", () => { + it("omits source HTML and MDX comments without changing fenced examples", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-docs-to-skills-")); + try { + const docsDir = path.join(tempDir, "docs"); + const outputDir = path.join(tempDir, "skills"); + fs.mkdirSync(docsDir, { recursive: true }); + fs.writeFileSync( + path.join(docsDir, "comment-test.mdx"), + [ + "---", + "title: Comment Test", + "description-agent: Use when validating docs-to-skills comment handling.", + "content:", + " type: how_to", + "---", + "# Comment Test", + "", + "Visible introduction.", + "", + "", + "", + "{/*", + "", + "This warning should not become a gotcha.", + "", + "*/}", + "", + '', + "## Visible Step", + "", + "Keep these examples literal:", + "", + "```md", + "", + "{/* keep mdx comment in code */}", + "```", + "", + ].join("\n"), + ); + + const result = spawnSync( + "python3", + [ + converterPath, + docsDir, + outputDir, + "--prefix", + "test", + "--doc-platform", + "fern-mdx", + ], + { cwd: repoRoot, encoding: "utf8" }, + ); + + expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0); + const generated = listMarkdownFiles(outputDir) + .map((file) => fs.readFileSync(file, "utf8")) + .join("\n"); + + expect(generated).toContain("Visible introduction."); + expect(generated).toContain('\n\n## Step 1: Visible Step'); + expect(generated).toContain("## Step 1: Visible Step"); + expect(generated).not.toContain("Hidden HTML comment."); + expect(generated).not.toContain("Hidden Heading"); + expect(generated).not.toContain("Hidden warning"); + expect(generated).not.toContain("This warning should not become a gotcha."); + expect(generated).toContain(""); + expect(generated).toContain("{/* keep mdx comment in code */}"); + } finally { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + }); +}); diff --git a/test/e2e/e2e-cloud-experimental/check-docs.sh b/test/e2e/e2e-cloud-experimental/check-docs.sh index 6a436936aa..f932736ffb 100755 --- a/test/e2e/e2e-cloud-experimental/check-docs.sh +++ b/test/e2e/e2e-cloud-experimental/check-docs.sh @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # # Documentation checks (default: all): -# 1) Markdown links — local paths exist; optional curl for unique http(s) URLs. +# 1) Markdown/MDX links — local paths exist; optional curl for unique http(s) URLs. # 2) CLI parity — `nemoclaw --help` vs ### `nemoclaw …` in docs/reference/commands.md. # # Usage (from repo root): @@ -12,7 +12,7 @@ # test/e2e/e2e-cloud-experimental/check-docs.sh --only-cli # test/e2e/e2e-cloud-experimental/check-docs.sh --local-only # CHECK_DOC_LINKS_REMOTE=0 test/e2e/e2e-cloud-experimental/check-docs.sh -# test/e2e/e2e-cloud-experimental/check-docs.sh path/to/a.md +# test/e2e/e2e-cloud-experimental/check-docs.sh path/to/a.md path/to/b.mdx # # Environment: # CHECK_DOC_LINKS_REMOTE If 0, skip http(s) probes for links check. @@ -42,13 +42,13 @@ WITH_SKILLS=0 usage() { cat <<'EOF' -Documentation checks: Markdown links + nemoclaw --help vs commands reference +Documentation checks: Markdown/MDX links + nemoclaw --help vs commands reference + install.sh --help vs canonical provider list. -Usage: test/e2e/e2e-cloud-experimental/check-docs.sh [options] [extra.md ...] +Usage: test/e2e/e2e-cloud-experimental/check-docs.sh [options] [extra.md/.mdx ...] Options: - --only-links Run only the Markdown link check. + --only-links Run only the Markdown/MDX link check. --only-cli Run only the CLI help vs docs/reference/commands.md check (includes both command-level and flag-level parity). --only-install Run only the install.sh --help vs canonical provider check. @@ -575,7 +575,7 @@ collect_default_docs() { [[ -f "$f" ]] && printf '%s\n' "$f" done if [[ -d "$REPO_ROOT/docs" ]]; then - find "$REPO_ROOT/docs" -type f -name '*.md' | LC_ALL=C sort + find "$REPO_ROOT/docs" -type f \( -name '*.md' -o -name '*.mdx' \) | LC_ALL=C sort fi if [[ "$WITH_SKILLS" -eq 1 && -d "$REPO_ROOT/.agents/skills" ]]; then find "$REPO_ROOT/.agents/skills" -type f -name '*.md' | LC_ALL=C sort @@ -660,6 +660,21 @@ check_local_ref() { return 0 fi + if [[ "$stripped" == /* ]]; then + local site_path="${stripped#/}" + local candidate + for candidate in \ + "$REPO_ROOT/docs/$site_path" \ + "$REPO_ROOT/docs/$site_path.mdx" \ + "$REPO_ROOT/docs/$site_path.md" \ + "$REPO_ROOT/docs/$site_path/index.mdx" \ + "$REPO_ROOT/docs/$site_path/index.md"; do + [[ -e "$candidate" ]] && return 0 + done + echo "check-docs: [links] broken site route in $md_path:$line_no -> $target" >&2 + return 1 + fi + if (cd "$(dirname "$md_path")" && [[ -e "$stripped" ]]); then return 0 fi @@ -752,7 +767,7 @@ run_links_check() { if [[ "$WITH_SKILLS" -eq 1 ]]; then log "[links] scope: default doc set + .agents/skills/**/*.md" else - log "[links] scope: README, CONTRIBUTING, SECURITY, spark-install, CODE_OF_CONDUCT, .github PR template, docs/**/*.md" + log "[links] scope: README, CONTRIBUTING, SECURITY, spark-install, CODE_OF_CONDUCT, .github PR template, docs/**/*.{md,mdx}" fi if [[ "$CHECK_DOC_LINKS_REMOTE" != 0 ]]; then log "[links] remote: curl unique http(s) targets (disable: CHECK_DOC_LINKS_REMOTE=0 or --local-only)" diff --git a/test/fern-frontmatter.test.ts b/test/fern-frontmatter.test.ts new file mode 100644 index 0000000000..4fffd3e555 --- /dev/null +++ b/test/fern-frontmatter.test.ts @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; +import YAML from "yaml"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, ".."); +const docsRoot = path.join(repoRoot, "docs"); +const skipFiles = new Set(["CONTRIBUTING.md", "index.md"]); +const requiredScalarFrontmatterKeys = ["title", "description", "description-agent"]; + +function listMarkdownFiles(root: string): string[] { + const files: string[] = []; + + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + const fullPath = path.join(root, entry.name); + + if (entry.isDirectory()) { + files.push(...listMarkdownFiles(fullPath)); + continue; + } + + if (entry.isFile() && entry.name.endsWith(".md")) { + files.push(fullPath); + } + } + + return files.sort(); +} + +function readFrontmatter(file: string): Record { + const raw = fs.readFileSync(file, "utf8"); + const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/); + if (!match) { + throw new Error(`${path.relative(repoRoot, file)} must start with YAML frontmatter`); + } + return YAML.parse(match[1]) ?? {}; +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function requireRecord(value: unknown, message: string): Record { + expect(isRecord(value), message).toBe(true); + if (!isRecord(value)) { + throw new Error(message); + } + return value; +} + +function expectNonEmptyString(value: unknown, message: string) { + expect(value, message).toEqual(expect.any(String)); + expect(String(value).trim().length, message).toBeGreaterThan(0); +} + +describe("Fern frontmatter", () => { + const convertedMarkdownFiles = listMarkdownFiles(docsRoot).filter((file) => { + const relative = path.relative(docsRoot, file).replaceAll(path.sep, "/"); + return !skipFiles.has(relative); + }); + + it("finds converted Markdown sources", () => { + expect(convertedMarkdownFiles.length).toBeGreaterThan(0); + }); + + for (const markdownFile of convertedMarkdownFiles) { + const mdxFile = markdownFile.replace(/\.md$/, ".mdx"); + const relPath = path.relative(repoRoot, mdxFile); + + it(`includes agent-routing frontmatter for ${relPath}`, () => { + expect(fs.existsSync(mdxFile), `${relPath} was not generated`).toBe(true); + + const sourceFrontmatter = readFrontmatter(markdownFile); + const fernFrontmatter = readFrontmatter(mdxFile); + for (const key of requiredScalarFrontmatterKeys) { + expectNonEmptyString(fernFrontmatter[key], `${relPath} has invalid frontmatter.${key}`); + } + expect(fernFrontmatter.keywords, `${relPath} must preserve frontmatter.keywords`).toEqual( + sourceFrontmatter.keywords, + ); + + const sourceContent = requireRecord( + sourceFrontmatter.content, + `${path.relative(repoRoot, markdownFile)} is missing frontmatter.content`, + ); + const fernContent = requireRecord( + fernFrontmatter.content, + `${relPath} is missing frontmatter.content`, + ); + expect(fernContent.type, `${relPath} must preserve frontmatter.content.type`).toBe( + sourceContent.type, + ); + + const sourceSkillPriority = isRecord(sourceFrontmatter.skill) + ? sourceFrontmatter.skill.priority + : sourceFrontmatter.skill_priority; + if (sourceSkillPriority !== undefined && sourceSkillPriority !== "") { + const fernSkill = requireRecord( + fernFrontmatter.skill, + `${relPath} is missing frontmatter.skill`, + ); + expect(fernSkill.priority, `${relPath} must preserve frontmatter.skill.priority`).toBe( + sourceSkillPriority, + ); + } + }); + } +});