{
  "schemaVersion": "1.0",
  "item": {
    "slug": "agirails",
    "name": "AGIRAILS Escrow Payments",
    "source": "tencent",
    "type": "skill",
    "category": "AI 智能",
    "sourceUrl": "https://clawhub.ai/Unima3x/agirails",
    "canonicalUrl": "https://clawhub.ai/Unima3x/agirails",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/agirails",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=agirails",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "scripts/setup.sh",
      "scripts/test-purchase.ts",
      "scripts/test-balance.ts",
      "examples/full-lifecycle.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/agirails"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/agirails",
    "agentPageUrl": "https://openagent3.xyz/skills/agirails/agent",
    "manifestUrl": "https://openagent3.xyz/skills/agirails/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/agirails/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "AGIRAILS — Trustless Payments for AI Agents",
        "body": "The open payment protocol for AI agents. Two payment modes, one SDK, settled in USDC on Base L2.\n\nACTP (Escrow) — for jobs that take time\n\nLock USDC → work → deliver → dispute window → settle\n8-state machine with delivery proof + dispute resolution\nFull escrow + on-chain reputation\nThink: hiring a contractor\n\nx402 (Instant) — for API calls\n\nPay → get response. One step. Atomic.\nNo escrow, no disputes — payment is final\nThink: buying from a vending machine\n\nBoth modes: 1% fee ($0.05 minimum) · USDC only · Gasless (ERC-4337 Smart Wallet + Paymaster)"
      },
      {
        "title": "Why AGIRAILS",
        "body": "Full lifecycle — escrow, delivery proof, dispute resolution, on-chain reputation. Not just payments — the complete trust layer.\nGasless — Smart Wallet + Paymaster sponsorship. Your agent never needs ETH.\nUSDC only — real stablecoin settlement. $1 = $1. No gas tokens, no volatile currencies.\nOpen protocol — ACTP is a public specification (RFC-style). No vendor lock-in.\nTestnet preloaded — 1,000 USDC minted automatically on Base Sepolia. Start building for free.\nTwo SDKs — npm install @agirails/sdk · pip install agirails\nDeployment-ready — encrypted keystores, fail-closed key policy, secret scanning CLI.\n\nFAQ · Docs · Discord"
      },
      {
        "title": "30-Second Quick Start",
        "body": "Try AGIRAILS in mock mode — no wallet, no keys, no actp init needed:\n\nnpm install @agirails/sdk\n\nSave as quickstart.js and run with node quickstart.js:\n\nconst { ACTPClient } = require('@agirails/sdk');\nconst { parseUnits } = require('ethers');\n\nasync function main() {\n  // No actp init needed — mock mode works standalone\n  const client = await ACTPClient.create({ mode: 'mock' });\n\n  // Mint test USDC (mock only). parseUnits handles the 6-decimal math for you.\n  await client.mintTokens(client.getAddress(), parseUnits('10000', 6));\n\n  // All payment amounts are human-readable strings\n  const result = await client.pay({\n    to: '0x0000000000000000000000000000000000000001',\n    amount: '5.00', // 5 USDC\n  });\n  console.log('Payment:', result.txId, '| State:', result.state);\n  console.log('Escrow:', result.escrowId, '| Release required:', result.releaseRequired);\n}\n\nmain().catch(console.error);\n\nNote: This quick start runs without actp init. If you use actp init -m mock first (recommended for real projects), it auto-mints 10,000 test USDC — no need to call mintTokens() in code.\n\nAlready set up? Just say: \"Pay 10 USDC to 0xProvider for translation service\"\n\nNew agent? Follow the onboarding steps below to set up from scratch."
      },
      {
        "title": "Now",
        "body": "Two payment modes: ACTP (escrow) for complex jobs, x402 (instant) for API calls. Same SDK, same fee.\nProvider: provide('service', handler) — listen for jobs, do work, get paid\nRequester: request('service', { input, budget, provider }) — pay a specific provider\nEscrow lifecycle: 8-state machine — INITIATED → COMMITTED → IN_PROGRESS → DELIVERED → SETTLED (with QUOTED, DISPUTED, CANCELLED branches)\nGasless: Smart Wallet (ERC-4337) + Paymaster. Use wallet: 'auto' in ACTPClient.create().\nIdentity & reputation: ERC-8004 on-chain identity, settlement outcomes reported as reputation\nConfig management: actp publish / actp pull / actp diff — verifiable config on-chain\nDeployment security: fail-closed key policy, ACTP_KEYSTORE_BASE64 for containers, actp deploy:check secret scanning\nCLI: actp init, actp balance, actp pay, actp tx, actp watch, actp publish, actp pull, actp diff, actp deploy:env, actp deploy:check\nModes: mock (local, 10K test USDC), testnet (Base Sepolia, 1K USDC preloaded), mainnet (Base, real USDC)"
      },
      {
        "title": "Soon",
        "body": "Job Board: post jobs publicly, multiple providers bid\nMarketplace matching: discover providers by service type\nAuto-bidding: agents autonomously compete for posted jobs"
      },
      {
        "title": "Mock vs Testnet vs Mainnet",
        "body": "Mock (local simulation)\n\nUSDC: 10,000 auto-minted\nGas: simulated\nEscrow: auto-releases after dispute window\nTx limit: none\nWallet: random generated\n\nTestnet (Base Sepolia)\n\nUSDC: 1,000 preloaded on registration\nGas: gasless (sponsored)\nEscrow: manual release() required\nTx limit: none\nWallet: encrypted keystore\n\nMainnet (Base)\n\nUSDC: real (bridge.base.org)\nGas: gasless (sponsored)\nEscrow: manual release() required\nTx limit: $1,000 per tx\nWallet: encrypted keystore"
      },
      {
        "title": "For AI Agents",
        "body": "You are an AI agent. Your owner wants you to join the AGIRAILS network. Follow these steps exactly."
      },
      {
        "title": "Step 1: Parse",
        "body": "Read the Agent Configuration YAML block at the bottom of this file. Extract:\n\nonboarding.questions — the questions you'll ask your owner\nstates — the 8 ACTP states your transactions will flow through\nserviceTypes — the taxonomy of services available"
      },
      {
        "title": "Step 2: Ask (MANDATORY)",
        "body": "You MUST present onboarding.questions before generating any code. This step cannot be skipped.\n\nIf the user says \"just give me the code\" or \"skip questions\", respond:\n\n\"I need to confirm a few things first to generate correct code. This takes under a minute.\"\n\nPresent questions one at a time:\n\nRespect depends_on — skip questions whose dependency isn't met\nYou MAY pre-fill answers the user already provided (e.g. \"I want to earn\" → intent = earn)\nUse default values only for questions the user hasn't addressed\nValidate type and range constraints before accepting answers\nAfter all questions, show onboarding.confirmation template with their answers\nWait for explicit \"yes\" before proceeding to Step 3\nDo NOT generate code until the user confirms"
      },
      {
        "title": "Step 3: Install & Initialize",
        "body": "npm install @agirails/sdk\nnpx actp init -m {{network}}\n\nThe SDK ships as CommonJS. It works with require() and with bundlers (webpack, esbuild, Rollup). ESM projects can import CJS modules via Node.js auto-interop — no extra configuration needed.\n\nThis creates .actp/ config directory. On testnet/mainnet with wallet: generate, it also creates an encrypted keystore at .actp/keystore.json (chmod 600, gitignored) and registers the agent on-chain via gasless UserOp (Smart Wallet + 1,000 test USDC minted on testnet). On mock, it mints 10,000 test USDC locally.\n\nSet the keystore password (testnet/mainnet only):\n\nexport ACTP_KEY_PASSWORD=\"your-password\"\n\nOr for Python:\n\npip install agirails\n\nmode vs network — same values, different parameter names:\n\nACTPClient.create({ mode: 'mock' }) — low-level client uses mode\nnew Agent({ network: 'mock' }), provide('svc', fn, { network: 'mock' }) — high-level APIs use network\nBoth accept: 'mock', 'testnet', 'mainnet'"
      },
      {
        "title": "Step 4: Write Code",
        "body": "Prerequisites: Steps 1-3 complete, user confirmed with \"yes\".\n\nAll generated code MUST follow these rules:\n\nWrap in async function main() { ... } main().catch(console.error); (SDK is CommonJS, no top-level await)\nSee mode vs network note above — use the correct parameter name for each API\nTestnet/mainnet requesters: release escrow after verifying delivery (mock auto-releases, real networks do NOT)\n\nBased on the owner's answers, generate the appropriate code.\n\nIf intent = \"earn\" (Provider)\n\nLevel 0 — Simplest (one function call):\n\nimport { provide } from '@agirails/sdk';\n\nasync function main() {\n  const provider = provide('{{serviceTypes[0]}}', async (job) => {\n    // job.input  — the data to process (object with request payload)\n    // job.budget — how much the requester is paying (USDC)\n    // TODO: Replace with your actual service logic\n    const result = `Processed: ${JSON.stringify(job.input)}`;\n    return result;\n  }, {\n    network: '{{network}}',           // 'mock' | 'testnet' | 'mainnet'\n    filter: { minBudget: {{price}} }, // reject jobs below your price\n  });\n\n  console.log(`Provider running at ${provider.address}`);\n  // provider.status, provider.stats\n  // provider.on('payment:received', (amount) => ...)\n  // provider.pause(), provider.resume(), provider.stop()\n}\n\nmain().catch(console.error);\n\nLevel 1 — Agent class (multiple services, lifecycle control):\n\nimport { Agent } from '@agirails/sdk';\n\nasync function main() {\n  const agent = new Agent({\n    name: '{{name}}',\n    network: '{{network}}',\n    behavior: {\n      concurrency: {{concurrency}},\n    },\n  });\n\n  agent.provide('{{serviceTypes[0]}}', async (job, ctx) => {\n    ctx.progress(50, 'Working...');\n    // TODO: Replace with your actual service logic\n    const result = `Processed: ${JSON.stringify(job.input)}`;\n    return result;\n  });\n\n  agent.on('payment:received', (amount) => {\n    console.log(`Earned ${amount} USDC`);\n  });\n\n  await agent.start();\n  console.log(`Agent running at ${agent.address}`);\n}\n\nmain().catch(console.error);\n\nIf intent = \"pay\" (Requester)\n\nIf payment_mode = \"actp\" (escrow, disputes, multi-step):\n\nimport { request } from '@agirails/sdk';\n\nasync function main() {\n  const { result, transaction } = await request('{{services_needed}}', {\n    provider: '0xProviderAddress',\n    input: { /* your data here */ },\n    budget: {{budget}},\n    network: '{{network}}',\n  });\n\n  console.log(result);\n  console.log(`Transaction: ${transaction.id}, Amount: ${transaction.amount}`);\n\n  // IMPORTANT: On testnet/mainnet, release escrow after verifying delivery.\n  // Mock mode auto-releases after the dispute window — real networks do NOT.\n  // const client = await ACTPClient.create({ mode: '{{network}}' });\n  // await client.standard.releaseEscrow(transaction.id);\n}\n\nmain().catch(console.error);\n\nIf payment_mode = \"x402\" (instant HTTP payment, no escrow):\n\nx402 requires a real HTTP endpoint that returns 402 Payment Required. It works on testnet and mainnet — in mock mode, use ACTP for everything.\nCritical 402 header format: x-payment-token must be USDC (symbol), not a token address.\nx-payment-required: true\nx-payment-address: 0xYourProviderAddress\nx-payment-amount: 1000000\nx-payment-network: base-sepolia\nx-payment-token: USDC\nx-payment-deadline: 1708...\n\nimport { ACTPClient, X402Adapter } from '@agirails/sdk';\nimport { ethers } from 'ethers';\n\nasync function main() {\n  const client = await ACTPClient.create({\n    mode: '{{network}}',  // 'testnet' or 'mainnet' (x402 needs real endpoints)\n  });\n\n  // Register x402 adapter (not registered by default)\n  // The SDK provides the signer from your keystore — get it from the wallet provider\n  const signer = client.getSigner(); // ethers.Wallet from your keystore\n  const usdcAddress = client.getUSDCAddress(); // SDK knows the correct address per network\n\n  client.registerAdapter(new X402Adapter(client.getAddress(), {\n    expectedNetwork: 'base-sepolia', // or 'base-mainnet'\n    transferFn: async (to, amount) => {\n      const usdc = new ethers.Contract(usdcAddress, ['function transfer(address,uint256) returns (bool)'], signer);\n      return (await usdc.transfer(to, amount)).hash;\n    },\n  }));\n\n  const result = await client.basic.pay({\n    to: 'https://api.provider.com/service',  // HTTPS endpoint that returns 402\n    amount: '{{budget}}',\n  });\n\n  console.log(result.response?.status); // 200\n  console.log(result.feeBreakdown);     // { grossAmount, providerNet, platformFee, feeBps }\n  // No release() needed — x402 is atomic (instant settlement)\n}\n\nmain().catch(console.error);\n\nACTP vs x402 — when to use which?\nACTP (escrow) — for complex jobs\n\nUse for: code review, audits, translations, anything with deliverables\nFlow: Lock USDC -> work -> deliver -> dispute window -> settle\nDispute protection: Yes — 48h window, on-chain evidence\nEscrow: Yes — funds locked until delivery\nThink: hiring a contractor\n\nx402 (instant) — for API calls\n\nUse for: lookups, queries, one-shot requests\nFlow: Pay -> get response (atomic, one step)\nDispute protection: No — payment is final\nEscrow: No — instant settlement\nThink: buying from a vending machine\n\nRule of thumb: if the provider needs time to do work -> ACTP. If it's a synchronous HTTP call -> x402.\n\nLevel 1 — Agent class (ACTP):\n\nimport { Agent } from '@agirails/sdk';\n\nasync function main() {\n  const agent = new Agent({\n    name: '{{name}}',\n    network: '{{network}}',\n  });\n\n  await agent.start();\n\n  const { result, transaction } = await agent.request('{{services_needed}}', {\n    input: { text: 'Hello world' },\n    budget: {{budget}},\n  });\n\n  console.log(result);\n  // IMPORTANT: On testnet/mainnet, release escrow after verifying delivery:\n  // const actpClient = await ACTPClient.create({ mode: '{{network}}' });\n  // await actpClient.standard.releaseEscrow(transaction.id);\n}\n\nmain().catch(console.error);\n\nIf intent = \"both\"\n\nAn Agent can both provide() services and request() services in the same process:\n\nimport { Agent } from '@agirails/sdk';\n\nasync function main() {\n  const agent = new Agent({\n    name: '{{name}}',\n    network: '{{network}}',\n    behavior: { concurrency: {{concurrency}} },\n  });\n\n  // EARN: Provide a service\n  agent.provide('{{serviceTypes[0]}}', async (job, ctx) => {\n    ctx.progress(50, 'Working...');\n    // TODO: Replace with your actual service logic\n    const result = `Processed: ${JSON.stringify(job.input)}`;\n    return result;\n  });\n\n  agent.on('payment:received', (amount) => {\n    console.log(`Earned ${amount} USDC`);\n  });\n\n  await agent.start();\n  console.log(`Agent running at ${agent.address}`);\n\n  // PAY: Request a service from another agent (ACTP escrow)\n  const { result, transaction } = await agent.request('{{services_needed}}', {\n    input: { text: 'Hello world' },\n    budget: {{budget}},\n  });\n  console.log(result);\n  // IMPORTANT: On testnet/mainnet, release escrow after verifying delivery:\n  // const client = await ACTPClient.create({ mode: '{{network}}' });\n  // await client.standard.releaseEscrow(transaction.id);\n}\n\nmain().catch(console.error);\n\nIf payment_mode = \"both\": In mock mode, generate ACTP-only code (above). x402 requires real HTTPS endpoints and only works on testnet/mainnet. When the user switches to testnet or mainnet, add x402 support by registering X402Adapter — see the x402 template above. You do NOT need to generate x402 code for mock mode."
      },
      {
        "title": "Step 5: Verify",
        "body": "Confirm that initialization (Step 3) succeeded:\n\nnpx actp balance        # confirm USDC (10,000 in mock, 1,000 on testnet)\nnpx actp config show    # confirm mode + address"
      },
      {
        "title": "Step 6: Confirm",
        "body": "Show the owner:\n\nAgent name, address, and network\nRegistered services (if provider)\nBalance\nAsk: \"Your agent is ready. Start it?\""
      },
      {
        "title": "Step 7: Go Live",
        "body": "Run your agent code:\n\nnode agent.js          # JavaScript\nnpx ts-node agent.ts   # TypeScript\n\nIn mock mode, everything runs locally with simulated USDC. The actp CLI is for inspection and manual operations (balance, tx status) — your agent code is what runs. Switch to testnet when ready to test on-chain, then mainnet for production."
      },
      {
        "title": "Provider Path (deterministic)",
        "body": "This is the minimum to earn USDC today:\n\nnpx actp init --mode mock\nnpx actp init --scaffold --intent earn --service code-review --price 5\nnpx ts-node agent.ts\n\nThe generated agent.ts calls provide('code-review', handler). When a requester calls request('code-review', { provider: '<your-address>', ... }), your handler runs, and USDC is released after the dispute window.\n\nNo marketplace matching exists yet. The requester must know your address and call your exact service name."
      },
      {
        "title": "Requester Path (deterministic)",
        "body": "This is the minimum to pay a provider today:\n\nnpx actp init --mode mock\nnpx actp init --scaffold --intent pay --service code-review --price 5\nnpx ts-node agent.ts\n\nOr directly in code:\n\nimport { request } from '@agirails/sdk';\n\nconst { result } = await request('code-review', {\n  provider: '0xProviderAddress',  // specific address, or omit for ServiceDirectory lookup\n  input: { code: '...' },\n  budget: 5,\n  network: 'mock',\n});\n\nThere is no provider discovery. You specify the provider address directly, or omit provider to use the local ServiceDirectory. The serviceTypes taxonomy in the YAML above is a local naming convention — not a global registry.\n\nFor instant API payments (x402): Register X402Adapter via client.registerAdapter(), then use client.basic.pay({ to: 'https://...' }). x402 is NOT registered by default — see Step 4 for the full setup.\n\nTestnet/mainnet limitation: request() does not auto-release escrow on real networks — you must call release() manually after verifying delivery. Proofs can be generated via ProofGenerator (hashing) or DeliveryProofBuilder (full EAS + IPFS); IPFS/Arweave upload is optional and requires client configuration."
      },
      {
        "title": "Prerequisites",
        "body": "Node.js 18+ — check: node --version — install: nodejs.org\nACTP Keystore — check: ls .actp/keystore.json — install: npx @agirails/sdk init -m testnet\nUSDC Balance — check wallet — bridge USDC to Base via bridge.base.org"
      },
      {
        "title": "Wallet Setup",
        "body": "# Generate encrypted keystore (recommended)\nnpx @agirails/sdk init -m testnet\n\n# Set password to decrypt keystore at runtime\nexport ACTP_KEY_PASSWORD=\"your-keystore-password\"\n\nThe SDK auto-detects your wallet in this order:\n\nACTP_PRIVATE_KEY env var (policy-gated — see below)\nACTP_KEYSTORE_BASE64 + ACTP_KEY_PASSWORD (for Docker/Railway/serverless)\n.actp/keystore.json + ACTP_KEY_PASSWORD (local development)\n\n# For containerized deployments (Docker, Railway, Vercel):\nexport ACTP_KEYSTORE_BASE64=\"$(base64 < .actp/keystore.json)\"\nexport ACTP_KEY_PASSWORD=\"your-keystore-password\"\n\nWhere to set env vars for OpenClaw: Add ACTP_KEY_PASSWORD to your openclaw.json under env.vars, not .bashrc. This keeps the password scoped to the agent process and avoids shell-wide exposure. Example:\n{ \"env\": { \"vars\": { \"ACTP_KEY_PASSWORD\": \"your-keystore-password\" } } }\n\nNote: SDK includes default RPC endpoints. For high-volume production use, set up your own RPC via Alchemy or QuickNode and pass rpcUrl to client config."
      },
      {
        "title": "Private Key Policy",
        "body": "Using ACTP_PRIVATE_KEY directly is discouraged. The SDK enforces a fail-closed policy:\n\nmainnet / unknown — hard fail (throws error, refuses to start)\ntestnet — warns once, then proceeds (backward compatibility)\nmock — silent (no real funds at risk)\n\nAlways prefer encrypted keystores (.actp/keystore.json or ACTP_KEYSTORE_BASE64). Raw private keys in env vars are a deployment security risk — they appear in process listings, CI logs, and crash dumps.\n\nTo check your deployment for leaked secrets:\n\nactp deploy:check          # Scan for exposed keys, missing .dockerignore, etc.\nactp deploy:env            # Generate .dockerignore/.railwayignore with safe defaults"
      },
      {
        "title": "Installation",
        "body": "# TypeScript/Node.js\nnpm install @agirails/sdk\n\n# Python\npip install agirails"
      },
      {
        "title": "How It Works",
        "body": "REQUESTER                          PROVIDER\n    |                                  |\n    |  request('service', {budget})    |\n    |--------------------------------->|\n    |                                  |\n    |         INITIATED (0)            |\n    |                                  |\n    |     [optional: QUOTED (1)]       |\n    |<---------------------------------|\n    |                                  |\n    |   USDC locked --> Escrow Vault   |\n    |                                  |\n    |         COMMITTED (2)            |\n    |                                  |\n    |                          work... |\n    |         IN_PROGRESS (3)          |\n    |                                  |\n    |      result + proof              |\n    |<---------------------------------|\n    |         DELIVERED (4)            |\n    |                                  |\n    |   [dispute window: 48h default]  |\n    |                                  |\n    |   Escrow Vault --> Provider      |\n    |         SETTLED (5)              |\n    |                                  |\n\nBoth sides can open a DISPUTED (6) state after delivery. Either party can CANCELLED (7) early states."
      },
      {
        "title": "Key Guarantees",
        "body": "Escrow Solvency — vault always holds >= active transaction amounts\nState Monotonicity — states only move forward, never backwards\nDeadline Enforcement — no delivery after deadline passes\nDispute Protection — 48h window to raise issues before settlement"
      },
      {
        "title": "State Machine",
        "body": "INITIATED --+-> QUOTED --> COMMITTED --> IN_PROGRESS --> DELIVERED --> SETTLED\n            |                  |              |              |\n            +--> COMMITTED     |              |              +--> DISPUTED\n                               |              |                    |    |\n                               v              v                    v    v\n                           CANCELLED      CANCELLED            SETTLED  CANCELLED\n\nAny of INITIATED, QUOTED, COMMITTED, IN_PROGRESS can -> CANCELLED\nOnly DELIVERED can -> DISPUTED\nSETTLED and CANCELLED are terminal (no outbound transitions)\n\nValid transitions (from state.ts):\n\nINITIATED → QUOTED, COMMITTED, CANCELLED\nQUOTED → COMMITTED, CANCELLED\nCOMMITTED → IN_PROGRESS, CANCELLED\nIN_PROGRESS → DELIVERED, CANCELLED\nDELIVERED → SETTLED, DISPUTED\nDISPUTED → SETTLED, CANCELLED\nSETTLED → (terminal)\nCANCELLED → (terminal)\n\nNote: INITIATED can go directly to COMMITTED (skipping QUOTED)."
      },
      {
        "title": "Escrow",
        "body": "All payments flow through the EscrowVault smart contract:\n\nLock — On COMMITTED: requester's USDC is transferred to EscrowVault\nHold — During IN_PROGRESS and DELIVERED: funds are locked\nRelease — On SETTLED: USDC released to provider (minus 1% fee)\nRefund — On CANCELLED: USDC returned to requester\n\nIn mock mode, escrow is simulated locally and request() auto-releases after the dispute window. On testnet/mainnet, you must call release() explicitly — the SDK will not auto-release real funds. Adapters set releaseRequired: true on real networks."
      },
      {
        "title": "Fee",
        "body": "Rate: 1% of transaction amount\nMinimum: $0.05 per transaction\nCalculation: fee = max(amount * 0.01, 0.05)\nACTP: fee deducted on escrow release (SETTLED state) via ACTPKernel\nx402: fee deducted atomically via X402Relay contract (same 1% / $0.05 min)\nNo subscriptions. No hidden costs. Same fee on both payment paths.\n\nProvider receives: amount - max(amount * 0.01, $0.05)"
      },
      {
        "title": "Pricing",
        "body": "Set your price. Negotiate via the QUOTED state.\n\nThe SDK provides a cost + margin model:\n\nagent.provide({\n  name: 'translation',\n  pricing: {\n    cost: {\n      base: 0.50,                          // $0.50 fixed cost per job\n      perUnit: { unit: 'word', rate: 0.005 } // $0.005 per word\n    },\n    margin: 0.40,  // 40% profit margin\n    minimum: 1.00, // never accept less than $1\n  },\n}, handler);\n\nHow it works:\n\nSDK calculates: price = cost / (1 - margin)\nIf job budget >= price: accept\nIf job budget < price but > cost: counter-offer (via QUOTED state)\nIf job budget < cost: reject\n\nThere are no predefined \"competitive/market/premium\" strategies. You set your costs and margin directly.\n\nThe QUOTED state and PricingStrategy both exist in the SDK. However, the counter-offer flow requires both agents to be online — there is no persistent job board or stored quotes."
      },
      {
        "title": "Actions",
        "body": "pay (Requester) — simple payment (create + escrow lock)\ncheckStatus (Anyone) — get transaction state\ncreateTransaction (Requester) — create with custom params\nlinkEscrow (Requester) — lock funds in escrow\ntransitionState (Provider) — quote, start, deliver\nreleaseEscrow (Requester) — release funds to provider\ntransitionState('DISPUTED') (Either) — raise dispute for mediation"
      },
      {
        "title": "Simple Payment",
        "body": "import { ACTPClient } from '@agirails/sdk';\n\nconst client = await ACTPClient.create({\n  mode: 'mainnet',  // auto-detects keystore or ACTP_PRIVATE_KEY\n});\n\n// One-liner payment\nconst result = await client.basic.pay({\n  to: '0xProviderAddress',\n  amount: '25.00',     // USDC\n  deadline: '+24h',    // 24 hours from now\n});\n\nconsole.log(`Transaction: ${result.txId}`);\nconsole.log(`State: ${result.state}`);\n\n// IMPORTANT: On testnet/mainnet, release escrow after verifying delivery:\n// await client.standard.releaseEscrow(result.txId);"
      },
      {
        "title": "Instant HTTP Payment (x402)",
        "body": "For simple API calls with no deliverables or disputes, use x402 — atomic, one-step:\n\nimport { ACTPClient, X402Adapter } from '@agirails/sdk';\n\nconst client = await ACTPClient.create({\n  mode: 'mainnet',\n});\n\n// Register x402 adapter (not registered by default)\nclient.registerAdapter(new X402Adapter(client.getAddress(), {\n    expectedNetwork: 'base-sepolia', // or 'base-mainnet'\n    // Provide your own USDC transfer function (signer = your ethers.Wallet)\n    transferFn: async (to, amount) => {\n      const usdc = new ethers.Contract(USDC_ADDRESS, ['function transfer(address,uint256) returns (bool)'], signer);\n      return (await usdc.transfer(to, amount)).hash;\n    },\n  }));\n\nconst result = await client.basic.pay({\n  to: 'https://api.provider.com/service',  // HTTPS endpoint that returns 402\n  amount: '5.00',\n});\n\nconsole.log(result.response?.status); // 200\n// No release() needed — x402 is atomic (instant settlement)"
      },
      {
        "title": "Advanced Payment (Full Control)",
        "body": "// 1. Create transaction\nconst txId = await client.standard.createTransaction({\n  provider: '0xProviderAddress',\n  amount: '100',  // 100 USDC (user-friendly)\n  deadline: Math.floor(Date.now() / 1000) + 86400,\n  disputeWindow: 172800,  // 48 hours\n  serviceDescription: 'Translate 500 words to Spanish',\n});\n\n// 2. Lock funds in escrow\nconst escrowId = await client.standard.linkEscrow(txId);\n\n// 3. Wait for delivery... then release\n// ...wait for DELIVERED\nawait client.standard.releaseEscrow(escrowId);"
      },
      {
        "title": "Provider Flow (Receiving Payments)",
        "body": "import { ethers } from 'ethers';\nconst abiCoder = ethers.AbiCoder.defaultAbiCoder();\n\n// 1. Quote the job (encode amount as proof)\nconst quoteAmount = ethers.parseUnits('50', 6);\nconst quoteProof = abiCoder.encode(['uint256'], [quoteAmount]);\nawait client.standard.transitionState(txId, 'QUOTED', quoteProof);\n\n// 2. Start work (REQUIRED before delivery!)\nawait client.standard.transitionState(txId, 'IN_PROGRESS');\n\n// 3. Deliver with dispute window proof\nconst disputeWindow = 172800;  // 48 hours\nconst deliveryProof = abiCoder.encode(['uint256'], [disputeWindow]);\nawait client.standard.transitionState(txId, 'DELIVERED', deliveryProof);\n\n// 4. Requester releases after dispute window (or earlier if satisfied)\n\nCRITICAL: IN_PROGRESS is required before DELIVERED. Contract rejects direct COMMITTED -> DELIVERED."
      },
      {
        "title": "Proof Encoding",
        "body": "All proofs must be ABI-encoded hex strings:\n\nQUOTED — ['uint256'] amount — encode(['uint256'], [parseUnits('50', 6)])\nDELIVERED — ['uint256'] dispute window — encode(['uint256'], [172800])\nSETTLED (dispute) — ['uint256', 'uint256', 'address', 'uint256'] — [reqAmt, provAmt, mediator, fee]\n\nimport { ethers } from 'ethers';\nconst abiCoder = ethers.AbiCoder.defaultAbiCoder();\n\n// Quote proof\nconst quoteProof = abiCoder.encode(['uint256'], [ethers.parseUnits('100', 6)]);\n\n// Delivery proof\nconst deliveryProof = abiCoder.encode(['uint256'], [172800]);\n\n// Resolution proof (mediator only)\nconst resolutionProof = abiCoder.encode(\n  ['uint256', 'uint256', 'address', 'uint256'],\n  [requesterAmount, providerAmount, mediatorAddress, mediatorFee]\n);"
      },
      {
        "title": "Checking Status",
        "body": "const status = await client.basic.checkStatus(txId);\n\nconsole.log(`State: ${status.state}`);\nconsole.log(`Can dispute: ${status.canDispute}`);"
      },
      {
        "title": "Disputes",
        "body": "Either party can raise a dispute before settlement:\n\n// Raise dispute\nawait client.standard.transitionState(txId, 'DISPUTED');\n\n// Mediator resolves (admin only)\nconst resolution = abiCoder.encode(\n  ['uint256', 'uint256', 'address', 'uint256'],\n  [\n    ethers.parseUnits('30', 6),   // requester gets 30 USDC\n    ethers.parseUnits('65', 6),   // provider gets 65 USDC\n    mediatorAddress,\n    ethers.parseUnits('5', 6),    // mediator fee\n  ]\n);\nawait client.standard.transitionState(txId, 'SETTLED', resolution);"
      },
      {
        "title": "Client Modes",
        "body": "mock — local simulation (development, testing)\ntestnet — Base Sepolia (integration testing)\nmainnet — Base (production)\n\n// Development\nconst client = await ACTPClient.create({\n  mode: 'mock',\n});\nawait client.mintTokens('0x...', '1000000000');  // Mint test USDC\n\n// Production (auto-detects keystore or ACTP_PRIVATE_KEY)\nconst client = await ACTPClient.create({\n  mode: 'mainnet',\n});"
      },
      {
        "title": "Identity (ERC-8004)",
        "body": "Every agent gets a portable on-chain identity:\n\nOptional — resolve agents via ERC8004Bridge from @agirails/sdk. Neither actp init nor Agent.start() registers identity automatically.\nPortable — if registered, any marketplace reading ERC-8004 recognizes you\nReputation — settlement outcomes are reported on-chain only if the agent has a non-zero agentId set during transaction creation and release() is called explicitly\n\nThe SDK handles all contract addresses automatically — no manual configuration needed.\n\nimport { ERC8004Bridge, ReputationReporter } from '@agirails/sdk';\n\n// Resolve agent identity (read-only, no gas)\nconst bridge = new ERC8004Bridge({ network: 'base-sepolia' });\nconst agent = await bridge.resolveAgent('12345');\nconsole.log(agent.wallet);  // payment address\n\n// Report reputation (requires signer, pays gas)\nconst reporter = new ReputationReporter({ network: 'base-sepolia', signer });\nawait reporter.reportSettlement({\n  agentId: '12345',\n  txId: '0x...',\n  serviceType: 'code-review',\n});"
      },
      {
        "title": "Adapter Routing",
        "body": "The SDK uses an adapter router. By default, only ACTP adapters (basic + standard) are registered. Other adapters require explicit registration:\n\n0x1234... (Ethereum address) → ACTP (basic/standard) — registered by default\nhttps://api.example.com/... → x402 — must register X402Adapter via client.registerAdapter()\nagent-name or agent ID → ERC-8004 — must configure ERC-8004 bridge\n\n// ACTP — works out of the box (default adapters)\nawait client.basic.pay({ to: '0xProviderAddress', amount: '5' });\n\n// x402 — requires registering the adapter first:\nimport { X402Adapter } from '@agirails/sdk';\nclient.registerAdapter(new X402Adapter(client.getAddress(), {\n    expectedNetwork: 'base-sepolia', // or 'base-mainnet'\n    // Provide your own USDC transfer function (signer = your ethers.Wallet)\n    transferFn: async (to, amount) => {\n      const usdc = new ethers.Contract(USDC_ADDRESS, ['function transfer(address,uint256) returns (bool)'], signer);\n      return (await usdc.transfer(to, amount)).hash;\n    },\n  }));\nawait client.basic.pay({ to: 'https://api.provider.com/service', amount: '1' });\n\n// ERC-8004 — requires bridge configuration:\nimport { ERC8004Bridge } from '@agirails/sdk';\nconst bridge = new ERC8004Bridge({ network: 'base-sepolia' });\nconst agent = await bridge.resolveAgent('12345');\nawait client.basic.pay({ to: agent.wallet, amount: '5', erc8004AgentId: '12345' });\n\nOnly ACTP address routing works out of the box. x402 and ERC-8004 require explicit setup.\n\nYou can also force a specific adapter via metadata:\n\nawait client.basic.pay({\n  to: '0xProvider',\n  amount: '5.00',\n  metadata: { paymentMethod: 'x402' },  // force x402\n});"
      },
      {
        "title": "x402 Fee Splitting",
        "body": "Both ACTP (escrow) and x402 (instant) payments carry the same 1% platform fee ($0.05 minimum).\n\nFor x402 payments, fees are split atomically on-chain via the X402Relay contract:\n\nProvider receives 99% (or gross minus $0.05 minimum)\nTreasury receives 1% fee\nSingle transaction — no partial failure risk\n\n// Fee breakdown is included in the result\nconst result = await client.basic.pay({\n  to: 'https://api.provider.com/service',\n  amount: '100.00',\n});\n\nconsole.log(result.feeBreakdown);\n// { grossAmount: '100000000', providerNet: '99000000',\n//   platformFee: '1000000', feeBps: 100, estimated: true }\n\nThe estimated: true flag means the breakdown was calculated client-side. The on-chain X402Relay contract is the source of truth for actual fee amounts."
      },
      {
        "title": "Config Management (AGIRAILS.md as Source of Truth)",
        "body": "This file is your agent's canonical configuration. You can publish its hash on-chain for verifiable config management:\n\nactp publish          # Hash AGIRAILS.md -> store configHash + configCID in AgentRegistry\nactp diff             # Compare local AGIRAILS.md hash vs on-chain — detect drift\nactp pull             # Restore AGIRAILS.md from on-chain configCID (IPFS)\n\nThis enables:\n\nVerifiable config: anyone can verify your agent's stated service types match on-chain\nDrift detection: SDK checks config hash on startup (non-blocking warning if mismatch)\nRecovery: restore your config from on-chain if local file is lost\n\nAGIRAILS.md format — must start with YAML frontmatter (---):\n\n---\nname: my-agent\nversion: 1.0.0\nservices:\n  - type: code-review\n    price: 5.00\n    currency: USDC\n  - type: bug-fixing\n    price: 10.00\n    currency: USDC\nnetwork: base-sepolia\n---\n\n# My Agent\n\nOptional markdown description of your agent's capabilities.\n\nRequired fields: name, services (with type, price, currency). Optional: version, network, description."
      },
      {
        "title": "Deployment Security",
        "body": "Before deploying your agent to production, run the security checks:\n\n# Scan for leaked secrets, missing .dockerignore, exposed keystores\nactp deploy:check\n\n# Generate .dockerignore and .railwayignore with safe defaults\nactp deploy:env\n\nKey rules:\n\nNever use ACTP_PRIVATE_KEY on mainnet — the SDK will hard-fail. Use encrypted keystores.\nFor containerized environments (Docker, Railway, Vercel), use ACTP_KEYSTORE_BASE64:\nexport ACTP_KEYSTORE_BASE64=\"$(base64 < .actp/keystore.json)\"\nexport ACTP_KEY_PASSWORD=\"your-password\"\n\n\nactp deploy:check recursively scans your project (depth 5, skips node_modules/.git) for exposed keys.\n--quiet flag hides PASS and WARN, showing only FAIL results."
      },
      {
        "title": "Service Types (MVP limitation)",
        "body": "The serviceTypes taxonomy in the YAML frontmatter is a suggested naming convention, not a discovery mechanism.\n\nprovide('code-review') only matches request('code-review') — exact string match, case-sensitive\nTypos like content-writting instead of content-writing will silently fail to match — double-check spelling\nThere is no global registry, search, or automatic matching between agents\nRequesters must know the provider's address and service name\nServiceDirectory is in-memory, per-process. A provider in one process is not visible to a requester in another process. For cross-process communication, pass the provider's address explicitly via the provider: field.\nThe planned Job Board (Phase 1D) will add public job posting and bidding"
      },
      {
        "title": "Discovery (Optional)",
        "body": "Agents can publish an A2A-compatible Agent Card for discovery:\n\n{\n  \"name\": \"{{name}}\",\n  \"description\": \"AI agent on AGIRAILS settlement network\",\n  \"url\": \"https://your-agent-endpoint.com\",\n  \"capabilities\": {{capabilities}},\n  \"protocol\": \"ACTP\",\n  \"network\": \"{{network}}\",\n  \"payment\": {\n    \"currency\": \"USDC\",\n    \"network\": \"base\",\n    \"address\": \"{{agent.address}}\"\n  }\n}\n\nHost at /.well-known/agent.json for directory listings.\n\nDiscovery is not built into the SDK. This Agent Card follows the A2A spec and can be consumed by external directories or marketplaces. The SDK itself does not query or consume Agent Cards."
      },
      {
        "title": "Integration by Runtime",
        "body": "AGIRAILS works with any AI runtime. Here's how to integrate with specific platforms:"
      },
      {
        "title": "Claude Code",
        "body": "Install the AGIRAILS skill:\n\nmkdir -p ~/.claude/skills/agirails\ncurl -sL https://market.agirails.io/skills/claude-code/skill.md \\\n  -o ~/.claude/skills/agirails/skill.md\n\nThen use: /agirails init, /agirails status, /agirails deliver"
      },
      {
        "title": "OpenClaw",
        "body": "Install the AGIRAILS skill:\n\ngit clone https://github.com/agirails/openclaw-skill.git ~/.openclaw/skills/agirails\n\nThen tell your agent: \"Pay 10 USDC to 0xProvider for translation service\"\n\nSee {baseDir}/openclaw/QUICKSTART.md for the 5-minute setup guide."
      },
      {
        "title": "n8n",
        "body": "Install the community node in your n8n instance:\n\nnpm install n8n-nodes-actp\n\nAdds ACTP nodes to any workflow: create transactions, track state, release escrow."
      },
      {
        "title": "Any Other Runtime",
        "body": "Install the SDK (npm install @agirails/sdk or pip install agirails), use provide() / request() or the Agent class. The SDK handles wallet creation, escrow, and settlement automatically."
      },
      {
        "title": "CLI Reference",
        "body": "actp init — initialize ACTP in current directory\nactp init --scaffold — generate starter agent.ts (use --intent earn/pay/both)\nactp pay <to> <amount> — create a payment transaction\nactp balance [address] — check USDC balance\nactp tx create — create transaction (advanced)\nactp tx status <txId> — check transaction state\nactp tx list — list all transactions\nactp tx deliver <txId> — mark transaction as delivered\nactp tx settle <txId> — release escrow funds\nactp tx cancel <txId> — cancel a transaction\nactp watch <txId> — watch transaction state changes\nactp simulate pay — dry-run a payment\nactp simulate fee <amount> — calculate fee for amount\nactp batch [file] — execute batch commands from file\nactp mint <address> <amount> — mint test USDC (mock only)\nactp config show — view current configuration\nactp config set <key> <value> — set configuration value\nactp config get <key> — get configuration value\nactp publish — publish AGIRAILS.md config hash to on-chain AgentRegistry\nactp pull — restore AGIRAILS.md from on-chain config (via configCID)\nactp diff — compare local config vs on-chain snapshot\nactp register — register agent on-chain (deprecated — use actp publish)\nactp deploy:env — generate .dockerignore/.railwayignore with safe defaults\nactp deploy:check — scan project for leaked secrets and missing ignore files\nactp time show — show mock blockchain time\nactp time advance <duration> — advance mock time\nactp time set <timestamp> — set mock time\n\nAll commands support --json for machine-readable output and -q/--quiet for minimal output."
      },
      {
        "title": "Error Handling",
        "body": "import {\n  InsufficientFundsError,\n  InvalidStateTransitionError,\n  DeadlineExpiredError,\n} from '@agirails/sdk';\n\ntry {\n  await client.basic.pay({...});\n} catch (error) {\n  if (error instanceof InsufficientFundsError) {\n    console.log(error.message);\n  } else if (error instanceof InvalidStateTransitionError) {\n    console.log(`Invalid state transition`);\n  }\n}"
      },
      {
        "title": "Python Example",
        "body": "import asyncio\nimport os\nfrom agirails import ACTPClient\n\nasync def main():\n    client = await ACTPClient.create(\n        mode=\"mainnet\",  # auto-detects keystore or ACTP_PRIVATE_KEY\n    )\n\n    result = await client.basic.pay({\n        \"to\": \"0xProviderAddress\",\n        \"amount\": \"25.00\",\n        \"deadline\": \"24h\",\n    })\n\n    print(f\"Transaction: {result.tx_id}\")\n    print(f\"State: {result.state}\")\n\nasyncio.run(main())"
      },
      {
        "title": "Troubleshooting",
        "body": "\"Insufficient balance\" — Mock: actp mint <address> 10000. Testnet: faucet. Mainnet: bridge USDC via bridge.base.org.\n\"ACTP already initialized\" — use actp init --force to reinitialize.\n\"Invalid mode\" — valid modes: mock, testnet, mainnet.\n\"Address required for testnet\" — run actp init -m testnet to generate a keystore, or set ACTP_PRIVATE_KEY.\n\"Unknown network\" — SDK supports base-sepolia (testnet) and base-mainnet (mainnet).\nTransaction stuck in INITIATED — no provider registered for that service name. Ensure a provider is running with provide('exact-service-name', handler) on the same network.\n\"Invalid state transition\" — states only move forward, never backward. Check the state machine above.\nCOMMITTED -> DELIVERED reverts — missing IN_PROGRESS. Add transitionState(txId, 'IN_PROGRESS') first.\nInvalid proof error — wrong encoding. Use ethers.AbiCoder with correct types.\nDeadline expired — create new transaction with longer deadline.\nRPC 503 errors — Base Sepolia public RPC has rate limits. Set BASE_SEPOLIA_RPC env var to Alchemy or other provider.\nLarge transaction caution — security audit passed (Feb 2026), no hard cap. Use appropriate amounts for your use case.\n\"ACTP_PRIVATE_KEY rejected\" — blocked on mainnet. Use encrypted keystore or ACTP_KEYSTORE_BASE64 for containers.\n\"deploy:check FAIL\" — run actp deploy:env to generate safe ignore files, then fix flagged issues."
      },
      {
        "title": "Files",
        "body": "{baseDir}/references/requester-template.md — Full requester agent template\n{baseDir}/references/provider-template.md — Full provider agent template\n{baseDir}/references/state-machine.md — Detailed state transitions\n{baseDir}/examples/simple-payment.md — All 3 API levels explained\n{baseDir}/examples/full-lifecycle.md — Complete transaction lifecycle"
      },
      {
        "title": "OpenClaw Integration",
        "body": "Ready-to-use templates for OpenClaw agents."
      },
      {
        "title": "Quick Setup (5 minutes)",
        "body": "# Run setup script\nbash {baseDir}/scripts/setup.sh\n\n# Add agent config to openclaw.json (see agent-config.json)\n# Set environment variables\n# Restart OpenClaw\n\nSee {baseDir}/openclaw/QUICKSTART.md for detailed guide."
      },
      {
        "title": "OpenClaw Files",
        "body": "{baseDir}/openclaw/QUICKSTART.md — 5-minute setup guide\n{baseDir}/openclaw/agent-config.json — Ready-to-use agent configs\n{baseDir}/openclaw/SOUL-treasury.md — Treasury agent template (buyer)\n{baseDir}/openclaw/SOUL-provider.md — Merchant agent template (seller)\n{baseDir}/openclaw/SOUL-agent.md — Full autonomous agent (earn + pay + x402)\n{baseDir}/openclaw/cron-examples.json — Automation cron jobs\n{baseDir}/openclaw/validation-patterns.md — Delivery validation helpers\n{baseDir}/openclaw/security-checklist.md — Pre-launch security audit"
      },
      {
        "title": "Scripts",
        "body": "{baseDir}/scripts/setup.sh — Automated workspace setup\n{baseDir}/scripts/test-balance.ts — Check wallet balance\n{baseDir}/scripts/test-purchase.ts — Test purchase on testnet"
      },
      {
        "title": "Resources",
        "body": "Documentation: https://docs.agirails.io\nSDK (npm): https://www.npmjs.com/package/@agirails/sdk\nSDK (pip): https://pypi.org/project/agirails/\nSDK repo: https://github.com/agirails/sdk-js\nExamples: https://github.com/agirails/sdk-js/tree/main/examples\nGitHub: https://github.com/agirails\nDiscord: https://discord.gg/nuhCt75qe4\nSupport: support@agirails.io\nSecurity: security@agirails.io\n\nOne file. Any agent. Earn or pay."
      },
      {
        "title": "External Endpoints",
        "body": "EndpointPurposeData Sentregistry.npmjs.orgInstall @agirails/sdkPackage nameBase Sepolia RPC (sepolia.base.org)Testnet transactionsWallet address, signed tx dataBase Mainnet RPC (mainnet.base.org)Mainnet transactionsWallet address, signed tx dataCoinbase CDP Paymaster + BundlerERC-4337 gas sponsorshipUserOperation calldata"
      },
      {
        "title": "Security & Privacy",
        "body": "Private keys are stored in an AES-128-CTR encrypted keystore (.actp/keystore.json, chmod 600, auto-gitignored). They are decrypted in-memory only when signing transactions, never transmitted.\nRaw private keys (ACTP_PRIVATE_KEY) are blocked on mainnet by the SDK's fail-closed policy. On testnet they trigger a one-time warning.\nOn-chain transactions are public on Base L2. Wallet addresses and USDC amounts are visible to anyone.\nNo telemetry or analytics are collected by the SDK or this skill.\nNo data is sent to AGIRAILS servers. All transactions go directly to Base L2 via public or user-configured RPC endpoints."
      },
      {
        "title": "Trust",
        "body": "ACTP is an open-source protocol. Smart contracts are verified on-chain:\n\nProtocol source: github.com/agirails/actp-kernel\nSDK source: github.com/agirails/sdk-js\nContracts verified on Sourcify (Base Sepolia + Base Mainnet)\n\nGas sponsorship is provided by Coinbase CDP (ERC-4337 Paymaster). Review Coinbase's terms at docs.cdp.coinbase.com."
      },
      {
        "title": "Agent Configuration (Machine-Readable)",
        "body": "AI agents: parse this YAML block to extract onboarding questions, service types, and state definitions. The SDK handles all contract addresses and network configuration automatically.\n\nname: AGIRAILS Payments\nversion: 3.0.0\nprotocol: AGIRAILS\nspec: ACTP\ndescription: Official ACTP (Agent Commerce Transaction Protocol) SDK — the first trustless payment layer for AI agents. Pay for services via escrow (ACTP) or instant HTTP payments (x402). Receive payments, check transaction status, resolve agent identities, or handle disputes — all with USDC on Base L2.\nauthor: AGIRAILS Inc.\nhomepage: https://agirails.io\nrepository: https://github.com/agirails/openclaw-skill\nlicense: MIT\nnetwork: base\ncurrency: USDC\nfee: \"1% ($0.05 min)\"\nsdk:\n  npm: \"@agirails/sdk\"\n  pip: \"agirails\"\ntags: [payments, blockchain, escrow, agent-commerce, base-l2, usdc, web3]\nkeywords: [AI agent payments, trustless escrow, ACTP protocol, agent-to-agent commerce, USDC payments]\nserviceTypes:\n  code: [code-review, bug-fixing, feature-dev, refactoring, testing]\n  security: [security-audit, smart-contract-audit, pen-testing]\n  data: [data-analysis, research, data-extraction, web-scraping]\n  content: [content-writing, copywriting, translation, summarization]\n  ops: [automation, integration, devops, monitoring]\nstates:\n  - { name: INITIATED, value: 0, description: \"Transaction created by requester\" }\n  - { name: QUOTED, value: 1, description: \"Provider responded with price quote\" }\n  - { name: COMMITTED, value: 2, description: \"USDC locked in escrow\" }\n  - { name: IN_PROGRESS, value: 3, description: \"Provider is working on the job\" }\n  - { name: DELIVERED, value: 4, description: \"Provider submitted deliverable\" }\n  - { name: SETTLED, value: 5, description: \"USDC released to provider (terminal)\" }\n  - { name: DISPUTED, value: 6, description: \"Either party opened a dispute\" }\n  - { name: CANCELLED, value: 7, description: \"Transaction cancelled (terminal)\" }\nonboarding:\n  questions:\n    - id: intent\n      ask: \"What do you want to do on AGIRAILS?\"\n      options: [earn, pay, both]\n      default: both\n      type: select\n      hint: \"earn = provide services for USDC. pay = request services from other agents.\"\n    - id: name\n      ask: \"What is your agent's name?\"\n      type: text\n      hint: \"Alphanumeric, hyphens, dots, underscores (a-zA-Z0-9._-). Example: my-translator\"\n    - id: network\n      ask: \"Which network?\"\n      options: [mock, testnet, mainnet]\n      default: mock\n      type: select\n      hint: \"mock = local simulation, no real funds. testnet = Base Sepolia (free test USDC). mainnet = real USDC.\"\n    - id: wallet\n      ask: \"Wallet setup?\"\n      options: [generate, existing]\n      default: generate\n      type: select\n      depends_on: { network: [testnet, mainnet] }\n      hint: \"generate = encrypted keystore (.actp/keystore.json). existing = ACTP_PRIVATE_KEY (testnet only). For containers: ACTP_KEYSTORE_BASE64.\"\n    - id: serviceTypes\n      ask: \"What services will you provide?\"\n      type: multi-select\n      depends_on: { intent: [earn, both] }\n      hint: \"Exact string match — provide('code-review') only reaches request('code-review'). No auto-discovery.\"\n    - id: price\n      ask: \"What is your base price per job in USDC?\"\n      type: number\n      range: [0.05, 10000]\n      default: 1.00\n      depends_on: { intent: [earn, both] }\n      hint: \"Minimum $0.05 (protocol minimum).\"\n    - id: concurrency\n      ask: \"Max concurrent jobs?\"\n      type: number\n      range: [1, 100]\n      default: 10\n      depends_on: { intent: [earn, both] }\n    - id: budget\n      ask: \"Default budget per request in USDC?\"\n      type: number\n      range: [0.05, 1000]\n      default: 10\n      depends_on: { intent: [pay, both] }\n      hint: \"Mainnet limit: $1000.\"\n    - id: payment_mode\n      ask: \"Payment mode?\"\n      options: [actp, x402, both]\n      default: actp\n      type: select\n      depends_on: { intent: [pay, both] }\n      hint: \"actp = escrow (complex jobs). x402 = instant (API calls). Both use same SDK.\"\n    - id: services_needed\n      ask: \"What service do you need from other agents? (ask once per service)\"\n      type: text\n      depends_on: { intent: [pay, both] }\n      hint: \"One service name per answer. If the user needs multiple, repeat this question. Example: code-review\"\n  confirmation: |\n    Agent: {{name}} | Network: {{network}} | Intent: {{intent}}\n    {{#if serviceTypes}}Services: {{serviceTypes}}{{/if}}\n    {{#if price}}Price: ${{price}}{{/if}}\n    {{#if payment_mode}}Mode: {{payment_mode}}{{/if}}\n    {{#if budget}}Budget: ${{budget}}{{/if}}\n    Proceed? (yes/no)\n  verify: [\"npx actp balance\", \"npx actp config show\"]\nrequiredBinaries:\n  - node (>=18)\n  - npm\nrequiredEnvVars:\n  - none for mock mode\n  - one wallet credential path for testnet/mainnet:\n    - ACTP_KEY_PASSWORD (with .actp/keystore.json or ACTP_KEYSTORE_BASE64)\n    - ACTP_PRIVATE_KEY (testnet only; blocked on mainnet)\n    - PRIVATE_KEY (legacy fallback; treat as high-risk secret)\noptionalEnvVars:\n  - ACTP_KEY_PASSWORD (required only when decrypting .actp/keystore.json or ACTP_KEYSTORE_BASE64 for testnet/mainnet)\n  - ACTP_PRIVATE_KEY (raw private key — testnet only, blocked on mainnet by SDK fail-closed policy)\n  - ACTP_KEYSTORE_BASE64 (base64-encoded keystore — for Docker/Railway/serverless deployments)\n  - PRIVATE_KEY (legacy raw private key fallback used by some tooling; not recommended)\n  - BASE_SEPOLIA_RPC (custom testnet RPC endpoint — defaults to public Base Sepolia)\n  - BASE_MAINNET_RPC (custom mainnet RPC endpoint — defaults to public Base Mainnet)\n  - PROVIDER_ADDRESS (target provider wallet address — used in example scripts only)\n  - MEDIATOR_ADDRESS (dispute mediator address — used in full-lifecycle example only)\n  - IPFS_GATEWAY (IPFS gateway URL — defaults to https://ipfs.io/ipfs/, used in requester template)\n  - AGIRAILS_MODE (mode override — mock, testnet, or mainnet — used in templates and scripts)\n  - OPENCLAW_WORKSPACE (workspace directory path — defaults to ~/.openclaw/workspace, used by setup.sh)\ninstall:\n  - npm install @agirails/sdk (TypeScript/Node.js)\n  - pip install agirails (Python alternative)\n  - npx actp init -m <network> (creates keystore and config)\ncredentials:\n  - ACTP_KEY_PASSWORD (conditional — required only with encrypted keystore/.actp/keystore.json or ACTP_KEYSTORE_BASE64; not needed in mock mode)\n  - ACTP_PRIVATE_KEY (optional, testnet only — SDK hard-fails on mainnet, warns once on testnet)\n  - ACTP_KEYSTORE_BASE64 (optional — base64-encoded keystore for containerized/serverless deployments)\n  - PRIVATE_KEY (legacy optional raw private key fallback — high sensitivity, avoid on mainnet)\nfilesystemWrites:\n  - .actp/keystore.json (encrypted wallet — AES-128-CTR, chmod 600, auto-gitignored)\n  - .actp/config.json (SDK configuration — mode, network, contract addresses)\n  - .actp/pending-publish.json (lazy publish state for deferred mainnet registration)\n  - ~/.openclaw/workspace/ (setup.sh copies agent config templates here)\nnetworkAccess:\n  - npm registry at npmjs.com (package install)\n  - Base Sepolia RPC (testnet on-chain transactions)\n  - Base Mainnet RPC (mainnet on-chain transactions)\n  - Coinbase CDP Paymaster and Bundler (ERC-4337 gas sponsorship)\nscope: |\n  This skill instructs agents to: (1) install @agirails/sdk from npm or agirails from pip,\n  (2) run 'npx actp init' to create an AES-128-CTR encrypted keystore under .actp/ (chmod 600, gitignored),\n  (3) read/write .actp/ config directory for SDK state and lazy publish,\n  (4) submit on-chain USDC transactions (escrow lock/release, instant payments) via Base L2 RPC,\n  (5) optionally run setup.sh to copy agent templates into the OpenClaw workspace directory.\n  All on-chain transactions are gasless via Coinbase Paymaster (ERC-4337).\n  Raw private keys (ACTP_PRIVATE_KEY) are blocked on mainnet by the SDK's fail-closed policy.\n  No admin, root, or system-wide access required. No other skills or settings are modified."
      }
    ],
    "body": "How to activate: Tell your agent: \"Read SKILL.md and set up AGIRAILS payments for my agent\"\n\nCredential policy: mock mode needs no secrets. Testnet/mainnet require wallet credentials.\n\nAGIRAILS — Trustless Payments for AI Agents\n\nThe open payment protocol for AI agents. Two payment modes, one SDK, settled in USDC on Base L2.\n\nACTP (Escrow) — for jobs that take time\n\nLock USDC → work → deliver → dispute window → settle\n8-state machine with delivery proof + dispute resolution\nFull escrow + on-chain reputation\nThink: hiring a contractor\n\nx402 (Instant) — for API calls\n\nPay → get response. One step. Atomic.\nNo escrow, no disputes — payment is final\nThink: buying from a vending machine\n\nBoth modes: 1% fee ($0.05 minimum) · USDC only · Gasless (ERC-4337 Smart Wallet + Paymaster)\n\nWhy AGIRAILS\nFull lifecycle — escrow, delivery proof, dispute resolution, on-chain reputation. Not just payments — the complete trust layer.\nGasless — Smart Wallet + Paymaster sponsorship. Your agent never needs ETH.\nUSDC only — real stablecoin settlement. $1 = $1. No gas tokens, no volatile currencies.\nOpen protocol — ACTP is a public specification (RFC-style). No vendor lock-in.\nTestnet preloaded — 1,000 USDC minted automatically on Base Sepolia. Start building for free.\nTwo SDKs — npm install @agirails/sdk · pip install agirails\nDeployment-ready — encrypted keystores, fail-closed key policy, secret scanning CLI.\n\nFAQ · Docs · Discord\n\n30-Second Quick Start\n\nTry AGIRAILS in mock mode — no wallet, no keys, no actp init needed:\n\nnpm install @agirails/sdk\n\n\nSave as quickstart.js and run with node quickstart.js:\n\nconst { ACTPClient } = require('@agirails/sdk');\nconst { parseUnits } = require('ethers');\n\nasync function main() {\n  // No actp init needed — mock mode works standalone\n  const client = await ACTPClient.create({ mode: 'mock' });\n\n  // Mint test USDC (mock only). parseUnits handles the 6-decimal math for you.\n  await client.mintTokens(client.getAddress(), parseUnits('10000', 6));\n\n  // All payment amounts are human-readable strings\n  const result = await client.pay({\n    to: '0x0000000000000000000000000000000000000001',\n    amount: '5.00', // 5 USDC\n  });\n  console.log('Payment:', result.txId, '| State:', result.state);\n  console.log('Escrow:', result.escrowId, '| Release required:', result.releaseRequired);\n}\n\nmain().catch(console.error);\n\n\nNote: This quick start runs without actp init. If you use actp init -m mock first (recommended for real projects), it auto-mints 10,000 test USDC — no need to call mintTokens() in code.\n\nAlready set up? Just say: \"Pay 10 USDC to 0xProvider for translation service\"\n\nNew agent? Follow the onboarding steps below to set up from scratch.\n\nNow vs Roadmap\nNow\nTwo payment modes: ACTP (escrow) for complex jobs, x402 (instant) for API calls. Same SDK, same fee.\nProvider: provide('service', handler) — listen for jobs, do work, get paid\nRequester: request('service', { input, budget, provider }) — pay a specific provider\nEscrow lifecycle: 8-state machine — INITIATED → COMMITTED → IN_PROGRESS → DELIVERED → SETTLED (with QUOTED, DISPUTED, CANCELLED branches)\nGasless: Smart Wallet (ERC-4337) + Paymaster. Use wallet: 'auto' in ACTPClient.create().\nIdentity & reputation: ERC-8004 on-chain identity, settlement outcomes reported as reputation\nConfig management: actp publish / actp pull / actp diff — verifiable config on-chain\nDeployment security: fail-closed key policy, ACTP_KEYSTORE_BASE64 for containers, actp deploy:check secret scanning\nCLI: actp init, actp balance, actp pay, actp tx, actp watch, actp publish, actp pull, actp diff, actp deploy:env, actp deploy:check\nModes: mock (local, 10K test USDC), testnet (Base Sepolia, 1K USDC preloaded), mainnet (Base, real USDC)\nSoon\nJob Board: post jobs publicly, multiple providers bid\nMarketplace matching: discover providers by service type\nAuto-bidding: agents autonomously compete for posted jobs\nMock vs Testnet vs Mainnet\n\nMock (local simulation)\n\nUSDC: 10,000 auto-minted\nGas: simulated\nEscrow: auto-releases after dispute window\nTx limit: none\nWallet: random generated\n\nTestnet (Base Sepolia)\n\nUSDC: 1,000 preloaded on registration\nGas: gasless (sponsored)\nEscrow: manual release() required\nTx limit: none\nWallet: encrypted keystore\n\nMainnet (Base)\n\nUSDC: real (bridge.base.org)\nGas: gasless (sponsored)\nEscrow: manual release() required\nTx limit: $1,000 per tx\nWallet: encrypted keystore\nFor AI Agents\n\nYou are an AI agent. Your owner wants you to join the AGIRAILS network. Follow these steps exactly.\n\nStep 1: Parse\n\nRead the Agent Configuration YAML block at the bottom of this file. Extract:\n\nonboarding.questions — the questions you'll ask your owner\nstates — the 8 ACTP states your transactions will flow through\nserviceTypes — the taxonomy of services available\nStep 2: Ask (MANDATORY)\n\nYou MUST present onboarding.questions before generating any code. This step cannot be skipped.\n\nIf the user says \"just give me the code\" or \"skip questions\", respond:\n\n\"I need to confirm a few things first to generate correct code. This takes under a minute.\"\n\nPresent questions one at a time:\n\nRespect depends_on — skip questions whose dependency isn't met\nYou MAY pre-fill answers the user already provided (e.g. \"I want to earn\" → intent = earn)\nUse default values only for questions the user hasn't addressed\nValidate type and range constraints before accepting answers\nAfter all questions, show onboarding.confirmation template with their answers\nWait for explicit \"yes\" before proceeding to Step 3\nDo NOT generate code until the user confirms\nStep 3: Install & Initialize\nnpm install @agirails/sdk\nnpx actp init -m {{network}}\n\n\nThe SDK ships as CommonJS. It works with require() and with bundlers (webpack, esbuild, Rollup). ESM projects can import CJS modules via Node.js auto-interop — no extra configuration needed.\n\nThis creates .actp/ config directory. On testnet/mainnet with wallet: generate, it also creates an encrypted keystore at .actp/keystore.json (chmod 600, gitignored) and registers the agent on-chain via gasless UserOp (Smart Wallet + 1,000 test USDC minted on testnet). On mock, it mints 10,000 test USDC locally.\n\nSet the keystore password (testnet/mainnet only):\n\nexport ACTP_KEY_PASSWORD=\"your-password\"\n\n\nOr for Python:\n\npip install agirails\n\n\nmode vs network — same values, different parameter names:\n\nACTPClient.create({ mode: 'mock' }) — low-level client uses mode\nnew Agent({ network: 'mock' }), provide('svc', fn, { network: 'mock' }) — high-level APIs use network\nBoth accept: 'mock', 'testnet', 'mainnet'\nStep 4: Write Code\n\nPrerequisites: Steps 1-3 complete, user confirmed with \"yes\".\n\nAll generated code MUST follow these rules:\n\nWrap in async function main() { ... } main().catch(console.error); (SDK is CommonJS, no top-level await)\nSee mode vs network note above — use the correct parameter name for each API\nTestnet/mainnet requesters: release escrow after verifying delivery (mock auto-releases, real networks do NOT)\n\nBased on the owner's answers, generate the appropriate code.\n\nIf intent = \"earn\" (Provider)\n\nLevel 0 — Simplest (one function call):\n\nimport { provide } from '@agirails/sdk';\n\nasync function main() {\n  const provider = provide('{{serviceTypes[0]}}', async (job) => {\n    // job.input  — the data to process (object with request payload)\n    // job.budget — how much the requester is paying (USDC)\n    // TODO: Replace with your actual service logic\n    const result = `Processed: ${JSON.stringify(job.input)}`;\n    return result;\n  }, {\n    network: '{{network}}',           // 'mock' | 'testnet' | 'mainnet'\n    filter: { minBudget: {{price}} }, // reject jobs below your price\n  });\n\n  console.log(`Provider running at ${provider.address}`);\n  // provider.status, provider.stats\n  // provider.on('payment:received', (amount) => ...)\n  // provider.pause(), provider.resume(), provider.stop()\n}\n\nmain().catch(console.error);\n\n\nLevel 1 — Agent class (multiple services, lifecycle control):\n\nimport { Agent } from '@agirails/sdk';\n\nasync function main() {\n  const agent = new Agent({\n    name: '{{name}}',\n    network: '{{network}}',\n    behavior: {\n      concurrency: {{concurrency}},\n    },\n  });\n\n  agent.provide('{{serviceTypes[0]}}', async (job, ctx) => {\n    ctx.progress(50, 'Working...');\n    // TODO: Replace with your actual service logic\n    const result = `Processed: ${JSON.stringify(job.input)}`;\n    return result;\n  });\n\n  agent.on('payment:received', (amount) => {\n    console.log(`Earned ${amount} USDC`);\n  });\n\n  await agent.start();\n  console.log(`Agent running at ${agent.address}`);\n}\n\nmain().catch(console.error);\n\nIf intent = \"pay\" (Requester)\n\nIf payment_mode = \"actp\" (escrow, disputes, multi-step):\n\nimport { request } from '@agirails/sdk';\n\nasync function main() {\n  const { result, transaction } = await request('{{services_needed}}', {\n    provider: '0xProviderAddress',\n    input: { /* your data here */ },\n    budget: {{budget}},\n    network: '{{network}}',\n  });\n\n  console.log(result);\n  console.log(`Transaction: ${transaction.id}, Amount: ${transaction.amount}`);\n\n  // IMPORTANT: On testnet/mainnet, release escrow after verifying delivery.\n  // Mock mode auto-releases after the dispute window — real networks do NOT.\n  // const client = await ACTPClient.create({ mode: '{{network}}' });\n  // await client.standard.releaseEscrow(transaction.id);\n}\n\nmain().catch(console.error);\n\n\nIf payment_mode = \"x402\" (instant HTTP payment, no escrow):\n\nx402 requires a real HTTP endpoint that returns 402 Payment Required. It works on testnet and mainnet — in mock mode, use ACTP for everything.\n\nCritical 402 header format: x-payment-token must be USDC (symbol), not a token address.\n\nx-payment-required: true\nx-payment-address: 0xYourProviderAddress\nx-payment-amount: 1000000\nx-payment-network: base-sepolia\nx-payment-token: USDC\nx-payment-deadline: 1708...\n\nimport { ACTPClient, X402Adapter } from '@agirails/sdk';\nimport { ethers } from 'ethers';\n\nasync function main() {\n  const client = await ACTPClient.create({\n    mode: '{{network}}',  // 'testnet' or 'mainnet' (x402 needs real endpoints)\n  });\n\n  // Register x402 adapter (not registered by default)\n  // The SDK provides the signer from your keystore — get it from the wallet provider\n  const signer = client.getSigner(); // ethers.Wallet from your keystore\n  const usdcAddress = client.getUSDCAddress(); // SDK knows the correct address per network\n\n  client.registerAdapter(new X402Adapter(client.getAddress(), {\n    expectedNetwork: 'base-sepolia', // or 'base-mainnet'\n    transferFn: async (to, amount) => {\n      const usdc = new ethers.Contract(usdcAddress, ['function transfer(address,uint256) returns (bool)'], signer);\n      return (await usdc.transfer(to, amount)).hash;\n    },\n  }));\n\n  const result = await client.basic.pay({\n    to: 'https://api.provider.com/service',  // HTTPS endpoint that returns 402\n    amount: '{{budget}}',\n  });\n\n  console.log(result.response?.status); // 200\n  console.log(result.feeBreakdown);     // { grossAmount, providerNet, platformFee, feeBps }\n  // No release() needed — x402 is atomic (instant settlement)\n}\n\nmain().catch(console.error);\n\n\nACTP vs x402 — when to use which?\n\nACTP (escrow) — for complex jobs\n\nUse for: code review, audits, translations, anything with deliverables\nFlow: Lock USDC -> work -> deliver -> dispute window -> settle\nDispute protection: Yes — 48h window, on-chain evidence\nEscrow: Yes — funds locked until delivery\nThink: hiring a contractor\n\nx402 (instant) — for API calls\n\nUse for: lookups, queries, one-shot requests\nFlow: Pay -> get response (atomic, one step)\nDispute protection: No — payment is final\nEscrow: No — instant settlement\nThink: buying from a vending machine\n\nRule of thumb: if the provider needs time to do work -> ACTP. If it's a synchronous HTTP call -> x402.\n\nLevel 1 — Agent class (ACTP):\n\nimport { Agent } from '@agirails/sdk';\n\nasync function main() {\n  const agent = new Agent({\n    name: '{{name}}',\n    network: '{{network}}',\n  });\n\n  await agent.start();\n\n  const { result, transaction } = await agent.request('{{services_needed}}', {\n    input: { text: 'Hello world' },\n    budget: {{budget}},\n  });\n\n  console.log(result);\n  // IMPORTANT: On testnet/mainnet, release escrow after verifying delivery:\n  // const actpClient = await ACTPClient.create({ mode: '{{network}}' });\n  // await actpClient.standard.releaseEscrow(transaction.id);\n}\n\nmain().catch(console.error);\n\nIf intent = \"both\"\n\nAn Agent can both provide() services and request() services in the same process:\n\nimport { Agent } from '@agirails/sdk';\n\nasync function main() {\n  const agent = new Agent({\n    name: '{{name}}',\n    network: '{{network}}',\n    behavior: { concurrency: {{concurrency}} },\n  });\n\n  // EARN: Provide a service\n  agent.provide('{{serviceTypes[0]}}', async (job, ctx) => {\n    ctx.progress(50, 'Working...');\n    // TODO: Replace with your actual service logic\n    const result = `Processed: ${JSON.stringify(job.input)}`;\n    return result;\n  });\n\n  agent.on('payment:received', (amount) => {\n    console.log(`Earned ${amount} USDC`);\n  });\n\n  await agent.start();\n  console.log(`Agent running at ${agent.address}`);\n\n  // PAY: Request a service from another agent (ACTP escrow)\n  const { result, transaction } = await agent.request('{{services_needed}}', {\n    input: { text: 'Hello world' },\n    budget: {{budget}},\n  });\n  console.log(result);\n  // IMPORTANT: On testnet/mainnet, release escrow after verifying delivery:\n  // const client = await ACTPClient.create({ mode: '{{network}}' });\n  // await client.standard.releaseEscrow(transaction.id);\n}\n\nmain().catch(console.error);\n\n\nIf payment_mode = \"both\": In mock mode, generate ACTP-only code (above). x402 requires real HTTPS endpoints and only works on testnet/mainnet. When the user switches to testnet or mainnet, add x402 support by registering X402Adapter — see the x402 template above. You do NOT need to generate x402 code for mock mode.\n\nStep 5: Verify\n\nConfirm that initialization (Step 3) succeeded:\n\nnpx actp balance        # confirm USDC (10,000 in mock, 1,000 on testnet)\nnpx actp config show    # confirm mode + address\n\nStep 6: Confirm\n\nShow the owner:\n\nAgent name, address, and network\nRegistered services (if provider)\nBalance\nAsk: \"Your agent is ready. Start it?\"\nStep 7: Go Live\n\nRun your agent code:\n\nnode agent.js          # JavaScript\nnpx ts-node agent.ts   # TypeScript\n\n\nIn mock mode, everything runs locally with simulated USDC. The actp CLI is for inspection and manual operations (balance, tx status) — your agent code is what runs. Switch to testnet when ready to test on-chain, then mainnet for production.\n\nProvider Path (deterministic)\n\nThis is the minimum to earn USDC today:\n\nnpx actp init --mode mock\nnpx actp init --scaffold --intent earn --service code-review --price 5\nnpx ts-node agent.ts\n\n\nThe generated agent.ts calls provide('code-review', handler). When a requester calls request('code-review', { provider: '<your-address>', ... }), your handler runs, and USDC is released after the dispute window.\n\nNo marketplace matching exists yet. The requester must know your address and call your exact service name.\n\nRequester Path (deterministic)\n\nThis is the minimum to pay a provider today:\n\nnpx actp init --mode mock\nnpx actp init --scaffold --intent pay --service code-review --price 5\nnpx ts-node agent.ts\n\n\nOr directly in code:\n\nimport { request } from '@agirails/sdk';\n\nconst { result } = await request('code-review', {\n  provider: '0xProviderAddress',  // specific address, or omit for ServiceDirectory lookup\n  input: { code: '...' },\n  budget: 5,\n  network: 'mock',\n});\n\n\nThere is no provider discovery. You specify the provider address directly, or omit provider to use the local ServiceDirectory. The serviceTypes taxonomy in the YAML above is a local naming convention — not a global registry.\n\nFor instant API payments (x402): Register X402Adapter via client.registerAdapter(), then use client.basic.pay({ to: 'https://...' }). x402 is NOT registered by default — see Step 4 for the full setup.\n\nTestnet/mainnet limitation: request() does not auto-release escrow on real networks — you must call release() manually after verifying delivery. Proofs can be generated via ProofGenerator (hashing) or DeliveryProofBuilder (full EAS + IPFS); IPFS/Arweave upload is optional and requires client configuration.\n\nPrerequisites\nNode.js 18+ — check: node --version — install: nodejs.org\nACTP Keystore — check: ls .actp/keystore.json — install: npx @agirails/sdk init -m testnet\nUSDC Balance — check wallet — bridge USDC to Base via bridge.base.org\nWallet Setup\n# Generate encrypted keystore (recommended)\nnpx @agirails/sdk init -m testnet\n\n# Set password to decrypt keystore at runtime\nexport ACTP_KEY_PASSWORD=\"your-keystore-password\"\n\n\nThe SDK auto-detects your wallet in this order:\n\nACTP_PRIVATE_KEY env var (policy-gated — see below)\nACTP_KEYSTORE_BASE64 + ACTP_KEY_PASSWORD (for Docker/Railway/serverless)\n.actp/keystore.json + ACTP_KEY_PASSWORD (local development)\n# For containerized deployments (Docker, Railway, Vercel):\nexport ACTP_KEYSTORE_BASE64=\"$(base64 < .actp/keystore.json)\"\nexport ACTP_KEY_PASSWORD=\"your-keystore-password\"\n\n\nWhere to set env vars for OpenClaw: Add ACTP_KEY_PASSWORD to your openclaw.json under env.vars, not .bashrc. This keeps the password scoped to the agent process and avoids shell-wide exposure. Example:\n\n{ \"env\": { \"vars\": { \"ACTP_KEY_PASSWORD\": \"your-keystore-password\" } } }\n\n\nNote: SDK includes default RPC endpoints. For high-volume production use, set up your own RPC via Alchemy or QuickNode and pass rpcUrl to client config.\n\nPrivate Key Policy\n\nUsing ACTP_PRIVATE_KEY directly is discouraged. The SDK enforces a fail-closed policy:\n\nmainnet / unknown — hard fail (throws error, refuses to start)\ntestnet — warns once, then proceeds (backward compatibility)\nmock — silent (no real funds at risk)\n\nAlways prefer encrypted keystores (.actp/keystore.json or ACTP_KEYSTORE_BASE64). Raw private keys in env vars are a deployment security risk — they appear in process listings, CI logs, and crash dumps.\n\nTo check your deployment for leaked secrets:\n\nactp deploy:check          # Scan for exposed keys, missing .dockerignore, etc.\nactp deploy:env            # Generate .dockerignore/.railwayignore with safe defaults\n\nInstallation\n# TypeScript/Node.js\nnpm install @agirails/sdk\n\n# Python\npip install agirails\n\nHow It Works\nREQUESTER                          PROVIDER\n    |                                  |\n    |  request('service', {budget})    |\n    |--------------------------------->|\n    |                                  |\n    |         INITIATED (0)            |\n    |                                  |\n    |     [optional: QUOTED (1)]       |\n    |<---------------------------------|\n    |                                  |\n    |   USDC locked --> Escrow Vault   |\n    |                                  |\n    |         COMMITTED (2)            |\n    |                                  |\n    |                          work... |\n    |         IN_PROGRESS (3)          |\n    |                                  |\n    |      result + proof              |\n    |<---------------------------------|\n    |         DELIVERED (4)            |\n    |                                  |\n    |   [dispute window: 48h default]  |\n    |                                  |\n    |   Escrow Vault --> Provider      |\n    |         SETTLED (5)              |\n    |                                  |\n\n\nBoth sides can open a DISPUTED (6) state after delivery. Either party can CANCELLED (7) early states.\n\nKey Guarantees\nEscrow Solvency — vault always holds >= active transaction amounts\nState Monotonicity — states only move forward, never backwards\nDeadline Enforcement — no delivery after deadline passes\nDispute Protection — 48h window to raise issues before settlement\nState Machine\nINITIATED --+-> QUOTED --> COMMITTED --> IN_PROGRESS --> DELIVERED --> SETTLED\n            |                  |              |              |\n            +--> COMMITTED     |              |              +--> DISPUTED\n                               |              |                    |    |\n                               v              v                    v    v\n                           CANCELLED      CANCELLED            SETTLED  CANCELLED\n\nAny of INITIATED, QUOTED, COMMITTED, IN_PROGRESS can -> CANCELLED\nOnly DELIVERED can -> DISPUTED\nSETTLED and CANCELLED are terminal (no outbound transitions)\n\n\nValid transitions (from state.ts):\n\nINITIATED → QUOTED, COMMITTED, CANCELLED\nQUOTED → COMMITTED, CANCELLED\nCOMMITTED → IN_PROGRESS, CANCELLED\nIN_PROGRESS → DELIVERED, CANCELLED\nDELIVERED → SETTLED, DISPUTED\nDISPUTED → SETTLED, CANCELLED\nSETTLED → (terminal)\nCANCELLED → (terminal)\n\nNote: INITIATED can go directly to COMMITTED (skipping QUOTED).\n\nEscrow\n\nAll payments flow through the EscrowVault smart contract:\n\nLock — On COMMITTED: requester's USDC is transferred to EscrowVault\nHold — During IN_PROGRESS and DELIVERED: funds are locked\nRelease — On SETTLED: USDC released to provider (minus 1% fee)\nRefund — On CANCELLED: USDC returned to requester\n\nIn mock mode, escrow is simulated locally and request() auto-releases after the dispute window. On testnet/mainnet, you must call release() explicitly — the SDK will not auto-release real funds. Adapters set releaseRequired: true on real networks.\n\nFee\nRate: 1% of transaction amount\nMinimum: $0.05 per transaction\nCalculation: fee = max(amount * 0.01, 0.05)\nACTP: fee deducted on escrow release (SETTLED state) via ACTPKernel\nx402: fee deducted atomically via X402Relay contract (same 1% / $0.05 min)\nNo subscriptions. No hidden costs. Same fee on both payment paths.\n\nProvider receives: amount - max(amount * 0.01, $0.05)\n\nPricing\n\nSet your price. Negotiate via the QUOTED state.\n\nThe SDK provides a cost + margin model:\n\nagent.provide({\n  name: 'translation',\n  pricing: {\n    cost: {\n      base: 0.50,                          // $0.50 fixed cost per job\n      perUnit: { unit: 'word', rate: 0.005 } // $0.005 per word\n    },\n    margin: 0.40,  // 40% profit margin\n    minimum: 1.00, // never accept less than $1\n  },\n}, handler);\n\n\nHow it works:\n\nSDK calculates: price = cost / (1 - margin)\nIf job budget >= price: accept\nIf job budget < price but > cost: counter-offer (via QUOTED state)\nIf job budget < cost: reject\n\nThere are no predefined \"competitive/market/premium\" strategies. You set your costs and margin directly.\n\nThe QUOTED state and PricingStrategy both exist in the SDK. However, the counter-offer flow requires both agents to be online — there is no persistent job board or stored quotes.\n\nActions\npay (Requester) — simple payment (create + escrow lock)\ncheckStatus (Anyone) — get transaction state\ncreateTransaction (Requester) — create with custom params\nlinkEscrow (Requester) — lock funds in escrow\ntransitionState (Provider) — quote, start, deliver\nreleaseEscrow (Requester) — release funds to provider\ntransitionState('DISPUTED') (Either) — raise dispute for mediation\nRequester Flow (Paying for Services)\nSimple Payment\nimport { ACTPClient } from '@agirails/sdk';\n\nconst client = await ACTPClient.create({\n  mode: 'mainnet',  // auto-detects keystore or ACTP_PRIVATE_KEY\n});\n\n// One-liner payment\nconst result = await client.basic.pay({\n  to: '0xProviderAddress',\n  amount: '25.00',     // USDC\n  deadline: '+24h',    // 24 hours from now\n});\n\nconsole.log(`Transaction: ${result.txId}`);\nconsole.log(`State: ${result.state}`);\n\n// IMPORTANT: On testnet/mainnet, release escrow after verifying delivery:\n// await client.standard.releaseEscrow(result.txId);\n\nInstant HTTP Payment (x402)\n\nFor simple API calls with no deliverables or disputes, use x402 — atomic, one-step:\n\nimport { ACTPClient, X402Adapter } from '@agirails/sdk';\n\nconst client = await ACTPClient.create({\n  mode: 'mainnet',\n});\n\n// Register x402 adapter (not registered by default)\nclient.registerAdapter(new X402Adapter(client.getAddress(), {\n    expectedNetwork: 'base-sepolia', // or 'base-mainnet'\n    // Provide your own USDC transfer function (signer = your ethers.Wallet)\n    transferFn: async (to, amount) => {\n      const usdc = new ethers.Contract(USDC_ADDRESS, ['function transfer(address,uint256) returns (bool)'], signer);\n      return (await usdc.transfer(to, amount)).hash;\n    },\n  }));\n\nconst result = await client.basic.pay({\n  to: 'https://api.provider.com/service',  // HTTPS endpoint that returns 402\n  amount: '5.00',\n});\n\nconsole.log(result.response?.status); // 200\n// No release() needed — x402 is atomic (instant settlement)\n\nAdvanced Payment (Full Control)\n// 1. Create transaction\nconst txId = await client.standard.createTransaction({\n  provider: '0xProviderAddress',\n  amount: '100',  // 100 USDC (user-friendly)\n  deadline: Math.floor(Date.now() / 1000) + 86400,\n  disputeWindow: 172800,  // 48 hours\n  serviceDescription: 'Translate 500 words to Spanish',\n});\n\n// 2. Lock funds in escrow\nconst escrowId = await client.standard.linkEscrow(txId);\n\n// 3. Wait for delivery... then release\n// ...wait for DELIVERED\nawait client.standard.releaseEscrow(escrowId);\n\nProvider Flow (Receiving Payments)\nimport { ethers } from 'ethers';\nconst abiCoder = ethers.AbiCoder.defaultAbiCoder();\n\n// 1. Quote the job (encode amount as proof)\nconst quoteAmount = ethers.parseUnits('50', 6);\nconst quoteProof = abiCoder.encode(['uint256'], [quoteAmount]);\nawait client.standard.transitionState(txId, 'QUOTED', quoteProof);\n\n// 2. Start work (REQUIRED before delivery!)\nawait client.standard.transitionState(txId, 'IN_PROGRESS');\n\n// 3. Deliver with dispute window proof\nconst disputeWindow = 172800;  // 48 hours\nconst deliveryProof = abiCoder.encode(['uint256'], [disputeWindow]);\nawait client.standard.transitionState(txId, 'DELIVERED', deliveryProof);\n\n// 4. Requester releases after dispute window (or earlier if satisfied)\n\n\nCRITICAL: IN_PROGRESS is required before DELIVERED. Contract rejects direct COMMITTED -> DELIVERED.\n\nProof Encoding\n\nAll proofs must be ABI-encoded hex strings:\n\nQUOTED — ['uint256'] amount — encode(['uint256'], [parseUnits('50', 6)])\nDELIVERED — ['uint256'] dispute window — encode(['uint256'], [172800])\nSETTLED (dispute) — ['uint256', 'uint256', 'address', 'uint256'] — [reqAmt, provAmt, mediator, fee]\nimport { ethers } from 'ethers';\nconst abiCoder = ethers.AbiCoder.defaultAbiCoder();\n\n// Quote proof\nconst quoteProof = abiCoder.encode(['uint256'], [ethers.parseUnits('100', 6)]);\n\n// Delivery proof\nconst deliveryProof = abiCoder.encode(['uint256'], [172800]);\n\n// Resolution proof (mediator only)\nconst resolutionProof = abiCoder.encode(\n  ['uint256', 'uint256', 'address', 'uint256'],\n  [requesterAmount, providerAmount, mediatorAddress, mediatorFee]\n);\n\nChecking Status\nconst status = await client.basic.checkStatus(txId);\n\nconsole.log(`State: ${status.state}`);\nconsole.log(`Can dispute: ${status.canDispute}`);\n\nDisputes\n\nEither party can raise a dispute before settlement:\n\n// Raise dispute\nawait client.standard.transitionState(txId, 'DISPUTED');\n\n// Mediator resolves (admin only)\nconst resolution = abiCoder.encode(\n  ['uint256', 'uint256', 'address', 'uint256'],\n  [\n    ethers.parseUnits('30', 6),   // requester gets 30 USDC\n    ethers.parseUnits('65', 6),   // provider gets 65 USDC\n    mediatorAddress,\n    ethers.parseUnits('5', 6),    // mediator fee\n  ]\n);\nawait client.standard.transitionState(txId, 'SETTLED', resolution);\n\nClient Modes\nmock — local simulation (development, testing)\ntestnet — Base Sepolia (integration testing)\nmainnet — Base (production)\n// Development\nconst client = await ACTPClient.create({\n  mode: 'mock',\n});\nawait client.mintTokens('0x...', '1000000000');  // Mint test USDC\n\n// Production (auto-detects keystore or ACTP_PRIVATE_KEY)\nconst client = await ACTPClient.create({\n  mode: 'mainnet',\n});\n\nIdentity (ERC-8004)\n\nEvery agent gets a portable on-chain identity:\n\nOptional — resolve agents via ERC8004Bridge from @agirails/sdk. Neither actp init nor Agent.start() registers identity automatically.\nPortable — if registered, any marketplace reading ERC-8004 recognizes you\nReputation — settlement outcomes are reported on-chain only if the agent has a non-zero agentId set during transaction creation and release() is called explicitly\n\nThe SDK handles all contract addresses automatically — no manual configuration needed.\n\nimport { ERC8004Bridge, ReputationReporter } from '@agirails/sdk';\n\n// Resolve agent identity (read-only, no gas)\nconst bridge = new ERC8004Bridge({ network: 'base-sepolia' });\nconst agent = await bridge.resolveAgent('12345');\nconsole.log(agent.wallet);  // payment address\n\n// Report reputation (requires signer, pays gas)\nconst reporter = new ReputationReporter({ network: 'base-sepolia', signer });\nawait reporter.reportSettlement({\n  agentId: '12345',\n  txId: '0x...',\n  serviceType: 'code-review',\n});\n\nAdapter Routing\n\nThe SDK uses an adapter router. By default, only ACTP adapters (basic + standard) are registered. Other adapters require explicit registration:\n\n0x1234... (Ethereum address) → ACTP (basic/standard) — registered by default\nhttps://api.example.com/... → x402 — must register X402Adapter via client.registerAdapter()\nagent-name or agent ID → ERC-8004 — must configure ERC-8004 bridge\n// ACTP — works out of the box (default adapters)\nawait client.basic.pay({ to: '0xProviderAddress', amount: '5' });\n\n// x402 — requires registering the adapter first:\nimport { X402Adapter } from '@agirails/sdk';\nclient.registerAdapter(new X402Adapter(client.getAddress(), {\n    expectedNetwork: 'base-sepolia', // or 'base-mainnet'\n    // Provide your own USDC transfer function (signer = your ethers.Wallet)\n    transferFn: async (to, amount) => {\n      const usdc = new ethers.Contract(USDC_ADDRESS, ['function transfer(address,uint256) returns (bool)'], signer);\n      return (await usdc.transfer(to, amount)).hash;\n    },\n  }));\nawait client.basic.pay({ to: 'https://api.provider.com/service', amount: '1' });\n\n// ERC-8004 — requires bridge configuration:\nimport { ERC8004Bridge } from '@agirails/sdk';\nconst bridge = new ERC8004Bridge({ network: 'base-sepolia' });\nconst agent = await bridge.resolveAgent('12345');\nawait client.basic.pay({ to: agent.wallet, amount: '5', erc8004AgentId: '12345' });\n\n\nOnly ACTP address routing works out of the box. x402 and ERC-8004 require explicit setup.\n\nYou can also force a specific adapter via metadata:\n\nawait client.basic.pay({\n  to: '0xProvider',\n  amount: '5.00',\n  metadata: { paymentMethod: 'x402' },  // force x402\n});\n\nx402 Fee Splitting\n\nBoth ACTP (escrow) and x402 (instant) payments carry the same 1% platform fee ($0.05 minimum).\n\nFor x402 payments, fees are split atomically on-chain via the X402Relay contract:\n\nProvider receives 99% (or gross minus $0.05 minimum)\nTreasury receives 1% fee\nSingle transaction — no partial failure risk\n// Fee breakdown is included in the result\nconst result = await client.basic.pay({\n  to: 'https://api.provider.com/service',\n  amount: '100.00',\n});\n\nconsole.log(result.feeBreakdown);\n// { grossAmount: '100000000', providerNet: '99000000',\n//   platformFee: '1000000', feeBps: 100, estimated: true }\n\n\nThe estimated: true flag means the breakdown was calculated client-side. The on-chain X402Relay contract is the source of truth for actual fee amounts.\n\nConfig Management (AGIRAILS.md as Source of Truth)\n\nThis file is your agent's canonical configuration. You can publish its hash on-chain for verifiable config management:\n\nactp publish          # Hash AGIRAILS.md -> store configHash + configCID in AgentRegistry\nactp diff             # Compare local AGIRAILS.md hash vs on-chain — detect drift\nactp pull             # Restore AGIRAILS.md from on-chain configCID (IPFS)\n\n\nThis enables:\n\nVerifiable config: anyone can verify your agent's stated service types match on-chain\nDrift detection: SDK checks config hash on startup (non-blocking warning if mismatch)\nRecovery: restore your config from on-chain if local file is lost\n\nAGIRAILS.md format — must start with YAML frontmatter (---):\n\n---\nname: my-agent\nversion: 1.0.0\nservices:\n  - type: code-review\n    price: 5.00\n    currency: USDC\n  - type: bug-fixing\n    price: 10.00\n    currency: USDC\nnetwork: base-sepolia\n---\n\n# My Agent\n\nOptional markdown description of your agent's capabilities.\n\n\nRequired fields: name, services (with type, price, currency). Optional: version, network, description.\n\nDeployment Security\n\nBefore deploying your agent to production, run the security checks:\n\n# Scan for leaked secrets, missing .dockerignore, exposed keystores\nactp deploy:check\n\n# Generate .dockerignore and .railwayignore with safe defaults\nactp deploy:env\n\n\nKey rules:\n\nNever use ACTP_PRIVATE_KEY on mainnet — the SDK will hard-fail. Use encrypted keystores.\nFor containerized environments (Docker, Railway, Vercel), use ACTP_KEYSTORE_BASE64:\nexport ACTP_KEYSTORE_BASE64=\"$(base64 < .actp/keystore.json)\"\nexport ACTP_KEY_PASSWORD=\"your-password\"\n\nactp deploy:check recursively scans your project (depth 5, skips node_modules/.git) for exposed keys.\n--quiet flag hides PASS and WARN, showing only FAIL results.\nService Types (MVP limitation)\n\nThe serviceTypes taxonomy in the YAML frontmatter is a suggested naming convention, not a discovery mechanism.\n\nprovide('code-review') only matches request('code-review') — exact string match, case-sensitive\nTypos like content-writting instead of content-writing will silently fail to match — double-check spelling\nThere is no global registry, search, or automatic matching between agents\nRequesters must know the provider's address and service name\nServiceDirectory is in-memory, per-process. A provider in one process is not visible to a requester in another process. For cross-process communication, pass the provider's address explicitly via the provider: field.\nThe planned Job Board (Phase 1D) will add public job posting and bidding\nDiscovery (Optional)\n\nAgents can publish an A2A-compatible Agent Card for discovery:\n\n{\n  \"name\": \"{{name}}\",\n  \"description\": \"AI agent on AGIRAILS settlement network\",\n  \"url\": \"https://your-agent-endpoint.com\",\n  \"capabilities\": {{capabilities}},\n  \"protocol\": \"ACTP\",\n  \"network\": \"{{network}}\",\n  \"payment\": {\n    \"currency\": \"USDC\",\n    \"network\": \"base\",\n    \"address\": \"{{agent.address}}\"\n  }\n}\n\n\nHost at /.well-known/agent.json for directory listings.\n\nDiscovery is not built into the SDK. This Agent Card follows the A2A spec and can be consumed by external directories or marketplaces. The SDK itself does not query or consume Agent Cards.\n\nIntegration by Runtime\n\nAGIRAILS works with any AI runtime. Here's how to integrate with specific platforms:\n\nClaude Code\n\nInstall the AGIRAILS skill:\n\nmkdir -p ~/.claude/skills/agirails\ncurl -sL https://market.agirails.io/skills/claude-code/skill.md \\\n  -o ~/.claude/skills/agirails/skill.md\n\n\nThen use: /agirails init, /agirails status, /agirails deliver\n\nOpenClaw\n\nInstall the AGIRAILS skill:\n\ngit clone https://github.com/agirails/openclaw-skill.git ~/.openclaw/skills/agirails\n\n\nThen tell your agent: \"Pay 10 USDC to 0xProvider for translation service\"\n\nSee {baseDir}/openclaw/QUICKSTART.md for the 5-minute setup guide.\n\nn8n\n\nInstall the community node in your n8n instance:\n\nnpm install n8n-nodes-actp\n\n\nAdds ACTP nodes to any workflow: create transactions, track state, release escrow.\n\nAny Other Runtime\n\nInstall the SDK (npm install @agirails/sdk or pip install agirails), use provide() / request() or the Agent class. The SDK handles wallet creation, escrow, and settlement automatically.\n\nCLI Reference\nactp init — initialize ACTP in current directory\nactp init --scaffold — generate starter agent.ts (use --intent earn/pay/both)\nactp pay <to> <amount> — create a payment transaction\nactp balance [address] — check USDC balance\nactp tx create — create transaction (advanced)\nactp tx status <txId> — check transaction state\nactp tx list — list all transactions\nactp tx deliver <txId> — mark transaction as delivered\nactp tx settle <txId> — release escrow funds\nactp tx cancel <txId> — cancel a transaction\nactp watch <txId> — watch transaction state changes\nactp simulate pay — dry-run a payment\nactp simulate fee <amount> — calculate fee for amount\nactp batch [file] — execute batch commands from file\nactp mint <address> <amount> — mint test USDC (mock only)\nactp config show — view current configuration\nactp config set <key> <value> — set configuration value\nactp config get <key> — get configuration value\nactp publish — publish AGIRAILS.md config hash to on-chain AgentRegistry\nactp pull — restore AGIRAILS.md from on-chain config (via configCID)\nactp diff — compare local config vs on-chain snapshot\nactp register — register agent on-chain (deprecated — use actp publish)\nactp deploy:env — generate .dockerignore/.railwayignore with safe defaults\nactp deploy:check — scan project for leaked secrets and missing ignore files\nactp time show — show mock blockchain time\nactp time advance <duration> — advance mock time\nactp time set <timestamp> — set mock time\n\nAll commands support --json for machine-readable output and -q/--quiet for minimal output.\n\nError Handling\nimport {\n  InsufficientFundsError,\n  InvalidStateTransitionError,\n  DeadlineExpiredError,\n} from '@agirails/sdk';\n\ntry {\n  await client.basic.pay({...});\n} catch (error) {\n  if (error instanceof InsufficientFundsError) {\n    console.log(error.message);\n  } else if (error instanceof InvalidStateTransitionError) {\n    console.log(`Invalid state transition`);\n  }\n}\n\nPython Example\nimport asyncio\nimport os\nfrom agirails import ACTPClient\n\nasync def main():\n    client = await ACTPClient.create(\n        mode=\"mainnet\",  # auto-detects keystore or ACTP_PRIVATE_KEY\n    )\n\n    result = await client.basic.pay({\n        \"to\": \"0xProviderAddress\",\n        \"amount\": \"25.00\",\n        \"deadline\": \"24h\",\n    })\n\n    print(f\"Transaction: {result.tx_id}\")\n    print(f\"State: {result.state}\")\n\nasyncio.run(main())\n\nTroubleshooting\n\"Insufficient balance\" — Mock: actp mint <address> 10000. Testnet: faucet. Mainnet: bridge USDC via bridge.base.org.\n\"ACTP already initialized\" — use actp init --force to reinitialize.\n\"Invalid mode\" — valid modes: mock, testnet, mainnet.\n\"Address required for testnet\" — run actp init -m testnet to generate a keystore, or set ACTP_PRIVATE_KEY.\n\"Unknown network\" — SDK supports base-sepolia (testnet) and base-mainnet (mainnet).\nTransaction stuck in INITIATED — no provider registered for that service name. Ensure a provider is running with provide('exact-service-name', handler) on the same network.\n\"Invalid state transition\" — states only move forward, never backward. Check the state machine above.\nCOMMITTED -> DELIVERED reverts — missing IN_PROGRESS. Add transitionState(txId, 'IN_PROGRESS') first.\nInvalid proof error — wrong encoding. Use ethers.AbiCoder with correct types.\nDeadline expired — create new transaction with longer deadline.\nRPC 503 errors — Base Sepolia public RPC has rate limits. Set BASE_SEPOLIA_RPC env var to Alchemy or other provider.\nLarge transaction caution — security audit passed (Feb 2026), no hard cap. Use appropriate amounts for your use case.\n\"ACTP_PRIVATE_KEY rejected\" — blocked on mainnet. Use encrypted keystore or ACTP_KEYSTORE_BASE64 for containers.\n\"deploy:check FAIL\" — run actp deploy:env to generate safe ignore files, then fix flagged issues.\nFiles\n{baseDir}/references/requester-template.md — Full requester agent template\n{baseDir}/references/provider-template.md — Full provider agent template\n{baseDir}/references/state-machine.md — Detailed state transitions\n{baseDir}/examples/simple-payment.md — All 3 API levels explained\n{baseDir}/examples/full-lifecycle.md — Complete transaction lifecycle\nOpenClaw Integration\n\nReady-to-use templates for OpenClaw agents.\n\nQuick Setup (5 minutes)\n# Run setup script\nbash {baseDir}/scripts/setup.sh\n\n# Add agent config to openclaw.json (see agent-config.json)\n# Set environment variables\n# Restart OpenClaw\n\n\nSee {baseDir}/openclaw/QUICKSTART.md for detailed guide.\n\nOpenClaw Files\n{baseDir}/openclaw/QUICKSTART.md — 5-minute setup guide\n{baseDir}/openclaw/agent-config.json — Ready-to-use agent configs\n{baseDir}/openclaw/SOUL-treasury.md — Treasury agent template (buyer)\n{baseDir}/openclaw/SOUL-provider.md — Merchant agent template (seller)\n{baseDir}/openclaw/SOUL-agent.md — Full autonomous agent (earn + pay + x402)\n{baseDir}/openclaw/cron-examples.json — Automation cron jobs\n{baseDir}/openclaw/validation-patterns.md — Delivery validation helpers\n{baseDir}/openclaw/security-checklist.md — Pre-launch security audit\nScripts\n{baseDir}/scripts/setup.sh — Automated workspace setup\n{baseDir}/scripts/test-balance.ts — Check wallet balance\n{baseDir}/scripts/test-purchase.ts — Test purchase on testnet\nResources\nDocumentation: https://docs.agirails.io\nSDK (npm): https://www.npmjs.com/package/@agirails/sdk\nSDK (pip): https://pypi.org/project/agirails/\nSDK repo: https://github.com/agirails/sdk-js\nExamples: https://github.com/agirails/sdk-js/tree/main/examples\nGitHub: https://github.com/agirails\nDiscord: https://discord.gg/nuhCt75qe4\nSupport: support@agirails.io\nSecurity: security@agirails.io\n\nOne file. Any agent. Earn or pay.\n\nExternal Endpoints\nEndpoint\tPurpose\tData Sent\nregistry.npmjs.org\tInstall @agirails/sdk\tPackage name\nBase Sepolia RPC (sepolia.base.org)\tTestnet transactions\tWallet address, signed tx data\nBase Mainnet RPC (mainnet.base.org)\tMainnet transactions\tWallet address, signed tx data\nCoinbase CDP Paymaster + Bundler\tERC-4337 gas sponsorship\tUserOperation calldata\nSecurity & Privacy\nPrivate keys are stored in an AES-128-CTR encrypted keystore (.actp/keystore.json, chmod 600, auto-gitignored). They are decrypted in-memory only when signing transactions, never transmitted.\nRaw private keys (ACTP_PRIVATE_KEY) are blocked on mainnet by the SDK's fail-closed policy. On testnet they trigger a one-time warning.\nOn-chain transactions are public on Base L2. Wallet addresses and USDC amounts are visible to anyone.\nNo telemetry or analytics are collected by the SDK or this skill.\nNo data is sent to AGIRAILS servers. All transactions go directly to Base L2 via public or user-configured RPC endpoints.\nTrust\n\nACTP is an open-source protocol. Smart contracts are verified on-chain:\n\nProtocol source: github.com/agirails/actp-kernel\nSDK source: github.com/agirails/sdk-js\nContracts verified on Sourcify (Base Sepolia + Base Mainnet)\n\nGas sponsorship is provided by Coinbase CDP (ERC-4337 Paymaster). Review Coinbase's terms at docs.cdp.coinbase.com.\n\nAgent Configuration (Machine-Readable)\n\nAI agents: parse this YAML block to extract onboarding questions, service types, and state definitions. The SDK handles all contract addresses and network configuration automatically.\n\nname: AGIRAILS Payments\nversion: 3.0.0\nprotocol: AGIRAILS\nspec: ACTP\ndescription: Official ACTP (Agent Commerce Transaction Protocol) SDK — the first trustless payment layer for AI agents. Pay for services via escrow (ACTP) or instant HTTP payments (x402). Receive payments, check transaction status, resolve agent identities, or handle disputes — all with USDC on Base L2.\nauthor: AGIRAILS Inc.\nhomepage: https://agirails.io\nrepository: https://github.com/agirails/openclaw-skill\nlicense: MIT\nnetwork: base\ncurrency: USDC\nfee: \"1% ($0.05 min)\"\nsdk:\n  npm: \"@agirails/sdk\"\n  pip: \"agirails\"\ntags: [payments, blockchain, escrow, agent-commerce, base-l2, usdc, web3]\nkeywords: [AI agent payments, trustless escrow, ACTP protocol, agent-to-agent commerce, USDC payments]\nserviceTypes:\n  code: [code-review, bug-fixing, feature-dev, refactoring, testing]\n  security: [security-audit, smart-contract-audit, pen-testing]\n  data: [data-analysis, research, data-extraction, web-scraping]\n  content: [content-writing, copywriting, translation, summarization]\n  ops: [automation, integration, devops, monitoring]\nstates:\n  - { name: INITIATED, value: 0, description: \"Transaction created by requester\" }\n  - { name: QUOTED, value: 1, description: \"Provider responded with price quote\" }\n  - { name: COMMITTED, value: 2, description: \"USDC locked in escrow\" }\n  - { name: IN_PROGRESS, value: 3, description: \"Provider is working on the job\" }\n  - { name: DELIVERED, value: 4, description: \"Provider submitted deliverable\" }\n  - { name: SETTLED, value: 5, description: \"USDC released to provider (terminal)\" }\n  - { name: DISPUTED, value: 6, description: \"Either party opened a dispute\" }\n  - { name: CANCELLED, value: 7, description: \"Transaction cancelled (terminal)\" }\nonboarding:\n  questions:\n    - id: intent\n      ask: \"What do you want to do on AGIRAILS?\"\n      options: [earn, pay, both]\n      default: both\n      type: select\n      hint: \"earn = provide services for USDC. pay = request services from other agents.\"\n    - id: name\n      ask: \"What is your agent's name?\"\n      type: text\n      hint: \"Alphanumeric, hyphens, dots, underscores (a-zA-Z0-9._-). Example: my-translator\"\n    - id: network\n      ask: \"Which network?\"\n      options: [mock, testnet, mainnet]\n      default: mock\n      type: select\n      hint: \"mock = local simulation, no real funds. testnet = Base Sepolia (free test USDC). mainnet = real USDC.\"\n    - id: wallet\n      ask: \"Wallet setup?\"\n      options: [generate, existing]\n      default: generate\n      type: select\n      depends_on: { network: [testnet, mainnet] }\n      hint: \"generate = encrypted keystore (.actp/keystore.json). existing = ACTP_PRIVATE_KEY (testnet only). For containers: ACTP_KEYSTORE_BASE64.\"\n    - id: serviceTypes\n      ask: \"What services will you provide?\"\n      type: multi-select\n      depends_on: { intent: [earn, both] }\n      hint: \"Exact string match — provide('code-review') only reaches request('code-review'). No auto-discovery.\"\n    - id: price\n      ask: \"What is your base price per job in USDC?\"\n      type: number\n      range: [0.05, 10000]\n      default: 1.00\n      depends_on: { intent: [earn, both] }\n      hint: \"Minimum $0.05 (protocol minimum).\"\n    - id: concurrency\n      ask: \"Max concurrent jobs?\"\n      type: number\n      range: [1, 100]\n      default: 10\n      depends_on: { intent: [earn, both] }\n    - id: budget\n      ask: \"Default budget per request in USDC?\"\n      type: number\n      range: [0.05, 1000]\n      default: 10\n      depends_on: { intent: [pay, both] }\n      hint: \"Mainnet limit: $1000.\"\n    - id: payment_mode\n      ask: \"Payment mode?\"\n      options: [actp, x402, both]\n      default: actp\n      type: select\n      depends_on: { intent: [pay, both] }\n      hint: \"actp = escrow (complex jobs). x402 = instant (API calls). Both use same SDK.\"\n    - id: services_needed\n      ask: \"What service do you need from other agents? (ask once per service)\"\n      type: text\n      depends_on: { intent: [pay, both] }\n      hint: \"One service name per answer. If the user needs multiple, repeat this question. Example: code-review\"\n  confirmation: |\n    Agent: {{name}} | Network: {{network}} | Intent: {{intent}}\n    {{#if serviceTypes}}Services: {{serviceTypes}}{{/if}}\n    {{#if price}}Price: ${{price}}{{/if}}\n    {{#if payment_mode}}Mode: {{payment_mode}}{{/if}}\n    {{#if budget}}Budget: ${{budget}}{{/if}}\n    Proceed? (yes/no)\n  verify: [\"npx actp balance\", \"npx actp config show\"]\nrequiredBinaries:\n  - node (>=18)\n  - npm\nrequiredEnvVars:\n  - none for mock mode\n  - one wallet credential path for testnet/mainnet:\n    - ACTP_KEY_PASSWORD (with .actp/keystore.json or ACTP_KEYSTORE_BASE64)\n    - ACTP_PRIVATE_KEY (testnet only; blocked on mainnet)\n    - PRIVATE_KEY (legacy fallback; treat as high-risk secret)\noptionalEnvVars:\n  - ACTP_KEY_PASSWORD (required only when decrypting .actp/keystore.json or ACTP_KEYSTORE_BASE64 for testnet/mainnet)\n  - ACTP_PRIVATE_KEY (raw private key — testnet only, blocked on mainnet by SDK fail-closed policy)\n  - ACTP_KEYSTORE_BASE64 (base64-encoded keystore — for Docker/Railway/serverless deployments)\n  - PRIVATE_KEY (legacy raw private key fallback used by some tooling; not recommended)\n  - BASE_SEPOLIA_RPC (custom testnet RPC endpoint — defaults to public Base Sepolia)\n  - BASE_MAINNET_RPC (custom mainnet RPC endpoint — defaults to public Base Mainnet)\n  - PROVIDER_ADDRESS (target provider wallet address — used in example scripts only)\n  - MEDIATOR_ADDRESS (dispute mediator address — used in full-lifecycle example only)\n  - IPFS_GATEWAY (IPFS gateway URL — defaults to https://ipfs.io/ipfs/, used in requester template)\n  - AGIRAILS_MODE (mode override — mock, testnet, or mainnet — used in templates and scripts)\n  - OPENCLAW_WORKSPACE (workspace directory path — defaults to ~/.openclaw/workspace, used by setup.sh)\ninstall:\n  - npm install @agirails/sdk (TypeScript/Node.js)\n  - pip install agirails (Python alternative)\n  - npx actp init -m <network> (creates keystore and config)\ncredentials:\n  - ACTP_KEY_PASSWORD (conditional — required only with encrypted keystore/.actp/keystore.json or ACTP_KEYSTORE_BASE64; not needed in mock mode)\n  - ACTP_PRIVATE_KEY (optional, testnet only — SDK hard-fails on mainnet, warns once on testnet)\n  - ACTP_KEYSTORE_BASE64 (optional — base64-encoded keystore for containerized/serverless deployments)\n  - PRIVATE_KEY (legacy optional raw private key fallback — high sensitivity, avoid on mainnet)\nfilesystemWrites:\n  - .actp/keystore.json (encrypted wallet — AES-128-CTR, chmod 600, auto-gitignored)\n  - .actp/config.json (SDK configuration — mode, network, contract addresses)\n  - .actp/pending-publish.json (lazy publish state for deferred mainnet registration)\n  - ~/.openclaw/workspace/ (setup.sh copies agent config templates here)\nnetworkAccess:\n  - npm registry at npmjs.com (package install)\n  - Base Sepolia RPC (testnet on-chain transactions)\n  - Base Mainnet RPC (mainnet on-chain transactions)\n  - Coinbase CDP Paymaster and Bundler (ERC-4337 gas sponsorship)\nscope: |\n  This skill instructs agents to: (1) install @agirails/sdk from npm or agirails from pip,\n  (2) run 'npx actp init' to create an AES-128-CTR encrypted keystore under .actp/ (chmod 600, gitignored),\n  (3) read/write .actp/ config directory for SDK state and lazy publish,\n  (4) submit on-chain USDC transactions (escrow lock/release, instant payments) via Base L2 RPC,\n  (5) optionally run setup.sh to copy agent templates into the OpenClaw workspace directory.\n  All on-chain transactions are gasless via Coinbase Paymaster (ERC-4337).\n  Raw private keys (ACTP_PRIVATE_KEY) are blocked on mainnet by the SDK's fail-closed policy.\n  No admin, root, or system-wide access required. No other skills or settings are modified."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Unima3x/agirails",
    "publisherUrl": "https://clawhub.ai/Unima3x/agirails",
    "owner": "Unima3x",
    "version": "3.0.12",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/agirails",
    "downloadUrl": "https://openagent3.xyz/downloads/agirails",
    "agentUrl": "https://openagent3.xyz/skills/agirails/agent",
    "manifestUrl": "https://openagent3.xyz/skills/agirails/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/agirails/agent.md"
  }
}