Skip to content

feat: add aggregate /.well-known/x402 and external buyer-tool compat - #806

Open
HananINouman wants to merge 7 commits into
mainfrom
feat/external-buyer-tool-compat
Open

feat: add aggregate /.well-known/x402 and external buyer-tool compat#806
HananINouman wants to merge 7 commits into
mainfrom
feat/external-buyer-tool-compat

Conversation

@HananINouman

@HananINouman HananINouman commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes Obol Stack storefront offers work with external x402 buyers — especially Merit Systems (AgentCash / x402scan / Poncho) and Bankr — via discovery docs, verifier hardenings, type-specific buy prompts, and flow-22.

Merit discovery (AgentCash / Poncho / x402scan)

Merit products share one discovery convention:

  1. Primary: /openapi.json with per-op x-payment-info
  2. Fallback: /.well-known/x402 for crawlers that don’t parse OpenAPI

This PR adds aggregate public /.well-known/x402, keeps/strengthens OpenAPI x-payment-info, defaults undeclared paid HTTP ops to GET (AgentCash-friendly), and documents both surfaces in skill.md / catalog.

Why AgentCash and Poncho share a flow: both are Merit. Poncho (tryponcho.com) is consumer chat; AgentCash is the micropayment/wallet layer. Same discovery → same 402 → sign → retry. Storefront pills differ mainly by “paste into AgentCash vs Poncho.” Live Base tests: both paid our HTTP offer successfully.

Bankr (live Base mainnet)

Bankr chat / CLI / Apps are different clients. Docs mention discovery-index / Apps allowedHosts, but allowlisting alone does not fix agents: we built a Bankr App with pay:x402 + allowedHosts for our tunnel and bankr.x402.fetch against bounty-radar — payment often verified, then the App failed with rpc timeout ~30s while the agent was still running. HTTP through the same App/chat path usually works (~1s).

Tried HTTP Agent
Chat / Max Mode auto-pay OK Fail / misleading
bankr x402 call Usually OK ~30s 504
Apps bankr.x402.fetch (with allowlist) Can verify rpc timeout after verify
bankr wallet sign + curl ≥180s OK OK (proven)

Two failure modes: (A) voucher (validAfter=now / bad sig → verify reject, usually no charge); (B) timeout/zombie (verify OK, client aborts ~30s; older sellers could still settle → on-chain charge). Seller side: skip settle on disconnect/write error/empty SSE; better facilitator error labels; dual CAIP-2+legacy accepts[]; PAYMENT-SIGNATURE + v=0/1→27/28; structured post-verify upstream errors.

Prompts we publish: HTTP → Bankr chat auto-pay; agent/inference → forbid chat/Apps/x402 call, teach bankr wallet sign + curl --max-time 300 with past validAfter and stream:true.

Storefront / CI / docs

  • Buyer pills: AgentCash · Poncho · Bankr · Another AI (buyprompts/api/services.json)
  • flow-22-external-buyer-compat.sh + generic x402 SDK buyer; release-smoke hook
  • docs/observability.md, CLAUDE.md pitfall 23, buy-x402 skill note

Test plan

  • Roll controller + x402-verifier + public-storefront from this branch
  • GET <tunnel>/.well-known/x402 + OpenAPI x-payment-info on paid ops
  • Storefront pills; HTTP Bankr = chat; agent Bankr = wallet-sign + curl
  • AgentCash + Poncho: pay HTTP (and agent with long timeout)
  • Bankr: HTTP chat OK; agent Apps/chat expected timeout; wallet-sign+curl ≥180s OK
  • Abort mid-agent stream → no settle (no zombie Transfer)
  • go test ./internal/buyprompts/ ./internal/x402/ ./internal/serviceoffercontroller/
  • Optional: flow-22 (rebuild controller first)

Poncho chat, agent offer

Screenshot 2026-08-05 at 9 23 38 PM

Bankr wallet+cursor curl, agent offer

Screenshot 2026-08-05 at 9 24 12 PM

Agentcash(skill/cli/mcp) connected to cursor , agent offer

Screenshot 2026-08-05 at 9 25 38 PM

Bankr chat, http offer

Screenshot 2026-08-05 at 9 26 02 PM Screenshot 2026-08-05 at 9 39 44 PM

HananINouman and others added 2 commits August 2, 2026 20:03
Publish AgentCash/x402scan discovery fallback on the shared storefront,
surface AgentCash/Bankr buy prompts, and gate the path with flow-22
(generic x402 SDK + agent chat-completions) in release-smoke.

Co-authored-by: Cursor <cursoragent@cursor.com>
Skip settle on client disconnect/write errors, classify facilitator rejections,
and teach HTTP buyers Bankr chat auto-pay while agent/inference use wallet-sign
plus long curl after live timeout and voucher failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread internal/x402/forwardauth.go Fixed
Comment thread internal/x402/forwardauth.go Fixed
Comment thread internal/x402/forwardauth.go Fixed
Comment thread internal/x402/forwardauth.go Fixed
Publish type-specific Poncho chat prompts alongside AgentCash/Bankr and
surface them in the storefront pill selector after a successful live pay test.

Co-authored-by: Cursor <cursoragent@cursor.com>
@HananINouman
HananINouman marked this pull request as ready for review August 5, 2026 18:40
Record that a Bankr App with pay:x402 + allowedHosts still hit rpc timeout
on Base mainnet agent offers; drop the Sepolia digression and clarify
HandleProxy settle-skip vs ForwardAuth verify-only.

Co-authored-by: Cursor <cursoragent@cursor.com>
@HananINouman
HananINouman requested a review from bussyjd August 5, 2026 18:58
bussyjd added a commit that referenced this pull request Aug 6, 2026
…-rc2

Brings the aggregate /.well-known/x402 discovery doc and external
buyer-tool compat (Merit/AgentCash/Poncho, Bankr) into rc2.

Conflict resolution — both sides were additive, both kept:
- catalog.go: the static-site match/hash now folds in BOTH the widget's
  embedded chat-vendor.js (rc2) and the new x402.json (#806), so a stale
  copy of either re-applies the ConfigMap.
- forwardauth_test.go: kept TestBuildResourceURL_Scheme (rc2) alongside
  #806's brokenPipeWriter settle-skip tests.
- Widget-era test call sites updated for the new wellKnownX402JSON param.

Claude-Session: https://claude.ai/code/session_01PnhCQLz7CHuDBUhWd5xF8v
bussyjd added a commit that referenced this pull request Aug 6, 2026
…SON param

The #806 merge added a wellKnownX402JSON parameter to
buildStaticSiteConfigMap/staticSiteContentMatches, but four widget-era
call sites in catalog_test.go and hostoffer_test.go were left at the old
arity, so the package failed to build its tests. Pass "" (these tests
do not exercise the aggregate x402 document).

Claude-Session: https://claude.ai/code/session_01PnhCQLz7CHuDBUhWd5xF8v
bussyjd added a commit that referenced this pull request Aug 6, 2026
@bussyjd bussyjd mentioned this pull request Aug 6, 2026
…njection)

CodeQL flagged four new go/log-injection alerts introduced by this PR in
internal/x402/forwardauth.go: the buyer's payment payload and the
facilitator's reject reason reach log.Printf unescaped, so a crafted
value containing CRLF can forge additional lines in the operator's log
(e.g. a fake "payment settled successfully" entry).

Fix at the producers rather than at each log call, so future call sites
inherit it: paymentPayloadSummary, facilitatorRejectDetail and the
normalize note now return CR/LF-stripped strings, and truncateForLog
sanitizes too (it carries the raw facilitator /verify body).

Claude-Session: https://claude.ai/code/session_01PnhCQLz7CHuDBUhWd5xF8v
@bussyjd
bussyjd force-pushed the feat/external-buyer-tool-compat branch from 5e15e33 to a5d6972 Compare August 6, 2026 12:48
bussyjd added a commit that referenced this pull request Aug 6, 2026
…-rc2

Brings the aggregate /.well-known/x402 + external buyer-tool compat work
along with its CodeQL go/log-injection fix.

Conflict resolutions (both additive — kept BOTH sides, not one over the
other):
  * catalog.go — the static-site match and content hash now fold in both
    the widget's embedded chat-vendor.js (rc2) and the new x402.json
    (#806). Dropping either side would silently pin a stale copy of that
    asset across controller upgrades via the skip-when-unchanged path.
  * forwardauth_test.go — kept rc2's TestBuildResourceURL_Scheme
    alongside #806's brokenPipeWriter settle-skip tests.

Also updates four widget-era test call sites in catalog_test.go and
hostoffer_test.go for #806's new wellKnownX402JSON parameter (they pass
"" — those tests do not exercise the aggregate x402 document). Without
this the package does not build its tests.

Replaces the unsigned a128bdf/dd9c5a1d/cdee3a22 with a single signed
merge; the resulting tree is byte-identical to cdee3a2.

Claude-Session: https://claude.ai/code/session_01PnhCQLz7CHuDBUhWd5xF8v
HananINouman and others added 2 commits August 6, 2026 18:46
…ecks

Drop chatty framing, require AgentCash/Poncho tx receipts, and teach Bankr
agent buyers to reuse the full accepts[] entry to avoid unsupported_scheme.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants