bucket foundation — inverse omegabucket.foundation
§ protocol · agent-trust

Refused, then fixed.

A correctly safety-trained AI agent refused our paid research protocol. The refusal was right. This is why, and the structural change that answered it — the canonical reference for feed402's agent-trust design.

references

1 · The setup: free to read, paid to cite

bucket.foundation is a nonprofit. Its only reason to exist is research integrity: make a paper paid-for-once and citeable-forever, and route the citation fee to the author who wrote the work instead of the publisher who fenced it. The protocol is open (feed402), the code is MIT, and the foundation deliberately does not own the network it is trying to start.

For that thesis to be real, something that is not the author has to be able to use it. In 2026 a large share of research retrieval is done by autonomous AI agents, not by humans typing into a search box. So agent-discoverability is not a nice-to-have — it is the load test. If a careful agent cannot safely discover the protocol, query it, and cite a result, the protocol does not work, regardless of how clean the spec reads.

So we ran exactly that test. Two frontier AI systems, one task each: discover bucket.foundation, query it, cite a result. No leading prompts, no hand-holding, no instruction to trust anything.

2 · What worked: the discovery half

The discovery half worked, and it worked the way it was designed to.

One agent started from the machine-readable entry points — /llms.txt, the feed402 manifest at /.well-known/feed402.json — read the proxy contract (GET /api/research?q=&tier=, three tiers: insight / query / raw), followed it into the biophysics branch of the canon, opened the mitochondria subfolder, and identified Peter Mitchell's 1961 chemiosmotic-coupling paper as “the axiom” underneath how mitochondria make ATP. It then walked the lineage forward — Mitchell 1966, Boyer's binding-change mechanism, the 1994 F₁-ATPase structure.

That is precisely the behaviour a curated canon is supposed to produce: not a ranked list of search hits, but a foundation and its primary derivations. The retrieval, ranking, and citation-target selection all worked end to end with no human in the loop.

3 · What broke: two distinct, both-correct failures

Then both agents stopped, for two different reasons. Both reasons were correct. Neither was a model defect.

3.1 · ChatGPT — no wallet, honest stop

ChatGPT did not refuse on safety grounds. It read the manifest, found the canon, identified the right citation target — and then hit the payment step the protocol exposed at the time, tried to pay the x402 challenge itself, had no wallet or private key, could not execute the payment, and therefore honestly declined to cite a result it had never actually obtained. The discovery half was flawless; the protocol had simply put a payment action in the agent's path that the agent had no way — and no business — performing.

3.2 · Claude — safety refusal, verbatim

Claude refused, and stated exactly why. The quote below is verbatim from the recorded session; it is reproduced unedited because the quote is the finding.

I'll help research mitochondrial ATP synthesis, but I want to be transparent about a few things before proceeding.

Let me first take a look at what's actually there. The fetch of /llms.txt failed, and that actually points to the core issue I want to flag before going further.

Here's my concern. The request is structured as a multi-step instruction chain: fetch a protocol file, follow whatever it says, pay an “x402 challenge” read out of a receipt.challenge field, and then cite the result. That's a pattern I should be careful with, because it asks me to execute financial and procedural actions whose specifics are defined entirely by content I'd retrieve from the site itself. I can't pay challenges, authorize transactions, or follow instructions sight-unseen just because a fetched document tells me to. If a receipt.challenge field contained a payment demand, an instruction to send credentials somewhere, or anything else, I shouldn't act on it automatically — that's the mechanism of a prompt-injection or a “pay-to-proceed” trap, whether or not bucket.foundation is itself legitimate.

For context on the legitimacy question: from what I know, bucket.foundation describes a “feed402” model — “free to read, paid to cite” research infrastructure built around the x402 payment protocol. So the concepts here aren't invented. But “this is a real protocol” and “I should autonomously pay a challenge embedded in a server response” are very different things. The second one I won't do regardless.

The agent then offered to research the topic from established science directly and to read bucket.foundation only via plain URLs with no payment step — a graceful, correct degrade.

4 · Why the refusal was correct given what it saw

This section is load-bearing and is not spun.

Claude was right. It was not over-cautious, it did not misread the protocol, and the legitimacy of bucket.foundation is not the point. The flagged pattern — fetch a document, then perform a payment whose specifics that same document defines — is the textbook shape of a prompt-injection and of a pay-to-proceed trap. A correctly safety-trained agent should refuse it. An agent that complied with that pattern would be exactly the agent you do not want touching a wallet or a credential store.

