Skip to main content
This guide explains how to integrate NVIDIA NeMo Guardrails with TrueFoundry AI Gateway as input and output guardrails. The integration runs NeMo’s self_check_input and self_check_output rails inside a small wrapper service that you deploy on TrueFoundry. The gateway invokes the wrapper through its Custom Guardrail interface - there are no native NeMo SDK calls from the gateway and no client SDK changes in your applications.
Source repository: truefoundry/integrations-custom-guardrails/integrations/nemo/. It contains the Dockerfile, deploy script, prompt templates, and tests referenced below.

What is NVIDIA NeMo Guardrails?

NVIDIA NeMo Guardrails is an open-source toolkit for adding programmable safety rails to LLM applications. It uses a small judge LLM plus a domain-specific language (Colang) to evaluate inbound prompts and outbound responses against policies you define.

Key Features of NeMo Guardrails on TrueFoundry

  1. Jailbreak and prompt-injection detection on inbound user messages via NeMo’s self_check_input rail.
  2. Output safety review on the model response before it returns to the caller via self_check_output.
  3. Unified audit trail: NeMo’s rail-judge LLM calls are routed back through your TrueFoundry gateway, so guardrail token spend, latency, and user attribution appear in the same dashboards as your inference traffic.
  4. Customizable rail bundle: extend the rails using NeMo’s Colang DSL and YAML - add Llama Guard, hallucination detection, or topical rails by editing config/ in the wrapper repo and redeploying.
The v1 rail bundle is intentionally minimal: on every request, a judge LLM is asked whether the input or output should be blocked, using a strict few-shot prompt that catches DAN-style role-play, “ignore previous instructions”, system-prompt extraction, and policy-bypass markers.

Architecture

The gateway dispatches the input rail call and the model call in parallel for low time-to-first-token. The wrapper extracts the user message, runs NeMo’s self_check_input flow (which calls a judge LLM through the same TrueFoundry gateway), and returns a verdict. The wrapper always returns HTTP 200 and signals the policy decision in the JSON body:
  • {"verdict": true} - allow
  • {"verdict": false, "message": "..."} - block
On a block, the gateway cancels the in-flight model call. The output rail runs sequentially after the model responds, with the same verdict shape. See Custom guardrail response contract for the underlying protocol.

Prerequisites

Before integrating NeMo Guardrails with TrueFoundry, ensure you have:
  • A TrueFoundry workspace you can deploy services into.
  • A TrueFoundry API key with access to the model you want NeMo’s rail judge to use. openai-main/gpt-4o-mini works well; openai-main/gpt-4o if you want stricter classification.
  • The model FQN you want to protect (e.g. openai-main/gpt-4o-mini).
  • A cluster with a configured base host (visible at Integrations → Clusters → <cluster>).

Integration Steps

1

Clone the wrapper repository

Clone the integration repo and switch to the NeMo folder:
2

Configure environment variables

Copy .env.example to .env and fill in the values. You will reference two TrueFoundry secrets that you create in the next step - get their FQNs from Platform → Secrets after creating them.
.env
Generate WRAPPER_API_KEY with python -c "import secrets; print(secrets.token_urlsafe(32))". The gateway will send this value as Authorization: Bearer … when calling the wrapper.
3

Create two TrueFoundry secrets

Navigate to Platform → Secrets and create a Secret Group named nemo-guardrails-tfy with two secrets:Copy each secret’s FQN and confirm the entries in .env (TFY_API_KEY_SECRET_FQN, WRAPPER_API_KEY_SECRET_FQN) match.
4

Deploy the wrapper service

Install the TrueFoundry CLI, log in, and deploy:
Verify the service is healthy:
5

Register the Custom Guardrail Config in TrueFoundry

Navigate to AI Gateway → Guardrails → + Add New Guardrails Group.
  1. Group name: nemo-self-check
  2. Description (optional): NVIDIA NeMo Guardrails self_check_input / self_check_output
  3. Click + Add Guardrail Config → Custom Guardrail Config twice - once for input, once for output.
Save the group.
The wrapper signals rail decisions via {"verdict": true \| false} on HTTP 200 - real failures (judge LLM unreachable, wrapper crash) come as HTTP 5xx. With Enforce But Ignore On Error, transient outages pass through while real policy decisions still block. Use Enforce for safety-critical rails where fail-closed is the right trade-off. See Custom guardrail response contract and Enforcing Strategy.
TrueFoundry Custom Guardrail configuration form populated for NVIDIA NeMo self_check_input with Custom Bearer Auth, Validate operation, Enforce strategy, Request target, and the wrapper self-check-input URL

NVIDIA NeMo Custom Guardrail configuration in TrueFoundry

6

Apply the guardrail to traffic

There are two ways to route requests through the rails - pick based on whether you want every call to a model protected, or per-call opt-in.
Navigate to AI Gateway → Models → <model> → Guardrails tab → attach the nemo-self-check group → Save. Every caller of this model now passes through the rails.
7

Test end-to-end

Issue two test calls through the gateway - one that should succeed and one that should be blocked:
A successful block returns:
The NeMo refusal text is preserved inside guardrail_checks.input_guardrails[0].data.explanation.

Customizing the Rail Bundle

The v1 bundle ships two rails. To add or change rails, edit files in the wrapper repo and redeploy. After editing, redeploy:
To change the judge LLM (e.g. for stricter classification), update JUDGE_MODEL in .env and redeploy:

Troubleshooting

The wrapper signals rail decisions via {"verdict": false} on HTTP 200. If the gateway returns a normal completion when the wrapper reported a block, your tenant gateway may not be honoring the verdict field. Two ways to confirm:
  1. Check the wrapper pod logs while running the blocking test prompt. If you see rail verdict=block from guardrail._nemo_runner but the gateway still returns a normal completion, the gateway isn’t honoring the verdict.
  2. Call the wrapper directly to bypass the gateway (see the next accordion). If it returns 200 + {"verdict": false}, the wrapper is fine and the gateway is the issue.
Workaround: switch the Custom Guardrail Configs’ Enforcing Strategy to Enforce. This maps the wrapper’s non-success state to a block. The trade-off is that transient wrapper outages will also block - accept it until your tenant gateway updates.
Call /self-check-input and /self-check-output directly to bypass the gateway. The wrapper always returns HTTP 200 with:
  • {"verdict": true, "message": null} → pass
  • {"verdict": false, "message": "<refusal text>"} → block
Non-200 responses indicate real errors (judge LLM unreachable, NeMo init crash, missing bearer token).
The Authorization: Bearer … value the gateway sends doesn’t match the wrapper’s WRAPPER_API_KEY env var. Three places must agree:
  1. The TFY secret wrapper-api-key value.
  2. The wrapper’s WRAPPER_API_KEY env var (resolved from the secret FQN at deploy time).
  3. The Custom Guardrail Config’s Auth Data → Custom Bearer Auth field value.
If (3) drifts from (1), re-paste the current secret value into the dashboard field.
The rail’s verdict is produced by the judge LLM. Check the wrapper’s pod logs:
If you see allow on a prompt that should block:
  • Try a stronger judge model: JUDGE_MODEL=openai-main/gpt-4o.
  • Tighten the prompt in config/prompts.yml - add a few-shot example matching the exact attack pattern that slipped through.
  • Redeploy with python deploy.py --wait. The pod loads RailsConfig once at module import, so YAML changes only take effect after a fresh deploy.

Known Limitations

  • No streaming-aware guardrails. The TrueFoundry custom-guardrail contract is buffered: the gateway holds the full response before calling the output rail. Streaming is supported end-to-end for the caller, but the output rail decision is made after the full response is generated.
  • In-memory state is per-replica. The /debug/loaded-config endpoint reflects the replica that served the curl. With multiple replicas, all should have identical config after a successful deploy.
  • Judge LLM cost. Every guarded request adds one or two LLM calls (one per direction). Watch JUDGE_MODEL token spend in your model usage dashboard. Using a smaller judge model (e.g. gpt-4o-mini or a Haiku-class model) keeps this in check.

Reference