# Guardrail

> An assertion about agent behavior.

`@kindgi/specs/guardrail.schema.json`, schema version 1.1.0.

An assertion about agent behavior. Checked at runtime, where in 0.1 only `halt` stops the turn and every other action is recorded, AND in CI (blocks builds). Same definition, two enforcement paths — no drift between what tests check and what prod enforces. Zero-LLM checks are default (fast, deterministic); LLM-judge scorers are an opt-in class with explicit cost declaration. Schema-version 1.1.0 matches the `Guardrail` type: `check` is required, a `retry` object, when given, needs `maxAttempts`, `kind` and `on-violation` accept any non-empty string (the built-ins are listed as `examples`), and `sandbox` / `limits` / `network` / `needsSpec` are allowed.

- `id` (string, required): Unique guardrail identifier.

- `name` (string): Human-readable name.

- `description` (string): What this guardrail guarantees, and what happens if violated.

- `kind` (string, required): How the guardrail is checked. Open string: the engine dispatches it to the execution strategy registered for that kind, and `defineGuardrail` requires a registered check of the same kind. Built-in kinds: 'zero-llm' = pure function over run trace (default, fast, deterministic). 'llm-judge' = uses a model to score (opt-in, costs money). 'external' = evaluated outside the engine by a caller-registered strategy (the built-in 'external' strategy returns an error). Adapters can register strategies for their own kinds.

- `check` (string, required): Id of the check in the CheckRegistry. For zero-llm: a built-in check ('must-cite', 'never-call-tool', 'max-tool-calls', 'output-matches', 'tool-order', 'required-substring', 'forbidden-substring') or a custom check id. For llm-judge: the id of a registered check of kind 'llm-judge' (the judge is configured by config and judgeCapabilities). For external and adapter kinds: an id the kind's strategy understands. Required since schema-version 1.1.0 (`defineGuardrail` already failed without a registered check).

- `config` (map of any): Check-specific configuration. Interpreted by the check implementation.

- `configSchema` (object): JSON Schema (Draft 2020-12) of the check's config, for a check that is pack code: the pack index's `configSchema`, which a deployment keeps on the guardrails it registers. The runtime checks a guardrail's `config` against it at registration, for any guardrail naming that check, and the pack service checks it on every call. Optional; a runtime-declaration field like `codeArtifactRef`.

- `action` ([Action](https://docs.kindgi.com/v0.1.10/reference/schemas/guardrail.md#action), required)

- `severity` (`"info"` | `"warn"` | `"error"` | `"critical"`)

- `scope` ([Scope](https://docs.kindgi.com/v0.1.10/reference/schemas/guardrail.md#scope)): When this guardrail applies: 'always' (every run), 'ci-only' (blocks CI, not runtime), 'runtime-only' (runtime enforcement, not CI), or a per-agent/per-flow selector.

- `budget` (object): For llm-judge guardrails: cost budget per invocation. Declarative — not enforced by the runtime.

  - `maxCostUsd` (number)
  - `maxLatencyMs` (integer)

- `sandbox` (`"none"` | `"context-isolated"` | `"strict"`): Isolation posture the runtime enforces around the check's handler. Same values as a tool's `sandbox`. Added in schema-version 1.1.0.

- `limits` (object): Sandbox-enforced resource caps while the check runs. Same shape as a tool's `limits`. Added in schema-version 1.1.0.

  - `memMB` (integer, required)
  - `cpuMs` (integer, required)

- `network` (one of the objects below): Network egress policy the sandbox honors while the check runs. Discriminated on `kind`; same shape as a tool's `network`. Added in schema-version 1.1.0.

  - an object
    - `kind` (`"none"` | `"unrestricted"`, required)

  - an object

    - `kind` (`"allowlist"`, required)
    - `hosts` (array of string, required)

- `needsSpec` (object): Typed discriminated needs of the check (env / secrets / config / capabilities / bindings). Same shape as a tool's `needsSpec`. Added in schema-version 1.1.0.

  - `env` (map of object)
  - `secrets` (map of object)
  - `config` (map of object)
  - `capabilities` (array of string)
  - `bindings` (array of string)

- `codeArtifactRef` (one of the objects below): Handler-artifact pointer for the guardrail's check implementation. Discriminated on `kind`: `oci` is the deploy-pipeline shape (image + module path + artifactVersion); `filesystem` is the local-development shape — absolute host path at the check module. Production servers SHOULD reject `filesystem`.

  - an object

    - `kind` (`"oci"`, required)
    - `imageRef` (string, required)
    - `modulePath` (string, required)
    - `artifactVersion` (string, required)

  - an object

    - `kind` (`"filesystem"`, required)
    - `modulePath` (string, required)

- `checkBuiltIn` (`true`): Set by the CLI on a guardrail that names a built-in check (`check`) without shipping a check of its own: its `codeArtifactRef` is only the file it's declared in. A runtime warns about a guardrail naming a built-in, with a code artifact and without this marker (built by an older CLI): its pack may ship its own check under the built-in's id, which the built-in replaces.

- `judgeCapabilities` (map of any): For llm-judge guardrails: capability declaration for the judge model. Routed through `@kindgi/capabilities` over the providers bound for evaluation; when the caller passes a tenant policy (an agent turn passes its own), the judge is routed under it. BYO judges supported.

## Definitions

### Action

- `on-violation` (string, required): What a failed check does to the agent turn. Open string: any non-empty name is accepted here. In 0.1 the runtime acts only on 'halt': the turn fails with `guardrail-violation` and its response is not stored. Any other name is recorded as a violation, as 'log-only' is, and the turn completes. Built-in actions: 'halt' = fail the turn. 'log-only' = record, don't block. 'retry', 'escalate' and 'compensate' are recorded like 'log-only' in 0.1: nothing runs the turn again, escalates or calls a compensating tool.
- `retry` (object): For on-violation = 'retry': the attempts it asks for. In 0.1 nothing acts on it: there's no second attempt.
  - `maxAttempts` (integer, required)
- `escalateTo` (string): For on-violation = 'escalate': a reviewer role or queue id. In 0.1 nothing escalates.
- `compensateWith` (string): For on-violation = 'compensate': the compensating tool's id. In 0.1 that tool isn't called.

### Scope

- `when` (`"always"` | `"ci-only"` | `"runtime-only"`)
- `agents` (array of string): Agent ids this guardrail applies to. Empty = all agents.
- `flows` (array of string): Flow ids this guardrail applies to. Empty = all flows.
- `tenants` (array of string): Tenant ids this guardrail applies to. Empty = all tenants.
