Skip to content
Talk to our solutions team

Rules

The Rules block runs decision logic that lives outside your application code: you write rules in GRL, hand the engine facts, and read back what the rules decided. Two things run them:

  • rules.svc, the service. A product keeps its rules in its own rules/ folder; the service loads them for each tenant, checks every rule when it loads, and answers calls that name a scope. A static scope can read the product’s data and propose writes back.
  • kis rules, the command line, which runs rule files over input files. It also reads documents: the spatial document model below is on the CLI only today.

A rule is a condition and an action:

rule ApproveSmallInvoice "auto-approve small invoices" salience 10 {
when
in.Double("invoice.total", 0.0) < 5000.0
then
out.Set("approved", true);
}
facts
{ "invoice": { "total": 1200.0 } }
out
{ "approved": true }

Execution is forward chaining, not a script. Every cycle the engine evaluates the when of every rule that has not fired yet and fires exactly one rule: the runnable rule with the highest salience. A rule that fires is retracted for the rest of the execution, so each rule fires at most once unless it calls agenda.Repeat(). The execution ends when nothing is runnable, a rule calls Complete(), or it runs out of time or cycles. A later rule sees what earlier rules wrote.

Facts go in as a map; read them with in, by dotted path, with a default for when the fact is absent: in.Str("invoice.currency", "EUR"). The engine binds these names itself:

NameWhat it is
inReads the facts: in.Has, in.Str, in.Int, in.Double, in.Bool, in.Date, in.Map, in.Rows, by path
outThe result: out.Set(k, v), and typed reads of what was set
findingsSeverity-graded validation results: findings.Error/Warn/Info/Critical(ruleID, category, message)
auditThe decision trail: audit.Log(ruleID, msg)
actProposed writes to product data: act
loglog.Debug/Info/Warn/Error
strings, num, math, time, date, map, array, to, util, vocab, …Helpers

rules.svc refuses a fact named like any of them; under kis rules a fact with such a name is lost or breaks the helper. See the rules service.

A call to rules.svc names a scope: a top folder of the product’s rules/, or a static scope of rules/rules.yaml. A static scope can bound its executions, declare the facts it takes, read knowledge and records from the product’s data as the caller, and declare the writes its rules may propose. Then a scope can decide over records (evaluate), over every record it matches (sweeps), or whenever a record changes (events). See Scopes and Rules over data.

The block also carries a spatial document model: OCR ingest, word merging, line and block reconstruction, reading order, tables, fields, checkboxes, fuzzy matching and confidence scoring. Rules reach a document through the bbox namespace, so a rule can ask what is written below this label rather than parsing text.

Documents run on the CLI: kis rules --bbox <name>=<path> binds an analysed document into the execution, and rules read it through bbox.Doc(). rules.svc serves no documents today. See Documents.

The rule and document commands (kis rules, kis bbox) run a separately installed plugin, kis-rules. When it is not installed you get Error: 'rules' is not installed. and nothing runs. See the CLI.

ConcernPage
One rule set, run end to endQuickstart
Rules, salience, chainingWriting rules
GRL syntax, operators, fact accessThe rule language
Everything callable from a ruleFunctions
Rule shapes to copy, and pitfallsPatterns
rules/rules.yamlScopes
Reading and writing product dataRules over data
Proposing writesact
Boxes, words, blocks, lines, reading orderThe document model
Running rules and documents locallyThe CLI
Routes, requests, responsesThe rules service
The rules: block, tenants, the system userConfiguration
Who may do whatAccess
Symptoms and fixesTroubleshooting
Error codes and messagesErrors

The rule language is GRL, from the open-source Grule rule engine. We run a heavily modified and wrapped build of it. The language itself is left largely intact, a rule you have written against upstream GRL will read as familiar, while the enterprise work sits in the layers around it: the namespaces a rule may call, the spatial document surface, tenancy and rule delivery, per-execution isolation, provenance and the audit trail, and the error and termination behaviour described above. Where this documentation and the upstream README disagree, this documentation describes what actually runs.