Entity State
Entity state is defined in the state: section of the DSL. Each entity type has a named entry with an entity_key and a list of typed fields. State is stored in the entity_snapshots table and is the input to all rule evaluation.
State Definition Syntax
state:
<entity_type>:
entity_key: <field_name>
fields:
- name: <field_name>
type: <type>
default: <value>Supported Types
| Type | Description | Example default |
|---|---|---|
string | UTF-8 string | "" |
int | Integer | 0 |
number | Floating-point | 0 |
boolean | True/false | false |
datetime | ISO 8601 timestamp | "" |
array | Typed array (requires item_type) | [] |
object | Nested object | {} |
Array Fields
Array fields require item_type. If the array contains objects, define item_fields:
- name: top_artists
type: array
item_type: object
item_fields:
artist_id: { type: string, required: true }
play_count: { type: int, required: true }
default: []Warning: Always declare a
defaultfor array fields. Arrays with anulldefault breakcontains()andsize()expressions, causing runtime errors in rules.
Object Fields
- name: preferences
type: object
default: {}Nested fields within objects are accessed via dot notation in expressions and slash notation in op paths.
Full Entity State Example
state:
user:
entity_key: user_id
fields:
- name: concert_count
type: int
default: 0
- name: favorite_venue
type: string
default: ""
- name: total_distance_traveled
type: number
default: 0
- name: top_artists
type: array
item_type: object
item_fields:
artist_id: { type: string, required: true }
play_count: { type: int, required: true }
default: []
- name: last_concert_date
type: datetime
default: ""
- name: preferences
type: object
default: {}Path Notation
Causet uses two notations depending on context:
Slash Notation (ops and when paths)
Used in op targets and when condition paths:
then:
- op: set
path: /favorite_venue
value: "The Stone Pony"
when:
- path: /concert_count
op: gte
value: 10For nested fields, use slash-separated paths:
- op: set
path: /inventory/gold
value: 100Dot Notation (expressions)
Used in value: expressions, derive: expressions, and intent payload references:
then:
- op: push
path: /top_artists
value:
artist_id: intent.artist_id
play_count: 1Accessing nested entity state in expressions:
derive:
venue_name: entity.preferences.default_venueScratch Space: _tmp/ Prefix
Fields prefixed with _tmp/ are scratch space. They are available in all rule contexts but are intended for transient state — workflow steps, saga tracking, intermediate computations.
state:
ticket_import:
entity_key: import_id
fields:
- name: _tmp/saga_step
type: int
default: 0
- name: raw_data
type: string
default: ""
- name: venue_name
type: string
default: ""_tmp/saga_step is writable by ordinary core rules (op: set) and readable by preflight rules — it lives in the entity snapshot alongside domain fields. A sagas: block writes to the same kind of _tmp/ field automatically (via a compiler-generated core rule per step, see Defining Sagas), but you can also set it yourself directly, as in Your First Workflow.
In slash notation: /_tmp/saga_step
In dot notation: entity._tmp.saga_step
Entity State in Rule Contexts
Entity state is available in all rule evaluation contexts as entity.*:
preflight:
rules:
- name: sufficient_balance
when:
- path: /balance
op: gte
value: intent.amount
error:
code: INSUFFICIENT_BALANCE
message: "balance too low"
core:
rules:
- name: deduct_balance
when: {}
then:
- op: add
path: /balance
value: "-intent.amount"Intent payload values are available as intent.*. Entity state is available as entity.*. Both are resolved at evaluation time against the current entity snapshot.
State Persistence
Entity state is persisted to PostgreSQL by the causet-projection-worker. The entity_snapshots table contains one row per entity, with the full state as a JSON column.
SELECT entity_id, state
FROM entity_snapshots
WHERE entity_type = 'user'
AND entity_id = 'user_abc123';The state column contains the full entity state object, including all _tmp/ fields:
{
"concert_count": 12,
"favorite_venue": "The Stone Pony",
"total_distance_traveled": 847.5,
"top_artists": [
{ "artist_id": "artist_pearl_jam", "play_count": 4 },
{ "artist_id": "artist_springsteen", "play_count": 3 }
],
"_tmp": {
"saga_step": 0
}
}State is Rebuilt from Ledger
Entity snapshots are derived artifacts. The source of truth is the ledger_events table. If you drop the entity_snapshots table and replay the ledger through the rules engine, you get the same snapshots.
This means:
- Snapshots can be rebuilt after schema changes
- The ledger is the audit log for all state transitions
- New fields added to the state definition can be backfilled by rebuilding from the ledger