Intents — Concept
An intent is a declared command — the contract between your API and the Causet runtime. When a client submits an intent, the runtime loads the target entity’s current state, runs your rules in order, appends events to the ledger, and returns success or a structured rejection.
Intents replace ad-hoc service logic with declarative, replayable rules.
Why intents exist
Most application bugs come from scattered validation and state mutation spread across controllers, services, and background jobs. Causet centralizes the write path:
- Validate input before any mutation (
preflight) - Mutate entity state deterministically (
core) - Emit domain events and schedule follow-up work (
side_effects)
Every successful intent produces an append-only record in the ledger. You can replay history and get the same state every time.
Intents vs events vs projections
| Layer | Role | When it runs |
|---|---|---|
| Intent | Accept a command, run rules, write ledger | Synchronous — write path |
| Event | Immutable fact emitted by an intent | Written to ledger, published async |
| Projection | Materialized read table from events | Async — read path |
Intents emit events. Projections consume events. Queries read projections. Never skip the chain: intent → event → projection → query.
Deterministic rules
Rules inside an intent must be pure relative to the ledger:
- No HTTP calls, database lookups outside
LOOKUP_FIELD, or external I/O - No
now(),random(), oruuid()— useevent.tsand deterministic IDs - Same entity state + same input → same mutations and same emitted events
This is what makes replay, audit, and debugging possible.
Rule phases (mental model)
- Preflight — read-only validation. Only
reject(and read ops likelookup) allowed. - Core — mutate the target entity.
set,add,push, relationships. Noemit. - Side effects — fan-out after commit.
emit,submit,schedule,decision. No direct state writes.
If preflight rejects, nothing is written. If core succeeds, the ledger is committed before side effects run.
Where intents are declared
# app.causet
includes:
actions: [./actions/**/*.actions.causet]Each .actions.causet file declares intents under the actions: key. The compiler transpiles them into the internal ruleset the runtime executes.
Next steps
- Overview — guide map for this section
- Defining Intents — input schema, entity routing, full anatomy
- Rules — preflight, core, and side_effects in depth
- Examples — concert-app patterns