Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
234706f
fix(sdk): report the installed nemo-platform version
cursoragent Aug 11, 2026
8aa84c9
feat(cli): match the missing-extra hint to the install method
cursoragent Aug 11, 2026
38baa51
docs: lead with uv tool install for the PyPI install path
cursoragent Aug 11, 2026
cd17eb7
docs: pin the documented tool install to a supported interpreter
cursoragent Aug 11, 2026
93fc656
ci: exercise the uv tool install path and assert a real version
cursoragent Aug 11, 2026
c650ea3
fix(sdk): declare the supported Python range on the bundled SDK
cursoragent Aug 11, 2026
228f484
ci: match the version fallback exactly in the CLI smoke test
cursoragent Aug 11, 2026
b29fdfe
fix(ci): repair the wheel-constraints generator
cursoragent Aug 12, 2026
548ac20
deps(nemo-agents): move NAT to the 1.9 line so the wheel resolves
cursoragent Aug 12, 2026
d6a8719
ci: install wheels without repo config in wheel-test
cursoragent Aug 12, 2026
89868b2
docs: keep the interpreter flag out of the install path
cursoragent Aug 12, 2026
b4cc5b2
chore(licenses): refresh the manifest for the NAT bump
cursoragent Aug 12, 2026
1c5a6b0
Revert "deps(nemo-agents): move NAT to the 1.9 line so the wheel reso…
cursoragent Aug 12, 2026
76d1643
docs: tighten the install sections and ground the troubleshooting
cursoragent Aug 12, 2026
f3b3c4a
docs: trim the install-failure entry to what a user needs
cursoragent Aug 12, 2026
da84640
Reapply "deps(nemo-agents): move NAT to the 1.9 line so the wheel res…
cursoragent Aug 13, 2026
7a73d01
chore: refresh wheel constraints for upstream patch releases
cursoragent Aug 13, 2026
0b99b01
Merge remote-tracking branch 'origin/main' into aditya/uv-tool-instal…
cursoragent Aug 13, 2026
903ecb9
chore: regenerate the requirements export for the NAT bump
cursoragent Aug 13, 2026
6bcdc7c
chore(ci): drop the obsolete litellm cap from wheel constraints
cursoragent Aug 13, 2026
0ae352a
docs: use uv for the virtual environment path too
cursoragent Aug 13, 2026
1140b59
Merge remote-tracking branch 'origin/main' into aditya/uv-tool-instal…
cursoragent Aug 13, 2026
77f0ff0
chore: regenerate derived artifacts after merging main
cursoragent Aug 13, 2026
f9d8a1b
Merge remote-tracking branch 'origin/main' into aditya/uv-tool-instal…
cursoragent Aug 13, 2026
268b9bf
test(licenses): stop asserting a package the closure no longer has
cursoragent Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/actions/build-nemo-platform-wheel/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ inputs:
required: false
default: "19700101000000"
python-version:
description: Python version for setup-uv.
description: Python version for setup-uv. Must be within the wheel's supported range.
required: false
default: "3.11"
default: "3.12"
source-root:
description: >
Path to the checked-out repository. release-bundle.yaml uses `source`;
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ Quick install from PyPI:
```bash
curl -LsSf https://astral.sh/uv/0.9.30/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv venv --python 3.13
source .venv/bin/activate
uv pip install nemo-platform
uv tool install "nemo-platform[all]"

nemo setup
```

`uv tool install` gives you a global `nemo` command in its own isolated environment, with nothing to activate. The `all` extra adds the platform services, so `nemo services run` works; without it you get the SDK and CLI only. To import the SDK from your own code, `pip install "nemo-platform[all]"` into a virtual environment instead.

Source checkout for development:

