Commands and mutations are normal TypeScript entrypoints loaded from a validated snapshot.
commands/
chess.previewMove.ts
mutations/
chess.move.ts
The file path is the callable id:
commands/chess.previewMove.ts -> command: chess.previewMove
mutations/chess.move.ts -> mutation: chess.move
Commands
Commands are quick logic. They can read, compute, validate, and return data. They do not commit durable state.
Use commands for:
- previewing a chess move,
- reading a derived shape that is awkward for a client,
- validating input before a user confirms,
- calling a cheap deterministic utility.
Mutations
Mutations commit durable state through PgPaw/Postgres.
Use mutations for:
- creating records,
- updating application tables,
- appending event rows when an ordered stream is needed,
- starting workflows by inserting or requesting a durable run.
Mutations require idempotency keys for retryable client calls. Same key and same payload returns the existing result. Same key and different payload is a conflict.
Why both exist
The split keeps the runtime honest.
command -> compute only
mutation -> commit through database policy
workflow -> durable orchestration over time
The generated package can expose all three as normal typed functions while the daemon keeps their execution rules separate.
