Skip to navigation

Configuration and Managed Clients

View as Markdown

The administrator installs shared files. Each user supplies a private route credential through the harness’s launch environment. Prepare these files before starting the service runbook for your platform.

System Configuration

FileLinux and macOSWindows
Runtime configuration/etc/nemo-relay/config.toml%ProgramData%\nemo-relay\config.toml
Plugin manifest/etc/nemo-relay/plugins.toml%ProgramData%\nemo-relay\plugins.toml
Identity stateSee the resolution order below.See the resolution order below.

Relay resolves identity state in this order on every platform, including Windows:

  1. If XDG_CONFIG_HOME is set, use <XDG_CONFIG_HOME>/nemo-relay/daemon.
  2. Otherwise, if HOME is set, use <HOME>/.config/nemo-relay/daemon.
  3. Otherwise, if USERPROFILE is set, use <USERPROFILE>/.config/nemo-relay/daemon.

On Windows, HOME takes precedence over USERPROFILE. Check the environment of the actual daemon or client process before backing up its keys and trust pins. The service runbooks set an explicit XDG_CONFIG_HOME for the daemon. It does not change the managed worker’s system configuration path.

Client identities stay with the user and must not be shared or copied into a machine image.

For a new deployment, create config.toml with these contents:

[upstream]
openai_base_url = "https://api.openai.com/v1"
anthropic_base_url = "https://api.anthropic.com"
response_timeout_secs = 0
[daemon.logging]
level = "info"
stderr_enabled = true
stderr_format = "jsonl"

Confirm provider URL fields against Provider Routing. Use your approved provider URLs when they differ from these defaults. Set the same routing on the daemon and clients for consistent pass-through behavior. The primary nemo-relay daemon process reads only [daemon.logging]; [logging] continues to configure user-space Relay processes such as agent launches. Do not store users’ provider credentials in this shared file. Info-level logs expose readiness events used by the runbooks; Relay’s default log level is error.

Relay waits for provider responses without a deadline by default, allowing long compaction and model execution to finish. Caller cancellation ends the request. Set [upstream] response_timeout_secs to a positive number of seconds to limit the response-header wait on daemon and worker hops. Set it to 0 to disable that limit. Connection, startup, and health checks retain their separate deadlines.

Create plugins.toml with the approved configuration from Configure Plugins. A minimal file with no plugins is:

version = 1
components = []

That minimal file is useful to bring up transport, but does not add observability or policy checks. For deployment acceptance, enable an approved exporter or policy and check its result. For example, use the ATOF exporter with a collector reachable by each client. Do not direct all user workers to one shared writable log file.

On Unix, create /etc/nemo-relay as root with mode 0755 and install the two configuration files as root with mode 0644. On Windows, create C:\ProgramData\nemo-relay as an administrator and allow users read access only. If the directory is new, set its ACLs before distributing files:

New-Item -ItemType Directory -Force 'C:\ProgramData\nemo-relay' | Out-Null
icacls 'C:\ProgramData\nemo-relay' /inheritance:r /grant:r '*S-1-5-18:(OI)(CI)F' '*S-1-5-32-544:(OI)(CI)F' '*S-1-5-32-545:(OI)(CI)RX'

After saving the examples as local config.toml and plugins.toml files, install them on a new Unix deployment:

sudo install -d -m 0755 /etc/nemo-relay
sudo install -m 0644 config.toml plugins.toml /etc/nemo-relay/

On Windows, copy them after setting the directory ACLs above:

Copy-Item .\config.toml, .\plugins.toml 'C:\ProgramData\nemo-relay\'

For an existing installation, merge approved settings rather than replacing files or ACLs blindly. Managed workers ignore personal runtime configuration, plugin directories, and lifecycle state. Install required plugin binaries and dependencies in the administrator-managed locations referenced by the system manifest.

Provision Client Credentials

