Skip to main content

jamjet-guardrails-nemo

NeMo Guardrails input and output rails backed by jamjet-guardrails, a zero-dependency library of deterministic content checks with published precision and recall.

Two system actions, two Colang 1.0 flows, and one line in your config folder's config.py. Every check that your config names is built when the rails load, so a check that is not installed fails the load rather than the first message. Every call writes an audit record naming which detector decided, at which version, what it decided and where it found something, and never the content.

Install

pip install jamjet-guardrails-nemo

Requires Python 3.10 to 3.13, the range nemoguardrails itself supports.

Wire it up

Copy the two shipped flow files into your rails config folder:

cp "$(python -c 'import jamjet_guardrails_nemo as m; print(m.flows_path())')"/*.co my_config/

my_config/config.py:

from jamjet_guardrails_nemo import init  # noqa: F401

my_config/config.yml:

models:
  - type: main
    engine: openai
    model: gpt-4o-mini

rails:
  input:
    flows: [jamjet guardrails check input]
  output:
    flows: [jamjet guardrails check output]

custom_data:
  jamjet_guardrails:
    input: [injection-structural, secrets]
    output: [pii, secrets]
    options:
      secrets: {on_match: deny}

Your config also needs a refusal message, which is the same one NeMo's own rails use. Put it in any .co file in the folder:

define bot refuse to respond
  "I am sorry, I cannot respond to that."

It is deliberately not shipped inside the flow files, so a config that already defines one keeps its own wording.

Which checks you can name

input and output take any check the installed jamjet-guardrails registers. That list grows with the core library, so read it from the library rather than from this page:

python -c "from jamjet_guardrails.detectors import AVAILABLE; print(sorted(AVAILABLE))"

The configuration above is an illustration, not the full set. options is per check and is passed to that check's constructor, so secrets: {on_match: deny} turns the secrets check from a redaction into a refusal. A check that takes no options needs no entry.

Configuration lives under custom_data

RailsConfig is a pydantic model with the default extra="ignore" behaviour. Measured on nemoguardrails 0.24.0: a top-level jamjet_guardrails: key in config.yml is parsed, discarded and unreachable from the loaded config, with no error anywhere. custom_data is NeMo's own field for configuration it does not model itself, so that is where the block goes. A config that puts it at the top level instead fails the load with a message showing the right shape, because a guardrail that silently did not run is the failure this library exists to prevent.

What the rails do

Chain decision Action returns What happens
allow true the turn continues, message untouched
redact true the message is replaced with the redacted one, then the turn continues
deny false the flow runs bot refuse to respond and stops
check raised false same as deny; the audit record names the failure's type

On a redact, the rewritten string is what the rest of the turn sees: the model is prompted with it on input, and it is what generate returns on output. On a deny the chain's merged content is never written back. GuardrailChain's own docstring is explicit that on a deny that string exists for the audit record and is not safe to send.

Every check in a direction inspects the same content. No check ever sees a string another check has already rewritten, and all the redactions are merged and applied in one pass. That is a leak fix rather than a simplification: rewriting in sequence lets one detector's placeholder split a credential so that the next detector matches only a stump and reports success over a tail that is still there. The core library's GuardrailChain documents the measured case.

The audit record

Every call writes a JSON record to the rail context under jamjet_guardrails. This is the record a real run produces for mail alice@example.com please checked with pii on the output rail:

{
  "decision": "redact",
  "direction": "output",
  "saw": "e0a1e7a20fda68f59025ebc1bca79c3aa6bb6e202edf48828b5db5b08fdc9dfe",
  "verdicts": [
    {
      "decision": "redact",
      "detector": "pii",
      "kind": "constraint",
      "spans": [[5, 22]],
      "types": ["EMAIL"],
      "version": "0.1.0"
    }
  ]
}

saw is the SHA-256 of exactly the string that was inspected. types and spans are parallel by index. An error key appears where a check failed, and carries the exception's type name only, never its message: an exception message routinely quotes the value that caused it, and that value is the content.

The record never carries the content, the rewritten content, or any substring of either. Read it with jamjet_guardrails_nemo.parse_audit_record.

The context key holds the record of the most recent call, so on a turn that runs both rails the output record replaces the input one. Both are retained in NeMo's own event log, and each record names its own direction.

What this adapter does not do yet

Colang 2.0 flows. The shipped flows are Colang 1.0.

Licence

Apache-2.0.

The framework this adapter installs makes network calls

jamjet-guardrails says on its own front page: no dependencies, no network calls, no model downloads. That is true of the core and it stops being true of your environment the moment you install this adapter, so it is said here rather than left for you to find.

Measured on nemoguardrails 0.24.0: it posts usage statistics to https://events.telemetry.data.nvidia.com/v1.1/events/json, with a heartbeat, and reads the destination from NEMO_GUARDRAILS_USAGE_STATS_SERVER. It is on by default.

It turns itself off under several conditions, and two of them are yours to set:

export NEMO_GUARDRAILS_NO_USAGE_STATS=1   # this framework only
export DO_NOT_TRACK=1                     # the cross-vendor convention

It also suppresses itself when CI is truthy, when PYTEST_CURRENT_TEST is set, when pytest is in sys.modules, and when a do-not-track file exists. That is why this package's own test suite never reaches the network and why a green CI run is not evidence about your deployment.

Nothing in this adapter sends anything anywhere. The audit record it writes goes into the rail context and stays in your process.

Metadata

Release files for jamjet-guardrails-nemo 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jamjet-guardrails-nemo 0.1.0
File Size Uploaded
jamjet_guardrails_nemo-0.1.0.tar.gz 27.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jamjet-guardrails-nemo 0.1.0
File Interpreter ABI Platform
jamjet_guardrails_nemo-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 47.7 kB

Release files / jamjet_guardrails_nemo-0.1.0.tar.gz

Download URL jamjet_guardrails_nemo-0.1.0.tar.gz
Size 27.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a94230fccb02334c21e9af96e42a5e35f6c3a6f2adb9fd4c605981cfe6ee62d6
BLAKE2b-256 checksum
How to use checksums
141d668e82e78e5d474461165ffa1418fd5a1eb8f0a24e24c623c1d89307f402
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / jamjet_guardrails_nemo-0.1.0-py3-none-any.whl

Download URL jamjet_guardrails_nemo-0.1.0-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e4b9353c58ac20a727938fc834663ac41e917249eb9395f0c6a1fd0dfa4da2c0
BLAKE2b-256 checksum
How to use checksums
fbdd0399c180c0ca17c70d01089c63ab5fe3b5324986c1b9f6b3aa51edad8c0a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page