Architecture State -- V1 Release

March 10, 2026 Β· View on GitHub

Project Summary

Ag402 v0.1.0 -- Payment infrastructure for the AI Agent economy. Powered by the Open402 standard.

Three-layer monorepo: open402 (protocol) + ag402-core (engine) + ag402-mcp (gateway adapter). 398 tests passing. Lint clean (ruff). E2E demo working. Security audited (P0-P2 fixed). CI/CD configured. Devnet tested (17 on-chain tests + 28 resilience tests + 4 devnet timing tests). Retry + failover integrated.

V1 Focus: 100% Python ecosystem support (generic Python agents via httpx/requests). Node.js/desktop integrations planned for V2.

Latest Changes (CLI UX Overhaul)

ag402 serve β€” Auto-starts built-in demo backend

  • Added _check_port_available() to detect backend port availability
  • If backend is not running, auto-starts a Starlette Demo API in background (returns JSON: service, message, path, params, price)
  • Runs via threading.Thread(daemon=True) with uvicorn
  • Custom request logging middleware replaces uvicorn default access logs (402β†’πŸ’°, 200β†’βœ“, 500β†’βœ—, with latency)
  • After startup, shows "buyer view" hint: ag402 pay <gateway_url>

ag402 pay β€” Full x402 negotiation visualization

  • No longer uses middleware black box β€” manually executes each protocol step
  • 6-step visual flow: β‘ Wallet setup β†’ β‘‘Send request (show 402) β†’ β‘’Receive payment challenge (chain/token/amount/address) β†’ β‘£Auto-pay (tx_hash) β†’ β‘€Retry with proof (proofβ†’200) β†’ β‘₯Settlement (elapsed time + balance change)
  • Added _print_response_body() helper: JSON pretty-print (10-line truncation), HTML/text (6-line truncation)
  • Uses open402 library: parse_www_authenticate, build_authorization, X402PaymentProof

CLI Output Polish

  • All commands use numbered steps (β‘ β‘‘β‘’β‘£β‘€) with clear labels
  • Colorized status codes, JSON pretty-printing
  • Non-JSON responses truncated with ellipsis

Three-Layer Architecture

+---------------------------------------------------+
|  ag402-mcp       HTTP gateway adapter           |
|  (adapters/mcp)     FastAPI reverse proxy + x402   |
+---------------------------------------------------+
|  ag402-core      Payment engine                 |
|  (core/)            Wallet, middleware, CLI,        |
|                     monkey-patch, proxy, runners    |
+---------------------------------------------------+
|  open402            Protocol standard              |
|  (protocol/)        Spec, headers, negotiation     |
|                     Zero dependencies              |
+---------------------------------------------------+

Package Details

Layer 1: open402 (protocol/open402/)

  • spec.py: X402PaymentChallenge, X402PaymentProof, X402ServiceDescriptor, JSON Schema. Amount validation rejects NaN/Infinity/zero/negative. Header serialization sanitizes CR/LF/quote to prevent injection.
  • headers.py: Parse/build WWW-Authenticate: x402 and Authorization: x402. Extension headers (X-Service-Hash, X-Agent-ID) parsed and passed through
  • negotiation.py: Accept-x402-Version negotiation with graceful degradation
  • Zero dependencies -- pure Python protocol types

Layer 2: ag402-core (core/ag402_core/)

Config (config.py)

  • Frozen X402Config dataclass
  • Auto-loads ~/.ag402/.env on startup (zero-config for users)
  • All budget limits configurable via environment variables with hard ceilings:
    • X402_DAILY_LIMIT (default $10, ceiling $1000)
    • X402_PER_MINUTE_LIMIT (default $2, ceiling $10)
    • X402_PER_MINUTE_COUNT (default 5, ceiling 50)
    • X402_CIRCUIT_BREAKER_THRESHOLD (default 3, ceiling 20)
    • X402_CIRCUIT_BREAKER_COOLDOWN (default 60s, ceiling 3600s)
  • RunMode enum: PRODUCTION / TEST
  • Default mode changed to TEST (v0.1.0) -- zero-config developer onboarding
  • PBE wallet encryption support via AG402_UNLOCK_PASSWORD

Env Manager (env_manager.py)

  • Zero-dependency .env file parser (handles quotes, equals in values, inline comments)
  • Robust: unparseable lines logged as warnings, never crashes
  • load_dotenv() / save_env_file() / set_env_value() / parse_env_file()
  • 30 unit tests covering edge cases