Provision one 32-byte random, base64url-encoded token for each machine-user identity. Keep the same token across that identity’s harness sessions. Do not regenerate it on every login. A token is not a model-provider key and does not replace the user’s normal provider login.

Create the Per-User Token File

The simplest provisioning path is the per-user token file. Run this command as the user who runs the coding agent, not as root or an administrator:

nemo-relay daemon token ensure --json

The command creates <user config dir>/.client-token if it does not already exist. Relay resolves the user config directory the same way on every platform, including Windows. It uses the first of these that is set:

  1. $XDG_CONFIG_HOME/nemo-relay
  2. $HOME/.config/nemo-relay
  3. %USERPROFILE%\.config\nemo-relay

For example, on Linux and macOS the file is usually ~/.config/nemo-relay/.client-token. On Windows it is %USERPROFILE%\.config\nemo-relay\.client-token unless XDG_CONFIG_HOME or HOME is set, as it often is in Git Bash or MSYS shells. The file Relay uses is the path value printed by nemo-relay daemon token ensure --json. The command:

  • Generates 32 bytes from the operating-system random source and writes them as one unpadded base64url line.
  • Creates the parent directory with mode 0700 when it does not exist and writes the file with mode 0600 (owner-only access on Windows).
  • Publishes the file atomically. Concurrent runs converge on one token.
  • Leaves an existing valid file unchanged and reports existing.
  • Never overwrites an existing invalid or unsafe file. It exits with an error naming the path and the problem; review and remove the file, then run the command again.
  • Never prints the token. --json prints only {"status":"created"|"existing","path":"..."}.
  • Refuses to run as root on Linux and macOS.

Fleet tooling can run the command at every login because it is idempotent. Do not copy one token file between users or machines.

Credential Resolution

Managed hooks (nemo-relay daemon hook), the managed MCP server (nemo-relay daemon mcp), and nemo-relay doctor --managed-bundle resolve the route credential in this order:

  1. NEMO_RELAY_CLIENT_TOKEN, when it is set, nonempty, and valid.
  2. The per-user token file, when it exists, is valid, and is safe: a regular file, not a symbolic link, owned by the current user, with no group or other permission bits (on Windows, the protected owner-only access list), and at most 128 bytes. One trailing newline is allowed.
  3. Otherwise, no credential.

An invalid environment value or an unsafe or invalid file is skipped with one redacted warning; it is not a hard error. The token value is never logged.

The token file exists because environment changes made after login, such as launchctl setenv on macOS, never reach processes that were already running, such as a terminal opened before the change. Every process of the same user can read the file.

The token file restores hooks and MCP only. Harness model requests do not read it. Each harness sends x-nemo-relay-client-token from its own provider configuration, which is read when the harness starts:

  • Codex reads env_http_headers, sourced from NEMO_RELAY_CLIENT_TOKEN, or a static http_headers entry for the managed provider.
  • Claude Code reads the header from ANTHROPIC_CUSTOM_HEADERS, in its launch environment or its settings env.

Without that header, model requests use daemon pass-through (see Requests Without a Bound Credential): they still work but produce no Relay telemetry. A daemon started with --require-worker rejects them with 401 instead. To attribute model traffic, provide the header and restart the harness. For example, export it from the token file in the login environment:

export NEMO_RELAY_CLIENT_TOKEN="$(cat "${XDG_CONFIG_HOME:-$HOME/.config}/nemo-relay/.client-token")"
export ANTHROPIC_CUSTOM_HEADERS="x-nemo-relay-client-token: ${NEMO_RELAY_CLIENT_TOKEN}"

The managed v1 Pi extension reads only NEMO_RELAY_CLIENT_TOKEN and does not read the token file. Pi fails to start without that environment variable: its hooks, MCP, and model routing all stop, not just telemetry. nemo-relay doctor --managed-bundle therefore rejects a file-only credential for bundles that include Pi.

Provision Through Enterprise Tooling

Your enterprise secret service can also provision the token directly. For a small deployment without the token file, choose the commands for your platform.

This example creates a private local bootstrap file once, without printing the token. It requires Python 3 and fails if the file already exists:

python3 - <<'PYTOKEN'
import os
import secrets
from pathlib import Path
root = Path.home() / '.config' / 'nemo-relay-bootstrap'
root.mkdir(mode=0o700, parents=True, exist_ok=True)
root.chmod(0o700)
fd = os.open(root / 'client-token', os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, 'w') as token_file:
token_file.write(secrets.token_urlsafe(32) + '\n')
PYTOKEN
export NEMO_RELAY_CLIENT_TOKEN="$(cat "$HOME/.config/nemo-relay-bootstrap/client-token")"
export ANTHROPIC_CUSTOM_HEADERS="x-nemo-relay-client-token: ${NEMO_RELAY_CLIENT_TOKEN}"

For later launches, run only the environment-loading lines, using the existing file. Use an administrator-provided launcher or login-environment mechanism to repeat that loading before starting the harness. Relay does not install a login agent. Launch desktop applications through that prepared environment; shell exports do not update an app that is already running.

The Claude header assignment above assumes no other custom headers are required. If your deployment needs other headers, preserve those and ensure there is exactly one x-nemo-relay-client-token entry with the matching token. Do not put the credential in the shared bundle, command-line arguments, service unit, or logs.

Choose Stable Deployment Paths

PlatformLocal dispatcher executableInstalled bundle
Linux and macOS/opt/nvidia/bin/nemo-relay/opt/nvidia/share/nemo-relay-managed-v1
WindowsC:/ProgramData/NVIDIA/NeMoRelay/nemo-relay.exeC:\ProgramData\NVIDIA\NeMoRelay\nemo-relay-managed-v1
Remote Linux client/opt/nvidia/bin/nemo-relay-dispatch/opt/nvidia/share/nemo-relay-managed-v1

The binary itself can be the stable dispatcher. The remote Linux example uses a small administrator-owned wrapper to supply worker network settings. Keep the chosen path fixed across binary upgrades. Dispatcher paths must contain no spaces or shell metacharacters, including on Windows. Bundle generation checks path shape; deployment tooling must enforce ownership and permissions.

On Windows, use forward slashes in --dispatcher-command. Generated hooks can run in Git Bash, which treats backslashes as escape characters. PowerShell file paths elsewhere in these examples can use backslashes.

Route Authentication

The managed topology has the following processes:

  • nemo-relay daemon owns the public LLM and hook endpoints and the authoritative route broker.
  • nemo-relay daemon mcp registers one MCP client reference for the current machine-user identity. It advertises no MCP tools.
  • nemo-relay daemon hook forwards one native hook payload using the managed route credential.
  • nemo-relay daemon worker runs the per-machine-user Relay configuration and remains attached to the daemon for its useful lifetime.

All LLM and hook paths remain at the daemon root. Managed settings do not use per-user route URLs. Requests use one Relay-specific public credential header:

x-nemo-relay-client-token: <base64url-encoded-256-bit-credential>

Pi provider registrations also preserve Pi’s runtime-selected endpoint in x-nemo-relay-upstream-base-url. The authenticated daemon consumes that routing header and removes it before contacting the provider. It is runtime model metadata, not part of the managed settings artifact.

Enterprise bootstrap can provide the credential through this environment variable. Managed hooks and MCP also read the per-user token file. The environment variable is still required for the managed Pi extension, and for model requests whose provider header is sourced from the environment: Codex env_http_headers, and ANTHROPIC_CUSTOM_HEADERS derived from it.

export NEMO_RELAY_CLIENT_TOKEN='<credential>'

Claude Code reads custom provider headers from its native environment variable, so the same bootstrap must derive exactly one header from that credential:

export ANTHROPIC_CUSTOM_HEADERS="x-nemo-relay-client-token: ${NEMO_RELAY_CLIENT_TOKEN}"

