A single decorator classifies every tool call by reversibility tier.
Mark any async function by its reversibility tier: idempotency, effect logging, and compensation wiring are handled automatically.
agent.py
tools.py
session.py
1# agent.py — Powered by UndoLog23from undolog_sdk import undolog_tool, ToolTier4from undolog_sdk.tier import CompensationDescriptor56# SAFE — read-only · no log entry · replayed on retry7@undolog_tool(tier=ToolTier.SAFE)8async def lookup_customer(customer_id: str) → dict:9return {name: ..., plan: ...}1011# COMPENSABLE — writes · logs effect · registers undo12@undolog_tool(13tier=ToolTier.COMPENSABLE,14compensation=CompensationDescriptor.new(15"undo_create_ticket",16args={{"ticket_id": "{ticket_id}"}},17),18)19async def create_ticket(customer_id: str, amount: float) → dict:20await tools.create_ticket(customer_id, amount)2122# IRREVERSIBLE — approval gate · session suspended23@undolog_tool(tier=ToolTier.IRREVERSIBLE)24async def send_email(to: str, subject: str, body: str) → dict:25return await mailer.send(to, subject, body)26
Python 3.12UTF-8Ln 26, Col 1
Tier Inspector
SAFE
No effect log. Auto-replayed on cache hit.
COMPENSABLE
Pre-registers compensation. Logged to journal. Saga LIFO on failure.
IRREVERSIBLE
Approval gate. Session suspended until human judgment.
Every tool call is intercepted, classified, and routed in real time.
Each tool call is intercepted at runtime, classified by tier, and routed through the correct safety path, without touching your agent logic.
Effect JournalLIVE
eff_a1b2c3d4COMP.
create_ticketcommitted
eff_5e6f7a8bIRREV.
send_emailpending
append-only · BLAKE3 deduplicated
When an action is irreversible, only a human can grant approval.
The session suspends the moment an irreversible action is requested. Risk tags, full context, and a single click: approved or rejected.