Setup Wizard (setup_wizard.py)

  • Interactive terminal UI for first-time setup
  • Role selection: consumer (buy API) / provider (sell API) / both
  • Full encryption flow even in test mode (security perception)
  • Generates ~/.ag402/.env and ~/.ag402/wallet.key
  • Auto-deposits test funds after setup

Monkey-Patch (monkey.py)

  • ag402_core.enable() / disable() / enabled() context manager
  • Patches httpx.AsyncClient.send and requests.Session.send
  • Non-402 responses pass through completely untouched (no exception swallowing)
  • Original exception stacks preserved exactly
  • Handles existing event loops via ThreadPoolExecutor + asyncio.run()
  • 11 unit tests

Forward Proxy (proxy/forward_proxy.py)

  • HTTP forward proxy on 127.0.0.1:14020
  • Intercepts 402 β†’ auto-pay β†’ retry with proof
  • HTTPS CONNECT tunnels passed through as-is (no MITM)
  • SSRF protection: Blocks CONNECT to private/loopback/link-local/reserved IPs; restricts to ports 80/443/8080/8443
  • Used by ag402 run for HTTP-level interception
  • Note: HTTPS auto-pay requires Python SDK injection (ag402.enable()), proxy mode only handles HTTP

Agent Runners (runners/)

  • base.py: AgentRunner β€” launches child process with env injection
    • sitecustomize.py + PYTHONPATH injection for Python processes (works for scripts AND interactive shells)
    • HTTP_PROXY for HTTP traffic

Friendly Errors (friendly_errors.py)

  • Wraps CLI with human-readable error messages
  • Pattern-matched errors β†’ "what went wrong" + "what to do next"
  • Raw tracebacks only shown with AG402_DEBUG=1

Wallet (wallet/)

  • agent_wallet.py: SQLite (WAL mode + 10s timeout) + asyncio.Lock. deposit/deduct/rollback/get_balance/get_daily_spend
  • models.py: Transaction dataclass
  • faucet.py: X402_MODE=test auto-deposits 100 virtual USD
  • payment_order.py: PaymentOrder + PaymentOrderStore + OrderState 6-state machine (CREATED β†’ LOCAL_DEDUCTED β†’ CHAIN_BROADCASTED β†’ DELIVERING β†’ SUCCESS / REFUNDED). Strict uni-directional transitions with SQLite persistence.

Payment (payment/)

  • base.py: BasePaymentProvider ABC + PaymentResult dataclass. verify_payment() supports expected_sender to prevent third-party tx_hash reuse. confirmation_status field distinguishes "confirmed" vs "sent" (confirmation timed out).
  • registry.py: PaymentProviderRegistry β€” lazy-loading provider resolution (auto/mock/solana/stripe-v2). Passes rpc_backup_url from config to SolanaAdapter.
  • solana_adapter.py: SolanaAdapter (real) + MockSolanaAdapter (test). Configurable confirmation_level ("confirmed"/"finalized") for chain reorg protection. Uses round() for lamport conversion to avoid float precision errors. Retry + Failover: RPC calls (get_latest_blockhash, send_transaction) are wrapped with retry_with_backoff (exponential backoff, configurable max_rpc_retries). On retry exhaustion, auto-failovers to rpc_backup_url via MultiEndpointClient. Returns confirmation_status ("confirmed" | "sent") in PaymentResult.
  • retry.py: retry_with_backoff() β€” async retry with exponential backoff (configurable max_retries, base_delay, max_delay). MultiEndpointClient β€” multi-RPC endpoint manager with sequential failover and primary reset. Both integrated into SolanaAdapter for production use.

Prepaid (prepaid/) β€” NEW in P0-1, seller-side in P0-2

  • models.py: PrepaidCredential dataclass. 5 package tiers (Starter 100c/3d β†’ Enterprise 10k c/730d). UTC-aware datetimes with _utc() backward-compat helper. HMAC-SHA256 signature covers buyer|package|expires_at (excludes remaining_calls β€” decrements locally)
  • client.py: Buyer-side JSON store at ~/.ag402/prepaid_credentials.json. Atomic write via tempfile+os.replace(). All from_dict() calls catch (KeyError, ValueError, TypeError) for corrupt-entry resilience. rollback_call() capped at original package limit to prevent reject-loop inflation
  • verifier.py (NEW in P0-2): Stateless PrepaidVerifier for seller/gateway side. 5-step: parse β†’ seller_address match β†’ expiry β†’ remaining_calls > 0 β†’ HMAC. hmac.compare_digest() for constant-time comparison. remaining_calls excluded from HMAC (buyer manages locally)
  • Prepaid fast-path in x402_middleware._try_prepaid(): 1ms local verify vs 500ms+ on-chain. check_and_deduct + rollback_call both under _payment_lock (TOCTOU + concurrent-rollback safe). 429/5xx upstream β†’ rollback (buyer gets service or refund)

Middleware (middleware/)

  • x402_middleware.py: Core loop: Intercept 402 -> parse -> budget -> prepaid fast-path -> deduct -> pay -> retry -> rollback. Prepaid path (_try_prepaid): check local credential under lock β†’ attach X-Prepaid-Credential header β†’ on seller rejection or network error, rollback under lock and fall through to on-chain. Dual-mode fallback (non-x402 402 -> Bearer API key). Replay header injection. Integrated PaymentOrder state machine for payment lifecycle tracking (CREATED β†’ LOCAL_DEDUCTED β†’ CHAIN_BROADCASTED β†’ DELIVERING β†’ SUCCESS/REFUNDED). Point-of-no-return semantics: after chain broadcast, local deductions are never rolled back. Budget-deduct lock: asyncio.Lock serializes budget check + deduct to prevent TOCTOU race.
  • budget_guard.py: Single-tx limit + per-minute limit + daily limit + circuit breaker + balance check. All configurable via env with hard ceilings.

Security (security/)

  • key_guard.py: PrivateKeyFilter logging filter + install_key_guard()
  • wallet_encryption.py: PBE encryption (PBKDF2-HMAC-SHA256 + Fernet/AES). Encrypt/decrypt private keys with user password. Docker support via env var. Atomic file write via tempfile + os.replace() to prevent crash-induced corruption.
  • rate_limiter.py: In-memory sliding-window rate limiter
  • replay_guard.py: ReplayGuard (timestamp + nonce validation, OrderedDict cache with pruning, nonce length limit, cache-full flood protection) + PersistentReplayGuard (SQLite-backed tx_hash deduplication with atomic INSERT OR IGNORE, lazy init with _ensure_db() on all public methods including prune()) + generate_replay_headers()
  • challenge_validator.py: Pre-payment challenge validation (URL, amount, address, token, trust). Uses ipaddress module for complete loopback detection (IPv4/IPv6/0.0.0.0).

Gateway (gateway/)

  • auth.py: PaymentVerifier for server-side proof validation

CLI (cli.py)

  • 19 commands: setup, init, run, env, serve, pay, prepaid, upgrade, help, status, balance, history, tx, config, info, doctor, demo, export, mcp, mcp-config, install
  • Prepaid management (NEW in P0-3): ag402 prepaid status / ag402 prepaid purge / ag402 prepaid buy <gateway_url> <package_id>
  • Interactive setup wizard: ag402 setup (role selection + encryption + budget)
  • Agent integration: ag402 run -- python agent.py
  • Config management: ag402 env show/set
  • Provider mode: ag402 serve (auto-starts built-in demo backend + custom request logging, --host 0.0.0.0 for Docker)
  • Buyer mode: ag402 pay <url> (6-step x402 negotiation visualization)
  • Production migration: ag402 upgrade
  • Beautiful help: ag402 help (categorized with usage hints)
  • Friendly errors: human-readable messages with "next step" guidance
  • Colorized output: ANSI colors with auto-detection, progress bars, dashboard layout
  • Cross-platform: macOS, Linux, Windows (respects NO_COLOR / FORCE_COLOR)

Layer 3: ag402-mcp (adapters/mcp/ag402_mcp/)

  • gateway.py: HTTP gateway adapter with CLI entry point (ag402-gateway)
  • Wraps any API with x402 payment verification
  • Prepaid fast-path (NEW in P0-2): X-Prepaid-Credential header processed before on-chain auth. Valid credential β†’ proxy immediately (1ms). Invalid/expired/depleted β†’ 402 with standard x402 challenge so buyer falls back to on-chain. Enabled via --prepaid-signing-key CLI arg or AG402_PREPAID_SIGNING_KEY env var
  • Prepaid purchase endpoints (NEW in P0-3): GET /prepaid/packages (public, 5 tiers) + POST /prepaid/purchase (verify tx_hash β†’ issue signed credential JSON). tx_hash validated [A-Za-z0-9_-]{1,128} (header injection prevention). Credential returned to buyer, not stored on seller.
  • Production mode safety: Refuses to start without real verifier when X402_MODE=production; prominent test mode warning banner
  • GET /health endpoint: Returns JSON with status, mode, uptime, and metrics counters (requests_total, payments_verified, payments_rejected, replays_rejected, challenges_issued, proxy_errors, prepaid_verified, prepaid_rejected)
  • Header whitelist: Only forwards known-safe headers (accept, content-type, user-agent, etc.) to upstream; blocks Cookie, X-Forwarded-For, Connection
  • tx_hash deduplication: Atomic INSERT OR IGNORE in persistent SQLite-backed PersistentReplayGuard (survives restarts). Eliminates TOCTOU race in concurrent requests.
  • Shared httpx client: Created/closed via lifespan, with fallback per-request client for non-lifespan usage

