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:
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:
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.
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:
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
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.
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,
maxCheckpointsPerDayin~/.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
Metadata
Release files for upoch 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| upoch-0.1.0.tar.gz | 16.0 kB | Without provenance | Details for upoch-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| upoch-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for upoch-0.1.0-py3-none-any.whl |
Total release size: 28.4 kB
Release files / upoch-0.1.0.tar.gz
| Download URL | upoch-0.1.0.tar.gz |
|---|---|
| Size | 16.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fbf3b685c0276bdcd0b8a17210c93833f67c20fd485f76d369e57df3197359a2
|
|
BLAKE2b-256 checksum How to use checksums |
b399619f7528536d88b0a1ff090ac2b144ed95058295a96bd68b47a66fbff824
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|
Release files / upoch-0.1.0-py3-none-any.whl
| Download URL | upoch-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be8791d1d3032d883115b0296064743c0d9d4efdd90da1b00a3f69dcdfea62c8
|
|
BLAKE2b-256 checksum How to use checksums |
d0753c43f36201022caa4a97dc327460bc048f78a2825a0d86a4352f73c6ced7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|
Security for upoch 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.