Skip to content

fix: manage Python dynamic plugin environments - #337

Merged
rapids-bot[bot] merged 10 commits into
NVIDIA:mainfrom
willkill07:fix/python-dynamic-plugin-lifecycle
Jul 1, 2026
Merged

fix: manage Python dynamic plugin environments#337
rapids-bot[bot] merged 10 commits into
NVIDIA:mainfrom
willkill07:fix/python-dynamic-plugin-lifecycle

Conversation

@willkill07

@willkill07 willkill07 commented Jun 30, 2026

Copy link
Copy Markdown
Member

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.

  • I confirm this contribution is my own work, or I have the right to submit it under this project's license.
  • I searched existing issues and open pull requests, and this does not duplicate existing work.

Details

  • Require source.manifest_root for Python worker manifests installed through plugins add.
  • Provision a deterministic per-plugin virtual environment, install the manifest root non-editably, persist environment_ref, and roll back partial installs.
  • Require lifecycle-managed environment_ref for Python worker activation. Direct or manually configured Python worker loading without lifecycle state is intentionally rejected.
  • Report environment readiness through lifecycle validation, inspect output, list state, and required startup preflight.
  • Tombstone before removal, guard cleanup to the expected Relay-managed directory, support retry after partial cleanup, and provision a fresh environment when reviving a plugin.
  • Configure a fixed valid gRPC authority for Unix-domain Python host channels so callbacks can await host-runtime calls such as emit_mark.
  • Correct the Python worker example manifest and documentation, including the integrity digest and nemo-relay --bind 127.0.0.1:4040 daemon command.
  • Add lifecycle, direct-loading rejection, Unix authority, real callback round-trip, and hermetic end-to-end coverage.

Validation:

  • cargo test -p nemo-relay-cli --no-fail-fast
  • just test-rust
  • just test-python-plugin
  • just test-python
  • just test-node
  • just test-go
  • just test-wasm
  • just docs
  • Python, Node.js, WebAssembly, and Python plugin package checks
  • uv run pre-commit run --all-files

Where should the reviewer start?

Start with crates/cli/src/plugins/lifecycle/environment.rs for environment ownership and provisioning, then crates/core/src/plugin/dynamic/worker.rs for the strict activation contract. The real emit_mark callback regression is in crates/core/tests/integration/worker_plugin_tests.rs.

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

Summary by CodeRabbit

  • New Features
    • Added lifecycle-managed per-plugin Python environments for dynamic workers, including environment tracking from add → activation/enable → inspect/validate → runtime launches.
    • Added environment_state reporting in lifecycle command responses.
  • Bug Fixes
    • Activation/enable now correctly blocks when the managed runtime environment is missing/unavailable, and surfaces clearer environment-related validation/last-error messages.
    • Removal now deletes the correct managed environment (when present) and updates validation status accordingly.
  • Documentation
    • Updated the Python SDK setup and the Python gRPC worker example to reflect registration-based managed environment behavior.
  • Tests
    • Expanded unit, integration, and end-to-end tests for provisioning, rollback, refusal, and cleanup scenarios.

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>
@willkill07
willkill07 requested a review from a team as a code owner June 30, 2026 17:39
@github-actions github-actions Bot added size:XL PR is extra large Bug issue describes bug; PR fixes bug lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code labels Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Managed 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.

Changes

Managed Python Environment Lifecycle

