Skip to content
indraft
Start free

Documentation

Safe writes

An agent retries. It runs twice on the same instruction, races another agent, and occasionally misreads what it already wrote. Every one of those is a normal Tuesday, so the write path is built for it rather than around it.

Every mutating call takes the same envelope

idempotencyKey A replay with the same key returns the ORIGINAL result marked as a replay, and creates nothing. Honored for 30 days. Reusing a key with materially different input is refused rather than silently applied.
expectedVersion A write whose expected version does not match the current one is refused with stale_version and the current version. Newer state is never overwritten by an agent working from an old read.
dryRun Runs the real operation and rolls it back, returning what would have happened. Not a prediction: a prediction drifts from the code it predicts, and a preview that lies is worse than no preview.
assertionKind Whether this was observed, inferred, imported, or supplied by a person. Carried through to every surface that shows the value.
attributionLabel A caller-supplied label for a scope of work. It grants nothing, and every surface presents it as caller-supplied rather than as verified.

An upsert can refuse to guess

Matching uses real identity evidence: a normalized domain for a company, a normalized email for a contact. Name similarity alone matches nothing, ever. When identity is genuinely uncertain the call returns ambiguous with candidates and commits NOTHING, and you choose. That refusal is the feature: a CRM that merges two different people who share a name has destroyed something you cannot get back.

A mutation and its ledger row commit together

Every write records the actor, the operation, the target, the request, the outcome, the access path, and the field-level diff, in the same transaction as the change itself. A partially applied mutation is not something you have to detect, because it is not something you can observe.

Undo is offered only where it works

A field change can be compensated. A record creation cannot: undoing one would mean a hard delete or an archive, and presenting an archive as an undo would be a lie. A merge is inverted by unmerge rather than compensated field by field, because a partial restoration that looks complete is worse than a refusal. Anything irreversible is marked as such BEFORE the click, never by failing after it.