Skip to content

fix(cli): make uv tool install the front door for nemo-platform - #1248

Open
callingmedic911 wants to merge 15 commits into
mainfrom
aditya/uv-tool-install-front-door-50d4
Open

fix(cli): make uv tool install the front door for nemo-platform#1248
callingmedic911 wants to merge 15 commits into
mainfrom
aditya/uv-tool-install-front-door-50d4

Conversation

@callingmedic911

@callingmedic911 callingmedic911 commented Aug 11, 2026

Copy link
Copy Markdown
Member

Blocker: nvidia-nat-core 1.8.0 caps cryptography at <47 while data-designer-engine 0.8.0 requires >=48.0.1, so nemo-platform[all] built from current main does not resolve from PyPI.

Possible path:

  • Bump NAT to 1.9.0aX release. (Not stable?)
  • Downgrade data-designer. (Lose features?)
  • Wait for NAT to be removed as dep. (Unsure abou timeline)

  • uv tool install "nemo-platform[all]" is the documented install path now.
  • fixed nemo --version to 0.0.0 for PyPi user.
  • detect and show right command uv tool ... vs pip ... based on how user set up nemo-platform.
  • update docs to promote uv tool as recommended path.
  • fix script/compile-wheel-constraints.sh: a missing closing quote makes bash -n fail — so the constraints could never be regenerated.
  • tightened python version mismatch: nemo-platform-sdk declared >=3.12, the wrapper wheel it ships in supports 3.12-3.13.

Cursor's description

Summary

uv tool install "nemo-platform[all]" is the documented install path now. Along the way this fixes nemo --version reporting 0.0.0 for every PyPI user, makes the missing-extra hint print a command that works where the user actually installed, and repairs the constraints generator. A dependency conflict that blocks the same install path for the next release is documented below and deferred.

Changes

  • _version.py queries nemo-platform instead of nemo-platform-sdk. The SDK distribution only exists in the workspace (nemo-platform-sdk is 404 on PyPI) — PyPI users get the SDK bundled inside the wrapper wheel, so the lookup raised and fell back to 0.0.0, which also reached telemetry client_version and the SDK client User-Agent. Both names report the same version in the workspace, so nothing changes for contributors. The edit is in the generator template, and SDK_DISTRIBUTION_NAME is untouched because it still names the distribution being built.
  • New local/install.py detects a uv tool environment through the uv-receipt.toml uv writes at the environment root, so the missing-extra hint prints uv tool install 'nemo-platform[all]' there and pip install 'nemo-platform[all]' in a virtual environment. Used by nemo services run, the nemo setup preflight, and local/services.py. The Python 3.14 variant of that hint is gone: the wheel declares requires-python <3.14.
  • Install docs lead with uv tool install "nemo-platform[all]" (repo README, PyPI README, docs/get-started/setup.mdx, docs/cli/index.mdx), keep the virtual environment variant for SDK imports, and label SETUP.md as the contributor path.
  • script/test-nemo-cli.sh asserts nemo --version reports a real version. It printed the output without checking it, which is how the 0.0.0 fallback went unnoticed. The CI wheel-test job runs this script, so the existing venv legs now guard the regression.
  • script/compile-wheel-constraints.sh has been syntactically invalid since it landed — a missing closing quote makes bash -n fail — so the constraints could never be regenerated. Fixed, and moved to a 3.12 probe environment because the wrapper's requires-python floor rejects the old 3.11 one.
  • The bundled SDK declared >=3.12 with a Programming Language :: Python :: 3.14 classifier while the wheel it ships in supports 3.12-3.13; both are tightened. The wheel build action defaults to 3.12 rather than 3.11, which requires-python already excludes.

Python version handling

--python 3.13 stays out of the install commands. The prerequisites state 3.12-3.13, and the escape hatch lives in CLI troubleshooting, because uv enforces only the lower bound of requires-python: it planned to install numpy==1.24.4, which declares <3.12, into a 3.14 environment, and it preferred a managed 3.14 over the system 3.12 for a tool install of this wheel. Metadata cannot keep a uv install on a supported interpreter, and the resulting failure is a source build of a dependency with no 3.14 wheels, so troubleshooting is where it belongs. NAT itself declares <3.14, so 3.14 support is gated upstream regardless.

Deferred: the next release cannot be installed with [all]

nvidia-nat-core 1.8.0 caps cryptography at <47 while data-designer-engine 0.8.0 requires >=48.0.1, so nemo-platform[all] built from current main does not resolve from PyPI. Reproduce with uv pip install --no-config "data-designer==0.8.0" "nvidia-nat-core==1.8.0". Published 0.3.0 predates the conflict and still installs, so users today are unaffected — the next release is not.

Two things hid this. The repo carries [tool.uv] override-dependencies with cryptography>=50 (for CVE-2026-69247), and wheel-test installs from inside the checkout, so uv applies that override and tests a dependency set no user can obtain. Running the same install from /tmp, or with --no-config, fails.

A branch that fixed it (NAT >=1.9.0a20260811, --no-config on the wheel installs, and a uv tool install leg in wheel-test, all verified green) was reverted in 1c5a6b0: NAT publishes no stable release above 1.8.0, only daily 1.9.0a builds, and shipping pre-releases of our own toolkit in a released wheel is not a trade worth making. The follow-up, once NAT 1.9.0 is released:

  1. Bump nvidia-nat-core / nvidia-nat-langchain in plugins/nemo-agents and its examples. Note that uv accepts a pre-release only when a requirement it reads names one, so a pre-release line also requires naming every NAT distribution in the closure — a stable 1.9.0 removes that.
  2. Add --no-config to the wheel installs in wheel-test so CI stops resolving with the repo's overrides.
  3. Add the uv tool install matrix leg, which is the only leg that exercises the documented front door and the only one that catches this class of break, since uv tool install ignores project config.

The only interim that avoids pre-releases is downgrading data-designer from 0.8.0 to 0.7.0, whose engine wants cryptography>=46.0.7,<47 and so overlaps NAT 1.8.0. That is a feature downgrade across four pins in another team's plugin, and it still lands users below the CVE fix, so it is not proposed here. Note that every published NAT and data-designer release caps cryptography below the patched 50.0.0; only an upstream cap relaxation gets wheel users onto it.

Type of Change

  • Code change with documentation updates

Quality Gates

  • Tests added or updated for changed behavior
  • Documentation updated for user-visible behavior

Verification

  • Pull request title follows the repository's Conventional Commit format
  • Every commit includes an appropriate Signed-off-by: trailer
  • uv run pre-commit run -a passes, or any blocked checks are identified below
  • Targeted tests pass, or tests are marked not applicable above
  • No secrets, API keys, or credentials are included

Targeted validation:

  • End to end from /tmp, no checkout and no activated virtual environment, against a wheel built from this branch: uv tool install <wheel> lands on 3.13 and nemo --version reports 0.3.0.post258.dev0+1c5a6b0e0; nemo services run prints the uv tool remediation, and the same check in a pip virtual environment prints the pip remediation; adding the extra (with a local cryptography override for the conflict above) and running script/test-nemo-cli.sh boots all 17 services and reports platform healthy; default+system workspaces present (exit 0).
  • The version assertion was checked both ways with a stub on PATH: a bare nemo version 0.0.0 fails the script, and the CI sentinel 0.0.0.dev19700101000000 passes.
  • uv run pytest packages/nemo_platform_ext/tests — 1751 passed, 4 skipped. uv run pytest plugins/nemo-agents/tests — 989 passed, 1 failed: test_is_port_free_returns_false_for_occupied_port, which turns on kernel SO_REUSEADDR semantics on this VM and passes in CI.
  • uv run ruff check ., uv lock --check (uv 0.9.14), and bash -n script/compile-wheel-constraints.sh are clean. uv run pre-commit run -a — ruff, ruff format, ty typechecks, config reference, uv.lock drift, copyright headers pass; helm-docs, uv-lock (wants uv 0.9.14) and the three Flox version-consistency hooks fail for environment reasons only.
Open in Web Open in Cursor 

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added isolated uv tool install options for the CLI and full platform services.
    • CLI errors now suggest the appropriate installation command for missing services.
  • Bug Fixes

    • Improved troubleshooting for unsupported Python versions and unavailable dependency wheels.
    • CLI version checks now reject fallback or invalid values.
  • Documentation

    • Updated setup and installation guidance with clearer environment-specific options.
    • Clarified supported Python versions: 3.12 and 3.13.

cursoragent and others added 6 commits August 11, 2026 22:28
_version.py queried nemo-platform-sdk, a distribution that only exists in
the workspace. PyPI users get the SDK bundled inside the nemo-platform
wheel, so the lookup raised and fell back to 0.0.0 for nemo --version,
telemetry client_version, and the SDK client User-Agent.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
uv tool environments cannot be extended with pip. Detect them through the
uv-receipt.toml uv writes at the environment root and print the matching
uv tool install command instead.

Drops the Python 3.14 variant of the hint: the nemo-platform wheel
declares requires-python <3.14, so no install that can print this message
runs on 3.14.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
The documented path created a venv and installed nemo-platform without
the [all] extra, so nemo services run failed on a fresh install. Make the
tool install the lead everywhere the install is documented, keep the venv
variant for SDK imports and constrained environments, and label the
source checkout as the contributor path.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
uv enforces the lower bound of requires-python but installs the wheel on
Python 3.14 despite the declared <3.14 upper bound, where the [all]
extra then fails building dependencies from source. Naming the
interpreter keeps the documented command deterministic.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
test-nemo-cli.sh called nemo --version without checking the output, which
is how the 0.0.0 fallback went unnoticed. Assert it, and add a uv tool
install leg to the wheel-test matrix so the documented front door is
covered; the plugin has no CLI, so it keeps only the venv leg.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
The generated SDK pyproject claimed >=3.12 with a 3.14 classifier while
the nemo-platform wheel it ships in supports 3.12-3.13. Tighten both, and
build wheels on 3.12 by default rather than 3.11, which the wrapper's
requires-python already excludes.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
@github-actions github-actions Bot added the fix label Aug 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 32242/40915 78.8% 63.7%
Integration Tests 18649/38840 48.0% 20.7%

cursoragent and others added 7 commits August 11, 2026 23:32
Test wheels are stamped with a sentinel 0.0.0.dev<timestamp>, which a
prefix match rejected. The CLI's missing-metadata fallback is a bare
0.0.0, so compare against that.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
The generator has been syntactically invalid since it landed: a missing
closing quote on the version-probe line made bash swallow the following
lines, so `bash -n` fails and the file could never be regenerated. Also
resolve on 3.12, since the wrapper's requires-python floor now rejects the
3.11 probe environment, and pass --no-config so the snapshot is a set a
user can actually resolve rather than one shaped by the repo's
override-dependencies.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
nemo-platform[all] could not be installed from PyPI: nvidia-nat-core 1.8.0
caps cryptography at <47 while data-designer-engine 0.8.0 requires >=48.0.1.
The workspace hid this behind [tool.uv] override-dependencies, which no
wheel user gets. NAT 1.9 is the first line whose cap overlaps
data-designer's; it ships only pre-releases today, so every NAT
distribution in the closure is named explicitly — uv accepts a pre-release
only when a requirement it reads names one.

A user install now resolves to cryptography 48.0.1, which is below the
50.0.0 that fixes CVE-2026-69247; the workspace override keeps developers
on 50. Only an upstream cap relaxation can give wheel users the patched
version.

Regenerating the constraints also picks up version drift that accumulated
while the generator was broken.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
The install step runs inside the checkout, so uv applied the repo's
[tool.uv] override-dependencies and resolved a dependency set no user can
get. That is why the venv leg passed while the uv tool leg — which does not
read project config — failed on the real conflict.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
State the supported Python range once in the prerequisites and move the
--python escape hatch to CLI troubleshooting, where a user whose default
interpreter is out of range will look. uv enforces only the lower bound of
requires-python, so the flag cannot be dropped entirely.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
Drops the transitive packages NAT 1.9 no longer pulls (oci, langchain-exa,
langchain-milvus, wikipedia, and friends) and adds
nvidia-nat-config-optimizer.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
…lves"

This reverts commit 548ac20 and its license refresh (b4cc5b2), and
drops the CI changes that depend on them.

NAT publishes no stable release above 1.8.0 — only daily 1.9.0a builds — so
the bump put pre-releases of our own toolkit into a shipped wheel. Wait for
1.9.0 stable instead.

Deferred with it: the uv tool install leg in wheel-test and --no-config on
the wheel installs. Both only pass once nemo-platform[all] resolves without
the repo's override-dependencies, which needs the NAT cryptography cap
relaxed. Published 0.3.0 still installs, so this affects the next release,
not users today.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>
@callingmedic911
callingmedic911 marked this pull request as ready for review August 12, 2026 20:00
@callingmedic911
callingmedic911 requested review from a team as code owners August 12, 2026 20:00
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c51446a8-2120-4808-8c70-3258badcd510

📥 Commits

Reviewing files that changed from the base of the PR and between 76d1643 and f3b3c4a.

📒 Files selected for processing (1)
  • docs/cli/troubleshooting.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/cli/troubleshooting.mdx

📝 Walkthrough

Walkthrough

Changes

Installation and compatibility

Layer / File(s) Summary
Dynamic service installation commands
packages/nemo_platform_ext/src/nemo_platform_ext/local/*, packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/*, packages/nemo_platform_ext/tests/local/test_install.py
Service dependency errors now show uv or pip commands based on the environment. Tests cover both command paths.
Installation workflow documentation
README.md, SETUP.md, docs/cli/*, docs/get-started/setup.mdx, packages/nemo_platform/README.md
Documentation recommends uv tool install, explains the all extra, and retains virtual-environment alternatives.
Python version and metadata alignment
.github/actions/build-nemo-platform-wheel/action.yaml, script/*, tools/nemo-platform-sdk-tools/src/nemo_platform_sdk_tools/sdk/post_generation_update.py
Build tooling now uses Python 3.12. CLI version checks reject invalid or fallback versions. Generated metadata requires Python 3.12 through 3.13.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: making uv tool install the primary installation path for nemo-platform.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aditya/uv-tool-install-front-door-50d4

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/cli/index.mdx (1)

31-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Render parallel installation choices as tabs.

These sections present alternative installation workflows sequentially. The repository guideline requires tab sets for parallel alternatives.

  • docs/cli/index.mdx#L31-L44: place tool and virtual-environment installation in separate tabs.
  • docs/get-started/setup.mdx#L27-L43: place full-service, SDK/CLI-only, and virtual-environment workflows in separate tabs.
  • SETUP.md#L89-L91: place source-checkout and published-wheel setup in separate tabs.
  • packages/nemo_platform/README.md#L27-L34: place full-service and SDK/CLI-only installation in separate tabs.

As per coding guidelines, “Use tab sets for parallel alternatives or variants.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/cli/index.mdx` around lines 31 - 44, Render the parallel installation
workflows as tabs using the repository’s established tab-set pattern: in
docs/cli/index.mdx lines 31-44, separate tool and virtual-environment
installation; in docs/get-started/setup.mdx lines 27-43, separate full-service,
SDK/CLI-only, and virtual-environment workflows; in SETUP.md lines 89-91,
separate source-checkout and published-wheel setup; and in
packages/nemo_platform/README.md lines 27-34, separate full-service and
SDK/CLI-only installation.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/cli/index.mdx`:
- Around line 33-36: Update the published-wheel installation workflows to ensure
the uv tool executable directory is available before running nemo, using uv tool
update-shell followed by the required shell refresh or qualifying the PATH
statement. Apply this consistently in docs/cli/index.mdx lines 33-36,
docs/get-started/setup.mdx lines 27-30, SETUP.md lines 89-91, and
packages/nemo_platform/README.md lines 28-34.

In `@script/test-nemo-cli.sh`:
- Around line 61-62: Update the version validation condition after extracting
version to anchor the entire value, accepting only semantic versions with
optional .dev followed by exactly 14 digits or rc followed by digits. Preserve
rejection of 0.0.0 and add a regression case demonstrating that an invalid
suffix such as trailing garbage is rejected.

---

Nitpick comments:
In `@docs/cli/index.mdx`:
- Around line 31-44: Render the parallel installation workflows as tabs using
the repository’s established tab-set pattern: in docs/cli/index.mdx lines 31-44,
separate tool and virtual-environment installation; in
docs/get-started/setup.mdx lines 27-43, separate full-service, SDK/CLI-only, and
virtual-environment workflows; in SETUP.md lines 89-91, separate source-checkout
and published-wheel setup; and in packages/nemo_platform/README.md lines 27-34,
separate full-service and SDK/CLI-only installation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4d699ccb-60db-4c91-bc0d-e3f8c9785430

📥 Commits

Reviewing files that changed from the base of the PR and between d5e9e4e and 1c5a6b0.

⛔ Files ignored due to path filters (7)
  • sdk/python/nemo-platform/pyproject.toml is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/_version.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/cli/commands/services/cli.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/cli/commands/setup.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/local/install.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/local/services.py is excluded by !sdk/**
  • sdk/python/nemo-platform/tests/vendored/nemo_platform_ext/local/test_install.py is excluded by !sdk/**
📒 Files selected for processing (15)
  • .github/actions/build-nemo-platform-wheel/action.yaml
  • README.md
  • SETUP.md
  • docs/cli/index.mdx
  • docs/cli/troubleshooting.mdx
  • docs/get-started/setup.mdx
  • packages/nemo_platform/README.md
  • packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/services/cli.py
  • packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/setup.py
  • packages/nemo_platform_ext/src/nemo_platform_ext/local/install.py
  • packages/nemo_platform_ext/src/nemo_platform_ext/local/services.py
  • packages/nemo_platform_ext/tests/local/test_install.py
  • script/compile-wheel-constraints.sh
  • script/test-nemo-cli.sh
  • tools/nemo-platform-sdk-tools/src/nemo_platform_sdk_tools/sdk/post_generation_update.py

Comment thread docs/cli/index.mdx Outdated
Comment on lines +33 to +36
Install the PyPI `nemo-platform` wrapper package with [uv](https://docs.astral.sh/uv/). uv puts the `nemo` command on your PATH in its own isolated environment, so there is no virtual environment to create or activate. 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.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target files ---'
for f in docs/cli/index.mdx docs/get-started/setup.mdx SETUP.md packages/nemo_platform/README.md; do
  if [ -f "$f" ]; then
    echo "### $f"
    nl -ba "$f" | sed -n '20,105p'
  else
    echo "MISSING: $f"
  fi
done
printf '%s\n' '--- PATH and uv tool references ---'
rg -n -i 'uv tool|update-shell|PATH|nemo setup|nemo ' \
  docs/cli/index.mdx docs/get-started/setup.mdx SETUP.md packages/nemo_platform/README.md

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 20355


🌐 Web query:

uv tool install executable directory PATH uv tool update-shell official documentation

💡 Result:

When you install a tool using uv tool install, the tool's executables are placed in a designated executable directory [1][2]. For these tools to be accessible from your shell, this directory must be included in your system's PATH variable [2][3]. If the directory is not already in your PATH, uv will display a warning upon installation [1][2]. You can resolve this by running the command: uv tool update-shell This command automatically detects your shell and attempts to add the tool executable directory to your appropriate shell configuration file [2][4]. After running it, you must either restart your shell or source your shell configuration file (e.g., source ~/.bashrc) for the changes to take effect [4]. Key details about the executable directory: - To identify the current path of your tool executable directory, you can run: uv tool dir --bin [4][5]. - The default location is typically ~/.local/bin on Unix systems, though this can be configured via environment variables like UV_TOOL_BIN_DIR [4][5]. - If uv tool update-shell does not work for your specific setup, you can manually add the output of uv tool dir --bin to your PATH in your shell configuration file (e.g., export PATH="$(uv tool dir --bin):$PATH") [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path

targets = {
    "docs/cli/index.mdx": (33, 36),
    "docs/get-started/setup.mdx": (27, 30),
    "SETUP.md": (89, 91),
    "packages/nemo_platform/README.md": (28, 39),
}
for name, (start, end) in targets.items():
    path = Path(name)
    print(f"### {name}")
    if not path.is_file():
        print("MISSING")
        continue
    lines = path.read_text().splitlines()
    for number in range(start, min(end, len(lines)) + 1):
        print(f"{number}: {lines[number - 1]}")
    print("contains PATH setup:", any(
        "uv tool update-shell" in line or "uv tool dir --bin" in line
        for line in lines
    ))
    print()

print("repository-wide uv PATH setup references:")
for path in Path(".").rglob("*"):
    if path.is_file() and ".git" not in path.parts:
        try:
            text = path.read_text()
        except (UnicodeDecodeError, OSError):
            continue
        if "uv tool update-shell" in text or "uv tool dir --bin" in text:
            print(path)
PY

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 2213


Ensure the uv tool executable directory is on PATH before running nemo.

uv tool install does not guarantee that the executable directory is on the current shell’s PATH. Add uv tool update-shell with the required shell refresh, or qualify the PATH claim, in all four published-wheel workflows: docs/cli/index.mdx, docs/get-started/setup.mdx, SETUP.md, and packages/nemo_platform/README.md.

📍 Affects 4 files
  • docs/cli/index.mdx#L33-L36 (this comment)
  • docs/get-started/setup.mdx#L27-L30
  • SETUP.md#L89-L91
  • packages/nemo_platform/README.md#L28-L34
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/cli/index.mdx` around lines 33 - 36, Update the published-wheel
installation workflows to ensure the uv tool executable directory is available
before running nemo, using uv tool update-shell followed by the required shell
refresh or qualifying the PATH statement. Apply this consistently in
docs/cli/index.mdx lines 33-36, docs/get-started/setup.mdx lines 27-30, SETUP.md
lines 89-91, and packages/nemo_platform/README.md lines 28-34.

Source: MCP tools

Comment thread script/test-nemo-cli.sh Outdated
Comment on lines +61 to +62
version="${version_output#nemo version }"
if [[ "${version}" == "0.0.0" ]] || [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target script ---'
cat -n script/test-nemo-cli.sh | sed -n '1,110p'

printf '%s\n' '--- version-related references ---'
rg -n --hidden -S '0\.0\.0\.dev|nemo version|version_output|test-nemo-cli|dev[<"'\'' ]|__version__' . \
  -g '!node_modules' -g '!dist' -g '!build' | sed -n '1,240p'

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 29007


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- files ---'
git ls-files | rg '(^|/)(script/test-nemo-cli\.sh|.*(version|nemo).*)$' | sed -n '1,160p'

printf '%s\n' '--- target script ---'
cat -n script/test-nemo-cli.sh | sed -n '45,75p'

printf '%s\n' '--- version grammar references ---'
rg -n --hidden -S '0\.0\.0\.dev|nemo version|version_output|__version__|VERSION' . \
  -g '!node_modules' -g '!dist' -g '!build' | sed -n '1,240p'

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 39872


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
import pathlib, re

target = pathlib.Path("script/test-nemo-cli.sh")
text = target.read_text()
for i, line in enumerate(text.splitlines(), 1):
    if "version_output" in line or "version}" in line or "0.0.0" in line:
        print(f"{target}:{i}:{line}")

print("--- current condition behavior ---")
pattern = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+")
for value in ("1.2.3", "1.2.3garbage", "0.0.0", "0.0.0.dev123", "1.2", "v1.2.3"):
    accepted = value == "0.0.0" or pattern.match(value) is not None
    print(f"{value!r}: {'accepted' if accepted else 'rejected'}")

print("--- repository declarations containing supported version forms ---")
for path in pathlib.Path(".").rglob("*"):
    if not path.is_file() or any(part in {"node_modules", ".git", "dist", "build"} for part in path.parts):
        continue
    try:
        data = path.read_text(errors="ignore")
    except OSError:
        continue
    for i, line in enumerate(data.splitlines(), 1):
        if re.search(r"0\.0\.0\.dev|nemo version|__version__", line):
            print(f"{path}:{i}:{line}")
PY

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 6464


🌐 Web query:

"script/test-nemo-cli.sh" "0.0.0.dev"

💡 Result:

There is no standard or official script named "script/test-nemo-cli.sh" in the NVIDIA NeMo Agent Toolkit or related NeMo repositories [1][2][3][4]. Based on an analysis of the NeMo Agent Toolkit and associated testing infrastructure: 1. Testing Mechanism: The NeMo Agent Toolkit uses pytest as its primary test framework [2]. Automated testing is typically managed via the orchestration script ci/scripts/run_tests.py, which handles multi-project testing and environment setup [1][2]. 2. CLI Testing: CLI functionality (often involving the nat command) is validated through integrated test suites [5], including end-to-end (E2E) tests that verify CLI behavior under various conditions [6][5]. 3. Versioning: The version string "0.0.0.dev" is a common development placeholder used in Python packages (often managed via setuptools_scm or similar tools) to indicate an unreleased or development build, rather than a specific script argument. If you encountered this filename in a specific project or documentation, it is likely a custom, project-specific utility rather than an official component of the NeMo ecosystem [7][4]. You may wish to check the root directory of the repository where you found this reference for local documentation or a README file.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- exact Bash condition behavior ---'
for version in \
  '1.2.3' \
  '1.2.3garbage' \
  '0.0.0' \
  '0.0.0.dev123' \
  '0.0.0.dev20260512010101' \
  '1.2.3.dev123' \
  '1.2.3+local'
do
  if [[ "${version}" == "0.0.0" ]] || [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
    result=rejected
  else
    result=accepted
  fi
  printf '%-28s %s\n' "${version}" "${result}"
done

printf '%s\n' '--- version stamping implementation ---'
cat -n .github/scripts/stamp_sdk_version.py | sed -n '1,220p'

printf '%s\n' '--- version stamping tests ---'
cat -n tests/unit/release/test_stamp_sdk_version.py | sed -n '80,145p'

printf '%s\n' '--- relevant package configuration ---'
rg -n -A18 -B8 'dynamic|version|stamp_sdk_version|UV_DYNAMIC_VERSIONING_BYPASS' \
  pyproject.toml packages/nemo_platform_ext/pyproject.toml sdk/python/nemo-platform/pyproject.toml \
  .github/actions/build-nemo-platform-wheel/action.yaml 2>/dev/null | sed -n '1,260p'

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 26036


Match the complete stamped version grammar.

The current check accepts 1.2.3garbage. Anchor the match and allow valid .dev<14 digits> and rc<digits> suffixes. Add a regression case for an invalid suffix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@script/test-nemo-cli.sh` around lines 61 - 62, Update the version validation
condition after extracting version to anchor the entire value, accepting only
semantic versions with optional .dev followed by exactly 14 digits or rc
followed by digits. Preserve rejection of 0.0.0 and add a regression case
demonstrating that an invalid suffix such as trailing garbage is rejected.

Render the two install paths as tab sets, per the Fern guideline, and cut
the prose to what distinguishes them: the tool install is global and needs
no activation, the virtual environment is for importing the SDK.

Stop claiming uv puts nemo on PATH unconditionally — it lands in the uv
tool executable directory, so command-not-found now covers both install
methods and points at uv tool update-shell. The interpreter entry cites
uv's documented behaviour of ignoring requires-python for tools.

Also anchor the version assertion so a trailing-garbage suffix cannot pass
while the stamped .post/.dev/local forms still do.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/nemo_platform/README.md (1)

24-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a Python SDK tab.

This section provides CLI installation commands and only mentions SDK use. Add a Python SDK example in a tab set beside the CLI path, or link to docs/pysdk/client/index.mdx:5-15 from that tab. As per coding guidelines, “Provide both Python SDK and CLI examples in tab-sets for consistency and to support multiple user workflows.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nemo_platform/README.md` around lines 24 - 36, Add a tab set to the
installation section with separate CLI and Python SDK tabs, keeping the existing
CLI commands in the CLI tab and adding a Python SDK example or link to the
client documentation in the SDK tab. Use the repository’s established tab-set
format and preserve the current installation guidance.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/get-started/setup.mdx`:
- Around line 33-34: Update the installation guidance following the uv tool
installation in docs/get-started/setup.mdx (lines 33-34) and
packages/nemo_platform/README.md (lines 26-30): replace “available everywhere”
with instructions to run uv tool update-shell, then restart the shell or source
its configuration so nemo is available on PATH.
- Around line 33-34: Pin every [all] install command to
nemo-platform[all]==0.3.0 to avoid the current dependency conflict: update both
commands in docs/get-started/setup.mdx at lines 33-34 and 45-46, and both
commands in packages/nemo_platform/README.md at lines 29-30 and 35-36.
- Around line 33-34: Pin both uv tool installation commands in
docs/get-started/setup.mdx (lines 33-34) to Python 3.13 by adding the --python
3.13 option. Update packages/nemo_platform/README.md (lines 29-30) to list uv
>=0.9.14 in the prerequisites.

In `@packages/nemo_platform/README.md`:
- Around line 32-36: Update the installation instructions in the README to
include creating and activating a virtual environment before running the
nemo-platform installation command, or link to the existing setup guidance in
docs/get-started/setup.mdx.

---

Nitpick comments:
In `@packages/nemo_platform/README.md`:
- Around line 24-36: Add a tab set to the installation section with separate CLI
and Python SDK tabs, keeping the existing CLI commands in the CLI tab and adding
a Python SDK example or link to the client documentation in the SDK tab. Use the
repository’s established tab-set format and preserve the current installation
guidance.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 22aaf8bd-fc65-4591-963e-46fbc404f621

📥 Commits

Reviewing files that changed from the base of the PR and between 1c5a6b0 and 76d1643.

📒 Files selected for processing (6)
  • README.md
  • docs/cli/index.mdx
  • docs/cli/troubleshooting.mdx
  • docs/get-started/setup.mdx
  • packages/nemo_platform/README.md
  • script/test-nemo-cli.sh
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/cli/index.mdx
  • README.md
  • script/test-nemo-cli.sh
  • docs/cli/troubleshooting.mdx

Comment on lines +33 to +34
uv tool install "nemo-platform[all]"
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- docs/get-started/setup.mdx ---'
cat -n docs/get-started/setup.mdx | sed -n '1,80p'
printf '%s\n' '--- packages/nemo_platform/README.md ---'
cat -n packages/nemo_platform/README.md | sed -n '1,60p'
printf '%s\n' '--- uv tool references ---'
rg -n -i 'uv tool|PATH|shell reload|nemo-platform\[all\]' docs packages/nemo_platform README.md 2>/dev/null || true

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 50384


🏁 Script executed:

#!/bin/bash
set -u
printf '%s\n' '--- cited documentation ranges ---'
sed -n '25,42p' docs/get-started/setup.mdx
printf '%s\n' '--- cited README range ---'
sed -n '20,36p' packages/nemo_platform/README.md
printf '%s\n' '--- uv availability and relevant help ---'
if command -v uv >/dev/null 2>&1; then
  uv --version
  uv tool --help | sed -n '1,160p'
  printf '%s\n' '--- uv tool dir --bin ---'
  uv tool dir --bin
else
  printf '%s\n' 'uv is not installed in the sandbox'
fi

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 1358


🌐 Web query:

site:docs.astral.sh/uv uv tool install PATH shell restart executable directory

💡 Result:

When you install a tool using uv tool install, the tool's executables are placed in a specific executable directory (bin directory) [1][2][3]. For these tools to be accessible directly from your shell, this directory must be included in your system's PATH environment variable [1][4]. If the directory is not already in your PATH, uv will display a warning upon installation [1][2]. To resolve this, you can run the following command to automatically add the executable directory to your shell's configuration files: uv tool update-shell [1][5] After running this command, you will typically need to restart your shell session (or source your configuration file, e.g., source ~/.bashrc or source ~/.zshrc) for the changes to take effect and for the new PATH to be recognized [1][4]. You can locate the tool executable directory on your system by running: uv tool dir --bin [3] This ensures that the symlinks or copies of the tool's executables are correctly referenced by your shell [1][4].

Citations:


Document uv PATH setup

If the uv tool executable directory is not on PATH, nemo is not immediately available. In both files, replace “available everywhere” with guidance to run uv tool update-shell, then restart the shell or source its configuration.

📍 Affects 2 files
  • docs/get-started/setup.mdx#L33-L34 (this comment)
  • packages/nemo_platform/README.md#L26-L30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/get-started/setup.mdx` around lines 33 - 34, Update the installation
guidance following the uv tool installation in docs/get-started/setup.mdx (lines
33-34) and packages/nemo_platform/README.md (lines 26-30): replace “available
everywhere” with instructions to run uv tool update-shell, then restart the
shell or source its configuration so nemo is available on PATH.

Source: MCP tools


🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- referenced documentation ---'
for f in docs/get-started/setup.mdx packages/nemo_platform/README.md; do
  if [ -f "$f" ]; then
    printf '\n### %s\n' "$f"
    nl -ba "$f" | sed -n '20,55p'
  else
    printf 'MISSING %s\n' "$f"
  fi
done

printf '%s\n' '--- package metadata and all extra ---'
rg -n -S --glob '!*node_modules*' \
  'nemo-platform|optional-dependencies|extras_require|\[all\]|all\s*=|dependency|conflict|next release' \
  pyproject.toml setup.py setup.cfg packages docs .github 2>/dev/null | sed -n '1,240p'

printf '%s\n' '--- repository files near package metadata ---'
git ls-files | rg '(^|/)(pyproject\.toml|setup\.py|setup\.cfg|requirements[^/]*|CHANGELOG|.*release.*|.*manifest.*)$' | sed -n '1,160p'

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 33075


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- setup instructions ---'
for f in docs/get-started/setup.mdx packages/nemo_platform/README.md; do
  printf '\n### %s\n' "$f"
  sed -n '20,55p' "$f"
done

printf '%s\n' '--- package metadata ---'
sed -n '1,220p' packages/nemo_platform/pyproject.toml

printf '%s\n' '--- relevant repository changes ---'
git diff --stat
git diff -- docs/get-started/setup.mdx packages/nemo_platform/README.md packages/nemo_platform/pyproject.toml | sed -n '1,260p'

printf '%s\n' '--- all references to the published install commands ---'
rg -n -F \
  -e 'uv tool install "nemo-platform[all]"' \
  -e 'pip install "nemo-platform[all]"' \
  -e 'nemo-platform[all]' \
  docs packages README.md 2>/dev/null | sed -n '1,220p'

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 37354


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- wrapper extra definitions ---'
rg -n -A12 -B4 \
  '^\[project\.optional-dependencies\]|^all\s*=|^services\s*=|^core-service\s*=|^service' \
  packages/nemo_platform/pyproject.toml | sed -n '1,260p'

printf '%s\n' '--- bundling documentation ---'
sed -n '1,155p' packages/nemo_platform/BUNDLING.md

printf '%s\n' '--- package version and release references ---'
rg -n -S \
  '^\[tool\.hatch|version|release|0\.[0-9]+\.[0-9]+|next release|unresolved|conflict' \
  packages/nemo_platform/pyproject.toml packages/nemo_platform/BUNDLING.md \
  docs/about/release-notes/current-release.mdx .github/release* .github/workflows/release.yaml \
  2>/dev/null | sed -n '1,240p'

printf '%s\n' '--- repository state ---'
git status --short
git log -5 --oneline -- packages/nemo_platform/pyproject.toml docs/get-started/setup.mdx packages/nemo_platform/README.md

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 32952


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- recent dependency-related commits ---'
for c in 1c5a6b0e0 89868b26e 548ac20d8 76d1643aa; do
  printf '\n### %s\n' "$c"
  git show --stat --oneline "$c"
  git show --format=fuller --no-ext-diff "$c" -- \
    packages/nemo_platform/pyproject.toml \
    docs/get-started/setup.mdx \
    packages/nemo_platform/README.md \
    plugins/nemo-agents/pyproject.toml \
    uv.lock | sed -n '1,280p'
done

printf '%s\n' '--- resolver tooling availability ---'
command -v uv || true
command -v pip || true
command -v python3 || true

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
import subprocess
import tomllib
from pathlib import Path

metadata = tomllib.loads(
    Path("packages/nemo_platform/pyproject.toml").read_text(encoding="utf-8")
)
extras = metadata["project"]["optional-dependencies"]

assert extras["all"] == ["nemo-platform[services]"]
assert any(dep == "nemo-platform[plugins]" for dep in extras["services"])
assert any("nvidia-nat-core>=1.8.0,<1.9" == dep for dep in extras["nemo-agents-plugin"])

for path in (
    Path("docs/get-started/setup.mdx"),
    Path("packages/nemo_platform/README.md"),
):
    text = path.read_text(encoding="utf-8")
    assert text.count('uv tool install "nemo-platform[all]"') == 1
    assert text.count('pip install "nemo-platform[all]"') == 1
    print(f"{path}: both published commands are unpinned")

message = subprocess.check_output(
    ["git", "show", "-s", "--format=%B", "1c5a6b0e0"],
    text=True,
)
required = (
    "Published 0.3.0 still installs",
    "this affects the next release",
    "nemo-platform[all] resolves without the repo's override-dependencies",
)
for phrase in required:
    assert phrase in message
print("1c5a6b0e0: records that 0.3.0 installs but the next release remains unresolved")
print("all -> services:", extras["all"])
print("NAT constraint:", next(
    dep for dep in extras["nemo-agents-plugin"]
    if dep.startswith("nvidia-nat-core")
))
PY

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 283


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
import subprocess
from pathlib import Path

pyproject = Path("packages/nemo_platform/pyproject.toml").read_text(encoding="utf-8")
for expected in (
    'all = ["nemo-platform[services]"]',
    '"nemo-platform[plugins]"',
    '"nvidia-nat-core>=1.8.0,<1.9"',
):
    assert expected in pyproject, expected

for path in (
    Path("docs/get-started/setup.mdx"),
    Path("packages/nemo_platform/README.md"),
):
    text = path.read_text(encoding="utf-8")
    assert text.count('uv tool install "nemo-platform[all]"') == 1
    assert text.count('pip install "nemo-platform[all]"') == 1
    print(f"{path}: both published commands are unpinned")

message = subprocess.check_output(
    ["git", "show", "-s", "--format=%B", "1c5a6b0e0"],
    text=True,
)
for phrase in (
    "Published 0.3.0 still installs",
    "this affects the next release",
    "nemo-platform[all] resolves without the repo's override-dependencies",
):
    assert phrase in message, phrase

print("1c5a6b0e0: records that 0.3.0 installs but the next release remains unresolved")
print("all -> services and NAT remains constrained to the 1.8 line")
PY

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 458


Pin or gate the [all] install commands. NAT 1.8 caps cryptography below the version required by data-designer==0.8.0. Use nemo-platform[all]==0.3.0 until the dependency conflict is resolved, or defer all four commands in docs/get-started/setup.mdx and packages/nemo_platform/README.md.

📍 Affects 2 files
  • docs/get-started/setup.mdx#L33-L34 (this comment)
  • docs/get-started/setup.mdx#L45-L46
  • packages/nemo_platform/README.md#L29-L30
  • packages/nemo_platform/README.md#L35-L36
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/get-started/setup.mdx` around lines 33 - 34, Pin every [all] install
command to nemo-platform[all]==0.3.0 to avoid the current dependency conflict:
update both commands in docs/get-started/setup.mdx at lines 33-34 and 45-46, and
both commands in packages/nemo_platform/README.md at lines 29-30 and 35-36.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- relevant files ---'
git ls-files 'docs/get-started/setup.mdx' 'packages/nemo_platform/README.md' \
  | while IFS= read -r f; do
    printf '\n--- %s ---\n' "$f"
    wc -l "$f"
    rg -n -C 5 'uv|python|requires-python|requires_python|Python|version' "$f" || true
  done

printf '\n--- package and project metadata candidates ---\n'
git ls-files | rg '(^|/)(pyproject\.toml|setup\.py|setup\.cfg|.*requirements.*|.*uv.*|README\.md)$' \
  | head -200

printf '\n--- Python requirement declarations ---\n'
rg -n -C 3 'requires-python|requires_python|python_requires|Programming Language :: Python|Python :: 3\.(12|13)|uv' \
  --glob 'pyproject.toml' --glob 'setup.py' --glob 'setup.cfg' --glob '*.md' --glob '*.mdx' . \
  | head -300

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 35084


🏁 Script executed:

#!/bin/bash
set -eu

for f in packages/nemo_platform/pyproject.toml pyproject.toml .cursor/rules/uv.mdc README.md; do
  if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
    printf '\n--- %s ---\n' "$f"
    wc -l "$f"
    rg -n -C 6 'requires-python|requires_python|python|tool\.uv|uv|index|resolution|conflict|nemo-platform' "$f" | head -240
  fi
done

printf '\n--- all nemo-platform Python requirements ---\n'
rg -n -C 4 'requires-python|requires_python|python_requires' \
  packages/nemo_platform/pyproject.toml sdk/python/nemo-platform/pyproject.toml \
  pyproject.toml 2>/dev/null || true

printf '\n--- install command occurrences ---\n'
rg -n -C 2 'uv tool install "nemo-platform\[all\]"|uv tool install' \
  docs/get-started/setup.mdx packages/nemo_platform/README.md README.md

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 27416


🌐 Web query:

Astral uv official documentation uv tool install --python interpreter selection default behavior requires-python

💡 Result:

When using uv tool install, the default Python interpreter selection and the handling of requires-python constraints behave according to the following logic: Python Interpreter Selection By default, uv attempts to select an appropriate Python interpreter for the tool environment [1]. It uses standard Python discovery logic [1], which searches for interpreters in the PATH, virtual environments, and managed installations (via uv python install) [2][3][4]. If no specific interpreter is requested via the --python flag, uv follows a preference hierarchy [5][4]: 1. The python-preference setting (defaulting to managed) determines whether uv prioritizes its own managed installations or system-installed interpreters [5][4]. 2. If multiple candidates exist, uv prioritizes newer versions among managed installations, while for system interpreters, it typically selects the first compatible version found [5][4]. 3. If no suitable Python version is found, uv may automatically download and install a required managed Python version [3][4]. Requires-Python Handling Historically, uv tool install did not automatically infer Python requirements from a package's metadata, which often led to resolution failures if the default discovered interpreter was incompatible [6][7]. However, recent updates have introduced mechanisms to improve this [8]: - Inference: uv can now inspect the requires-python metadata (e.g., from pyproject.toml or wheel distribution metadata) to refine the Python version request [8]. - Resolution and Refinement: If initial resolution fails due to an incompatible interpreter, uv can automatically attempt to refine the choice—including downloading a compliant managed Python version—to satisfy the tool's requirements [9]. For precise control, you can always explicitly specify the required Python version or range using the --python flag [1], for example: uv tool install --python ">=3.10" This approach overrides default discovery and ensures the tool is installed in an environment using a compatible interpreter [1][7].

Citations:


🌐 Web query:

site:docs.astral.sh/uv OR site:github.com/astral-sh/uv uv 0.9.14 tool install requires-python compatible interpreter release

💡 Result:

In uv version 0.9.14, the uv tool install command is designed to be aware of the requires-python metadata of the package being installed [1][2]. When you run uv tool install, uv performs the following steps: 1. Initial Interpreter Selection: It initially identifies a Python interpreter based on your environment and system defaults [2]. 2. Resolution and Compatibility Check: It attempts to resolve the package's dependencies. If the initially selected interpreter does not satisfy the package's Requires-Python constraint, the resolution will fail [3][1]. 3. Automated Refinement: If resolution fails due to an incompatible Python version, uv attempts to automatically refine the interpreter [3][1]. It will search for a compatible Python version—including downloading a managed Python interpreter if necessary—that satisfies the package's requires-python requirements [3][1]. It is important to note that uv tool ignores local project-specific configuration files such as .python-version or pyproject.toml files found in the current working directory [4]. Additionally, while uv respects the lower bounds of requires-python constraints during dependency resolution, it intentionally ignores upper bounds [5]. You can always override the automatic discovery by explicitly specifying the desired interpreter using the --python flag, for example: uv tool install --python 3.12 <package_name> [4][6].

Citations:


🌐 Web query:

site:github.com/astral-sh/uv/pull/19577 uv tool install requires-python version

💡 Result:

When using uv tool install, the command generally ignores non-global Python version requests, including requires-python values found in a pyproject.toml file [1][2]. Instead, it uses standard Python version discovery logic to create an isolated virtual environment for the tool [1][2]. If you need to use a specific Python version for a tool, you should use the --python flag during the installation command [1][2]. Note: Recent developments in the uv repository (as of mid-2026) have introduced experimental efforts to infer Python version requirements from source trees (e.g., peeking at pyproject.toml when installing tools from a local directory) to improve compatibility and reduce installation failures [3]. However, the stable documentation maintains that uv tool install generally ignores requires-python metadata to maintain consistent, isolated environments [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

if command -v uv >/dev/null 2>&1; then
  printf '%s\n' '--- installed uv version ---'
  uv --version
  printf '%s\n' '--- uv tool install options ---'
  uv tool install --help | rg -n -C 2 -- '--python|requires-python|version|managed'
else
  printf '%s\n' 'uv is not installed in the sandbox\n'
fi

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 200


🌐 Web query:

site:docs.astral.sh/uv/concepts/tools/ "requires-python" "uv tool install"

💡 Result:

When using the uv tool install command, uv ignores the requires-python constraint specified in a pyproject.toml file [1][2]. While uv uses standard Python version discovery logic to create an isolated virtual environment for the tool, it explicitly excludes non-global Python version requests, including.python-version files and requires-python metadata [1][2]. If you need to install a tool with a specific Python version requirement, you must explicitly provide the --python option during the installation command [1][2]. For example: uv tool install --python If the Python version selected for the tool is later uninstalled, the tool environment will be broken and the tool may become unusable [1][2].

Citations:


🌐 Web query:

site:docs.astral.sh/uv/concepts/tools/ "The Python version" "--python" tool install

💡 Result:

To specify a Python version when installing a tool with the uv package manager, you can use the --python option [1][2]. For example, to install a package with a specific Python version using uv, you would use the following syntax [1][2]: uv tool install --python Each tool installed via uv is linked to a specific Python version [1][2]. When using the --python option, uv uses its standard Python version discovery logic to locate the requested version, while ignoring local configuration files like.python-version or pyproject.toml requirements [1][2]. If the specified Python version is later uninstalled from your system, the tool environment will become broken and the tool may no longer function [1][2].

Citations:


🌐 Web query:

site:docs.astral.sh/uv/guides/tools/ "python" "tool install"

💡 Result:

To install Python tools for personal use, the current recommended approach is to use tools like uv or pipx, which create isolated environments for each application to prevent dependency conflicts. Using uv, you can install a tool into a persistent environment where its executables are added to your PATH, allowing you to run them directly [1][2]. To install a tool using uv, use the following command: uv tool install For example, to install ruff: uv tool install ruff When installed this way, uv places the tool's executables in a bin directory [1][2]. If the directory is not already in your PATH, you can update your shell configuration using: uv tool update-shell If you want to specify a particular Python version for the tool, you can provide it during installation [1][2]: uv tool install --python 3.10 ruff Unlike installing packages with standard pip into your global environment, using these dedicated tool managers ensures that each application's dependencies remain isolated [1][2].

Citations:


🌐 Web query:

site:docs.astral.sh/uv/concepts/tools/ "Requires-Python" package metadata tool environment

💡 Result:

The Requires-Python metadata field is a specification used in Python packaging to declare the range of Python versions that a package or project supports [1][2][3]. This field is typically defined in a projects configuration file, such as pyproject.toml. When working with packaging tools and environments, the Requires-Python value serves as a constraint for installation. For instance, if a user attempts to install a package into an environment running a Python version outside the range specified in Requires-Python, the packaging tool should identify this incompatibility and prevent the installation. However, usage can vary by tool context. For example, some modern tooling like uv, when managing isolated tool environments, may ignore the Requires-Python value from a projects pyproject.toml in favor of specific version discovery logic or explicit user-provided version requirements [1][3]. In these specific tool environments, the tool links the environment to a designated Python version rather than strictly adhering to the metadata constraint defined within the project itself [1][2].

Citations:


Pin the tool environment to Python 3.13. uv tool install does not use local Python constraints during interpreter discovery, while nemo-platform requires Python 3.12–3.13. Apply --python 3.13 to both commands. Add uv >=0.9.14 to the package README prerequisites.

📍 Affects 2 files
  • docs/get-started/setup.mdx#L33-L34 (this comment)
  • packages/nemo_platform/README.md#L29-L30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/get-started/setup.mdx` around lines 33 - 34, Pin both uv tool
installation commands in docs/get-started/setup.mdx (lines 33-34) to Python 3.13
by adding the --python 3.13 option. Update packages/nemo_platform/README.md
(lines 29-30) to list uv >=0.9.14 in the prerequisites.

Source: MCP tools

Comment on lines +32 to 36
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]"
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,90p' packages/nemo_platform/README.md
printf '\n--- related setup references ---\n'
rg -n -i 'virtual environment|python -m venv|nemo-platform\[all\]|pip install|uv sync|NeMoPlatform' packages/nemo_platform docs README.md 2>/dev/null | head -200

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 28297


🏁 Script executed:

cat -n packages/nemo_platform/README.md | sed -n '1,90p'
printf '\n--- related setup references ---\n'
rg -n -i 'virtual environment|python -m venv|nemo-platform\[all\]|pip install|uv sync|NeMoPlatform' packages/nemo_platform docs README.md 2>/dev/null | head -200

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 27070


🏁 Script executed:

sed -n '25,60p' docs/get-started/setup.mdx
printf '\n--- CLI installation tabs ---\n'
sed -n '32,60p' docs/cli/index.mdx
printf '\n--- interpreter behavior probe ---\n'
python3 - <<'PY'
import os
import sys
print("current interpreter:", sys.executable)
print("virtual environment active:", sys.prefix != sys.base_prefix)
print("pip target for `python -m pip`:", sys.prefix)
print("PATH pip candidates:")
for directory in os.environ.get("PATH", "").split(os.pathsep):
    candidate = os.path.join(directory, "pip")
    if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
        print(candidate)
PY

Repository: NVIDIA-NeMo/nemo-platform

Length of output: 1738


Create and activate the virtual environment before installing.

This command can install into the current system interpreter. Add the setup sequence or link to docs/get-started/setup.mdx.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nemo_platform/README.md` around lines 32 - 36, Update the
installation instructions in the README to include creating and activating a
virtual environment before running the nemo-platform installation command, or
link to the existing setup guidance in docs/get-started/setup.mdx.

Drop the uv tool update-shell step: uv's own installer puts its bin
directory on PATH, so the command-not-found entry only needs the virtual
environment case. Cut the wheel-publishing detail from the interpreter
entry.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Aditya Pandey <aditya@autospace.co>

@mckornfield mckornfield left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

know we have the nat question still. I also think we should make pip install the last option, personally I'd prefer just uv tool install or uv install and then pip last (or not at all because it sucks)

Comment thread docs/cli/index.mdx

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we just prefer the uv way, tool or not?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants