diff --git a/.agents/skills/omniclaw-cli/scripts/generate_cli_reference.sh b/.agents/skills/omniclaw-cli/scripts/generate_cli_reference.sh deleted file mode 100755 index 644523e..0000000 --- a/.agents/skills/omniclaw-cli/scripts/generate_cli_reference.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" -cd "$ROOT_DIR" -python3 .agents/skills/omniclaw-cli/scripts/generate_cli_reference.py diff --git a/.dockerignore b/.dockerignore index 5918ab1..b2b8939 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,7 +7,8 @@ logs tmp .runtime output/doc -docs/internal +internal +.agents dist build *.egg-info diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7bc8c67 --- /dev/null +++ b/.env.example @@ -0,0 +1,130 @@ +# OmniClaw environment template +# +# Copy to `.env` for local development. Never commit real secrets. +# Pick the sections that match your deployment role. + +# ============================================================================= +# Shared Network Configuration +# ============================================================================= + +# Supported examples: ETH-SEPOLIA, BASE-SEPOLIA, ARC-TESTNET +OMNICLAW_NETWORK=BASE-SEPOLIA +OMNICLAW_RPC_URL=https://sepolia.base.org + +# development, test, or production +OMNICLAW_ENV=development + +# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL +OMNICLAW_LOG_LEVEL=INFO + +# ============================================================================= +# Buyer / Seller Signing Key +# ============================================================================= + +# Private key used by the SDK or Financial Policy Engine for allowed actions. +# In production, use restricted infrastructure and secret management. +OMNICLAW_PRIVATE_KEY=0x... + +# ============================================================================= +# Financial Policy Engine +# ============================================================================= + +# Use this when an agent, worker, or partner integration should not hold raw key +# authority. The policy engine exposes the controlled payment API. +OMNICLAW_AGENT_TOKEN=replace-with-agent-token +OMNICLAW_AGENT_POLICY_PATH=./policy.json +OMNICLAW_OWNER_TOKEN=replace-with-owner-token + +# Policy hot reload interval in seconds. Use a larger value or disable reload in +# production if policies are deployed immutably. +OMNICLAW_POLICY_RELOAD_INTERVAL=5 + +# Optional persistence backend. +# Values: memory, redis +OMNICLAW_STORAGE_BACKEND=memory +OMNICLAW_REDIS_URL=redis://localhost:6379/0 + +# ============================================================================= +# Agent CLI Runtime +# ============================================================================= + +# Used by `omniclaw-cli` when acting as an agent execution layer. +OMNICLAW_SERVER_URL=http://127.0.0.1:8080 +OMNICLAW_TOKEN=replace-with-agent-token + +# Optional human-readable CLI output. Default output is agent-friendly JSON. +OMNICLAW_CLI_HUMAN=0 + +# ============================================================================= +# Circle Gateway / Nanopayments +# ============================================================================= + +# Required for Circle Gateway nanopayments, Gateway balance, and Circle-backed +# wallet operations. +CIRCLE_API_KEY=replace-with-circle-api-key + +# Entity secret for Circle wallet encryption. +# If your Circle account/API key already has an Entity Secret, set it here. +# Circle only allows one active Entity Secret per account/API key, so OmniClaw +# only auto-generates/registers a new one when no existing secret is provided or +# found in the managed local credential store. +ENTITY_SECRET= + +OMNICLAW_NANOPAYMENTS_ENABLED=true +OMNICLAW_NANOPAYMENTS_ENV=testnet +OMNICLAW_NANOPAYMENTS_AUTO_TOPUP=false +OMNICLAW_NANOPAYMENTS_TOPUP_THRESHOLD=1.00 +OMNICLAW_NANOPAYMENTS_TOPUP_AMOUNT=10.00 +OMNICLAW_NANOPAYMENTS_MICRO_THRESHOLD=1.00 + +# Optional Gateway contract override for seller GatewayWalletBatched metadata. +CIRCLE_GATEWAY_CONTRACT= + +# ============================================================================= +# Vendor / Enterprise SDK Seller +# ============================================================================= + +# Vendor wallet that receives seller payments. +SELLER_ADDRESS=0x... + +# Default Circle seller path: +# payment=client.sell("$0.25", seller_address=os.environ["SELLER_ADDRESS"]) + +# Thirdweb managed x402 seller path: +# payment=client.sell("$0.25", seller_address=os.environ["SELLER_ADDRESS"], facilitator="thirdweb") +THIRDWEB_SECRET_KEY= +THIRDWEB_SERVER_WALLET_ADDRESS= +THIRDWEB_X402_NETWORK=base-sepolia + +# OmniClaw self-hosted exact seller path: +# payment=client.sell("$0.25", seller_address=os.environ["SELLER_ADDRESS"], facilitator="omniclaw") +OMNICLAW_X402_SELF_HOSTED_FACILITATOR_URL=http://127.0.0.1:4022 +OMNICLAW_X402_EXACT_NETWORK_PROFILE=ARC-TESTNET + +# ============================================================================= +# Self-Hosted Exact Facilitator +# ============================================================================= + +# Run with: +# omniclaw facilitator exact --network-profile ARC-TESTNET --port 4022 +OMNICLAW_X402_FACILITATOR_PRIVATE_KEY=0x... +OMNICLAW_X402_FACILITATOR_NETWORK_PROFILE=ARC-TESTNET +OMNICLAW_X402_FACILITATOR_RPC_URL=https://rpc.testnet.arc.network +OMNICLAW_X402_FACILITATOR_NETWORKS=eip155:5042002 +OMNICLAW_X402_FACILITATOR_HOST=0.0.0.0 +OMNICLAW_X402_FACILITATOR_PORT=4022 + +# ============================================================================= +# Production Hardening +# ============================================================================= + +# Required for production seller replay protection. +OMNICLAW_SELLER_NONCE_REDIS_URL=redis://localhost:6379/1 +OMNICLAW_SELLER_REQUIRE_DISTRIBUTED_NONCE=true + +# Strict settlement should remain enabled for production payment gates. +OMNICLAW_STRICT_SETTLEMENT=true + +# Webhook verification and deduplication. +OMNICLAW_WEBHOOK_VERIFICATION_KEY= +OMNICLAW_WEBHOOK_DEDUP_DB_PATH=/var/lib/omniclaw/webhook_dedup.sqlite3 diff --git a/.gitignore b/.gitignore index 3831e67..4d434a3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .env .env.* +!.env.example .env.local *.pem *.key @@ -46,8 +47,10 @@ tmp/ .runtime/ output/doc/ -# Internal docs / GTM materials -docs/internal/ +# Private operating workspace +# Keep the root internal workspace out of git. +internal/ +.agents/ # OS Thumbs.db diff --git a/CHANGELOG.md b/CHANGELOG.md index 0662f76..56d3535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to OmniClaw are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added +- Added the owner/operator `omniclaw facilitator exact` command for self-hosted x402 exact settlement. +- Added public facilitator documentation covering Circle Gateway, external facilitators, and OmniClaw self-hosted exact settlement. +- Added Arc Testnet exact-settlement support documentation using CAIP-2 `eip155:5042002`. + +### Changed +- Moved the owner/operator CLI entrypoint to `omniclaw.admin_cli:main` so it no longer conflicts with the `omniclaw.cli` agent CLI package. +- Updated release artifact verification for the new admin CLI module and package layout. + ## [0.0.5] - 2026-04-04 ### Fixed diff --git a/README.md b/README.md index b350c9b..5346d65 100644 --- a/README.md +++ b/README.md @@ -1,327 +1,245 @@ # OmniClaw -**Economic Execution and Control Layer for Agentic Systems** — Policy-controlled payments with Circle Gateway nanopayments (EIP-3009), x402 protocol support, gasless transactions, and per-agent wallet isolation. +**Policy-controlled payments for AI agents and machine services.** -📦 [PyPI](https://pypi.org/project/omniclaw/) · 🧪 [Tests: 1220 passed](tests/) +[![CI](https://github.com/omnuron/omniclaw/actions/workflows/ci.yml/badge.svg)](https://github.com/omnuron/omniclaw/actions/workflows/ci.yml) +[![PyPI](https://img.shields.io/pypi/v/omniclaw.svg)](https://pypi.org/project/omniclaw/) +[![Python](https://img.shields.io/pypi/pyversions/omniclaw.svg)](https://pypi.org/project/omniclaw/) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ---- +OmniClaw lets software agents pay, earn, and access paid APIs without giving the agent unrestricted wallet authority. -## Why OmniClaw? +The owner runs a **Financial Policy Engine**. Agents and applications execute through constrained interfaces. Every payment is checked against policy before funds move. -In the Agent Era, software can act economically. But current wallets fail when software, not humans, is the operator: +## Why It Exists -- **Full key access** = extreme risk (agent can drain the wallet) -- **Human approval** = kills speed and autonomy -- **No spending limits** = agent can spend unlimited +AI agents can browse, reason, call APIs, and run workflows. The hard part is money movement. -Where Stripe helps merchants accept human payments, OmniClaw governs autonomous agents making machine payments — with policy, trust verification, and concurrency safety built in. +OmniClaw solves the control problem: -**OmniClaw solves this** by separating: -1. **Financial Policy Engine** (owner runs) - holds private keys, enforces policy -2. **Zero-Trust Execution Layer** (agent uses) - constrained CLI that only does what policy allows +- agents can pay for services without receiving raw wallet control +- sellers can monetize APIs through x402-compatible payment gates +- operators can enforce budgets, recipient rules, confirmations, and route selection +- payments can settle through Circle Gateway, standard x402 exact settlement, or a self-hosted exact facilitator -The agent **never touches the private key**. It only talks to the CLI. The owner decides what the agent can do via policy.json. +## Core Surfaces ---- +| Surface | Used By | Purpose | +| --- | --- | --- | +| Financial Policy Engine | owner / operator | Enforces policy, signs allowed actions, exposes the control API | +| `omniclaw-cli` | agents / automation | Executes buyer payments through the policy engine without direct key access | +| Python SDK | developers / vendors | Embeds buyer payments and seller monetization into Python applications | +| Seller middleware | vendors / enterprises | Turns production HTTP routes into paid x402 endpoints | +| Exact facilitator | operators | Optional self-hosted x402 exact settlement for supported EVM networks | -## Architecture: Three Components +## Install -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ OMNICLAW SYSTEM │ -├─────────────────────────────────────────────────────────────────────┤ -│ │ -│ OWNER SIDE (runs the Financial Policy Engine) AGENT SIDE (uses CLI) │ -│ ════════════════════════════════════════════════ ═══════════════════════ │ -│ │ -│ ┌─────────────────────────────┐ ┌─────────────────────┐ │ -│ │ Financial Policy Engine │ │ OmniClaw CLI │ │ -│ │ (uvicorn server) │◄──────────────►│ (zero-trust exec) │ │ -│ │ │ HTTPS │ │ │ -│ │ - Holds private key │ │ - pay │ │ -│ │ - Enforces policy │ │ - deposit │ │ -│ │ - Signs transactions │ │ - withdraw │ │ -│ └─────────────────────────────┘ └─────────────────────┘ │ -│ │ │ │ -│ │ Circle Nanopayment │ │ -│ └──────────────┬──────────────────────┘ │ -│ │ │ -│ ┌──────▼──────┐ │ -│ │ Circle │ │ -│ │ Gateway │ │ -│ │ (USDC) │ │ -│ └─────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────┘ +```bash +pip install omniclaw ``` -### Why Two Parts? +For local development: -| Component | Who Runs It | What It Does | -|-----------|-------------|--------------| -| **Financial Policy Engine** | Owner/human | Holds private key, enforces policy, signs transactions | -| **CLI** (agent uses) | Agent | Zero-trust execution layer - constrained command surface, cannot bypass policy | +```bash +uv add omniclaw +``` ---- +## Choose The Right Path -## Key Concepts +| If you are building... | Use... | Why | +| --- | --- | --- | +| An agent that needs to buy services | Financial Policy Engine + `omniclaw-cli` | The agent can pay without holding raw wallet authority | +| A backend service that buys from paid APIs | Python SDK `client.pay(...)` | Programmatic payments inside your own app | +| A vendor or enterprise API | Python SDK `client.sell(...)` | Production paid endpoints inside your application | +| A temporary local paid agent service | `omniclaw-cli serve` | Fast agent-owned/local monetization, not the enterprise seller path | +| Custom or Arc exact settlement infrastructure | `omniclaw facilitator exact` | Self-hosted standard x402 `verify` / `settle` | -### 1. Two Wallets Every Agent Has +## Credential Model -Every agent has **two wallets**: +OmniClaw has two different key surfaces: -| Wallet | How It Works | -|--------|--------------| -| **EOA** (External Owned Account) | Derived from `OMNICLAW_PRIVATE_KEY`. Holds actual USDC on-chain. Used to sign deposits. | -| **Circle Developer Wallet** | Created via policy.json. Where withdrawn funds go. The "circle wallet." | +- `OMNICLAW_PRIVATE_KEY` is the EOA key used for direct x402 exact settlement and Circle Gateway nanopayment signing. +- `ENTITY_SECRET` is Circle's developer-controlled wallet encryption secret. -### 2. Why Deposit + Pay + Withdraw? +If your Circle account/API key already has an Entity Secret, set it directly. Circle allows one active Entity Secret per account/API key. OmniClaw only auto-generates and registers a new one when no existing secret is provided or found in its managed local credential store. -``` -Your USDC starts here: Then moves here: Ends up here: -┌──────────┐ ┌────────────┐ ┌──────────────┐ -│ EOA │ ─deposit───────► │ Gateway │ ──pay──────► │ Seller │ -│ (on-chain)│ (on-chain) │ Contract │ (x402) │ EOA │ -└──────────┘ └────────────┘ └──────────────┘ - │ │ - │ withdraw │ - └──────────────► Circle Developer Wallet +```bash +export CIRCLE_API_KEY="..." +export ENTITY_SECRET="your_existing_64_char_hex_entity_secret" +export OMNICLAW_PRIVATE_KEY="0x..." ``` -- **Deposit**: Move USDC from your EOA → Gateway (on-chain, costs gas) -- **Pay**: Use Gateway for gasless payments (x402 protocol) -- **Withdraw**: Move USDC from Gateway → your Circle wallet +For a non-interactive local setup: -### 3. Why Gasless Nanopayments? - -Circle's Gateway supports **EIP-3009** - off-chain authorization: -- No gas needed for payments -- Instant settlement -- Circle batches and settles on-chain -- Sub-cent transactions are economically viable - -This is what makes agent-to-agent commerce practical — agents can trade at high frequency without bleeding gas on every transaction. - -### 4. Seller Side: Accept Payments from Other Agents +```bash +omniclaw setup --api-key "$CIRCLE_API_KEY" --entity-secret "$ENTITY_SECRET" +``` -OmniClaw isn't just for buyers. You can protect your own endpoint behind x402 and accept payments from other agents: +## Buyer: Agent CLI -```python -from omniclaw.protocols.nanopayments import GatewayMiddleware +Use this when an autonomous agent or script should pay through the Financial Policy Engine. -# Protect any async endpoint -middleware = GatewayMiddleware( - price="0.01", # 0.01 USDC per call - seller_address="0xYourAddress", -) +Start the owner-side policy engine: -app = FastAPI() -app.add_middleware(GatewayMiddleware, price="0.01") +```bash +export OMNICLAW_PRIVATE_KEY="0x..." +export OMNICLAW_AGENT_TOKEN="agent-token" +export OMNICLAW_AGENT_POLICY_PATH="./policy.json" +export OMNICLAW_NETWORK="BASE-SEPOLIA" +export OMNICLAW_RPC_URL="https://sepolia.base.org" -@app.get("/api/data") -async def get_data(): - return {"data": "expensive information"} +omniclaw server --port 8080 ``` -This opens your service to agent-to-agent commerce — other agents can pay your endpoint using gasless nanopayments. - ---- - -## Quick Start - -### 1. Install +Configure the agent runtime: ```bash -pip install omniclaw -# or -uv add omniclaw +export OMNICLAW_SERVER_URL="http://localhost:8080" +export OMNICLAW_TOKEN="agent-token" ``` -### 2. Environment Variables (Required) +Pay a protected x402 URL: ```bash -# Required to run -export OMNICLAW_PRIVATE_KEY="0x..." # Your agent's private key -export OMNICLAW_AGENT_TOKEN="your-token" # Token from policy.json -export OMNICLAW_AGENT_POLICY_PATH="/path/to/policy.json" -export CIRCLE_API_KEY="your-circle-key" # Circle API key - -# Network (testnet or mainnet) -export OMNICLAW_NETWORK="ETH-SEPOLIA" # or ETH-MAINNET -export OMNICLAW_ENV="production" # set for mainnet - -# RPC for on-chain operations -export OMNICLAW_RPC_URL="https://..." -# Nanopayments CAIP-2 is derived from OMNICLAW_NETWORK (EVM only) +omniclaw-cli can-pay --recipient https://seller.example.com/compute +omniclaw-cli inspect-x402 --recipient https://seller.example.com/compute +omniclaw-cli pay --recipient https://seller.example.com/compute --idempotency-key job-123 ``` -### 3. Start Financial Policy Engine (Owner) +Pay a direct address: ```bash -uvicorn omniclaw.agent.server:app --port 8080 +omniclaw-cli pay \ + --recipient 0xRecipientAddress \ + --amount 5.00 \ + --purpose "service payment" \ + --idempotency-key job-123 ``` -This runs the Financial Policy Engine that holds the private key and enforces policy. +## Buyer: Python SDK -### 4. Configure CLI (Agent) +Use this when a Python service should pay programmatically. -Agent runtime should set these (no interactive setup required): +```python +from omniclaw import Network, OmniClaw -```bash -export OMNICLAW_SERVER_URL="http://localhost:8080" -export OMNICLAW_TOKEN="your-agent-token" -``` +client = OmniClaw(network=Network.BASE_SEPOLIA) -Optional: persist config locally for dev workflows: +result = await client.pay( + wallet_id="wallet-id", + recipient="https://seller.example.com/compute", + amount="1.00", + purpose="compute job", + idempotency_key="job-123", +) -```bash -omniclaw-cli configure --server-url http://localhost:8080 --token your-token --wallet primary +print(result.status, result.blockchain_tx or result.transaction_id) ``` -CLI output is agent-first (JSON, no banner). For human-friendly output set: +For x402 URLs, `amount` acts as the maximum spend allowed for that request. The seller's x402 requirements define the exact amount to settle. -```bash -export OMNICLAW_CLI_HUMAN=1 -``` +## Seller: Vendor / Enterprise SDK -Note: `omniclaw` and `omniclaw-cli` point to the same CLI. +Use this when a vendor, enterprise, or application team wants to monetize API routes. This is the default seller path for real products. -## Examples +```python +from fastapi import FastAPI +from omniclaw import OmniClaw -- `examples/local-economy/README.md` — canonical local buyer/seller flow -- `examples/business-compute/README.md` — business-facing paid compute and paid PDF seller using OmniClaw directly in a web app +app = FastAPI() +client = OmniClaw() + +@app.get("/premium-data") +async def premium_data( + payment=client.sell("$0.25", seller_address="0xYourSellerWallet") +): + return { + "data": "premium content", + "paid_by": payment.payer, + "amount": payment.amount, + } +``` ---- +The route returns `402 Payment Required` until the buyer submits a valid x402 payment. After verification and settlement, the handler executes and returns the paid response. -## For BUYERS (Paying for Services) +## Seller: Agent-Owned Local Service -### Step 1: Get USDC -Send USDC to your EOA address (derived from OMNICLAW_PRIVATE_KEY) +Use this only when an agent or local automation wants to expose a temporary paid service. It is not the recommended integration path for vendor or enterprise APIs. -### Step 2: Deposit to Gateway ```bash -omniclaw-cli deposit --amount 10 +omniclaw-cli serve \ + --price 0.25 \ + --endpoint /compute \ + --exec "python compute_job.py" \ + --port 8000 ``` -→ Moves USDC from EOA → Circle Gateway contract (on-chain, costs gas) -### Step 3: Pay for Services -```bash -# Pay another agent -omniclaw-cli pay --recipient 0xDEAD... --amount 5 +For vendor and enterprise APIs, use the Python SDK middleware so payments are part of the application itself. -# Or pay for x402 service (URL) -omniclaw-cli pay --recipient https://api.example.com/data --amount 1 -``` -→ Uses gasless nanopayments via x402 protocol (Gateway CAIP-2 derived from `OMNICLAW_NETWORK`, EVM only) +## Settlement Paths -### Step 4: Withdraw to Circle Wallet -```bash -omniclaw-cli withdraw --amount 3 -``` -→ Moves USDC from Gateway → your Circle Developer Wallet +OmniClaw is settlement-rail aware and policy-first. The buyer uses one execution path while the seller advertises the x402 requirements it supports. ---- +| Path | Status | Notes | +| --- | --- | --- | +| Circle Gateway `GatewayWalletBatched` | supported | Gasless nanopayments through Circle Gateway | +| Standard x402 exact via x402.org | live-proven on Base Sepolia | External exact facilitator validation | +| OmniClaw self-hosted exact facilitator | live-proven on Arc Testnet | Self-hosted `verify` and `settle` for supported EVM profiles | +| Thirdweb x402 HTTP facilitator | implemented and test-covered | Live account validation pending credentials | -## For SELLERS (Receiving Payments) +Current live proof: -### Option A: Simple Transfer -Just share your address, receive payments directly: -```bash -omniclaw-cli address # Get your address to share -``` +- Base Sepolia external x402 exact settlement +- Arc Testnet self-hosted exact settlement +- buyer/seller wallet separation +- policy-controlled buyer route through `/api/v1/pay` -### Option B: x402 Payment Gate (Recommended) -Expose your service behind payment: +## Examples -```bash -omniclaw-cli serve \ - --price 0.01 \ - --endpoint /api/data \ - --exec "python my_service.py" \ - --port 8000 -``` +| Example | Demonstrates | +| --- | --- | +| [B2B SDK Integration](examples/b2b-sdk-integration/README.md) | Enterprise buyer/seller SDK integration with multiple facilitators | +| [Machine to Machine](examples/machine-to-machine/README.md) | One machine service paying another | +| [Machine to Vendor](examples/machine-to-vendor/README.md) | Agent buyer paying a vendor-owned API | +| [Vendor Integration](examples/vendor-integration/README.md) | Vendor-side paid API integration | +| [Business Compute](examples/business-compute/README.md) | Payment-gated compute service | +| [Local Economy](examples/local-economy/README.md) | Local buyer/seller economy with Docker | +| [External x402 Facilitator](examples/external-x402-facilitator/README.md) | x402.org Base Sepolia validation | +| [Thirdweb HTTP Facilitator](examples/thirdweb-http-facilitator/README.md) | Thirdweb HTTP API validation | -This opens `http://localhost:8000/api/data` that requires USDC payment to access. - ---- - -## Complete CLI Commands - -| Command | Description | Example | -|---------|-------------|---------| -| `configure` | Set Financial Policy Engine URL, token, wallet | `configure --server-url http://localhost:8080 --token mytoken --wallet primary` | -| `address` | Get wallet address | `address` | -| `balance` | Get wallet balance | `balance` | -| `balance-detail` | Detailed balance (EOA, Gateway, Circle) | `balance-detail` | -| `deposit` | Deposit USDC to Gateway | `deposit --amount 5` | -| `withdraw` | Withdraw to Circle wallet | `withdraw --amount 2` | -| `withdraw-trustless` | Trustless withdraw (~7-day fallback) | `withdraw-trustless --amount 2` | -| `withdraw-trustless-complete` | Complete trustless withdraw after delay | `withdraw-trustless-complete` | -| `pay` | Make payment | `pay --recipient 0x... --amount 5` | -| `simulate` | Simulate payment | `simulate --recipient 0x... --amount 5` | -| `serve` | Expose x402 payment gate | `serve --price 0.01 --endpoint /api --exec "echo hello"` | -| `status` | Agent status | `status` | -| `ping` | Health check | `ping` | -| `ledger` | Transaction history | `ledger --limit 20` | - ---- - -## Default Policy.json - -Copy and edit `examples/policy-simple.json`: - -For full policy options, see **[docs/POLICY_REFERENCE.md](docs/POLICY_REFERENCE.md)** - -```json -{ - "version": "2.0", - "tokens": { - "YOUR_AGENT_TOKEN": { - "wallet_alias": "primary", - "active": true, - "label": "Your Agent Name" - } - }, - "wallets": { - "primary": { - "name": "Primary Wallet", - "limits": { - "daily_max": "100.00", - "per_tx_max": "50.00" - }, - "recipients": { - "mode": "allow_all" - } - } - } -} -``` +## Documentation ---- +| Start Here | Use Case | +| --- | --- | +| [Documentation Index](docs/README.md) | Complete docs map | +| [Developer Guide](docs/developer-guide.md) | Python SDK buyer and seller integration | +| [Agent Getting Started](docs/agent-getting-started.md) | Agent CLI setup and usage | +| [CLI Reference](docs/cli-reference.md) | Generated `omniclaw-cli` reference | +| [Operator CLI](docs/operator-cli.md) | `omniclaw server`, setup, policy, facilitator commands | +| [Policy Reference](docs/POLICY_REFERENCE.md) | Policy file structure and controls | +| [Facilitators](docs/facilitators.md) | x402 facilitator model and deployment paths | +| [Production Readiness](docs/production-readiness.md) | Proof status and release checklist | +| [API Reference](docs/API_REFERENCE.md) | Python SDK and API details | -## Environment Variables Reference +## Development -| Variable | Required | Description | -|----------|----------|-------------| -| `OMNICLAW_PRIVATE_KEY` | Yes | Agent's private key for signing | -| `OMNICLAW_AGENT_TOKEN` | Yes | Token matching policy.json | -| `OMNICLAW_AGENT_POLICY_PATH` | Yes | Path to policy.json | -| `OMNICLAW_NETWORK` | No | Network (ETH-SEPOLIA, ETH-MAINNET) | -| `OMNICLAW_ENV` | No | Set to "production" for mainnet | -| `OMNICLAW_RPC_URL` | No | RPC endpoint for on-chain ops | -| `CIRCLE_API_KEY` | Yes | Circle API key | -| `OMNICLAW_SERVER_URL` | No | Financial Policy Engine URL for the zero-trust CLI | +```bash +uv sync --extra dev +uv run pytest +``` ---- +Release verification: -## Documentation +```bash +./scripts/release_verify.sh +``` + +## Security -- **[docs/agent-getting-started.md](docs/agent-getting-started.md)** - Agent setup walkthrough -- **[docs/agent-skills.md](docs/agent-skills.md)** - Skill instructions for AI agents -- **[docs/FEATURES.md](docs/FEATURES.md)** - Full feature documentation +OmniClaw is designed around separation of authority: agents do not need unrestricted wallet access. Production deployments should still use restricted keys, policy limits, confirmation thresholds, hardened secrets, and audited infrastructure. ---- +Report vulnerabilities through [SECURITY.md](SECURITY.md). ## License -MIT — © 2026 [Omnuron AI](https://www.omniclaw.ai/). See [LICENSE](LICENSE) for details. +MIT. See [LICENSE](LICENSE). diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index ca8bff2..420095e 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -15,6 +15,7 @@ from omniclaw import ( PaymentStatus, PaymentIntentStatus, quick_setup, + validate_entity_secret, ) ``` @@ -24,7 +25,7 @@ Required: ```env CIRCLE_API_KEY=... -OMNICLAW_NETWORK=ETH-SEPOLIA # or ARC-TESTNET +OMNICLAW_NETWORK=ETH-SEPOLIA # Direct-key mode (recommended for agents / nanopayments) OMNICLAW_PRIVATE_KEY=0x... ``` @@ -56,17 +57,29 @@ OMNICLAW_CONFIRM_THRESHOLD=500.00 Defined in [onboarding.py](../src/omniclaw/onboarding.py). -### `quick_setup(api_key, env_path=".env", network="ARC-TESTNET")` +### `quick_setup(api_key, env_path=".env", network="ARC-TESTNET", entity_secret=None)` -One-time onboarding helper that generates and registers an entity secret and writes an env file (optional). +One-time onboarding helper that writes a local env file and syncs OmniClaw's managed credential store. + +If `entity_secret` is provided, OmniClaw treats it as the existing Circle Entity Secret for that API key and does not try to register a replacement. Circle only allows one active Entity Secret per account/API key. + +If `entity_secret` is omitted, OmniClaw generates and registers a new Entity Secret, then saves the recovery file in the secure config directory. + +The helper currently defaults to `ARC-TESTNET`, so pass an explicit network if you want the generated env file to target `ETH-SEPOLIA`, `BASE-SEPOLIA`, or another supported network. + +Public examples in the docs usually show `ETH-SEPOLIA` or `BASE-SEPOLIA`, but the SDK still supports other configured networks such as `ARC-TESTNET` when selected explicitly. ### `generate_entity_secret()` (optional) Returns a 64-character hex entity secret (manual setup only). +### `validate_entity_secret(entity_secret)` + +Validates that an existing Circle Entity Secret is a 64-character hex value before it is written to env or managed config. + ### `register_entity_secret(api_key, entity_secret, recovery_dir=None)` (optional) -Registers an entity secret with Circle and downloads the recovery file (manual setup only). +Registers a new entity secret with Circle and downloads the recovery file (manual setup only). Do not call this for an API key/account that already has an Entity Secret; set `ENTITY_SECRET` directly instead. ### `create_env_file(api_key, entity_secret, env_path=".env", network="ARC-TESTNET", overwrite=False)` (optional) @@ -167,6 +180,27 @@ await client.pay( ) ``` +For x402 URL payments, pass the HTTP request context through `kwargs`: + +```python +await client.pay( + wallet_id=wallet.id, + recipient="https://seller.example.com/premium", + amount="0.25", + method="POST", + request_body='{"job":"prime-count","size":70000}', + request_headers={"x-request-id": "job-123"}, +) +``` + +Buyer routing is requirement-driven: + +- seller advertises `GatewayWalletBatched` and the buyer is Gateway-ready -> OmniClaw can use the Gateway nanopayment path +- seller advertises standard x402 `exact` -> OmniClaw uses the upstream x402 SDK path +- seller advertises both and the buyer is not Gateway-ready -> OmniClaw uses `exact` + +When the seller is exact-only, OmniClaw routes directly to `exact` instead of attempting Gateway first. + ```python await client.simulate( wallet_id, @@ -234,8 +268,8 @@ Nanopayments use EIP-3009 for gas-free USDC transfers on Circle Gateway. They wo # Get the GatewayMiddleware for protecting endpoints await client.gateway() # -> GatewayMiddleware -# Decorator factory for marking paid FastAPI routes -client.sell(price: str) # -> Depends() for FastAPI +# Dependency factory for marking paid FastAPI routes +client.sell(price: str) # -> FastAPI Depends() object # Get current payment info inside a @sell() decorated route client.current_payment() # -> PaymentInfo(payer, amount, network, transaction) @@ -244,10 +278,8 @@ client.current_payment() # -> PaymentInfo(payer, amount, network, transaction) Example (FastAPI seller): ```python -from fastapi import Depends - @app.get("/premium") -async def premium(payment=Depends(omniclaw.sell("$0.001"))): +async def premium(payment=omniclaw.sell("$0.001")): payment_info = omniclaw.current_payment() return {"data": "paid content", "paid_by": payment_info.payer} ``` diff --git a/docs/ChatGPT Image Apr 2, 2026, 09_43_28 AM.png b/docs/ChatGPT Image Apr 2, 2026, 09_43_28 AM.png deleted file mode 100644 index b8446b7..0000000 Binary files a/docs/ChatGPT Image Apr 2, 2026, 09_43_28 AM.png and /dev/null differ diff --git a/docs/ChatGPT Image Mar 30, 2026, 02_19_22 PM.png b/docs/ChatGPT Image Mar 30, 2026, 02_19_22 PM.png deleted file mode 100644 index 26fa54a..0000000 Binary files a/docs/ChatGPT Image Mar 30, 2026, 02_19_22 PM.png and /dev/null differ diff --git a/docs/FEATURES.md b/docs/FEATURES.md index a3abb8c..828391b 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -49,11 +49,41 @@ The router in [payment/router.py](../src/omniclaw/payment/router.py) chooses an Current routing: -- URL -> `NanopaymentProtocolAdapter` (Gateway x402), with fallback to `X402Adapter` if needed +- URL -> inspect seller requirements, then choose `NanopaymentProtocolAdapter` for `GatewayWalletBatched` only when the buyer is Gateway-ready; otherwise use `X402Adapter` for standard `exact` x402 when the seller advertises it - address + amount below micro-threshold -> `NanopaymentProtocolAdapter` (Gateway) - address -> `TransferAdapter` - `destination_chain` set -> `GatewayAdapter` +### Exact Facilitator Layer + +OmniClaw is facilitator-agnostic. It can pay seller endpoints backed by external x402 facilitators, Circle Gateway, or an optional self-hosted OmniClaw exact facilitator. + +The self-hosted exact facilitator layer exists for standard x402 settlement when teams need local proof, custom network control, or a fallback while validating an external provider. + +Current exact-settlement profiles include: + +- Base Sepolia +- Ethereum Sepolia +- Base mainnet +- Ethereum mainnet +- Arc Testnet + +Arc Testnet uses CAIP-2 `eip155:5042002` and the official USDC ERC-20 interface `0x3600000000000000000000000000000000000000`. + +The facilitator layer is intentionally separate from the Financial Policy Engine. The policy engine decides whether an agent is allowed to pay. The facilitator verifies and settles a valid x402 payload on the selected network. + +Supported deployment modes: + +- managed external x402 facilitator, including Thirdweb-backed seller endpoints +- Circle Gateway `GatewayWalletBatched` for gasless nanopayment settlement +- self-hosted OmniClaw exact facilitator, started with `omniclaw facilitator exact` + +Thirdweb is a priority external integration path because it provides broad EVM facilitator coverage and gas-sponsored settlement. OmniClaw adds buyer-side policy, route selection, SDK/CLI execution surfaces, and operator visibility. + +OmniClaw added the self-hosted exact facilitator so teams can support networks and proof environments before they are available through their selected hosted facilitator. This is how Arc Testnet is handled: it remains standard x402 `exact` settlement, with OmniClaw providing the network profile, asset metadata, RPC, and facilitator runtime. + +See [facilitators.md](facilitators.md) for deployment details. + ### Guards The guard system in [guards/](../src/omniclaw/guards) is the primary spend-control layer. @@ -148,7 +178,7 @@ The on-chain settlement is batched — multiple nanopayments settle in a single #### Buyer vs Seller - **Buyer**: Uses `NanopaymentAdapter` and `NanopaymentClient` to create and send payments via `client.pay()` -- **Seller**: Uses `GatewayMiddleware` and `@omniclaw.sell()` to protect FastAPI endpoints +- **Seller**: Uses `GatewayMiddleware` and `client.sell()` to protect FastAPI endpoints #### Key Management @@ -194,7 +224,7 @@ Core environment variables: ```env CIRCLE_API_KEY=... -OMNICLAW_NETWORK=ARC-TESTNET +OMNICLAW_NETWORK=ETH-SEPOLIA ``` Optional: @@ -214,6 +244,8 @@ OMNICLAW_CONFIRM_ALWAYS=false OMNICLAW_CONFIRM_THRESHOLD=500.00 ``` +Use the network that matches your target environment. Public examples in this repo mainly use `ETH-SEPOLIA` or `BASE-SEPOLIA`, while other supported networks can still be selected explicitly. + ## Execution Sequence For a typical `pay()` call, the Financial Policy Engine does the following: diff --git a/docs/Gemini_Generated_Image_pekpr0pekpr0pekp.png b/docs/Gemini_Generated_Image_pekpr0pekpr0pekp.png deleted file mode 100644 index ce7dde7..0000000 Binary files a/docs/Gemini_Generated_Image_pekpr0pekpr0pekp.png and /dev/null differ diff --git a/docs/PRODUCTION_HARDENING.md b/docs/PRODUCTION_HARDENING.md index 30c2705..92e2d8b 100644 --- a/docs/PRODUCTION_HARDENING.md +++ b/docs/PRODUCTION_HARDENING.md @@ -46,6 +46,26 @@ Production seller flows must use distributed nonce storage: - `OMNICLAW_STRICT_SETTLEMENT=true` ensures success reflects irreversible settlement states. - Do not disable strict settlement in production. +## Facilitator Strategy + +OmniClaw is facilitator-agnostic. Production deployments should choose the settlement provider that fits the seller and network: + +- Thirdweb-backed x402 facilitator for managed gas-sponsored exact settlement across broad EVM coverage +- Circle Gateway `GatewayWalletBatched` for gasless batched nanopayments +- external standard x402 facilitator where the seller already uses one +- self-hosted OmniClaw exact facilitator only when local proof, custom network support, or enterprise self-hosting is required + +Do not run a self-hosted facilitator by default if a managed facilitator already supports the target flow. The self-hosted path is operational infrastructure, not the primary product wedge. + +Before production traffic, validate the exact seller path with: + +```bash +omniclaw-cli inspect-x402 --recipient https://seller.example.com/compute +omniclaw-cli pay --recipient https://seller.example.com/compute --idempotency-key production-canary-001 +``` + +For Thirdweb validation, use `examples/thirdweb-http-facilitator/README.md`. + ## Canary and SLA Use the canary script to validate end-to-end payment lifecycle before/after deploys: @@ -55,7 +75,7 @@ python scripts/payment_canary.py \ --wallet-id \ --recipient \ --amount 0.10 \ - --network ARC-TESTNET \ + --network \ --sla-seconds 300 ``` @@ -69,10 +89,11 @@ Exit behavior: 1. Apply required production env vars. 2. Run `omniclaw doctor`. 3. Run canary in target environment. -4. Deploy with staged traffic. -5. Monitor: +4. Confirm `inspect-x402` selects the expected seller scheme and network. +5. Confirm settlement appears in the selected facilitator dashboard or explorer. +6. Deploy with staged traffic. +7. Monitor: - settlement latency - webhook duplicate reject counts - pending settlement age distribution -6. Keep rollback path ready (app + env). - +8. Keep rollback path ready (app + env). diff --git a/docs/README.md b/docs/README.md index 0265071..8839272 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,45 +1,74 @@ -# OmniClaw Docs +# OmniClaw Documentation -This directory is split into two parts: +OmniClaw is a policy-controlled payment layer for agents, applications, and machine services. -- public product and developer docs in `docs/` -- internal GTM, grant, outreach, and demo materials in `docs/internal/` +Use this index to choose the right integration path. -## Public Docs +## Choose Your Path -### Getting Started +| Role | Start Here | What You Build | +| --- | --- | --- | +| Agent buyer | [Agent Getting Started](agent-getting-started.md) | An agent that pays through `omniclaw-cli` | +| Python buyer | [Developer Guide](developer-guide.md) | A backend service that pays programmatically | +| Vendor / enterprise seller | [Developer Guide](developer-guide.md) | A FastAPI service with paid endpoints through the SDK | +| Operator | [Operator CLI](operator-cli.md) | Financial Policy Engine, policies, and facilitators | +| Release owner | [Production Readiness](production-readiness.md) | Proof checklist and ship status | -- `docs/agent-getting-started.md` -- `docs/agent-skills.md` -- `docs/cli-reference.md` +## Buyer Guides -### Examples +| Guide | Use Case | +| --- | --- | +| [Agent Getting Started](agent-getting-started.md) | Configure an agent with `omniclaw-cli` | +| [CLI Reference](cli-reference.md) | Full generated `omniclaw-cli` command reference | +| [Developer Guide](developer-guide.md) | Pay with the Python SDK | +| [API Reference](API_REFERENCE.md) | SDK methods, request shapes, and payment APIs | -- `examples/local-economy/README.md` -- `examples/business-compute/README.md` +## Seller Guides -### Product And Architecture +| Guide | Use Case | +| --- | --- | +| [Developer Guide](developer-guide.md) | Add production paid FastAPI routes with `client.sell()` | +| [B2B SDK Integration](../examples/b2b-sdk-integration/README.md) | Enterprise SDK deployment with Circle, Thirdweb, or self-hosted exact | +| [Vendor Integration](../examples/vendor-integration/README.md) | Production-style vendor API integration | +| [Business Compute](../examples/business-compute/README.md) | Payment-gated compute service | +| [CLI Reference](cli-reference.md) | Agent-owned local service flow with `omniclaw-cli serve` | -- `docs/FEATURES.md` -- `docs/compliance-architecture.md` -- `docs/architecture_overview.svg` -- `docs/OmniClaw_Whitepaper_v1.0.pdf` +## Machine Payment Examples -### Technical Reference +| Example | Demonstrates | +| --- | --- | +| [B2B SDK Integration](../examples/b2b-sdk-integration/README.md) | Enterprise buyer/seller SDK integration | +| [Machine to Machine](../examples/machine-to-machine/README.md) | One automated service paying another | +| [Machine to Vendor](../examples/machine-to-vendor/README.md) | Agent buyer paying a vendor-owned API | +| [Local Economy](../examples/local-economy/README.md) | Local buyer/seller stack with Docker | +| [External x402 Facilitator](../examples/external-x402-facilitator/README.md) | x402.org exact settlement on Base Sepolia | +| [Thirdweb HTTP Facilitator](../examples/thirdweb-http-facilitator/README.md) | Thirdweb HTTP facilitator integration | -- `docs/API_REFERENCE.md` -- `docs/POLICY_REFERENCE.md` -- `docs/SDK_USAGE_GUIDE.md` -- `docs/CCTP_USAGE.md` -- `docs/PRODUCTION_HARDENING.md` -- `docs/erc_804_spec.md` +## Operator and Production Docs -## Internal Docs +| Document | Covers | +| --- | --- | +| [Operator CLI](operator-cli.md) | `omniclaw server`, `omniclaw setup`, `omniclaw facilitator exact` | +| [Policy Reference](POLICY_REFERENCE.md) | Tokens, wallets, budgets, recipient rules, confirmations | +| [Facilitators](facilitators.md) | Circle Gateway, x402.org, Thirdweb, self-hosted exact | +| [Production Readiness](production-readiness.md) | Live proof status and release checklist | +| [Production Hardening](PRODUCTION_HARDENING.md) | Deployment controls, Redis, nonce, security settings | -Use `docs/internal/README.md` for: +## Architecture and Reference -- grant strategy -- sponsor and investor messaging -- public post drafts -- demo narration and story -- archived older grant docs +| Document | Covers | +| --- | --- | +| [Architecture and Features](FEATURES.md) | Core design, route selection, guards, settlement paths | +| [Architecture Diagram](architecture_overview.svg) | System overview | +| [Compliance Architecture](compliance-architecture.md) | Compliance and control framing | +| [CCTP Usage](CCTP_USAGE.md) | Circle CCTP notes | +| [ERC-804 Spec](erc_804_spec.md) | Trust-related specification notes | + +## Project Files + +| File | Purpose | +| --- | --- | +| [CHANGELOG](../CHANGELOG.md) | Release history | +| [CONTRIBUTING](../CONTRIBUTING.md) | Development and PR workflow | +| [SECURITY](../SECURITY.md) | Security reporting | +| [ROADMAP](../ROADMAP.md) | Built status and planned work | diff --git a/docs/SDK_USAGE_GUIDE.md b/docs/SDK_USAGE_GUIDE.md deleted file mode 100644 index fd622fa..0000000 --- a/docs/SDK_USAGE_GUIDE.md +++ /dev/null @@ -1,509 +0,0 @@ -# OmniClaw Financial Policy Engine Usage Guide - -This guide covers common workflows for the Financial Policy Engine without repeating the full architecture or every method signature. - -## 1. Initialize the Client - -```python -from omniclaw import OmniClaw, Network - -client = OmniClaw(network=Network.ARC_TESTNET) -``` - -With environment variables: - -```env -CIRCLE_API_KEY=your_circle_api_key -OMNICLAW_NETWORK=ARC-TESTNET -``` - -Optional runtime settings: - -```env -OMNICLAW_STORAGE_BACKEND=redis -OMNICLAW_REDIS_URL=redis://localhost:6379 -OMNICLAW_LOG_LEVEL=DEBUG -OMNICLAW_RPC_URL=https://your-rpc-provider - -# Nanopayments network is derived from OMNICLAW_NETWORK (EVM chain) -``` - -### Entity Secret - -You do not need to set `ENTITY_SECRET` manually. It is auto-generated and registered on first run when `CIRCLE_API_KEY` is available. - -Linux recovery-file location: - -```text -~/.config/omniclaw/ -``` - -This matters because Circle entity secret registration is effectively a one-time setup per account until you recover or reset it. - -Run the built-in diagnostic command to check the full state: - -```bash -omniclaw doctor -``` - -## Testing with Real Funds - -To test payments with real USDC on testnet: - -**1. Configure for Base Sepolia:** - -```env -OMNICLAW_NETWORK=BASE-SEPOLIA -OMNICLAW_RPC_URL=https://sepolia.base.org -``` - -**2. Get testnet tokens:** - -- **ETH (for gas):** https://faucets.chain.link/base-sepolia -- **USDC (for payments):** https://faucet.circle.com/ → Select Base Sepolia → Send 20 USDC - -**3. Get payment addresses:** - -```python -wallet_set, wallet = await client.create_agent_wallet("my-agent") - -# Circle wallet (for transfers) -circle_address = wallet.address - -# Nano/Gateway (for nanopayments - EIP-3009) -nano_address = client.nanopayment_adapter.address -``` - -**4. Test a payment:** - -```python -result = await client.pay( - wallet_id=wallet.id, - recipient="0xRecipientAddress", - amount="0.01", # 1 cent USDC -) -``` - -## 2. Create a Wallet - -Fastest path: - -```python -wallet_set, wallet = await client.create_agent_wallet("agent-007") -``` - -Manual path: - -```python -wallet_set = await client.create_wallet_set("ops-wallets") -wallet = await client.create_wallet( - wallet_set_id=wallet_set.id, - blockchain=Network.ETH, -) -``` - -Common wallet operations: - -```python -wallets = await client.list_wallets(wallet_set_id=wallet_set.id) -wallet_info = await client.get_wallet(wallet.id) -balance = await client.get_balance(wallet.id) - -# Get payment address (where to fund with USDC) -payment_address = await client.get_payment_address(wallet.id) - -# Get detailed balance (available + reserved for intents) -detailed = await client.get_detailed_balance(wallet.id) -print(f"Available: {detailed['available']}, Reserved: {detailed['reserved']}") - -transactions = await client.list_transactions(wallet_id=wallet.id) -``` - -## 3. Add Safety Guards - -```python -await client.add_budget_guard(wallet.id, daily_limit="100.00", hourly_limit="20.00") -await client.add_rate_limit_guard(wallet.id, max_per_minute=5) -await client.add_single_tx_guard(wallet.id, max_amount="25.00") -await client.add_recipient_guard( - wallet.id, - mode="whitelist", - addresses=["0xTrustedRecipient"], - domains=["api.openai.com"], -) -await client.add_confirm_guard(wallet.id, threshold="500.00") -``` - -Wallet-set guard helpers apply the same logic across all wallets in a set. - -```python -await client.add_budget_guard_for_set(wallet_set.id, daily_limit="500.00") -await client.add_rate_limit_guard_for_set(wallet_set.id, max_per_hour=100) -``` - -## 4. Execute a Payment - -```python -result = await client.pay( - wallet_id=wallet.id, - recipient="0x742d35Cc6634C0532925a3b844Bc9e7595f5e4a0", - amount="10.50", - purpose="vendor payment", -) -``` - -Key runtime arguments: - -- `wallet_id`: required source wallet -- `recipient`: blockchain address or URL -- `amount`: USDC amount -- `destination_chain`: set for cross-chain flows -- `purpose`: audit-friendly note -- `idempotency_key`: caller-controlled dedupe key -- `skip_guards`: bypass guards, only for special cases -- `check_trust`: `None`, `True`, or `False` -- `wait_for_completion`: wait for provider confirmation when supported - -## 5. Understand Routing - -OmniClaw routes automatically: - -- URL -> Gateway nanopayments (x402), with fallback to x402 direct if needed -- address + amount below micro-threshold -> Gateway nanopayments -- address -> direct transfer -- address + `destination_chain` -> gateway/cross-chain - -Examples: - -```python -await client.pay(wallet_id=wallet.id, recipient="0xRecipient", amount="5.00") -await client.pay(wallet_id=wallet.id, recipient="https://api.vendor.com/paywall", amount="0.05") -await client.pay( - wallet_id=wallet.id, - recipient="0xRecipientOnBase", - amount="20.00", - destination_chain=Network.BASE, -) -``` - -## 6. Simulate Before Sending - -```python -sim = await client.simulate( - wallet_id=wallet.id, - recipient="0xRecipient", - amount="25.00", -) - -if sim.would_succeed: - print(sim.route) -else: - print(sim.reason) -``` - -Simulation checks: - -- balance after reservations -- guard outcomes -- trust outcome when enabled -- adapter suitability - -## 7. Use Payment Intents for Approval Flows - -```python -intent = await client.create_payment_intent( - wallet_id=wallet.id, - recipient="0xRecipient", - amount="250.00", - purpose="high-value purchase", -) -``` - -Confirm later: - -```python -result = await client.confirm_payment_intent(intent.id) -``` - -Cancel if needed: - -```python -await client.cancel_payment_intent(intent.id, reason="approval denied") -``` - -Use intents when you need: - -- human review -- delayed execution -- serialized approval flows -- explicit reservation of spendable balance - -## 8. Receive Nanopayments as a Seller - -Nanopayments use EIP-3009 for gas-free USDC transfers via Circle Gateway batch settlement. As a seller, you protect FastAPI endpoints so buyers pay before receiving content. - -### Quick Start (6 lines!) - -```python -from fastapi import FastAPI, Depends -from omniclaw import OmniClaw - -app = FastAPI() -client = OmniClaw() - -# Create seller account - ONE CALL does everything -wallet_set, wallet = await client.create_agent_wallet("my-saas-product") - -# Protect your endpoint - that's it! -@app.get("/premium-data") -async def get_premium(payment=Depends(client.sell("$0.01"))): - return { - "data": "premium content", - "paid_by": payment.payer, - } -``` - -### How It Works - -1. **Circle Gateway batch settlement** - All nanopayments are automatically batched and settled via EIP-3009 -2. **Gasless for buyers** - Buyers don't pay gas fees -3. **Seller receives USDC in Gateway** - Instant settlement to your Gateway wallet - -### Get Payment Address - -```python -# Get address for buyers to pay to -payment_address = await client.get_payment_address(wallet.id) -``` - -### Check Earnings - -```python -# Check your Gateway balance (USDC received from buyers) -balance = await client.get_gateway_balance(wallet.id) -print(f"Total: {balance.formatted_total}") -print(f"Available: {balance.formatted_available}") -``` - -### Withdraw Earnings - -```python -# Withdraw to your Circle wallet -await client.withdraw_from_gateway( - wallet_id=wallet.id, - amount_usdc="50.00", -) - -# Or withdraw to another chain (cross-chain via CCTP) -await client.withdraw_from_gateway( - wallet_id=wallet.id, - amount_usdc="25.00", - destination_chain="eip155:1", # Ethereum mainnet - recipient="0xYourEthAddress", -) -``` - -### Why OmniClaw vs Raw x402? - -**OmniClaw (SIMPLE - 3 lines):** -```python -wallet_set, wallet = await client.create_agent_wallet("my-product") - -@app.get("/data") -async def handler(payment=Depends(client.sell("$0.01"))): - return {"data": "..."} -``` - -**Raw x402 (40+ lines):** -```python -server = x402ResourceServer(HTTPFacilitatorClient(FacilitatorConfig(url=...))) -server.register("eip155:84532", ExactEvmServerScheme()) - -routes = { - "GET /data": RouteConfig( - accepts=[PaymentOption(scheme="exact", price="$0.01", network="eip155:84532", pay_to=address)] - ), -} -app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server) - -@app.get("/data") -async def handler(): - return {"data": "..."} -``` - -**OmniClaw handles all the complexity** - facilitator, settlement, networks - you just write business logic! - -### Advanced: Custom Routes (like x402) - -If you need more control like x402: - -```python -# Coming soon - define custom routes with multiple payment options -routes = { - "GET /premium": RouteConfig( - accepts=[ - PaymentOption(scheme="exact", price="$0.01", network="eip155:84532", pay_to=address), - PaymentOption(scheme="exact", price="$0.01", network="eip155:1", pay_to=address), - ] - ), -} -``` - -### Deposit USDC to Enable Receiving - -Your gateway wallet needs a USDC balance to receive payments (it acts as a buffer — buyers pay you by sending from their gateway to yours). - -```python -# Check your gateway balance (uses wallet_id) -balance = await client.get_gateway_balance(wallet.id) -print(f"Gateway balance: {balance.formatted_total}") - -# Deposit from your Circle wallet to Gateway (for gasless nanopayments) -await client.deposit_to_gateway( - wallet_id=wallet.id, - amount_usdc="100.00", -) - -# Withdraw from Gateway back to your wallet -await client.withdraw_from_gateway( - wallet_id=wallet.id, - amount_usdc="50.00", -) -``` - -### Protect FastAPI Endpoints - -```python -from fastapi import FastAPI, Depends - -app = FastAPI() - -@app.get("/premium-data") -async def get_premium(payment=Depends(client.sell("$0.001"))): - payment_info = client.current_payment() - return { - "data": "premium content", - "paid_by": payment_info.payer, - "network": payment_info.network, - } -``` - -The `@client.sell()` decorator: - -- Returns a FastAPI `Depends()` that gates the route with x402 payment -- Checks the `PAYMENT-SIGNATURE` header (base64-encoded EIP-3009 authorization) -- Verifies the payment amount matches -- Settles via Circle Gateway -- Returns `PaymentInfo` including the payer's address - -### Get Paid Content - -```python -@app.get("/premium") -async def premium(payment=Depends(client.sell("$0.50"))): - info = client.current_payment() - print(f"Paid by {info.payer} on {info.network}") - print(f"Transaction: {info.transaction}") - return {"content": "..."} -``` - -### Withdraw from Gateway - -```python -# Withdraw to your Circle wallet -await client.withdraw_from_gateway( - wallet_id=wallet.id, - amount_usdc="50.00", -) - -# Or withdraw to another blockchain address -await client.withdraw_from_gateway( - wallet_id=wallet.id, - amount_usdc="25.00", - destination_chain=Network.BASE, - recipient="0xBaseRecipient", -) -``` - -### Auto-Topup - -Automatically refill gateway balance when it drops below a threshold: - -```python -client.configure_nanopayments( - auto_topup_enabled=True, - auto_topup_threshold="5.00", # Refill when balance < $5 - auto_topup_amount="50.00", # Add $50 each time - wallet_manager=gateway_manager, -) -``` - -## 9. Send Nanopayments as a Buyer - -Nanopayments are sent automatically when you `pay()` a small amount to a gateway-enabled address: - -```python -# Amounts below the micro threshold use gateway nanopayments -result = await client.pay( - wallet_id=wallet.id, - recipient="0xSellerGatewayAddress", - amount="0.05", # Small amount → gas-free nanopayment -) -``` - -Configuration: - -```env -OMNICLAW_NANOPAYMENTS_MICRO_THRESHOLD=1.00 # Amounts < $1 use nanopayments -``` - -**Gateway CAIP-2:** The nanopayment CAIP-2 chain identifier is derived from `OMNICLAW_NETWORK` via `network_to_caip2`. Only EVM networks are supported. - -On the buyer side, OmniClaw: -1. Checks if the recipient supports gateway nanopayments -2. Creates an EIP-3009 authorization (off-chain signing) -3. Sends the authorization as a `PAYMENT-SIGNATURE` header to Circle's settle API -4. Circle batches and settles on-chain - -## 10. Enable Trust Checks - -Set a real RPC URL: - -```env -OMNICLAW_RPC_URL=https://your-rpc-provider -``` - -Then request trust evaluation: - -```python -result = await client.pay( - wallet_id=wallet.id, - recipient="0xRecipient", - amount="10.00", - check_trust=True, -) -``` - -Rules: - -- `check_trust=True` fails if no real RPC URL is configured -- `check_trust=None` uses auto mode -- `check_trust=False` skips trust evaluation - -## 11. Webhooks - -Use the webhook parser when handling Circle events: - -```python -event = client.webhooks.handle(payload, headers) -``` - -If signature verification is configured, pass the raw payload and headers so verification can run before parsing. - -## 12. Operational Guidance - -- Use Redis in any concurrent deployment. -- Keep `OMNICLAW_NETWORK` explicit in every deployed environment. -- Keep trust checks opt-in unless your deployment is prepared with a working RPC provider. -- Prefer `simulate()` for higher-risk or user-approved operations. -- Prefer payment intents for review-required or delayed-execution flows. diff --git a/docs/agent-getting-started.md b/docs/agent-getting-started.md index 5140edc..6bf1255 100644 --- a/docs/agent-getting-started.md +++ b/docs/agent-getting-started.md @@ -1,6 +1,6 @@ # OmniClaw Agent Getting Started -This guide walks you through setting up an OmniClaw agent for both buying and selling. +This guide walks you through setting up an OmniClaw agent for policy-controlled payments. OmniClaw is the **Economic Execution and Control Layer for Agentic Systems**. In that system: @@ -8,7 +8,9 @@ In that system: - the owner runs the **Financial Policy Engine** - the agent uses `omniclaw-cli` as the **zero-trust execution layer** - buyers pay with `omniclaw-cli pay` -- sellers earn with `omniclaw-cli serve` +- agents can expose temporary local paid services with `omniclaw-cli serve` + +For vendor, SaaS, or enterprise APIs, use the Python SDK seller middleware instead of `omniclaw-cli serve`. See the [Developer Guide](developer-guide.md). --- @@ -16,6 +18,7 @@ In that system: - Python 3.10+ - Circle API key +- Circle Entity Secret if your Circle account/API key already has one - USDC on the target network (testnet or mainnet) - A private key for your agent @@ -68,6 +71,10 @@ export OMNICLAW_AGENT_TOKEN="my-agent-token" # Must match policy.json token ke export OMNICLAW_AGENT_POLICY_PATH="/path/to/policy.json" export CIRCLE_API_KEY="your-circle-api-key" +# Required when your Circle account/API key already has an Entity Secret. +# If omitted, OmniClaw only auto-generates one when no existing local secret is found. +export ENTITY_SECRET="your-existing-64-char-hex-entity-secret" + # Network (testnet or mainnet) export OMNICLAW_NETWORK="ETH-SEPOLIA" # or ETH-MAINNET for production @@ -85,7 +92,7 @@ export OMNICLAW_POLICY_RELOAD_INTERVAL="5" # Hot reload interval (seconds) ## Step 3: Start the Financial Policy Engine ```bash -uvicorn omniclaw.agent.server:app --port 8080 +omniclaw server --port 8080 ``` The Financial Policy Engine runs at `http://localhost:8080`. @@ -134,7 +141,7 @@ omniclaw-cli balance_detail ```bash omniclaw-cli deposit --amount 10 ``` -This moves USDC from your EOA to the Circle Gateway contract. +This moves USDC from your EOA to the Circle Gateway contract. It is required for `GatewayWalletBatched` nanopayments. It is not required for standard x402 `exact` payments that spend from the buyer signer directly. ### Withdraw to Circle Wallet ```bash @@ -142,6 +149,31 @@ omniclaw-cli withdraw --amount 5 ``` This moves USDC from Gateway to your Circle Developer Wallet. +### Buyer Flow For x402 Services + +For a new paid URL, use this order: + +```bash +omniclaw-cli can-pay --recipient https://seller.example.com/premium +omniclaw-cli inspect-x402 --recipient https://seller.example.com/premium +omniclaw-cli pay --recipient https://seller.example.com/premium --idempotency-key job-123 +``` + +What this tells you: + +- `can-pay` confirms policy allow or deny +- `inspect-x402` shows whether the seller is paywalled, what schemes it advertises, and whether OmniClaw will use `gateway_balance` or `direct_wallet` +- `pay` executes through the single `/api/v1/pay` buyer route + +For x402 URLs, OmniClaw chooses the route from the seller's advertised requirements: + +- `GatewayWalletBatched` when the seller advertises Circle Gateway nanopayments and the buyer is actually Gateway-ready +- `exact` when the seller advertises a standard x402 payment flow + +If the seller advertises both and the buyer has no Gateway balance, OmniClaw uses `exact`. + +If the seller is exact-only, OmniClaw routes directly to the x402 exact path. + --- ## Confirmations (High-Value Policy Thresholds) @@ -172,9 +204,9 @@ Then retry the payment with the same `confirmation_id` in metadata: --- -## For SELLERS: Expose a Payment Gate +## Agent-to-Agent Selling (Local Data) -To receive payments, expose a service behind x402 payment: +If an agent wants to temporarily sell access to a local Python script or data file to another agent, they can use the CLI to spin up a fast payment gate: ```bash omniclaw-cli serve \ @@ -184,13 +216,9 @@ omniclaw-cli serve \ --port 8000 ``` -This opens `http://localhost:8000/api/data` that requires USDC payment to access. +This opens `http://localhost:8000/api/data` that requires a USDC payment to execute `my_service.py` and return its output. -This is the seller side of the same OmniClaw economy. -The same CLI powers both sides: - -- buyer: `omniclaw-cli pay` -- seller: `omniclaw-cli serve` +> **Web developer or vendor:** For real API or SaaS products, use the Python SDK inside your FastAPI application instead of `omniclaw-cli serve`. See the [Developer Guide](developer-guide.md). --- @@ -204,7 +232,9 @@ The same CLI powers both sides: | `omniclaw-cli withdraw --amount X` | Withdraw to Circle wallet | | `omniclaw-cli withdraw_trustless --amount X` | Trustless withdraw (~7-day delay) | | `omniclaw-cli withdraw_trustless_complete` | Complete trustless withdraw after delay | +| `omniclaw-cli inspect-x402 --recipient URL` | Inspect seller requirements and buyer readiness | | `omniclaw-cli pay --recipient 0x... --amount X` | Pay another agent | +| `omniclaw-cli pay --recipient URL` | Pay a seller x402 endpoint | | `omniclaw-cli serve --price X --endpoint /api --exec "cmd"` | Start payment gate | --- @@ -231,7 +261,16 @@ Wait a few seconds and retry. The agent is setting up. Check that `OMNICLAW_AGENT_TOKEN` matches a key in your policy.json's `tokens` section. ### "Insufficient balance" -Make sure you've deposited USDC to the Gateway first: +Check which route the seller requires: + +```bash +omniclaw-cli inspect-x402 --recipient https://seller.example.com/premium +``` + +If the route is `GatewayWalletBatched`, deposit to Gateway first: + ```bash omniclaw-cli deposit --amount 10 ``` + +If the route is `exact`, fund the buyer signer wallet on the required chain instead. diff --git a/docs/agent-skills.md b/docs/agent-skills.md index ca0d588..4301b45 100644 --- a/docs/agent-skills.md +++ b/docs/agent-skills.md @@ -16,10 +16,12 @@ That full system is larger than the CLI alone: - the settlement rails include direct USDC transfers, x402, CCTP, and Circle Gateway nanopayments - the policy, trust, ledger, and concurrency controls are part of the overall OmniClaw system -It is the same CLI on both sides of the economy: +It is the same CLI for agent-side economic execution: - buyer side: `omniclaw-cli pay` -- seller side: `omniclaw-cli serve` +- temporary/local seller side: `omniclaw-cli serve` + +Vendor and enterprise seller APIs should use the Python SDK with `client.sell(...)`. That two-sided model matters: @@ -35,17 +37,13 @@ There are now three separate artifacts, each with a different audience: - `docs/agent-skills.md` - human/operator guide -- `.agents/skills/omniclaw-cli/SKILL.md` - - actual agent instruction file -- `.agents/skills/omniclaw-cli/references/cli-reference.md` - - exact agent command reference generated from live CLI help - -There is also a human-copy of the generated command reference: - +- `docs/omniclaw-cli-skill/SKILL.md` + - public shipped skill specification - `docs/cli-reference.md` + - exact generated command reference for the public CLI surface This split is deliberate. -It keeps agent instructions short and reliable while giving humans a fuller explanation. +It keeps the public skill specification separate from the human/operator guide and generated command reference. ## Setup Model @@ -280,6 +278,7 @@ Current top-level commands exposed by the CLI: ## Recommended Operational Rules - use `can-pay` for new recipients +- use `inspect-x402` for a new paid URL before the first live payment - use `--idempotency-key` for job-based payments - use `balance-detail` when Gateway balances matter - use `simulate` when the amount or guard risk is non-trivial @@ -293,12 +292,11 @@ The exact command reference is generated from the live CLI help surface. Regenerate it with: ```bash -python .agents/skills/omniclaw-cli/scripts/generate_cli_reference.py +python docs/omniclaw-cli-skill/scripts/generate_cli_reference.py ``` Generated outputs: -- `.agents/skills/omniclaw-cli/references/cli-reference.md` - `docs/cli-reference.md` That keeps the documented flags and command surface aligned with the actual CLI. @@ -315,18 +313,19 @@ It is useful for things like: It is not required for the OmniClaw agent skill to work. -For this repository, the functional sources of truth are: +For this repository, the public sources of truth are: -- `.agents/skills/omniclaw-cli/SKILL.md` -- `.agents/skills/omniclaw-cli/references/cli-reference.md` +- `docs/omniclaw-cli-skill/SKILL.md` +- `docs/cli-reference.md` -That keeps the runtime path minimal and avoids duplicating instruction content in another file. +That keeps the shipped skill and the shipped command reference in public docs. ## Ship Recommendation This is now the recommended storage layout: -- keep agent runtime instructions under `.agents/skills/omniclaw-cli/` +- keep public shipped skill specs under `docs/` +- keep repo-local internal-use skills under `.agents/skills/` - keep human/operator docs under `docs/` - keep the exact CLI reference generated, not handwritten diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 5692345..6426824 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -6,13 +6,14 @@ Do not hand-edit command schemas here; regenerate instead. Generator: ```bash -python3 .agents/skills/omniclaw-cli/scripts/generate_cli_reference.py +python3 docs/omniclaw-cli-skill/scripts/generate_cli_reference.py ``` ## Usage Notes - same CLI, two roles: buyer uses `pay`, seller uses `serve` - use `can-pay` before a new recipient when policy allow/deny matters +- use `inspect-x402` before a new paid URL when you need to see seller requirements and buyer funding readiness - use `balance-detail` when Gateway state matters - use `--idempotency-key` for job-based payments - for x402 URLs, `--amount` can be omitted because the payment requirements come from the seller endpoint @@ -24,6 +25,7 @@ Buyer paying an x402 endpoint: ```bash omniclaw-cli can-pay --recipient http://seller-host:8000/api/data +omniclaw-cli inspect-x402 --recipient http://seller-host:8000/api/data omniclaw-cli pay --recipient http://seller-host:8000/api/data --idempotency-key job-123 ``` @@ -82,6 +84,9 @@ omniclaw-cli serve \ │ withdraw_trustless_complete Alias for withdraw-trustless-complete │ │ pay Execute a payment or pay for an x402 service. │ │ simulate Simulate a payment without executing. │ +│ inspect-x402 Inspect an x402 endpoint and show which │ +│ payment route OmniClaw would use. │ +│ inspect_x402 Alias for inspect-x402 │ │ can-pay Check if recipient is allowed. │ │ can_pay Alias for can-pay │ │ create-intent Create a payment intent (authorize). │ @@ -204,6 +209,24 @@ omniclaw-cli serve \ ╰──────────────────────────────────────────────────────────────────────────────╯ ``` +### `omniclaw-cli inspect-x402 --help` + +```text + + Usage: omniclaw-cli inspect-x402 [OPTIONS] + + Inspect an x402 endpoint and show which payment route OmniClaw would use. + +╭─ Options ────────────────────────────────────────────────────────────────────╮ +│ * --recipient TEXT x402 URL to inspect [required] │ +│ --amount TEXT Optional max amount in USDC │ +│ --method TEXT HTTP method for x402 requests [default: GET] │ +│ --body TEXT Request body for x402 requests │ +│ --header TEXT Additional headers for x402 requests │ +│ --help Show this message and exit. │ +╰──────────────────────────────────────────────────────────────────────────────╯ +``` + ### `omniclaw-cli simulate --help` ```text diff --git a/docs/developer-guide.md b/docs/developer-guide.md new file mode 100644 index 0000000..146083d --- /dev/null +++ b/docs/developer-guide.md @@ -0,0 +1,224 @@ +# OmniClaw Developer Guide (Python SDK) + +This guide covers how developers, vendors, and application teams build policy-controlled payment flows with the OmniClaw Python SDK. + +> **Vendors vs Agents:** This guide is for developers embedding OmniClaw code into real Python applications (like FastAPI servers or backend worker scripts). If you are looking to operate an autonomous AI Agent using the command line, please see the [Agent CLI Guide](agent-getting-started.md). + +--- + +## 1. Initialize the SDK Client + +```python +from omniclaw import OmniClaw, Network + +# Initialize the client (auto-loads credentials from env) +client = OmniClaw(network=Network.ETH_SEPOLIA) +``` + +With environment variables: + +```env +CIRCLE_API_KEY=your_circle_api_key +OMNICLAW_NETWORK=ETH-SEPOLIA +``` + +### Automatic Entity Secret Management + +If your Circle account/API key already has an Entity Secret, set it directly: + +```env +ENTITY_SECRET=your_existing_64_char_hex_entity_secret +``` + +Circle only allows one active Entity Secret per account/API key. OmniClaw will use `ENTITY_SECRET` from the environment first, then its managed local credential store. It only auto-generates and registers a new Entity Secret when no existing secret is provided or found. + +For non-interactive setup: + +```bash +omniclaw setup --api-key "$CIRCLE_API_KEY" --entity-secret "$ENTITY_SECRET" +``` + +--- + +## 2. Managing Wallets programmatically + +Whether you are building a buyer app that needs to spend funds or a seller app that needs to receive funds, you need an OmniClaw-managed wallet. + +### Create an Application Wallet +```python +# Creates a wallet_set and primary wallet for your app +wallet_set, wallet = await client.create_agent_wallet("my-backend-app") + +print(f"Your application's wallet ID is: {wallet.id}") +print(f"Your on-chain address is: {wallet.address}") + +# Get detailed balance (what you can spend safely) +detailed = await client.get_detailed_balance(wallet.id) +print(f"Available USDC: {detailed['available']}") +``` + +--- + +## 3. As a Developer: Buying and Sending Payments + +Use the SDK to programmatically send USDC payments (e.g., in a background job, cron script, or user-initiated transaction). + +### Standard P2P Transfer +```python +result = await client.pay( + wallet_id=wallet.id, + recipient="0xRecipientAddress", + amount="10.50", + purpose="Monthly API refill", +) +print(f"Payment successful. TX: {result.blockchain_tx or result.transaction_id}") +``` + +### Paying an x402 Paid Endpoint Programmatically +OmniClaw's routing engine handles all the complexity of the x402 402-Payment-Required handshake internally. Just pass the URL as the recipient: + +```python +# OmniClaw performs the 402 handshake, signs the selected payment, retries the +# request with the payment header, and returns the paid resource response. +result = await client.pay( + wallet_id=wallet.id, + recipient="https://api.vendor.com/premium-data", + amount="0.05", +) + +print(result.status, result.blockchain_tx or result.transaction_id) +print(result.resource_data) +``` + +--- + +## 4. As a Developer: Selling and Receiving Payments (Vendor) + +If you are building an API and want to monetize it without setting up a separate billing system, use `client.sell()` in FastAPI. + +### Quick Start: Gated Endpoints +```python +from fastapi import FastAPI +from omniclaw import OmniClaw + +app = FastAPI() +client = OmniClaw() + +# Require $0.01 in USDC to access this route +@app.get("/premium-data") +async def get_data( + payment=client.sell("$0.01", seller_address="0xYourWalletAddress"), +): + + # This code ONLY executes if the payment has cleared and settled. + return { + "status": "success", + "data": "premium content", + "buyer_address": payment.payer, + } +``` + +### Seller Facilitator Options + +The seller SDK supports multiple settlement paths. + +Circle Gateway default: + +```python +payment=client.sell("$0.25", seller_address="0xVendorWallet") +``` + +Thirdweb managed x402: + +```python +payment=client.sell( + "$0.25", + seller_address="0xThirdwebServerWallet", + facilitator="thirdweb", +) +``` + +OmniClaw self-hosted exact facilitator: + +```python +payment=client.sell( + "$0.25", + seller_address="0xVendorWallet", + facilitator="omniclaw", +) +``` + +For the self-hosted path, run the facilitator separately: + +```bash +export OMNICLAW_X402_SELF_HOSTED_FACILITATOR_URL="http://127.0.0.1:4022" +export OMNICLAW_X402_EXACT_NETWORK_PROFILE="ARC-TESTNET" + +omniclaw facilitator exact --network-profile ARC-TESTNET --port 4022 +``` + +See [B2B SDK Integration](../examples/b2b-sdk-integration/README.md) for complete deployment examples. + +### Managing Your Vendor Earnings +Payments received via the standard Circle Gateway routes pile up in your Gateway balance. You must withdraw them to your main on-chain wallet. + +```python +# Check earnings +balance = await client.get_gateway_balance(wallet.id) +print(f"Earnings waiting in Gateway: {balance.formatted_total}") + +# Sweep earnings to your exact on-chain wallet +await client.withdraw_from_gateway( + wallet_id=wallet.id, + amount_usdc="50.00", +) +``` + +--- + +## 5. Adding Safety Guards via Code + +As a developer, you want absolute assurance your background jobs won't drain your liquidity. + +```python +# Block your application from spending more than $100 a day +await client.add_budget_guard(wallet.id, daily_limit="100.00", hourly_limit="20.00") + +# Stop runaway loops: max 5 payments per minute +await client.add_rate_limit_guard(wallet.id, max_per_minute=5) + +# Never allow a single payment over $25 +await client.add_single_tx_guard(wallet.id, max_amount="25.00") + +# Restrict outbound funds to a specific whitelist of known vendor APIs +await client.add_recipient_guard( + wallet.id, + mode="whitelist", + addresses=["0xTrustedSupplier"], + domains=["api.openai.com", "api.anthropic.com"], +) +``` + +## 6. Advanced programmatic controls + +### Simulating Payments +Test if a complex payment flow will pass guards without actually sending money. +```python +sim = await client.simulate( + wallet_id=wallet.id, + recipient="0xRecipient", + amount="25.00", +) + +if sim.would_succeed: + print(f"Will execute using route: {sim.route}") +else: + print(f"Blocked by: {sim.reason}") +``` + +### Webhooks +When receiving async settlement events from the Circle API: +```python +event = client.webhooks.handle(payload, headers) +print(f"Received settlement for transaction {event.transaction_hash}") +``` diff --git a/docs/erc_804_spec.md b/docs/erc_804_spec.md index add9574..fca6197 100644 --- a/docs/erc_804_spec.md +++ b/docs/erc_804_spec.md @@ -5,7 +5,7 @@ This file is a historical design note for OmniClaw's trust-layer direction. It i Use these docs for the current product surface instead: - [README](../README.md) -- [Financial Policy Engine Usage Guide](SDK_USAGE_GUIDE.md) +- [Developer Guide (SDK)](developer-guide.md) - [API Reference](API_REFERENCE.md) - [Architecture and Features](FEATURES.md) diff --git a/docs/facilitators.md b/docs/facilitators.md new file mode 100644 index 0000000..db71b44 --- /dev/null +++ b/docs/facilitators.md @@ -0,0 +1,361 @@ +# x402 Facilitators + +OmniClaw supports x402 payments through facilitator-backed settlement. + +A facilitator is the service that verifies an x402 payment payload and settles it on the target rail. OmniClaw is integration-first: it governs agent financial authority and routes into the facilitator that fits the seller's requirements. + +Supported deployment shapes: + +- Circle Gateway `GatewayWalletBatched` for gasless nanopayments +- standard x402 `exact` settlement through an external facilitator such as Thirdweb or x402.org +- optional standard x402 `exact` settlement through a self-hosted OmniClaw facilitator + +## Deployment Matrix + +Use this matrix as the canonical operating model: + +| Mode | Seller creates `accepts` | Who runs `verify` / `settle` | Live proof status | +| --- | --- | --- | --- | +| Circle Gateway | OmniClaw seller middleware | Circle Gateway facilitator | already supported in OmniClaw seller flow | +| External exact via x402.org | seller app or OmniClaw external seller harness | x402.org | live-proven on Base Sepolia | +| External exact via Thirdweb | Thirdweb `accepts` API or seller using Thirdweb server wallet | Thirdweb | HTTP integration wired and tested in repo; live account validation pending credentials | +| Self-hosted OmniClaw exact facilitator | seller app or OmniClaw seller harness | OmniClaw exact facilitator | live-proven on Arc Testnet; use for Arc, Base, Ethereum Sepolia, and other supported EVM profiles | + +The architectural split matters: + +- `accepts` is a seller concern +- `verify` and `settle` are facilitator concerns +- buyer routing is an OmniClaw policy concern + +OmniClaw does not mix these layers together. + +The buyer still uses one action: + +```bash +omniclaw-cli inspect-x402 --recipient https://seller.example.com/compute +omniclaw-cli pay --recipient https://seller.example.com/compute --idempotency-key job-123 +``` + +The Financial Policy Engine inspects the seller's x402 requirements and chooses a route that the seller supports and the buyer can actually fund. + +## Integration Model + +OmniClaw supports managed and self-hosted settlement paths. Thirdweb, Circle, x402.org, and other facilitators can handle settlement where they are the best fit. + +OmniClaw's product responsibility: + +- inspect what the seller accepts +- enforce buyer policy before money moves +- choose a fundable route +- sign only the allowed action +- preserve logs, limits, and operator visibility + +That means a seller can use managed facilitator coverage, while the buyer still uses OmniClaw as the policy-controlled execution layer. + +## SDK Seller Examples + +Vendor and enterprise sellers should normally use the Python SDK. + +Circle Gateway: + +```python +payment=client.sell("$0.25", seller_address="0xVendorWallet") +``` + +Thirdweb: + +```python +payment=client.sell( + "$0.25", + seller_address="0xThirdwebServerWallet", + facilitator="thirdweb", +) +``` + +OmniClaw self-hosted exact: + +```python +payment=client.sell( + "$0.25", + seller_address="0xVendorWallet", + facilitator="omniclaw", +) +``` + +For the self-hosted exact path, set: + +```env +OMNICLAW_X402_SELF_HOSTED_FACILITATOR_URL=http://127.0.0.1:4022 +OMNICLAW_X402_EXACT_NETWORK_PROFILE=ARC-TESTNET +``` + +## Self-Hosted Exact Facilitator + +OmniClaw includes a self-hosted exact facilitator for teams that need direct control over settlement infrastructure. + +Common use cases: + +- custom network support +- enterprise self-hosting requirements +- deterministic testnet proof +- chain-native settlement on a selected EVM profile +- local development and integration testing + +The self-hosted facilitator implements standard x402 `exact` verify and settle behavior. The seller still owns the resource URL and `accepts` requirements; the facilitator verifies and settles the signed payment payload. + +## Buyer Route Selection + +For URL payments, the buyer path is: + +1. request the resource +2. receive HTTP 402 x402 requirements +3. inspect accepted payment schemes +4. enforce OmniClaw policy +5. choose the best supported route +6. sign and execute through the selected payment rail + +Current route priority: + +- use `GatewayWalletBatched` when the seller supports Circle Gateway nanopayments and the buyer has Gateway balance on the required network +- use `exact` when the seller supports standard x402 exact settlement +- if the seller supports both and Gateway is not ready, use `exact` +- if no supported route is available, fail clearly before spending + +## Self-Host An Exact Facilitator + +Use self-hosting when you need local proof, custom network control, or a fallback while validating an external provider. + +Run a facilitator with the first-class OmniClaw command: + +```bash +export OMNICLAW_X402_FACILITATOR_PRIVATE_KEY="0x..." + +omniclaw facilitator exact \ + --network-profile ARC-TESTNET \ + --port 4022 +``` + +For Base Sepolia: + +```bash +export OMNICLAW_X402_FACILITATOR_PRIVATE_KEY="0x..." + +omniclaw facilitator exact \ + --network-profile BASE-SEPOLIA \ + --port 4022 +``` + +You can override the RPC and accepted CAIP-2 network explicitly: + +```bash +omniclaw facilitator exact \ + --network-profile ARC-TESTNET \ + --network eip155:5042002 \ + --rpc-url https://rpc.testnet.arc.network \ + --port 4022 +``` + +The facilitator exposes: + +- `GET /supported` +- `POST /verify` +- `POST /settle` + +It does not need to expose `accepts`. + +For standard x402, `accepts` comes from the seller endpoint that is being monetized. OmniClaw's seller layer and seller harnesses create those requirements, and the facilitator handles verification and settlement after the buyer signs. + +## Environment Variables + +Self-hosted facilitator: + +```env +OMNICLAW_X402_FACILITATOR_PRIVATE_KEY=0x... +OMNICLAW_X402_FACILITATOR_NETWORK_PROFILE=ARC-TESTNET +OMNICLAW_X402_FACILITATOR_RPC_URL=https://rpc.testnet.arc.network +OMNICLAW_X402_FACILITATOR_NETWORKS=eip155:5042002 +OMNICLAW_X402_FACILITATOR_HOST=0.0.0.0 +OMNICLAW_X402_FACILITATOR_PORT=4022 +``` + +Seller exact endpoint: + +```env +OMNICLAW_X402_EXACT_NETWORK_PROFILE=ARC-TESTNET +OMNICLAW_X402_EXACT_FACILITATOR_URL=http://127.0.0.1:4022 +OMNICLAW_X402_EXACT_PRICE=$0.25 +``` + +Preferred behavior: + +- set `OMNICLAW_PRIVATE_KEY` for the seller runtime +- let the seller derive `payTo` from that key + +Optional override: + +```env +OMNICLAW_X402_EXACT_PAY_TO=0xSellerAddress +``` + +Use the override only when you intentionally want the seller to advertise a payout address different from the runtime key. + +External exact facilitator: + +```env +OMNICLAW_X402_EXACT_FACILITATOR_URL=https://x402.org/facilitator +``` + +### x402.org Base Sepolia + +Use x402.org first when you need an external facilitator test without Thirdweb account setup. + +```bash +export OMNICLAW_PRIVATE_KEY="0xYourSellerPrivateKey" +export OMNICLAW_X402_EXACT_NETWORK_PROFILE="BASE-SEPOLIA" +export OMNICLAW_X402_EXACT_FACILITATOR_URL="https://x402.org/facilitator" + +python scripts/start_external_x402_seller.py +``` + +If you need a non-default payout address, add: + +```bash +export OMNICLAW_X402_EXACT_PAY_TO="0xYourSellerAddress" +``` + +Then pay the seller with: + +```bash +omniclaw-cli inspect-x402 --recipient http://127.0.0.1:4021/compute?size=70000 +omniclaw-cli pay --recipient http://127.0.0.1:4021/compute?size=70000 --idempotency-key x402-org-base-sepolia-001 +``` + +Full runbook: [../examples/external-x402-facilitator/README.md](../examples/external-x402-facilitator/README.md). + +Thirdweb-backed sellers normally configure their seller middleware with Thirdweb's own facilitator object. OmniClaw buyers do not need special Thirdweb configuration; they inspect and pay the seller's x402 endpoint through the standard buyer path. + +For OmniClaw seller-side Thirdweb validation, set: + +```env +THIRDWEB_SECRET_KEY=... +THIRDWEB_SERVER_WALLET_ADDRESS=0x... +THIRDWEB_X402_NETWORK=base-sepolia +``` + +Then create the seller gate with `facilitator="thirdweb"` and use the Thirdweb server wallet address as the seller address. + +Thirdweb is different from the self-hosted OmniClaw exact facilitator: + +- Thirdweb exposes `accepts`, `verify`, `settle`, `fetch`, and discovery over HTTP +- OmniClaw exact facilitator exposes `supported`, `verify`, and `settle` +- OmniClaw seller middleware or seller app still owns the resource URL and price policy + +## Arc Testnet + +Arc is supported as an exact-settlement EVM network profile: + +- OmniClaw profile: `ARC-TESTNET` +- CAIP-2 network: `eip155:5042002` +- default RPC: `https://rpc.testnet.arc.network` +- explorer: `https://testnet.arcscan.app` +- USDC interface: `0x3600000000000000000000000000000000000000` + +That means an Arc seller can advertise standard x402 `exact` requirements, the buyer can pay through OmniClaw policy controls, and settlement can be viewed on ArcScan. + +Arc self-hosted exact is now live-proven in this repo workflow: + +- seller advertises `exact` on `eip155:5042002` +- OmniClaw buyer selects `x402` with `direct_wallet` +- OmniClaw exact facilitator handles `verify` and `settle` +- settlement confirms on Arc Testnet RPC + +Practical boundary: + +- yes, self-hosted OmniClaw exact can be used for Arc +- yes, the same exact model works for Base Sepolia and other supported EVM profiles +- no, this does not mean "every network automatically works" + +For the profiles already configured in OmniClaw, nothing else needs to be invented in the product layer. The required network metadata is already present in code: + +- CAIP-2 mapping +- default RPC +- explorer base URL where available +- default USDC asset address where available + +The network must have: + +- an EVM CAIP-2 mapping +- a configured network profile +- an RPC endpoint +- a USDC asset address compatible with the exact flow + +So the operational requirement for an already configured profile is only: + +- run the facilitator with a funded seller key +- run the seller surface with the same target profile +- run the buyer policy engine with a funded buyer key on that network +- execute `inspect-x402` and `pay` + +That is a deployment requirement, not a missing architecture requirement. + +## External Facilitators + +External facilitators remain first-class. If a seller advertises an `exact` payment requirement using another facilitator, OmniClaw's buyer flow can still pay through the standard x402 SDK path as long as: + +- the buyer has the required chain funds +- the seller requirements include a supported `exact` payment option +- the selected facilitator can verify and settle the payload + +The product rule is simple: OmniClaw governs financial authority; facilitators settle supported x402 payment payloads. + +### Thirdweb + +Thirdweb is the recommended managed external facilitator path to validate next. It is a strong fit for teams that want broad EVM network coverage and gas sponsorship without operating their own facilitator. + +Based on Thirdweb's x402 facilitator docs, their facilitator: + +- verifies and submits x402 payments +- uses the seller's Thirdweb server wallet +- supports gasless transaction submission through EIP-7702 +- exposes public HTTP `accepts`, `verify`, `settle`, `fetch`, and discovery endpoints that OmniClaw can call directly from Python +- supports payments across 170+ EVM chains +- supports tokens that expose ERC-2612 permit or ERC-3009 authorization + +How this fits OmniClaw: + +- buyer side: OmniClaw can pay Thirdweb-backed x402 endpoints through the standard `exact` buyer path +- seller side: a team can use Thirdweb's own seller/facilitator stack instead of running an OmniClaw facilitator +- policy layer: OmniClaw still controls whether the agent is allowed to pay before money moves + +Recommended Thirdweb validation flow: + +1. call Thirdweb's HTTP `accepts` endpoint through OmniClaw's Python facilitator adapter to generate seller requirements +2. capture a signed x402 `paymentPayload` and matching `paymentRequirements` +3. call Thirdweb's HTTP `verify` endpoint through OmniClaw's Python facilitator adapter +4. call Thirdweb's HTTP `settle` endpoint through OmniClaw's Python facilitator adapter +5. optionally test Thirdweb's HTTP `fetch` and discovery endpoints for ecosystem integration +6. confirm the transaction in the Thirdweb dashboard and chain explorer +7. run a full buyer flow against a Thirdweb-backed seller URL once seller credentials are available + +The repo includes a direct HTTP validation target at [../examples/thirdweb-http-facilitator/README.md](../examples/thirdweb-http-facilitator/README.md). + +When Thirdweb credentials are available, validate the full flow with the same proof checklist used for other facilitators: seller URL, requirements, payment result, settlement transaction, and final paid response. + +## Operational Model + +For production-like deployments, run the facilitator as separate infrastructure from the Financial Policy Engine. + +Recommended separation: + +- buyer Financial Policy Engine: enforces the buyer's policy and signs buyer-side actions +- seller app: exposes paid resources and advertises x402 requirements +- facilitator: verifies and settles x402 payloads + +This separation matters because it keeps policy, resource serving, and settlement independently deployable. + +## References + +- Arc contract addresses: https://docs.arc.network/arc/references/contract-addresses +- Circle USDC contract addresses: https://developers.circle.com/stablecoins/usdc-contract-addresses +- Thirdweb x402 facilitator: https://portal.thirdweb.com/x402/facilitator +- x402 network and token support: https://docs.x402.org/core-concepts/network-and-token-support diff --git a/.agents/skills/omniclaw-cli/SKILL.md b/docs/omniclaw-cli-skill/SKILL.md similarity index 77% rename from .agents/skills/omniclaw-cli/SKILL.md rename to docs/omniclaw-cli-skill/SKILL.md index b79d65f..837c129 100644 --- a/.agents/skills/omniclaw-cli/SKILL.md +++ b/docs/omniclaw-cli-skill/SKILL.md @@ -1,12 +1,12 @@ --- name: omniclaw description: > - Use this skill whenever you need to pay for an x402 URL, transfer USDC to an - address, inspect OmniClaw balances or ledger entries, or expose a paid API - with omniclaw-cli serve. OmniClaw is the Economic Execution and Control Layer - for Agentic Systems. The CLI is the zero-trust execution layer: buyers use - `omniclaw-cli pay`, sellers use `omniclaw-cli serve`. Use this skill for the - CLI execution path only, not for owner setup, policy editing, wallet + Use this skill whenever an agent needs to pay for an x402 URL, transfer USDC + to an address, inspect OmniClaw balances or ledger entries, or expose a + temporary agent-owned paid service with omniclaw-cli serve. OmniClaw is the + Economic Execution and Control Layer for Agentic Systems. The CLI is the + zero-trust execution layer for agents. Use this skill for the CLI execution + path only, not for vendor SDK integration, owner setup, policy editing, wallet provisioning, or Financial Policy Engine administration. requires: - env: OMNICLAW_SERVER_URL @@ -31,7 +31,7 @@ Use `omniclaw-cli` only when the task is directly about one of these actions: - transfer USDC to an address - inspect wallet, Gateway, or Circle balances - inspect transaction history -- expose a paid seller endpoint with `serve` +- expose a temporary agent-owned paid endpoint with `serve` Do not use this skill for: @@ -52,10 +52,12 @@ It is the economic execution and control layer that combines: This skill is specifically about the CLI execution surface. -The same CLI has two economic roles: +The same CLI has two agent-side economic roles: - buyer role: `omniclaw-cli pay` -- seller role: `omniclaw-cli serve` +- temporary/local seller role: `omniclaw-cli serve` + +Vendor and enterprise seller APIs should use the Python SDK with `client.sell(...)`, not this CLI skill. The agent does not control the private key. The Financial Policy Engine enforces policy and signs allowed actions. @@ -93,16 +95,17 @@ Do not invent or search for them yourself. ### For x402 URLs -1. Use `omniclaw-cli pay --recipient `. -2. Add `--method`, `--body`, and `--header` when the paid endpoint expects a non-GET request. -3. Add `--output` if the paid response should be saved. +1. Run `omniclaw-cli inspect-x402 --recipient ` before the first live payment to confirm the seller requirements and buyer funding path. +2. Use `omniclaw-cli pay --recipient `. +3. Add `--method`, `--body`, and `--header` when the paid endpoint expects a non-GET request. +4. Add `--output` if the paid response should be saved. ### For direct address transfers 1. Use `omniclaw-cli pay --recipient <0xaddress> --amount `. 2. Always include `--purpose`. -### For seller tasks +### For agent-owned local seller tasks 1. Inspect current state with `balance-detail`. 2. Start the paid endpoint with `omniclaw-cli serve`. diff --git a/.agents/skills/omniclaw-cli/references/cli-reference.md b/docs/omniclaw-cli-skill/references/cli-reference.md similarity index 94% rename from .agents/skills/omniclaw-cli/references/cli-reference.md rename to docs/omniclaw-cli-skill/references/cli-reference.md index 5692345..a729bea 100644 --- a/.agents/skills/omniclaw-cli/references/cli-reference.md +++ b/docs/omniclaw-cli-skill/references/cli-reference.md @@ -6,13 +6,14 @@ Do not hand-edit command schemas here; regenerate instead. Generator: ```bash -python3 .agents/skills/omniclaw-cli/scripts/generate_cli_reference.py +python3 scripts/generate_cli_reference.py ``` ## Usage Notes - same CLI, two roles: buyer uses `pay`, seller uses `serve` - use `can-pay` before a new recipient when policy allow/deny matters +- use `inspect-x402` before a new paid URL when you need to see seller requirements and buyer funding readiness - use `balance-detail` when Gateway state matters - use `--idempotency-key` for job-based payments - for x402 URLs, `--amount` can be omitted because the payment requirements come from the seller endpoint @@ -24,6 +25,7 @@ Buyer paying an x402 endpoint: ```bash omniclaw-cli can-pay --recipient http://seller-host:8000/api/data +omniclaw-cli inspect-x402 --recipient http://seller-host:8000/api/data omniclaw-cli pay --recipient http://seller-host:8000/api/data --idempotency-key job-123 ``` @@ -82,6 +84,9 @@ omniclaw-cli serve \ │ withdraw_trustless_complete Alias for withdraw-trustless-complete │ │ pay Execute a payment or pay for an x402 service. │ │ simulate Simulate a payment without executing. │ +│ inspect-x402 Inspect an x402 endpoint and show which │ +│ payment route OmniClaw would use. │ +│ inspect_x402 Alias for inspect-x402 │ │ can-pay Check if recipient is allowed. │ │ can_pay Alias for can-pay │ │ create-intent Create a payment intent (authorize). │ @@ -204,6 +209,24 @@ omniclaw-cli serve \ ╰──────────────────────────────────────────────────────────────────────────────╯ ``` +### `omniclaw-cli inspect-x402 --help` + +```text + + Usage: omniclaw-cli inspect-x402 [OPTIONS] + + Inspect an x402 endpoint and show which payment route OmniClaw would use. + +╭─ Options ────────────────────────────────────────────────────────────────────╮ +│ * --recipient TEXT x402 URL to inspect [required] │ +│ --amount TEXT Optional max amount in USDC │ +│ --method TEXT HTTP method for x402 requests [default: GET] │ +│ --body TEXT Request body for x402 requests │ +│ --header TEXT Additional headers for x402 requests │ +│ --help Show this message and exit. │ +╰──────────────────────────────────────────────────────────────────────────────╯ +``` + ### `omniclaw-cli simulate --help` ```text diff --git a/docs/omniclaw-cli-skill/scripts/generate_cli_reference.py b/docs/omniclaw-cli-skill/scripts/generate_cli_reference.py new file mode 100755 index 0000000..0a1a753 --- /dev/null +++ b/docs/omniclaw-cli-skill/scripts/generate_cli_reference.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import os +import subprocess +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[3] +HUMAN_REF = REPO_ROOT / "docs" / "cli-reference.md" + +COMMANDS = [ + ("omniclaw-cli --help", ["omniclaw-cli", "--help"]), + ("omniclaw-cli configure --help", ["omniclaw-cli", "configure", "--help"]), + ("omniclaw-cli status --help", ["omniclaw-cli", "status", "--help"]), + ("omniclaw-cli ping --help", ["omniclaw-cli", "ping", "--help"]), + ("omniclaw-cli address --help", ["omniclaw-cli", "address", "--help"]), + ("omniclaw-cli balance --help", ["omniclaw-cli", "balance", "--help"]), + ("omniclaw-cli balance-detail --help", ["omniclaw-cli", "balance-detail", "--help"]), + ("omniclaw-cli can-pay --help", ["omniclaw-cli", "can-pay", "--help"]), + ("omniclaw-cli inspect-x402 --help", ["omniclaw-cli", "inspect-x402", "--help"]), + ("omniclaw-cli simulate --help", ["omniclaw-cli", "simulate", "--help"]), + ("omniclaw-cli pay --help", ["omniclaw-cli", "pay", "--help"]), + ("omniclaw-cli deposit --help", ["omniclaw-cli", "deposit", "--help"]), + ("omniclaw-cli withdraw --help", ["omniclaw-cli", "withdraw", "--help"]), + ("omniclaw-cli withdraw-trustless --help", ["omniclaw-cli", "withdraw-trustless", "--help"]), + ("omniclaw-cli withdraw-trustless-complete --help", ["omniclaw-cli", "withdraw-trustless-complete", "--help"]), + ("omniclaw-cli serve --help", ["omniclaw-cli", "serve", "--help"]), + ("omniclaw-cli create-intent --help", ["omniclaw-cli", "create-intent", "--help"]), + ("omniclaw-cli confirm-intent --help", ["omniclaw-cli", "confirm-intent", "--help"]), + ("omniclaw-cli get-intent --help", ["omniclaw-cli", "get-intent", "--help"]), + ("omniclaw-cli cancel-intent --help", ["omniclaw-cli", "cancel-intent", "--help"]), + ("omniclaw-cli ledger --help", ["omniclaw-cli", "ledger", "--help"]), + ("omniclaw-cli list-tx --help", ["omniclaw-cli", "list-tx", "--help"]), + ("omniclaw-cli confirmations --help", ["omniclaw-cli", "confirmations", "--help"]), + ("omniclaw-cli confirmations get --help", ["omniclaw-cli", "confirmations", "get", "--help"]), + ("omniclaw-cli confirmations approve --help", ["omniclaw-cli", "confirmations", "approve", "--help"]), + ("omniclaw-cli confirmations deny --help", ["omniclaw-cli", "confirmations", "deny", "--help"]), +] + +FALLBACK_OUTPUTS = { + "omniclaw-cli balance --help": """\ +Usage: omniclaw-cli balance [OPTIONS] + +Get wallet balance. + +Options: + --help Show this message and exit. +""", + "omniclaw-cli balance-detail --help": """\ +Usage: omniclaw-cli balance-detail [OPTIONS] + +Get detailed balance including Gateway and Circle wallet. + +Options: + --help Show this message and exit. +""", +} + +TIMEOUT_SECONDS = 25 + +HEADER = """# OmniClaw CLI Reference + +This file is generated from the live `omniclaw-cli --help` surface. +Do not hand-edit command schemas here; regenerate instead. + +Generator: + +```bash +python3 scripts/generate_cli_reference.py +``` + +## Usage Notes + +- same CLI, two roles: buyer uses `pay`, seller uses `serve` +- use `can-pay` before a new recipient when policy allow/deny matters +- use `inspect-x402` before a new paid URL when you need to see seller requirements and buyer funding readiness +- use `balance-detail` when Gateway state matters +- use `--idempotency-key` for job-based payments +- for x402 URLs, `--amount` can be omitted because the payment requirements come from the seller endpoint +- `serve` binds to `0.0.0.0` even if the banner prints `localhost` + +## Example Flows + +Buyer paying an x402 endpoint: + +```bash +omniclaw-cli can-pay --recipient http://seller-host:8000/api/data +omniclaw-cli inspect-x402 --recipient http://seller-host:8000/api/data +omniclaw-cli pay --recipient http://seller-host:8000/api/data --idempotency-key job-123 +``` + +Buyer paying a direct address: + +```bash +omniclaw-cli pay \\ + --recipient 0xRecipientAddress \\ + --amount 5.00 \\ + --purpose "service payment" \\ + --idempotency-key job-123 +``` + +Seller exposing a paid endpoint: + +```bash +omniclaw-cli serve \\ + --price 0.01 \\ + --endpoint /api/data \\ + --exec "python app.py" \\ + --port 8000 +``` + +## Live Help Output +""" + + +def run_help(title: str, args: list[str]) -> str: + try: + proc = subprocess.run( + args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + timeout=TIMEOUT_SECONDS, + check=False, + env={"OMNICLAW_CLI_NO_BANNER": "1", **os.environ}, + ) + except subprocess.TimeoutExpired: + fallback = FALLBACK_OUTPUTS.get(title) + if fallback: + return f"{fallback.rstrip()}\n\n[live help timed out after {TIMEOUT_SECONDS}s; schema filled from source]" + return f"[help command timed out after {TIMEOUT_SECONDS}s]" + + output = (proc.stdout or "").rstrip() + if proc.returncode == 0: + return output + + if output: + return f"{output}\n\n[exit code: {proc.returncode}]" + return f"[help command failed with exit code {proc.returncode}]" + + +sections: list[str] = [HEADER.rstrip()] +for title, args in COMMANDS: + output = run_help(title, args) + sections.append(f"### `{title}`\n\n```text\n{output}\n```") + +content = "\n\n".join(sections) + "\n" +HUMAN_REF.write_text(content) +print(f"wrote {HUMAN_REF}") diff --git a/docs/omniclaw-cli-skill/scripts/generate_cli_reference.sh b/docs/omniclaw-cli-skill/scripts/generate_cli_reference.sh new file mode 100755 index 0000000..0188225 --- /dev/null +++ b/docs/omniclaw-cli-skill/scripts/generate_cli_reference.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" +python3 scripts/generate_cli_reference.py diff --git a/docs/operator-cli.md b/docs/operator-cli.md new file mode 100644 index 0000000..68fe01a --- /dev/null +++ b/docs/operator-cli.md @@ -0,0 +1,54 @@ +# Operator CLI + +OmniClaw ships two command surfaces: + +- `omniclaw` for owner/operator infrastructure +- `omniclaw-cli` for agent-side financial execution + +Use `omniclaw` when you are running infrastructure: + +```bash +omniclaw setup --api-key "$CIRCLE_API_KEY" --entity-secret "$ENTITY_SECRET" +omniclaw server --port 8080 +omniclaw facilitator exact --network-profile ARC-TESTNET --port 4022 +omniclaw policy lint --path ./policy.json +omniclaw env +omniclaw doctor +``` + +`--entity-secret` is optional only when this Circle API key/account has not created one yet. Circle allows one active Entity Secret per account/API key. If you already have it, pass it directly; if you omit it and OmniClaw cannot find one in env or managed config, setup will generate and register a new one. + +Use `omniclaw-cli` when an agent is performing constrained financial actions: + +```bash +omniclaw-cli can-pay --recipient https://seller.example.com/compute +omniclaw-cli inspect-x402 --recipient https://seller.example.com/compute +omniclaw-cli pay --recipient https://seller.example.com/compute --idempotency-key job-123 +omniclaw-cli serve --price 0.01 --endpoint /api/data --exec "python app.py" +``` + +`omniclaw-cli serve` is for agent-owned or local paid services. Vendor and enterprise APIs should use the Python SDK seller middleware (`client.sell(...)`) inside the application. + +## Responsibility Split + +The operator CLI manages trusted infrastructure and configuration. The agent CLI executes through the Financial Policy Engine and never needs raw owner authority. + +This split is central to OmniClaw: + +- tools expose what the agent can try to do +- the Financial Policy Engine governs what financial authority the agent actually has +- facilitators settle valid x402 payment payloads on supported rails + +## Self-Hosted Facilitator + +The operator CLI includes a first-class facilitator command: + +```bash +export OMNICLAW_X402_FACILITATOR_PRIVATE_KEY="0x..." + +omniclaw facilitator exact \ + --network-profile ARC-TESTNET \ + --port 4022 +``` + +For the full facilitator guide, see [facilitators.md](facilitators.md). diff --git a/docs/production-readiness.md b/docs/production-readiness.md new file mode 100644 index 0000000..3b55167 --- /dev/null +++ b/docs/production-readiness.md @@ -0,0 +1,134 @@ +# Production Readiness + +This is the short production checklist for OmniClaw. + +Use it before publishing a release, running a pilot, or demoing a real external facilitator flow. + +## What OmniClaw Is + +OmniClaw is the policy-controlled execution layer for agent payments. + +It does four things: + +- inspects what a seller accepts +- enforces buyer policy before money moves +- routes to a compatible payment rail +- records what happened for operators + +## Facilitator Strategy + +OmniClaw is facilitator-aware. Sellers can use the settlement path that fits their deployment while buyers keep OmniClaw policy controls in front of money movement. + +Supported facilitator paths: + +- x402.org can validate external standard exact settlement immediately on Base Sepolia +- Thirdweb can provide broad gas-sponsored x402 settlement +- Circle Gateway can provide batched gasless nanopayments +- x402.org or other facilitators can support standard exact settlement +- OmniClaw self-hosted exact facilitator is optional infrastructure for proof, Arc/custom networks, and self-hosted control + +## Required Proofs Before Claiming Support + +For any public network/facilitator claim, capture: + +- seller URL +- `inspect-x402` output +- `pay` output +- transaction hash or settlement ID +- dashboard/explorer screenshot +- policy file used for the buyer + +Do not claim a facilitator/network combination is production-proven until this proof exists. + +## Buyer Lock + +The buyer path is locked when: + +- `omniclaw-cli can-pay` works +- `omniclaw-cli inspect-x402` reports the selected route +- `omniclaw-cli pay` uses `/api/v1/pay` +- policy blocks unsafe recipients before settlement +- exact x402 payments use the standard x402 SDK path +- Gateway payments require Gateway readiness before selecting `GatewayWalletBatched` + +## Seller Lock + +The seller path is locked when: + +- seller advertises correct x402 requirements +- seller does not leak Gateway metadata into non-Gateway exact flows +- paid response unlocks only after settlement +- settlement status is visible in logs and response metadata + +## Facilitator Lock + +The facilitator strategy is locked as: + +- x402.org first for external exact validation on Base Sepolia +- Thirdweb next for managed external x402 validation once account access is available +- Circle Gateway for batched nanopayments +- external exact facilitators where seller requirements support them +- OmniClaw self-hosted exact facilitator only for proof, custom networks, Arc, and self-hosted enterprise deployments + +Operational split: + +- seller surface creates `accepts` +- facilitator verifies and settles +- buyer policy engine decides whether payment is allowed and which route is selected + +Keep these layers separate in deployment docs and product claims. + +## Current Proof Status + +Treat these as the current ship state: + +- Base Sepolia external exact via x402.org: live-proven end to end +- buyer exact x402 path via `/api/v1/pay`: live-proven end to end +- seller exact route advertising correct `payTo`: live-proven end to end +- OmniClaw self-hosted exact facilitator: live-proven on Arc Testnet and test-covered +- Arc exact profile: live-proven with self-hosted facilitator settlement +- Thirdweb HTTP integration: wired and test-covered for `accepts`, `verify`, `settle`, `fetch`, and discovery; live account proof still pending credentials + +Production wording rule: + +- say `live-proven` only when transaction proof exists +- say `code-ready` when the path is implemented and test-covered but not yet rerun live in the current environment + +## Release Gate + +Run before shipping: + +```bash +uv sync --extra dev +uv run pytest \ + tests/test_setup.py \ + tests/test_payment_intents.py \ + tests/test_client.py \ + tests/test_webhook_verification.py + +python3 -m py_compile \ + src/omniclaw/seller/facilitator_generic.py \ + examples/thirdweb-http-facilitator/verify_settle.py \ + src/omniclaw/admin_cli.py \ + src/omniclaw/facilitator/exact.py \ + src/omniclaw/facilitator/networks.py \ + scripts/verify_release_artifact.py + +python3 scripts/release_verify.sh +``` + +If you are validating exact-flow pilot coverage, run the current smoke slice after syncing +dependencies: + +```bash +uv run pytest \ + tests/test_facilitator_e2e.py \ + tests/test_cli_facilitator.py \ + tests/test_cctp_constants.py \ + tests/test_exact_network_profiles.py \ + tests/test_exact_facilitator_app.py \ + tests/test_x402_sdk_adapter.py \ + -q +``` + +This exact-flow slice currently depends on an `x402` build that exposes `x402.schemas`. diff --git a/examples/agent/seller/start.sh b/examples/agent/seller/start.sh index 8f33c96..a8440be 100755 --- a/examples/agent/seller/start.sh +++ b/examples/agent/seller/start.sh @@ -1,9 +1,8 @@ #!/bin/bash -export CIRCLE_API_KEY=TEST_API_KEY:511a1daf3edd65884326e8f56368088a:396b2b196a9206c435c08de607f7ee2b -export OMNICLAW_PRIVATE_KEY=0x5ec6f9922879be60d25c2d10b39a89cd8138eeffedc077296a174c2a1b9254c0 -export OMNICLAW_RPC_URL=https://ethereum-sepolia-rpc.publicnode.com -export OMNICLAW_NETWORK=ETH-SEPOLIA -export OMNICLAW_AGENT_TOKEN=seller-agent-token -export OMNICLAW_AGENT_POLICY_PATH=/home/abiorh/omnuron-labs/omniclaw/examples/agent/seller/policy.json -cd /home/abiorh/omnuron-labs/omniclaw +export CIRCLE_API_KEY=${CIRCLE_API_KEY:-} +export OMNICLAW_PRIVATE_KEY=${OMNICLAW_PRIVATE_KEY:-} +export OMNICLAW_RPC_URL=${OMNICLAW_RPC_URL:-https://ethereum-sepolia-rpc.publicnode.com} +export OMNICLAW_NETWORK=${OMNICLAW_NETWORK:-ETH-SEPOLIA} +export OMNICLAW_AGENT_TOKEN=${OMNICLAW_AGENT_TOKEN:-seller-agent-token} +export OMNICLAW_AGENT_POLICY_PATH=${OMNICLAW_AGENT_POLICY_PATH:-$(pwd)/examples/agent/seller/policy.json} exec uv run uvicorn omniclaw.agent.server:app --host 0.0.0.0 --port 8081 diff --git a/examples/b2b-sdk-integration/README.md b/examples/b2b-sdk-integration/README.md new file mode 100644 index 0000000..55e8e33 --- /dev/null +++ b/examples/b2b-sdk-integration/README.md @@ -0,0 +1,220 @@ +# B2B SDK Integration + +This is the enterprise/vendor integration path. + +Use this when a business owns the product surface, backend, API, or workflow. The vendor integrates OmniClaw through the Python SDK. Agents may still buy from that vendor, but the vendor does not need to run `omniclaw-cli`. + +## Deployment Model + +| Component | Who Runs It | Purpose | +| --- | --- | --- | +| Vendor app | enterprise/vendor | Serves the product API and uses `client.sell(...)` | +| Buyer app or agent | customer/partner/internal team | Pays through SDK or CLI | +| Financial Policy Engine | owner/operator | Optional API service for policy-controlled agent execution | +| Facilitator | vendor/operator/managed provider | Verifies and settles x402 payloads | + +The Financial Policy Engine is the hosted policy-control service built on the same OmniClaw SDK primitives. Use it when the payer is an agent, workflow, or external automation that should not hold raw wallet authority. + +For pure backend-to-backend integrations, a business can also embed the SDK directly in its own service and apply guards/policy in-process. + +## Scenario 1: Vendor API With Circle Gateway + +Use this when the vendor wants Circle Gateway `GatewayWalletBatched` settlement. + +Environment: + +```bash +export CIRCLE_API_KEY="..." +export OMNICLAW_PRIVATE_KEY="0xVendorOrOperatorKey" +export OMNICLAW_NETWORK="BASE-SEPOLIA" +export OMNICLAW_RPC_URL="https://sepolia.base.org" +export SELLER_ADDRESS="0xVendorSellerAddress" +``` + +Vendor app: + +```python +import os + +from fastapi import FastAPI +from omniclaw import Network, OmniClaw + +app = FastAPI() +client = OmniClaw(network=Network.BASE_SEPOLIA) + +@app.get("/compute") +async def compute( + payment=client.sell("$0.25", seller_address=os.environ["SELLER_ADDRESS"]), +): + return { + "service": "vendor-compute", + "paid_by": payment.payer, + "result": {"job": "complete"}, + } +``` + +Executable example: `vendor_circle.py` + +Run: + +```bash +uvicorn vendor_app:app --host 0.0.0.0 --port 8000 +``` + +## Scenario 2: Vendor API With Thirdweb Managed x402 + +Use this when the vendor wants managed external x402 settlement and Thirdweb server wallet support. + +Environment: + +```bash +export THIRDWEB_SECRET_KEY="..." +export THIRDWEB_SERVER_WALLET_ADDRESS="0xThirdwebServerWallet" +export THIRDWEB_X402_NETWORK="base-sepolia" +export SELLER_ADDRESS="$THIRDWEB_SERVER_WALLET_ADDRESS" +``` + +Vendor app: + +```python +import os + +from fastapi import FastAPI +from omniclaw import OmniClaw + +app = FastAPI() +client = OmniClaw() + +@app.get("/report") +async def report( + payment=client.sell( + "$0.50", + seller_address=os.environ["SELLER_ADDRESS"], + facilitator="thirdweb", + ), +): + return { + "service": "vendor-report", + "paid_by": payment.payer, + "report": {"status": "ready"}, + } +``` + +Executable example: `vendor_thirdweb.py` + +Thirdweb creates the seller `accepts` requirements and handles `verify` / `settle`. OmniClaw still controls the SDK surface and exposes the same paid endpoint behavior. + +## Scenario 3: Vendor API With OmniClaw Self-Hosted Exact Facilitator + +Use this when the vendor wants self-hosted exact settlement on a supported EVM profile such as Arc Testnet or Base Sepolia. + +Start the facilitator: + +```bash +export OMNICLAW_X402_FACILITATOR_PRIVATE_KEY="0xFacilitatorKey" + +omniclaw facilitator exact \ + --network-profile ARC-TESTNET \ + --port 4022 +``` + +Vendor app environment: + +```bash +export OMNICLAW_X402_SELF_HOSTED_FACILITATOR_URL="http://127.0.0.1:4022" +export OMNICLAW_X402_EXACT_NETWORK_PROFILE="ARC-TESTNET" +export SELLER_ADDRESS="0xVendorSellerAddress" +``` + +Vendor app: + +```python +import os + +from fastapi import FastAPI +from omniclaw import OmniClaw + +app = FastAPI() +client = OmniClaw() + +@app.get("/arc-compute") +async def arc_compute( + payment=client.sell( + "$0.25", + seller_address=os.environ["SELLER_ADDRESS"], + facilitator="omniclaw", + ), +): + return { + "service": "arc-vendor-compute", + "paid_by": payment.payer, + "result": {"network": "ARC-TESTNET", "status": "complete"}, + } +``` + +Executable example: `vendor_self_hosted_exact.py` + +In this mode: + +- the vendor app creates `accepts` +- the self-hosted OmniClaw facilitator handles `/verify` and `/settle` +- the buyer can pay with OmniClaw CLI, OmniClaw SDK, or any compatible x402 buyer + +## Scenario 4: Enterprise Buyer With SDK + +Use this when a backend service, not an interactive agent, needs to buy from a paid vendor endpoint. + +```python +from omniclaw import Network, OmniClaw + +client = OmniClaw(network=Network.BASE_SEPOLIA) + +result = await client.pay( + wallet_id="enterprise-wallet-id", + recipient="https://vendor.example.com/compute", + amount="1.00", + purpose="vendor compute job", + idempotency_key="compute-job-2026-04-14-001", +) + +if not result.success: + raise RuntimeError(result.error or "payment failed") + +print(result.status, result.blockchain_tx or result.transaction_id) +``` + +Executable example: `buyer_sdk.py` + +## Scenario 5: Enterprise Buyer With Policy Engine + +Use this when the payer is an internal agent, worker, or partner-facing integration and the enterprise wants a network boundary between the agent and signing authority. + +Policy engine environment: + +```bash +export OMNICLAW_PRIVATE_KEY="0xEnterpriseBuyerKey" +export OMNICLAW_AGENT_TOKEN="enterprise-agent-token" +export OMNICLAW_AGENT_POLICY_PATH="./policy.json" +export OMNICLAW_NETWORK="BASE-SEPOLIA" +export OMNICLAW_RPC_URL="https://sepolia.base.org" + +omniclaw server --port 8080 +``` + +Agent or worker environment: + +```bash +export OMNICLAW_SERVER_URL="https://policy.enterprise.example" +export OMNICLAW_TOKEN="enterprise-agent-token" +``` + +The worker can now call the policy engine instead of holding wallet authority directly. The CLI is one client for this API; an enterprise can also call the API from its own worker. + +## Deployment Checklist + +- Choose the seller path: Circle Gateway, Thirdweb, or OmniClaw self-hosted exact. +- Put the vendor product API behind `client.sell(...)`. +- Run the buyer through SDK directly or through the Financial Policy Engine. +- Use one idempotency key per business job. +- Log seller fulfillment separately from settlement. +- Capture `402`, `inspect`, `pay`, settlement tx, and final paid response before production traffic. diff --git a/examples/b2b-sdk-integration/buyer_sdk.py b/examples/b2b-sdk-integration/buyer_sdk.py new file mode 100644 index 0000000..3d4f8e1 --- /dev/null +++ b/examples/b2b-sdk-integration/buyer_sdk.py @@ -0,0 +1,23 @@ +from __future__ import annotations + +import asyncio +import os +from uuid import uuid4 + +from omniclaw import Network, OmniClaw + + +async def main() -> None: + client = OmniClaw(network=Network.from_string(os.getenv("OMNICLAW_NETWORK", "BASE-SEPOLIA"))) + result = await client.pay( + wallet_id=os.environ["OMNICLAW_BUYER_WALLET_ID"], + recipient=os.environ["OMNICLAW_BUYER_RECIPIENT"], + amount=os.getenv("OMNICLAW_BUYER_MAX_AMOUNT", "1.00"), + purpose=os.getenv("OMNICLAW_BUYER_PURPOSE", "vendor payment"), + idempotency_key=os.getenv("OMNICLAW_BUYER_IDEMPOTENCY_KEY", f"buyer-sdk-{uuid4()}"), + ) + print(result.model_dump_json(indent=2) if hasattr(result, "model_dump_json") else result) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/b2b-sdk-integration/vendor_circle.py b/examples/b2b-sdk-integration/vendor_circle.py new file mode 100644 index 0000000..7371822 --- /dev/null +++ b/examples/b2b-sdk-integration/vendor_circle.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +import os + +from fastapi import FastAPI + +from omniclaw import Network, OmniClaw + + +app = FastAPI(title="OmniClaw B2B Vendor - Circle Gateway") +client = OmniClaw(network=Network.from_string(os.getenv("OMNICLAW_NETWORK", "BASE-SEPOLIA"))) + + +@app.get("/compute") +async def compute( + payment=client.sell("$0.25", seller_address=os.environ["SELLER_ADDRESS"]), +): + return { + "service": "vendor-circle-compute", + "paid_by": payment.payer, + "amount": payment.amount, + "result": {"status": "complete"}, + } + diff --git a/examples/b2b-sdk-integration/vendor_self_hosted_exact.py b/examples/b2b-sdk-integration/vendor_self_hosted_exact.py new file mode 100644 index 0000000..9898278 --- /dev/null +++ b/examples/b2b-sdk-integration/vendor_self_hosted_exact.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import os + +from fastapi import FastAPI + +from omniclaw import OmniClaw + + +app = FastAPI(title="OmniClaw B2B Vendor - Self-Hosted Exact") +client = OmniClaw() + + +@app.get("/arc-compute") +async def arc_compute( + payment=client.sell( + "$0.25", + seller_address=os.environ["SELLER_ADDRESS"], + facilitator="omniclaw", + ), +): + return { + "service": "vendor-self-hosted-exact-compute", + "paid_by": payment.payer, + "amount": payment.amount, + "network": os.getenv("OMNICLAW_X402_EXACT_NETWORK_PROFILE", "ARC-TESTNET"), + "result": {"status": "complete"}, + } + diff --git a/examples/b2b-sdk-integration/vendor_thirdweb.py b/examples/b2b-sdk-integration/vendor_thirdweb.py new file mode 100644 index 0000000..879fe4b --- /dev/null +++ b/examples/b2b-sdk-integration/vendor_thirdweb.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +import os + +from fastapi import FastAPI + +from omniclaw import OmniClaw + + +app = FastAPI(title="OmniClaw B2B Vendor - Thirdweb") +client = OmniClaw() + + +@app.get("/report") +async def report( + payment=client.sell( + "$0.50", + seller_address=os.environ["SELLER_ADDRESS"], + facilitator="thirdweb", + ), +): + return { + "service": "vendor-thirdweb-report", + "paid_by": payment.payer, + "amount": payment.amount, + "report": {"status": "ready"}, + } + diff --git a/examples/business-compute/README.md b/examples/business-compute/README.md index e888cc6..e3e86e3 100644 --- a/examples/business-compute/README.md +++ b/examples/business-compute/README.md @@ -28,6 +28,24 @@ From the repo root: bash scripts/start_business_compute_demo.sh ``` +## Arc Vendor Mode + +For the shipped Arc-specific flow, use: + +```bash +bash scripts/start_arc_vendor_demo.sh +``` + +This mode is different from the older local demo in one important way: + +- the buyer is not a bundled local test button +- the buyer is your real external CLI agent, for example Telegram/OpenClaw +- the launcher deploys the buyer policy engine and seller policy engine +- the browser app acts as the vendor-facing seller surface +- `ARC-TESTNET` is the default network + +The launcher prints the buyer policy engine details you need to configure the external CLI agent. + Open in the browser: ```text @@ -98,3 +116,10 @@ This example is intentionally business-first. The business is not presented as another agent using `omniclaw-cli`. The business owns the API surface, while OmniClaw provides the payment and control layer underneath. + +In Arc vendor mode: + +- the buyer uses `omniclaw-cli` externally +- the seller is a vendor web app +- both policy engines run on `ARC-TESTNET` +- the business app shows the payment flow, deliveries, and settlement visibility diff --git a/examples/business-compute/app.py b/examples/business-compute/app.py index 795e0ad..52ae89d 100644 --- a/examples/business-compute/app.py +++ b/examples/business-compute/app.py @@ -25,6 +25,15 @@ BUYER_SERVER_URL = os.environ.get("BUYER_OMNICLAW_SERVER_URL", "http://localhost:9090") BUYER_TOKEN = os.environ.get("BUYER_OMNICLAW_TOKEN", "payment-agent-token") APP_PORT = int(os.environ.get("BUSINESS_COMPUTE_PORT", "8010")) +NETWORK_NAME = os.environ.get("BUSINESS_COMPUTE_NETWORK", "ARC-TESTNET") +EXPLORER_BASE_URL = os.environ.get( + "BUSINESS_COMPUTE_EXPLORER_BASE_URL", "https://testnet.arcscan.app" +) +ENABLE_LOCAL_BUYER = os.environ.get("BUSINESS_COMPUTE_ENABLE_LOCAL_BUYER", "false").lower() in { + "1", + "true", + "yes", +} PAPERS_DIR = Path(__file__).resolve().parent / "papers" DOWNLOAD_SIGNING_SECRET = os.environ.get( "BUSINESS_COMPUTE_DOWNLOAD_SECRET", "local-business-compute-demo-secret" @@ -42,7 +51,11 @@ def default_buyer_base_url() -> str: return f"http://{ip}:{APP_PORT}" -BUYER_BASE_URL = os.environ.get("BUSINESS_COMPUTE_BUYER_BASE_URL", default_buyer_base_url()) +PUBLIC_BASE_URL = os.environ.get( + "BUSINESS_COMPUTE_PUBLIC_BASE_URL", + os.environ.get("BUSINESS_COMPUTE_BUYER_BASE_URL", default_buyer_base_url()), +) +AGENT_BASE_URL = os.environ.get("BUSINESS_COMPUTE_AGENT_BASE_URL", default_buyer_base_url()) app = FastAPI(title="OmniClaw Business Demo") EVENTS: deque[dict[str, Any]] = deque(maxlen=120) @@ -174,7 +187,7 @@ class PaperProduct: - OmniClaw Business Demo + OmniClaw Arc Vendor Demo