feat: add dynamic plugin lifecycle CLI commands#292
Conversation
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughIntroduces full dynamic plugin lifecycle CLI commands ( ChangesDynamic Plugin Lifecycle CLI
Sequence Diagram(s)sequenceDiagram
participant User
participant run_plugins
participant lifecycle as plugins::lifecycle::*
participant load_and_hydrate_scopes
participant ScopedRegistry
participant config_io as plugins::config_io
User->>run_plugins: plugins <subcommand> [--json]
run_plugins->>run_plugins: json_context() → Option~PluginJsonContext~
run_plugins->>lifecycle: add/validate/list/inspect/enable/disable/remove(command, server)
lifecycle->>load_and_hydrate_scopes: resolve_plugins_config + load_scoped_registries
load_and_hydrate_scopes-->>lifecycle: Vec~ScopedRegistry~
lifecycle->>ScopedRegistry: mutate records / save()
lifecycle->>config_io: append/remove_dynamic_plugin_reference(plugins_toml)
alt save fails
lifecycle->>config_io: restore_plugins_toml (rollback)
end
alt --json flag
lifecycle->>lifecycle: print_response_json(envelope)
lifecycle-->>run_plugins: Ok or CliError::PluginLifecycle
run_plugins->>lifecycle: render_plugin_error → ExitCode
else terminal output
lifecycle->>User: rendered text output
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test 086832f |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 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/src/plugins/config_io.rs`:
- Around line 181-185: The issue is that DynamicPluginManifest::load_from_path
is being called without error handling, causing the entire removal operation to
abort if any manifest in the plugins.dynamic list is stale or broken, even if
that manifest is not the target plugin being removed. To fix this, modify the
code around the DynamicPluginManifest::load_from_path call to handle the error
gracefully instead of propagating it. When a manifest cannot be loaded, attempt
to match the target plugin using the registry's recorded source or manifest
reference instead of loading the full manifest. For non-target entries that
cannot be read, log a warning and continue scanning rather than failing the
whole remove operation. This allows the requested plugin to be removed even when
unrelated broken manifests exist in the configuration.
- Around line 165-170: The code currently returns Ok(false) when the [plugins]
section is not a table or when plugins.dynamic is not an array, which silently
masks configuration errors. Instead of treating these as missing sections,
return proper error results that indicate the configuration is malformed. In the
first else block (when root_table.get_mut("plugins") doesn't yield a Table), and
in the second else block (when plugins.get_mut("dynamic") doesn't yield an
Array), return an Err with a descriptive error message explaining that the
configuration format is invalid, so callers can properly handle and report the
configuration problem rather than proceeding as if the sections simply don't
exist.
In `@crates/cli/src/plugins/lifecycle.rs`:
- Around line 64-76: The rollback logic in the error handler after
scopes[scope_index].save() fails is using remove_dynamic_plugin_reference to
undo the append_dynamic_plugin_reference call, but this approach deletes all
references matching the plugin_id, including any pre-existing manual entries in
plugins.toml. Instead, capture a snapshot of the plugins_toml_path file before
calling append_dynamic_plugin_reference at line 74, then on save failure restore
the exact previous snapshot content rather than attempting selective removal.
This ensures only the newly appended reference is rolled back without affecting
any pre-existing configuration.
In `@crates/cli/src/plugins/lifecycle/render.rs`:
- Around line 123-132: The host_config_json formatting is currently exposing the
full plugin configuration including potential secrets by cloning and
pretty-printing the entire config object. Replace the map chain starting with
plugin.config.clone() through the serde_json::to_string_pretty call to instead
return a redacted placeholder string such as "<redacted>" rather than the actual
configuration content, ensuring sensitive plugin secrets are not exposed in
terminal output or support bundles while maintaining consistent JSON-style
formatting in the terminal inspect output.
In `@crates/cli/src/plugins/lifecycle/responses.rs`:
- Around line 208-210: The host_config field at line 209 is directly serializing
plugin.config without redacting sensitive information like credentials or tokens
that could be exposed in CI logs through the inspect --json output. Replace the
direct clone of plugin.config with a redaction function that masks or removes
sensitive values from the configuration, only exposing full values if an
explicit reveal flag is provided. Apply this same redaction logic consistently
to both the JSON serialization in the host_config mapping and to any terminal or
text-based inspect output to ensure credentials and tokens are never
inadvertently exposed.
In `@crates/cli/src/plugins/lifecycle/state.rs`:
- Around line 68-85: The save() method writes directly to self.state_path
without atomic operations, which can corrupt the registry if the process crashes
or disk fills during write. Instead of writing directly to self.state_path,
write the rendered content to a temporary file in the same directory (obtained
from self.state_path.parent()), ensure the file is flushed to disk, and then
atomically replace the original file using a rename operation. This ensures the
state file is only updated when the write is completely successful.
In `@crates/cli/src/plugins/lifecycle/target.rs`:
- Around line 22-29: The `looks_like_path` function in the target.rs file uses
`path.exists()` to determine if a string is a path, which creates ambiguity when
a plugin has a registered ID like "acme.plugin" and a file with that same name
exists in the current directory. Remove the `path.exists()` check and rely only
on explicit path syntax indicators such as the `.toml` file extension and path
separators (`/` or `\` or the platform-specific separator). This ensures that
registered plugin IDs are not incorrectly treated as paths merely because a
same-named file happens to exist in the filesystem.
In `@crates/cli/tests/coverage/main_tests.rs`:
- Around line 37-129: The dispatch tests for run_plugins are reading ambient
user/global plugin configuration from the environment, which causes flakiness
outside clean CI environments. Use the existing env lock strategy to set HOME
and XDG_CONFIG_HOME environment variables to temporary directories before
executing the test assertions. This will isolate the tests from ambient
configuration and ensure deterministic behavior for the exit-code assertions on
missing plugins in the dispatch test cases.
In `@crates/cli/tests/coverage/plugins_lifecycle_tests.rs`:
- Around line 68-73: The test suite is not fully isolating the environment for
plugin config resolution. While CurrentDirGuard handles changing the current
working directory, the HOME and XDG_CONFIG_HOME environment variables are not
being controlled, allowing ambient user/global plugin configs to leak into the
test and break assertions on plugin counts and lookups. Create an additional
environment guard similar to CurrentDirGuard that sets both HOME and
XDG_CONFIG_HOME to temporary directory paths for the duration of the test,
ensuring complete isolation of the plugin configuration environment. This guard
should be applied alongside or as part of the existing setup in this test suite
where resolve_plugins_config(None) is called.
🪄 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: 7d25b628-5095-4042-995a-b0ff0aa260ce
📒 Files selected for processing (15)
crates/cli/src/config.rscrates/cli/src/error.rscrates/cli/src/main.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/cli_tests.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/src/plugin/dynamic/registry.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (15)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/plugin/dynamic/registry.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/plugin/dynamic/registry.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/plugin/dynamic/registry.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/core/src/plugin/dynamic/registry.rscrates/cli/tests/coverage/main_tests.rscrates/cli/src/main.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/src/error.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/tests/cli_tests.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/config.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/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/main_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/tests/cli_tests.rscrates/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/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/cli/tests/cli_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rs
**/*config*.{rs,ts,py,go,js,json,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Ensure dynamic config shape still matches the documented canonical model
Files:
crates/cli/src/plugins/config_io.rscrates/cli/src/config.rs
🔇 Additional comments (14)
crates/cli/src/config.rs (1)
200-244: LGTM!Also applies to: 341-420, 734-740
crates/cli/src/error.rs (1)
8-18: LGTM!Also applies to: 39-45, 60-73
crates/core/src/plugin/dynamic/registry.rs (1)
25-41: 📐 Maintainability & Code QualityPlease confirm the required core-change validation matrix was run.
This PR changes
crates/core, so please provide command results forcargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings,just test-rust,validate-change, and the affected language test matrix (just test-python,just test-go,just test-node,just test-wasm) before merge.As per coding guidelines, "
Any Rust change must run just test-rust", "Run cargo fmt --all", "Run cargo clippy --workspace --all-targets -- -D warnings", and forcrates/corechanges "also use validate-change" plus "run the full matrix across Rust, Python, Go, Node.js, and WebAssembly".Source: Coding guidelines
crates/cli/src/plugins/config_io.rs (2)
9-246: 📐 Maintainability & Code QualityConfirm the required Rust validation passed.
This cohort changes Rust files; please confirm
cargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings,just test-rust, anduv run pre-commit run --all-fileswere run before merge. As per coding guidelines,**/*.rs: “Any Rust change must runjust test-rust”, “Any Rust change must runcargo fmt --all”, “Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings”, and “Validate Rust code withuv run pre-commit run --all-files”.Source: Coding guidelines
9-17: LGTM!Also applies to: 29-54, 107-151, 209-246
crates/cli/src/plugins.rs (1)
25-25: LGTM!Also applies to: 95-95
crates/cli/src/plugins/lifecycle/target.rs (1)
1-20: LGTM!crates/cli/src/plugins/lifecycle/responses.rs (1)
1-207: LGTM!Also applies to: 215-316
crates/cli/src/plugins/lifecycle/render.rs (1)
1-122: LGTM!Also applies to: 137-273
crates/cli/tests/cli_tests.rs (2)
36-67: LGTM!Also applies to: 133-301
133-145: 📐 Maintainability & Code QualityConfirm these Rust validation commands were executed for this change.
Required checks for any Rust changes in this repository:
just test-rustcargo fmt --allcargo clippy --workspace --all-targets -- -D warningsuv run pre-commit run --all-filescrates/cli/tests/coverage/plugins_tests.rs (1)
6-7: LGTM!Also applies to: 94-122
crates/cli/src/plugins/lifecycle.rs (1)
1-508: 📐 Maintainability & Code QualityConfirm the required Rust validation passed.
This cohort changes Rust CLI code; please record/pass
just test-rust,cargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings, anduv run pre-commit run --all-filesbefore merge.As per coding guidelines, "
**/*.rs: Any Rust change must runjust test-rust", "cargo fmt --all", "cargo clippy --workspace --all-targets -- -D warnings", and "Validate Rust code withuv run pre-commit run --all-files".Source: Coding guidelines
crates/cli/src/main.rs (1)
87-87: LGTM!Also applies to: 104-138
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
crates/cli/src/plugins/lifecycle/target.rs (1)
38-42: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick winRemove
path.exists()check to prevent ID-to-path misclassification.Line 40 still uses
path.exists(), creating ambiguity when a registered plugin ID matches a filesystem entry name. If a user runsplugins validate acme.pluginand both a registered plugin "acme.plugin" and a file "acme.plugin" exist, the parser choosesPath, skipping the registry ID branch and preventing validation status persistence. The comment at lines 35-37 states the goal is to keep canonical IDs on the ID branch;path.exists()violates this. Remove the exists check and rely only on explicit path syntax (is_absolute()and the separator/prefix/suffix checks).🔧 Proposed fix
fn should_treat_target_as_path(target: &str) -> bool { let path = Path::new(target); - if path.exists() || path.is_absolute() { + if path.is_absolute() { return true; }🤖 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/target.rs` around lines 38 - 42, In the function should_treat_target_as_path, remove the path.exists() check from the condition on line 40. Keep only the path.is_absolute() check to determine if the target should be treated as a path. This prevents registered plugin IDs from being misclassified as filesystem paths when a file with the same name happens to exist, ensuring that canonical IDs are properly routed to the registry lookup branch instead of being incorrectly treated as filesystem paths.
🤖 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/src/plugins/lifecycle/target.rs`:
- Around line 116-124: The test
parse_treats_existing_filesystem_entries_as_paths is now invalid because it
relies on the removed path.exists() check that incorrectly treated "acme.worker"
as a path when it is actually a valid plugin ID format. Update the test by
passing explicit path syntax like "./acme.worker" to PluginTarget::parse()
instead of just the directory path string, so it correctly tests that the parser
treats explicitly-formatted paths as paths rather than IDs, or alternatively
remove the test entirely if it no longer serves a valid purpose after the parser
refactoring.
---
Duplicate comments:
In `@crates/cli/src/plugins/lifecycle/target.rs`:
- Around line 38-42: In the function should_treat_target_as_path, remove the
path.exists() check from the condition on line 40. Keep only the
path.is_absolute() check to determine if the target should be treated as a path.
This prevents registered plugin IDs from being misclassified as filesystem paths
when a file with the same name happens to exist, ensuring that canonical IDs are
properly routed to the registry lookup branch instead of being incorrectly
treated as filesystem paths.
🪄 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: 44dd9809-af44-4692-be9b-1cf25708201d
📒 Files selected for processing (1)
crates/cli/src/plugins/lifecycle/target.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (26)
- GitHub Check: Python / Test (macos-arm64)
- GitHub Check: Rust / Test (linux-amd64)
- GitHub Check: Node.js / Test (macos-arm64)
- GitHub Check: Rust / Test (linux-arm64)
- GitHub Check: Go / Test (windows-amd64)
- GitHub Check: Go / Test (macos-arm64)
- GitHub Check: Rust / Test (windows-arm64)
- GitHub Check: Go / Test (linux-amd64)
- GitHub Check: Rust / Test (windows-amd64)
- GitHub Check: Rust / Test (macos-arm64)
- GitHub Check: Go / Test (linux-arm64)
- GitHub Check: Go / Test (windows-arm64)
- GitHub Check: Node.js / Test (windows-amd64)
- GitHub Check: Node.js / Test (windows-arm64)
- GitHub Check: WebAssembly / Test (linux-amd64)
- GitHub Check: Node.js / Test (linux-arm64)
- GitHub Check: Node.js / Test (linux-amd64)
- GitHub Check: Python / Test (windows-arm64)
- GitHub Check: Python / Test (windows-amd64)
- GitHub Check: Python / Test (linux-amd64)
- GitHub Check: WebAssembly / Test (windows-amd64)
- GitHub Check: Python / Test (linux-arm64)
- GitHub Check: WebAssembly / Test (windows-arm64)
- GitHub Check: WebAssembly / Test (linux-arm64)
- GitHub Check: WebAssembly / Test (macos-arm64)
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (8)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/cli/src/plugins/lifecycle/target.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/cli/src/plugins/lifecycle/target.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/src/plugins/lifecycle/target.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/src/plugins/lifecycle/target.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/src/plugins/lifecycle/target.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/cli/src/plugins/lifecycle/target.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/cli/src/plugins/lifecycle/target.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/cli/src/plugins/lifecycle/target.rs
🔇 Additional comments (3)
crates/cli/src/plugins/lifecycle/target.rs (3)
12-19: LGTM!
21-33: LGTM!
12-52: 📐 Maintainability & Code QualityRun Rust validation for this change
Run
cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings, andjust test-rustfor this Rust change.
Signed-off-by: Alex Fournier <afournier@nvidia.com>
…dd-dynamic-plugin-lifecycle-cli-commands-and-operator
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
crates/cli/src/plugins/lifecycle.rs (1)
68-78: 🗄️ Data Integrity & Integration | 🟠 MajorFix
.ok()suppression that can delete existingplugins.tomlon rollback.
std::fs::read(&plugins_toml_path).ok()collapses all IO errors intoNone, including non-NotFounderrors like permission or transient failures. Therestore_plugins_tomlfunction treatsNoneas "file did not previously exist" (line 451), so a save failure triggers deletion of the existing config rather than restoration — silent data loss.Distinguish
NotFoundfrom real IO errors in both locations:
- Line 68–78 in
add()- Line 252 in
remove()Apply this pattern to both:
- let original_plugins_toml = std::fs::read(&plugins_toml_path).ok(); + let original_plugins_toml = match std::fs::read(&plugins_toml_path) { + Ok(bytes) => Some(bytes), + Err(error) if error.kind() == std::io::ErrorKind::NotFound => None, + Err(error) => return Err(error.into()), + };🤖 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 68 - 78, The `.ok()` call in the `add()` function at line 68 and similar logic in the `remove()` function at line 252 suppress all IO errors when reading the plugins.toml file, treating permission errors and transient failures the same as file-not-found. This causes the rollback function `restore_plugins_toml` to delete the existing configuration file instead of restoring it when a save failure occurs. Replace the `.ok()` suppression pattern in both locations with explicit error handling that distinguishes the NotFound error case (which should be suppressed as `None`) from other IO errors (which should be propagated). Use pattern matching on the error kind to only suppress NotFound errors while allowing real IO errors to bubble up and prevent silent data loss during rollback.
🤖 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/src/plugins/config_io.rs`:
- Around line 187-202: The `target_manifest_ref` is converted to a bare PathBuf
without being resolved relative to the TOML file path, while `manifest_ref`
entries are resolved via resolve_manifest_ref which produces absolute paths.
This asymmetry causes the comparison `manifest_ref == target_manifest_ref` to
fail for relative path references, breaking the fast-path match and forcing
fallback to the slower load_from_path approach. Resolve `target_manifest_ref`
symmetrically by applying the same resolve_manifest_ref function to it, passing
the path parameter to convert it to an absolute path before the comparison,
ensuring both sides of the equality check use the same path resolution logic.
---
Duplicate comments:
In `@crates/cli/src/plugins/lifecycle.rs`:
- Around line 68-78: The `.ok()` call in the `add()` function at line 68 and
similar logic in the `remove()` function at line 252 suppress all IO errors when
reading the plugins.toml file, treating permission errors and transient failures
the same as file-not-found. This causes the rollback function
`restore_plugins_toml` to delete the existing configuration file instead of
restoring it when a save failure occurs. Replace the `.ok()` suppression pattern
in both locations with explicit error handling that distinguishes the NotFound
error case (which should be suppressed as `None`) from other IO errors (which
should be propagated). Use pattern matching on the error kind to only suppress
NotFound errors while allowing real IO errors to bubble up and prevent silent
data loss during rollback.
🪄 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: cff1aabe-15c8-48aa-b201-6aa18c49cb0a
📒 Files selected for processing (8)
crates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (11)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.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/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.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/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.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/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/cli/src/plugins/lifecycle/target.rscrates/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/responses.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/state.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/main_tests.rscrates/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/cli/tests/coverage/main_tests.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rs
**/*config*.{rs,ts,py,go,js,json,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Ensure dynamic config shape still matches the documented canonical model
Files:
crates/cli/src/plugins/config_io.rs
🔇 Additional comments (10)
crates/cli/tests/coverage/main_tests.rs (2)
79-82: LGTM!Also applies to: 92-187
5-64: 📐 Maintainability & Code QualityInclude results from
just test-rust,cargo fmt --all, andcargo clippy --workspace --all-targets -- -D warningsto confirm this change meets Rust validation requirements.Per coding guidelines, all Rust changes require execution of these three commands. The sandbox environment cannot execute them, so manual verification is needed before approval.
crates/cli/tests/coverage/plugins_lifecycle_tests.rs (1)
32-82: LGTM!Also applies to: 116-757
crates/cli/src/plugins/config_io.rs (1)
166-183: Malformed[plugins]/plugins.dynamicnow surfaceCliError::Configinstead of silent not-found, and a single unreadable manifest no longer aborts the whole scan (Line 199.unwrap_or(false)). Both prior concerns addressed.crates/cli/src/plugins/lifecycle/state.rs (1)
82-113: LGTM!crates/cli/src/plugins/lifecycle/target.rs (1)
38-52: LGTM!crates/cli/src/plugins/lifecycle/responses.rs (1)
207-212: LGTM!crates/cli/src/plugins/lifecycle.rs (1)
245-266: Remove flow looks sound, aside from the shared.ok()snapshot risk. The load-then-hydrate fallback, registry remove, reference removal, and save-failure restore are ordered correctly and operate on a consistentscopesbinding. See the Line 68 comment for theoriginal_plugins_tomlsnapshot fix that also applies to Line 252.crates/cli/src/plugins/lifecycle/render.rs (2)
123-132: Redaction correctly applied. Host config values are now redacted before pretty-printing, and empty config falls through to<none>. This resolves the prior secret-leak concern in terminalinspectoutput.
274-287: 📐 Maintainability & Code QualityNo refactor needed:
redacted_host_config_jsonis already defined once inrender.rsand imported byresponses.rs.The function has a single definition in
crates/cli/src/plugins/lifecycle/render.rs:274and is imported intoresponses.rs(line 21), not duplicated. The recommended pattern of a shared, single definition is already in place.> Likely an incorrect or invalid review comment.
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/src/plugins/lifecycle.rs`:
- Around line 80-81: Remove the `let _ = (scope, manifest_ref,
plugins_toml_path, revived);` scaffolding line in the `add` function at line 80
since most bindings don't need explicit discards and `revived` is dead code
(computed but never used). Either incorporate `revived` into the println message
to implement the intended "revival-aware messaging for add operations", or drop
the binding entirely if that messaging is not needed. Also remove the similar
`let _ = ...` lines in the `remove` function at line 263 and the
`mutate_enabled_state` function at line 305, optionally binding their function
call results to `_` at the call sites instead if you want to suppress
unused-value warnings.
🪄 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: 9066a65e-ee37-4010-919a-e55e4158858b
📒 Files selected for processing (6)
crates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/src/plugins/lifecycle.rscrates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (11)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/cli/src/plugins/lifecycle/render.rscrates/cli/src/plugins/lifecycle/state.rscrates/cli/src/config.rscrates/cli/src/plugins/config_io.rscrates/cli/tests/coverage/plugins_lifecycle_tests.rscrates/cli/src/plugins/lifecycle.rs
**/*config*.{rs,ts,py,go,js,json,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Ensure dynamic config shape still matches the documented canonical model
Files:
crates/cli/src/config.rscrates/cli/src/plugins/config_io.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/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/cli/tests/coverage/plugins_lifecycle_tests.rs
🔇 Additional comments (5)
crates/cli/src/config.rs (1)
833-833: 📐 Maintainability & Code QualityPlease confirm Rust validation gates were run for this change.
I can’t verify from this diff whether the required Rust checks were executed. Please confirm
just test-rust,cargo fmt --all, andcargo clippy --workspace --all-targets -- -D warningswere run for this PR.As per coding guidelines: “Any Rust change must run
just test-rust”, “Any Rust change must runcargo fmt --all”, and “Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings.”Source: Coding guidelines
crates/cli/src/plugins/lifecycle/render.rs (1)
22-39: LGTM!Also applies to: 65-66, 78-82, 153-157
crates/cli/src/plugins/config_io.rs (1)
187-188: Symmetric resolution fix is correct.
target_manifest_refis now resolved viaresolve_manifest_ref(path, ...), matching the per-entry resolution at Line 194, so relative stored refs compare correctly and the fast-path match works for stale/moved manifests. Resolves the earlier asymmetry concern.crates/cli/src/plugins/lifecycle/state.rs (1)
12-14: LGTM!Also applies to: 19-20, 147-147, 248-248, 270-270
crates/cli/tests/coverage/plugins_lifecycle_tests.rs (1)
422-422: LGTM!Also applies to: 688-729
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test f35f8d1 |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test c993948 |
License DiffCompared against Lockfile license changesLockfile License ChangesRustAdded
Removed
Updated/Changed
NodeAdded
Removed
Updated/Changed
PythonAdded
Removed
Updated/Changed
Status output |
…dd-dynamic-plugin-lifecycle-cli-commands-and-operator
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test 518648e |
Overview
Add the dynamic plugin lifecycle CLI surface for RELAY-340.
Details
add,validate,list,inspect,enable,disable, andremovedynamic-plugins.jsonregistry file so desired-state mutations are durable across CLI runsplugins.tomldynamic plugin refs when no state file exists yetremovetombstone-based and add rollback for multi-file mutation failure on the host config pathplugins list --all, revival-aware add messaging, and richer inspect output for source and lifecycle stateplugins validate,plugins list, andplugins inspectplugins validate --jsonsuccess pathWhere should the reviewer start?
Start in
crates/cli/src/plugins/lifecycle.rs, then reviewcrates/cli/src/plugins/lifecycle/json.rsandcrates/cli/tests/coverage/plugins_lifecycle_tests.rs.Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Summary by CodeRabbit
Release Notes
New Features
--jsonoutput for lifecycle commands (including structured success and error payloads).Bug Fixes
Improvements
plugins.toml.