Skip to content
Back to skills

Add Middleware

ASecurity

Add a new NeMo Relay guardrail or intercept type, registration surface, or pipeline stage. Do not use for changing an existing middleware implementation without a new middleware contract.

  • 190 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 3, 2026
ai-agentsrustgorailsapidocumentation

Works with

  • api

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add NVIDIA/NeMo-Relay --skill add-middleware --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Add Middleware?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Add Middleware
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nvidia-add-middleware/badge)](https://www.skillsdirectory.com/skills/nvidia-add-middleware)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: add-middleware
description: Add a new NeMo Relay guardrail or intercept type, registration surface, or pipeline stage. Do not use for changing an existing middleware implementation without a new middleware contract.
license: Apache-2.0
---


# Add a Middleware Type

NeMo Relay supports guardrails (validate/gate) and intercepts (transform) at various
pipeline stages. Adding a new middleware type requires checking every layer that
exposes the new contract.

Use this skill when introducing a new middleware registration surface or adding
middleware behavior to a new pipeline stage.

## Lock The Design First

Decide these before editing code:

- Is this for tools, LLMs, marks, scope events, or a combination?
- Is it a conditional guardrail, sanitize guardrail, request intercept, or
  execution intercept?
- Does it run on request input, inner callable execution, stream chunks, or
  final response output?
- Is the callback fallible, and how should callback failures propagate?
- Does it need both global and scope-local registration?
- What should subscribers and exporters observe in the event payload after this
  middleware runs?
- If this is an event sanitizer, which of `data`, `category_profile`, and
  `metadata` can change, and is the event used only as immutable context?

## Pipeline Order

Refer to `docs/about-nemo-relay/concepts/middleware.mdx` for the full diagrams.

- **Tool execute**:
  conditional guardrails -> request intercepts -> sanitize request (for events)
  | execution intercept chain(callable) -> sanitize response
- **LLM execute**:
  conditional guardrails -> request intercepts -> sanitize request (for events)
  | execution intercept chain(callable) -> sanitize response
- **Mark and scope events**:
  specialized tool or LLM sanitizer (when applicable) -> mark or scope event
  sanitizer -> subscriber and exporter dispatch

Tool execution callbacks and each execution-intercept `next` continuation
return the canonical `ToolExecutionResult { result, annotation }`. A forwarding
intercept must preserve both fields in `ToolExecutionInterceptOutcome`; Relay
retains `pending_marks` separately. Tool sanitize-response guardrails receive
only `result`. Scope-end event sanitizers govern the annotation after Relay
projects it to `category_profile.tool_result_annotation`.

## Core Steps

1. Define or reuse the callback type alias in
   `crates/core/src/api/runtime/callbacks.rs`.

```rust
pub type MyNewFn = Box<dyn Fn(&str, Json) -> Json + Send + Sync>;
```

2. Add the registry field to `NemoRelayContextState` in
   `crates/core/src/api/runtime/state.rs`.

Add a `SortedRegistry<GuardrailEntry<MyNewFn>>` or `SortedRegistry<Intercept<MyNewFn>>`
field to the state struct.

3. Add registration and deregistration APIs in `crates/core/src/api/`.

Use the existing `global_*_registry_api!` and `scope_*_registry_api!` macro
patterns in `crates/core/src/api/registry.rs`. Both global and scope-local
variants are needed unless the design explicitly rules one out.

4. Add chain execution helpers to `NemoRelayContextState` in
   `crates/core/src/api/runtime/state.rs`.

Follow the pattern of `tool_sanitize_request_chain` or `tool_request_intercepts_chain`.

5. Wire the chain into the execute path.

Update the relevant lifecycle owner to call the new chain method at the
appropriate pipeline stage. Tool and LLM paths live in
`crates/core/src/api/tool.rs` and `crates/core/src/api/llm.rs`; shared mark and
scope event sanitization lives in `crates/core/src/api/shared.rs` and is called
from `crates/core/src/api/scope.rs`.

6. Expose the new middleware surface in every affected binding.

For a public middleware contract, implement the Rust source of truth, then
update only the bindings, FFI, wrappers, documentation, and tests that expose
or observe the new contract.

## Required Tests

- [ ] Registration and duplicate-name behavior
- [ ] Deregistration and no-op missing-name behavior
- [ ] Ordering by priority
- [ ] Callback failure policy, including fail-open behavior when required
- [ ] Scope-local registration, inheritance, and cleanup on pop
- [ ] Event payload semantics after middleware mutation
- [ ] Tool execution result and annotation preservation, replacement, and
      removal when the middleware touches tool execution
- [ ] Mark and scope event field semantics, including immutable identity fields
- [ ] Parity coverage in every affected binding

## Key References

- Pipeline logic: `crates/core/src/api/tool.rs`, `crates/core/src/api/llm.rs`
- Type aliases: `crates/core/src/api/runtime/callbacks.rs`
- Runtime state and chain builders: `crates/core/src/api/runtime/state.rs`
- Scope-local registry merging: `crates/core/src/context/registries.rs`
- Registry: `crates/core/src/registry.rs`
- Pipeline docs: `docs/about-nemo-relay/concepts/middleware.mdx`
- Architecture docs: `docs/about-nemo-relay/architecture.mdx`
- Registration examples: `docs/instrument-applications/advanced-guide.mdx`

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…