tesoro 0.1.3

Get started

Install to a first refusal in about five minutes. No wallet, no testnet, no model key, no account to sign up for. A spend cap that has never refused anything has not been demonstrated, so the goal here is a refusal you can read.

1 · Install

pip install tesoro

Two packages, on purpose: tesoro and PyYAML. No web framework, no model client, no network library — a layer that decides whether a payment may happen has no business pulling in an HTTP stack. Python 3.11 or newer.

ExtraAdds
tesoro[schema]validate emitted records against the AEGS schemas
tesoro[x402]the x402 payment rail
tesoro[claude] [adk] [langgraph] [crewai]framework adapters
tesoro[advisors]optional advisory models — never on the decision path

2 · Create a project

mkdir my-agent && cd my-agent
tesoro init

Two files, and the split between them is the one concept worth understanding up front:

FileWhat it isWritten by
tesoro.yamlwhich profile, which pack, where evidence goesyou (deployment)
policies/default.yamlyour rules — the numbers and the decisionsyou (policy)

3 · Check it before an agent holds a wallet

tesoro check
config : /my-agent/tesoro.yaml
profile: aegs-1  7 required control(s)
policy : default  46abca353ed56adc703aa555ca1e12d6  12 rules

ok

Exit 0 means the config and the pack it points at are both valid. Every fault is reported at once rather than one per run, so this belongs in CI:

- run: tesoro check      # fails the build on an invalid policy

That hash is the pack's content hash, and it goes into every decision this pack produces. A label can be reused across edited rules; a hash cannot.

4 · Ask it a question

tesoro decide --amount 0.01 --vendor acme --resource /market/snapshot
APPROVE  /market/snapshot  $0.010000
  rule     : auto-approve-micro
  trust    : 0.2500  ['new_vendor']
  budget   : ok=True binding=None

Now one it should refuse:

tesoro decide --amount 500 --vendor acme --resource /market/snapshot
REJECT  /market/snapshot  $500.000000
  rule     : deny-over-balance

Check the exit code — this is what makes it scriptable

ExitMeans
0approved
2refused. The layer worked and said no — not an error
1invalid config or policy
3the evidence chain does not verify
4usage error
if tesoro decide --amount 500 --vendor acme --resource /r; then
  echo "cleared"
else
  echo "refused: $?"     # 2
fi

2 is a refusal rather than a failure because a governance layer that returns an error when it governs cannot be told apart from one that is broken. 4 exists because argparse exits 2 by default, which would collide.

Windows, Git Bash only. MSYS rewrites a leading / before Python sees it, so /market/snapshot arrives as C:/Program Files/Git/market/snapshot — and it is recorded in your evidence that way with no error. Use PowerShell, cmd, or MSYS_NO_PATHCONV=1. Not a Tesoro behaviour, but it silently corrupts a resource identifier, which is worse than an error.

5 · Govern the actual agent

from tesoro import Governor

gov = Governor.load()                  # reads ./tesoro.yaml
agent = gov.wrap(my_agent)             # duck-typed; any framework, or none

Or hold the payment yourself:

decision = gov.authorize(
    amount_usd="2.50",                 # a string. A float raises
    vendor="acme",
    resource="/market/snapshot",
)

if decision.approved:
    pay(...)                           # your payment call, on any rail
    gov.settle(decision, success=True)  # envelopes consume HERE
else:
    print(decision.verdict, decision.attributed_control, decision.reason)

settle() is where envelopes consume, not authorize(). A decision is made before money moves; a settlement records what actually happened. So an abandoned decision does not eat budget — and if the amount paid differs from the amount quoted, pass actual_amount_usd= and that is what counts against your limits.

Skipping settle() means the layer knows what it authorised and never learns what happened: nothing is consumed, and counterparty trust never accumulates.

Two more things in that snippet are load-bearing:

6 · See what happened

tesoro report
tesoro report --html -o spend.html    # one self-contained file

Four panels, one question each: Policy (what will this do?), Envelopes (how much is left?), Decisions (why did my agent stop?), Evidence (can I trust this record?).

No server, no port, no listener, and no outbound request of any kind — no CDN, no webfont, no analytics. It is a file you can attach to a ticket. That property is asserted by a test that greps the rendered bytes, because a page describing what your agent spends should not phone anywhere. (This documentation site follows the same rule.)

The part worth reading is by attributed control:

by attributed control  -- what actually governed this agent
  policy                 2
  treasury               1

Counts by verdict tell you what happened. Counts by attributed control tell you what is actually governing this agent — frequently not what whoever wrote the policy expected.

7 · Verify the record

tesoro audit

Every decision is journalled in an append-only, hash-chained record. audit re-verifies the chain and exits 3 if it does not hold.

DetectedNot detected
editing an entry · deleting one from the middle · reordering · replay deleting entries off the end

Any prefix of a valid chain is itself a valid chain, so an agent that was refused could delete the refusal and verification would still report success. Closing that needs an external anchor. Tesoro prints the caveat next to every VALID rather than shipping a head.json beside the journal — which would look like a fix while defending against nothing, since whoever can truncate the journal can rewrite the file next to it.

Run the whole thing against a mock seller

The examples repository ships a stdlib x402 mock seller — no wallet, no testnet, no chain — that speaks the real protocol: its 402 carries a genuine PAYMENT-REQUIRED header built with the SDK's own encoder, so the buyer's decoder parses it exactly as it parses a live seller's.

git clone https://github.com/tesoro-labs/tesoro-integrations
cd tesoro-integrations
pip install -r quickstarts/no-framework/requirements.txt
python quickstarts/no-framework/run_mock.py
bought   /market/snapshot       $ 0.010000
bought   /market/depth          $ 0.050000
REFUSED  /premium/feed          $ 2.500000
         control : policy
REFUSED  /expensive/report      $25.000000
         control : treasury, envelope per_transaction
         because : per_transaction admits $10.000000 but the request is $25.000000

OK: 2 refusal(s), 1 of them from an envelope (per_transaction).

What a green run there proves, and what it does not. It proves the loop works, governance is wired in, a budget is authorised before the run, a ceiling stops it, envelopes consume on settlement, and the chain records all of it.

It proves nothing about signatures or settlement: the mock accepts any payment header without checking it, its receipt's transaction id is literally 0xMOCK-NO-CHAIN-INVOLVED, and /health reports settles: false so a caller can always ask what it is talking to.

Six use cases, each checking its own claim

python usecases/run_all.py
CaseThe claim
data-marketplacethe baseline — an agent shops, the expensive thing does not go through
intent-drifttreasury, trust, risk and policy all say yes. Only intent knows what the agent was sent to do
delegationa sub-agent can never claim more than its parent — including one that declares nothing
budget-exhaustionan exhausted token budget must REJECT; the same breach on a payout is REVIEW
prompt-injectioncounterparty text cannot move a verdict, because nothing on the path reads prose
aml-structuringnothing is refused. An open gap, shipped as a runnable artifact

Each exits non-zero if it stops demonstrating its point — including a case refused by the wrong control, which is CONF-2 applied to an example: a right ending for the wrong reason teaches the reader something false. The structuring case inverts it and fails if a refusal ever appears, because that would mean the gap had closed.

Real settlement

export X402_SELLER_URL=http://localhost:4021   # any x402 resource server
export X402_PRIVATE_KEY=0x...                 # Base Sepolia. Testnet only.

Testnet only. Never a mainnet key in an example script. Tesoro's job is to make an agent's spending bounded and explicable; it is not a substitute for keeping a funded key out of a quickstart. BYOK keys are never stored, logged or journalled by the layer — a masked display path is the only way a key is ever shown.

Before you rely on this

0.x. The API may change before 1.0, and this is here rather than at the bottom of a changelog because you are about to point it at a wallet.

Specifically: structuring is open, AML screening is a schema with no engine behind it, no regulatory compliance is claimed or sought, journal truncation needs an external anchor, and no independent implementation has been scored.

Reference

Quickstart

The same seven steps, in the repository.

quickstart.md →

CLI

Every command and flag.

cli.md →

Public API

Stability tiers and what is deliberately not public.

api-surface.md →

Examples

Agents, the mock seller, use cases, the measurement harness.

tesoro-integrations →