Developer Experience (DX) Flow

pip install ag402-core
    ↓
ag402 setup          ← Interactive wizard (role/mode/encryption/limits)
    ↓
ag402 demo           ← Live demo
    ↓
ag402 run -- python my_agent.py  ← Integrate your agent
    ↓
ag402 upgrade        ← Test β†’ production migration

No need to: read more than 10 lines of README, edit config files, or manually set environment variables.

V1 Compatibility Matrix

Agent FrameworkCompatibilityMethod
Generic Python Agentβ˜…β˜…β˜…β˜…β˜…ag402 run -- python xxx
Python SDKβ˜…β˜…β˜…β˜…β˜…ag402_core.enable() β€” two lines
LangChain / AutoGen / CrewAIβ˜…β˜…β˜…β˜…β˜…httpx/requests based, auto-compatible

Key Design Decisions

  1. Three-layer monorepo: Protocol (zero deps) -> Engine -> Adapters
  2. x402 Compatible: Standard Coinbase x402 fields + extension headers (X-Service-Hash, X-Agent-ID)
  3. Frozen Config: Immutable after startup
  4. Hard ceilings: All env-configurable limits have hardcoded upper bounds for safety
  5. Adapter pattern: BasePaymentProvider -> Solana now, Stripe/Coinbase/Lightning later
  6. Lazy loading: Heavy deps (solana-py) only imported when needed
  7. Auto-rollback: Payment or retry failure -> wallet deduction reversed
  8. Sub-wallet only: Auto-generated, never import main wallet
  9. Replay defense: Timestamp window + nonce uniqueness (server-side opt-in)
  10. Dual-mode: x402 payment OR Bearer API key fallback for non-x402 services
  11. Test-first default: New installs default to TEST mode for safe experimentation
  12. PBE encryption: Private keys encrypted at rest with PBKDF2 + AES
  13. Monkey-patch transparency: Non-402 responses pass through untouched, original exceptions preserved. Stream-safe: never reads body of non-402 responses
  14. .env zero-dependency: Custom parser (no python-dotenv), graceful on malformed lines
  15. Test mode = full encryption: Even test mode walks through encryption flow for security perception
  16. V1 Python-only focus: 100% Python ecosystem, Node.js/desktop planned for V2
  17. sitecustomize injection: Replaced PYTHONSTARTUP (interactive-only) with sitecustomize.py + PYTHONPATH for reliable script injection
  18. tx_hash anti-replay: Gateway tracks consumed tx_hashes via OrderedDict with FIFO eviction to prevent payment replay attacks
  19. SQLite WAL mode: Wallet DB uses WAL journal mode + busy_timeout for multi-process safety
  20. Thread-safe circuit breaker: BudgetGuard uses threading.Lock for class-level state
  21. serve auto-backend: ag402 serve auto-starts a built-in Starlette demo API if no backend is running on the target port
  22. pay 6-step visualization: ag402 pay manually executes each x402 protocol step with numbered output, replacing middleware black-box
  23. Custom request logging: serve uses middleware-based request logging (402πŸ’°/200βœ“/500βœ— + latency), suppressing uvicorn default access logs
  24. PaymentProviderRegistry: Dynamic provider resolution based on config mode β€” eliminates hardcoded adapter selection
  25. PaymentOrder state machine: Strict 6-state lifecycle (CREATED β†’ LOCAL_DEDUCTED β†’ CHAIN_BROADCASTED β†’ DELIVERING β†’ SUCCESS/REFUNDED). Point-of-no-return after chain broadcast ensures local deductions are never incorrectly rolled back.
  26. PersistentReplayGuard: SQLite-backed tx_hash deduplication that survives process restarts. Lazy init (_ensure_db()) on all public methods (including prune()). Demo cleanup closes persistent guard to prevent orphaned aiosqlite threads.
  27. RPC Retry + Failover: SolanaAdapter wraps critical RPC calls (get_latest_blockhash, send_transaction) with retry_with_backoff (exponential backoff). On retry exhaustion, auto-failovers to backup RPC via MultiEndpointClient. Resets to primary after successful send.
  28. confirmation_status in PaymentResult: "confirmed" = confirmed at requested level, "sent" = tx sent but confirmation timed out (may still succeed on-chain). Eliminates ambiguity when success=True but confirmation was incomplete.

