Skip to content
Browse the documentation
Guide

After the first verdict

Once the first verdict has settled, these are the pieces that turn one call into an operation: test without storing, hear about verdicts, hold a workflow until the verdict is in, and record from code, from an assistant or from traces.

Try before you store

POST /v1/actions/verify with dry_run: true evaluates an action and facts inside a transaction that is rolled back: nothing is stored and nothing is metered. Use it in tests and in the playground under Actions → Verify.

curl -X POST https://api.commitlayer.ai/v1/actions/verify -H "X-API-Key: $COMMITLAYER_RECORDER_KEY" -H "Content-Type: application/json" \
  -d '{"dry_run": true, "action": {...}, "facts": [...]}'

Get told when a verdict settles, and what it waited on

Subscribe a webhook to action.verified (and action.pending for the first provisional verdict) under Settings → Webhooks. Every delivery carries the verdict, its reasons, whether it is pending or settled and what it is waiting on, the record that reversed it and what it was before, with the standard envelope and an HMAC-SHA256 signature; Slack alerts say the same in one line. contract.weakened fires when a saved contract version accepts more than the last one.

{"id": "evt_...", "event": "action.verified", "created_at": "...",
 "data": {"action_id": "act_0001", "contract_id": "refund_workflow", "outcome": "FAIL", "policy": "FAIL", "status": "settled",
          "reasons": [{"code": "expected_effect_missing:shopify.order_cancelled", "label": "..."}],
          "settlement": {"settles_at": "...", "waiting_on": [], "stale_sources": []},
          "reversal": null, "previous": {"outcome": "FAIL", "policy": "FAIL"}, "changed": false, "verdict_hash": "sha256:..."}}

Do not say "done" before it settled

The completion gate is your workflow reading the verdict before it makes a claim. GET /v1/actions/{id}/wait holds the request until the verdict settles or the timeout passes (60 seconds per call; the SDKs loop), evaluating the evidence that arrived and storing the settled verification once. PASS: tell the customer. FAIL: route to recovery. A timeout with status pending is your decision, never a success. The refund is already issued when the gate is consulted, so the gate adds no latency to the action and cannot block it. The Temporal and Inngest integrations ship this as a verifier activity and a step helper.

v = cl.wait_for_settlement("refund:order_10231", timeout=300)   # Python; JS: await cl.waitForSettlement(ref, {timeoutMs})
if v["timed_out"]: ...                                           # pending: your policy
elif v["lenses"]["outcome"]["verdict"] == "PASS": notify_customer(...)
else: open_recovery(v)

Settlement waits for evidence, not for the clock

A verdict that is not yet a PASS settles only when its window has closed and every source the contract reads has reported past it: a synced connector's watermark, or the one you declare when pushing facts. A lagging source delays the verdict instead of failing it, for at most 48 hours; then it settles and names the sources still behind. A source that never declares a watermark is taken as current.

curl -X POST https://api.commitlayer.ai/v1/facts -H "X-API-Key: $COMMITLAYER_EVIDENCE_KEY" -H "Content-Type: application/json" \
  -d '{"facts": [...], "watermarks": {"crm": "2026-10-13T10:45:00Z"}}'   # everything up to here has been sent for crm

Record from code with the Python SDK

pip install the SDK from sdk/python in the API repository. The @action decorator records the call as an action before the function runs and never touches its result; if the API is unreachable the function still runs and a warning is logged. The client also pushes facts with watermarks, reads verdicts and drafts contracts.

from commitlayer import Client
cl = Client(agent_id="support-bot")   # COMMITLAYER_API_KEY = the Runtime recorder key; facts go through a separate evidence client

@cl.action("refund_workflow", subject="order_id", params=lambda amount, **_: {"amount": amount},
           action_id=lambda order_id, **_: f"refund:{order_id}")   # retries update one claim
def refund(order_id: str, amount: float) -> dict:
    return payments.refund(order_id, amount)

Draft a contract from what was recorded

POST /v1/contracts/draft reads the recorded actions of one type and the facts observed around them, and proposes expected effects, a window, preconditions and limits from the sample, with the shares in the YAML comments. Nothing is saved; validate and save it like any version. Validate and save also warn when a version is weaker than the one it replaces: a removed check, a raised limit, a longer window.

curl -X POST https://api.commitlayer.ai/v1/contracts/draft -H "X-API-Key: $COMMITLAYER_RECORDER_KEY" -H "Content-Type: application/json" \
  -d '{"action_type": "refund_order", "lookback_days": 30}'

Read the evidence from an assistant, record from an MCP tool call

The same workspace is an MCP server at /mcp: an assistant with a Read-only key (or a ChatGPT-style client signed in with OAuth) reads actions, verdicts, reasons and contracts, validates and dry-runs a change, and never touches facts or verdicts. The recorder is a stdio proxy that records a mapped tool call as an action before forwarding it to the downstream MCP server. See the MCP page for both.

claude mcp add --transport http commitlayer https://api.commitlayer.ai/mcp --header "Authorization: Bearer $COMMITLAYER_API_KEY"
commitlayer-mcp-recorder --map stripe.json -- npx -y @stripe/mcp --tools=all

Record from OpenTelemetry instead

On every plan the agent runtime can emit spans and CommitLayer records the action from them, with no API call in the agent's code; the actions count toward the monthly allowance like any other. Internal agents → OpenTelemetry in the app shows the attributes to set.

Catch actions nobody recorded

GET /v1/actions/orphans?contract_id=refund_workflow lists effects of the kinds the contract watches that appeared in your systems with no recorded action behind them: the wrong-customer and injected-instruction cases. Builder plan and above.

Next

Beyond one action: the checks that look across actions and across time.