```bash
Expand Down
4 changes: 3 additions & 1 deletion SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ is unavailable, start Docker and retry—do not proceed to `rm -rf`.

## Bootstrap and start

The README documents the streamlined path. Prefer this over the manual steps below whenever the task fits — it covers prerequisites install, service startup, provider registration, default/fast model selection, and demo agent deployment in one shot:
This section is the **source checkout** path: use it to work on NeMo Platform itself, on a local plugin, or on Studio assets. To only *use* the platform, install the published wheel instead — `uv tool install "nemo-platform[all]"` needs no checkout and no toolchain, then continue at `nemo setup`.

The steps below cover prerequisites install, service startup, provider registration, default/fast model selection, and demo agent deployment in one shot. Prefer them over the manual sections further down whenever the task fits:

Before running `make bootstrap`, install Flox from the [Flox installation guide](https://flox.dev/docs/install-flox/install). Flox is the recommended source-development toolchain and does not need to be activated first. Contributors using a preinstalled host toolchain instead need uv `>=0.9.14`, Node.js `22.23.2`, pnpm `10.34.5`, and a C compiler; they must use `make TOOLCHAIN=system bootstrap`.

Expand Down
26 changes: 17 additions & 9 deletions docs/cli/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,33 @@ If you previously installed the `nemo-microservices` package, uninstall it first
pip uninstall nemo-microservices
```

### Install in a Virtual Environment
### Install

Install the PyPI `nemo-platform` wrapper package in a Python 3.12-3.13 virtual environment. If you are working from a source checkout, run `make bootstrap` from the repository root instead; the generated SDK package under `sdk/python/nemo-platform/pyproject.toml` does not define the wrapper extras.
Install the PyPI `nemo-platform` wrapper package. From a source checkout, run `make bootstrap` from the repository root instead; the generated SDK package under `sdk/python/nemo-platform/pyproject.toml` does not define the wrapper extras.

<Tabs>

<Tab title="uv tool (recommended)">

One command, `nemo` available everywhere, nothing to activate.

```bash
pip install "nemo-platform[all]"
uv tool install "nemo-platform[all]"
```

Or with uv:
</Tab>

<Tab title="Virtual environment">

Use when you also import the SDK from your own code. `nemo` works only while the environment is active.

```bash
uv pip install "nemo-platform[all]"
pip install "nemo-platform[all]"
Comment thread
callingmedic911 marked this conversation as resolved.
Outdated
```

<Warning>

When installed in a virtual environment, the `nemo` command is only available when the environment is activated.
</Tab>

</Warning>
</Tabs>

### Verify Installation

Expand Down
19 changes: 19 additions & 0 deletions docs/cli/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ Activate the virtual environment where you installed the package:
source /path/to/venv/bin/activate
```

## Installation Issues

### Install Fails Building a Dependency

**Symptoms:**
- `uv tool install "nemo-platform[all]"` fails while building a dependency, often on a missing C header such as `omp.h`

**Cause:**

NeMo Platform supports Python 3.12 and 3.13, but uv [picks the interpreter itself](https://docs.astral.sh/uv/concepts/tools/#python-versions), so an install can land on Python 3.14.

**Solution:**

Name a supported interpreter. uv downloads one if you do not have it:

```bash
uv tool install --python 3.13 "nemo-platform[all]"
```

## Connection Issues

### Unable to Connect to Server
Expand Down
28 changes: 21 additions & 7 deletions docs/get-started/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Install NeMo Platform and start working with AI agents.
- Python 3.12-3.13
- An API key from one of: [NVIDIA Build](https://build.nvidia.com), [OpenAI](https://platform.openai.com/api-keys), [Anthropic](https://console.anthropic.com/settings/keys), [Google Gemini](https://aistudio.google.com/apikey), or a local [Ollama](https://ollama.com) instance (no key needed)
- 16 GB available disk space and 8 GB RAM
- For the PyPI install: `pip` in a Python environment
- For the PyPI install: [uv](https://docs.astral.sh/uv/) `>=0.9.14`, or `pip` in a Python environment
- For the source checkout install: [Git](https://git-scm.com/), GNU Make, [uv](https://docs.astral.sh/uv/) `>=0.9.14`, [Node.js (≥22.23.2, \<23)](https://nodejs.org/en/download) satisfying `web/package.json`, and [pnpm](https://pnpm.io/installation)

## Install
Expand All @@ -21,21 +21,35 @@ Choose the install path that matches what you want to do.

### Install from PyPI

Use the [PyPI package](https://pypi.org/project/nemo-platform/) for the quickest local install. The `all` extra includes the SDK, CLI, platform services, and default first-party plugins:
Use the [PyPI package](https://pypi.org/project/nemo-platform/) for the quickest local install. The `all` extra includes the SDK, CLI, platform services, and default first-party plugins; drop it for the SDK and CLI alone.

<Tabs>

<Tab title="uv tool (recommended)">

One command, `nemo` available everywhere, nothing to activate.

```bash
uv tool install "nemo-platform[all]"
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