V1 Security Audit (Completed)

Full security audit performed. All P0 (critical) and P1 (high) issues fixed. All P2 (medium) issues fixed. P3 (low) items deferred to V2.

P0 Fixes (Critical β€” production blockers)

IDIssueFixFile
P0-1.1verify_payment() missing sender check β€” stolen tx_hash attackAdded expected_sender param; _verify_sender() checks pre_token_balance decreasesolana_adapter.py, base.py, auth.py
P0-1.2Gateway defaults to test mode (no chain verification)Production mode raises ValueError without verifier; prominent test mode warninggateway.py
P0-1.3tx_hash dedup TOCTOU race β€” concurrent double-spendAtomic INSERT OR IGNORE + rowcount checkreplay_guard.py
P0-1.4Forward Proxy CONNECT tunnel β€” unrestricted SSRFBlock private/loopback/link-local IPs; restrict to ports 80/443/8080/8443forward_proxy.py
P0-1.5int(amount * 1e6) float truncationround(amount * 1_000_000)solana_adapter.py

P1 Fixes (High β€” pre-launch required)

IDIssueFixFile
P1-2.1amount_float accepts NaN/InfinityValidates with math.isnan/math.isinf, rejects zero/negativespec.py
P1-2.2Header injection via CR/LF in challenge fields_HEADER_UNSAFE_RE sanitization in to_header_value()spec.py
P1-2.3No password strength enforcement for wallet encryptionMinimum 8-character password enforced in encrypt_private_key()wallet_encryption.py
P1-2.4Wallet file non-atomic write β€” crash corruptiontempfile.mkstemp() + os.replace()wallet_encryption.py
P1-2.5Budget check β†’ deduct TOCTOUasyncio.Lock serializes budget_check + deductx402_middleware.py
P1-2.6No health check endpointGET /health + metrics countersgateway.py
P1-2.7No request rate limiting on GatewayIP-based sliding-window rate limiter (default 60 req/min), returns HTTP 429gateway.py

P2 Fixes (Medium β€” V1.1)

IDIssueFixFile
P2-3.1Only "confirmed" commitment β€” reorg riskConfigurable confirmation_level param ("confirmed"/"finalized")solana_adapter.py
P2-3.3Nonce cache flooding / oversized nonces_MAX_NONCE_LENGTH=128 + cache-full rejection after prunereplay_guard.py
P2-3.4Gateway forwards all headers (Cookie, X-Forwarded-For)Whitelist-only forwarding (accept, content-type, user-agent, etc.)gateway.py
P2-3.5localhost check misses ::1, 0.0.0.0, 127.x.x.x range_is_local_address() via ipaddress modulechallenge_validator.py
P2-3.6No health check or observabilityGET /health + metrics counters (requests, verified, rejected, errors)gateway.py
P2-3.7Forward Proxy zero test coverage39 tests: SSRF, ports, lifecycle, nonce flood, headers, health, localhosttest_v1_p2_security_fixes.py

P3 Items (Low β€” deferred to V2)

  • Dependency version pinning (>= β†’ == + lockfile)
  • Docker secrets / vault for password management
  • Key Guard for base64/hex-encoded private keys
  • bytearray instead of str for in-memory private keys
  • MockSolanaAdapter negative balance protection

Test Coverage

PackageTestsCoverageStatus
open402 (spec, headers, negotiation)27100%PASS
ag402-core: wallet1096%PASS
ag402-core: payment + registry1894%+PASS
ag402-core: middleware + stateful1697%PASS
ag402-core: gateway388%PASS
ag402-core: security (replay, key_guard, rate_limiter)6298%+PASS
ag402-core: payment_order (state machine)2098%PASS
ag402-core: CLI (enhanced)6175%PASS
ag402-core: env_manager3098%PASS
ag402-core: monkey-patch1190%PASS
ag402-core: budget_enhanced1295%PASS
ag402-core: decimal_precision4100%PASS
ag402-core: phase4 (integration)2290%PASS
ag402-core: solana_enhanced1094%PASS
ag402-core: solana_resilience (mock)2896%PASS
ag402-core: devnet on-chain17--PASS
ag402-core: devnet resilience + timing4--PASS
ag402-core: payment_verifier_amounts595%PASS
ag402-core: v1 security audit (P0/P1)4098%PASS
ag402-core: v1 security audit (P2)3996%PASS
ag402-mcp: adapter tests5--PASS
Total44792%+ALL PASS