Layer / File(s) Summary
Environment provisioning helpers
crates/cli/src/plugins/lifecycle/environment.rs
New helpers provision and remove managed Python environments, compute managed path locations, and derive runtime environment state from the manifest and stored environment reference.
Add, remove, and validation wiring
crates/cli/src/plugins/lifecycle.rs
plugins add provisions environments and stores environment_ref; cleanup runs on add failures; plugins remove deletes managed environments and resets validation; validation, enable, and hydration recompute environment state; summary output renders environment availability.
Responses and server activation
crates/cli/src/plugins/lifecycle/responses.rs, crates/cli/src/server.rs, crates/cli/tests/coverage/server_tests.rs
Inspect and validate responses include environment_state; validation errors include environment failure messages; server activation forwards environment_ref; server tests set environment_ref: None for native load errors.
Worker load and registry contracts
crates/core/src/plugin/dynamic/worker.rs, crates/core/src/plugin/dynamic/registry.rs
Worker load specs carry environment_ref; Python worker startup resolves managed interpreters and clears host Python variables; registry records can update environment references and validation state together.
CLI lifecycle coverage
crates/cli/tests/cli_tests.rs, crates/cli/tests/coverage/plugins_lifecycle_tests.rs
Test manifests switch to command entrypoints; fake environment provisioning is exercised across add/remove, rollback, cleanup guards, and environment-state assertions.
Core worker integration tests
crates/core/tests/integration/worker_plugin_tests.rs, crates/core/tests/unit/dynamic_worker_tests.rs
Worker plugin tests adopt environment_ref, reject missing managed environments, verify configured-environment lookup failures, and check host Python environment clearing and path validation helpers.
Python SDK, docs, and e2e workflow
python/plugin/src/nemo_relay_plugin/_api.py, python/tests/plugin/test_worker_sdk.py, justfile, examples/python-grpc-worker-plugin/..., python/plugin/README.md
The Python SDK opens host channels through a helper, unix socket cleanup handles timeout, example docs/manifest describe Relay-managed environments, and the justfile adds an end-to-end managed-plugin workflow.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.57% 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
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the main change to Python dynamic plugin environment management.
Description check ✅ Passed The description matches the template with Overview, Details, Reviewer Start, related issue, and completed checklist items.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

Copy link
Copy Markdown

@willkill07 willkill07 self-assigned this Jun 30, 2026
@willkill07 willkill07 added this to the 0.5 milestone Jun 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 win

Clear host Python env before spawning the worker.

Command inherits the daemon environment. If Relay runs inside a virtualenv or with PYTHONHOME/PYTHONPATH set, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 266db37 and 2b77829.

📒 Files selected for processing (17)
  • crates/cli/src/plugins/lifecycle.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/src/plugins/lifecycle/responses.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/tests/coverage/server_tests.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • examples/python-grpc-worker-plugin/.gitignore
  • examples/python-grpc-worker-plugin/README.md
  • examples/python-grpc-worker-plugin/relay-plugin.toml
  • justfile
  • python/plugin/README.md
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/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_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

**/*.rs: Run cargo fmt --all to format all Rust code
Run cargo clippy --workspace --all-targets -- -D warnings to enforce all clippy lints as errors

**/*.rs: Run cargo fmt --all when Rust files changed as part of WebAssembly work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files changed as part of WebAssembly work

**/*.rs: If any Rust code changed, always run just test-rust
If any Rust code changed, also run cargo fmt --all
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting with cargo fmt --all
Run Rust linting with cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • crates/cli/src/plugins/lifecycle/responses.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.rs
  • crates/cli/tests/cli_tests.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • crates/cli/src/plugins/lifecycle/responses.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • crates/cli/src/plugins/lifecycle/responses.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.rs
  • examples/python-grpc-worker-plugin/relay-plugin.toml
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • crates/cli/src/plugins/lifecycle/responses.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.rs
  • examples/python-grpc-worker-plugin/relay-plugin.toml
  • python/plugin/README.md
  • crates/core/src/plugin/dynamic/registry.rs
  • examples/python-grpc-worker-plugin/README.md
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/src/plugins/lifecycle/responses.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/src/plugins/lifecycle/responses.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • crates/cli/src/plugins/lifecycle/responses.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.rs
  • examples/python-grpc-worker-plugin/relay-plugin.toml
  • python/plugin/README.md
  • crates/core/src/plugin/dynamic/registry.rs
  • examples/python-grpc-worker-plugin/README.md
  • crates/cli/src/server.rs
  • crates/cli/tests/cli_tests.rs
  • justfile
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/src/plugins/lifecycle/responses.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.rs
  • crates/cli/tests/cli_tests.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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.toml
  • python/tests/plugin/test_worker_sdk.py
  • python/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.toml
  • examples/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.toml
  • python/plugin/README.md
  • examples/python-grpc-worker-plugin/README.md
  • python/tests/plugin/test_worker_sdk.py
  • python/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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually do not need to be spelled out for developer audiences.

Files:

  • python/plugin/README.md
  • examples/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.md
  • examples/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.md
  • examples/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.md
  • examples/python-grpc-worker-plugin/README.md
**/*.{md,rst,txt}

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)

Spell NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