</Tab>

<Tab title="Virtual environment">

Use when you also import the SDK from your own code. `nemo` works only while the environment is active.

```bash
python -m venv .venv
source .venv/bin/activate
pip install "nemo-platform[all]"
```

For SDK and CLI usage only, install the base package:
</Tab>

```bash
pip install nemo-platform
```
</Tabs>

After installing `nemo-platform[all]` from PyPI, continue with `nemo setup`.
Continue with `nemo setup`.

### Install from source

Expand Down
12 changes: 8 additions & 4 deletions packages/nemo_platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ NeMo Platform brings NVIDIA NeMo libraries together under one CLI, Python SDK, a

**Prerequisites:** Python 3.12–3.13 and an API key for an inference provider (NVIDIA Build, OpenAI, Anthropic, Google Gemini, or a local Ollama instance).

The `nemo-platform` distribution is a convenience wrapper that bundles the SDK, shared runtime packages, default first-party plugins, and platform services into a single wheel. Install just the SDK and CLI, or install everything needed to run the platform locally:
The `nemo-platform` distribution is a convenience wrapper that bundles the SDK, shared runtime packages, default first-party plugins, and platform services into a single wheel. The `all` extra adds the platform services; drop it for the SDK and CLI alone.

Recommended — one command, `nemo` available everywhere, nothing to activate:

```bash
# SDK + CLI only
pip install nemo-platform
uv tool install "nemo-platform[all]"
```

# SDK + CLI + all platform services and default plugins (recommended)
Use a virtual environment instead when you also import the SDK from your own code. `nemo` then works only while the environment is active:

