Skip to content

leeoxiang/agentos

Repository files navigation

AgentOS

AgentOS

AgentOS

The wallet your agents actually operate.

Every AI agent has the same bug: it can do the work, but it can't pay for anything. AgentOS fixes that — x402 payments settled in USDG, tokenized stocks on Robinhood Chain, and five autonomous agents trading against each other live, right now.


Live site X npm

Chain Settlement Protocol Next.js License


Watch it live · Give your agent a wallet · The arena · Build on it


The problem

Your agent can write code, plan a trip, analyse a portfolio. Then it hits an API that costs two cents and stops — waiting for a human with a credit card.

The web's payment layer assumes a person. Agents don't have hands.

The fix

HTTP has had a status code reserved for this since 1997 and nobody could use it, because money didn't move like data. Now it does.

GET /api/x402/quote?symbol=NVDA
  → 402  { accepts: [{ scheme: "exact", asset: USDG, maxAmountRequired: "1000", … }] }

  agent signs TransferWithAuthorization         (a signature — no gas, no broadcast)

GET /api/x402/quote?symbol=NVDA   X-PAYMENT: base64(envelope)
  → 200  { symbol: "NVDA", price: 213.47, … }   X-PAYMENT-RESPONSE: base64(receipt)

One round trip. No card, no checkout, no human.


Give your agent a wallet

claude mcp add agentos -- npx -y agentos-mcp

Works in Claude Code, Claude Desktop, Cursor — anything speaking the Model Context Protocol. Runs with zero configuration; a private key is only needed for the paid tools. The host model never sees it.

Manual config — claude_desktop_config.json / .cursor/mcp.json
{
  "mcpServers": {
    "agentos": {
      "command": "npx",
      "args": ["-y", "agentos-mcp"],
      "env": {
        "AGENTOS_PRIVATE_KEY": "0x...",
        "AGENTOS_MAX_PAYMENT_USDG": "0.10"
      }
    }
  }
}

Tools your agent gets

Tool Price Returns
agentos_status free Its own address, caps, and what it's allowed to do
agentos_market free Live prices and pool depth
agentos_portfolio free Any wallet's gas, cash, vault position and stock book
agentos_vault free ERC-4626 vault state
agentos_quote 0.001 USDG Routed price, pool, fee tier, depth for one ticker
agentos_screen 0.01 USDG Every tradable ticker ranked by depth
agentos_route_order 0.02 USDG Submit-ready SwapRouter02 calldata
agentos_research 0.05 USDG Written brief grounded in live pool state
agentos_submit_order gated Broadcasts a trade. Off unless the operator enables it.

Every paid result carries an _x402 receipt — price, recipient, nonce, settlement status — so an agent's spend is visible in the transcript rather than buried in a log.


The arena

Five agents. One market. Five incompatible theses. A round fires every minute, whether anyone is watching or not.

Agent Style Reads News
🟠 Momo Trend follower Fast SMA over slow — never argues with the tape +0.8
🟢 Vega Mean reversion Fades the extremes; buys the bottom of the range −0.6
🟡 Byte Breakout hunter Sits flat through chop, commits when price clears the high +0.5
🔵 Nova Liquidity seeker Depth first, direction second — only trades what it can exit +0.15
🟣 Zen Volatility patient Does nothing, expensively well, until vol says otherwise +0.45

Every round, each agent:

  1. Pays for its own market data over x402 — a real EIP-3009 signature, verified against USDG's on-chain authorizationState, then broadcast by a facilitator. Real USDG moves.
  2. Reads the same headlines — live web search, source-linked, under 72 hours old.
  3. Decides from real prices rebuilt from Uniswap V3 Swap events.
  4. Trades, marked to live pool prices and charged the pool's actual fee tier.
  5. Talks — commentary in its own voice, about decisions it actually made.

The news column is why they disagree: Momo leans into a catalyst that Vega fades. A headline contradicting a signal strongly enough cancels the trade outright.

You can play too. Connect a wallet at agentos.markets, get the same 1,000 USDG book, and take them on. Read-only — no signature, nothing spent.


What's actually real

Everything runs against Robinhood Chain mainnet (4663). No mocks, no fixtures, no simulated tape.

Prices Rebuilt from on-chain Swap events, not an oracle — why
Universe Ranked by traded USDG volume, not depth. Only tickers with real counterparties.
Payments EIP-3009 signatures verified and settled on-chain. Clickable on Blockscout.
Routing Uniswap V3 SwapRouter02, deepest pool, slippage-bounded amountOutMinimum
Yield Steakhouse USDG — a real ERC-4626 vault holding ~170M USDG
News Live web search with enforced recency, source URLs, and a verification gate

Why not the TWAP oracle?

The obvious source for price history is the pool's own oracle. It's unusable here, and finding out why changed the architecture.

Uniswap V3 pools ship with observationCardinality = 1 unless someone pays to grow the ring buffer — and nobody has on this chain. So observe() reverts on NVDA, which does 877 swaps an hour, while happily returning an hour of history for AAPL, which nobody trades. History where there's no volume, and no history where there is.

Swap events carry sqrtPriceX96 on every fill. Replaying them gives a real, trade-by-trade series for exactly the pools with flow — plus the USDG volume alongside it, which is the honest measure of whether a ticker trades at all.

Depth is not volume. AAPL holds liquidity it never uses.


Build on it

Put a paywall in front of anything

import { requirePayment, withReceipt } from "@/lib/x402/server";

export async function GET(req: Request) {
  const gate = await requirePayment(req, {
    id: "my.endpoint",
    path: "/api/my-endpoint",
    priceUsdg: 0.005,
    description: "Whatever you're selling",
  });
  if (!gate.paid) return gate.response;   // 402 + machine-readable terms

  return withReceipt({ data: "the goods" }, gate);
}

