Skip to content

Use a built-in check

Kindgi has seven built-in checks for common rules: words an answer must or mustn't contain, a pattern it must match, citations, and which tools a turn may call, how many and in what order. A guardrail can name one instead of shipping a check you write yourself.

In a TypeScript pack, the guardrail names the built-in as its check, gives its config, and ships no check implementation:

guardrails/no-guarantees/index.ts
export default {
id: 'my-pack.no-guarantees',
name: 'Never promise a guarantee',
kind: 'zero-llm',
check: 'forbidden-substring',
config: { patterns: ['guaranteed', 'we promise'] },
action: { 'on-violation': 'halt' },
severity: 'error',
};

Put it on an agent by its id, as with any guardrail (Put it on an agent). With halt, an answer containing "guaranteed" stops the turn (A halted turn). The failure gives the check's reason. For a must-cite guardrail on an answer without a citation:

Error [guardrail-violation]: Turn blocked by guardrail 'acme.cite-or-halt': expected >= 1 citations, found 0

A Python, Java or Scala pack can't name a built-in yet: a guardrail there is always defined with its own check (Python's @guardrail decorates a check function). Write the rule as your own check; the table below says what each built-in checks.

A tool list holds tool ids, as <pack>.<tool>. A setting in bold is required.

Check Fails when config
must-cite the answer is empty, or has fewer than minCitations matches of sourcePattern minCitations: a whole number, 1 or more (1 by default); sourcePattern: a regular expression (by default, citations in square brackets, such as [ord_1003])
never-call-tool the turn called any tool in tools tools: a list of one or more tool ids
max-tool-calls the turn made more than max tool calls max: a whole number, 0 or more (10 by default)
output-matches the answer doesn't match pattern, or, with negate: true, it does pattern: a regular expression; flags: regular-expression flags (d, g, i, m, s, u, v, y), such as "i"; negate: true or false
tool-order the tools in sequence weren't called in that order (other calls may come between) sequence: a list of one or more tool ids
required-substring the answer is empty, or lacks any of patterns patterns: a list of one or more plain-text strings; caseSensitive (false by default)
forbidden-substring the answer contains any of patterns patterns: a list of one or more plain-text strings; caseSensitive (false by default)

A config the check doesn't take is refused: a required setting left out, a setting of the wrong type, one the check doesn't know, or a regular expression that doesn't compile. Registering such a guardrail answers 422 guardrail-config-invalid, with each problem in details.issues, and deploying a pack with one fails with deployment-validation-failed. If one reaches a turn anyway, its check can't run, so with halt the turn stops (When the check can't run).

The built-in ids are reserved. A pack that ships its own check under one, such as a defineCheck({ id: 'must-cite', … }), is refused when you build it (reserved-check-id; in Python, DefinitionError). Give your check a name of its own, such as my-pack.checks.must-cite, or, to use the built-in, name it and drop your implementation.

A pack built with a CLI from before 0.1.5 wasn't checked for this, and a current CLI marks a guardrail that only names a built-in. So from runtime 0.1.6, a guardrail that names a built-in, comes with its pack's code, and lacks that mark gets one warning in the runtime's log each time the runtime loads the guardrail. The built-in runs either way. If the guardrail only names the built-in, rebuild the pack with a current CLI and the warning goes. If its module is your own check, rename that check as above: the built-in has been running in its place.