Skip to content

feat: add local backend for built-in nemo guardrails#197

Open
afourniernv wants to merge 27 commits into
NVIDIA:mainfrom
afourniernv:afournier/relay-149-implement-local-python-backed-backend-for-built-in-nemo
Open

feat: add local backend for built-in nemo guardrails#197
afourniernv wants to merge 27 commits into
NVIDIA:mainfrom
afourniernv:afournier/relay-149-implement-local-python-backed-backend-for-built-in-nemo

Conversation

@afourniernv
Copy link
Copy Markdown
Contributor

@afourniernv afourniernv commented Jun 1, 2026

Overview

This PR adds the built-in local backend for the first-party nemo_guardrails plugin and updates the shipped remote/local mode boundaries in docs and coverage.

The local backend now runs NeMo Guardrails through a python3 subprocess worker instead of embedding Python in the Rust core or CLI binary. That keeps static Linux *-musl package builds from linking PyO3/libpython while still supporting local Guardrails checks when a compatible Python runtime is available. The final PR diff does not include any Cargo.toml changes.

  • 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

What changed:

  • move the built-in local NeMo Guardrails backend under crates/core ownership instead of a Python-binding-installed provider path
  • replace the in-process PyO3 local backend with a persistent JSONL python3 subprocess worker
  • add local.python_executable, defaulting to NEMO_RELAY_PYTHON when set and otherwise python3
  • enforce the local runtime contract in the worker: python3 >= 3.11 and nemoguardrails==0.22.0
  • support local managed LLM input/output, local managed tool_input/tool_output, and local streaming output through Guardrails-native stream_first = true semantics
  • reject unsupported local surfaces explicitly, including request_defaults and rails.output.streaming.stream_first = false
  • update Rust, Python native, CLI, and docs coverage for the subprocess backend path
  • restore the branch's Cargo manifests to match upstream/main

Important local-mode boundaries in this PR:

  • local mode requires an external Python executable; NeMo Relay does not embed or link Python for this backend
  • local mode requires nemoguardrails==0.22.0
  • local streamed output uses Guardrails-native stream_first = true semantics, so a later output block can happen after some chunks were already emitted
  • local mode does not support request_defaults
  • local mode does not support rails.output.streaming.stream_first = false
  • install semantics remain explicit: nemo-relay plus upstream nemoguardrails==0.22.0

Validation run:

  • cargo fmt --all
  • cargo test -p nemo-relay nemo_guardrails
  • cargo test -p nemo-relay-cli nemo_guardrails
  • cargo test -p nemo-relay-python --lib
  • cargo test -p nemo-relay --features atof-streaming streaming_endpoints_receive_raw_atof_events_and_file_output_remains
  • cargo tree -p nemo-relay-cli --target x86_64-unknown-linux-musl -e normal with no PyO3/libpython packages in the CLI graph
  • cargo check -p nemo-relay --no-default-features
  • just test-python
  • just docs
  • focused uv run pre-commit run --files ...

Notes:

  • A local full cargo check --target x86_64-unknown-linux-musl -p nemo-relay-cli could not complete on macOS because the local machine lacks x86_64-linux-musl-gcc; CI installs musl tools.
  • A local full just test-rust was stopped after hanging for several minutes in unrelated server/session tests. The Rust CI failures seen after the subprocess change were covered by the focused ATOF and Python-native coverage tests above.

Where should the reviewer start?

Start with:

  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • docs/nemo-guardrails-plugin/configuration.mdx

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

Summary by CodeRabbit

  • New Features

    • Added a local backend mode for NeMo Guardrails (requires Python 3.11+ and nemoguardrails==0.22.0). Supports managed tool input/output, broader LLM codec coverage, streaming enforcement, and an optional python_executable setting.
  • Bug Fixes / Validation

    • Local-mode config validation now rejects request_defaults and surfaces clearer diagnostics for missing/invalid local backend settings. Improved runtime failure propagation for local worker errors.
  • Documentation

    • Docs updated with remote vs local mode guidance, examples, requirements, and mode capability matrix.
  • Tests

    • Expanded unit and integration tests covering local mode, streaming, and rollback on plugin registration errors.

Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Jun 1, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Looking for one thing? Review this PR in Change Stack to search files, summaries, diffs, and code without losing your place.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 480986de-6575-4f98-a2e4-48b4d39e43e9

📥 Commits

Reviewing files that changed from the base of the PR and between 6d68272 and 33df99f.

📒 Files selected for processing (2)
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • docs/nemo-guardrails-plugin/configuration.mdx
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (19)
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
**

