Configure a guardrail
A check's settings (a limit, a list of words, a tool's id) don't belong in
its code. The guardrail declares them as config, and the check runs with
them. The answer-length guardrail has one setting,
maxChars:
// in guardrails/answer-length/index.tsexport const check = defineCheck({ id: 'my-pack.checks.answer-length', kind: 'zero-llm', configSchema: z.object({ maxChars: z.number().int().positive().default(500) }), evaluate: async (config, trace) => { // config.maxChars: 60 here, or 500 when the declaration gives none // … },});
export default { id: 'my-pack.answer-length', // … check, config: { maxChars: 60 }, // …};configSchema describes the settings; config in the declaration gives
their values. The check's evaluate gets those values, typed from the
schema.
# in guardrails/answer_length.pyclass Config(BaseModel): max_chars: int = Field(500, alias="maxChars", gt=0)
@guardrail( id="my-pack.answer-length", # … config={"maxChars": 60},)def answer_length(config: Config, trace: RunTrace) -> CheckResult: ...The type of the check's first parameter describes the settings; config=
gives their values, keyed by their wire names, the aliases: maxChars, not
max_chars.
Change a setting
Section titled “Change a setting”Edit the value and save; the next turn uses it. With maxChars: 100, the
dev-echo answer from Write a guardrail
passes:
kindgi runs start --agent=my-pack.echo-agent --input='{"userMessage":"hi"}' "status": "completed", … "violations": [],The registered guardrail shows the values it runs with:
kindgi guardrails get my-pack.answer-length "config": { "maxChars": 100 },What the check receives
Section titled “What the check receives”The check gets config resolved by its schema, in both SDKs:
- Defaults are filled in. A guardrail without
configruns with the schema's defaults; here, a limit of 500. - A value that doesn't fit is refused before any turn runs, and the message names the setting.
Zod's .default() and a JSON Schema's default both apply. When the pack is
indexed, each guardrail's config is checked against its configSchema, so
kindgi dev reports the file and kindgi build refuses the pack. With
config: { maxChars: -5 }:
guardrails/answer-length/index.ts: guardrail my-pack.answer-length's config doesn't fit its configSchema at /maxChars: must be > 0A setting the schema requires, with no default, must be in config:
guardrails/answer-length/index.ts: guardrail my-pack.answer-length's config doesn't fit its configSchema: must have required property 'maxChars'The check gets config parsed into its type:
-
Defaults are filled in. Give every field a default: a required field with no value isn't caught when the pack is indexed, and fails every turn the guardrail checks, whatever its action (
input-validation-failed: Check "my-pack.req-cfg" config failed validation). -
Values are checked where they're declared. A value that doesn't fit is a
DefinitionError, andpython -m kindgi.pack index(andkindgi dev) reports the file:Guardrail "my-pack.answer-length": config does not fit its type: 1 validation error for ConfigmaxCharsInput should be greater than 0 [type=greater_than, input_value=-5, input_type=int] -
A key that isn't a wire name is ignored.
config={"max_chars": 60}isn't an error: the field keeps its default.