Files:

  • python/plugin/README.md
  • examples/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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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.md
  • examples/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-linkcheck when links change

Files:

  • python/plugin/README.md
  • examples/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.md
  • examples/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.md
  • examples/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.md
  • examples/python-grpc-worker-plugin/README.md
{crates/core,crates/adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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/core or shared runtime semantics, also use validate-change for broader validation

crates/core/**/*.rs: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
crates/{core,adaptive}/**

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper 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.toml and import paths used throughout the codebase

Files:

  • python/tests/plugin/test_worker_sdk.py
  • python/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.asyncio to any test in Python test files
Do not add a -> None return type annotation to test functions
When mocking a class, use unittest.mock.MagicMock or unittest.mock.AsyncMock with the spec constructor argument when necessary, rather than defining a new class
Prefix mocked class names with mock, not fake
Prefer pytest fixtures over helper methods in Python tests
Prefer pytest.mark.parametrize over 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 with uv run ruff format python
Run Python testing with uv 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
Run ty for 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 with uv run pre-commit run --all-files to enforce Ruff linting and formatting, and ty type checking

Files:

  • python/tests/plugin/test_worker_sdk.py
  • python/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 Quality

Covered 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 Correctness

No action needed: this TOML has a single [source] block and a single [integrity] block.

			> Likely an incorrect or invalid review comment.

Comment thread crates/cli/tests/coverage/plugins_lifecycle_tests.rs
Comment thread crates/core/src/plugin/dynamic/worker.rs Outdated
Comment thread crates/core/tests/integration/worker_plugin_tests.rs Outdated
Comment thread examples/python-grpc-worker-plugin/README.md Outdated
Comment thread python/plugin/README.md Outdated
Signed-off-by: Will Killian <wkillian@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
crates/core/src/plugin/dynamic/worker.rs (1)

753-760: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Enforce the actual managed root, not just the path suffix.

is_managed_path still accepts any absolute path whose last two components are .dynamic-plugin-environments/<sha256(plugin_id)>. A hand-edited registry record, or any future caller of DynamicPluginRegistry::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 later python.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

📥 Commits

Reviewing files that changed from the base of the PR and between 2b77829 and 7320a98.

📒 Files selected for processing (8)
  • crates/cli/src/plugins/lifecycle.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • examples/python-grpc-worker-plugin/README.md
  • python/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_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

**/*.rs: Run cargo fmt --all to format all Rust code
Run cargo clippy --workspace --all-targets -- -D warnings to enforce all clippy lints as errors

**/*.rs: Run cargo fmt --all when Rust files changed as part of WebAssembly work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files changed as part of WebAssembly work

**/*.rs: If any Rust code changed, always run just test-rust
If any Rust code changed, also run cargo fmt --all
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting with cargo fmt --all
Run Rust linting with cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle.rs
{crates/core,crates/adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle.rs
crates/core/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

crates/core/**/*.rs: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
crates/{core,adaptive}/**

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • python/plugin/README.md
  • examples/python-grpc-worker-plugin/README.md
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.rs
  • python/plugin/README.md
  • examples/python-grpc-worker-plugin/README.md
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/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.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually do not need to be spelled out for developer audiences.

Files:

  • python/plugin/README.md
  • examples/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.md
  • examples/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.md
  • examples/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.md
  • examples/python-grpc-worker-plugin/README.md
**/*.{md,rst,txt}

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)

Spell NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

Files:

  • python/plugin/README.md
  • examples/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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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.md
  • examples/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-linkcheck when links change

Files:

  • python/plugin/README.md
  • examples/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.md
  • examples/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.md
  • examples/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.md
  • examples/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.md
  • examples/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 Quality

Run the Rust checks cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, and just test-rust before 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

Comment thread crates/core/tests/unit/dynamic_worker_tests.rs
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 lift

Validate policy and trust before provisioning the Python environment.

provision_python_environment installs source.manifest_root with pip install, so calling it here before validation lets a policy-blocked or integrity-failing plugin execute package build code during plugins 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 win

Do 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 win

Surface cleanup failures during provisioning rollback.

Lines 103, 112, and 127 discard cleanup errors. If venv creation or pip install fails 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 win

Heavy Rust/e2e build now runs unconditionally inside the Python test path.

test-python-plugin unconditionally chains into test-python-plugin-e2e, which builds the wheel, builds nemo-relay-cli with cargo 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 for just 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-rust pattern), so test-python-plugin stays 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

