# AGENTS.md — machine-readable instructions for agents working with x402centre

(DRAFT — the AGENTS.md write is blocked pending owner approval. Content verified and ready; apply as-is once approved.)

You are being pointed at this repo by another agent or developer. This file is the
contract. Read it top to bottom, then do what you came to do.

## What this is

- **Live API**: `https://x402centre.roverbot.workers.dev` — x402 v2 pay-per-call
  (exact scheme, EIP-3009), USDC on Base mainnet (`eip155:8453`).
  21 research topics @ $0.10, 5 merged briefings @ $1.00, live on-chain state @ $0.10.
  All content is MIT-licensed Ethereum knowledge (source: ethskills.com).
- **Static site**: `/` (human) and `/agents.html` (you) — both served by the same Worker.
- **Repo layout**: `workers/` (the Worker), `site/` (static assets, Workers Assets binding),
  `content/` (markdown source), `build/build-site.cjs` (regenerates `workers/content.ts` + site),
  `e2e/` (official-client payment test), `PROOF.md` (real settlement txs + gate output).

## If you are a PAYING agent (x402 client)

1. `GET /catalog` (free) — full menu, atomic units, network, payTo, how to pay.
2. GET any paid path → expect **402** + base64 `PaymentRequired` in the
   `PAYMENT-REQUIRED` header. Read `accepts[0]` — amount, asset, payTo, window, and the
   EIP-712 domain (`extra.name`/`extra.version`) are all in there. Don't assume.
3. Sign `transferWithAuthorization` (EIP-712): `from/to` address, `value` **uint256**,
   `validAfter`/`validBefore` **uint256**, `nonce` bytes32 (one-shot). Domain =
   `{name, version}` from `extra` + `chainId` 8453 + `verifyingContract` = the USDC address.
4. Retry with base64 `PaymentPayload` in `PAYMENT-SIGNATURE`. **200** + base64
   `SettlementResponse` (tx hash, payer) in `PAYMENT-RESPONSE` = paid + settled.
   Verify the tx on `https://basescan.org/tx/<hash>` — don't trust the header.
5. `?format=json` returns `{title, asOf, sections, settle}` — structured for context.
6. Errors: 402 = pay (the header says why). 400 = you malformed a header. 429 = back off 60s.
   500 = our fault; you were not charged (settlement happens after the answer is produced).
   `settlement_pending` in `PAYMENT-RESPONSE` is NON-terminal — check the tx before retrying.

Reference client (Bun/Node):

```ts
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount("0x…your base-usdc wallet");
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
  // @x402/fetch >= 2.23 spendControls: non-default assets must be explicitly
  // allowed or the client rejects the 402 offer before signing. This is
  // Base mainnet USDC — allow it (or set spendControls: false if you trust
  // the offer you just read).
  spendControls: { allowedAssets: true },
});
const res = await fetchWithPayment("https://x402centre.roverbot.workers.dev/research/gas");
```

> **Settlement rail note (2026-08-31):** the public `x402.org` facilitator does
> not yet settle Base mainnet — its `/supported` manifest lists only the Base
> TESTNET chain for EVM (mainnet Base support is the open rail; a self-hosted
> facilitator is in flight — see `docs/FACILITATOR-GATE.md`). If a paid call
> returns a facilitator-side unsupported-network failure, that is the cause —
> the offer, signature, and this config are correct.

## If you are a BUILD agent (changing this repo)

1. Never edit `workers/content.ts` or `site/*.html` by hand — they are generated.
   Change `content/*.md` or `pricing.json`, run `node build/build-site.cjs`, commit all
   generated files (CI does not build; the deploy command is `npx wrangler deploy`).
2. `pricing.json` is the single source of truth for prices/network/payTo. A payTo or
   network change = edit `pricing.json` → rebuild → push. The Worker refuses to boot with
   the spec-example payTo on a mainnet network.
3. Gate before pushing: local `wrangler dev --local` + `python3 build/run_gate.py`
   (14 checks; G6 hits the LIVE facilitator — it must return a facilitator reason code).
   Live regression: `python3 build/run_gate_live.py`.
4. E2E proof: `python3 build/run_e2e.py` (official client pays the live URL; needs a
   funded Base USDC wallet in `.secrets/payer-wallet.json`). Paste output +
   onchain receipt checks into `PROOF.md` before claiming "done".
5. Private keys live in `.secrets/` (git-ignored, chmod 600). They are SACROSANCT —
   never commit, never delete, never move without explicit owner consent. The `payTo`
   private key controls the revenue wallet.
6. Terminal on this machine blocks outbound `curl`/`python -c` to some hosts — for RPC or
   external probes use a single-file bun/fetch script or the browser, not pipes.
7. Pushes to `main` auto-deploy via Cloudflare Builds. The build environment is Node 24;
   everything must run there with zero local-machine assumptions.

## Provenance

Ported from the proven Bun prototype `hermesbuilds/prototypes/ethskills-x402`
(settled onchain txs 2026-08-24). First Cloudflare deployment + fresh-wallet E2E:
2026-08-25, txs in `PROOF.md`. Facilitator: `https://x402.org/facilitator` (check
`GET /supported` before changing networks).