Do not append another x-nemo-relay-client-token entry to an existing custom header value. Managed diagnostics reject a missing, duplicate, or mismatched credential header when the credential comes from NEMO_RELAY_CLIENT_TOKEN. When the credential comes from the token file, diagnostics accept a missing ANTHROPIC_CUSTOM_HEADERS (Claude Code model requests then use pass-through) but still reject a present header that does not match the file.

The same credential identifies MCP registration, Codex and Claude LLM requests, Pi provider requests, and managed hook requests. The daemon does not require a token file or a token environment variable. During signed MCP registration, it binds the credential digest to the user-machine fingerprint. An existing binding cannot be reassigned to another fingerprint. The daemon stores only credential digests, removes the public header before forwarding a request, and preserves the caller’s provider authentication.

Replace a Client Token

The daemon binds each token to the machine-user identity that first registers it. Bindings are kept in memory and are not released just because sessions end. A binding is cleared only when:

  • the daemon restarts;
  • the identity reaches its token limit and the token is its least recently registered one without a live MCP session (described below); or
  • the daemon’s route table is full and the identity’s whole route is evicted because it has no MCP references.

If the token changes while the daemon is running, for example because the token file is removed and nemo-relay daemon token ensure creates a new one:

  • MCP registration with the new token joins the identity’s existing route and worker. No second worker is launched.
  • The old token stays bound to that route alongside the new one, so sessions that still hold it keep working, until one of the events above clears it.
  • Removing or purging a token file does not revoke a token the daemon has already bound. Use a daemon restart to clear every binding at once.

One identity can hold a limited number of distinct tokens at once: 4 by default. The limit bounds the daemon’s in-memory token table; it is not a security control. When a new token arrives at the limit:

  1. The daemon releases the identity’s least recently registered token that has no live MCP session and logs route_token_released. A released token resolves like any unbound token and can bind again later.
  2. If every bound token still has a live MCP session, the new token is rejected with route_credential_rejected, and the daemon logs mcp_registration_rejected with reason = "route_token_limit_reached". nemo-relay daemon mcp does not retry the rejection; it logs daemon_mcp_pass_through with reason = "credential_rejected" and keeps serving MCP without a route, so the harness keeps working. The same applies when an already running MCP registers again after a reconnect or daemon restart: it logs the fallback with phase = "reregistration" and keeps serving instead of exiting. The fallen-back MCP does not register again, so freeing a slot or restarting the daemon does not bind its token. Requests with that token use pass-through, or receive 401 with --require-worker, until a new MCP session with the token registers. Restart the affected harness session to bind it once a slot is free.

Change the limit with nemo-relay daemon --max-tokens-per-identity <N> or the NEMO_RELAY_DAEMON_MAX_TOKENS_PER_IDENTITY environment variable on the daemon service, from 1 through 64. The flag takes precedence. An invalid environment value stops daemon startup with a configuration error. Set the variable in the service definition, for example EnvironmentVariables in the macOS launchd plist, Environment= in a systemd unit, or the WinSW service environment, then restart the daemon. Raise it only if users legitimately run sessions on more than four tokens at the same time; idle tokens are released automatically.

Requests Without a Bound Credential

