Skip to content

v0.14.0-rc2 - Discoverable by buyers you didn't build for

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Aug 16:46
· 18 commits to main since this release
v0.14.0-rc2
b874a19

Obol banner

v0.14.0-rc2 - Discoverable by buyers you didn't build for

One /.well-known/x402 for the whole stack — and the compatibility work that lets AgentCash, Bankr, Poncho and any generic x402 SDK actually find and pay it.

Up to now a buyer had to already know one of your offers to pay it. rc2 publishes a single stack-level x402 discovery document at /.well-known/x402 on your shared storefront, listing every paid route across every ready offer. Point an external buyer tool at your storefront root and it can enumerate what you sell, then pay it.

Making that reachable meant meeting real buyer tools where they are, so the payment path picked up a round of compatibility and hardening: facilitator rejections are now classified (so buyers stop burning credits retrying errors that will never succeed), legacy network names are accepted alongside CAIP-2, and a streaming buyer whose connection dies mid-response is no longer debited for a stream they never received.

The rest of the cycle is operator-facing: safe branding previews that render through the real storefront without ever touching your public tunnel, and the running CLI version surfaced in the frontend footer.

Install with OBOL_RELEASE=v0.14.0-rc2 (command below) and put it through its paces before the tagged release.

Important

Behavior change: offers of type: http that do not declare methods on their paid route now advertise GET instead of POST in openapi.json, /skill.md and /.well-known/x402. Inference, agent and fine-tuning offers still default to POST. If your type: http service takes a JSON body, declare it explicitly — methods: [POST] on the paid route — before upgrading, or buyers will be told to call it the wrong way.

Note

Known issue: on streaming (SSE) responses the X-PAYMENT-RESPONSE settlement receipt is now delivered as an HTTP trailer rather than a header. This is a consequence of deferring settlement until the stream completes (which is what fixes the debit-after-disconnect bug below). Many proxies and HTTP clients do not surface trailers, so streaming buyers may not see a receipt even though settlement succeeded — verify on-chain if you need confirmation. Non-streaming responses are unaffected. We expect to revisit the delivery mechanism before the tagged release.

Warning

This software is early alpha, you could lose what you put in. Please use caution when it comes to non-testnet assets.

Install / Upgrade

# Install this release
OBOL_RELEASE=v0.14.0-rc2 bash <(curl -s https://stack.obol.org)

# Run the stack
obol stack init && obol stack up

# Check what your stack advertises to external buyers
curl -s https://<your-storefront>/.well-known/x402 | jq

Release Highlights

One discovery document for the whole stack

Your shared storefront now serves an aggregate x402 document at /.well-known/x402. It emits one resources[] entry per paid route across every operationally-ready offer, rooted at each offer's effective public path, in a stable namespace/name order.

Offers that are deleted, drained, or not yet ready are omitted, so the document only ever advertises routes a buyer can actually pay right now. Per-offer /.well-known/x402 documents on dedicated origins are unchanged — this is an addition, not a replacement.

External buyer tools can pay your endpoints

The storefront's buyer guidance grew a dedicated external tab with per-tool prompts for AgentCash, Bankr, Poncho and a generic x402 SDK client, replacing the old catch-all "other AI tools" section. The payment path itself picked up the compatibility fixes those tools need:

  • Facilitator failures are classified. A transport failure (facilitator_unreachable) is now distinguished from a facilitator that answered and rejected the payment. Previously both were reported as "unreachable", which sent buyer agents into loops of identical retries that could never succeed.
  • Legacy network aliases are advertised alongside CAIP-2 identifiers in accepts[], so buyers pinned to the older naming can still match a requirement.
  • The facilitator URL is echoed in the 402 body when it is safe to disclose, so a buyer can construct a payment without out-of-band configuration.
  • Payload tolerance: a resource sent as a plain string, and ECDSA signatures using v = 0/1 instead of 27/28, are both normalized before verification rather than rejected.

Don't debit a buyer who never got the stream

On streaming (text/event-stream) responses, settlement is now deferred until the response actually completes, and is skipped when the client disconnected, when writing to the client failed, or when no body ever reached them. Previously a buyer whose connection dropped mid-stream — a common Bankr/agent timeout — could still be charged for output they never received.

Safer operator branding previews

Storefront branding drafts now render through the real public storefront renderer instead of a duplicated preview UI, so what you see is what buyers get. Previews are session-only and pinned to storefront-preview.obol.stack — they never publish to your public tunnel — and that renderer survives teardown of the public catch-all. Branding is applied with server-side apply, so large inline logos no longer hit kubectl's 256 KiB last-applied annotation limit.

The running CLI version, in the UI

obol stack up and tunnel sync now write obolVersion into obol-stack-config and inject OBOL_STACK_VERSION into the frontend pod, so the web UI footer shows the CLI release actually running. Comes with tunnel fixes so publishing the version no longer prunes tunnelURL, and obol upgrade keeps the variable set.

Security

CodeQL flagged four go/log-injection paths in the ForwardAuth middleware: the buyer's payment payload and the facilitator's reject reason reached the operator log unescaped, so a crafted value containing CRLF could forge log lines — for example a fake "payment settled successfully" entry. Untrusted strings are now stripped of CR/LF at the producing functions, so any future log statement inherits the sanitization.


Breaking changes / Migration notes

  • type: http offers default to GET. See the callout above. Declare methods: [POST] explicitly on the paid route if your service takes a request body. Other offer types are unaffected.
  • Streaming settlement receipts moved to HTTP trailers — see the known-issue callout. If you have tooling that asserts on the X-PAYMENT-RESPONSE header for SSE endpoints, it needs to read trailers or fall back to on-chain verification.
  • Everything else upgrades in place with obol stack up. The aggregate /.well-known/x402 needs no configuration; it appears once the controller is upgraded.

What's Changed

As with rc1, the headline work landed through the integration branch (#809) rather than as individual merges to main, so it does not appear in the auto-generated list above:

  • feat: aggregate /.well-known/x402 + external buyer-tool compat (#806)
  • feat(storefront): secure operator previews and local-only preview publish (#805)
  • fix(x402): sanitize untrusted strings before logging — CodeQL go/log-injection (#806)
  • deps: bundled renovate updates and obol-frontend pinned to v0.1.28-rc5

This RC also carries everything from v0.14.0-rc1 — the agent chat widget, the opt-in auth-capture unlock gate, and the agent model-strip.

Note

rc1's notes listed the facilitator support for the auth-capture unlock gate as still pending. It has since landed: the hosted facilitator now runs beta-2.0.2 with the v2-eip155-auth-capture scheme enabled (obol-infrastructure#2997), so the gate is usable on this release. It remains opt-in and disabled by default — Obol takes no fee unless you configure authCaptureUnlock with your own feeRecipient and fee bps.

Full Changelog: v0.14.0-rc1...v0.14.0-rc2