diff --git a/ci/platform-matrix.json b/ci/platform-matrix.json index 71387c2530c..6f7eeda445b 100644 --- a/ci/platform-matrix.json +++ b/ci/platform-matrix.json @@ -64,7 +64,7 @@ "status": "deferred", "prd_priority": "P1", "ci_tested": false, - "notes": "The PRD marks this platform as P1. Workstation form-factor with NVIDIA GPUs and the same Docker + NVIDIA Container Toolkit + CDI requirements as DGX Spark. The installer detects DGX Station and offers express install with the pinned `nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4` recipe, including an approximately 352 GB model download, without follow-up provider, model, policy, or sandbox-name choices. Pass `--station-deepseek` to use `deepseek-ai/DeepSeek-V4-Flash` for a Station demo while retaining the one-confirmation express flow. Direct managed-vLLM onboarding still defaults to `deepseek-ai/DeepSeek-V4-Flash` when no model override is set. The full NemoClaw onboarding path, including the express recipe, has not been validated end-to-end on physical DGX Station hardware and remains `deferred` until that run is signed off." + "notes": "The PRD marks this platform as P1. Workstation form-factor with NVIDIA GPUs and the same Docker + NVIDIA Container Toolkit + CDI requirements as DGX Spark. The installer detects DGX Station and offers express install with the pinned `nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4` recipe, including an approximately 352 GB model download, without follow-up provider, model, policy, or sandbox-name choices. Pass `--station-deepseek` to use `deepseek-ai/DeepSeek-V4-Flash` for a Station demo while retaining the one-confirmation express flow. The flag requires an interactive terminal, and `/dev/tty` must be available when the installer runs through `curl | bash`. For headless setup, select `NEMOCLAW_PROVIDER=install-vllm` and `NEMOCLAW_VLLM_MODEL=deepseek-v4-flash` instead. Direct managed-vLLM onboarding still defaults to `deepseek-ai/DeepSeek-V4-Flash` when no model override is set. The full NemoClaw onboarding path, including the express recipe, has not been validated end-to-end on physical DGX Station hardware and remains `deferred` until that run is signed off." }, { "name": "NVIDIA RTX (consumer and Pro workstation GPUs)", diff --git a/docs/get-started/quickstart.mdx b/docs/get-started/quickstart.mdx index 5273d8ce94c..90518a4318a 100644 --- a/docs/get-started/quickstart.mdx +++ b/docs/get-started/quickstart.mdx @@ -129,6 +129,7 @@ Use these details when your first-run path needs more control. After it changes pinned packages, the installer exits with status `10` at the required reboot boundary; reboot, sign in, and run the printed exact-commit command to resume the accepted recipe without another prompt. This automation does not change Station's Deferred support status; physical end-to-end validation remains open. Pass `--station-deepseek` to use DeepSeek V4 Flash for a Station demo instead. + The flag selects the interactive express prompt and requires terminal access. Refer to [Platform Support](../reference/platform-support) and [Choose an Inference Provider](../inference/learn-and-choose/choose-inference-provider) for the current platform behavior. If `nemoclaw` is not found after installation and you use nvm or fnm, open a new terminal or reload your shell profile. @@ -194,7 +195,7 @@ Use these details when your first-run path needs more control. ``` On DGX Spark, Station GB300 hosts running the generic Ubuntu 24.04 ARM64 image, and Windows WSL, interactive installation offers 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, and selects the managed local inference path for that platform. + After you confirm the interactive express prompt, the installer switches the remaining onboarding to non-interactive mode, allows `sudo` password prompts for required host changes, and selects the managed local inference path for that platform. DGX Spark uses managed vLLM with `qwen3.6-35b-a3b-nvfp4` by default. DGX Station express install explicitly selects `nemotron-3-ultra-550b-a55b` instead of the Station managed-vLLM profile default, `deepseek-v4-flash`, and discloses the approximately `352 GB` model download before confirmation. Before onboarding, the Station path requires Station GB300 with the generic Ubuntu 24.04 ARM64 image and checks for NVIDIA open driver `610.43.02`, Docker CE `29.6.1` with Buildx, and NVIDIA Container Toolkit `1.19.1`. @@ -207,6 +208,20 @@ Use these details when your first-run path needs more control. Changing pinned packages exits with status `10` for a reboot; after you sign in and run the printed exact-commit command, the accepted express recipe resumes without another prompt. This automation does not change Station's Deferred support status; physical end-to-end validation remains open. To select DeepSeek V4 Flash while retaining the one-confirmation Station express flow, run `curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -s -- --station-deepseek`. + The `--station-deepseek` flag requires an interactive terminal; in a `curl | bash` pipeline, `/dev/tty` must be available. + Without terminal access, the installer stops before it installs Docker or build dependencies instead of ignoring the flag. + For a headless or CI install on a prepared DGX Station, omit the flag and select the same managed-vLLM recipe explicitly. + + ```bash + curl -fsSL https://www.nvidia.com/nemoclaw.sh | \ + NEMOCLAW_NON_INTERACTIVE=1 \ + NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 \ + NEMOCLAW_PROVIDER=install-vllm \ + NEMOCLAW_VLLM_MODEL=deepseek-v4-flash \ + NEMOCLAW_SANDBOX_NAME=my-assistant \ + bash + ``` + Unless `NEMOCLAW_POLICY_TIER` is set, express install applies policy in `suggested` mode with the `balanced` tier, including the base sandbox policy and supported package, model, web-search, and local-inference presets. Express install uses `my-assistant` as the sandbox name across all platforms unless `NEMOCLAW_SANDBOX_NAME` is set. Windows WSL selects the Windows-host Ollama setup path. diff --git a/docs/inference/set-up-vllm.mdx b/docs/inference/set-up-vllm.mdx index a251f37bdc4..c2604f314e7 100644 --- a/docs/inference/set-up-vllm.mdx +++ b/docs/inference/set-up-vllm.mdx @@ -147,6 +147,8 @@ When you start managed vLLM outside the installer express flow, NemoClaw uses th On DGX Station, accepting the installer express prompt sets `NEMOCLAW_VLLM_MODEL=nemotron-3-ultra-550b-a55b` and overrides the profile default. Pass `--station-deepseek` to select the existing `deepseek-v4-flash` recipe while retaining the same one-confirmation express flow. +The flag requires an interactive terminal; in a `curl | bash` pipeline, `/dev/tty` must be available. +Without terminal access, the installer stops before it installs Docker or build dependencies instead of silently continuing with another configuration. The registered Ultra recipe tracks the [official DGX Station deployment guide](https://github.com/NVIDIA-NeMo/Nemotron/blob/287ae845639d2ce998998cb8fd1f70a3fa943c0b/usage-cookbook/Nemotron-3-Ultra/StationDeploymentGuide/README.md) and configures the pinned model revision, CPU offload, `16 GB` of shared memory, memory/stack ulimits, MTP speculative decoding, and the Nemotron reasoning and tool-call parsers. NemoClaw intentionally keeps its existing bridge-networked managed-inference topology instead of importing the playbook's host-network setting. The container publishes port `8000` through Docker, so apply the firewall guidance at the top of this page. @@ -176,6 +178,14 @@ Add `NEMOCLAW_EXPERIMENTAL=1` on a generic Linux NVIDIA GPU host. Non-interactive runs use the profile default unless you set `NEMOCLAW_VLLM_MODEL`. On DGX Station, a direct provider-only run therefore selects `deepseek-v4-flash`; the installer express flow sets the Nemotron 3 Ultra override for you. +For a headless DGX Station setup that selects DeepSeek V4 Flash explicitly, use the environment-variable path instead of `--station-deepseek`. + +```bash +NEMOCLAW_PROVIDER=install-vllm \ + NEMOCLAW_VLLM_MODEL=deepseek-v4-flash \ + $$nemoclaw onboard --non-interactive +``` + ## Select a Managed Model Set `NEMOCLAW_VLLM_MODEL=` before onboarding to select a model without prompting. diff --git a/docs/reference/platform-support.mdx b/docs/reference/platform-support.mdx index 35a31916def..fc80acf9eb8 100644 --- a/docs/reference/platform-support.mdx +++ b/docs/reference/platform-support.mdx @@ -82,7 +82,7 @@ For the onboarding-time supported set without deferred rows, refer to [Prerequis | macOS (Apple Silicon) | Colima, Docker Desktop | Tested with limitations | P0 | Yes | Start the container runtime (Colima or Docker Desktop) before running the installer. Homebrew Colima users must install both Colima and the Docker CLI (`brew install colima docker`) before `docker info` can work. Xcode Command Line Tools (`xcode-select --install`) are typically required for Node native modules during install. NemoClaw recommends them but does not enforce them during preflight. | | DGX Spark | Docker | Tested | P1 | Yes | Use the standard installer and `$$nemoclaw onboard`. For an end-to-end walkthrough with local inference, see the [NVIDIA Spark playbook](https://build.nvidia.com/spark/nemoclaw). | | Windows WSL2 | Docker Desktop (WSL backend) | Tested with limitations | P1 | No | Requires WSL2 with Docker Desktop backend. | -| DGX Station | Docker | Deferred | P1 | No | The PRD marks this platform as P1. Workstation form-factor with NVIDIA GPUs and the same Docker + NVIDIA Container Toolkit + CDI requirements as DGX Spark. The installer detects DGX Station and offers express install with the pinned `nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4` recipe, including an approximately 352 GB model download, without follow-up provider, model, policy, or sandbox-name choices. Pass `--station-deepseek` to use `deepseek-ai/DeepSeek-V4-Flash` for a Station demo while retaining the one-confirmation express flow. Direct managed-vLLM onboarding still defaults to `deepseek-ai/DeepSeek-V4-Flash` when no model override is set. The full NemoClaw onboarding path, including the express recipe, has not been validated end-to-end on physical DGX Station hardware and remains `deferred` until that run is signed off. | +| DGX Station | Docker | Deferred | P1 | No | The PRD marks this platform as P1. Workstation form-factor with NVIDIA GPUs and the same Docker + NVIDIA Container Toolkit + CDI requirements as DGX Spark. The installer detects DGX Station and offers express install with the pinned `nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4` recipe, including an approximately 352 GB model download, without follow-up provider, model, policy, or sandbox-name choices. Pass `--station-deepseek` to use `deepseek-ai/DeepSeek-V4-Flash` for a Station demo while retaining the one-confirmation express flow. The flag requires an interactive terminal, and `/dev/tty` must be available when the installer runs through `curl \| bash`. For headless setup, select `NEMOCLAW_PROVIDER=install-vllm` and `NEMOCLAW_VLLM_MODEL=deepseek-v4-flash` instead. Direct managed-vLLM onboarding still defaults to `deepseek-ai/DeepSeek-V4-Flash` when no model override is set. The full NemoClaw onboarding path, including the express recipe, has not been validated end-to-end on physical DGX Station hardware and remains `deferred` until that run is signed off. | | NVIDIA RTX (consumer and Pro workstation GPUs) | Docker | Deferred | P1 | No | The PRD marks this platform as P1. Covers RTX consumer cards and RTX Pro workstation cards on Linux hosts that meet the generic-Linux-GPU requirements (NVIDIA Container Toolkit + CDI present). The provider menu emits managed vLLM behind `NEMOCLAW_EXPERIMENTAL=1` or `NEMOCLAW_PROVIDER=install-vllm` for this host class today; the end-to-end onboard path on this hardware is not yet validated in CI. | {/* platform-matrix-full:end */} diff --git a/scripts/install.sh b/scripts/install.sh index 0eb66b34948..b719cc7831e 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -747,7 +747,7 @@ usage() { printf " --non-interactive Skip prompts (uses env vars / defaults)\n" printf " --yes-i-accept-third-party-software Accept the third-party software notice without prompting\n" printf " --fresh Discard any failed/interrupted onboarding session and start over\n" - printf " --station-deepseek Use DeepSeek V4 Flash for DGX Station express install\n" + printf " --station-deepseek Use DeepSeek V4 Flash for DGX Station express install (interactive terminal required)\n" printf " --version, -v Print installer version and exit\n" printf " --help, -h Show this help message and exit\n\n" printf " ${C_DIM}Environment:${C_RESET}\n" @@ -2902,6 +2902,22 @@ normalize_station_vllm_model() { printf "%s" "${1:-}" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//' } +# True when an interactive terminal is reachable for a prompt: stdin is a TTY, +# or /dev/tty can be opened (the curl|bash case where stdin is the script pipe). +# Mirrors how maybe_offer_express_install decides whether it can prompt. +express_prompt_can_read_tty() { + [ -t 0 ] && return 0 + if { exec 3/dev/null; then + exec 3<&- + return 0 + fi + return 1 +} + +fail_station_deepseek_terminal_required() { + error "--station-deepseek selects the DGX Station express prompt, which needs an interactive terminal. Re-run from a terminal (for a curl|bash pipe, /dev/tty must be available), or omit --station-deepseek and configure the install non-interactively." +} + validate_station_deepseek_override() { local platform="$1" if [ "${STATION_DEEPSEEK:-}" != "1" ]; then @@ -2938,6 +2954,17 @@ validate_station_deepseek_override() { error "--station-deepseek conflicts with NEMOCLAW_VLLM_MODEL='${NEMOCLAW_VLLM_MODEL}'. Remove one override or set NEMOCLAW_VLLM_MODEL=${STATION_DEEPSEEK_VLLM_MODEL}." ;; esac + + # #7014: --station-deepseek selects the interactive DGX Station express prompt, + # so it needs a terminal. Without one, maybe_offer_express_install would just + # log "Skipping express prompt (no TTY)" and continue, silently ignoring the + # flag and installing a different configuration. Fail fast here (before Docker + # / build deps) with a clear message instead, mirroring the --non-interactive + # rejection above. Checked last so a genuine config conflict (provider/model) + # is still reported first. + if ! express_prompt_can_read_tty; then + fail_station_deepseek_terminal_required + fi } preflight_explicit_express_flags() { @@ -3262,6 +3289,9 @@ maybe_offer_express_install() { describe_express_install "$platform" printf " Run express install with these settings? [Y/n]: " if ! IFS= read -r reply; then + if [ "${STATION_DEEPSEEK:-}" = "1" ]; then + fail_station_deepseek_terminal_required + fi info "Skipping express install (unable to read from TTY)." return 0 fi @@ -3271,6 +3301,9 @@ maybe_offer_express_install() { printf " Run express install with these settings? [Y/n]: " if ! IFS= read -r reply <&3; then exec 3<&- + if [ "${STATION_DEEPSEEK:-}" = "1" ]; then + fail_station_deepseek_terminal_required + fi info "Skipping express install (unable to read from TTY)." return 0 fi diff --git a/test/install-express-prompt.test.ts b/test/install-express-prompt.test.ts index 74f3600ac38..32e900bf63f 100644 --- a/test/install-express-prompt.test.ts +++ b/test/install-express-prompt.test.ts @@ -60,6 +60,9 @@ detect_express_platform() { printf "$EXPRESS_PLATFORM"; } NON_INTERACTIVE="\${NON_INTERACTIVE:-}" NEMOCLAW_PROVIDER="\${NEMOCLAW_PROVIDER:-}" NEMOCLAW_NO_EXPRESS="\${NEMOCLAW_NO_EXPRESS:-}" +if [ "\${FORCE_EXPRESS_PROMPT_READ_FAILURE:-}" = "1" ]; then + read() { return 1; } +fi maybe_offer_express_install printf "RESULT NON_INTERACTIVE=%s SUDO_MODE=%s PROVIDER=%s MODEL=%s VLLM_MODEL=%s POLICY=%s YES=%s SANDBOX=%s\\n" \\ "\${NON_INTERACTIVE:-}" "\${NEMOCLAW_NON_INTERACTIVE_SUDO_MODE:-}" "\${NEMOCLAW_PROVIDER:-}" "\${NEMOCLAW_MODEL:-}" \\ @@ -443,6 +446,89 @@ main "$@" expect(output).not.toMatch(/cannot be combined with non-interactive mode/); }); + it("errors instead of silently skipping --station-deepseek when no interactive terminal is available (#7014)", () => { + // Python's start_new_session runs main without a controlling terminal, and + // stdin is /dev/null — so neither `-t 0` nor /dev/tty is available. This is + // deterministic on both Linux and macOS regardless of the test runner TTY. + // Docker / build deps are mocked to prove the error fires before any host + // mutation (the preflight validation path). + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-station-notty-")); + try { + const mutationLog = path.join(tmp, "host-mutations.log"); + const python = + spawnSync("bash", ["--noprofile", "--norc", "-c", "command -v python3"], { + encoding: "utf-8", + }).stdout.trim() || "python3"; + const shellScript = ` +source "$INSTALLER_UNDER_TEST" >/dev/null +detect_express_platform() { printf "%s" "$EXPRESS_PLATFORM"; } +ensure_docker() { printf "ensure_docker\\n" >>"$MUTATION_LOG"; } +ensure_openshell_build_deps() { printf "ensure_openshell_build_deps\\n" >>"$MUTATION_LOG"; } +main "$@" +`; + const result = spawnSync( + python, + [ + "-c", + ` +import os +import subprocess +import sys + +result = subprocess.run( + ["bash", "--noprofile", "--norc", "-c", sys.argv[1], "_", "--station-deepseek"], + cwd=os.getcwd(), + env=os.environ.copy(), + stdin=subprocess.DEVNULL, + capture_output=True, + start_new_session=True, + timeout=10, +) +sys.stdout.buffer.write(result.stdout) +sys.stderr.buffer.write(result.stderr) +sys.exit(result.returncode) +`, + shellScript, + ], + { + cwd: tmp, + encoding: "utf-8", + timeout: 15_000, + killSignal: "SIGKILL", + env: { + HOME: tmp, + PATH: TEST_SYSTEM_PATH, + INSTALLER_UNDER_TEST: INSTALLER_PAYLOAD, + MUTATION_LOG: mutationLog, + EXPRESS_PLATFORM: "DGX Station", + }, + }, + ); + const output = `${result.stdout}${result.stderr}`; + expect(result.error, output).toBeUndefined(); + const mutations = fs.existsSync(mutationLog) ? fs.readFileSync(mutationLog, "utf-8") : ""; + expect(result.status, output).not.toBe(0); + expect(output).toMatch(/--station-deepseek.*needs an interactive terminal/); + // Failed at preflight, before Docker / build-dependency mutation. + expect(mutations).toBe(""); + } finally { + fs.rmSync(tmp, { recursive: true, force: true }); + } + }); + + it("fails closed if the Station DeepSeek prompt becomes unreadable after preflight (#7014)", () => { + const result = runExpressPromptWithTty("", "tty", "DGX Station", { + FORCE_EXPRESS_PROMPT_READ_FAILURE: "1", + STATION_DEEPSEEK: "1", + }); + const output = `${result.stdout}${result.stderr}`; + expect(result.error, output).toBeUndefined(); + expect(result.status, output).not.toBe(0); + expect(output).toMatch(/--station-deepseek.*needs an interactive terminal/); + expect(output).not.toMatch(/Using express install/); + expect(output).not.toMatch(/RESULT NON_INTERACTIVE=/); + }); + it.each([ ["Unsupported DGX Station OS", { NEMOCLAW_NO_EXPRESS: "1" }], ["Unsupported DGX Station generation", { NEMOCLAW_PROVIDER: "openai" }],