⚙️ 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:

  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/src/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.py
{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/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.py
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/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{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/plugins/nemo_guardrails/local_worker.py
**/*.{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/plugins/nemo_guardrails/local_worker.py
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py

[warning] 214-214: Too many branches (14 > 12)

(PLR0912)


[warning] 274-274: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (5)
crates/core/src/plugins/nemo_guardrails/local_worker.py (4)

208-211: LGTM!


214-214: LGTM!


241-247: LGTM!


265-288: LGTM!

docs/nemo-guardrails-plugin/configuration.mdx (1)

54-54: LGTM!


Walkthrough

Adds a production-ready local NeMo Guardrails backend using a Python subprocess worker, updates schema/validation and plugin registration, implements Rust bridge and worker protocol with streaming support, adds extensive unit/integration tests, and updates documentation.

Changes

Local Backend Configuration & Registration

Layer / File(s) Summary
Configuration Schema & Validation
crates/core/src/plugins/nemo_guardrails/component.rs, crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs, crates/cli/tests/coverage/plugins_tests.rs
Adds LocalBackendConfig.python_executable (optional) with non-empty validation; editor schema recognizes local fields; request_defaults is rejected in local mode; tests updated.
Backend Registration & Module Entry
crates/core/src/plugins/nemo_guardrails/local.rs, crates/core/src/plugins/nemo_guardrails/component.rs
Adds local.rs thin module and routes mode == "local" to register_local_backend instead of unimplemented.

Python Plugin Registration

Layer / File(s) Summary
invoke_python_plugin_register & Tests
crates/python/src/py_plugin.rs, crates/python/tests/coverage/py_plugin_coverage_tests.rs
Centralizes Python register invocation, config conversion, draining, and rollback-on-error; PyPlugin::register delegates to helper; test verifies rollback of partial registrations.
Py test module registration
crates/python/src/lib.rs
Adds PyModule import and registers nemo_guardrails_coverage_tests under #[cfg(test)].

Local Backend Runtime Implementation

Layer / File(s) Summary
Python Local Worker Process
crates/core/src/plugins/nemo_guardrails/local_worker.py
Worker implements JSON-line protocol, validates nemoguardrails version, builds RailsConfig from path or YAML, handles init/check/stream commands, and emits events/responses.
register_local_backend & Runtime
crates/core/src/plugins/nemo_guardrails/python.rs
Adds register_local_backend and LocalGuardrailsRuntime that decode provider requests, send checks to the worker, apply pass/block/modify outcomes, and wire interceptors.
Bridge, Worker, Writer & Envelope Routing
crates/core/src/plugins/nemo_guardrails/python.rs
Implements LocalGuardrailsBridge and LocalGuardrailsWorker for process lifecycle, reader thread, envelope dispatch, WorkerCommandWriter, and worker error propagation.
Codec Selection & Streaming Handling
crates/core/src/plugins/nemo_guardrails/python.rs
Codec translators for OpenAI/Anthropic shapes, guarded streaming forwarding, monitor loop, and blocked-stream handling.

Testing & Validation

Layer / File(s) Summary
CLI & Component Tests
crates/cli/tests/coverage/plugins_tests.rs, crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
Adds helpers and test cases for local/local-LLM configs, editor schema assertions, validate_config cases rejecting request_defaults and mis-specified local sources, and persistence round-trip checks.
Local Unit Tests
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
Fake guardrails fixture, bridge behavior tests, streaming validation, parse/modified-tool/extract tests, and stream monitor unit tests.
Integration Coverage Tests
crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
Large integration suite building fake Python packages at runtime, isolating Python modules, testing registration, LLM/tool enforcement, streaming behavior, and version constraints.
Test Infra Fixes
crates/core/tests/unit/observability/atof_tests.rs, crates/cli/src/config.rs, docs/build-plugins/nemoguardrails.mdx
Minor HTTP test header fix, doc comment rewording, and whitespace adjustment.

Documentation & Configuration Guides

Layer / File(s) Summary
Concepts & About
docs/about-nemo-relay/concepts/plugins.mdx, docs/nemo-guardrails-plugin/about.mdx
Documents both remote and local backends, local runtime requirements, and updates capability matrix and managed-surface vs request-defaults mapping.
Configuration Guide
docs/nemo-guardrails-plugin/configuration.mdx
Reworked config docs with component shape fields, remote vs local support matrix, examples, and local-mode validation/rules including rejection of request_defaults and streaming/tool semantics.

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.38% 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 Title follows Conventional Commits format (feat: lowercase scope-free concise imperative). Directly summarizes the main change: adding local backend for nemo guardrails.
Description check ✅ Passed PR description includes all required template sections: Overview with confirmations, Details explaining what changed and why, Where to start pointers, and Related Issues reference.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added size:XL PR is extra large Feature a new feature lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code labels Jun 1, 2026
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@afourniernv afourniernv marked this pull request as ready for review June 1, 2026 15:05
@afourniernv afourniernv requested a review from a team as a code owner June 1, 2026 15:05
@willkill07 willkill07 added this to the 0.4 milestone Jun 1, 2026
@willkill07
Copy link
Copy Markdown
Member

/ok to test 98d4915

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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/python/src/lib.rs`:
- Around line 112-121: The current retry unconditionally swallows any py.import
error and prepends source_python_dir; change load_guardrails_local_register_fn
to only attempt the fallback when the original PyErr is specifically a
ModuleNotFoundError for "nemo_relay" or "nemo_relay._guardrails_local": capture
the Err(err) from py.import, inspect its Python exception type (e.g. compare
against pyo3::exceptions::PyModuleNotFoundError) and/or the exception message to
ensure it indicates the module is missing, and only then check
source_python_dir, call prepend_python_path_if_missing(py, &source_python_dir)
and retry the import; for any other error type, immediately return Err(err)
unchanged (preserving the original error).

In `@crates/python/src/py_plugin.rs`:
- Around line 177-181: The call to register_fn.call1((plugin_config_py,
py_ctx.clone_ref(py))) can raise after partial registrations were made, but the
current code only drains registrations on the success path; to fix, call
register_fn.call1 and capture its Result, and if it Errs then immediately bind
the PyPluginContext (py_ctx.bind(py).borrow()) and call drain_registrations() to
rollback any partial registrations before returning the Err; keep the
successful-path behavior unchanged. Use the existing symbols register_fn.call1,
py_ctx, PyPluginContext (py_ctx.bind(py).borrow()), and drain_registrations() to
locate and implement the error-path cleanup.

In `@crates/python/tests/coverage/coverage_tests.rs`:
- Around line 344-357: The test currently only asserts check_calls length, which
misses verifying the actual guardrail kinds; update the assertions to explicitly
assert the captured guardrail sequence from result_json["check_calls"] matches
the expected rail types in order (input, output, tool_input, tool_output) and
also validate each call's input payload where relevant (use the recorded
(messages, rail_types) entries from the fake backend), replacing the len() check
with explicit equality checks against the expected sequence so order and types
are enforced (refer to check_calls, seen_request_messages, seen_tool_args, and
llm_result in the diff to locate the assertions to update).
- Around line 232-236: The tests mutate Python's sys.modules for the nemo_relay
namespace without isolating changes; add a small helper (e.g.,
snapshot_and_swap_nemo_relay or with_nemo_relay_modules) that, given a Python
GIL/python interpreter handle, snapshots all sys.modules keys starting with
"nemo_relay", clears or removes those keys, yields to a closure where you
perform the modules.set_item("nemo_relay._native", native_module.clone()) swap,
and finally restores the original snapshot even on panic; replace the direct
modules.set_item calls in
test_guardrails_local_helper_registers_and_enforces_llm_and_tool_checks,
test_guardrails_local_helper_enforces_streamed_output_rails, and
test_local_guardrails_provider_initializes_and_enforces_managed_core_calls with
this helper so each test always restores the full nemo_relay.* entries.

In `@python/nemo_relay/_guardrails_local.py`:
- Around line 455-486: The monitor task is created eagerly which leaks when the
returned async generator (guarded_provider_stream) is never iterated; move
creation of text_queue, blocked and the asyncio.create_task(...) that starts
_monitor_streaming_output_rails into the start of guarded_provider_stream so the
monitor is only created when the generator is actually consumed, keep the
existing finally block logic (await text_queue.put(None); await monitor;
re-check blocked["message"] and call _raise_streaming_output_blocked if needed),
and ensure you still use _extract_stream_text, stream and blocked inside the
generator as before.
🪄 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: 37c4df6f-db71-420c-b283-495a31160158

📥 Commits

Reviewing files that changed from the base of the PR and between b0557a9 and 98d4915.

📒 Files selected for processing (11)
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/lib.rs
  • crates/python/src/py_plugin.rs
  • crates/python/tests/coverage/coverage_tests.rs
  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/build-plugins/nemoguardrails.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
  • python/nemo_relay/_guardrails_local.py
💤 Files with no reviewable changes (1)
  • docs/build-plugins/nemoguardrails.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (32)
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • python/nemo_relay/_guardrails_local.py
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_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/src/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.rs
  • python/nemo_relay/_guardrails_local.py
**/*.{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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.rs
  • python/nemo_relay/_guardrails_local.py
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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.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/plugins/nemo_guardrails/component_tests.rs
  • crates/python/tests/coverage/coverage_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/plugins/nemo_guardrails/component_tests.rs
  • crates/python/tests/coverage/coverage_tests.rs
crates/python/**/*.rs

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

If the native Rust bridge changed, add the Rust crate tests for nemo-relay-python

Files:

  • crates/python/src/py_plugin.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.rs
crates/{python,ffi,node,wasm}/**/*

⚙️ CodeRabbit configuration file

crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.

Files:

  • crates/python/src/py_plugin.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.rs
{crates/python/src/py_api/**/*.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Update Python native binding in crates/python/src/py_api/mod.rs with Python wrapper docstring in python/nemo_relay/<module>.py and type stubs in python/nemo_relay/*.pyi modules

Files:

  • python/nemo_relay/_guardrails_local.py
python/nemo_relay/**/*.py

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Use snake_case naming convention for Python identifiers (e.g., nemo_relay.tools.call)

Format changed Python wrapper and test files with uv run ruff format python

Python wrapper modules live under python/nemo_relay/; the native extension is built from crates/python with maturin.

Files:

  • python/nemo_relay/_guardrails_local.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/nemo_relay/_guardrails_local.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/nemo_relay/_guardrails_local.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/nemo_relay/_guardrails_local.py
python/nemo_relay/**/*

⚙️ CodeRabbit configuration file

python/nemo_relay/**/*: Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.

Files:

  • python/nemo_relay/_guardrails_local.py
🪛 LanguageTool
docs/nemo-guardrails-plugin/configuration.mdx

[style] ~294-~294: To form a complete sentence, be sure to include a subject.
Context: ...g_yamlis required. -colang_contentcan only be used withconfig_yaml. - rem...

(MISSING_IT_THERE)

🪛 Ruff (0.15.15)
python/nemo_relay/_guardrails_local.py

[warning] 59-59: Missing return type annotation for private function _load_nemoguardrails

(ANN202)


[warning] 66-69: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 70-73: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 83-83: Dynamically typed expressions (typing.Any) are disallowed in status

(ANN401)


[warning] 87-87: Dynamically typed expressions (typing.Any) are disallowed in annotated

(ANN401)


[warning] 92-92: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 93-93: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 94-94: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 122-126: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 156-160: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 163-167: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 171-171: Dynamically typed expressions (typing.Any) are disallowed in result

(ANN401)


[warning] 174-180: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 184-184: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 185-185: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 186-186: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 202-202: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 206-206: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 206-206: Dynamically typed expressions (typing.Any) are disallowed in _output_streaming_config

(ANN401)


[warning] 210-210: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 215-215: Too many return statements (10 > 6)

(PLR0911)


[warning] 215-215: Too many branches (13 > 12)

(PLR0912)


[warning] 271-271: Missing return type annotation for private function _queue_string_stream

(ANN202)


[warning] 271-271: Remove quotes from type annotation

Remove quotes

(UP037)


[warning] 281-281: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 283-283: Remove quotes from type annotation

Remove quotes

(UP037)


[warning] 300-304: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 307-307: Dynamically typed expressions (typing.Any) are disallowed in rails_config_cls

(ANN401)


[warning] 307-307: Dynamically typed expressions (typing.Any) are disallowed in _build_guardrails_config

(ANN401)


[warning] 319-319: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 324-324: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 325-325: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 326-326: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 347-347: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 348-348: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 349-349: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 376-376: Missing return type annotation for private function _make_llm_intercept

(ANN202)


[warning] 378-378: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 379-379: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 380-380: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 385-385: Missing return type annotation for private function intercept

(ANN202)


[warning] 415-415: Missing return type annotation for private function _make_llm_stream_intercept

(ANN202)


[warning] 417-417: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 418-418: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 419-419: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 425-425: Missing return type annotation for private function stream_intercept

(ANN202)


[warning] 443-446: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 450-453: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 466-466: Missing return type annotation for private function guarded_provider_stream

(ANN202)


[warning] 491-491: Missing return type annotation for private function _make_tool_intercept

(ANN202)


[warning] 493-493: Dynamically typed expressions (typing.Any) are disallowed in rails

(ANN401)


[warning] 494-494: Dynamically typed expressions (typing.Any) are disallowed in rail_type

(ANN401)


[warning] 495-495: Dynamically typed expressions (typing.Any) are disallowed in rail_status

(ANN401)


[warning] 499-499: Missing return type annotation for private function tool_intercept

(ANN202)


[warning] 527-527: Dynamically typed expressions (typing.Any) are disallowed in result

(ANN401)


[warning] 533-538: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (12)
crates/core/src/plugins/nemo_guardrails/local.rs (2)

17-37: LGTM!


39-51: Lock-free invocation is the right call. Cloning the provider handle and dropping the MutexGuard before invoking avoids re-entrancy deadlock if the provider touches the registry, and keeps the lock off the async registration path.

crates/core/src/plugins/nemo_guardrails/component.rs (2)

20-28: LGTM!

Also applies to: 454-454


960-970: Local-mode request_defaults rejection is consistent. Early-return correctly short-circuits the remote-only field checks. Note the diagnostic honors policy.unsupported_value, so an Ignore policy will pass validation and forward request_defaults to the provider — that matches policy semantics, just confirm the Python backend tolerates/ignores the field rather than erroring.

crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs (1)

43-49: Coverage and isolation look solid. reset_runtime clearing the provider at each test entry (under test_mutex) keeps the new dispatch test from leaking registration state into siblings, and the assertions inside the provider closure verify both invocation and config propagation.

Also applies to: 793-807, 995-995, 1027-1054

docs/about-nemo-relay/concepts/plugins.mdx (1)

174-177: LGTM!

docs/nemo-guardrails-plugin/about.mdx (3)

23-55: LGTM!


59-116: LGTM!


121-121: LGTM!

docs/nemo-guardrails-plugin/configuration.mdx (3)

37-59: LGTM!


61-197: LGTM!


211-345: LGTM!

Comment thread crates/python/src/lib.rs Outdated
Comment thread crates/python/src/py_plugin.rs Outdated
Comment thread crates/python/tests/coverage/coverage_tests.rs Outdated
Comment thread crates/python/tests/coverage/coverage_tests.rs Outdated
Comment thread crates/core/src/plugins/nemo_guardrails/embedded_python/_guardrails_local.py Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@willkill07
Copy link
Copy Markdown
Member

/ok to test 67fd1b9

Copy link
Copy Markdown
Member

@willkill07 willkill07 left a comment

Choose a reason for hiding this comment

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

Overall the design looks good. Let's propagate the logic as embedded rust/python code rather than needing nemo-relay installed.

Also, we need to fix CI (which is failing)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
crates/python/src/lib.rs (1)

155-166: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Only fall back to ../../python on a true missing-module error.

This still treats any py.import("nemo_relay") failure as recoverable, so an installed-but-broken package can be silently shadowed by the source tree. Preserve the original PyErr, retry only for ModuleNotFoundError on nemo_relay, and return that original error unchanged when the source tree is absent.

🤖 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/python/src/lib.rs` around lines 155 - 166, In
ensure_nemo_relay_package_importable, preserve and inspect the original PyErr
from py.import("nemo_relay") instead of treating any failure as recoverable:
call py.import and if it returns Err, capture that error, check whether it is a
ModuleNotFoundError specifically for the "nemo_relay" name; only then proceed to
check embedded_guardrails_source_python_dir and call
prepend_python_path_if_missing and retry import via py.import; if the source
tree is absent return the original PyErr unchanged, and if the original error
was not ModuleNotFoundError for "nemo_relay" return it immediately (do not
shadow a broken installed package).
🤖 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.

Duplicate comments:
In `@crates/python/src/lib.rs`:
- Around line 155-166: In ensure_nemo_relay_package_importable, preserve and
inspect the original PyErr from py.import("nemo_relay") instead of treating any
failure as recoverable: call py.import and if it returns Err, capture that
error, check whether it is a ModuleNotFoundError specifically for the
"nemo_relay" name; only then proceed to check
embedded_guardrails_source_python_dir and call prepend_python_path_if_missing
and retry import via py.import; if the source tree is absent return the original
PyErr unchanged, and if the original error was not ModuleNotFoundError for
"nemo_relay" return it immediately (do not shadow a broken installed package).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 505b1e7e-510f-4922-89e9-b887e63991ad

📥 Commits

Reviewing files that changed from the base of the PR and between 67fd1b9 and e86ae58.

📒 Files selected for processing (4)
  • crates/python/embedded_python/_guardrails_local.py
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/coverage_tests.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (25)
{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:

  • crates/python/embedded_python/_guardrails_local.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:

  • crates/python/embedded_python/_guardrails_local.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:

  • crates/python/embedded_python/_guardrails_local.py
**/*.{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:

  • crates/python/embedded_python/_guardrails_local.py
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{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/python/embedded_python/_guardrails_local.py
  • crates/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.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/python/embedded_python/_guardrails_local.py
  • crates/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.rs
crates/{python,ffi,node,wasm}/**/*

⚙️ CodeRabbit configuration file

crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.

Files:

  • crates/python/embedded_python/_guardrails_local.py
  • crates/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.rs
**/*.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/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.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/python/tests/coverage/coverage_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/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.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/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.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/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.rs
crates/python/**/*.rs

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

If the native Rust bridge changed, add the Rust crate tests for nemo-relay-python

Files:

  • crates/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.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/python/tests/coverage/coverage_tests.rs
  • crates/python/src/lib.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/python/tests/coverage/coverage_tests.rs
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
🪛 Ruff (0.15.15)
crates/python/embedded_python/_guardrails_local.py

[warning] 80-83: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 87-91: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (7)
docs/nemo-guardrails-plugin/configuration.mdx (1)

228-234: LGTM!

crates/python/src/lib.rs (1)

30-54: LGTM!

Also applies to: 80-91, 131-152, 170-172

crates/python/embedded_python/_guardrails_local.py (1)

25-25: LGTM!

Also applies to: 78-91

crates/python/tests/coverage/coverage_tests.rs (4)

48-50: LGTM!

Also applies to: 122-148


326-330: LGTM!

Also applies to: 350-350, 423-423


479-557: LGTM!


574-578: LGTM!

Also applies to: 615-615, 713-713

Copy link
Copy Markdown
Member

@willkill07 willkill07 left a comment

Choose a reason for hiding this comment

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

The new shape looks great!

I just realized a core issue that we have:

The plugin config and enablement is under core but the logic for the guardrails plugin is all under Python. We can't have this split.

I'm okay with core getting an added PyO3 dependency (add a new feature named python and default to enabled).

Then we can gate the "local" config on the python feature.

I know this is extra churn, but I'm not sure how else we could get it to work in a deployed scenario with the core Relay library (or just the CLI)

…nt-local-python-backed-backend-for-built-in-nemo' into guardrails-cli-local-test

# Conflicts:
#	crates/core/src/plugins/nemo_guardrails/local.rs
#	crates/python/tests/coverage/coverage_tests.rs
@willkill07
Copy link
Copy Markdown
Member

/ok to test 0260c7e

willkill07
willkill07 previously approved these changes Jun 5, 2026
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@afourniernv
Copy link
Copy Markdown
Contributor Author

/ok to test 4aee554

@willkill07
Copy link
Copy Markdown
Member

/ok to test 0260c7e

@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Jun 5, 2026

/ok to test 0260c7e

@willkill07, there was an error processing your request: E2

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/

@willkill07
Copy link
Copy Markdown
Member

/ok to test 4aee554

willkill07 and others added 2 commits June 5, 2026 16:52
…acked-backend-for-built-in-nemo

Signed-off-by: Will Killian <2007799+willkill07@users.noreply.github.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
@github-actions github-actions Bot added the lang:python PR changes/introduces Python code label Jun 5, 2026
@willkill07
Copy link
Copy Markdown
Member

/ok to test aba629c

Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07
Copy link
Copy Markdown
Member

/ok to test cdbd1a0

@willkill07 willkill07 removed the request for review from a team June 5, 2026 22:42
Signed-off-by: Will Killian <wkillian@nvidia.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 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/src/plugins/nemo_guardrails/local_worker.py`:
- Around line 235-241: The per-stream queue is unbounded and allows stdin
ingestion to outrun the consumer; change the queue creation to a bounded
asyncio.Queue by supplying a maxsize (e.g., STREAM_QUEUE_MAXSIZE or a small
integer) when creating the queue for a request_id (the place that currently
calls asyncio.Queue()) so that await queue.put(...) in the "stream_text" branch
will block when the consumer (worker.monitor_stream) is behind; apply the same
change to the other occurrence around lines 257-265 and leave the call to
asyncio.create_task(worker.monitor_stream(request_id, ...)) unchanged so
backpressure is enforced by the bounded queue.

In `@crates/core/src/plugins/nemo_guardrails/python.rs`:
- Around line 898-913: The code currently sends a provider delta into chunk_tx
before the guardrails check runs, so the client can receive blocked text; to
fix, delay sending to chunk_tx until after the worker/guardrail has seen the
text and blocked_message(&blocked) has been evaluated (i.e., send to text_tx
first and await the monitor/verdict), then if blocked_message returns None
forward the chunk via chunk_tx, otherwise send
Err(streaming_output_blocked(...)) to chunk_tx and None to text_tx and await
monitor; reference chunk_tx, text_tx, monitor, blocked_message, and
streaming_output_blocked to locate and reorder this logic or make the worker the
authoritative source of streamed output.

In `@crates/python/src/lib.rs`:
- Around line 64-73: Add a doc comment above install_native_module_alias
explaining the dual-registration strategy: register the native module in
sys.modules (modules.set_item) so imports like "from nemo_relay._native import
..." work, and also attempt to attach it as an attribute on the imported package
(package.setattr("_native", m)) so attribute-style access like
"nemo_relay._native_scope_stack_active()" works; explicitly state that setattr
errors are intentionally ignored because the package may not be importable or
fully initialized during some startup phases, so failure to set the attribute is
non-fatal.

In `@crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs`:
- Around line 136-150: The current check_sequence_guardrails() returns a PASSED
on the LLM output leg so the test never exercises non-streaming output
modifications; change the second element returned by self._check_results in
check_sequence_guardrails() from Result(RailStatus.PASSED) to a
Result(RailStatus.MODIFIED, content="sanitized assistant" or similar) or a
blocking Result, and then update the corresponding test to call llm.execute
(non-streaming) and assert that the Python API surfaces the modification/block
(e.g., the returned object indicates modified/blocked and contains the provided
content), ensuring the test verifies the output-rail branch of the local
backend.
- Around line 223-305: Tests must run serially and always clean up even if f
panics: add a file-local static Mutex (e.g., via
once_cell::sync::Lazy<Mutex<()>>) and acquire its lock at the start of helpers
to serialize tests, and change with_event_loop and
with_isolated_nemo_relay_modules to ensure cleanup runs in a finally path by
using catch_unwind(AssertUnwindSafe(...)) around f, performing restoring actions
(reset event loop/policy via asyncio.set_event_loop(py.None()),
event_loop.close(), clear_nemo_relay_modules, restore saved sys.modules entries,
and call reset_runtime_state()) before re-resuming the panic
(std::panic::resume_unwind) or returning the value; reference functions:
with_isolated_nemo_relay_modules, clear_nemo_relay_modules, with_event_loop, and
reset_runtime_state.
- Around line 41-59: The test helper currently shells out to a hardcoded
"python3" in write_python_wrapper, which can invoke a different interpreter than
PyO3's; update new (fn new(_py: Python<'_>, ...)) to capture the active
interpreter path by evaluating sys.executable from the provided Python<'_>
(`py.run` or `py.eval`) and pass that executable path into write_python_wrapper
(or change write_python_wrapper to accept an executable arg and use it when
generating the wrapper); apply the same change to the other wrapper variant
referenced around lines 185-216 so both wrappers use sys.executable from the
PyO3 runtime instead of "python3".

In `@docs/nemo-guardrails-plugin/about.mdx`:
- Around line 53-55: Update the documentation text for the `local` backend to
state the exact required nemoguardrails package version: change the sentence
mentioning "tested `nemoguardrails` dependency" (the line describing the `local`
backend and `python3 >= 3.11`) to explicitly require "nemoguardrails==0.22.0"
(e.g., "requires python3 >= 3.11 and nemoguardrails==0.22.0"), so readers know
which package/version to install.
🪄 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: b1252090-fe69-4727-9f1e-a2b8a21c93b9

📥 Commits

Reviewing files that changed from the base of the PR and between 67fd1b9 and cdbd1a0.

📒 Files selected for processing (17)
  • Cargo.toml
  • crates/cli/src/config.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/Cargo.toml
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Check / Run
🧰 Additional context used
📓 Path-based instructions (34)
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • Cargo.toml
  • docs/nemo-guardrails-plugin/about.mdx
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • Cargo.toml
  • docs/nemo-guardrails-plugin/about.mdx
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**

⚙️ 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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • Cargo.toml
  • crates/core/tests/unit/observability/atof_tests.rs
  • docs/nemo-guardrails-plugin/about.mdx
  • crates/python/Cargo.toml
  • crates/cli/src/config.rs
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/cli/tests/coverage/plugins_tests.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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:

  • Cargo.toml
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/Cargo.toml
  • crates/cli/src/config.rs
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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:

  • Cargo.toml
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/Cargo.toml
  • crates/cli/src/config.rs
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/Cargo.toml

📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)

Update WebAssembly crate names and generated package names during coordinated rename operations

Confirm or infer the target release version from upstream/main:Cargo.toml. Derive the release branch as release/<major>.<minor>.

Files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
Cargo.toml

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

Cargo.toml: Maintain Cargo.toml [workspace.package].version as the source of truth for Rust workspace and Python build versioning
Keep Cargo.toml [workspace.dependencies] self-references aligned when the workspace version changes

Files:

  • Cargo.toml
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in TOML configuration files using hash comment syntax

Files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
**/*.{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:

  • Cargo.toml
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/Cargo.toml
  • crates/cli/src/config.rs
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.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/observability/atof_tests.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.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/observability/atof_tests.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.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/observability/atof_tests.rs
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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/tests/unit/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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/observability/atof_tests.rs
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.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/observability/atof_tests.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.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/observability/atof_tests.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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/tests/unit/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_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/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/{python,ffi,node,wasm}/**/*

⚙️ CodeRabbit configuration file

crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.

Files:

  • crates/python/Cargo.toml
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/python/src/lib.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.rs
crates/python/**/*.rs

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

If the native Rust bridge changed, add the Rust crate tests for nemo-relay-python

Files:

  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/python/src/lib.rs
{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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.py
🧠 Learnings (58)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Keep documentation aligned with current NeMo Relay behavior, repo layout, and entry points

Applied to files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)

Applied to files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Applies to **/README.md|docs/index.md|python/nemo_relay/README.md|crates/*/README.md : Public behavior changes must be reflected in corresponding entry-point documentation (Must-Fix)

Applied to files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • crates/cli/src/config.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Keep plugin context surfaces aligned across all language implementations

Applied to files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Applies to Cargo.toml : Keep `Cargo.toml` `[workspace.dependencies]` self-references aligned when the workspace version changes

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Applies to Cargo.toml : Maintain `Cargo.toml` `[workspace.package].version` as the source of truth for Rust workspace and Python build versioning

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
📚 Learning: 2026-05-21T22:51:21.017Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-python-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:21.017Z
Learning: If any Rust files changed as part of the Python work, also run `cargo fmt --all`, `just test-rust`, and `cargo clippy --workspace --all-targets -- -D warnings`

Applied to files:

  • Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
📚 Learning: 2026-05-21T22:49:17.713Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-packaging/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:17.713Z
Learning: Applies to **/{Cargo.toml,**/*.rs} : Maintain consistency between Rust package names in `Cargo.toml` and their actual usage across the codebase

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-21T22:49:46.956Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/rename-surfaces/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:46.956Z
Learning: Applies to **/*.{rs,toml} : Update Rust crate names and module prefixes during coordinated rename operations

Applied to files:

  • Cargo.toml
  • crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:49:46.956Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/rename-surfaces/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:46.956Z
Learning: Applies to **/Cargo.toml : Update WebAssembly crate names and generated package names during coordinated rename operations

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Run `cargo check --workspace` to refresh `Cargo.lock` after workspace package entries change

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to **/*.rs : 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`

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Do not forget to update `Cargo.lock`, `ATTRIBUTIONS-Rust.md`, and `ATTRIBUTIONS-Node.md` after changing versioned inputs that feed them

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-21T22:49:35.949Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/prepare-pr/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:35.949Z
Learning: Applies to **/*.rs : Any Rust change must run `cargo clippy --workspace --all-targets -- -D warnings`

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-21T22:51:21.017Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-python-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:21.017Z
Learning: Applies to crates/python/**/*.rs : If the native Rust bridge changed, add the Rust crate tests for `nemo-relay-python`

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/python/src/lib.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Applies to python/nemo_relay/**/*.py : Python wrapper modules live under `python/nemo_relay/`; the native extension is built from `crates/python` with `maturin`.

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/python/src/lib.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to {crates/python/src/py_api/**/*.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi} : Update Python native binding in `crates/python/src/py_api/mod.rs` with Python wrapper docstring in `python/nemo_relay/<module>.py` and type stubs in `python/nemo_relay/*.pyi` modules

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,go/nemo_relay/!(adaptive)/**,**/node/**,**/wasm/**} : Keep adaptive surface in sync across crates/adaptive, shared plugin behavior in core and bindings, Python adaptive/plugin wrappers in python/nemo_relay/adaptive.py and python/nemo_relay/plugin.py, Go adaptive helpers under go/nemo_relay/adaptive plus shared plugin helpers in go/nemo_relay, and Node/WebAssembly adaptive helpers and plugin wrappers

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : Keep `nemo_relay` as an optional dependency and ensure framework behavior falls back cleanly when NeMo Relay is unavailable

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/python/src/lib.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:51:34.986Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-wasm-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:34.986Z
Learning: Applies to crates/wasm/**/*.rs : Run `cargo test -p nemo-relay-wasm` when Rust-only WebAssembly helpers changed

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to crates/ffi/nemo_relay.h : Ensure FFI header sync for `crates/ffi/nemo_relay.h` through Cargo/build.rs

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/ffi/src/api/**/*.rs : Use `nemo_relay_` prefix for C FFI function names (e.g., `nemo_relay_tool_call`)

Applied to files:

  • Cargo.toml
  • crates/python/Cargo.toml
  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:48:57.484Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-observability/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:57.484Z
Learning: Applies to crates/core/src/observability/{atif,otel,openinference}.rs : When changing event fields in ATIF, OpenTelemetry, or OpenInference observability surfaces, keep the core event model in `crates/core/src/observability/atif.rs`, `crates/core/src/observability/otel.rs`, and `crates/core/src/observability/openinference.rs` in sync

Applied to files:

  • crates/core/tests/unit/observability/atof_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Events use ATOF `0.1` as the canonical event format. Scope events use start/end pairs; mark events record runtime checkpoints.

Applied to files:

  • crates/core/tests/unit/observability/atof_tests.rs
📚 Learning: 2026-05-21T22:48:57.484Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-observability/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:57.484Z
Learning: When event fields change, run Rust crate tests and execute `just test-rust` to validate the affected observability modules

Applied to files:

  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Applies to **/README.md|docs/index.md|python/nemo_relay/README.md|crates/*/README.md : Update entry-point documentation (README.md, docs/index.md, package/crate READMEs, and binding-level source READMEs) whenever public behavior changes

Applied to files:

  • docs/nemo-guardrails-plugin/about.mdx
  • crates/cli/src/config.rs
  • crates/python/src/lib.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:50:43.254Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/small-fix/SKILL.md:0-0
Timestamp: 2026-05-21T22:50:43.254Z
Learning: Update documentation if public behavior changed

Applied to files:

  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to {README.md,docs/getting-started/**/*.md} : Update `README.md`, `docs/getting-started/`, or binding-level READMEs if behavior differs by language or usage changed

Applied to files:

  • docs/nemo-guardrails-plugin/about.mdx
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Apply this skill when reviewing docs-only changes, example-heavy changes, or any public-facing text update that should be checked against NVIDIA style guidance and NeMo Relay repo conventions.

Applied to files:

  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/ffi/src/api/**/*.rs : Add or update FFI wrappers in relevant `crates/ffi/src/api/*.rs` modules, re-export through `crates/ffi/src/api/mod.rs`, and ensure generated `crates/ffi/nemo_relay.h` stays correct

Applied to files:

  • crates/python/Cargo.toml
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/python/src/lib.rs
  • crates/cli/tests/coverage/plugins_tests.rs
📚 Learning: 2026-05-21T22:47:20.312Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/README.md:0-0
Timestamp: 2026-05-21T22:47:20.312Z
Learning: Use this directory for maintainer-only skill set for developing NeMo Relay itself, including core API changes, patch maintenance, packaging, CI, documentation, middleware and observability internals, and library validation across bindings

Applied to files:

  • crates/python/Cargo.toml
  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Applies to crates/node/**/*.{js,ts,tsx} : Node.js public entry points include the main runtime package plus `nemo-relay-node/typed`, `nemo-relay-node/plugin`, and `nemo-relay-node/adaptive`.

Applied to files:

  • crates/python/Cargo.toml
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to **/README.md : Update relevant crate or package README when that surface changed

Applied to files:

  • crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:52:14.330Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/validate-change/SKILL.md:0-0
Timestamp: 2026-05-21T22:52:14.330Z
Learning: Applies to {docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md} : Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes

Applied to files:

  • crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/wasm/src/api/**/*.rs : Update WebAssembly binding in `crates/wasm/src/api/mod.rs` for language-native bindings

Applied to files:

  • crates/cli/src/config.rs
  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:50:51.194Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-ffi-surface/SKILL.md:0-0
Timestamp: 2026-05-21T22:50:51.194Z
Learning: Applies to **/*.rs : Run `just test-rust` to validate FFI changes

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Run tests for every language affected by a change. If you touch the Rust core runtime, middleware semantics, event shape, scope behavior, typed codecs, plugins, or observability, expect to validate every affected binding because the bindings share the same runtime contract.

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:27.841Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-rust-core/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:27.841Z
Learning: Use narrower crate tests as a local debug loop, not as the final validation story for Rust changes

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Run all affected language test targets (`just test-rust`, `just test-python`, `just test-go`, `just test-node`, `just test-wasm`) when changes touch the core Rust crate since all bindings depend on it

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
📚 Learning: 2026-05-21T22:49:35.949Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/prepare-pr/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:35.949Z
Learning: Applies to **/*.rs : Any Rust change must run `just test-rust`

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
📚 Learning: 2026-05-21T22:52:14.330Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/validate-change/SKILL.md:0-0
Timestamp: 2026-05-21T22:52:14.330Z
Learning: For core runtime or shared semantics changes, use `test-rust-core` which includes Rust testing, formatting, linting, and full cross-language matrix

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/registry.rs : Use existing `global_*_registry_api!` and `scope_*_registry_api!` macro patterns in `crates/core/src/api/registry.rs` for both global and scope-local registration APIs unless design explicitly rules one out

Applied to files:

  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/runtime/state.rs : Add registry fields as `SortedRegistry<GuardrailEntry<T>>` or `SortedRegistry<Intercept<T>>` to `NemoRelayContextState` in `crates/core/src/api/runtime/state.rs`

Applied to files:

  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/runtime/state.rs : Add chain execution helpers to `NemoRelayContextState` following the pattern of existing methods like `tool_sanitize_request_chain` or `tool_request_intercepts_chain`

Applied to files:

  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to crates/core/**/*.rs : If the change touched `crates/core` or shared runtime semantics, also use `validate-change` for broader validation

Applied to files:

  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/node/src/api/**/*.rs : Update Node.js binding in `crates/node/src/api/mod.rs` for language-native bindings

Applied to files:

  • crates/python/src/lib.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to crates/ffi/*.h : Prefix C FFI exports with `nemo_relay_`

Applied to files:

  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : Optional import/activation guard must be in place for the framework integration

Applied to files:

  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,**/node/adaptive/**,**/wasm/adaptive/**} : Ensure typed helper constructors still map cleanly to the same config document in adaptive bindings across Python, Go, Node, and WebAssembly

Applied to files:

  • crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to crates/ffi/**/*.rs : If the change touched `crates/ffi`, also use `test-ffi-surface` for validation

Applied to files:

  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:49:17.713Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-packaging/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:17.713Z
Learning: Applies to RELEASING.md : Ensure public packaging changes are reflected in release-facing documentation and RELEASING.md

Applied to files:

  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : LLM calls should use NeMo Relay managed execution where possible

Applied to files:

  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : Tool calls should use NeMo Relay managed execution where possible

Applied to files:

  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:48:28.092Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/contribute-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:28.092Z
Learning: Preserve the framework's original behavior when NeMo Relay is absent

Applied to files:

  • docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**} : Maintain documented and tested validation and report behavior for adaptive surfaces

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:34.986Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-wasm-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:34.986Z
Learning: If the change touched shared runtime semantics in `crates/core` or `crates/adaptive`, also use the `validate-change` skill

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:27.841Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-rust-core/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:27.841Z
Learning: Run `just test-rust` as the primary Rust testing command for shared runtime

Applied to files:

  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py

[warning] 33-33: Missing type annotation for **fields

(ANN003)


[warning] 62-62: Do not catch blind exception: Exception

(BLE001)


[warning] 73-73: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


[warning] 76-76: Missing return type annotation for special method __aiter__

(ANN204)


[warning] 79-79: Missing return type annotation for special method __anext__

(ANN204)


[warning] 87-87: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


[warning] 88-88: Version block is outdated for minimum Python version

Remove outdated version block

(UP036)


[warning] 89-89: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 98-102: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 109-109: Missing return type annotation for private function _import_dependency

(ANN202)


[warning] 115-118: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 119-122: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 124-124: Missing return type annotation for private function _build_guardrails_config

(ANN202)


[warning] 131-131: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 137-137: Missing return type annotation for private function _rail_kind

(ANN202)


[warning] 142-142: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 167-170: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 173-176: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 178-178: Missing return type annotation for private function _output_rails_config

(ANN202)


[warning] 197-197: Do not catch blind exception: Exception

(BLE001)


[warning] 207-207: Too many branches (14 > 12)

(PLR0912)


[warning] 208-208: Using the global statement to update worker is discouraged

(PLW0603)


[warning] 223-223: Abstract raise to an inner function

(TRY301)


[warning] 223-223: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 237-237: Store a reference to the return value of asyncio.create_task