📥 Commits

Reviewing files that changed from the base of the PR and between 7320a98 and e8a3049.

📒 Files selected for processing (9)
  • crates/cli/src/plugins/lifecycle.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • examples/python-grpc-worker-plugin/README.md
  • justfile
  • python/plugin/README.md
  • python/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_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

**/*.rs: Run cargo fmt --all to format all Rust code
Run cargo clippy --workspace --all-targets -- -D warnings to enforce all clippy lints as errors

**/*.rs: Run cargo fmt --all when Rust files changed as part of WebAssembly work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files changed as part of WebAssembly work

**/*.rs: If any Rust code changed, always run just test-rust
If any Rust code changed, also run cargo fmt --all
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting with cargo fmt --all
Run Rust linting with cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/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.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/src/plugins/lifecycle.rs
{crates/core,crates/adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/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.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/cli/src/plugins/lifecycle.rs
crates/core/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

crates/core/**/*.rs: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
crates/{core,adaptive}/**

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/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.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • python/plugin/README.md
  • examples/python-grpc-worker-plugin/README.md
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/src/plugin/dynamic/registry.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.rs
  • crates/core/tests/unit/plugin_dynamic_tests.rs
  • python/plugin/README.md
  • examples/python-grpc-worker-plugin/README.md
  • justfile
  • python/tests/plugin/test_worker_sdk.py
  • crates/cli/tests/coverage/plugins_lifecycle_tests.rs
  • crates/cli/src/plugins/lifecycle/environment.rs
  • crates/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.rs
  • crates/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.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/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.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually do not need to be spelled out for developer audiences.

Files:

  • python/plugin/README.md
  • examples/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.md
  • examples/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.md
  • examples/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.md
  • examples/python-grpc-worker-plugin/README.md
**/*.{md,rst,txt}

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)

Spell NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

Files:

  • python/plugin/README.md
  • examples/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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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.md
  • examples/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-linkcheck when links change

Files:

  • python/plugin/README.md
  • examples/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.md
  • examples/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.md
  • examples/python-grpc-worker-plugin/README.md
  • python/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.md
  • examples/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.md
  • examples/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_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper 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.toml and 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.asyncio to any test in Python test files
Do not add a -> None return type annotation to test functions
When mocking a class, use unittest.mock.MagicMock or unittest.mock.AsyncMock with the spec constructor argument when necessary, rather than defining a new class
Prefix mocked class names with mock, not fake
Prefer pytest fixtures over helper methods in Python tests
Prefer pytest.mark.parametrize over 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 with uv run ruff format python
Run Python testing with uv 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
Run ty for 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 with uv run pre-commit run --all-files to 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 & Availability

Confirm 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 char AF_UNIX path limit on platforms with long default TMPDIRs (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 before plugins remove looks correct.

Killing/waiting on gateway_pid and clearing it (lines 1251-1253) before invoking plugins remove avoids a double-kill race with the cleanup() EXIT trap, and the test ! -e "$environment_ref" assertion (line 1255) correctly validates lifecycle-managed cleanup independent of the later rm -rf "$tmp".

python/plugin/README.md (1)

10-15: LGTM!

Comment thread examples/python-grpc-worker-plugin/README.md
Comment thread python/tests/plugin/test_worker_sdk.py Outdated
Comment thread python/tests/plugin/test_worker_sdk.py Outdated
Signed-off-by: Will Killian <wkillian@nvidia.com>

@zhongxuanwang-nv zhongxuanwang-nv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks Will! :)

Comment thread crates/cli/src/plugins/lifecycle/environment.rs
Comment thread crates/core/tests/integration/worker_plugin_tests.rs
Comment thread crates/cli/src/plugins/lifecycle/environment.rs
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>
@willkill07

Copy link
Copy Markdown
Member Author

/merge

@rapids-bot
rapids-bot Bot merged commit cc3e5f1 into NVIDIA:main Jul 1, 2026
65 of 66 checks passed
@willkill07
willkill07 deleted the fix/python-dynamic-plugin-lifecycle branch July 26, 2026 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug issue describes bug; PR fixes bug lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code size:XL PR is extra large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants