fix: manage Python dynamic plugin environments - #337
Conversation
Provision isolated Python environments during plugin registration, persist and validate them for activation, and clean them up safely on removal. Reject direct Python worker loading without managed lifecycle state and fix Unix host-runtime gRPC authority handling. Signed-off-by: Will Killian <wkillian@nvidia.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughManaged Python environments are now provisioned during plugin registration, stored on records, forwarded into worker activation, validated at inspect/validate time, and cleaned up on removal. Docs, tests, the Python SDK, and an end-to-end workflow were updated to use the new lifecycle-managed environment flow. ChangesManaged Python Environment Lifecycle
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/core/src/plugin/dynamic/worker.rs (1)
714-723: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winClear host Python env before spawning the worker.
Commandinherits the daemon environment. If Relay runs inside a virtualenv or withPYTHONHOME/PYTHONPATHset, the managed Python worker can resolve host packages instead of the plugin venv, breaking isolation.Suggested hardening
command + .env_remove("PYTHONHOME") + .env_remove("PYTHONPATH") + .env_remove("VIRTUAL_ENV") .current_dir(manifest_dir) .env("NEMO_RELAY_WORKER_ID", spec.activation_id) .env("NEMO_RELAY_PLUGIN_ID", spec.plugin_id) .env("NEMO_RELAY_WORKER_SOCKET", spec.worker_endpoint)🤖 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 `@crates/core/src/plugin/dynamic/worker.rs` around lines 714 - 723, The worker spawn setup in dynamic worker launch still inherits the daemon’s Python environment, which can break isolation. In the command-building path around the current_dir/env chain for the worker process, explicitly remove host Python-related variables such as PYTHONHOME, PYTHONPATH, and any virtualenv markers before spawning the managed worker, while keeping the existing NEMO_RELAY_* env values intact. Use the command construction in the worker launch flow to locate the fix.
🤖 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 `@crates/cli/tests/coverage/plugins_lifecycle_tests.rs`:
- Around line 638-647: The test only checks the Python executables, so it can
miss regressions in the actual provisioning command. Tighten the assertions in
the lifecycle test using runner.calls() to verify the managed install command
itself from the provisioning flow, including the expected venv invocation and
the non-editable pip install contract, so it catches changes like installing
source.manifest_root, installing the manifest file, or switching to editable
mode.
In `@crates/core/src/plugin/dynamic/worker.rs`:
- Around line 694-700: The Python worker launch path in
`resolve_python_executable`/`DynamicPluginRegistry::update_environment` is
trusting a stored `environment_ref` path without verifying it is Relay-managed.
Add a validation step that checks the ref resolves to the deterministic managed
`.dynamic-plugin-environments` location before accepting it in the readiness
path, and reject any path outside that managed area even if `<ref>/bin/python`
exists. If needed, prefer storing and validating an opaque environment ID in
`environment_ref` instead of a raw filesystem path so `worker.rs` only launches
lifecycle-managed environments.
In `@crates/core/tests/integration/worker_plugin_tests.rs`:
- Around line 848-872: The cleanup at the end of the Python worker integration
test is not panic-safe, so failures before the final calls can leak subscriber
and plugin state. Wrap the teardown in a drop guard or equivalent RAII cleanup
near the test setup so `deregister_subscriber`, `clear_plugin_configuration`,
and `activation.clear()` always run, even if assertions after
`register_subscriber`/`flush_subscribers` fail.
In `@examples/python-grpc-worker-plugin/README.md`:
- Around line 34-37: The README text for the plugin worker startup contract
incorrectly mentions a plugin ID environment variable. Update the documentation
around serve_plugin and the manifest entrypoint to list only the
runtime-provided variables it actually supplies: worker socket, host socket,
activation ID, and activation token. Keep plugin ID described as coming from the
plugin implementation, not from an environment variable.
In `@python/plugin/README.md`:
- Around line 10-14: The README section jumps straight into the example block
without a complete lead-in sentence, which breaks the repo doc convention. Add a
short introductory sentence immediately before the existing example so the
paragraph in this section flows naturally into the block; update the surrounding
prose near the dependency/entrypoint guidance and keep the example itself
unchanged.
---
Outside diff comments:
In `@crates/core/src/plugin/dynamic/worker.rs`:
- Around line 714-723: The worker spawn setup in dynamic worker launch still
inherits the daemon’s Python environment, which can break isolation. In the
command-building path around the current_dir/env chain for the worker process,
explicitly remove host Python-related variables such as PYTHONHOME, PYTHONPATH,
and any virtualenv markers before spawning the managed worker, while keeping the
existing NEMO_RELAY_* env values intact. Use the command construction in the
worker launch flow to locate the fix.
🪄 Autofix (Beta)
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: ASSERTIVE
Plan: Enterprise
Run ID: 62815372-9c88-41b0-8028-e290d3774d50
📒 Files selected for processing (17)
crates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/tests/coverage/server_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rsexamples/python-grpc-worker-plugin/.gitignoreexamples/python-grpc-worker-plugin/README.mdexamples/python-grpc-worker-plugin/relay-plugin.tomljustfilepython/plugin/README.mdpython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_worker_sdk.py
💤 Files with no reviewable changes (1)
- examples/python-grpc-worker-plugin/.gitignore
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (35)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/cli/tests/coverage/server_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/responses.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/cli/tests/coverage/server_tests.rscrates/cli/tests/cli_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/cli/tests/coverage/server_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/responses.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/cli/tests/coverage/server_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/responses.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/cli/tests/coverage/server_tests.rsexamples/python-grpc-worker-plugin/relay-plugin.tomlcrates/core/src/plugin/dynamic/registry.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/responses.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/cli/tests/coverage/server_tests.rsexamples/python-grpc-worker-plugin/relay-plugin.tomlpython/plugin/README.mdcrates/core/src/plugin/dynamic/registry.rsexamples/python-grpc-worker-plugin/README.mdcrates/cli/src/server.rscrates/cli/tests/cli_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/src/plugins/lifecycle/responses.rspython/plugin/src/nemo_relay_plugin/_api.pycrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/cli/tests/coverage/server_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/src/plugins/lifecycle/responses.rspython/plugin/src/nemo_relay_plugin/_api.pycrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/cli/tests/coverage/server_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/cli/src/server.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/responses.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/cli/tests/coverage/server_tests.rsexamples/python-grpc-worker-plugin/relay-plugin.tomlpython/plugin/README.mdcrates/core/src/plugin/dynamic/registry.rsexamples/python-grpc-worker-plugin/README.mdcrates/cli/src/server.rscrates/cli/tests/cli_tests.rsjustfilepython/tests/plugin/test_worker_sdk.pycrates/cli/src/plugins/lifecycle/responses.rspython/plugin/src/nemo_relay_plugin/_api.pycrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/src/plugins/lifecycle.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/cli/tests/coverage/server_tests.rscrates/cli/tests/cli_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/tests/integration/worker_plugin_tests.rs
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
examples/python-grpc-worker-plugin/relay-plugin.tomlpython/tests/plugin/test_worker_sdk.pypython/plugin/src/nemo_relay_plugin/_api.py
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
examples/python-grpc-worker-plugin/relay-plugin.tomlexamples/python-grpc-worker-plugin/README.md
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
examples/python-grpc-worker-plugin/relay-plugin.tomlpython/plugin/README.mdexamples/python-grpc-worker-plugin/README.mdpython/tests/plugin/test_worker_sdk.pypython/plugin/src/nemo_relay_plugin/_api.py
**/*.toml
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in TOML configuration files using hash comment syntax
Files:
examples/python-grpc-worker-plugin/relay-plugin.toml
**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.md
📄 CodeRabbit inference engine (.agents/skills/contribute-integration/SKILL.md)
Documentation must be updated if activation or usage changed
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links ...
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/{docs,examples,**/*.md,*.patch,*.diff,.github,*.sh,*.yaml,*.yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update documentation, examples, CI configuration, and patch artifacts when performing rename operations
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/README.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update relevant crate or package README when that surface changed
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
justfile
📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)
justfile: Keep helper function inputs aligned when editing version helpers:set_project_versionshould call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensureset_cargo_workspace_versionhelper updates[workspace.package].versionplus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensureset_node_package_versionshelper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries
Files:
justfile
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}
⚙️ CodeRabbit configuration file
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.
Files:
justfile
**/test_*.{py,py}
📄 CodeRabbit inference engine (.agents/skills/add-integration/SKILL.md)
Relevant integration tests or smoke coverage must exist for the integration path
Files:
python/tests/plugin/test_worker_sdk.py
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
python/tests/plugin/test_worker_sdk.pypython/plugin/src/nemo_relay_plugin/_api.py
python/**/*test*.py
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
python/**/*test*.py: Do not add@pytest.mark.asyncioto any test in Python test files
Do not add a-> Nonereturn type annotation to test functions
When mocking a class, useunittest.mock.MagicMockorunittest.mock.AsyncMockwith thespecconstructor argument when necessary, rather than defining a new class
Prefix mocked class names withmock, notfake
Prefer pytest fixtures over helper methods in Python tests
Preferpytest.mark.parametrizeover creating individual tests for different input types
Files:
python/tests/plugin/test_worker_sdk.py
python/**/{conftest.py,*test*.py}
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
When creating a fixture follow the pattern:
@pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) def <fixture_name>_fixture() -> <return_type>:and only specify the scope argument when the value is something other than "function"
Files:
python/tests/plugin/test_worker_sdk.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
python/tests/plugin/test_worker_sdk.pypython/plugin/src/nemo_relay_plugin/_api.py
🔇 Additional comments (11)
crates/cli/src/plugins/lifecycle/responses.rs (1)
104-104: LGTM!Also applies to: 124-124, 232-232, 253-280, 300-300
crates/cli/src/server.rs (1)
270-270: LGTM!crates/cli/tests/cli_tests.rs (1)
96-97: LGTM!crates/cli/tests/coverage/plugins_lifecycle_tests.rs (2)
5-8: LGTM!Also applies to: 52-52, 148-149, 159-245, 573-637
648-945: LGTM!Also applies to: 1307-1307, 1577-1634, 2369-2372
crates/cli/tests/coverage/server_tests.rs (1)
1738-1738: LGTM!crates/core/tests/integration/worker_plugin_tests.rs (1)
813-822: 📐 Maintainability & Code QualityCovered by the test recipe.
python/plugin/src/nemo_relay_plugin/_api.py (1)
1137-1137: LGTM!Also applies to: 1646-1653, 1705-1706
python/tests/plugin/test_worker_sdk.py (1)
48-48: LGTM!Also applies to: 1516-1535, 1682-1682
justfile (1)
1180-1242: LGTM!examples/python-grpc-worker-plugin/relay-plugin.toml (1)
20-25: 🎯 Functional CorrectnessNo action needed: this TOML has a single
[source]block and a single[integrity]block.> Likely an incorrect or invalid review comment.
Signed-off-by: Will Killian <wkillian@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
crates/core/src/plugin/dynamic/worker.rs (1)
753-760: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy liftEnforce the actual managed root, not just the path suffix.
is_managed_pathstill accepts any absolute path whose last two components are.dynamic-plugin-environments/<sha256(plugin_id)>. A hand-edited registry record, or any future caller ofDynamicPluginRegistry::update_environment, can therefore point a Python worker at an interpreter outside Relay-managed state as long as it is placed under that suffix. The new tests even encode that behavior by treating an arbitrary temp directory with the right suffix as valid until the laterpython.is_file()check. Validate against the scoped lifecycle root before launch, or store an opaque environment ID instead of a raw filesystem path.🤖 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 `@crates/core/src/plugin/dynamic/worker.rs` around lines 753 - 760, The current is_managed_path check in dynamic/worker.rs only verifies the path suffix, so a crafted absolute path can still be treated as managed. Update the validation around is_managed_path in the environment launch flow to confirm the path lives under the actual Relay-managed lifecycle root used by DynamicPluginRegistry and not just under .dynamic-plugin-environments/<expected_name>. If needed, resolve the scoped root from the registry or carry an opaque environment identifier instead of trusting a raw filesystem path, and keep the later python.is_file() check as a secondary guard rather than the only protection.
🤖 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 `@crates/core/tests/unit/dynamic_worker_tests.rs`:
- Around line 30-51: The current test in dynamic_worker_tests only covers the
hash/suffix validation in resolve_python_executable and misses the new
symlink_metadata rejection branch. Extend
python_environment_resolution_requires_lifecycle_managed_path to create a
.dynamic-plugin-environments/<digest> entry as a symlink and call
resolve_python_executable with that path. Assert that the error from
resolve_python_executable contains the symbolic-link rejection message ("must
not be a symbolic link") so the symlink escape path is covered.
---
Duplicate comments:
In `@crates/core/src/plugin/dynamic/worker.rs`:
- Around line 753-760: The current is_managed_path check in dynamic/worker.rs
only verifies the path suffix, so a crafted absolute path can still be treated
as managed. Update the validation around is_managed_path in the environment
launch flow to confirm the path lives under the actual Relay-managed lifecycle
root used by DynamicPluginRegistry and not just under
.dynamic-plugin-environments/<expected_name>. If needed, resolve the scoped root
from the registry or carry an opaque environment identifier instead of trusting
a raw filesystem path, and keep the later python.is_file() check as a secondary
guard rather than the only protection.
🪄 Autofix (Beta)
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: ASSERTIVE
Plan: Enterprise
Run ID: 75f9e3ad-08f8-4aff-a4be-473eb1cfb235
📒 Files selected for processing (8)
crates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/unit/dynamic_worker_tests.rsexamples/python-grpc-worker-plugin/README.mdpython/plugin/README.md
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (26)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/tests/unit/dynamic_worker_tests.rspython/plugin/README.mdexamples/python-grpc-worker-plugin/README.mdcrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/core/tests/unit/dynamic_worker_tests.rspython/plugin/README.mdexamples/python-grpc-worker-plugin/README.mdcrates/core/src/plugin/dynamic/worker.rscrates/cli/src/plugins/lifecycle/environment.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/worker_plugin_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/dynamic_worker_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rs
**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.md
📄 CodeRabbit inference engine (.agents/skills/contribute-integration/SKILL.md)
Documentation must be updated if activation or usage changed
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links ...
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/{docs,examples,**/*.md,*.patch,*.diff,.github,*.sh,*.yaml,*.yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update documentation, examples, CI configuration, and patch artifacts when performing rename operations
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/README.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update relevant crate or package README when that surface changed
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
examples/python-grpc-worker-plugin/README.md
🔇 Additional comments (8)
examples/python-grpc-worker-plugin/README.md (1)
12-36: LGTM!python/plugin/README.md (1)
10-16: LGTM!crates/core/tests/integration/worker_plugin_tests.rs (1)
753-780: LGTM!Also applies to: 821-950
crates/core/tests/unit/dynamic_worker_tests.rs (1)
53-64: LGTM!crates/cli/src/plugins/lifecycle/environment.rs (2)
15-35: LGTM!Also applies to: 45-143, 145-196
15-196: 📐 Maintainability & Code QualityRun the Rust checks
cargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings, andjust test-rustbefore merging this Rust change.crates/cli/src/plugins/lifecycle.rs (1)
58-186: LGTM!Also applies to: 198-220, 605-690, 718-758, 1001-1014, 1203-1282
crates/cli/tests/coverage/plugins_lifecycle_tests.rs (1)
46-53: LGTM!Also applies to: 227-243, 574-714, 818-885
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
crates/cli/src/plugins/lifecycle.rs (2)
113-118: 🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy liftValidate policy and trust before provisioning the Python environment.
provision_python_environmentinstallssource.manifest_rootwithpip install, so calling it here before validation lets a policy-blocked or integrity-failing plugin execute package build code duringplugins add. Run host policy and trust checks first, then provision and recompute environment state only for accepted manifests.🤖 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 `@crates/cli/src/plugins/lifecycle.rs` around lines 113 - 118, The Python environment is being provisioned before the manifest has passed policy and trust validation, allowing unwanted install-time code execution in `provision_python_environment`. Update the `lifecycle.rs` flow so host policy and trust checks run before calling `provision_python_environment`, and only proceed to environment creation and subsequent state recomputation for manifests that are accepted by the checks.
190-194: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winDo not discard managed-environment rollback failures.
This hides failed cleanup after add/registration errors and can leave an orphaned environment while returning an unrelated failure. Preserve the original error, but include the cleanup failure so operators know the managed directory needs attention.
🤖 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 `@crates/cli/src/plugins/lifecycle.rs` around lines 190 - 194, The rollback cleanup in remove_managed_environment is currently being ignored with a discarded result, which can hide a failed managed-environment cleanup after registration errors. Update the rollback path in the lifecycle code to preserve the original add/registration error while also capturing and reporting any cleanup failure from remove_managed_environment, so the caller sees both the primary failure and the managed directory cleanup issue.crates/cli/src/plugins/lifecycle/environment.rs (1)
102-128: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winSurface cleanup failures during provisioning rollback.
Lines 103, 112, and 127 discard cleanup errors. If
venvcreation orpip installfails and removal also fails, the command reports only the original error while leaving a partial managed environment behind, which breaks the rollback contract.🤖 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 `@crates/cli/src/plugins/lifecycle/environment.rs` around lines 102 - 128, In the managed Python environment provisioning flow in environment.rs, the rollback paths after runner.run() failures and the interpreter existence check currently ignore remove_directory_if_present() errors; update the cleanup handling so rollback failures are surfaced instead of discarded. In the provisioning logic around environment_python_path(), runner.run(), and remove_directory_if_present(), capture the cleanup error and include it in the returned Result (or otherwise propagate it) when removing the partial environment fails, so a failed venv creation or pip install does not silently leave a broken environment behind.justfile (1)
1180-1200: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winHeavy Rust/e2e build now runs unconditionally inside the Python test path.
test-python-pluginunconditionally chains intotest-python-plugin-e2e, which builds the wheel, buildsnemo-relay-cliwithcargo build, spins up a live gateway, and runs a Rust integration test. AGENTS.md's validation guidance for "Python binding or wrapper changes" only calls forjust test-python; conflating that with a full CLI build + live-process e2e run materially increases runtime and ties an ostensibly Python-scoped test command to Rust build/test infrastructure. The only existing guard is for unsupported gRPC platforms (line 1198-1200); there's no opt-out for contributors who just want fast Python iteration.Consider gating the e2e portion behind an explicit flag/variable (similar to the existing
just ci=true test-rustpattern), sotest-python-pluginstays fast by default and the e2e flow is opt-in or CI-only.🤖 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 `@justfile` around lines 1180 - 1200, The Python test target currently always chains into the heavier e2e flow, which pulls in Rust builds and live-process integration work. Update the justfile recipe around test-python-plugin and test-python-plugin-e2e so the e2e portion is behind an explicit opt-in flag or variable, similar to the existing ci=true pattern for Rust tests. Keep the default Python path fast by having test-python-plugin run only the lightweight Python checks, and make the Rust/CLI build plus gateway integration path conditional in test-python-plugin-e2e.Source: Path instructions
🤖 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 `@examples/python-grpc-worker-plugin/README.md`:
- Around line 16-22: Add an explicit imperative step in the README procedure
after the foreground nemo-relay command to tell the reader how to stop Relay
before cleanup, using the existing setup/cleanup flow around relay_tmp,
relay_config, and the nemo-relay commands. Make the instruction unambiguous (for
example, tell the reader to press Ctrl+C to stop Relay) and keep it as a
separate action so the later “remove the plugin” step clearly follows a stopped
gateway.
In `@python/tests/plugin/test_worker_sdk.py`:
- Around line 1698-1699: The test setup in the worker SDK plugin test is
creating a real Unix server via asyncio.start_unix_server only to produce a
socket file, while the connection logic is already mocked. Replace this with
direct Unix socket file creation in the same style as the sibling test (using a
socket.socket(AF_UNIX, SOCK_STREAM) bind flow) so the lstat/S_ISSOCK check still
works without needing server.close() or wait_closed() cleanup; update the setup
around socket_path and the related teardown in the affected test cases.
- Around line 1701-1710: Replace the hand-written TimeoutWriter stand-in in the
open_unix_connection test setup with an AsyncMock-based mock using a spec for
asyncio.StreamWriter. Keep the same behavior by configuring close() as the sync
member and setting wait_closed() to raise TimeoutError via side_effect, so the
test still exercises the same timeout path without introducing a custom class.
---
Outside diff comments:
In `@crates/cli/src/plugins/lifecycle.rs`:
- Around line 113-118: The Python environment is being provisioned before the
manifest has passed policy and trust validation, allowing unwanted install-time
code execution in `provision_python_environment`. Update the `lifecycle.rs` flow
so host policy and trust checks run before calling
`provision_python_environment`, and only proceed to environment creation and
subsequent state recomputation for manifests that are accepted by the checks.
- Around line 190-194: The rollback cleanup in remove_managed_environment is
currently being ignored with a discarded result, which can hide a failed
managed-environment cleanup after registration errors. Update the rollback path
in the lifecycle code to preserve the original add/registration error while also
capturing and reporting any cleanup failure from remove_managed_environment, so
the caller sees both the primary failure and the managed directory cleanup
issue.
In `@crates/cli/src/plugins/lifecycle/environment.rs`:
- Around line 102-128: In the managed Python environment provisioning flow in
environment.rs, the rollback paths after runner.run() failures and the
interpreter existence check currently ignore remove_directory_if_present()
errors; update the cleanup handling so rollback failures are surfaced instead of
discarded. In the provisioning logic around environment_python_path(),
runner.run(), and remove_directory_if_present(), capture the cleanup error and
include it in the returned Result (or otherwise propagate it) when removing the
partial environment fails, so a failed venv creation or pip install does not
silently leave a broken environment behind.
In `@justfile`:
- Around line 1180-1200: The Python test target currently always chains into the
heavier e2e flow, which pulls in Rust builds and live-process integration work.
Update the justfile recipe around test-python-plugin and test-python-plugin-e2e
so the e2e portion is behind an explicit opt-in flag or variable, similar to the
existing ci=true pattern for Rust tests. Keep the default Python path fast by
having test-python-plugin run only the lightweight Python checks, and make the
Rust/CLI build plus gateway integration path conditional in
test-python-plugin-e2e.
🪄 Autofix (Beta)
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: ASSERTIVE
Plan: Enterprise
Run ID: bac4be09-30a3-4418-8dd6-4c1c4749fd33
📒 Files selected for processing (9)
crates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rsexamples/python-grpc-worker-plugin/README.mdjustfilepython/plugin/README.mdpython/tests/plugin/test_worker_sdk.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (34)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rspython/plugin/README.mdexamples/python-grpc-worker-plugin/README.mdpython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rspython/plugin/README.mdexamples/python-grpc-worker-plugin/README.mdjustfilepython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle/environment.rscrates/cli/src/plugins/lifecycle.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/core/tests/unit/plugin_dynamic_tests.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/plugin_dynamic_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/plugin_dynamic_tests.rspython/tests/plugin/test_worker_sdk.pycrates/cli/tests/coverage/plugins_lifecycle_tests.rs
**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.md
📄 CodeRabbit inference engine (.agents/skills/contribute-integration/SKILL.md)
Documentation must be updated if activation or usage changed
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links ...
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/{docs,examples,**/*.md,*.patch,*.diff,.github,*.sh,*.yaml,*.yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update documentation, examples, CI configuration, and patch artifacts when performing rename operations
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.mdpython/tests/plugin/test_worker_sdk.py
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
**/README.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update relevant crate or package README when that surface changed
Files:
python/plugin/README.mdexamples/python-grpc-worker-plugin/README.md
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
examples/python-grpc-worker-plugin/README.md
justfile
📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)
justfile: Keep helper function inputs aligned when editing version helpers:set_project_versionshould call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensureset_cargo_workspace_versionhelper updates[workspace.package].versionplus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensureset_node_package_versionshelper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries
Files:
justfile
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}
⚙️ CodeRabbit configuration file
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.
Files:
justfile
**/test_*.{py,py}
📄 CodeRabbit inference engine (.agents/skills/add-integration/SKILL.md)
Relevant integration tests or smoke coverage must exist for the integration path
Files:
python/tests/plugin/test_worker_sdk.py
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
python/tests/plugin/test_worker_sdk.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
python/tests/plugin/test_worker_sdk.py
python/**/*test*.py
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
python/**/*test*.py: Do not add@pytest.mark.asyncioto any test in Python test files
Do not add a-> Nonereturn type annotation to test functions
When mocking a class, useunittest.mock.MagicMockorunittest.mock.AsyncMockwith thespecconstructor argument when necessary, rather than defining a new class
Prefix mocked class names withmock, notfake
Prefer pytest fixtures over helper methods in Python tests
Preferpytest.mark.parametrizeover creating individual tests for different input types
Files:
python/tests/plugin/test_worker_sdk.py
python/**/{conftest.py,*test*.py}
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
When creating a fixture follow the pattern:
@pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) def <fixture_name>_fixture() -> <return_type>:and only specify the scope argument when the value is something other than "function"
Files:
python/tests/plugin/test_worker_sdk.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
python/tests/plugin/test_worker_sdk.py
🪛 ast-grep (0.44.0)
python/tests/plugin/test_worker_sdk.py
[info] 1696-1696: Do not hardcode temporary file or directory names
Context: "/tmp"
Note: [CWE-377] Insecure Temporary File.
(hardcoded-tmp-file)
🪛 Ruff (0.15.20)
python/tests/plugin/test_worker_sdk.py
[warning] 1708-1708: Missing return type annotation for private function open_unix_connection
(ANN202)
🔇 Additional comments (11)
crates/core/src/plugin/dynamic/registry.rs (1)
173-185: LGTM!crates/core/tests/unit/plugin_dynamic_tests.rs (1)
468-495: LGTM!crates/cli/src/plugins/lifecycle/environment.rs (1)
82-82: LGTM!Also applies to: 138-153, 235-258
crates/cli/src/plugins/lifecycle.rs (1)
419-419: LGTM!Also applies to: 437-437, 760-783, 1203-1282
crates/cli/tests/coverage/plugins_lifecycle_tests.rs (1)
46-53: LGTM!Also applies to: 159-220, 242-258, 774-831, 956-986, 1717-1773, 2452-2581
python/tests/plugin/test_worker_sdk.py (2)
1697-1697: 🩺 Stability & AvailabilityConfirm the hardcoded
dir="/tmp"is intentional (AF_UNIX path-length workaround).This new test pins
tempfile.TemporaryDirectory(prefix="nr-plugin-", dir="/tmp")while the sibling test at line 1669 lets it use the default system temp dir. Static analysis flags hardcoded/tmp(CWE-377). This is plausibly intentional to avoid exceeding the ~104-108 charAF_UNIXpath limit on platforms with long defaultTMPDIRs (e.g., macOS), but it's worth confirming and noting the rationale in a comment so it isn't "fixed" away later, and so it's consistent with the other unix-socket tests in this file.
48-48: LGTM!Also applies to: 1519-1524
examples/python-grpc-worker-plugin/README.md (1)
32-46: LGTM!justfile (2)
1212-1224: LGTM!
1225-1255: Explicit early shutdown beforeplugins removelooks correct.Killing/waiting on
gateway_pidand clearing it (lines 1251-1253) before invokingplugins removeavoids a double-kill race with thecleanup()EXIT trap, and thetest ! -e "$environment_ref"assertion (line 1255) correctly validates lifecycle-managed cleanup independent of the laterrm -rf "$tmp".python/plugin/README.md (1)
10-15: LGTM!
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <2007799+willkill07@users.noreply.github.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
|
/merge |
Overview
Fix the Python dynamic plugin lifecycle regressions discovered by end-to-end testing after #310. Python plugins are now installed into Relay-managed virtual environments, activated with those environments, and removed safely with their owned resources.
Details
source.manifest_rootfor Python worker manifests installed throughplugins add.environment_ref, and roll back partial installs.environment_reffor Python worker activation. Direct or manually configured Python worker loading without lifecycle state is intentionally rejected.emit_mark.nemo-relay --bind 127.0.0.1:4040daemon command.Validation:
cargo test -p nemo-relay-cli --no-fail-fastjust test-rustjust test-python-pluginjust test-pythonjust test-nodejust test-gojust test-wasmjust docsuv run pre-commit run --all-filesWhere should the reviewer start?
Start with
crates/cli/src/plugins/lifecycle/environment.rsfor environment ownership and provisioning, thencrates/core/src/plugin/dynamic/worker.rsfor the strict activation contract. The realemit_markcallback regression is incrates/core/tests/integration/worker_plugin_tests.rs.Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Summary by CodeRabbit
environment_statereporting in lifecycle command responses.