Verification is six checks, cheapest first: scheme match, terms match, freshness, signature recovery, on-chain nonce unused, payer solvent. Replay protection lives on-chain in USDG's authorizationState map, so a captured envelope can never settle twice.

Add an agent to the arena

Every agent is a pure function from market view to decision. Drop an object into lib/arena/agents.ts and it gets a wallet, an x402 budget, news, and a leaderboard slot automatically.

{
  id: "yours",
  name: "Yours",
  color: "#7aa2f7",
  aggression: 0.4,          // fraction of bankroll at full conviction
  takeProfitMult: 3.0,      // multiples of realised volatility
  stopLossMult: 1.5,
  newsWeight: 0.6,          // −1 fades headlines, +1 chases them

  decide({ price, candles, depthUsdg, sentiment, headline }, holding) {
    const fast = sma(candles, 4);
    const slow = sma(candles, 12);
    if (fast === null || slow === null)
      return { action: "hold", conviction: 0, rationale: "warming up", readout: {} };

    const spreadBps = ((fast - slow) / slow) * 10_000;
    if (spreadBps > 3 && !holding)
      return {
        action: "buy",
        conviction: Math.min(1, spreadBps / 25),
        rationale: `trend up ${spreadBps.toFixed(1)}bps`,
        readout: { spreadBps },
      };

    return { action: "hold", conviction: 0, rationale: "no edge", readout: { spreadBps } };
  },
}

Embed the live leaderboard

<iframe src="https://agentos.markets/embed" width="440" height="280" frameborder="0"></iframe>

Tech stack

Layer Choice Why
Framework Next.js 15 · React 19 · App Router Streaming route handlers for the agent console
Language TypeScript, strict Money paths deserve a type checker
Chain viem 2 · wagmi 2 Typed ABIs, batched multicall reads
Styling Tailwind 4 (@theme) Design tokens in CSS, no config file
State Upstash / Vercel KV Durable across serverless cold starts
Model Claude Opus 4.8 Tool use, adaptive thinking, server-side web search
Protocol MCP SDK 1.29 The published agentos-mcp package
Tests Vitest 21 tests against live chain state

Repository layout

app/
  page.tsx              The arena — five agents competing, live
  console/              LLM console with streamed tool use
  agent/[id]/           Per-agent record: every decision, every trade
  wallet/ pay/ swap/    Balances · x402 handshake · Uniswap V3
  earn/ trader/         ERC-4626 vault · single-agent trader
  build/ docs/          Integration guides
  embed/                Iframe-able leaderboard
  api/x402/             402-gated endpoints + service discovery
  api/arena/            Rounds, players, news
  api/health/           Liveness — 503 when degraded

lib/
  chain.ts              Chain config, contract addresses, EIP-712 domain
  market.ts             Pool discovery, V3 price math, impact estimation
  volume.ts             Price series + traded volume from Swap events
  order.ts              Routing and calldata construction
  ratelimit.ts          Fail-closed limiting on metered routes
  kv.ts                 Durable KV with in-memory fallback
  x402/                 types · server (paywall) · facilitator · client
  arena/                agents · engine · news · players · wallets · store

packages/mcp/           The published npm package
test/                   Money-path tests

Run it locally

git clone https://github.com/ArchieHowell/AgentOS.git
cd AgentOS && npm install
cp .env.example .env.local
npm run dev

Every read works with no configuration — market data, balances, quotes and vault state come straight off mainnet.

Variable Needed for
NEXT_PUBLIC_PAY_TO Receiving x402 payments. Without it, metered endpoints 402 with a config error.
ANTHROPIC_API_KEY Console agent, agent commentary, news search
KV_REST_API_URL + KV_REST_API_TOKEN Durable state. Without it, per-instance and resets on cold start.
CRON_SECRET The arena cron. GET /api/arena/tick refuses unauthenticated requests.
FACILITATOR_PRIVATE_KEY Broadcasting settlements so payments are gasless for agents
ARENA_SEED Deriving agent wallets. The default seed is public — set your own before funding.
LIVE_TRADING Agents place real swaps instead of paper fills. Capped by MAX_LIVE_TRADE_USDG.
npm test          # price math, order construction, payment verification, book accounting
npm run build

Contracts

Address
USDG (Global Dollar) 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
steakUSDG (ERC-4626) 0xBeEff033F34C046626B8D0A041844C5d1A5409dd
SwapRouter02 0xCaf681a66D020601342297493863E78C959E5cb2
UniswapV3Factory 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA

RPC https://rpc.mainnet.chain.robinhood.com · Explorer robinhoodchain.blockscout.com

USDG's EIP-712 domain version is "1" — the token doesn't expose version(), so it was recovered by matching the on-chain DOMAIN_SEPARATOR. Get it wrong and every signature silently fails to recover.


Security model

The agent gets wallet capabilities, not wallet ownership.

  • AgentOS never custodies funds. It quotes, routes, and returns unsigned calldata. The signature always comes from a key the user controls.
  • Spend caps are enforced before signing, not after. A cap checked on the response is not a cap.
  • Payment is retried exactly once. A second 402 means the terms changed or settlement failed; silently re-signing there is how an agent drains its own wallet.
  • Routing and submitting are different tools. Broadcasting is separately gated, marked destructiveHint, and capped independently.
  • Metered routes fail closed. If the rate-limit store is unreachable they refuse rather than leaving an LLM endpoint uncapped.

License

MIT

About

Wallet for agents on Robinhood Chain — x402 payments in USDG, tokenized-stock swaps, DeFi yield, autonomous trading

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors