The rule sheet
A rule sheet states the rules over your tools as YAML a person can read aloud: a refund over 200 needs a supervisor's approval; closing an account waits for the customer to confirm; nobody deletes a customer. It compiles to the same rulebook a Colang policy becomes, so the guardrail reads a sheet exactly as it reads Colang.
A sheet
rules:
- action: refund_card
requires: [supervisor_approved]
when: { amount_over: 200 }
- action: charge_card
requires_confirmation: true
- action: send_receipt
after: [charge_card]
at_most: 1
Every key
One rule per action. Each rule names its action, one of your tools, and says one or more of:
| Key | What it says | What it compiles to |
|---|---|---|
requires: [a, b] |
the action runs only where every named context holds | a deny-by-default flow for the action, guarded on $a and $b |
when: {amount_over: 200} |
when the requirements apply, as conditions on the call's own arguments: <argument>_over, _under, _at_least, _at_most or _is |
the guard holds only where the condition does; the tool check computes the condition from the call's arguments, so the host cannot set it |
never: true |
the action never runs | a flow that refuses it unconditionally |
requires_confirmation: true |
a person confirms each call | a confirmation the catalogue declares, enforced by the tool check |
confirmation: "…" |
the same, with the words the person is asked | as above, with the wording |
after: [tool] |
the action runs only after each named tool, in the same session | the order rule, enforced by the tool check |
not_after: [tool] |
the action never runs after a named tool | as above |
at_most: 3 |
the action runs at most that many times in a session | as above |
check: [{field: quantity, at_most: {from: check_stock.in_stock}}] |
conditions on the call, all of which must hold: a value, a list, or what an earlier tool returned | the tool's own conditions; a value the tool check cannot read refuses the call |
Confirmations, order and checks are laid over your tools; the rulebook decides whether an action may happen at all.
In the guardrail, the first stop is named your_rules (the rulebook, conditions, limits and spend), order or, for
a confirmation, the call waits for the person.
Compiling it
The service compiles a sheet; the decisions are then made on your machine.
$ stalwart rules compile rules.yaml --out-dir compiled
writes rulebook.ir.json, catalogue_overlay.json and rule_sheet.co (the Colang it equals) to compiled/. Pass
the folder as Guardrail(..., rules="compiled"). A sheet's path also works (rules="rules.yaml"): it is compiled
when the guardrail is made, with QLS_API_KEY.
In stalwart mcp: compile_rules("rules.yaml") writes the same folder, and the other tools read it.
The lints
The sheet is checked against your tools, and each problem is a lint, not a failure:
rule_action_unknown: a rule for a tool you do not have;write_ungoverned: a write the sheet never names, so a new write is never left without a rule by omission.
lint_rules("rules.yaml") in stalwart mcp lists them against the tools the guardrail checks.
What is refused
A sheet the compiler cannot state exactly is refused, naming its line, and nothing is written:
- a key that is not one of those above;
- a second rule for the same action: how two would combine is never guessed;
neverwith anything beside it;whenon a rule that requires nothing;- a condition with no comparison the compiler can state, or a number compared with something that is not one;
- YAML outside the sheet's subset: tabs, a block list, a value on the line below its key, a second document.
A sheet is refused rather than approximated: an approximation would be a rule you did not write, enforced as though you had.
The limits
- A sheet states what its keys express and no more; a rule that needs more is written in Colang.
- The contexts a sheet
requiresare set by your systems at run time; the guardrail makes the action wait for them, not that they are set truthfully. - Lints are advice. Reading them is how a new write is not left without a rule.
- Your rules are only as complete as you wrote them:
huntlooks for a way through them.