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.

That distinction is the whole point of the namespace. A bare fact access on a key that is not there is an error; every function here returns a default instead.

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");
Complete();
}

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);
}

Written as order["status"] == "open", the same test raises when status is absent. 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);
}

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);
}

Each takes a default and returns it when the path is absent or the value will not convert. None of them raise.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path
defstringReturned when absent
rule DefaultChannel "unstated channel is 'branch'" {
when
in.Has("application")
then
out.Set("channel", in.Str("application.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.

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

Returns the date at path, or the zero date.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path

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");
}
rule ApplicationDated "the application carries a readable date" {
when
!in.Date("application.date").IsZero()
then
out.Set("applicationDate", in.Date("application.date"));
}

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 — so 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 captured — pass it to out.SetValue, or it is discarded.

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"));
}

Returns the map at path, or nil.

ParameterTypeMeaning
pathstringThe fact name, or a dotted path

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"))));
}

Every path argument accepts a dotted path — application.borrower.name — reaching into nested maps without a chain of accessors.

Dotted-path reads are off by default and enabled per deployment. Where they are off, a dotted string is read as a single flat key, which is worth knowing because it fails quietly: the read returns your default rather than erroring. If a nested read is unexpectedly returning the default, that is the first thing to check.

These still work, so rules written against them keep running. They are listed so you recognise them in an inherited ruleset; write new rules against the forms above.

Older formWrite insteadWhy
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.SetScratch memory predates the output collector; what a rule computes belongs in the output
in.GetMemAsMap()out.SetReturns a deep-copied snapshot, which is expensive and rarely what was wanted
in.NewMapWithValues(k, v, …)map.Of(k, v, …), or out.SetEvery use in the production corpus was building an output envelope inline

The scratch-memory family is the one worth migrating deliberately. It was how rules passed values to each other before out existed; using it now means a value that later rules can read but the caller never receives.