An AI-CRM without safe-to-retry execution has one failure mode. The model reasons, produces a plausible action, and either fires it once and forgets — or fires it twice and creates two of everything. Every gap between the reasoning surface and the execution surface becomes a support ticket.
Actionary closes the gap in the substrate. Reasoning proposes; the platform lands. A tool call that fires twice — a network retry, a browser refresh, a re-issued webhook, an LLM stutter — converges on one record, one grant, one download, one signal, one webhook delivery. The guarantee lives in the schema, the indexes, and the code paths that touch them.
That is what makes the agent trustable at enterprise scale.
Propose-then-execute on the tool surface
The propose-entity-update MCP tool stages a diff in Redis with a short TTL. A separate execute-entity-update call commits it. The model proposes; the operator or a downstream check confirms; the platform applies.
A naive tool-use loop fires the destructive action inside the same turn the model proposes it. If the API returns 502 mid-flight and the client retries, the tenant gets two records, two invoices, two emails to the customer. Actionary treats destructive actions as a two-phase commit by default.
The destructive-confirm gate is a per-conversation, per-tool-use uniqueness constraint on a pending-confirmation table. The pending tool-call block stays out of the assistant message until confirmation — the message protocol stays self-consistent across the pending → confirmed → tool-result transition. Every tool-call block resolves. Protocol-level rejections hours later stay off the table.
Partial-unique-index guards on every live-row primitive
Every shared primitive uses the same pattern: a partial unique index gated on the not-yet-revoked tombstone column. The permission grant, both sides of the session store, external MCP OAuth clients, and external share-recipient tokens all use the same shape.
Granting the same person access to the same record twice creates one row. The transfer-content flow that moves ownership when a user is offboarded is atomic on this primitive: grant the target, revoke the departing user’s live grants, in one transaction, idempotent under retry.
Durable workflow execution on Postgres
The workflow engine is durable execution today. FOR UPDATE SKIP LOCKED step claims run safely across multiple replicas from a single Postgres queue. The step-insert path uses a do-nothing-on-conflict clause on the (run, node) uniqueness constraint — a replayed step never double-inserts. A dead-letter table captures every terminal failure with retry backoff.
Every workflow step carries an idempotency-key header derived from the tenant, event, run, step, and action type. Outbound webhooks from the engine present the same key on every retry — a downstream receiver that respects it converges to one delivery.
The token-passing graph shape follows industry-standard durable-orchestration semantics. Postgres is the durable substrate — one system to keep alive in the deploy topology.
Public writes deduplicate at the boundary
An idempotency-key header honoured on public form-submission endpoints with a trailing lookback window. A live-row uniqueness constraint on the tenant + signal source + external id triple on the Signals entity — a form-submission-to-signal round-trip converges even if the fan-out retries mid-flight.
The same shape covers the Stripe billing bridge — a usage-record retry never double-charges a tenant. Every connector that lands data through Actionary inherits the same boundary discipline.
Outbound webhooks — signed, retried, dead-lettered
Public-surface webhook fan-out signs every delivery with HMAC-SHA256. The delivery ledger carries a partial index over pending retries so a scheduler walks the retry queue efficiently.
Every retry carries the same signature. Every terminal failure lands in a dead-letter table an operator can see under /platform/workflow-dead-letters. A downstream receiver that respects the signature and the delivery id converges to one processed event — regardless of how many times the network forces a re-send.
Asset-download tokens redeem the same way. Issue once; redeem many; the same asset comes back, never a fresh mint. A compliance auditor points at one row per download event, no matter how many refreshes the user hit.
Deliberate conflict handling across the schema
Every write path is either idempotent by construction or an explicit upsert — every path is deterministic under retry. Three load-bearing examples: the workflow event log rejects a redelivered scheduler event on a tenant + event-id constraint; the workflow step-insert path re-creates steps safely on the (run, node) constraint; the agent’s pending-confirmation table upserts on the (conversation, tool-use) constraint so re-staging a pending action does not duplicate it.
Every schema migration applies through an in-app runner with content-hash drift detection. A migration tracker records every apply with content hash, duration, applying user, and stdout. Editing a migration after apply flags drift and refuses to silently re-run. The audit trail matches what enterprise change control requires.
The takeaway
Idempotency is an architectural commitment. It has to hold at the database, at the tool surface, at the workflow engine, and at every outbound webhook — or the whole story collapses on the first retry. Actionary makes the commitment in all four places, and enforces it with partial unique indexes, typed conflict clauses, HMAC-signed retries, and a dead-letter ledger the operator can see.
The reasoning is the agent. The planning is a workflow or an agent turn. The landing is durable, retryable, auditable — because the schema, the indexes, and the code refuse to double-execute when the network, the browser, the webhook receiver, or the model tries. That is the substrate an engineering team can bet a five-year roadmap on. More for CTOs.