A missing credential means telemetry and guardrails are skipped for that request; the coding agent keeps working:

  • A public request with no x-nemo-relay-client-token header, or with a well-formed credential that no MCP session has bound (for example, after a daemon restart and before MCP registers again), uses pass-through. So does a bound credential whose route has no live MCP session, for example from a harness whose MCP exited while the daemon was restarted or reinstalled. Hook requests receive the agent’s no-op pass-through response. Provider requests are forwarded directly to the configured provider with the caller’s own provider authentication.
  • A malformed credential or a repeated header still returns 401.
  • A daemon started with --require-worker keeps rejecting missing and unbound credentials with 401.
  • A request without a bound credential never receives daemon-held provider credentials (configured provider auth headers or the daemon’s own OPENAI_API_KEY or ANTHROPIC_API_KEY), except that a daemon explicitly started with --pass-through applies its provider credentials to every request.
  • A provider request that names its own upstream with x-nemo-relay-upstream-base-url, as the managed Pi extension does, is honored only with a bound credential. Without one it receives 503 with Retry-After and is never forwarded, so a credential meant for the named upstream cannot reach the configured provider. After a daemon restart, retry once MCP registers again. The daemon logs public_request_named_upstream_rejected.
  • The daemon logs each decision as public_request_pass_through with route_mode = "pass_through" and reason = "missing_credential", reason = "unbound_credential", or reason = "no_live_session", rate-limited, without the credential.

On the client side, nemo-relay daemon hook with no resolvable credential does not contact the daemon. It writes the same pass-through response and exits 0, regardless of --fail-open or --fail-closed, and logs a warning. nemo-relay daemon mcp with no resolvable credential keeps serving the MCP protocol without registering a route, so hosts that require the server keep running. It does the same, without retrying, when the daemon rejects its credential at registration; see Replace a Client Token.

Enrollment is open to anyone who can reach the daemon and prove possession of their machine identity. This proof establishes identity, not organizational authorization. Restrict daemon access to trusted users through your network or authenticated reverse proxy; do not expose open enrollment to an untrusted network. TLS remains required for non-loopback communication.

Challenge requests are limited to 16 per transport-peer IP in a 15-second window, before the request body is read. MCP and worker challenges retain separate capacity limits. Forwarded IP headers do not override this limit: clients behind a reverse proxy share its peer budget. Apply additional per-client admission controls at the proxy for larger deployments.

Distribute Immutable Managed Settings

A managed bundle is an administrator-owned deployment artifact, not an output of personal nemo-relay install. For each agent, platform, and deployment, its plugin configuration and settings must remain byte-for-byte identical across users and Relay binary releases.

The bundle follows these rules:

  • Daemon and provider URLs and hook command text are fixed for the deployment.
  • Artifacts contain no user path, fingerprint, credential, generation ID, or Relay binary version.
  • A stable administrator-owned dispatcher command or path survives Relay upgrades.
  • Refresh validates immutable artifacts and never rewrites them.
  • An incompatible settings change uses a separately named v2 artifact rather than replacing v1 bytes.

Enterprise bootstrap owns credential provisioning and login-environment injection. Relay validates the resolved route credential from NEMO_RELAY_CLIENT_TOKEN or the per-user token file, and nemo-relay daemon token ensure creates that file, but Relay does not install an operating-system-specific login agent.

Create a bundle once from fixed deployment values. Repeat --agent to select the artifacts that the administrator distributes:

nemo-relay daemon managed-bundle \
--output /opt/nvidia/share/nemo-relay-managed-v1 \
--daemon-address http://127.0.0.1:47632 \
--dispatcher-command /opt/nvidia/bin/nemo-relay \
--platform linux \
--agent codex \
--agent claude \
--agent pi

Run bundle generation as an administrator when writing the installed system path. For macOS, change --platform linux to --platform macos. For remote Linux, use --daemon-address https://relay.example.com:8443 and --dispatcher-command /opt/nvidia/bin/nemo-relay-dispatch.

On Windows, use an elevated PowerShell window:

& 'C:\ProgramData\NVIDIA\NeMoRelay\nemo-relay.exe' daemon managed-bundle `
--output 'C:\ProgramData\NVIDIA\NeMoRelay\nemo-relay-managed-v1' `
--daemon-address http://127.0.0.1:47632 `
--dispatcher-command 'C:/ProgramData/NVIDIA/NeMoRelay/nemo-relay.exe' `
--platform windows --agent codex --agent claude --agent pi

The installed bundle must be readable by users and writable only by administrators. Store the printed digest in your deployment records and provision it separately to clients. Do not add files to the bundle after generation, even a digest file or a marketplace manifest; its exact file set is validated.

The destination must be new or already byte-identical. The command never rewrites a different v1 bundle and prints only the canonical full-bundle SHA-256. Provision that digest separately from the bundle; a digest stored inside the same artifact is not a trust root. The dispatcher path is validated for the target platform and must be an absolute, stable administrator path outside known user and temporary directories.

Validate a distributed bundle and its current environment without modifying the bundle:

nemo-relay doctor \
--managed-bundle /path/to/nemo-relay-managed-v1 \
--managed-bundle-sha256 '<separately-provisioned-64-character-sha256>'

Doctor compares the exact file set and bytes with the canonical manifest and the separately provisioned digest, then reports missing, unexpected, or changed artifacts. This is a managed-only diagnostic: it does not load or fail because of personal configuration, plugins, or agent installations.

Load a Managed Harness

Install only the managed Relay integration for this deployment. Disable or remove the personal Relay plugin through its harness before switching. Two Relay MCP entries or two sets of Relay hooks can conflict or submit events twice.

The following steps load the generated bytes. They do not make a user’s entire harness configuration immutable. For organization-wide enforcement, distribute these artifacts with the harness’s managed policy mechanism and verify its effective settings. Keep unrelated settings and existing authentication intact.

Codex

Codex needs both the generated plugin and the provider configuration. Create an administrator-owned local marketplace beside the validated bundle. On Linux and macOS, use /opt/nvidia/share/nemo-relay-codex-marketplace-v1; on Windows, use C:\ProgramData\NVIDIA\NeMoRelay\codex-marketplace-v1.

Inside that marketplace, create .agents/plugins/marketplace.json:

{
"name": "nemo-relay-managed",
"interface": { "displayName": "NeMo Relay Managed" },
"plugins": [{
"name": "nemo-relay-managed-v1",
"source": { "source": "local", "path": "./plugins/nemo-relay-managed-v1" },
"policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" },
"category": "Coding"
}]
}

Copy the entire bundle directory codex/plugin-v1 to the marketplace’s plugins/nemo-relay-managed-v1, including hidden files. On Unix:

sudo mkdir -p /opt/nvidia/share/nemo-relay-codex-marketplace-v1/.agents/plugins
sudo mkdir -p /opt/nvidia/share/nemo-relay-codex-marketplace-v1/plugins/nemo-relay-managed-v1
sudo cp -R /opt/nvidia/share/nemo-relay-managed-v1/codex/plugin-v1/. \
/opt/nvidia/share/nemo-relay-codex-marketplace-v1/plugins/nemo-relay-managed-v1/

On Windows, create the corresponding directories in an elevated PowerShell window:

$RelayMarket = 'C:\ProgramData\NVIDIA\NeMoRelay\codex-marketplace-v1'
if (Test-Path "$RelayMarket\plugins\nemo-relay-managed-v1") {
throw 'The plugin destination already exists; compare it with the validated bundle instead of copying again.'
}
New-Item -ItemType Directory -Force "$RelayMarket\.agents\plugins", "$RelayMarket\plugins" | Out-Null
Copy-Item -Recurse -Force 'C:\ProgramData\NVIDIA\NeMoRelay\nemo-relay-managed-v1\codex\plugin-v1' "$RelayMarket\plugins\nemo-relay-managed-v1"

Run the copy only when creating this marketplace. Keep its files administrator-owned. For subsequent deployments, compare the copy with the validated bundle rather than merging new files into it. Save the JSON manifest at the path given above.

As the target user, register and enable the plugin:

codex plugin marketplace add /opt/nvidia/share/nemo-relay-codex-marketplace-v1
codex plugin add nemo-relay-managed-v1@nemo-relay-managed
codex plugin list

On Windows, use the same commands with the quoted Windows marketplace path. These commands match the Codex plugin add interface; confirm the installed harness meets the repository’s minimum version.

Load codex/settings-v1/config.toml from the bundle into the deployed Codex configuration. For a fresh user configuration, copy its contents to ~/.codex/config.toml (Windows: %USERPROFILE%\.codex\config.toml). If a config already exists, back it up and merge the top-level model_provider setting and the [model_providers.nemo-relay-managed-v1] table once. Keep authentication and unrelated configuration. Do not append duplicate TOML tables. If CODEX_HOME is already configured, use that configuration location instead.

For ChatGPT voice calls, add this setting to your user-level Codex configuration or /etc/codex/managed_config.toml. Put it at the top level, before any TOML table headers. Use your daemon’s address if it differs from this local example.

experimental_realtime_webrtc_call_base_url = "http://127.0.0.1:47632/backend-api/codex"

This URL makes Codex send ChatGPT’s JSON call request to /realtime/calls. The updated daemon forwards that request through the selected worker. Keep the managed provider’s existing /v1 base URL. API-key sessions use the public API format and do not need this ChatGPT setting.

Restart Codex Desktop after changing its configuration. The default WebRTC sideband can connect directly to OpenAI. The audio also travels directly. For this setup, you do not need to set experimental_realtime_ws_base_url.

Keep this setting in the source configuration used by your deployment tools so they preserve it during updates. Do not edit the immutable codex/settings-v1/config.toml bundle artifact. Updating the binary or running managed refresh does not add this setting. The personal-install command nemo-relay install codex --force does not update a managed deployment.

Enable hooks in that effective configuration:

[features]
hooks = true

Merge hooks = true into an existing [features] table when present. Restart Codex from the prepared token environment. Open /mcp and confirm the Relay MCP connection is ready. Review and trust the installed Relay hooks through Codex’s hook controls; verify exactly one enabled handler for every generated hook event. A plugin listing alone does not prove that hooks are trusted or the provider is selected. See Codex configuration for configuration layers and Operations for end-to-end checks.

Claude Code

Launch Claude Code with both generated artifacts. On Linux and macOS:

claude --plugin-dir /opt/nvidia/share/nemo-relay-managed-v1/claude-code/plugin-v1 \
--settings /opt/nvidia/share/nemo-relay-managed-v1/claude-code/settings-v1/managed-settings.json

On Windows:

claude --plugin-dir 'C:\ProgramData\NVIDIA\NeMoRelay\nemo-relay-managed-v1\claude-code\plugin-v1' `
--settings 'C:\ProgramData\NVIDIA\NeMoRelay\nemo-relay-managed-v1\claude-code\settings-v1\managed-settings.json'

