From 94073632a73c3cd0e3f6fac9ebc49865974b5148 Mon Sep 17 00:00:00 2001 From: Miyoung Choi Date: Wed, 3 Jun 2026 17:02:34 -0700 Subject: [PATCH 1/3] test: reject file extensions in Fern route links --- docs/reference/commands-nemohermes.mdx | 2 +- docs/reference/commands.mdx | 2 +- test/check-docs-links.test.ts | 53 +++++++++++++++++++ test/e2e/e2e-cloud-experimental/check-docs.sh | 21 ++++++-- 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/docs/reference/commands-nemohermes.mdx b/docs/reference/commands-nemohermes.mdx index 7cbc697cc4..11180a30a7 100644 --- a/docs/reference/commands-nemohermes.mdx +++ b/docs/reference/commands-nemohermes.mdx @@ -1665,7 +1665,7 @@ These flags change defaults for commands that manage existing sandboxes. These variables seed defaults for `nemohermes deploy` and `nemohermes onboard --remote`, which provision a sandbox on a Brev instance. Each has a flag equivalent on `deploy`; the env var lets non-interactive runs skip the prompt. -For narrative how-to coverage of `NEMOCLAW_BREV_PROVIDER` and `NEMOCLAW_GPU`, see [Deploy to Remote GPU](../deployment/deploy-to-remote-gpu.mdx). +For narrative how-to coverage of `NEMOCLAW_BREV_PROVIDER` and `NEMOCLAW_GPU`, see [Deploy to Remote GPU](../deployment/deploy-to-remote-gpu). | Variable | Default | Effect | |----------|---------|--------| diff --git a/docs/reference/commands.mdx b/docs/reference/commands.mdx index a676ff3ad1..caa202c465 100644 --- a/docs/reference/commands.mdx +++ b/docs/reference/commands.mdx @@ -1934,7 +1934,7 @@ These flags change defaults for commands that manage existing sandboxes. These variables seed defaults for `$$nemoclaw deploy` and `$$nemoclaw onboard --remote`, which provision a sandbox on a Brev instance. Each has a flag equivalent on `deploy`; the env var lets non-interactive runs skip the prompt. -For narrative how-to coverage of `NEMOCLAW_BREV_PROVIDER` and `NEMOCLAW_GPU`, see [Deploy to Remote GPU](../deployment/deploy-to-remote-gpu.mdx). +For narrative how-to coverage of `NEMOCLAW_BREV_PROVIDER` and `NEMOCLAW_GPU`, see [Deploy to Remote GPU](../deployment/deploy-to-remote-gpu). | Variable | Default | Effect | |----------|---------|--------| diff --git a/test/check-docs-links.test.ts b/test/check-docs-links.test.ts index bbb2b1148c..29019e157b 100644 --- a/test/check-docs-links.test.ts +++ b/test/check-docs-links.test.ts @@ -95,6 +95,59 @@ describe("check-docs link validation", () => { expect(slugAliasResult.status).toBe(0); }); + it("rejects .md/.mdx suffixes for links that resolve as Fern routes", () => { + const tempPath = path.join(REPO_ROOT, "docs", "check-docs-route-suffix-temp.mdx"); + const navPath = path.join(os.tmpdir(), `nemoclaw-check-docs-nav-${process.pid}.yml`); + try { + fs.writeFileSync( + tempPath, + [ + "---", + 'title: "Temporary Link Check Page"', + "---", + "", + "[Wrong](deployment/deploy-to-remote-gpu.mdx)", + "[Right](deployment/deploy-to-remote-gpu)", + "", + ].join("\n"), + ); + fs.writeFileSync( + navPath, + [ + "navigation:", + " - tab: user-guide", + " variants:", + " - title: OpenClaw", + " slug: openclaw", + " layout:", + ' - page: "Temp"', + " path: check-docs-route-suffix-temp.mdx", + " slug: temp", + ' - section: "Deployment"', + " slug: deployment", + " contents:", + ' - page: "Deploy"', + " path: deployment/deploy-to-remote-gpu.mdx", + " slug: deploy-to-remote-gpu", + "", + ].join("\n"), + ); + + const result = runCheckDocs(tempPath, { CHECK_DOCS_FERN_NAV_YML: navPath }); + + expect(result.status).toBe(1); + expect(`${result.stdout}${result.stderr}`).toContain( + `route-style link should omit .md/.mdx extension in ${tempPath}:5 -> deployment/deploy-to-remote-gpu.mdx`, + ); + expect(`${result.stdout}${result.stderr}`).not.toContain( + `broken local link in ${tempPath}:6 -> deployment/deploy-to-remote-gpu`, + ); + } finally { + fs.rmSync(tempPath, { force: true }); + fs.rmSync(navPath, { force: true }); + } + }); + it("rejects broken Fern site routes", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-check-docs-bad-fern-")); const mdPath = path.join(tempDir, "guide.mdx"); diff --git a/test/e2e/e2e-cloud-experimental/check-docs.sh b/test/e2e/e2e-cloud-experimental/check-docs.sh index bfd52daaae..afab25e4bd 100755 --- a/test/e2e/e2e-cloud-experimental/check-docs.sh +++ b/test/e2e/e2e-cloud-experimental/check-docs.sh @@ -966,6 +966,13 @@ site_source_ref_exists() { return 1 } +has_markdown_extension() { + case "$1" in + *.md | *.mdx) return 0 ;; + *) return 1 ;; + esac +} + check_local_ref() { local md_path="$1" line_no="$2" target="$3" local stripped @@ -991,6 +998,10 @@ check_local_ref() { fern_route_exists "$stripped" _fern_rc=$? set -e + if [[ "$_fern_rc" -eq 0 ]] && has_markdown_extension "$stripped"; then + echo "check-docs: [links] route-style link should omit .md/.mdx extension in $md_path:$line_no -> $target" >&2 + return 1 + fi if [[ "$_fern_rc" -eq 0 ]]; then return 0 elif [[ "$_fern_rc" -eq 3 ]]; then @@ -1003,19 +1014,23 @@ check_local_ref() { return 1 fi - if source_ref_exists "$(dirname "$md_path")" "$stripped"; then - return 0 - fi local _fern_relative_rc set +e fern_relative_ref_exists "$md_path" "$stripped" _fern_relative_rc=$? set -e + if [[ "$_fern_relative_rc" -eq 0 ]] && has_markdown_extension "$stripped"; then + echo "check-docs: [links] route-style link should omit .md/.mdx extension in $md_path:$line_no -> $target" >&2 + return 1 + fi if [[ "$_fern_relative_rc" -eq 0 ]]; then return 0 elif [[ "$_fern_relative_rc" -eq 3 ]]; then return 1 fi + if source_ref_exists "$(dirname "$md_path")" "$stripped"; then + return 0 + fi echo "check-docs: [links] broken local link in $md_path:$line_no -> $target" >&2 return 1 } From 3dce4fcce893a22dc7bf630e4f93774bb4844b37 Mon Sep 17 00:00:00 2001 From: Miyoung Choi Date: Wed, 3 Jun 2026 17:58:59 -0700 Subject: [PATCH 2/3] docs: fix links in hermes variant and the link checker --- docs/about/ecosystem-hermes.mdx | 2 +- docs/about/how-it-works.mdx | 4 +- docs/about/overview.mdx | 4 +- docs/about/release-notes.mdx | 2 +- docs/get-started/prerequisites.mdx | 2 +- docs/get-started/windows-preparation.mdx | 6 +- docs/index.mdx | 2 +- docs/index.yml | 2 +- docs/inference/inference-options.mdx | 2 + docs/inference/use-local-inference.mdx | 6 +- docs/manage-sandboxes/lifecycle.mdx | 2 +- docs/manage-sandboxes/messaging-channels.mdx | 2 + docs/reference/commands-nemohermes.mdx | 13 --- docs/reference/commands.mdx | 13 --- docs/reference/troubleshooting.mdx | 14 ++- docs/security/best-practices.mdx | 6 +- fern/docs.yml | 12 ++- scripts/sync-agent-variant-docs.ts | 103 ++++++++++++++----- 18 files changed, 125 insertions(+), 72 deletions(-) diff --git a/docs/about/ecosystem-hermes.mdx b/docs/about/ecosystem-hermes.mdx index f1ee332ee2..9c892a899f 100644 --- a/docs/about/ecosystem-hermes.mdx +++ b/docs/about/ecosystem-hermes.mdx @@ -99,4 +99,4 @@ Use the following table to decide when to use NemoHermes versus OpenShell alone. - [Overview](overview) describes what NemoClaw is, including capabilities, benefits, and use cases. - [How It Works](how-it-works) describes how NemoClaw runs, the blueprint, sandbox creation, routing, and protection layers for Hermes. - [Architecture](../reference/architecture) shows the repository structure and technical diagrams. -- [Quickstart with Hermes](../get-started/quickstart-hermes) installs NemoClaw and launches your first Hermes sandbox. +- [Quickstart with Hermes](../get-started/quickstart) installs NemoClaw and launches your first Hermes sandbox. diff --git a/docs/about/how-it-works.mdx b/docs/about/how-it-works.mdx index 268de0b199..2c52d95b60 100644 --- a/docs/about/how-it-works.mdx +++ b/docs/about/how-it-works.mdx @@ -135,8 +135,8 @@ When the agent tries to reach an unlisted host, OpenShell blocks the request and -- Read [Ecosystem](ecosystem-hermes) for stack-level relationships and NemoClaw versus OpenShell-only paths. -- Follow [Quickstart with Hermes](../get-started/quickstart-hermes) to launch your first sandbox. +- Read [Ecosystem](ecosystem) for stack-level relationships and NemoClaw versus OpenShell-only paths. +- Follow [Quickstart with Hermes](../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. - For details on the baseline rules, refer to [Network Policies](../reference/network-policies). diff --git a/docs/about/overview.mdx b/docs/about/overview.mdx index 04d4174e86..5361d3337c 100644 --- a/docs/about/overview.mdx +++ b/docs/about/overview.mdx @@ -82,8 +82,8 @@ Navigate to the following topics to learn more about NemoClaw and how to install - [Architecture Overview](how-it-works) to understand how NemoClaw works. -- [Ecosystem](ecosystem-hermes) to understand how Hermes, OpenShell, and NemoClaw relate in the wider stack, and when to use NemoClaw versus OpenShell. -- [Quickstart with Hermes](../get-started/quickstart-hermes) to install NemoClaw and run your first Hermes sandbox with `$$nemoclaw`. +- [Ecosystem](ecosystem) to understand how Hermes, OpenShell, and NemoClaw relate in the wider stack, and when to use NemoClaw versus OpenShell. +- [Quickstart with Hermes](../get-started/quickstart) to install NemoClaw and run your first Hermes sandbox with `$$nemoclaw`. - [Agent Skills](../resources/agent-skills) to load NemoClaw guidance into an AI coding assistant. - [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 index edeeae011a..3b14cd765e 100644 --- a/docs/about/release-notes.mdx +++ b/docs/about/release-notes.mdx @@ -51,7 +51,7 @@ NemoClaw v0.0.54 updates messaging activation, Windows WSL onboarding, NemoHerme - Generated OpenClaw config now marks Telegram, Discord, Slack, and WhatsApp as enabled at the channel level. Selected messaging plugins are pinned during the image build, and `channels add` verifies Telegram, Discord, and Slack bridge startup after the rebuild instead of leaving silent channel failures for later debugging. For more information, refer to [Messaging Channels](../manage-sandboxes/messaging-channels). - The Windows bootstrap flow waits for Ubuntu account creation before touching Docker settings, enables Docker Desktop WSL integration for the target distro, avoids changing the global WSL default distro, and adds WSL-specific Docker reachability hints during onboarding. For more information, refer to [Prepare Windows for NemoClaw](../get-started/prerequisites/windows-preparation). - Windows-host Ollama setup inside WSL now requires the Docker Desktop WSL integration path. NemoClaw still shows Windows-host Ollama options when it detects them, but labels the Docker Desktop requirement and blocks unsupported native Docker-in-WSL selections before it tries to start or install Ollama. For more information, refer to [Use a Local Inference Server](../inference/use-local-inference). -- NemoHermes can expose the optional native Hermes web dashboard separately from the OpenAI-compatible API. Set `NEMOCLAW_HERMES_DASHBOARD=1` before onboarding to start and forward the dashboard on port `9119`, with `NEMOCLAW_HERMES_DASHBOARD_PORT` and `NEMOCLAW_HERMES_DASHBOARD_TUI` available for port and TUI tab control. For more information, refer to [NemoClaw Quickstart with Hermes](../../hermes/get-started/quickstart-hermes). +- NemoHermes can expose the optional native Hermes web dashboard separately from the OpenAI-compatible API. Set `NEMOCLAW_HERMES_DASHBOARD=1` before onboarding to start and forward the dashboard on port `9119`, with `NEMOCLAW_HERMES_DASHBOARD_PORT` and `NEMOCLAW_HERMES_DASHBOARD_TUI` available for port and TUI tab control. For more information, refer to [NemoClaw Quickstart with Hermes](../../hermes/get-started/quickstart). - Onboarding diagnostics include more copy-paste-ready recovery hints. Invalid sandbox names now include a `Try: ` line when NemoClaw can derive a valid name, and non-interactive NVIDIA Endpoints setup prints the exact `export NVIDIA_API_KEY=nvapi-...` shape when the key is missing. For more information, refer to [NemoClaw CLI Commands Reference](../reference/commands). - Homebrew stays on the Linuxbrew prefix while exposing installed formula commands in sandbox shell sessions, the `/nemoclaw` slash command activates at OpenClaw startup again, Hermes rebuilds tolerate older release tarballs that lack optional UI package lockfiles, and device scope-upgrade approvals recover without being pinned to the old gateway-scoped request. For more information, refer to [Common NemoClaw Integration Policy Examples](../network-policy/integration-policy-examples). - The host-gateway allowance for OpenClaw `web_fetch` is confined to the trusted proxy path, while strict and direct paths continue to block host-gateway names. Hermes Provider onboarding skips the host-side smoke probe only for OAuth-backed setup and keeps direct validation for Nous API key setup. For more information, refer to [NemoClaw Inference Options](../inference/inference-options). diff --git a/docs/get-started/prerequisites.mdx b/docs/get-started/prerequisites.mdx index a02008b529..899f717b39 100644 --- a/docs/get-started/prerequisites.mdx +++ b/docs/get-started/prerequisites.mdx @@ -79,5 +79,5 @@ The table comes from [`ci/platform-matrix.json`](https://github.com/NVIDIA/NemoC ## Next Steps - [Prepare Windows for NemoClaw](prerequisites/windows-preparation) if you are using Windows. -- [Quickstart](quickstart) to install NemoClaw and launch your first sandbox. +- [Quickstart](quickstart) to install NemoClaw and launch your first sandboxed agent. - [Agent Skills](../resources/agent-skills) to load NemoClaw guidance into an AI coding assistant before setup. diff --git a/docs/get-started/windows-preparation.mdx b/docs/get-started/windows-preparation.mdx index 3e3012795b..58642d7b1e 100644 --- a/docs/get-started/windows-preparation.mdx +++ b/docs/get-started/windows-preparation.mdx @@ -16,7 +16,7 @@ You can run NemoClaw inside Windows Subsystem for Linux (WSL 2) on Windows. Complete these steps before following the [Quickstart](../quickstart). -Complete these steps before following [Quickstart with Hermes](../quickstart-hermes). +Complete these steps before following [Quickstart with Hermes](../quickstart). Linux and macOS users do not need this page and can go directly to the Quickstart. @@ -36,7 +36,7 @@ Verify the following before you begin: -- Hardware requirements are the same as [Quickstart with Hermes](../quickstart-hermes). +- Hardware requirements are the same as [Quickstart with Hermes](../quickstart). @@ -167,7 +167,7 @@ If you used the bootstrap script, follow the installer command it printed inside If you prepared Windows manually, open a WSL terminal (type `wsl` in PowerShell, or open Ubuntu from Windows Terminal) and continue with the [Quickstart](../quickstart) to install NemoClaw and launch your first sandbox. -If you prepared Windows manually, open a WSL terminal (type `wsl` in PowerShell, or open Ubuntu from Windows Terminal) and continue with [Quickstart with Hermes](../quickstart-hermes) to install NemoClaw and launch your first Hermes sandbox. +If you prepared Windows manually, open a WSL terminal (type `wsl` in PowerShell, or open Ubuntu from Windows Terminal) and continue with [Quickstart with Hermes](../quickstart) to install NemoClaw and launch your first Hermes sandbox. All NemoClaw commands run inside WSL, not in PowerShell. diff --git a/docs/index.mdx b/docs/index.mdx index df743a4e76..af1c394bfb 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -60,7 +60,7 @@ By default, NemoClaw installs the OpenClaw agent. Use one of the following quick | Agent | Guide | |-------|-------| | OpenClaw (default) | [Quickstart with OpenClaw](../openclaw/get-started/quickstart) | -| Hermes | [Quickstart with Hermes](../hermes/get-started/quickstart-hermes) | +| Hermes | [Quickstart with Hermes](../hermes/get-started/quickstart) | ## Select User Guide for Your Agent diff --git a/docs/index.yml b/docs/index.yml index 180dd59090..34bd85457a 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -203,7 +203,7 @@ navigation: slug: windows-preparation - page: "Quickstart with Hermes" path: get-started/quickstart-hermes.mdx - slug: quickstart-hermes + slug: quickstart - section: "Inference" slug: inference collapsed: open-by-default diff --git a/docs/inference/inference-options.mdx b/docs/inference/inference-options.mdx index 9c5012c5cb..04ff8f0b16 100644 --- a/docs/inference/inference-options.mdx +++ b/docs/inference/inference-options.mdx @@ -199,5 +199,7 @@ Other provider credentials, such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMI ## Next Steps - [Use a Local Inference Server](use-local-inference) for Ollama, vLLM, NIM, and compatible-endpoint setup details. + - [Tool-Calling Reliability](tool-calling-reliability) for deciding when Ollama is enough and when vLLM with a parser is safer. + - [Switch Inference Models](switch-inference-providers) for changing the model at runtime without re-onboarding. diff --git a/docs/inference/use-local-inference.mdx b/docs/inference/use-local-inference.mdx index 54dd26db5a..51cfab2698 100644 --- a/docs/inference/use-local-inference.mdx +++ b/docs/inference/use-local-inference.mdx @@ -26,7 +26,7 @@ OpenShell intercepts inference traffic and forwards it to the local endpoint you - NemoClaw installed. Refer to the [Quickstart](../get-started/quickstart) if you have not installed yet. -- NemoClaw installed. Refer to [Quickstart with Hermes](../get-started/quickstart-hermes) if you have not installed yet. +- NemoClaw installed. Refer to [Quickstart with Hermes](../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. @@ -109,6 +109,7 @@ Windows-host Ollama requires Docker Desktop WSL integration because the sandbox If NemoClaw detects native Docker Engine inside WSL, the provider menu labels Windows-host Ollama actions as requiring Docker Desktop integration. Selecting one of those actions in the unsupported native Docker topology exits early with a remediation message instead of trying to start or install Ollama on Windows. + 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 @@ -116,6 +117,7 @@ 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](tool-calling-reliability). + ### Authenticated Reverse Proxy @@ -466,6 +468,6 @@ If the provider itself needs to change (for example, switching from vLLM to a cl - [Inference Options](inference-options) for the full list of providers available during onboarding. - [Switch Inference Models](switch-inference-providers) for runtime model switching. -- [Quickstart with Hermes](../get-started/quickstart-hermes) for first-time installation. +- [Quickstart with Hermes](../get-started/quickstart) for first-time installation. diff --git a/docs/manage-sandboxes/lifecycle.mdx b/docs/manage-sandboxes/lifecycle.mdx index 8eb14c2f49..06f454d91b 100644 --- a/docs/manage-sandboxes/lifecycle.mdx +++ b/docs/manage-sandboxes/lifecycle.mdx @@ -17,7 +17,7 @@ import { AgentOnly } from "../_components/AgentGuide"; Use this guide after you finish the [OpenClaw quickstart](../get-started/quickstart). -Use this guide after you finish [Quickstart with Hermes](../get-started/quickstart-hermes). +Use this guide after you finish [Quickstart with Hermes](../get-started/quickstart). It covers day-two sandbox operations such as listing sandboxes, checking health, managing ports, rebuilding safely, upgrading, and uninstalling. diff --git a/docs/manage-sandboxes/messaging-channels.mdx b/docs/manage-sandboxes/messaging-channels.mdx index 4f35274114..d7282732d9 100644 --- a/docs/manage-sandboxes/messaging-channels.mdx +++ b/docs/manage-sandboxes/messaging-channels.mdx @@ -337,6 +337,8 @@ $$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/reference/commands-nemohermes.mdx b/docs/reference/commands-nemohermes.mdx index 11180a30a7..1e637bab8d 100644 --- a/docs/reference/commands-nemohermes.mdx +++ b/docs/reference/commands-nemohermes.mdx @@ -1661,19 +1661,6 @@ These flags change defaults for commands that manage existing sandboxes. | `NEMOCLAW_DISABLE_INFERENCE_ROUTE_REPAIR` | `1` to enable | Skips the automatic DNS-proxy repair for stale `inference.local` routes during `nemohermes connect` and `nemohermes connect --probe-only`. Use only as a troubleshooting escape hatch. | | `NEMOCLAW_SHIELDS_ACCEPT_LEGACY_BASELINE` | `1` to opt in | Allows advanced immutable-config verification to trust the current on-disk bytes for older or partial content baselines. Use only after you have rebuilt or manually inspected the sandbox state and accepted that the baseline is operator-approved. | -### Remote Deployment - -These variables seed defaults for `nemohermes deploy` and `nemohermes onboard --remote`, which provision a sandbox on a Brev instance. -Each has a flag equivalent on `deploy`; the env var lets non-interactive runs skip the prompt. -For narrative how-to coverage of `NEMOCLAW_BREV_PROVIDER` and `NEMOCLAW_GPU`, see [Deploy to Remote GPU](../deployment/deploy-to-remote-gpu). - -| Variable | Default | Effect | -|----------|---------|--------| -| `NEMOCLAW_BREV_PROVIDER` | `gcp` | Cloud provider for Brev instance creation. | -| `NEMOCLAW_GPU` | `a2-highgpu-1g:nvidia-tesla-a100:1` | GPU specification (instance type and GPU model) for the Brev instance. | -| `NEMOCLAW_DEPLOY_NO_CONNECT` | unset | When set to `1`, skips the automatic `connect` step after the remote deploy completes. | -| `NEMOCLAW_DEPLOY_NO_START_SERVICES` | unset | When set to `1`, skips starting services automatically after the remote deploy. | - ### Legacy `nemohermes setup` Deprecated. Use `nemohermes onboard` instead. diff --git a/docs/reference/commands.mdx b/docs/reference/commands.mdx index caa202c465..4242f51867 100644 --- a/docs/reference/commands.mdx +++ b/docs/reference/commands.mdx @@ -1930,19 +1930,6 @@ These flags change defaults for commands that manage existing sandboxes. | `NEMOCLAW_DISABLE_INFERENCE_ROUTE_REPAIR` | `1` to enable | Skips the automatic DNS-proxy repair for stale `inference.local` routes during `$$nemoclaw connect` and `$$nemoclaw connect --probe-only`. Use only as a troubleshooting escape hatch. | | `NEMOCLAW_SHIELDS_ACCEPT_LEGACY_BASELINE` | `1` to opt in | Allows advanced immutable-config verification to trust the current on-disk bytes for older or partial content baselines. Use only after you have rebuilt or manually inspected the sandbox state and accepted that the baseline is operator-approved. | -### Remote Deployment - -These variables seed defaults for `$$nemoclaw deploy` and `$$nemoclaw onboard --remote`, which provision a sandbox on a Brev instance. -Each has a flag equivalent on `deploy`; the env var lets non-interactive runs skip the prompt. -For narrative how-to coverage of `NEMOCLAW_BREV_PROVIDER` and `NEMOCLAW_GPU`, see [Deploy to Remote GPU](../deployment/deploy-to-remote-gpu). - -| Variable | Default | Effect | -|----------|---------|--------| -| `NEMOCLAW_BREV_PROVIDER` | `gcp` | Cloud provider for Brev instance creation. | -| `NEMOCLAW_GPU` | `a2-highgpu-1g:nvidia-tesla-a100:1` | GPU specification (instance type and GPU model) for the Brev instance. | -| `NEMOCLAW_DEPLOY_NO_CONNECT` | unset | When set to `1`, skips the automatic `connect` step after the remote deploy completes. | -| `NEMOCLAW_DEPLOY_NO_START_SERVICES` | unset | When set to `1`, skips starting services automatically after the remote deploy. | - ### Legacy `$$nemoclaw setup` Deprecated. Use `$$nemoclaw onboard` instead. diff --git a/docs/reference/troubleshooting.mdx b/docs/reference/troubleshooting.mdx index 51dc311151..ab2e521478 100644 --- a/docs/reference/troubleshooting.mdx +++ b/docs/reference/troubleshooting.mdx @@ -1359,7 +1359,13 @@ sudo systemctl stop ollama OLLAMA_CONTEXT_LENGTH=16384 ollama serve ``` -For additional troubleshooting, see the [Quickstart](../get-started/quickstart) and [Windows Setup](../get-started/prerequisites/windows-preparation) pages. +For additional troubleshooting, see the [Windows Setup](../get-started/prerequisites/windows-preparation) page. + +For first-time OpenClaw setup, see the [Quickstart](../get-started/quickstart). + + +For first-time Hermes setup, see [Quickstart with Hermes](../get-started/quickstart). + ## Podman @@ -1369,7 +1375,9 @@ If you encounter issues with Podman, switch to a tested runtime (Docker Engine, ## Brev + For Brev setup instructions, refer to [Brev Web UI](../deployment/brev-web-ui). + ### Most OpenClaw skills show as blocked @@ -1453,7 +1461,7 @@ After the rebuild completes, return to the Skills page to confirm the skill is r ## Hermes The issues below are common problems you may encounter when running Hermes through `nemohermes`. -For setup, refer to [Quickstart with Hermes](../../hermes/get-started/quickstart-hermes). +For setup, refer to [Quickstart with Hermes](../../hermes/get-started/quickstart). ### Port 8642 in a browser shows a blank page or `Cannot GET /` @@ -1550,7 +1558,7 @@ Reset a specific provider's credentials with `nemohermes credentials reset +For additional protection, pass `--cap-drop=ALL` with `docker run` or Compose. Refer to [Sandbox Hardening](../manage-sandboxes/sandbox-hardening). + | Aspect | Detail | |---|---| @@ -599,7 +601,9 @@ The following patterns weaken security without providing meaningful benefit. - [Network Policies](../reference/network-policies) for the full baseline policy reference. - [Customize the Network Policy](../network-policy/customize-network-policy) for static and dynamic policy changes. - [Approve or Deny Network Requests](../network-policy/approve-network-requests) for the operator approval flow. + - [Sandbox Hardening](../manage-sandboxes/sandbox-hardening) for container-level security measures. + - [Inference Options](../inference/inference-options) for provider configuration details. - [How It Works](../about/how-it-works) for the protection layer architecture. {/* - OpenShell [Security Best Practices](https://docs.nvidia.com/openshell/latest/security/best-practices.html) for the platform-level controls reference, including network namespace isolation, seccomp filters, SSRF protection, TLS termination, and gateway authentication. */} diff --git a/fern/docs.yml b/fern/docs.yml index d46f068250..87d04dc239 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -108,11 +108,15 @@ redirects: destination: "/nemoclaw/user-guide/openclaw/:path*" - source: "/nemoclaw/user-guide/nemoclaw-for-hermes/:path*" destination: "/nemoclaw/user-guide/hermes/:path*" + - source: "/nemoclaw/latest/user-guide/hermes/get-started/quickstart-hermes" + destination: "/nemoclaw/latest/user-guide/hermes/get-started/quickstart" + - source: "/nemoclaw/user-guide/hermes/get-started/quickstart-hermes" + destination: "/nemoclaw/user-guide/hermes/get-started/quickstart" # User Guide tab with OpenClaw/Hermes variants: preserve legacy flat URLs (OpenClaw default). - source: "/nemoclaw/latest/about/:path*" destination: "/nemoclaw/latest/user-guide/openclaw/about/:path*" - source: "/nemoclaw/latest/get-started/quickstart-hermes" - destination: "/nemoclaw/latest/user-guide/hermes/get-started/quickstart-hermes" + destination: "/nemoclaw/latest/user-guide/hermes/get-started/quickstart" - source: "/nemoclaw/latest/get-started/:path*" destination: "/nemoclaw/latest/user-guide/openclaw/get-started/:path*" - source: "/nemoclaw/latest/inference/:path*" @@ -137,14 +141,14 @@ redirects: - source: "/nemoclaw/latest/get-started/openclaw/:path*" destination: "/nemoclaw/latest/user-guide/openclaw/get-started/:path*" - source: "/nemoclaw/latest/get-started/hermes/quickstart-hermes" - destination: "/nemoclaw/latest/user-guide/hermes/get-started/quickstart-hermes" + destination: "/nemoclaw/latest/user-guide/hermes/get-started/quickstart" - source: "/nemoclaw/latest/get-started/hermes/:path*" destination: "/nemoclaw/latest/user-guide/hermes/get-started/:path*" # Same redirects without the version slug (Fern check canonical paths). - source: "/nemoclaw/about/:path*" destination: "/nemoclaw/user-guide/openclaw/about/:path*" - source: "/nemoclaw/get-started/quickstart-hermes" - destination: "/nemoclaw/user-guide/hermes/get-started/quickstart-hermes" + destination: "/nemoclaw/user-guide/hermes/get-started/quickstart" - source: "/nemoclaw/get-started/:path*" destination: "/nemoclaw/user-guide/openclaw/get-started/:path*" - source: "/nemoclaw/inference/:path*" @@ -168,6 +172,6 @@ redirects: - source: "/nemoclaw/get-started/openclaw/:path*" destination: "/nemoclaw/user-guide/openclaw/get-started/:path*" - source: "/nemoclaw/get-started/hermes/quickstart-hermes" - destination: "/nemoclaw/user-guide/hermes/get-started/quickstart-hermes" + destination: "/nemoclaw/user-guide/hermes/get-started/quickstart" - source: "/nemoclaw/get-started/hermes/:path*" destination: "/nemoclaw/user-guide/hermes/get-started/:path*" diff --git a/scripts/sync-agent-variant-docs.ts b/scripts/sync-agent-variant-docs.ts index 9d5182502b..e9b950b38a 100644 --- a/scripts/sync-agent-variant-docs.ts +++ b/scripts/sync-agent-variant-docs.ts @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; +import { mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { parse } from "yaml"; @@ -18,6 +18,10 @@ type RenderedFile = { path: string; contents: string; }; +type RenderTarget = { + sourcePath: string; + variant: AgentVariant; +}; type RenderAgentVariantOptions = { outputPath?: string; sourcePath?: string; @@ -172,31 +176,55 @@ export function renderAgentVariantPage( } function renderGeneratedAgentVariantPages(): RenderedFile[] { - return findAgentVariantSourcePaths().flatMap((sourceFilePath) => { + return findAgentVariantTargets().map(({ sourcePath, variant }) => { + const sourceFilePath = path.join(docsRoot, sourcePath); const source = readFileSync(sourceFilePath, "utf8"); const basename = path.basename(sourceFilePath, ".mdx"); const relativeSourceDirectory = path.relative(docsRoot, path.dirname(sourceFilePath)); - return agentVariants.map((variant) => { - const outputPath = path.join( - generatedDocsRoot, - relativeSourceDirectory, - `${basename}.${variant}.generated.mdx`, - ); - return { - path: outputPath, - contents: renderAgentVariantPage(source, variant, { - outputPath, - sourcePath: sourceFilePath, - }), - }; - }); + const outputPath = path.join( + generatedDocsRoot, + relativeSourceDirectory, + `${basename}.${variant}.generated.mdx`, + ); + return { + path: outputPath, + contents: renderAgentVariantPage(source, variant, { + outputPath, + sourcePath: sourceFilePath, + }), + }; }); } -function findAgentVariantSourcePaths(): string[] { +function findAgentVariantTargets(): RenderTarget[] { const sharedSources = findSharedNavigationSourcePaths(); assertNoUnsharedPlaceholders(sharedSources); - return [...sharedSources].sort().map((sourcePath) => path.join(docsRoot, sourcePath)); + return findGeneratedNavigationTargets().sort((left, right) => { + const sourceOrder = left.sourcePath.localeCompare(right.sourcePath); + return sourceOrder === 0 ? left.variant.localeCompare(right.variant) : sourceOrder; + }); +} + +function findGeneratedNavigationTargets(): RenderTarget[] { + const docsIndex = parse(readFileSync(path.join(docsRoot, "index.yml"), "utf8")) as DocsIndex; + const userGuide = docsIndex.navigation?.find((item) => Array.isArray(item.variants)); + if (!userGuide?.variants) { + throw new Error("docs/index.yml must define navigation variants"); + } + return userGuide.variants.flatMap((variant) => { + if (variant.slug !== "openclaw" && variant.slug !== "hermes") return []; + return collectGeneratedTargets(variant.layout ?? [], variant.slug); + }); +} + +function collectGeneratedTargets(nodes: NavigationNode[], variant: AgentVariant): RenderTarget[] { + return nodes.flatMap((node): RenderTarget[] => { + const sourcePath = normalizeGeneratedNavigationSourcePath(node.path); + const current = sourcePath ? [{ sourcePath, variant }] : []; + return node.contents + ? [...current, ...collectGeneratedTargets(node.contents, variant)] + : current; + }); } function findSharedNavigationSourcePaths(): Set { @@ -228,15 +256,19 @@ function collectSourcePaths(nodes: NavigationNode[]): Set { } function normalizeNavigationSourcePath(navPath: string | undefined): string | null { + if (!navPath) return null; + const sourcePath = + normalizeGeneratedNavigationSourcePath(navPath) ?? normalizeLegacyVariantSource(navPath); + if (!sourcePath.endsWith(".mdx") || sourcePath === "index.mdx") return null; + return sourcePath; +} + +function normalizeGeneratedNavigationSourcePath(navPath: string | undefined): string | null { if (!navPath) return null; const generatedMatch = navPath.match( /^_build\/agent-variants\/(.+)\.(?:openclaw|hermes)\.generated\.mdx$/, ); - const sourcePath = generatedMatch?.[1] - ? `${generatedMatch[1]}.mdx` - : normalizeLegacyVariantSource(navPath); - if (!sourcePath.endsWith(".mdx") || sourcePath === "index.mdx") return null; - return sourcePath; + return generatedMatch?.[1] ? `${generatedMatch[1]}.mdx` : null; } function normalizeLegacyVariantSource(navPath: string): string { @@ -338,6 +370,7 @@ function rewriteRelativeLinkTarget( } function writeGeneratedFiles(files: RenderedFile[]): void { + pruneStaleGeneratedFiles(new Set(files.map((file) => file.path))); for (const file of files) { if (readOptionalFile(file.path) === file.contents) { console.log(`${path.relative(repoRoot, file.path)} is already up to date`); @@ -349,6 +382,30 @@ function writeGeneratedFiles(files: RenderedFile[]): void { } } +function pruneStaleGeneratedFiles(expectedPaths: Set): void { + for (const filePath of listGeneratedFiles(generatedDocsRoot)) { + if (expectedPaths.has(filePath)) continue; + rmSync(filePath); + console.log(`Removed ${path.relative(repoRoot, filePath)}`); + } +} + +function listGeneratedFiles(directory: string): string[] { + let entries; + try { + entries = readdirSync(directory, { withFileTypes: true }); + } catch (error) { + if (isNodeError(error) && error.code === "ENOENT") return []; + throw error; + } + + return entries.flatMap((entry) => { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) return listGeneratedFiles(entryPath); + return entry.isFile() && entry.name.endsWith(".generated.mdx") ? [entryPath] : []; + }); +} + function transformNemoclawCliInvocations(body: string): string { return restoreProtectedLiterals( protectNonAliasableLiterals(body) From a633a6c30e286f251e476e60b3bfa6afaf31b4a1 Mon Sep 17 00:00:00 2001 From: Miyoung Choi Date: Wed, 3 Jun 2026 18:22:42 -0700 Subject: [PATCH 3/3] test: avoid predictable temp file in link check --- test/check-docs-links.test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/check-docs-links.test.ts b/test/check-docs-links.test.ts index 29019e157b..95e3c80d24 100644 --- a/test/check-docs-links.test.ts +++ b/test/check-docs-links.test.ts @@ -96,8 +96,10 @@ describe("check-docs link validation", () => { }); it("rejects .md/.mdx suffixes for links that resolve as Fern routes", () => { - const tempPath = path.join(REPO_ROOT, "docs", "check-docs-route-suffix-temp.mdx"); - const navPath = path.join(os.tmpdir(), `nemoclaw-check-docs-nav-${process.pid}.yml`); + const tempDir = fs.mkdtempSync(path.join(REPO_ROOT, "docs", "check-docs-route-suffix-")); + const tempPath = path.join(tempDir, "temp.mdx"); + const navPath = path.join(tempDir, "index.yml"); + const tempNavPath = path.relative(path.join(REPO_ROOT, "docs"), tempPath); try { fs.writeFileSync( tempPath, @@ -121,7 +123,7 @@ describe("check-docs link validation", () => { " slug: openclaw", " layout:", ' - page: "Temp"', - " path: check-docs-route-suffix-temp.mdx", + ` path: ${tempNavPath}`, " slug: temp", ' - section: "Deployment"', " slug: deployment", @@ -143,8 +145,7 @@ describe("check-docs link validation", () => { `broken local link in ${tempPath}:6 -> deployment/deploy-to-remote-gpu`, ); } finally { - fs.rmSync(tempPath, { force: true }); - fs.rmSync(navPath, { force: true }); + fs.rmSync(tempDir, { force: true, recursive: true }); } });