Skip to content

41 · Rules without Colang: 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 every check that reads a rulebook reads a sheet exactly as it reads Colang. This chapter is the sheet, construct by construct, and what happens when a sheet says something the compiler cannot state exactly.

A sheet

# The shop's rules, as a sheet a person can read aloud.
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

One rule per action. Each rule names its action, a tool of your catalogue, and says one or more of:

Key What it says The Colang it equals
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 condition becomes a context the tool check computes from the checked 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 not in the rulebook: a confirmation the catalogue declares, which the tool check enforces
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 catalogue's 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, in the words every condition of an agent.yaml uses: a value, a list, or what an earlier tool returned the tool's own conditions, added to any the catalogue declares; the tool check decides them, and a value it cannot read refuses the call

A sheet's confirmations, order rules and checks are not in the rulebook, because the rulebook decides whether an action may happen at all, and those decide when and how. They are returned as an overlay on your catalogue, and the tool check enforces them like any declaration (chapter 32).

Compiling

$ stalwart rules compile rules.yaml --out-dir rules     # compiled; nothing is kept

The service compiles the sheet into the Colang policy it equals, and the Colang front end every policy goes through emits the rulebook from that. A sheet and the Colang it equals are therefore one gate, and every verdict over one is a verdict over the other. --out-dir writes what the compiler made: rule_sheet.co, the Colang; rulebook.ir.json, the rulebook; and catalogue_overlay.json, the confirmations, order and checks the sheet sets. That folder is what a guardrail or a gateway reads as its rules.

Nothing of the sheet is kept on the service. Keep it as a file beside your agent and name it, or the folder compiled from it, as the agent's rulebook: (chapter 45): the agent compiles a sheet once when it starts, lays its confirmations, order and checks over your catalogue, and every tool check carries them from then on.

The console's Rules page is a form over the same sheet: it compiles on the page and saves nothing (chapter 5). Over HTTP, POST /v1/rule-sheets/compile compiles, and keeps nothing. It needs the catalogue grant.

The lints

The sheet is checked against your catalogue where your catalogue is -- by the guardrail and the gateway as they read their rules, and by stalwart verify -- and each problem is a lint, not a failure:

  • rule_action_unknown: the sheet has a rule for an action the catalogue does not hold;
  • write_ungoverned: a write the catalogue holds that the sheet never names, so a new write is never left ungoverned by omission.

What every mode reads

The rulebook a sheet compiles to is what the tool check enforces at run time, what stalwart verify and the bug hunter scan, and what a guardrail job verifies when you send the compiled rulebook as rulebook_ir. Each answers over it exactly as over a rulebook from Colang.

Refused, never approximated: rule_sheet_unsupported

A sheet the compiler cannot state exactly is refused, naming its line and the reason, and nothing is written. The reasons are concrete:

  • a key that is not one of the nine above;
  • a second rule for the same action: how two rules would combine is never guessed;
  • never with anything beside it: an action that never runs has no other condition;
  • when on a rule that requires nothing: the conditions say when the requirements apply;
  • 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.
$ stalwart rules compile unsupported.yaml
unsupported.yaml:4: rule_sheet_unsupported: line 4: `refund_card` has a rule already: one rule per action, so how two would combine is never guessed. The sheet was not compiled; nothing was changed.
$ echo $?
1

A sheet is refused rather than approximated because an approximation would be a rule you did not write, enforced as though you had. stalwart rules compile exits 1 on a refusal, 0 on a sheet that compiled, 2 where the file could not be read and 3 where the service could not be reached.

From a drafted rule to a sheet

A rule Guardrail Writing drafted and verified is Colang. Where its rule is one of the shapes above, it can be restated as a sheet a reviewer reads more easily, and the two compile to one gate: compile both and compare the rulebooks, or verify the same obligation over each.

The limits

  • A sheet states what its constructs express and no more. A rule that needs a construct the sheet does not have is written in Colang.
  • The contexts a sheet requires are set by your systems at run time; the sheet proves the action waits for them, not that they are set truthfully.
  • Lints are advice. A sheet with lints still compiles; reading them is how a new write is not left without a rule.