Use these arguments in the managed launcher for every session. The filename managed-settings.json does not itself enforce policy when passed with --settings; enforced deployments must install it through Claude Code’s managed settings mechanism. Preserve any existing organization policy when merging its env.ANTHROPIC_BASE_URL value. The plugin and its MCP/hook files remain unchanged. See Claude Code’s plugin loading guide and settings reference.

Hooks and MCP can use the per-user token file when the launch environment has no NEMO_RELAY_CLIENT_TOKEN. Gateway model routing still needs ANTHROPIC_CUSTOM_HEADERS with the matching token, set in the launch environment or in Claude Code settings env. Without it, Claude model requests pass through the daemon without Relay telemetry, or receive 401 from a daemon started with --require-worker. When both variables are set, their tokens must match. Check /mcp after startup and verify that Relay hooks are enabled. Managed Claude model routing requires an Anthropic API key or an administrator-configured Anthropic-compatible gateway credential. Claude.ai OAuth is not supported with ANTHROPIC_BASE_URL: Claude Code refreshes that session against its native service rather than an Anthropic-compatible gateway. Do not set the managed base URL for a Claude.ai OAuth-only deployment; preserve native routing until Anthropic provides a supported OAuth gateway contract.

Pi

Use the managed Pi extension below on Unix. On Windows, the equivalent launch command is:

pi --no-extensions -e 'C:\ProgramData\NVIDIA\NeMoRelay\nemo-relay-managed-v1\pi\extension-v1\index.ts'

Always include --no-extensions and the exact administrator-owned extension path. Verify a model whose provider uses one of the supported HTTP APIs. Pi starts the managed MCP process itself; do not register a second Relay MCP process.

Deploy the Managed Pi Extension

The Pi artifact is a fixed TypeScript extension under pi/extension-v1/index.ts. Load that exact administrator-installed file while disabling discovered extensions; do not copy it into a per-user extension directory or rewrite it during upgrades. For example:

pi --no-extensions -e /opt/nvidia/share/nemo-relay-managed-v1/pi/extension-v1/index.ts

--no-extensions is mandatory for managed launches. Pi still loads the explicit -e extension, but does not also load user, project, or discovered extensions that could alter provider registration, tool arguments, or shell policy after Relay has authorized an operation.

The extension starts the fixed dispatcher as daemon mcp --daemon-address <URL>, waits for MCP initialization before registering managed providers, and keeps one process-wide broker reference across Pi reload, new, resume, and fork transitions. It sends Pi’s session, agent, turn, compaction, tool, and custom shell events to /hooks/pi; policy responses are converted back into Pi’s native tool_call and user_bash blocking results. Any selected Pi provider whose models use only OpenAI Completions, OpenAI Responses, or Anthropic Messages and share one endpoint is registered against the daemon, including custom provider names. The registration attaches x-nemo-relay-client-token and Pi’s exact runtime-selected endpoint in x-nemo-relay-upstream-base-url. No per-user upstream, fingerprint, generation, user path, or route value is written into the managed artifact.

Supported Provider Routes

The managed daemon accepts provider requests for only these API types:

  • OpenAI Completions
  • OpenAI Responses
  • Anthropic Messages

The daemon does not have a route for Google’s Gemini or Vertex API. Requests to those normal Google endpoints do not pass through Relay, so Relay cannot record the LLM call or apply LLM request rules to it.

To send Gemini model traffic through the daemon, use a provider or proxy that accepts OpenAI Completions, OpenAI Responses, or Anthropic Messages requests, then configure the client to use that compatible API. Do not point a Gemini endpoint at the daemon’s OpenAI or Anthropic routes; the request formats are different. Relay’s Gemini codec can translate Gemini data in application integrations, but it does not add a managed daemon route.

Codex Responses Compatibility

Both the personal gateway and managed daemon recognize Codex ChatGPT OAuth on OpenAI routes, including the managed provider’s /v1/responses and /v1/models requests. When no administrator OpenAI credential is configured, Relay preserves the OAuth credential and sends the request to the native ChatGPT Codex backend. When openai_auth_header or OPENAI_API_KEY is configured for the daemon, Relay removes the ChatGPT OAuth credential, injects that replacement credential, and uses the administrator’s configured OpenAI-compatible upstream instead.

ChatGPT voice call creation is an exception. Requests to POST /backend-api/codex/realtime/calls keep the caller’s ChatGPT credential and use the native ChatGPT backend even when a replacement OpenAI credential is configured. This preserves ChatGPT’s JSON call format.

Live and Realtime connections use the configured OpenAI upstream and keep the caller’s provider credential. By default, that upstream is api.openai.com, which matches Codex’s WebRTC sideband destination. Relay does not replace a ChatGPT sideband credential with an administrator key.

The daemon also accepts Codex’s ChatGPT-shaped POST /backend-api/codex/responses path and canonicalizes it to the ordinary Responses route. A WebSocket upgrade probe sent with GET to that path, /responses, or /v1/responses receives 426 Upgrade Required, which causes clients that support the fallback to use HTTP streaming. An ordinary GET remains 405 Method Not Allowed.