Metadata-Version: 2.4
Name: upoch
Version: 0.1.0
Summary: Upoch Guard for Python agents: verifiable checkpoints, recovery and rollback on Robinhood Chain, with a one-line LangChain and LangGraph callback.
License-Expression: MIT
Project-URL: Homepage, https://upoch.tech
Project-URL: Documentation, https://upoch.tech/docs
Keywords: upoch,ai-agents,checkpoint,recovery,rollback,robinhood-chain,langchain,langgraph
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: langchain
Requires-Dist: langchain-core<2,>=1.0; extra == "langchain"
Dynamic: license-file

# upoch: Upoch Guard for Python agents

Give your Python agent a memory and an undo button.

Upoch Guard saves verifiable checkpoints of an agent's work on Robinhood Chain. If the agent crashes, gets a bad
prompt or makes a bad trade, it restores the last good state, checked against the chain, or rolls back to the
checkpoint before the mistake and keeps going. It also knows which of its actions already happened.

Website and debugger: https://upoch.tech. Contract (Robinhood Chain, 4663): `0x6179d9123c3c1f9e82f948101a4350cb55aa8c27`

## Setup

Once, in your own terminal. You need Node.js 24 or later, because the `upoch` command holds the keys and does the
signing:

```sh
npm install -g @upoch/guard
upoch setup
```

`upoch setup` creates your keys in `~/.upoch`, waits while you send the owner address a little ETH on Robinhood
Chain (0.001 ETH is plenty), and registers your agent. Then:

```sh
pip install upoch                 # or: pip install "upoch[langchain]"
```

## LangChain and LangGraph

One line: every consequential tool call (swaps, transfers, bridges, staking, lending, trades, mints, launches and
approvals) is checkpointed before and after it runs. The pre-tool checkpoint is committed before the tool runs,
with `invoke` and `ainvoke`.

```python
from upoch.langchain import UpochCallbackHandler, upoch_tools

upoch = UpochCallbackHandler()

# Automatic checkpoints around consequential tool calls:
agent.invoke(inputs, config={"callbacks": [upoch]})

# Optional: let the model restore, checkpoint and roll back itself.
tools = [*your_tools, *upoch_tools(handler=upoch)]
```

| Tool | |
|---|---|
| `upoch_restore` | Latest checkpoint, verified against the chain, and which actions completed |
| `upoch_checkpoint` | Save the current state |
| `upoch_rollback` | Go back to an earlier checkpoint and continue. By default, the one right before the last swap or transfer |
| `upoch_history` | Recent checkpoints |
| `upoch_complete` | Mark the task finished |

Options:

```python
UpochCallbackHandler(
    watch=["swap_tokens", "send_eth"],   # exact tool names, or a compiled regex (default: value-moving names)
    state=lambda: my_agent_state,        # what each checkpoint holds (default: the log of watched tool calls)
    strict=True,                         # stop the tool when its pre-tool checkpoint fails (default False)
)
```

## Any Python agent

```python
from upoch import Guard

with Guard() as guard:
    restored = guard.restore()            # where the last run stopped, verified against the chain
    state = restored.get("state") or {"step": 0}

    guard.record_action("swap-1", "swap", "planned", input={"sell": "WETH", "qty": 0.1})
    guard.checkpoint(state, note="before swap", kind="before_action")
    tx = do_the_swap()
    guard.record_action("swap-1", "swap", "confirmed", transaction_hash=tx)
    guard.checkpoint({**state, "step": 1}, note="after swap", kind="after_action")

    # Something went wrong? Go back to the checkpoint before it:
    guard.rollback(0, reason="the swap was the wrong size")
```

| Method | What it does | On-chain |
|---|---|---|
| `restore(sequence=None)` | Latest (or a given) checkpoint after verifying it: state, note, completed and unresolved actions | read |
| `checkpoint(state, note, kind)` | Saves the state (`progress`, `before_action`, `after_action`, `manual`) | 1 transaction |
| `record_action(...)` | Records an external action (planned, submitted, confirmed, failed) with its transaction hash | no (goes into the next checkpoint) |
| `rollback(sequence, reason)` | Goes back to an earlier checkpoint and continues from it; lists actions since then that were not undone on-chain | 1 transaction |
| `complete(state, note)` | Saves a final checkpoint and marks the run finished | 1 transaction |
| `history(limit)` | Recent checkpoints | read |
| `verify(sequence)` | Verifies one checkpoint without restoring it | read |
| `status()` | Workflow, executor funds and today's usage | read |

Each method returns the result as a dict. Refusals and errors raise `upoch.UpochError` (with a `code`).

A rollback restores the agent's state. It cannot reverse transactions that already happened on-chain; those are
listed so the agent can account for them.

## How it works

`Guard` starts the `upoch mcp` command from `@upoch/guard` and talks to it over stdio. That process holds the keys:
it encrypts each checkpoint on your machine, stores it on IPFS, commits its fingerprint to the Upoch contract, and
reads it back to verify it. Only someone with your checkpoint key can read it, and anyone can check that it has
not been changed. Every checkpoint opens in the [Time-Travel Debugger](https://upoch.tech/docs/debugger).

Settings live in `UPOCH_HOME` (default `~/.upoch`); `Guard(home=...)` picks another one. If `upoch` is not on your
`PATH`, set `UPOCH_COMMAND` (for example `node /path/to/cli.js mcp`) or pass `Guard(command=[...])`.

## Safety

- Each checkpoint is one transaction from the agent's executor key. That key can only submit checkpoints. There is a
  daily limit (100 by default, `maxCheckpointsPerDay` in `~/.upoch/config.json`).
- State that looks like private keys, seed phrases or API tokens is refused, because checkpoints are permanent.
- Keys stay on your machine, in `~/.upoch/secrets.json`, and never pass through Python. Back that file up.
- The Upoch contracts have not been audited.

## License

MIT