(RUF006)


[warning] 247-247: Abstract raise to an inner function

(TRY301)


[warning] 247-247: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 248-248: Do not catch blind exception: Exception

(BLE001)


[warning] 262-262: Do not catch blind exception: Exception

(BLE001)


[warning] 265-265: Store a reference to the return value of asyncio.create_task

(RUF006)

Comment thread crates/core/src/plugins/nemo_guardrails/local_worker.py Outdated
Comment thread crates/core/src/plugins/nemo_guardrails/python.rs
Comment thread crates/core/src/plugins/nemo_guardrails/python.rs Outdated
Comment thread crates/python/src/lib.rs Outdated
Comment thread crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs Outdated
Comment thread crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
Comment thread crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
Comment thread docs/nemo-guardrails-plugin/about.mdx Outdated
Signed-off-by: Will Killian <wkillian@nvidia.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
crates/core/src/plugins/nemo_guardrails/python.rs (2)

898-913: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Don't emit a delta before the rail verdict for that delta is known.

After text_tx.send(Some(text)), yield_now() only gives the monitor a chance to run; it does not wait for the Python worker to approve that text. The same delta can still be forwarded on Line 913 before a later "blocked" event arrives, which leaks output that stream_first = true is supposed to suppress. Buffer the provider chunk until the worker has definitively cleared it, or make the worker the source of streamed output.