```bash
pip install "nemo-platform[all]"
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import typer
from nemo_platform_ext.cli.core.help_formatter import create_typer_app
from nemo_platform_ext.cli.docker_preflight import require_docker_for_default_local
from nemo_platform_ext.local.install import services_extra_install_command
from nemo_platform_ext.local.process import (
ForegroundInstanceError,
InstanceAlreadyRunningError,
Expand Down Expand Up @@ -75,10 +76,7 @@ def _require_services_extra() -> None:
"Running local platform services needs extra components that aren't installed yet.\n"
"\n"
"Install them with:\n"
" pip install 'nemo-platform[all]'\n"
"\n"
"On Python 3.14, use:\n"
" PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 pip install 'nemo-platform[all]'\n",
f" {services_extra_install_command()}\n",
err=True,
)
raise typer.Exit(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from pydantic import SecretStr
from rich import box
from rich.console import Console
from rich.markup import escape
from rich.panel import Panel

from nemo_platform_ext.cli.commands.skills import registry as skills_registry
Expand All @@ -49,6 +50,7 @@
from nemo_platform_ext.client.tls import client_verify_from_env
from nemo_platform_ext.config.config import Config
from nemo_platform_ext.config.models import DEFAULT_BASE_URL, ConfigFile, ConfigParams, LocalServicesConfig, NoAuthUser
from nemo_platform_ext.local.install import services_extra_install_command
from nemo_platform_ext.local.process import (
PortConflict,
check_port_available_for_start,
Expand Down Expand Up @@ -1154,9 +1156,7 @@ def _maybe_start_services(
if importlib.util.find_spec("pyleak") is None:
console.print(f"{CROSS} Local services require extra dependencies that aren't installed.")
console.print(" Install them with:")
console.print(" [cyan]pip install 'nemo-platform\\[all]'[/cyan]")
console.print(" On Python 3.14, use:")
console.print(" [cyan]PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 pip install 'nemo-platform\\[all]'[/cyan]")
console.print(f" [cyan]{escape(services_extra_install_command())}[/cyan]")
raise typer.Exit(1)

# Fail before stop/spawn when default local needs Docker (NVBug 6537617).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""How this NeMo Platform install was created."""

from __future__ import annotations

import sys
from pathlib import Path


def services_extra_install_command() -> str:
"""Return the command that adds the packaged service dependencies here.

``uv tool install`` environments are managed by uv and are not meant to be
edited with pip; re-running the tool install with the extra upgrades them
in place. uv marks such an environment with a ``uv-receipt.toml`` at its
root, which is what distinguishes it from an ordinary virtual environment.
"""
if (Path(sys.prefix) / "uv-receipt.toml").is_file():
return "uv tool install 'nemo-platform[all]'"
return "pip install 'nemo-platform[all]'"
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from nemo_platform import AsyncNeMoPlatform, NeMoPlatform
from nemo_platform_ext.local import process
from nemo_platform_ext.local.install import services_extra_install_command
from nemo_platform_ext.local.transport import (
EMBEDDED_BASE_URL,
UDS_BASE_URL,
Expand Down Expand Up @@ -407,7 +408,7 @@ async def stop_async(self, *, timeout: float = 30.0, force: bool = False) -> pro
def require_services_extra() -> None:
if importlib.util.find_spec("pyleak") is not None:
return
raise ServicesExtraRequiredError("Install service dependencies with `pip install 'nemo-platform[all]'`.")
raise ServicesExtraRequiredError(f"Install service dependencies with `{services_extra_install_command()}`.")


def _validate_socket_path_length(socket_path: Path) -> None:
Expand Down
27 changes: 27 additions & 0 deletions packages/nemo_platform_ext/tests/local/test_install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

from __future__ import annotations

import sys
from pathlib import Path

import pytest
from nemo_platform_ext.local.install import services_extra_install_command


@pytest.mark.parametrize(
("uv_tool_env", "expected"),
[
(False, "pip install 'nemo-platform[all]'"),
(True, "uv tool install 'nemo-platform[all]'"),
],
)
def test_services_extra_install_command_matches_install_method(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, uv_tool_env: bool, expected: str
) -> None:
if uv_tool_env:
(tmp_path / "uv-receipt.toml").write_text("[tool]\n")
monkeypatch.setattr(sys, "prefix", str(tmp_path))

assert services_extra_install_command() == expected
4 changes: 2 additions & 2 deletions script/compile-wheel-constraints.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ emit_constraints() {
local wheel="$1" spec="$2" label="$3" out="$4" venv meta
venv="$(mktemp -d)"
meta="$(mktemp -d)"
uv venv "${venv}" --python 3.11 --quiet
uv venv "${venv}" --python 3.12 --quiet
# Resolve+install once with the cap so we snapshot consistent, py3.14-safe versions.
printf '%s\n' "${LITELLM_CAP%% *}" >"${meta}/cap.txt"
uv pip install --python "${venv}/bin/python" --constraint "${meta}/cap.txt" "${spec}" >/dev/null
Expand All @@ -61,7 +61,7 @@ PY
printf '# Regenerate with: script/compile-wheel-constraints.sh <dir-with-built-wheels>\n#\n'
while read -r name; do
[[ -n "${name}" ]] || continue
ver="$("${venv}/bin/python" -c "import importlib.metadata as m; print(m.version('${name}'))" 2>/dev/null || true)
ver="$("${venv}/bin/python" -c "import importlib.metadata as m; print(m.version('${name}'))" 2>/dev/null || true)"
[[ -n "${ver}" ]] && printf '%s==%s\n' "${name}" "${ver}"
done <"${meta}/names.txt" | sort
printf '%s\n' "${LITELLM_CAP}"
Expand Down
15 changes: 14 additions & 1 deletion script/test-nemo-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,20 @@ done

echo "----- nemo on PATH -----"
command -v nemo
nemo --version
version_output="$(nemo --version)"
echo "${version_output}"
# A bare `0.0.0` is the CLI's fallback when its importlib.metadata lookup
# misses the distribution it was installed from, which is invisible unless the
# output is asserted. Match it exactly: nightly wheels are stamped with a
# sentinel `0.0.0.dev<timestamp>` that is a legitimate version string. The
# pattern is the subset of PEP 440 this project stamps — release, optional
# pre-release, any number of .post/.dev segments, optional local version.
version="${version_output#nemo version }"
if [[ "${version}" == "0.0.0" ]] ||
[[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?(\.(post|dev)[0-9]+)*(\+[0-9a-z.]+)?$ ]]; then
echo "::error::nemo --version did not report an installed version: ${version_output}" >&2
exit 1
fi

# Import-time checks for commands that ship in the bundled wrapper. We don't
# call `nemo services --help` here because `nemo services run` below is a
Expand Down
3 changes: 1 addition & 2 deletions sdk/python/nemo-platform/pyproject.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/python/nemo-platform/src/nemo_platform/_version.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading