reversi-sdk lets a Python agent journal its tool calls through a Reversi server, and lets any
Python program verify ledgers and validate manifests offline. It needs Python 3.9 or later and has no runtime
dependencies.
The package is not published to PyPI by this repository. Install it from the checkout, or publish it yourself. The
test suite (
npm run test:py, 55 tests) runs against a live Reversi server as well as fakes.What it covers
It talks to the run, approval, halt and evidence endpoints. The newer governance endpoints (search, impact preview,
simulate, replay, registry, holds, retention, keys and the rest of the admin API) are not
wrapped yet: call them over HTTP, or use the CLI or TypeScript SDK.
Journal a call
call journals the intent before running your function and the outcome after. If the process dies in between, the
server shows the step as unresolved rather than pretending it never happened. Raise EffectUncertain from your
function when you cannot tell whether the effect happened (a timeout, a dropped connection): the step is recorded as
uncertain and an operator settles it later.
start_run(permissions, run_id=None, mode="enforce", reason=None) takes the run’s permission scope. mode is
enforce (violations block), observe (violations are journaled and the call runs; the key needs allow_observe) or
advise. Pass run_id to start a run with a name you choose, and client.run(run_id) to pick up an existing one.
Lower-level methods exist when you do not want call to run the function for you: run.begin(tool, reason, args)
returns the decision (allow or block) and a step number, and run.complete(step, status, result=…, error=…) records
the outcome. run.state() returns the steps and their statuses.
Decorate tools so every call goes through the run:
Approvals
When a call needs approval,Blocked.approval_id holds the request id. The approval is bound to the exact arguments
and used once, so ask an approver to decide it, then retry the same call:
Operator and admin methods
Each needs a key with the matching role.
The rollback report lists
compensated, failed, deferred, awaiting_approval and not_undoable steps. It does not
run a manifest’s declared read-back verification: that happens on the server side
(rollback).
Errors: ReversiError (with status and message) for any refused or failed request, Blocked for a policy refusal
of a call, EffectUncertain raised by you.
Offline tools (no server)
python -m reversi_sdk verify ledger.jsonl checks a ledger’s hash chain from a shell (exit 0 ok, 1 tampered, 64 usage).
validate_manifest accepts the full manifest format (versions, status, risk, residue, verification, timeouts, retry,
idempotency, approval rules) and returns the normalized manifest or a list of every error. It is tested against the
TypeScript validator on shared fixtures, so the two agree.
Two limits: manifests are read from JSON, so convert YAML first, and Ed25519 evidence bundles are not verified in
Python (the standard library has no Ed25519). Verify bundles with reversi verify-bundle.
Canonical JSON for payload hashing rejects non-whole floats outside 1e-4 to 1e16, where Python and JavaScript format
numbers differently. Pass such values as strings.
Webhook signatures
sha256=<hex>, an HMAC-SHA256 of the body; the comparison is
constant time and a missing or malformed header returns False. See notifications for the
server side.
Pydantic models
reversi_sdk.pydantic_models has pydantic v2 ToolManifest, Compensation and Verification models for IDE types and
JSON Schema generation. They run the standard library validator first, so the two cannot disagree.
Agent frameworks and Claude Code
Adapters for LangGraph, CrewAI, the OpenAI Agents SDK and FastMCP, and thereversi-claude-hook command for Claude Code
hooks, are in integrations. They are tested against fakes of those frameworks’ interfaces, not
against the frameworks themselves.