🤖 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/plugins/nemo_guardrails/python.rs` around lines 898 - 913,
The code currently sends chunk_tx(Ok(chunk)) before the guardrail verdict can
arrive; after sending text_tx.send(Some(text)) replace the yield_now-based check
with a deterministic wait for the monitor/verdict: do not call
chunk_tx.send(Ok(chunk)) until the monitor has processed the text and
blocked_message(&blocked) is confirmed absent (or until the monitor explicitly
signals approval); use the existing monitor/blocked state (monitor.await or a
monitor-provided approval signal) and the blocked_message(&blocked) check (and
keep finish_stream_monitor/streaming_output_blocked handling) so the provider
chunk is buffered and only forwarded when the guardrail has definitively cleared
it.

462-469: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout to non-init worker RPCs.

request() waits on receiver.recv() forever. If the Python subprocess hangs inside check_async or stream_async without exiting, intercepted LLM/tool calls wedge indefinitely and the shared worker never gets recycled. Bound this wait and tear down the worker on expiry so calls fail predictably.

🤖 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/plugins/nemo_guardrails/python.rs` around lines 462 - 469,
request() currently blocks forever on receiver.recv(); wrap the recv() call in a
tokio::time::timeout (use a sensible constant like WORKER_RPC_TIMEOUT or make it
configurable) so non-init worker RPCs fail after the deadline, map the timeout
to a FlowError::Internal (or appropriate FlowError) and ensure you tear down the
worker on expiry (invoke the worker shutdown/cleanup path you already have for
terminating stalled workers or call the worker teardown method/logic after
timeout before returning), keeping the rest of the flow (send_request, envelope
handling and worker_result(envelope)) intact.
crates/core/src/plugins/nemo_guardrails/local_worker.py (1)

236-242: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Bounded queues here still don't restore end-to-end backpressure.

STREAM_QUEUE_MAXSIZE caps streams[request_id], but main() still keeps reading stdin and spawning detached handle_message() tasks for every stream_text. Once a stream falls behind, the backlog moves from the queue into pending tasks and retained JSON lines instead of applying backpressure to stdin ingestion. Process stream_* messages inline, or otherwise gate reads on per-stream capacity, so long/stalled streams cannot grow memory without bound.

Also applies to: 256-266

🤖 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/plugins/nemo_guardrails/local_worker.py` around lines 236 -
242, Bounded per-stream queues (STREAM_QUEUE_MAXSIZE) don't stop stdin from
being read because main() spawns detached handle_message() tasks for every
incoming "stream_text", letting backlog accumulate in tasks/JSON; instead, gate
reads by making stream messages processed inline or by using awaitable
backpressure on the per-stream queue. Change main() and handle_message() so that
when command is "stream_text" you do an await on streams[request_id].put(text)
(or await handle_message(...) directly) rather than creating a detached
asyncio.create_task; keep monitor_stream(request_id, ...) unchanged but ensure
streams.get(request_id) is checked and awaited (blocking) when full so stalled
streams naturally apply backpressure to stdin and prevent unbounded memory
growth.
🤖 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/src/plugins/nemo_guardrails/python.rs`:
- Around line 678-688: The parse_check_result function currently treats any
status other than "blocked" or "modified" as Passed; change this to explicitly
accept "passed" and reject unknown statuses by returning a FlowError::Internal.
In the match on result.status (in parse_check_result), add an explicit "passed"
arm that returns Ok(LocalCheckOutcome::Passed) and replace the wildcard arm with
an Err(FlowError::Internal(...)) that includes the unexpected status string
(e.g., format!("unexpected worker check status: {}", result.status)). This
ensures WorkerCheckResult (and function parse_check_result) only accepts
"blocked", "modified", or "passed" and fails closed for any other value.
- Around line 541-552: LocalGuardrailsWorker::write_command currently performs
blocking writes and flushes synchronously on Tokio worker threads (called from
request → send_request and from monitor_guardrails_stream →
send_stream_text/send_stream_end), which can block the runtime; refactor so
writes run off the async tokio tasks: create a dedicated blocking writer (e.g.,
spawn a std::thread that owns the child stdin and a channel) and add a sender
field to LocalGuardrailsWorker; change write_command to serialize the Json and
send it over the channel (returning errors if the channel is closed), perform
the actual writeln!/flush() inside the dedicated writer thread and translate I/O
errors back into FlowError; ensure proper shutdown/flush when the worker is
dropped or the channel is closed.

---

Duplicate comments:
In `@crates/core/src/plugins/nemo_guardrails/local_worker.py`:
- Around line 236-242: Bounded per-stream queues (STREAM_QUEUE_MAXSIZE) don't
stop stdin from being read because main() spawns detached handle_message() tasks
for every incoming "stream_text", letting backlog accumulate in tasks/JSON;
instead, gate reads by making stream messages processed inline or by using
awaitable backpressure on the per-stream queue. Change main() and
handle_message() so that when command is "stream_text" you do an await on
streams[request_id].put(text) (or await handle_message(...) directly) rather
than creating a detached asyncio.create_task; keep monitor_stream(request_id,
...) unchanged but ensure streams.get(request_id) is checked and awaited
(blocking) when full so stalled streams naturally apply backpressure to stdin
and prevent unbounded memory growth.

In `@crates/core/src/plugins/nemo_guardrails/python.rs`:
- Around line 898-913: The code currently sends chunk_tx(Ok(chunk)) before the
guardrail verdict can arrive; after sending text_tx.send(Some(text)) replace the
yield_now-based check with a deterministic wait for the monitor/verdict: do not
call chunk_tx.send(Ok(chunk)) until the monitor has processed the text and
blocked_message(&blocked) is confirmed absent (or until the monitor explicitly
signals approval); use the existing monitor/blocked state (monitor.await or a
monitor-provided approval signal) and the blocked_message(&blocked) check (and
keep finish_stream_monitor/streaming_output_blocked handling) so the provider
chunk is buffered and only forwarded when the guardrail has definitively cleared
it.
- Around line 462-469: request() currently blocks forever on receiver.recv();
wrap the recv() call in a tokio::time::timeout (use a sensible constant like
WORKER_RPC_TIMEOUT or make it configurable) so non-init worker RPCs fail after
the deadline, map the timeout to a FlowError::Internal (or appropriate
FlowError) and ensure you tear down the worker on expiry (invoke the worker
shutdown/cleanup path you already have for terminating stalled workers or call
the worker teardown method/logic after timeout before returning), keeping the
rest of the flow (send_request, envelope handling and worker_result(envelope))
intact.
🪄 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: df148fab-30d9-4ef4-8f64-ddfcfe65f9c4

📥 Commits

Reviewing files that changed from the base of the PR and between 67fd1b9 and 527b1f8.

📒 Files selected for processing (14)
  • crates/cli/src/config.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/python/src/lib.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (31)
**/*.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/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_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/src/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.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/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.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/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.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/plugins/nemo_guardrails/local.rs
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_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/plugins/nemo_guardrails/local.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local.rs
  • docs/about-nemo-relay/concepts/plugins.mdx
  • crates/cli/src/config.rs
  • crates/core/tests/unit/observability/atof_tests.rs
  • crates/python/src/lib.rs
  • docs/nemo-guardrails-plugin/about.mdx
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{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:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/about-nemo-relay/concepts/plugins.mdx
  • docs/nemo-guardrails-plugin/about.mdx
  • docs/nemo-guardrails-plugin/configuration.mdx
**/*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.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/observability/atof_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_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/observability/atof_tests.rs
  • crates/cli/tests/coverage/plugins_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/python/**/*.rs

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

If the native Rust bridge changed, add the Rust crate tests for nemo-relay-python

Files:

  • crates/python/src/lib.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/{python,ffi,node,wasm}/**/*

⚙️ CodeRabbit configuration file

crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.

Files:

  • crates/python/src/lib.rs
  • crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
{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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.py
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py

[warning] 34-34: Missing type annotation for **fields

(ANN003)


[warning] 63-63: Do not catch blind exception: Exception

(BLE001)


[warning] 74-74: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


[warning] 77-77: Missing return type annotation for special method __aiter__

(ANN204)


[warning] 80-80: Missing return type annotation for special method __anext__

(ANN204)


[warning] 88-88: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


[warning] 89-89: Version block is outdated for minimum Python version

Remove outdated version block

(UP036)


[warning] 90-90: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 99-103: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 110-110: Missing return type annotation for private function _import_dependency

(ANN202)


[warning] 116-119: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 120-123: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 125-125: Missing return type annotation for private function _build_guardrails_config

(ANN202)


[warning] 132-132: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 138-138: Missing return type annotation for private function _rail_kind

(ANN202)


[warning] 143-143: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 168-171: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 174-177: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 179-179: Missing return type annotation for private function _output_rails_config

(ANN202)


[warning] 198-198: Do not catch blind exception: Exception

(BLE001)


[warning] 208-208: Too many branches (14 > 12)

(PLR0912)


[warning] 209-209: Using the global statement to update worker is discouraged

(PLW0603)


[warning] 224-224: Abstract raise to an inner function

(TRY301)


[warning] 224-224: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 238-238: Store a reference to the return value of asyncio.create_task

(RUF006)


[warning] 248-248: Abstract raise to an inner function

(TRY301)


[warning] 248-248: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 249-249: Do not catch blind exception: Exception

(BLE001)


[warning] 263-263: Do not catch blind exception: Exception

(BLE001)


[warning] 266-266: Store a reference to the return value of asyncio.create_task

(RUF006)

🔇 Additional comments (25)
crates/core/src/plugins/nemo_guardrails/component.rs (7)

195-197: LGTM!


332-332: LGTM!


533-533: LGTM!


702-714: LGTM!


977-987: Validation correctly rejects request_defaults in local mode.

The early return when config.mode == "local" prevents downstream validation from running on request_defaults fields, which is the intended behavior for this unsupported surface.


20-21: LGTM!

Also applies to: 25-25


457-457: LGTM!

crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs (3)

364-364: LGTM!


765-765: LGTM!

Also applies to: 792-797


799-813: Good test coverage for local mode request_defaults rejection.

This test validates the validation rule added at component.rs:977-987.

crates/cli/tests/coverage/plugins_tests.rs (2)

202-205: LGTM!


1352-1352: LGTM!

Also applies to: 1363-1366

crates/core/src/plugins/nemo_guardrails/local.rs (1)

1-15: LGTM!

docs/about-nemo-relay/concepts/plugins.mdx (1)

177-178: LGTM!

docs/nemo-guardrails-plugin/about.mdx (3)

23-24: LGTM!


48-54: LGTM!


80-116: LGTM!

docs/nemo-guardrails-plugin/configuration.mdx (3)

49-60: LGTM!


220-306: LGTM!


322-352: LGTM!

crates/python/src/lib.rs (1)

26-26: LGTM!

Also applies to: 67-69

crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs (1)

1-339: LGTM!

crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs (1)

1-914: LGTM!

crates/cli/src/config.rs (1)

161-161: LGTM!

crates/core/tests/unit/observability/atof_tests.rs (1)

303-303: LGTM!

Comment thread crates/core/src/plugins/nemo_guardrails/python.rs
Comment thread crates/core/src/plugins/nemo_guardrails/python.rs
Signed-off-by: Will Killian <wkillian@nvidia.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/src/plugins/nemo_guardrails/local_worker.py`:
- Around line 266-269: The create_task call in main that fires handle_message
without keeping the Task (the asyncio.create_task(handle_message(...)) branch)
discards the handle and prevents graceful shutdown/observability; change main to
store created tasks in a module/local set (e.g., pending_tasks), add a done
callback to remove completed tasks, and on stdin-close/shutdown cancel and await
remaining tasks (or await asyncio.gather(*pending_tasks,
return_exceptions=True)) before returning so handle_message tasks are tracked
and cleaned up; keep the stream-handling branch unchanged but ensure both paths
use the same tracking set.

In `@docs/nemo-guardrails-plugin/configuration.mdx`:
- Line 54: The long table cell under the "Managed streaming LLM execution"
comparison is too dense; refactor it to improve readability by either (a)
splitting that single cell into multiple rows with separate cells for remote
HTTP(S) contract support, managed input checks vs Guardrails-native output
streaming, and the note about chunk release behavior and `stream_first = false`
limitation, or (b) simplify the cell to a short summary (e.g., "Supported; see
Streaming behavior section") and move the detailed clauses (provider chunk
release after local rail monitor clears stream, `rails.output.streaming.enabled
= true`, and `stream_first = false` not supported) into a new subsection
elsewhere in the document. Update the "Managed streaming LLM execution" table
row accordingly and add the new subsection referenced from the table if you
choose option (b).
🪄 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: b9be7bfe-fe3c-4849-9459-c87eb955da13

📥 Commits

Reviewing files that changed from the base of the PR and between 527b1f8 and 6d68272.

📒 Files selected for processing (4)
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • docs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (28)
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{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:

  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/nemo-guardrails-plugin/configuration.mdx
**

⚙️ 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:

  • docs/nemo-guardrails-plugin/configuration.mdx
  • crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.rs
  • crates/core/src/plugins/nemo_guardrails/local_worker.py
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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_tests.rs
  • crates/core/src/plugins/nemo_guardrails/python.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/plugins/nemo_guardrails/local_python_tests.rs
{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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.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:

  • crates/core/src/plugins/nemo_guardrails/local_worker.py
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py

[warning] 269-269: Store a reference to the return value of asyncio.create_task

(RUF006)

🔇 Additional comments (11)
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs (1)

297-355: LGTM!

docs/nemo-guardrails-plugin/configuration.mdx (5)

23-44: LGTM!


61-219: LGTM!


220-306: LGTM!


307-321: LGTM!


322-351: LGTM!

crates/core/src/plugins/nemo_guardrails/python.rs (5)

36-36: LGTM!

Also applies to: 463-481


361-363: LGTM!

Also applies to: 397-398, 553-577, 585-638


579-583: LGTM!


754-767: LGTM!


949-1034: LGTM!

Comment thread crates/core/src/plugins/nemo_guardrails/local_worker.py Outdated
Comment thread docs/nemo-guardrails-plugin/configuration.mdx Outdated
willkill07 and others added 2 commits June 5, 2026 20:56
Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07
Copy link
Copy Markdown
Member

/ok to test 8527102

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

Labels

Feature a new feature 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