Treeship for Claude Commerce Agents
Signed, offline-verifiable receipts for every tool call in anthropics/commerce-agents, on all three of its runtimes.
The reference draws its own boundary in docs/safety.md: the approval surface, payment,
and log hygiene are "what a deployment owns". This package is what a deployment adds for
the record of what happened. It records; it does not gate. The reference's provenance
gates, caps, and host approval still decide what runs.
What it does
commerce_common.execution.BaseToolExecutor.execute is the one method every tool call
passes through on the Messages API, the Agent SDK, and Managed Agents. TreeshipExecutorMixin
overrides it:
- a signed intent receipt before dispatch: tool, SHA-256 of the canonical arguments, session tag;
- the tool, exactly as the reference runs it;
- a signed result receipt: status (
ok,blockedwith the gate's name,error), SHA-256 of the result text, event types, timing.
Each receipt names its parent, so a session reads intent → result → intent → result … from
the Treeship session's root, and treeship verify walks it as one chain. A held call is a
signed refusal, not a missing receipt.
Never written: the arguments, the result text (fenced third-party content on the reference), or the commerce session id (the request credential). The receipt carries the same twelve-hex session tag the reference's own log lines use, so an operator holding the id can correlate and a reader cannot.
Install
# from a clone of anthropics/commerce-agents, with its venv active
pip install -r requirements.txt # their seven packages (unregistered on PyPI)
pip install treeship-sdk treeship-commerce
curl -fsSL https://treeship.dev/install | sh && treeship init
Use
from treeship_sdk import Treeship
from treeship_commerce import TreeshipReceipts, attach, receipted
from treeship_commerce.lifecycle import close_session, start_session
from shopping_agent.executor import ShoppingToolExecutor
ts = Treeship()
root = start_session(ts, name="storefront:acme", actor="agent://shopping")
executor = receipted(ShoppingToolExecutor)(backend=..., config=..., skills=..., session=..., state=..., memory=...)
attach(executor, TreeshipReceipts(ts, actor="agent://shopping", session_id=session.session_id, parent_id=root))
# ... the runtime calls executor.execute(...) as it always did ...
close_session(ts, summary="...") # seals a .treeship package; `treeship session report` publishes it
All three runtimes construct executors themselves through executor_class
(ShoppingAgent, ShoppingToolset, the MCP server's build_server). Give
receipted() a recorder factory and each executor gets its own recorder on
its first tool call:
ReceiptedShopping = receipted(ShoppingToolExecutor, recorder=lambda ex: TreeshipReceipts(
ts, actor="agent://shopping", session_id=ex._session.session_id, parent_id=root))
Same for MerchantToolExecutor.
Recording never breaks the agent path: a receipt that cannot be written warns once, is
counted in TreeshipReceipts.dropped, and later results say intent_recorded: false where
the intent is missing. Nothing is invented. TREESHIP_DISABLE=1 turns recording off.
Demo
TREESHIP_BIN=... python -m treeship_commerce.demo
Runs the reference's shopping executor over the retail mock with no model and no API key:
a search, a product read, an add, an add the provenance gate holds, a checkout hand-off.
Prints every receipt id, seals the session, and shows the treeship verify command.
TREESHIP_BIN=... python -m treeship_commerce.demo_merchant
The merchant side: a staged price change, held while unapproved, applied once under a signed single-use operator approval, then refused on replay while the reference's own in-process approval mark is still set. Prints the grant id and the journal's record of its one use.
Approvals
MerchantApprovals turns the host's y/N into a signed Approval Grant scoped to one actor,
one action, and one change (change://<change_id>), max_uses=1. approved(receipted( MerchantToolExecutor), approvals) signs the apply's intent receipt with the grant's nonce,
so the CLI reserves a use in the Approval Use Journal before signing. A second apply finds
the grant spent; a grant for another change is refused by scope. The receipt says
approval: "proven" or "unproven" with the reason. Recording only, unless
enforce=True. Needs treeship-sdk 0.29.0 or later (attest_action takes subject).
On the Agent SDK runtime, approving(toolset, approvals) wraps MerchantToolset.host_approve
and host_clear in place, so the reference console's y/N loop mints and forgets grants with
no edits. On the Messages API the host calls approvals.grant() beside its own mark. On
Managed Agents the platform's prompt is the approval surface and the click is outside the
process; an apply there is receipted with no approval claim, never an invented one.
What this does not do (yet)
- Checkout hand-off receipt. Signing the cart digest and hosted-checkout URL digest at
checkout_handoff, chained to the host's order placement. - Prove the work is correct. A receipt is evidence of what ran and what the gates decided. It does not make a wrong answer right.
Tests
TREESHIP_BIN=/path/to/treeship python -m pytest
Twenty-eight cases on a real isolated ship over the real retail and merchant mocks: chain
order and linkage, a held call signed as blocked with its gate, digests-only content,
recording failure leaving the tool untouched, TREESHIP_DISABLE, attach refusing an
executor that would record nothing, one per runtime, and the approval properties: a grant
binds to its receipt, is spendable once, is refused for another change, enforce=True
holds an unapproved apply, the receipt note is the CLI's reason rather than the SDK's
wrapper, the merchant side on all three runtimes through executor_class, and arguments
that arrive as parsed pydantic models (the MCP server's shape) digesting like their dicts.
Release files for treeship-commerce 0.29.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 | |
|---|---|---|---|
| treeship_commerce-0.29.0.tar.gz | 32.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| treeship_commerce-0.29.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.0 kB
Release files / treeship_commerce-0.29.0.tar.gz
| Download URL | treeship_commerce-0.29.0.tar.gz |
|---|---|
| Size | 32.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
792a71aafc7e73865b77afe6c9ebb61a6ad51ab5d3c08b4b97dafcda1beb358d
|
|
BLAKE2b-256 checksum How to use checksums |
44b21e6957c95c1e8045da42a2b5cdf4573ed77ca050bfe0e5100778cbacb538
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency logRelease files / treeship_commerce-0.29.0-py3-none-any.whl
| Download URL | treeship_commerce-0.29.0-py3-none-any.whl |
|---|---|
| Size | 25.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1d8f5b9285c33bf945c4b64c9d668aab2eef30a34658dfced389ff32c6cc33ef
|
|
BLAKE2b-256 checksum How to use checksums |
0c19e1190803edf12508f7cd949d0779dc929c16c1596ddd6d1f2daeb762ce89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency log