Saphan StudioDocs
Security/Guardrails

Configuring

Turning judging on, pinning a plugin, and the settings that choose what is judged.

Recording needs no configuration: it is on by default. Everything on this page is about judging.

The plugin

A plugin is any executable that speaks the guardrail-v1 protocol: it reads one JSON line on its standard input and answers with one JSON line on its standard output — a decision of allow, block or error. A block or an error carries a rule id and a reason code. One plugin process serves one proxy, and decisions are taken one at a time.

A plugin is pinned, not named:

  • guardrail.plugin_digest is the SHA-256 of the plugin's manifest;
  • the manifest's own artifact_sha256 pins the executable, which is re-checked before every run.

A change to either is a different plugin.

The shipped adapter, saphan-guard-adapter, forwards the text to an NVIDIA NeMo Guardrails service that you run. The rules are whatever that service is configured with.

Turning judging on

saphan config set guardrail.plugin_manifest /absolute/path/manifest.json
saphan config set guardrail.plugin_artifact /absolute/path/plugin
saphan config set guardrail.plugin_digest <64 lowercase hex: the manifest's SHA-256>
saphan config set guardrail.backends claude-code,codex
saphan config set guardrail.enabled true

guardrail.enabled can be turned on only when the three plugin settings are present and at least one backend is listed. Paths must be absolute. Check the result with:

saphan guardrail config --backend claude-code

It prints the resolved settings, where each came from, and whether each stage enforces or observes.

The settings

settingmeaning
guardrail.enabledtrue to judge. false (the default) records but judges nothing
guardrail.recordrecord every run; true by default. A single run can opt out with saphan run --no-recording
guardrail.backendscomma-separated backends whose model conversations are judged. Empty means none
guardrail.seatslimit judging of model conversations to these seats. Empty means every seat of a listed backend
guardrail.plugin_manifest, guardrail.plugin_artifact, guardrail.plugin_digestthe pinned plugin
guardrail.request_mode, guardrail.response_mode, guardrail.handoff_mode, guardrail.ingress_modeobserve or enforce, per stage. observe is the default
guardrail.enforce_actsthe file holding the signed acts that arm enforcement — see Observe and enforce
guardrail.listena fixed local address (127.0.0.1:<port>) for the proxy, needed for backends that cannot be told an address per run
guardrail.upstream.<backend>, guardrail.codec.<backend>override the model endpoint and wire format for one backend

guardrail.backends and guardrail.seats apply to the model conversation only. The spawn.handoff and bridge.ingress stages are judged whenever judging is enabled and a plugin is pinned, for every backend and seat.

⚠ Every guardrail setting is printed by saphan config show. Never put a secret in one.

⚠ The bridge loads its guardrail settings once per gateway process. Restart the gateway after changing the plugin pin, the acts file or the bridge.ingress mode.

Testing a plugin before you rely on it

saphan guardrail replay --plugin-manifest <path> --plugin-artifact <path> --plugin-digest <sha256> --fixture-dir <path>
saphan guardrail stats --audit <audit file>

replay runs the false-positive cases the plugin's manifest names (false_positive_fixture), read from --fixture-dir, against the real plugin; it takes the pins from its flags, not from the configuration. stats summarises an audit file: decisions per stage and plugin, and latency. An empty file is reported as unmeasured, never as a clean result.

On this page