Your agent can read anything.
It cannot act on it without asking.
An agent's danger is usually the sequence, not the step: a permitted read, then a permitted send. Bounds evaluates each call against the path of its task and the rules you wrote, refuses what breaks one, and records the verdict with a reason you can read and hand to somebody else.
Install it and watch it refuse.
$ npx attesso log --action web.read --subject docs.example --task job-1 \
--trust untrusted --capability read
#1 ALLOW web.read docs.example (ALLOW)
$ npx attesso log --action mail.send --subject partner@example.com --task job-1 \
--capability send
#2 DENY mail.send partner@example.com (PATH_DENIED by step #1 under no-send-after-untrusted-read)
$ npx attesso prove 2 --out receipt.json
$ npx attesso verify-receipt receipt.json
receipt verifies: entry #2 is in the tree of 2
No account, no server, no key to register. The ledger is hash-chained and signed locally, and attesso report shows what ran, what was refused, and what it cost in tokens and dollars. A receipt verifies in an empty directory with the public key: it proves the entry is in the log whose head this key signed, not that a human approved it.
npx attesso ui opens the same ledger as a local control surface at 127.0.0.1, and npx attesso sync mirrors decision summaries to a paid workspace. The local tier stays free and unlimited.
Path rules, refusals with reasons, and a record.
- Rules judge the task path, not one call: a send after an untrusted read is refused, and the refusal names the step that tainted it.
- Step and repeat ceilings stop a loop before it spends the afternoon: the same tool with the same arguments, refused at the limit you set.
- Every verdict is recorded with its rule and the state it was judged against, so the answer to "what happened" is a file, not a memory.
- Enforcement is steer first: on a repeat the earlier result is handed back, which is where tokens actually stop being spent.
Money and exposure, kept apart.
- Repeats and retry loops: in one measured session, 193 duplicate runs and 136 failure-shaped results out of 2,070 tool calls, an upper bound of 16% of that session's cost.
- Actions outside the bounds a person signed: refused before they run, with a signed reason.
- Context you did not need: a step or cost ceiling per task, enforced instead of noticed afterwards.
Waste is measured on your own sessions and quoted as a percentage of model spend. Incident avoidance is exposure, not a saving, and we do not multiply it by an invented probability.
Measured, not modelled · 31 October 2026
What it saves, from runs we can point at.
193 of 2,070
tool calls were duplicates
In one long agent session. Together with 136 failure-shaped results that is an upper bound of 16% of its $3.19 cost, $0.51. An inventory, not a bill we saved.
28×
one looped task cost
A retrying task burned 37,150 tokens against 1,332 for the same task minutes later. That spread is what a step or repeat ceiling ends.
+66%
median tokens when a refusal lands on wanted work
Refusing an action the agent needed costs tokens, so the ceiling is the point, not the refusal. Watching in observe mode costs +9.7%.
We publish no average savings percentage, because we have not measured one that survives its own noise: a refusal only pays when it ends a loop, and it costs+66% when it lands on work you wanted. The report shows your numbers, from your sessions, with the date on them.
The limits, stated here.
- A local ledger key sits beside the log. It proves the file was not edited, not that a human authorised anything.
- A local receipt proves one entry offline against the key that signed it; a stranger still has to trust that key. Hosted evidence verifies against published keys.
- Local mode has no cross-device approval and no revocation beyond deleting the directory.
Verification by a stranger needs the hosted plane, where a receipt is signed by Attesso and verifies against published keys. Human approval over exact terms is built for the payments product; it is not wired into a Bounds decision yet, and nothing above should be read as if it were.
What it costs when it stops something.
- Free and unlimited on your own machine. Rules, ledger, report, hook; nothing metered.
- $0.00085 per synced decision when the record has to leave your laptop, about $34 a month for a developer running 40,000 agent calls.
- No plan, no seats, no minimum. $2 of credit to start, about 2,350 decisions, no card.
Synced means a receipt Attesso signed, verifiable by someone who trusts neither you nor us. Decisions made offline are never metered. Volume and platform contracts: contact sales.
A local key proves integrity. Ours proves it to a stranger.
| Method | What it proves | Where it fits |
|---|---|---|
| Local Ed25519 key | The ledger was not edited, and one entry proves offline | Free, on your machine |
| Attesso attestation (ES256) | Names the window you synced, its rows and your own signature; a stranger checks it against published keys | Hosted, per synced window |
| Human approval (WebAuthn) | A person approved these exact terms | Through a Mandate you create separately |
Each hosted sync returns an envelope over the window it stored and the CLI keeps it in .attesso/attestations/; attesso coverage --jwks jwks.json verifies every one of them offline and exits non-zero on the first that does not.
A receipt names which signer it carries. A record claiming human authority must carry a WebAuthn assertion; a local or CI key is not interchangeable with one, and the verifier refuses the combination. A Bounds decision carries its own key signature today; the passkey assertion lives in the Mandate that authorizes the action.
Commands and refusal codes: docs.attesso.com/bounds. Install from npmjs.com/package/attesso, read the source at github.com/Attesso/bounds.
Install it and watch it refuse.
Free on your machine, no account. $0.00085 per synced decision when the record has to travel.