Skip to content
Talk to our solutions team

`in`, reading facts

in reads the facts handed to the execution. Every top-level key of the input is also bound under its own name, so order["total"] works directly. in is what you use when you want a read that cannot raise, a default, or a dotted path into nested objects.

That distinction is why the namespace exists. A bare fact name the caller did not send aborts the whole execution, even in the when of a rule that has nothing to do with it (non existent key optional_field), and dot access on a map fact (order.total) aborts too. Every function here returns a default instead.

The surface is twelve functions:

FunctionReturns
in.Has(path)Whether anything is at path
in.Eq(path, value) · in.EqInt · in.EqNumEquality, false when absent
in.Str · in.Int · in.Double · in.BoolThe value, or your default
in.Date(path)A date, or the zero date
in.Value(path)The typed value, or Null
in.Map(path) · in.Rows(path)A nested object, or table rows

Reports whether anything is present at path.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
rule RequireApplication "nothing to do without an application" salience 100 {
when
!in.Has("application")
then
findings.Critical("RequireApplication", "input", "No application supplied");
out.Set("status", "incomplete");
Complete();
}
facts
{ "applicant": { "name": "Ana Silva" } }
out
{ "status": "incomplete" }

Reports whether the fact at path equals value. False when absent, which is the point: it cannot raise, so it needs no guard.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
valuestringThe string to compare against
rule OpenOrdersOnly "only process open orders" {
when
in.Eq("order.status", "open")
then
out.Set("processed", true);
}
facts
{ "order": { "id": "SO-1042", "status": "open" } }
out
{ "processed": true }

Written as order["status"] == "open", the same test raises when order was not sent. in.Eq is the form that survives incomplete input, which on extracted documents is most input.

Reports whether the integer fact at path equals value. False when absent.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
valueint64The whole number to compare against

Prefer this over in.EqNum for anything conceptually a whole number: a page number, a count, a term in months, so the literal at the call site is a bare 1 rather than 1.0.

rule FirstPageOnly "classification runs on page one" {
when
in.EqInt("page", 1)
then
out.Set("classified", true);
}
facts
{ "page": 1 }
out
{ "classified": true }

Reports whether the numeric fact at path equals value. False when absent.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
valuefloat64The number to compare against
rule ExactRate "the rate is exactly the promotional one" {
when
in.EqNum("loan.rate", 6.125)
then
out.Set("promotional", true);
}
facts
{ "loan": { "rate": 6.125 } }
out
{ "promotional": true }

Each takes a default and returns it when the path is absent, at any level. None of them raise.

The default covers absence only. A value that is present but does not convert reads as the type’s zero: "n/a" through in.Double is 0.0, not your default. For text that may not be a number, read it with in.Str and convert with to.NumOr.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
defstringReturned when absent

A number or date at the path comes back as text.

rule DefaultChannel "unstated channel is 'branch'" {
when
in.Has("application")
then
out.Set("channel", in.Str("application.channel", "branch"));
}
facts
{ "application": { "id": "A-2291" } }
out
{ "channel": "branch" }
ParameterTypeMeaning
pathstringThe fact name, or a dotted path
defint64Returned when absent
ParameterTypeMeaning
pathstringThe fact name, or a dotted path
deffloat64Returned when absent

The same decimal-point rule applies to the default: write 0.0, not 0. in.Double("x", 0) loads cleanly and then aborts the execution when it runs.

rule SeniorApproval "large invoices need a senior approver" {
when
in.Double("invoice.total", 0.0) > 1000.0
then
out.Set("approver", "senior");
}
facts
{ "invoice": { "number": "INV-88", "total": 1500.0 } }
out
{ "approver": "senior" }
ParameterTypeMeaning
pathstringThe fact name, or a dotted path
defboolReturned when absent

Text reads leniently: true, yes, y, 1, checked and x are true, in any case, and any other text is false. That is how the Yes/No encoding document extraction produces lands correctly.

Returns the date at path, or the zero date.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path

A text fact parses as YYYY-MM-DD, MM/DD/YYYY, M/D/YYYY, MM-DD-YYYY or YYYY/MM/DD. There is no sentinel to compare against: an absent or unparseable date is IsZero(), not the literal 0001-01-01 you might be tempted to test for.

A Date offers three methods:

MethodReturns
IsZero()Whether the date is absent or unparseable. The test to use
String()The canonical YYYY-MM-DD rendering
Time()The underlying time, for the time namespace’s arithmetic and comparisons

Time() is the bridge: time.DaysBetween and time.IsBefore take times, so a date read from a fact reaches them through it.

rule ApplicationAge "applications older than 90 days are stale" {
when
!in.Date("application.date").IsZero() &&
time.DaysBetween(in.Date("application.date").Time(), time.Now()) > 90
then
findings.Warn("ApplicationAge", "freshness", "Application is more than 90 days old");
}

out.Set writes a Date in YYYY-MM-DD form:

rule ApplicationDated "the application carries a readable date" {
when
!in.Date("application.date").IsZero()
then
out.Set("applicationDate", in.Date("application.date"));
}
facts
{ "application": { "date": "05/01/2026" } }
out
{ "applicationDate": "2026-05-01" }

Returns the typed value at path, or Null: the general form. Use it when you want to ask the value about itself rather than convert it immediately.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path

This is the engine’s own Value, distinct from the document read Value that bbox.Doc().Right(...) returns. Both in.Value and out.Value produce it.

MethodReturns
IsNull()Whether the value is absent
Kind()The value’s type, for diagnostics
Str()Text. Numbers and dates in canonical form; a null is ""
Int()An integer, parsing or truncating as needed
Double()A float
Bool()A boolean, read leniently so the Yes/No encoding used across document extraction lands correctly
Date()A Date, parsing a string if needed. A non-date returns the zero date
Map()The nested object, or nil
Rows()The table rows, or nil
Any()The underlying value
Equal(other)Equality, comparing across numeric kinds: an integer 1 equals a float 1
Attributes()The producer’s metadata, or nil
WithAttr(name, val)A copy carrying one more attribute
WithAttrs(attrs)A copy with the given attributes merged over any existing ones. The map is copied, so yours stays yours

Equal comparing across numeric kinds is the useful one: it removes the integer-versus-float trap that catches direct comparisons elsewhere in the language.

The two With* methods return copies rather than mutating, so the result has to be used, passed to out.SetValue, or it is discarded. Attributes travel beside the value: they are readable with out.AttrStr and do not appear in the output map itself.

rule TagProvenance "mark this value as derived rather than read" {
when
in.Has("computed.ratio")
then
out.SetValue("ratio", in.Value("computed.ratio").WithAttr("source", "computed"));
}
facts
{ "computed": { "ratio": 0.42 } }
out
{ "ratio": 0.42 }

Returns the map at path, or nil.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path

Pass it straight to a call: a local variable cannot hold a map (the load-time check rejects m = in.Map(...)).

rule CopyBorrower "carry the borrower block through unchanged" {
when
in.Has("application.borrower")
then
out.Set("borrower", in.Map("application.borrower"));
}
facts
{ "application": { "borrower": { "name": "Ana Silva", "years": 4 } } }
out
{ "borrower": { "name": "Ana Silva", "years": 4 } }

Returns the table rows at path, or nil.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
rule HasLineItems "the input carried line items" {
when
array.Len(to.List(in.Rows("invoice.lines"))) > 0
then
out.Set("lineCount", array.Len(to.List(in.Rows("invoice.lines"))));
}
facts
{ "invoice": { "lines": [ { "sku": "A-1", "amount": 10.0 }, { "sku": "B-7", "amount": 5.5 } ] } }
out
{ "lineCount": 2 }

Every path argument accepts a dotted path, application.borrower.name, reaching into nested objects without a chain of accessors. A missing segment anywhere along the path returns your default.

PathReads
"application.borrower.name"name inside borrower inside application
"a\\.b"The top-level key a.b. \. (written \\. inside a GRL string) is a literal dot
"Work Phone Ext."The key as written. A dot that would leave an empty segment is kept literally

A path cannot index into a list: read the list with in.Rows, then use the array functions.

These still load and run, with a warning from the load-time check naming the replacement. Write new rules against the forms above.

DeprecatedWrite insteadNotes
in.Get(key)in.Value(path)Returns a typed value rather than a bare any
in.GetStr(key)in.Str(path, def)Takes a default
in.GetInt(key)in.Int(path, def)Takes a default
in.GetFloat(key)in.Double(path, def)Takes a default
in.GetBool(key)in.Bool(path, def)Takes a default
in.GetMap(key)in.Map(path)Same shape, current name
in.MemSet / MemGet / MemGetStr / MemGetRows / MemDelete / MemClearout.SetA value one rule computes for another belongs in out, which later rules read directly
in.GetMemAsMap()out.SetBuilds an envelope field by field; out.Set takes the value directly
in.NewMapWithValues(k, v, …)map.Of(k, v, …)The same map, from the collections namespace

The deprecated Get* reads follow dotted paths like the current ones and return the type’s zero value when absent. Scratch memory is a value later rules can read but the caller never receives. Values a later rule needs go in out: a later rule’s when sees an earlier rule’s out write with no further call.