> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/relay/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/relay/_mcp/server.

# Conditional Middleware Guardrails

> Understand how Relay controls the eligibility of global runtime registrations.

A conditional middleware guardrail temporarily excludes an existing global runtime
registration from future middleware snapshots. The target remains registered and keeps
its original owner. When no gate suppresses the target, Relay includes it again without
recreating it.

This control is useful for operational decisions. For example, an application can pause
an exporter during an outage or exclude an expensive intercept while a dependency is
unhealthy. A conditional middleware guardrail does not approve or reject a tool or LLM
call. Use a conditional-execution guardrail for call-level policy.

## Registration Identity

Relay describes each gateable global registration with four identity fields:

* `kind` identifies the subscriber, metadata injector, guardrail, or intercept family.
* `local_name` is the name that the registration owner supplied.
* `effective_name` is the runtime name that a conditional middleware guardrail targets.
* `owner` identifies core, global API, or plugin ownership. Plugin ownership also
  includes the plugin kind and component ordinal when available.

Applications and plugins must discover the effective name from the active runtime.
Plugin contexts qualify local names, and that qualification can change after a process
restart or plugin configuration reload. A controller must not persist an effective name
or construct one from a plugin kind, local name, or component position.

Discovery reports global registrations even when a gate currently suppresses them. This
behavior lets another controller inspect or manage an ineligible target. Discovery does
not report scope-local registrations because global gates never control scope-local
behavior.

## Matching and Ordering

A gate selects an effective registration name and one or more registration kinds. Relay
evaluates every matching gate in gate-name order when it creates a middleware or event
publication snapshot. The target is eligible only when every matching gate returns no
reason. One gate cannot override another gate that suppresses the target.

A reason describes why the target is ineligible for the snapshot. The reason does not
deregister the target, transfer its ownership, or change its configuration.

## Failure and Snapshot Semantics

Conditional middleware guardrails fail open. If a callback fails or panics, Relay keeps
the target eligible and records a bounded runtime diagnostic. This behavior prevents a
faulty operational control from silently removing observability or execution behavior.

Gate changes affect future snapshots. An in-flight execution chain keeps the decision
from the snapshot that created it. An event that already entered the queued publication
path also keeps its existing decision. Registering or removing a gate does not rewrite
those snapshots.

Relay never applies a gate to gate registration, gate deregistration, target
deregistration, or plugin teardown. These operations must remain available so the host
can recover and clean up.

## Ownership Models

An activation-owned gate belongs to one plugin component. The component context
qualifies the gate name, includes registration in the activation transaction, rolls the
gate back after failed activation, and removes it during teardown. This model is
appropriate when configuration determines the target and the gate must exist for the
component's complete active lifetime.

A runtime-discovered dynamic gate belongs to the application or active dynamic plugin
that creates it. A timer, health check, or controller can discover a target and add or
remove the gate while the process runs. The owner must retain the gate handle or name and
provide an explicit cleanup path. Dynamic plugin hosts also enforce activation ownership
so one plugin cannot remove another plugin's gate.

Language-binding gates can evaluate a callback against current in-process state. Native
and worker plugins instead install a host-resident constant reason. This distinction
keeps snapshot construction in the host and avoids a native-library or worker round trip
for every eligibility decision.

## Callback Safety

Gate callbacks run while Relay constructs a snapshot. They must be fast, deterministic,
and side-effect free. A callback can read state that is already available, such as an
atomic timer flag or a cached health result.

A callback must not make a reentrant Relay call that produces middleware, flushes
subscribers, waits for an exporter, or clears plugins. A background task can update the
state that the callback reads or can register and deregister a host-resident dynamic
gate.

## Binding Support

Rust, Python, and Node.js expose the primary language-binding APIs. The native Rust SDK,
Rust worker SDK, and Python worker SDK expose activation-owned and runtime-discovered
host-resident controls.

Refer to [Add Middleware](/instrument-applications/advanced-guide) for application
guidance and [PluginContext](/build-plugins/fundamentals/plugin-context) for plugin
ownership. The corresponding code-example pages provide binding-specific APIs.