Every witness stays.
A later readback does not rewrite the earlier one. In the delayed_reconciled trace, the first verification stays unknown after the second resolves it.
A tool response is only part of the story. ConseqaX keeps the response, the agent’s own report, independent readback and effect origin apart, so you can see what the record actually supports.
Each tab replays a trace written by the package’s own demo or a runnable example, then shows what explain() concludes from it. Nothing here is a hand-written outcome.
my-demo/traces/episode_01.jsonProvider origin metadataOther evidence linksUnknown verification
The first four traces come from consequa-x demo with seed 0. The two-part outcome comes from examples/two_part_outcome.py: one tool call must refund the order and close the ticket, the CRM update is dropped, and readback from each system decides the all_of contract. Times are the recorded milliseconds; playback compresses the gaps between them. The graph shows every node and link the package builds for these records, except captured-order links and context events.
| Demo trace | Tool response | Agent reported | Verified state | Effect origin | Alignment | Diagnoses |
|---|---|---|---|---|---|---|
timeout_after_commit | timeout | failure | satisfied | confirmed | contradicted | ASSESSMENT_DIVERGENCE ACKNOWLEDGEMENT_EFFECT_DIVERGENCE |
delayed_visibility | success | success | unknown | unknown | unassessable | UNKNOWN_OUTCOME UNVERIFIED_ASSESSMENT |
external_actor | timeout | failure | satisfied | other_actor | unassessable | UNASSESSABLE_ASSESSMENT EXTERNAL_ACTOR_EFFECT |
delayed_reconciled | success | success | satisfied | confirmed | consistent | CONSISTENT_OUTCOME |
ticket_left_open | success | success | violated | confirmed | contradicted | ASSESSMENT_DIVERGENCE RESPONSE_EFFECT_DIVERGENCE CONSEQUENCE_VIOLATION PART_VIOLATED |
Refunds, deliveries, database writes. When an agent changes something, keep the intention, the history and independent readback together.
Register a contract before the action: what must hold, by when, how many times. A run can register several actions, and an outcome with several parts is one all_of or any_of contract. The recorder keeps dispatches, responses and what the agent reported.
rec = TraceRecorder(
"agent-loop", actor=AGENT)
refund = rec.register(
"refund-o-17", "issue_refund",
ORDER, contract=CONTRACT)
with refund.attempt() as attempt:
issue_refund(ORDER, attempt)
Read your system of record through a separate read-only path. The built-in record verifier checks rows, orders or tickets, and CompositeVerifier checks each part against its own source; stale, incomplete or unavailable readback stays unknown.
VERIFIER = RecordVerifier(
scope_fields=("order_id",))
receipt = refund.verify(
readback, verifier=VERIFIER)
receipt.status.value # "satisfied"
receipt.origin.value # "confirmed"
Compare the agent’s report with verified state and origin, then decide whether a retry would duplicate the effect.
ex = explain(rec.trace())
ex.actions[0].assessment_alignment
# "contradicted"
retry_advice(receipt).advice
# "do_not_retry"
You define success and establish source trust. ConseqaX preserves and explains the evidence you supply; a graph link does not establish causal necessity. Values are from the tested SQLite agent-loop example (timeout after commit; ConseqaX 2.1).
Three real commands, their unedited output, and the exact report file they produce. Scroll the report yourself at any point.
Recorded from consequa-x 2.1.2 in a fresh folder by scripts/build_site_demo.py. Printed absolute paths are shown relative to that folder; nothing else is edited. The window shows the file those commands wrote, byte for byte (SHA-256 9a34912b6ca7…). It runs no action, verifier or model in your browser.
A later readback does not rewrite the earlier one. In the delayed_reconciled trace, the first verification stays unknown after the second resolves it.
Default reports omit captured payloads and raw identifiers and use local aliases. Field omission is not anonymization; timing and structure stay visible.
Reports open directly in a browser with no JavaScript, remote assets, model, API key or hosted account. Keep the original trace as the record.
@consequential_tool(calls=calls)
In place of function_tool. Records each call, its errors and the SDK’s own tool timeout.
ConsequaCallbackHandler(calls)
A callback handler for tool runs, including errors a tool handles itself. LangGraph agents run tools the same way.
consequa-x[langchain]hooks=consequa_hooks(calls)
Pre- and post-tool-use hooks that only observe. They never block or change a call.
consequa-x[claude-agent-sdk]consequa-x otel-export trace.json
execute_tool spans as the GenAI conventions name them, or start a trace from the tool spans you already have.
Optional extras: the core still has no runtime dependency. You decide which calls are consequential; a tool response is never treated as verification. Tested offline against each SDK’s own machinery, not with a live model.
Install the package, generate the synthetic demo, and open a report. Then connect your application’s own independent readback.
python -m pip install consequa-x==2.1.2
consequa-x demo --output my-democonsequa-x report my-demo/traces/episode_01.json --output my-report.htmlmy-report.htmlVersion 2.1.2 is on PyPI. The demo performs no real refund, delivery or network call.