一键导入
payment-router
402-aware outbound payment pipeline
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
402-aware outbound payment pipeline
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Complete visual content system for Claude Code. Use when generating blog headers, infographics, editorial art, diagrams, or comics. Default aesthetic: light backgrounds, teal/burnt orange accents, hand-drawn sketch style.
Meta-skill for driving Blender via BlenderMCP: 3D modelling (box, hard-surface, boolean), digital sculpting, PBR material authoring, lighting, rendering, and scene assembly. Claude writes and runs bpy Python (execute_code), screenshots the viewport, inspects, and corrects — with GPU renders via blender-batch and interactive sessions via the gui-tools GPU sidecar. Use this whenever a task involves Blender, a .blend file, 3D modelling/sculpting/texturing, a Cycles or EEVEE render, or generating and processing 3D assets — even when the user does not name Blender explicitly (e.g. 'model a low-poly house', 'sculpt a creature head', 'make a PBR metal material', 'render this scene on the GPU', 'build a modular sci-fi corridor kit'). Not for 2D image editing (use imagemagick), text-to-image generation (use comfyui), or GIS map rendering (use qgis).
Real-time AI meeting copilot. Dual audio capture (system + mic), live transcription (faster-whisper local or Deepgram cloud), LLM coaching loop (Claude/GPT every ~35s), always-on-top overlay, session logging with markdown export. Use when the user says "meeting recap", "meeting copilot", "live transcription", "meeting insights", "coaching during meeting", or "record this call".
Expand and analyze URLs using Google Gemini 2.5 Flash URL Context API. Efficiently fetches, summarizes, and extracts information from up to 20 URLs per request with grounding metadata and source citations. Use when analysing or summarising specific URLs using Gemini's 1M-token context window.
Build world-class comprehensive reports with LaTeX, Python analytics, Wardley maps, diagrams-as-code (TikZ + Mermaid), Nano Banana AI infographics, multi-LLM research swarms, and automated quality control. Use when creating research reports, white papers, sector analyses, technical documentation, policy briefs, or any document requiring professional presentation with data-driven charts, citations, and strategic visualisations.
Plan UK ground-mounted (utility-scale) solar farms end-to-end: site suitability, optimal tilt and inter-row spacing (GCR), array capacity and annual yield, 3D layout with inter-row shadow review, generation forecasting, and DNO grid-connection feasibility. Composes the qgis (site/terrain/ALC/flood) and blender (3D array + shading) skills with PVGIS yield data, Open Climate Fix's quartz-solar-forecast, and OpenDSS grid modelling. Use whenever the task involves a UK solar farm / solar site / ground-mount PV array — assessing a field or parcel for solar, sizing capacity, choosing panel tilt/row spacing, estimating kWh/yield or land use, visualising an array layout, checking shading, forecasting generation, or DNO/grid-connection pre-checks (e.g. 'is this 30-acre field good for solar', 'what tilt and spacing for a solar farm near Peterborough', 'how many MW fit on 20 hectares', 'model the array layout and winter shadows'). UK-specific (latitude, diffuse light, ALC land grades, DNO). Not for rooftop domestic PV or
| name | payment-router |
| version | 1.0.0 |
| description | 402-aware outbound payment pipeline |
| gate | skills.payment_router.enabled |
| dependencies | ["cost-estimation"] |
402-aware outbound payment pipeline for agentbox agents. Wraps fetch with
a transparent detect-classify-pay-retry loop so any skill or adapter can call
cost-gated external resources without writing payment logic inline.
Implements the consumer side of PRD-015 (C1-C6) and the scheme-detection grammar defined in ADR-032.
PRD-015 (Consumer & Broadcast Economy Surfaces) defines six consumer capabilities:
| Phase | ID | Capability |
|---|---|---|
| Detect | C1 | Intercept HTTP 402 responses |
| Classify | C2 | Identify payment scheme (ADR-032 grammar) |
| Policy | C3 | Apply operator spend policy before any payment |
| Pay | C4 | Execute payment on the appropriate rail |
| Retry | C5 | Replay the original request with proof of payment |
| Receipt | C6 | Preflight estimate → hold buffer → fail-closed |
ADR-032 defines the classification grammar: a pure function
classify({status, headers, body}) returning
{scheme, payable, offer, reason} with a closed result set
(agentbox-ledger | x402 | l402 | unknown). The classifier never throws;
unknown input is unknown and spends nothing.
Settlement stance (PRD-015 v1.2, Lightning-first): only agentbox-ledger
has a native rail in Phase 1. x402 and l402 are detected but
return rail-not-available. unknown is fail-closed: no retry, no spend.
import { payFetch } from "./skills/payment-router/scripts/pay-fetch.mjs";
// Drop-in replacement for fetch — handles 402 transparently
const res = await payFetch(
"https://api.example.com/premium/endpoint",
{
method: "GET",
headers: { Authorization: "Nostr <nip98-token>" }
},
{
pubkey: process.env.AGENTBOX_PUBKEY, // operator pubkey for attribution
logger: fastify.log, // optional pino-compatible logger
tier: "inference", // for preflight estimate (C6)
}
);
if (!res.ok) {
const err = await res.json();
console.error("Payment failed:", err);
} else {
const data = await res.json();
// ...
}
payFetch is a named ES module export. It is a thin wrapper: non-402
responses pass through unchanged; 402 responses trigger the payment loop.
The full loop executed on a 402 response:
1. INTERCEPT — res.status === 402? enter loop, else pass through
2. CAP CHECK — body <= 64 KiB? else → {error:"unrecognised-scheme",
reason:"oversized-body"} (never parse oversized input)
3. CLASSIFY — classify({status:402, headers, body}) [ADR-032 grammar]
4. SCHEME? — unknown → fail-closed (no spend, named error)
x402/l402 → rail-not-available (Phase 1)
agentbox-ledger → continue
5. POLICY — spend gate: deterministic code, operator caps enforced
(see Security section)
6. ESTIMATE — preflight POST /v1/pay/estimate (C6) before any debit
7. PAY — POST <deposit_endpoint> with idempotency key
409 Conflict = already paid (idempotent, treat as success)
8. RETRY — replay original request exactly once if pay succeeded
9. RECEIPT — receipt URN minted by the pod on successful debit
(urn:agentbox:receipt:<pubkey>:sha256-…, ADR-013)
On pay failure the response is a synthetic 402 JSON object with
error:"payment-failed" and a reason string. The original request is
never replayed after a failed payment.
Before executing a payment, payFetch calls the local estimate endpoint to
compute the required hold amount:
POST /v1/pay/estimate
Content-Type: application/json
{ "endpoint": "<tier>", "units": <offer.amount> }
The response hold_sats value applies a HOLD_BUFFER_RATIO of 1.2x
(configurable) over the raw estimated cost. The actual debit sent to the
deposit endpoint uses offer.amount_sats from the classified challenge —
the estimate is used only for operator policy enforcement before the wire
call.
Fail-closed rule: if the estimate endpoint is unreachable, or if
hold_sats exceeds the operator cap configured under
[payments.consumer].max_spend_sats, payFetch returns a synthetic 402
with error:"policy-denied" and does NOT proceed to payment. The model
cannot override this gate.
| Condition | Outcome | Spends? |
|---|---|---|
| Body > 64 KiB | {error:"unrecognised-scheme", reason:"oversized-body"} 402 | No |
| Body not valid JSON | classified unknown via ADR-032 | No |
scheme === "unknown" | {error:"unrecognised-scheme", reason:<classifier reason>} 402 | No |
scheme === "x402" or "l402" | {error:"rail-not-available", scheme, reason:"no native rail in Phase 1"} 402 | No |
| Estimate endpoint unreachable | {error:"policy-denied", reason:"estimate-unavailable"} 402 | No |
hold_sats > operator cap | {error:"policy-denied", reason:"cap-exceeded"} 402 | No |
| Deposit POST fails (non-409) | {error:"payment-failed", reason:<status or message>} 402 | No |
| Deposit POST returns 409 | idempotent success — continue to retry | Yes (already paid) |
| Deposit POST returns 402 | {error:"payment-failed", reason:"insufficient-balance"} 402 | No |
| Retry request fails | pass through upstream error as-is | Yes (payment made) |
One retry only. After a successful payment the original request is
replayed exactly once. If the replayed request itself returns 402, it is
returned as-is — no second payment loop. The idempotency key is a fresh
crypto.randomUUID() per payment attempt and is included in the deposit
POST body and Idempotency-Key header so duplicate POSTs (e.g. from network
timeouts) are absorbed by the pod.
[skills.payment_router] (settings.toml / env)| Key | Default | Description |
|---|---|---|
enabled | false | Gate: skill is inactive unless explicitly enabled |
hold_buffer_ratio | 1.2 | Multiplier applied to raw estimate before policy check |
Env-var equivalents follow the management-api convention:
HOLD_BUFFER_RATIO=1.2.
[payments.consumer] (settings.toml)| Key | Default | Description |
|---|---|---|
max_spend_sats | 1000 | Hard cap per request (estimate hold_sats must be ≤ this) |
allowed_schemes | ["agentbox-ledger"] | Whitelist; other detected schemes return rail-not-available |
deposit_fallback | /v1/pay/deposit | Used when the classified offer has no deposit field |
| Variable | Used by | Purpose |
|---|---|---|
SOLID_POD_PORT | pay-fetch.mjs | Port of the local solid-pod-rs instance (default: 8484) |
HOLD_BUFFER_RATIO | routes/payments.js | Buffer over raw estimate (default: 1.2) |
BASE_COST_SATS | routes/payments.js | Base cost per unit in satoshis (default: 10) |
AGENTBOX_PUBKEY | pay-fetch.mjs | Operator BIP-340 x-only pubkey hex (for attribution) |
The spend gate is deterministic code. The model cannot authorise a payment above operator caps.
Specifically:
classify() is a pure function imported from a fixed module path
(management-api/lib/pay402.js). Its input is the raw 402 response
bytes; the caller cannot inject a pre-classified result.
The deposit endpoint URL is derived from the classified offer.deposit
field or falls back to the hardcoded /v1/pay/deposit local path. It is
never taken from user-supplied input or from the 402 body as an
unvalidated string — pay-fetch.mjs resolves relative paths against the
hardcoded podBase origin.
amount_sats is taken from offer.amount (normalised by the
classifier from cost_sats in the challenge body, never from the
advisory X-Cost header). An amount-mismatch between the legacy and
accepts-array forms classifies unknown (ADR-032 D2) and is unpayable.
The preflight estimate (C6) runs before any wire call. If the estimated
hold_sats exceeds [payments.consumer].max_spend_sats, the loop
aborts. This check runs in the same process as the payment call; there is
no TOCTOU window between estimate and debit.
unknown scheme is terminal and fail-closed by construction. A server
returning a crafted 402 body that does not match any frozen detection
signature (ADR-032 D2) receives no payment and no retry.