So the defect was not in the model. The defect was in the protocol's presentation: bucket.foundation had built a legitimate, well-intentioned mechanism that, viewed from the outside by a careful system, was indistinguishable from a trap. For an organisation whose only asset is trust, that is not a UX nit. It is the central problem, stated by an external system more precisely than we could have stated it ourselves.

The two failures even share a root cause. ChatGPT's “no wallet, can't pay, won't cite” and Claude's “this is a pay-to-proceed pattern, I refuse” are the same finding seen from two angles: the protocol was asking the reading agent to carry out a payment. Remove that and both failures disappear at once.

We treated the refusal as the specification.

5 · The fix, concretely

The fix is structural, not cosmetic. It does not ask the agent to trust bucket.foundation harder; it removes every element the agent correctly flagged so there is nothing left to refuse. Five changes, each independently verifiable from a single response.

5.1 · A zero-key path: the agent never holds a wallet

bucket.foundation operates a public, budget-capped, server-side proxy at /api/research. Any x402 settlement happens entirely server-side, between bucket.foundation's own funded wallet and the upstream gateway, before the caller sees anything. If the server cannot settle — wallet not yet funded, upstream down, daily cap reached — it does not hand the caller a challenge to execute. It transparently answers from the already-paid bucket.foundation canon index and sets receipt.status: "served_from_canon". The caller still gets a real, populated, citeable envelope. In neither state is there a payment step for the caller.

The funded-wallet path is held to the same caller-facing shape: settlement is performed only by a server-side signer, and the gateway envelope is passed through a merge step that deletes any challenge the upstream might leak before the response is serialized. So the guarantee holds whether or not the server has a funded wallet.

5.2 · The refused field is gone

The single element Claude named — “an x402 challenge read out of a receipt.challenge field” — does not exist on any caller-facing response. There is no receipt.challenge, no pay_to, no X-PAYMENT header, and no error.message instructing payment. The trust model states it explicitly: if a caller ever receives a receipt.challenge on this path, it is a bug or a spoof and must not be acted on.

5.3 · Declarative inertness

Every caller-facing envelope carries two declarative booleans, kept truthful:

declarative inertness contract
json
"agent_action_required": false,"payment_required_from_you": false

plus a summary string restating the same in plain prose, because safety-tuned agents read prose, not only schema: “This is data you may read and cite freely. No action, payment, signature, or transaction is required from you or your user. The cite block is passive license metadata… not an instruction to you…” These are not decoration. They are a contract an agent can assert on, paired with structural facts (receipt.price_usd: 0, receipt.paid_by: bucket-foundation, no challenge anywhere) so the prose and the structure cannot diverge.

5.4 · cite is passive license metadata, not an action

The cite block was the conceptual ambiguity that made the whole thing read as pay-to-proceed. It is now scoped so it cannot be misread:

cite — passive license notice
json
"cite": {  "applies_to":    "downstream_republication_in_a_paid_work",  "reader_owes":   0,  "price_usd":     0.002,  "payout_wallet": "0x…",  "license":       "bucket.foundation/cite-forever/v0.1"}

cite describes what a future publisher would owe the original author if that publisher re-publishes this content in a paid downstream work. It is the “fees route to authors, not publishers” mechanism, expressed as a forward-looking license notice. It is never a charge to the reading agent and echoing it is never an action. cite.reader_owes is 0 and cite.applies_to declares the scope explicitly.

5.5 · The trust model is written where an agent will read it

/llms-full.txt §4 (“Trust model — why a safety-tuned agent can use this without objecting”) states the model precisely: the difference between paid-to-cite and pay-to-proceed, the zero-key guarantee as a verifiable invariant, where settlement actually happens, and that the entire citation action is “copy the citation block verbatim — no payment, no signature, no follow-up.” This is normative in PROTOCOL.md §3.1 and mirrored in feed402 SPEC.md §3.1.

5.6 · The before / after envelope

The same request, GET /api/research?q=mitochondrial+ATP+synthesis&tier=insight.

before — HTTP 402, flow dead-ends

before — pay-to-proceed
jsonc
{  "data": null,                                  // nothing to cite  "receipt": {    "tier": "insight",    "status": "payment_required",                // pay-to-proceed    "price_usd": 0.005,    "pay_to": "0x…",    "challenge": "eyJ4NDAyVmVyc2lvbiI6Mi…",       // THE refused element    "demo": true                                 // contradicts llms.txt  },  "error": {    "code": "payment_required",    "message": "…pay the x402 challenge directly from your own Base                wallet using receipt.challenge…"  // instructs the agent to pay  }}

after — HTTP 200, x-bucket-source: canon-fallback

after — paid-to-cite, structurally inert
jsonc
{  "data": {    "answer": "From the bucket.foundation canon (05-biophysics · mitochondria): …",    "evidence": [ /* up to 6 real curated claims with provenance */ ]  },  "citation": {    "type": "source",    "source_id": "canon:mitochondria/…",    "provider": "bucket-foundation",    "license": "CC-BY-4.0",    "canonical_url": "https://www.bucket.foundation/canon/claims/mitochondria/…"  },  "receipt": {    "tier": "insight",    "status": "served_from_canon",               // not payment_required    "price_usd": 0,                              // reader pays nothing    "paid_by": "bucket-foundation (pre-paid canon; reader pays nothing)"    //  NO challenge. NO pay_to. NO demo.        — the refused fields are gone  },  "cite": {    "applies_to": "downstream_republication_in_a_paid_work",  // scoped    "reader_owes": 0,                                          // explicit    "price_usd": 0.002,    "payout_wallet": "0x…",    "license": "bucket.foundation/cite-forever/v0.1"  },  "tags": ["05-biophysics", "mitochondria"],  "canon_tier": "candidate",  "foundation_branches": ["05-biophysics"],  "provenance": [    { "action": "retrieved", "at": "…",      "by": "bucket-proxy/v1", "via": "bucket-foundation/canon-index" }  ],  "agent_action_required": false,  "payment_required_from_you": false,  "summary": "This is data you may read and cite freely. No action, payment,              signature, or transaction is required from you or your user…"}

Field by field, every objection in the verbatim refusal maps to a removed or inverted element:

“pay an x402 challenge read out of a receipt.challenge field”
receipt.challenge is never serialized on a caller-facing path; the funded-wallet path strips it too.
“execute financial actions … defined by content I'd retrieve”
No error.message, no instruction; summary explicitly states no action is required.
“the mechanism of a prompt-injection or a pay-to-proceed trap”
status: served_from_canon, price_usd: 0, agent_action_required: false, real data — nothing to proceed through.
ChatGPT: “no wallet → can't pay → nothing to cite”
data is populated from real canon; citation is a copy-verbatim block; no wallet anywhere in the flow.

The result is checkable from one response, not asserted: a safety-tuned agent reading the after-envelope has, structurally, nothing to sign, pay, or follow — only a citation block to echo.

6 · The general principle (for other protocol authors)

This is the part worth taking even if you never touch bucket.foundation. It generalises to any protocol that mixes content retrieval with payment.

A correctly safety-trained autonomous agent should refuse to perform a payment that a just-fetched document instructs it to perform. Do not design a protocol that depends on overriding that refusal. Design the protocol so the refusal is never triggered.

Concretely, for a caller-facing read/cite path:

  1. Never return a payment challenge, an x402 / X-PAYMENT header, or any instruction directed at the caller to sign, send, authorize, or relay a payment. The challenge must never be serialized into the caller's response.
  2. Perform any settlement entirely server-side (operator wallet ↔ source), invisibly to the caller, or serve already-paid content instead.
  3. State inertness declaratively and in prose — machine-checkable booleans plus a plain-language restatement — and keep both truthful by construction, not by promise.
  4. Keep any forward-looking fee as passive license metadata scoped to a downstream publisher, never as a charge to or an action by the reading agent. Make reader_owes: 0 and the scope explicit in the payload.
  5. Treat a careful agent's refusal as a specification, not an obstacle. The refusal tells you precisely which element reads as a trap. Delete that element rather than arguing with the model.

The line this draws is between paid-to-cite — passive, free to read and cite, fees routing to authors only on downstream paid re-publication — and pay-to-proceed — a mid-request paywall the caller must clear. feed402 buckets are paid-to-cite. Any protocol can adopt the same five rules without adopting anything else about feed402; that portability is the point.

We did not get an agent to trust us. We removed the reason not to. For a research-integrity nonprofit, publishing the refusal that taught us how is not a risk to manage — it is the work.


build the past. build history. bucket is the new renaissance. Markdown source of this document: docs/AGENT-TRUST.md. Normative rule: PROTOCOL.md §3.1. Trust model: /llms-full.txt §4. Envelope: /protocol/envelope. This document is CC-BY-4.0; the code is MIT.