Release Notes for NVIDIA NeMo Relay
This page contains the release notes for NVIDIA NeMo Relay.
For the full release history, including individual pull requests, refer to GitHub Releases.
Release 0.9.0
Highlights
This release adds the following features and changes:
- A shared daemon routes coding-agent requests to separate workers. Each user on each computer gets a worker with its own plugins and runtime state.
- The CLI adds Pi support. You can install its extension, record session activity, check tool calls against policy, and route supported model requests.
- All language bindings use the same plugin host to start, check, and stop plugins. Reports show the combined settings from files and application code.
- Related work stays in the same trace by default. OpenTelemetry tool spans include more details about tool execution and sanitized tool content.
Update plugin-host calls and tool execution intercepts before upgrading. Review trace boundaries and policies for removing personally identifiable information (PII). Change remote plaintext trace endpoints to HTTPS. OTLP/HTTP trace exporters no longer follow redirects. For required steps, refer to the Migration Guides.
Managed Daemon Deployments
Daemon mode supports the following shared-service features:
nemo-relay daemonroutes requests from authenticated Model Context Protocol (MCP) clients to workers. It supports coding-agent bundles that administrators manage for Codex, Claude Code, and Pi. Workers load system settings.- MCP clients and workers keep WebSocket control connections open. These connections carry route updates, readiness checks, shutdown requests, and recovery messages. Model and hook traffic uses separate HTTP connections. Responses stream back as data arrives.
- Local deployments support Windows, macOS, and Linux. Remote deployments use HTTPS. Clients must reach the daemon, and the daemon must reach each client worker. Proxies must support WebSocket upgrades, keep those connections open, and forward frames in both directions. For setup, service management, upgrades, and troubleshooting, refer to Daemon.
- A managed gateway has up to 20 seconds after Relay starts it to resolve its persistent configuration, bind its listener, and report readiness. This gives slow configuration discovery time to finish.
Coding-Agent and Framework Support
The following updates extend support for coding agents and frameworks:
- Use
nemo-relay install pi,nemo-relay pi, andnemo-relay doctor pito install, launch, and check the Pi extension. This proof of concept is tested with Pi 0.84.x. It records sessions, turns, tools, and shell commands entered in Pi. It checks policy through supported hooks. - When Relay launches Pi, model requests can select named upstreams automatically. Relay skips models that use unsupported APIs. It also skips providers whose models have incompatible endpoint settings. For routing details, refer to Pi.
- Use
create_tool_nodeto run standalone LangGraphToolNodecalls through Relay’s tool pipeline. LangGraph still supplies state, store, and runtime arguments. AddNemoRelayCallbackHandlerto record graph lifecycle scopes. For details, refer to Managed ToolNode Calls. - The OpenClaw plugin now targets OpenClaw 2026.9.3. Its minimum gateway version is also 2026.9.3. For details, refer to OpenClaw Plugin.
Plugin Configuration and Caching
Plugin settings and response caching include the following updates:
initializeandvalidateuse the same plugin settings, version checks, and trust policy. Exact validation checks only the static document you pass in. Initialization returns aPluginHostActivationhandle that controls plugin lifetime. For details, refer to Configure and Initialize Plugins.- Host reports include
config_pathsandresolved_config. These fields show which files contributed settings and how Relay combined them with application settings. Reports redact literal credentials and values in dynamic-plugin settings whose meaning Relay does not know. - Dynamic plugin declarations now layer by manifest plugin ID. When a higher-precedence file declares the same ID, its complete record replaces the lower-precedence record instead of blocking startup with a duplicate-ID error. For details, refer to Plugin Configuration Files.
- Response caching adds
key_strategy = "logical". It ignores changes to tool descriptions and tool order. Other tool-definition changes still affect the key.exact_requestremains the default. Each strategy has its own set of cache keys. For details, refer to Key Strategies.
Observability and Redaction
Trace exports and PII redaction include the following changes:
- Forking a scope stack or capturing propagation context keeps the Relay root when one is available. This root links related work to the same OpenTelemetry trace, even across processes. You can still capture a rootless context to start a separate trace.
- ATIF uses the propagated root as the exported
session_idwhen one is present. Thetrajectory_id, filenames, storage keys, and remote session headers still use the individual trajectory scope UUID. - Claude Code, Codex, and Pi provide consistent tool types and executing-agent
names, including known subagent names. The
gen_aioutput format now includes sanitized tool arguments and successful results when they are JSON objects. It also includes tool-definition identities. Thefullandopeninferenceformats receive the added tool metadata. For details, refer to OpenTelemetry. - Direct trace, log, and metric subscribers can read exporter headers from
environment variables. Use
header_env, orheaderEnvin Node.js. Relay reads the values when it creates the subscriber. Missing or invalid values prevent creation without exposing the secret. - Observability exporters can also read a header from a local file with
header_file. This supports credentials that another process rotates. Relay reads the file for each HTTP delivery. An ATOF WebSocket reads it when it connects or reconnects, and an NDJSON sink reads it when it starts. Relay does not write the header value to diagnostics. - OpenTelemetry trace, log, and metric exports add their standard SDK resource
fields automatically. Do not set the reserved
telemetry.sdk.*fields yourself. - The PII
trajectory_contextpreset removes unknown fields and opaque payloads, whose structure Relay cannot safely interpret. It keeps approved analytics fields and trace links. Typed metric attributes must match allowed string names and values. The preset drops numeric, boolean, and unlisted attributes. Python, Node.js, and Go configuration helpers expose the preset and its typed settings. For details, refer to PII Redaction Configuration.
Operational Diagnostics
The CLI and daemon now provide more privacy-safe operational logs:
- Daemon logs show worker, route, MCP session, and upstream lifecycle events. CLI logs also show hook delivery and upstream request events, including slow or stalled streams. These records use random operation IDs and do not include prompts, tool data, model names, URLs, headers, or credentials.
- Failure records use short, fixed reason codes. These codes help operators identify a failed MCP session, gateway recovery, or worker startup without placing private error text in structured logs.
nemo-relay doctornow includes the redacted plugin-host preflight. It shows static settings and dynamic-plugin trust or configuration problems without starting plugins.
For the event names, fields, and logging setup, refer to Operational Logging.
Support Matrix and Compatibility Updates
For supported platforms, architectures, worker runtimes, coding agents, and integrations, refer to the Support Matrix. Go and the raw C FFI remain experimental, with source-first support.
For steps to upgrade from 0.8.x to 0.9, refer to the Migration Guides.
Breaking Changes
Review each of the following changes before upgrading.
Tool Execution Intercepts
Tool execution intercepts now receive (ToolExecutionContext, next) because
Relay needs to pass the provider tool-call ID with the name and arguments.
Update every callback and plugin SDK that you use. Native plugins use ABI v5,
and native or worker plugins that register this callback cannot support Relay
0.8. Follow the Migration Guides before you
upgrade.
Plugin Host Lifecycle and Trust
Global plugin clear and report functions and explicit dynamic activation-spec APIs are removed because one activation handle now owns the plugin host. Keep the handle, read its report, and close it during shutdown. The host also checks dynamic-plugin trust through every embedding API, so an unsigned plugin that previously started can now fail. Follow the Migration Guides before you upgrade.
Layered Dynamic Plugin Records
A higher-precedence [[plugins.dynamic]] record with the same manifest ID now
replaces the full lower-precedence record. This avoids duplicate-ID failures,
but it also means that the lower record’s config is not kept. Copy all needed
settings to the higher-precedence record. Follow the
Migration Guides before you upgrade.
Python Plugin Errors
Python plugin initialization and activation now raise ValueError for invalid
static settings and FileNotFoundError for unavailable files or resources.
These errors replace RuntimeError for those cases, so existing exception
handlers can miss them. Follow the Migration Guides
before you upgrade.
Trace Boundaries
Default propagation can now join traces that were separate. In ATIF,
session_id identifies a run and trajectory_id identifies one trajectory in
that run. This preserves the parent trace across related work. Follow the
Migration Guides before you upgrade.
GenAI Tool Content
GenAI exports now include sanitized tool content by default. Review redaction and data-access rules because your collector can receive content that it did not receive before. Follow the Migration Guides before you upgrade.
Secure Trace Transport
Remote trace collectors must use HTTPS. Plain HTTP is limited to localhost and loopback IP addresses, and OTLP/HTTP trace exporters reject redirects. This prevents trace data from being sent to an unexpected or insecure destination. Follow the Migration Guides before you upgrade.
File-Based Exporter Headers
Rust observability struct literals must set the new header_file field, and Go
code that uses unkeyed composite literals must switch to keyed fields. Also,
when any exporter header source is set, remote ATOF, ATIF, log, and metric
destinations require secure HTTPS or WSS transport. These rules protect rotated
credentials. Follow the Migration Guides before
you upgrade.
PII Redaction
The stricter trajectory_context preset removes opaque fields and metric
attributes that it previously kept, so analytics that use them need updates.
Follow the Migration Guides before you upgrade.
Rust Response Cache API
Rust ResponseCacheConfig.key_strategy now uses
ResponseCacheKeyStrategy instead of String, and
KEY_STRATEGY_EXACT_REQUEST is removed. Update source code that configures a
response cache. Follow the
Migration Guides before you upgrade.
Fixed Known Issues in 0.9
This release fixes the following issues that also affect earlier releases:
- Coding-agent LLM events keep the provider’s conversation ID when one is given. Otherwise, they use the coding agent’s session ID to link events.
- LangChain keeps message boundaries, tool-call IDs, and provider-specific
content blocks when middleware processes messages. Relay omits its headers
for models whose SDK rejects
extra_headers, so those calls can proceed. - Anthropic token usage is kept when a stream reports it across several events.
Gateway routing handles upstream URLs that already end in
/v1. Collected streams also keep content and encrypted content from Anthropiccompaction_deltaevents. - OpenAI Responses decoding keeps Codex automation tool outputs. Codex routing overrides also stay in the launched command’s execution scope.
- Codex installation handles marketplace entries that point to missing files.
Use
nemo-relay install codex --forceto repair stale entries owned by Relay. - Generated Codex and Claude Code hook commands use private files.
- PII URL masking no longer keeps credentials. Overlapping PII path selectors no longer remove unrelated request content.
- Gateway streams can run for more than five minutes when data keeps arriving. Relay still stops a stream that stays idle for five minutes.
nemo-relay doctorgives a slow coding-agent CLI up to 10 seconds to report its version. Network health checks keep their shorter timeout.nemo-relay gateway stoprecognizes the published pinned CLI process and can stop the Relay-owned gateway it started.- OpenTelemetry flush and shutdown drain accepted trace, log, and metric data more reliably before they finish.
Other Improvements
This release also includes the following updates:
- Unix and PowerShell uninstall scripts remove a CLI installed by a script. They keep settings and integrations. They check active processes and refuse removal while managed daemon processes use the binary. For details, refer to Remove a Script-Installed CLI.
- ATIF documentation explains how metadata placeholders become safe path components. Slashes in metadata values do not create nested directories. For details, refer to Metadata-Based Paths.
Known Issues in 0.9
The following limitations still apply in this release:
- OTLP collectors can return a successful response while rejecting individual spans, log records, or metric data points. Relay does not report these partial successes in runtime diagnostics, and flush or shutdown can still succeed. Monitor collector-side rejection metrics and logs. Refer to OpenTelemetry.
- Go and the raw C FFI remain experimental and source-first. Generated API pages focus on Rust, Python, and Node.js.
- Local coding-agent observability depends on host hooks and provider traffic reaching the local gateway. Relay cannot fully capture remote or cloud execution that bypasses the local host.
- Persistent Codex and Claude Code integrations use user-scoped
configuration and a shared loopback gateway. Use
nemo-relay runwhen a launch must retain project-specific configuration. - On Windows, a restrictive host Job Object can limit gateway reuse or prevent
persistent bootstrap. Codex can also make a cold-start
/modelsrequest before required MCP servers start; Relay retries the request. - Codex 0.143 does not expose
SessionEnd, and Codex multi-agent v2 encrypts delegated-task payloads that Relay cannot decrypt or reliably link. - Pi support is a proof of concept tested with 0.84.x. By default, its personal extension lets work continue if the gateway is unavailable. Later extensions can change arguments after Relay checks them. Unsupported provider routes produce no LLM spans. This includes Google’s native Gemini and Vertex APIs. To route Gemini model traffic through Relay, use a provider or proxy that accepts an OpenAI- or Anthropic-compatible API. Nested Pi processes appear as separate sessions. SIGINT in headless mode can stop Pi before queued events are sent. For details, refer to Pi Limitations.
- If a managed daemon worker fails to start, its authenticated route can enter pass-through mode. This mode forwards model requests without worker plugins until all MCP clients leave the route. MCP readiness alone does not prove that policy checks or exporters are active. For details, refer to Daemon Operations.
- Remote daemons and client workers must be able to reach each other. Proxies must support WebSockets. Loopback control connections do not send periodic pings. An idle hung process can go undetected until an operation times out.
- The Node.js binding and package workflows require Node.js 24 or later.
- OpenClaw has public hook-backed telemetry. Its security and optimization coverage is partial because it does not own a managed execution path.
- The built-in
nemo_guardrailsplugin is deprecated and scheduled for removal in NeMo Relay 0.9. No replacement is included. Until removal, the remote backend inherits its configured service’s availability, latency, and policy behavior, and the local backend requires Python 3.11 or later andnemoguardrails==0.22.0. Removal will include the built-in component kind, the publicnemo_relay::plugins::nemo_guardrailsRust module, its CLI editor entry, and theguardrails-remoteCargo feature. - The PII redaction plugin currently supports its deterministic local backend; local-model backend configuration is reserved for future work.
- Pricing and optimization estimates depend on model names, token data, pricing sources, and freshness evidence. Missing or inconsistent evidence produces partial or absent cost fields rather than zero values.
- ATOF stream sinks and remote ATIF storage require reachable, correctly configured destinations. A failed stream sink does not stop file output or other active sinks.
- ATIF omits point-in-time marks. Use ATOF for the canonical mark stream;
the
gen_aiOpenTelemetry projection also omits marks. Thefullandopeninferenceprojections retain their fixed native mark handling. - Native dynamic plugins run in the Relay process and are not sandboxed. A
grpc-v1worker runs in a separate process, but that process is not a security sandbox. - Treat Python
LLMRequestobjects as immutable. Request middleware that changes content must return a new request object. - Native subscriber callbacks arrive asynchronously. Flush subscribers before depending on their side effects, captured events, files, or exporter output.
- OpenTelemetry endpoints use finite batch queues. A burst that fills an
endpoint queue drops completed spans without applying backpressure and can
leave an incomplete trace, including a missing root span. The SDK warns on
the first drop and reports the exact dropped-span count during graceful
shutdown. Configure
max_queue_size,max_export_batch_size, andscheduled_delay_millisindependently on each endpoint, or use the standardOTEL_BSP_*environment variables as process-wide fallbacks. A larger finite queue does not guarantee lossless telemetry. - Operational logging covers Relay-managed hooks, gateway requests, the daemon, and workers. It does not yet cover every CLI command.
Previous Releases
For previous release notes, release artifacts, and the complete PR-by-PR history, refer to GitHub Releases.
Related Topics
For more information, refer to the following pages: