Skip to content

Commit a78999f

Browse files
MajorTalclaude
andcommitted
Add MPP tests, docs, and version bump to 1.14.0
- 5 new mock e2e tests: init mpp, allowance status/balance/fund in MPP mode, switch back - Tempo RPC mock (tempo_fundAddress, pathUSD balance) - CLI help: mention init mpp, MPP rail - SKILL.md: document dual-rail (x402 + MPP) - OpenClaw SKILL.md: mention MPP - Bump version 1.13.5 → 1.14.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 127d364 commit a78999f

5 files changed

Lines changed: 116 additions & 15 deletions

File tree

SKILL.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: run402
3-
description: Provision and manage AI-native Postgres databases with REST API, auth, storage, and row-level security. Prototype tier is free (testnet). Paid tiers use x402 USDC on Base or Stripe credits.
3+
description: Provision and manage AI-native Postgres databases with REST API, auth, storage, and row-level security. Prototype tier is free (testnet). Paid tiers use x402 USDC on Base, MPP pathUSD on Tempo, or Stripe credits.
44
metadata:
55
openclaw:
66
emoji: "🐘"
@@ -17,7 +17,11 @@ metadata:
1717

1818
# Run402 — Postgres for AI Agents
1919

20-
Run402 gives you a full Postgres database with a REST API, user auth, file storage, and row-level security. The prototype tier is free — you pay with testnet USDC to test the x402 flow end-to-end, no real money needed. Higher tiers (hobby, team) cost real money, payable with USDC on Base or Stripe credits. No signups, no human approval needed.
20+
Run402 gives you a full Postgres database with a REST API, user auth, file storage, and row-level security. The prototype tier is free — you pay with testnet USDC to test the payment flow end-to-end, no real money needed. Higher tiers (hobby, team) cost real money, payable with USDC on Base (x402), pathUSD on Tempo (MPP), or Stripe credits. No signups, no human approval needed.
21+
22+
Two payment rails are supported:
23+
- **x402** (default): USDC on Base Sepolia (testnet) or Base mainnet. Standard HTTP 402 protocol.
24+
- **MPP**: pathUSD on Tempo Moderato (testnet). Stripe's Machine Payments Protocol. Same wallet key works on both chains.
2125

2226
One tool call. One payment. You get back `anon_key`, `service_key`, and a project ID. Start creating tables immediately.
2327

@@ -308,7 +312,7 @@ run_sql(project_id: "prj_...", sql: "SELECT count(*) FROM todos")
308312

309313
## Payment Handling
310314

311-
Run402 uses the x402 HTTP payment protocol. Here's what you need to know:
315+
Run402 supports two payment protocols: **x402** (USDC on Base) and **MPP** (pathUSD on Tempo). Both use the same wallet key. Here's what you need to know:
312316

313317
**When payment is needed:** Only `provision_postgres_project` and `renew_project` require x402 payment. All other tools (run_sql, rest_query, upload_file) use stored project keys — no payment needed.
314318

@@ -327,7 +331,7 @@ Run402 uses the x402 HTTP payment protocol. Here's what you need to know:
327331
| Hobby | $5.00 | 30 days | 1 GB | 5,000,000 | 25 | 30s | 256MB | 50 |
328332
| Team | $20.00 | 30 days | 10 GB | 50,000,000 | 100 | 60s | 512MB | 200 |
329333

330-
Prototype uses Base Sepolia testnet USDC — no real money needed. Get test USDC from the faucet. Hobby and Team require real payment via USDC on Base or Stripe credits.
334+
Prototype uses testnet tokens — no real money needed. With x402: Base Sepolia USDC from the faucet. With MPP: Tempo Moderato pathUSD from the Tempo faucet (instant, no rate limit). Hobby and Team require real payment via USDC on Base, pathUSD on Tempo, or Stripe credits.
331335

332336
**Budget enforcement:** When a project hits its tier's API call or storage limit, REST/SQL calls return 402 with usage details and a renew URL. Suggest renewing the project at the same or higher tier.
333337

@@ -362,15 +366,22 @@ Prototype uses Base Sepolia testnet USDC — no real money needed. Get test USDC
362366

363367
## Agent Allowance Setup
364368

365-
To pay Run402, the user needs an agent allowance with USDC on Base. If they don't have one yet, here are the options:
369+
To pay Run402, the user needs an agent allowance. Two payment rails are available:
366370

367-
**Option A: Coinbase AgentKit (recommended)** — Gives you an allowance on Base with built-in x402 support. No KYC, no manual key management.
371+
**x402 rail (default):** USDC on Base. Set up with `run402 init`.
372+
- Prototype: Base Sepolia testnet USDC (free from faucet)
373+
- Hobby/Team: real USDC on Base mainnet
368374

369-
**Option B: AgentPayy** — Auto-bootstraps an MPC wallet on Base using Coinbase CDP. Purpose-built for x402.
375+
**MPP rail:** pathUSD on Tempo. Set up with `run402 init mpp`.
376+
- Prototype: Tempo Moderato testnet pathUSD (free from faucet, instant, no rate limit)
377+
- Hobby/Team: real pathUSD on Tempo mainnet
370378

371-
**Option C: x402 OpenClaw Skill** — Install the x402 skill from ClawHub for x402 payment capabilities.
379+
The same wallet key works on both chains — switching rails just changes which chain is used for payments.
372380

373-
**Prototype (free):** Use Base Sepolia testnet. Get free test USDC from the faucet (`request_faucet`) or Circle. No real money needed — the goal is to test the x402 payment flow end-to-end.
381+
**Additional setup options:**
382+
- **Coinbase AgentKit** — Gives you an allowance on Base with built-in x402 support
383+
- **AgentPayy** — Auto-bootstraps an MPC wallet on Base using Coinbase CDP
384+
- **x402 OpenClaw Skill** — Install the x402 skill from ClawHub for x402 payment capabilities
374385

375386
**Hobby/Team (real money):** Fund the allowance with USDC on Base mainnet, or buy credits via Stripe. The simplest path: download Coinbase Wallet, buy USDC, send to the allowance address. Base transactions cost under $0.01.
376387

cli-e2e.test.mjs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ function noContent() {
4747

4848
// USDC balance as ABI-encoded uint256 (250000 = 0.25 USDC)
4949
const USDC_BALANCE_HEX = "0x" + "0".repeat(58) + "03d090";
50+
// pathUSD balance as ABI-encoded uint256 (1000000 = 1.00 pathUSD)
51+
const PATHUSD_BALANCE_HEX = "0x" + "0".repeat(59) + "f4240";
52+
const TEMPO_RPC_URL = "https://rpc.moderato.tempo.xyz/";
5053
let rpcCallCount = 0;
54+
let tempoRpcCallCount = 0;
5155

5256
function mockFetch(input, init) {
5357
// Handle Request objects (x402 library may pass these)
@@ -72,6 +76,31 @@ function mockFetch(input, init) {
7276
body = rawBody;
7377
}
7478

79+
// ── Tempo Moderato RPC (pathUSD balance, faucet) ──
80+
if (url === TEMPO_RPC_URL && body?.jsonrpc === "2.0") {
81+
tempoRpcCallCount++;
82+
if (body.method === "tempo_fundAddress") {
83+
return Promise.resolve(json({ jsonrpc: "2.0", result: ["0xtx1", "0xtx2", "0xtx3", "0xtx4"], id: body.id }));
84+
}
85+
if (body.method === "eth_call") {
86+
// Return 0 for first call (before faucet), positive for subsequent
87+
const balance = tempoRpcCallCount <= 1 ? "0x0" : PATHUSD_BALANCE_HEX;
88+
return Promise.resolve(json({ jsonrpc: "2.0", result: balance, id: body.id }));
89+
}
90+
if (body.method === "eth_chainId") {
91+
return Promise.resolve(json({ jsonrpc: "2.0", result: "0xa5bf", id: body.id }));
92+
}
93+
if (Array.isArray(body)) {
94+
const results = body.map(req => {
95+
if (req.method === "eth_call") return { jsonrpc: "2.0", result: PATHUSD_BALANCE_HEX, id: req.id };
96+
if (req.method === "eth_chainId") return { jsonrpc: "2.0", result: "0xa5bf", id: req.id };
97+
return { jsonrpc: "2.0", result: "0x0", id: req.id };
98+
});
99+
return Promise.resolve(json(results));
100+
}
101+
return Promise.resolve(json({ jsonrpc: "2.0", result: "0x0", id: body.id }));
102+
}
103+
75104
// ── Viem JSON-RPC calls (eth_call for USDC balance, eth_chainId, etc.) ──
76105
if (body?.jsonrpc === "2.0") {
77106
rpcCallCount++;
@@ -820,4 +849,63 @@ describe("CLI e2e happy path", () => {
820849
assert.ok(data.allowance.address, "should include allowance address");
821850
assert.ok(Array.isArray(data.projects), "should include projects array");
822851
});
852+
853+
// ── MPP rail ─────────────────────────────────────────────────────────────
854+
855+
it("init mpp (switch to MPP rail)", async () => {
856+
tempoRpcCallCount = 0; // reset for fresh faucet flow
857+
const { run } = await import("./cli/lib/init.mjs");
858+
captureStart();
859+
await run(["mpp"]);
860+
captureStop();
861+
const out = captured();
862+
assert.ok(out.includes("Tempo"), "should show Tempo network");
863+
assert.ok(out.includes("pathUSD"), "should show pathUSD");
864+
assert.ok(out.includes("mpp"), "should show mpp rail");
865+
// Verify rail saved
866+
const allowance = JSON.parse(readFileSync(join(tempDir, "allowance.json"), "utf-8"));
867+
assert.equal(allowance.rail, "mpp", "rail should be mpp");
868+
});
869+
870+
it("allowance status (MPP rail)", async () => {
871+
const { run } = await import("./cli/lib/allowance.mjs");
872+
captureStart();
873+
await run("status", []);
874+
captureStop();
875+
assert.ok(captured().includes("mpp"), "should show mpp rail");
876+
});
877+
878+
it("allowance balance (MPP rail)", async () => {
879+
const { run } = await import("./cli/lib/allowance.mjs");
880+
captureStart();
881+
await run("balance", []);
882+
captureStop();
883+
const out = captured();
884+
assert.ok(out.includes("tempo-moderato_pathusd_micros"), "should show Tempo balance");
885+
assert.ok(out.includes("mpp"), "should show mpp rail");
886+
});
887+
888+
it("allowance fund (MPP rail)", async () => {
889+
tempoRpcCallCount = 0; // reset so first call returns 0, faucet tops up
890+
const { run } = await import("./cli/lib/allowance.mjs");
891+
captureStart();
892+
await run("fund", []);
893+
captureStop();
894+
const out = captured();
895+
assert.ok(out.includes("tempo-moderato_pathusd_micros"), "should show Tempo fund result");
896+
assert.ok(out.includes("mpp"), "should show mpp rail");
897+
});
898+
899+
it("init (switch back to x402)", async () => {
900+
const { run } = await import("./cli/lib/init.mjs");
901+
captureStart();
902+
await run([]);
903+
captureStop();
904+
const out = captured();
905+
assert.ok(out.includes("Base Sepolia"), "should show Base Sepolia network");
906+
assert.ok(out.includes("x402"), "should show x402 rail");
907+
// Verify rail switched back
908+
const allowance = JSON.parse(readFileSync(join(tempDir, "allowance.json"), "utf-8"));
909+
assert.equal(allowance.rail, "x402", "rail should be x402");
910+
});
823911
});

cli/cli.mjs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Usage:
1919
run402 <command> [subcommand] [options]
2020
2121
Commands:
22-
init Set up allowance, funding, and check tier status
22+
init Set up allowance, funding, and check tier status (x402 default)
23+
init mpp Set up with MPP payment rail (Tempo Moderato testnet)
2324
status Show full account state (allowance, balance, tier, projects)
2425
allowance Manage your agent allowance (create, fund, balance, status)
2526
tier Manage tier subscription (status, set)
@@ -31,7 +32,7 @@ Commands:
3132
sites Deploy static sites
3233
subdomains Manage custom subdomains (claim, list, delete)
3334
apps Browse and manage the app marketplace
34-
image Generate AI images via x402 micropayments
35+
image Generate AI images via x402 or MPP micropayments
3536
message Send messages to Run402 developers
3637
agent Manage agent identity (contact info)
3738
@@ -48,7 +49,8 @@ Examples:
4849
run402 image generate "a startup mascot, pixel art" --output logo.png
4950
5051
Getting started:
51-
run402 init Set up everything in one command
52+
run402 init Set up with x402 (Base Sepolia)
53+
run402 init mpp Set up with MPP (Tempo Moderato)
5254
run402 tier set prototype Subscribe to a tier
5355
run402 deploy --manifest app.json
5456
`;

cli/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "run402",
3-
"version": "1.13.5",
4-
"description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 micropayments.",
3+
"version": "1.14.0",
4+
"description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
55
"type": "module",
66
"bin": {
77
"run402": "cli.mjs"

openclaw/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: run402
3-
description: Provision Postgres databases, deploy static sites, generate images, and build full-stack webapps on Run402 using x402 micropayments. Use when the user asks to build a webapp, deploy a site, create a database, generate images, or mentions Run402.
3+
description: Provision Postgres databases, deploy static sites, generate images, and build full-stack webapps on Run402 using x402 or MPP micropayments. Use when the user asks to build a webapp, deploy a site, create a database, generate images, or mentions Run402.
44
---
55

66
# Run402 — AI-Native Postgres & Static Hosting

0 commit comments

Comments
 (0)