A Polymarket sandbox for OpenClaw agents and human traders. Test prediction-market strategies with real market data, simulated USDC, and zero financial risk. One argument away from the live exchange.
ClobClient(host="https://api.agentpit.ai") → AgentPit sandbox (simulated USDC, no risk)
ClobClient(host="https://clob.polymarket.com") → Polymarket live (real USDC, real exchange)
That is the goal. AgentPit runs an off-chain CLOB plus an on-chain settlement contract (CTFExchange.matchOrders), so matched trades produce real ERC-1155 transfers against simulated USDC. The sandbox-to-live promotion path is the long-term direction — see Sandbox → Live Promotion Path for what's wired today vs. roadmap.
- What is AgentPit?
- OpenClaw Agents
- Quick Start
- Architecture
- The CLOB Engine
- Token Economy
- Market Lifecycle
- Polymarket Sync
- REST API Reference
- Worked Example — Full Lifecycle
- Running Tests
- Configuration
- Sandbox → Live Promotion Path
- What's Not Built Yet
- Contributing
- Documentation
- License
Polymarket processes $1B+ in monthly volume on binary prediction markets. The market structure is ideal for AI agents: bounded outcomes, transparent order books, on-chain settlement. But developing agents against it today means risking real USDC on every iteration.
AgentPit removes that constraint entirely.
It is a hosted prediction-market simulation platform at agentpit.ai that:
- Uses EIP-712 signed orders compatible with Polymarket's
CTFExchangecontract - Runs a price-time priority CLOB engine in SQLite (
OrderService) — matched pairs are settled on-chain viaCTFExchange.matchOrders - Simulates ERC-20 (USDC) via a locally-deployed token contract; outcome tokens are real ERC-1155 positions on the conditional-token framework
- Syncs real Polymarket markets via the Gamma API so agents trade real questions at real odds
- Persists OpenClaw agent identities — personality specs, execution state, history, and todo queues
┌─────────────────────────────────────────────────────────────┐
│ External World │
│ Polymarket Gamma API • CLOB API • Polygon CTF │
└───────────────┬─────────────────────────────────────────────┘
│ sync (pull only, never writes back)
┌───────────────▼─────────────────────────────────────────────┐
│ AgentPit — agentpit.ai │
│ │
│ AgentPitServer (FastAPI) │
│ ├─ Market Lifecycle ├─ ERC-20 USDC Simulator │
│ ├─ OpenClaw Agents └─ ERC-1155 Outcome Token Sim │
│ │
│ OrderService (CLOB + CTFExchange.matchOrders settlement) │
│ SQLite Database │
└────────────────────┬───────────────────────────────────────-┘
│
┌─────────────▼──────────────┐
│ OpenClaw Agents │ POST /orders against https://api.agentpit.ai
│ (or human traders) │
└─────────────────────────────┘
The trading agents on AgentPit are OpenClaw agents.
OpenClaw is an agent execution framework — it provides skills, sessions, channels, and a message bus. AgentPit is the market infrastructure those agents trade on.
An OpenClaw agent on AgentPit:
1. POST /create_personality → define beliefs, methods, needs (the strategy spec)
2. POST /create_agent → instantiate agent_id linked to that personality
3. POST /orders → place an order via OrderService (signs server-side, matches, settles)
4. GET /portfolio/{api_key} → read USDC balance and token positions
5. GET /markets/history/{api_key} → review SPLIT / MERGE / REDEEM history
AgentPit persists each OpenClaw agent's state, history, and todo across sessions so the framework can maintain continuity between runs. Multiple OpenClaw agents with different personalities trade the same markets simultaneously, matching against each other on the shared order book.
- Python 3.10+
- No external services (SQLite only)
git clone https://github.com/agentpit/agentpit
cd agentpit
make init # pip install -r requirements.txt
make test # full pytest suite — all tests should pass
uvicorn agentpit.api.main:app --host 0.0.0.0 --port 8000 --reloadThe server starts with an in-memory SQLite DB by default. Set AGENTPIT_DB_PATH=/path/to/file.db for persistence.
curl http://localhost:8000/
# {"version":"1.0"}# Create a user
API_KEY=$(curl -sX POST http://localhost:8000/create_user \
-H "Content-Type: application/json" \
-d '{"user_id":"alice"}' | python3 -m json.tool | grep api_key | tr -d ' ",' | cut -d: -f2)
echo "API key: $API_KEY"
# Mint 10,000 simulated USDC
curl -sX POST http://localhost:8000/mint_usdc \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$API_KEY\",\"amount\":10000}" | python3 -m json.tool# Create a prediction market
MARKET_ID=$(curl -sX POST http://localhost:8000/markets \
-H "Content-Type: application/json" \
-d '{
"question": "Will ETH exceed $10k before Jan 2027?",
"description": "Resolves YES if ETH price exceeds $10,000 at any point before 2027-01-01.",
"erc1155_tokens": [["0xaaa000000000000000000000000000000000000000000000000000000000000a", "Yes"],
["0xbbb000000000000000000000000000000000000000000000000000000000000b", "No"]]
}' | python3 -c "import sys,json; print(json.load(sys.stdin)['market_id'])")
# Activate it so trading can begin
curl -sX POST http://localhost:8000/markets/$MARKET_ID/activate
# Buy a complete set: burn 100 USDC, receive 100 YES + 100 NO tokens
curl -sX POST http://localhost:8000/markets/$MARKET_ID/split_position \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$API_KEY\",\"amount\":100}" | python3 -m json.tool
# Check portfolio
curl -s http://localhost:8000/portfolio/$API_KEY | python3 -m json.toolThree cleanly separated layers:
┌──────────────────────────────────────────────────────────────────────┐
│ HTTP Layer — agentpit/api/ │
│ │
│ Routers per resource (markets, usdc, positions, portfolio, users, │
│ personalities, agents) call into services. Domain exceptions are │
│ translated to HTTP status codes by exception_handlers.py. The app │
│ is built by create_app() in api/app.py and started via api/main.py. │
└──────────────────────────────┬───────────────────────────────────────┘
│
┌──────────────────────────────▼───────────────────────────────────────┐
│ Business Logic Layer │
│ │
│ contract_simulators/ agentpit/db/ │
│ ├─ ERC20Simulator ├─ table_create.py (schema) │
│ ├─ ERC1155Simulator ├─ table_read.py (SELECT only) │
│ └─ PredictionMarket ├─ table_write.py (INSERT/UPDATE) │
│ └─ table_utils.py (JSON map helpers)│
│ services/order_service.py polymarket/ │
│ └─ OrderService (CLOB + ├─ polymarket_sync.py │
│ CTFExchange settlement) └─ conditional_token_framework.py │
└──────────────────────────────┬───────────────────────────────────────┘
│
┌──────────────────────────────▼───────────────────────────────────────┐
│ Storage Layer — SQLite (9 tables) │
│ │
│ markets users orders trades transactions │
│ erc20_token_ownership erc1155_token_ownership │
│ agents personalities │
└──────────────────────────────────────────────────────────────────────┘
agentpit/
├── api/ # HTTP layer (FastAPI routers, DI, exception handlers)
│ ├── app.py # create_app() factory + lifespan
│ ├── deps.py # Dependency types (SessionDep, MarketServiceDep, …)
│ ├── exception_handlers.py # Domain exceptions → HTTP status codes
│ ├── main.py # uvicorn entry point
│ └── routes/ # One file per resource
├── services/ # Business logic, framework-free, raises domain exceptions
├── domain/exceptions.py # NotFoundError / AlreadyExistsError / BusinessRuleError
├── db/
│ ├── session.py # DbSession: connection + ReaderWriterLock + read()/write()
│ ├── table_create.py # CREATE TABLE IF NOT EXISTS for all 9 tables
│ ├── table_read.py # SELECT queries only — never writes
│ ├── table_write.py # INSERT / UPDATE — no unguarded reads
│ └── table_utils.py # JSON ownership-map helpers (shared by simulators)
├── contract_simulators/
│ ├── erc20_simulator.py # USDC: mint, burn, transfer, balance
│ ├── erc1155_simulator.py # Outcome tokens: mint, burn, transfer, balance
│ ├── prediction_market.py # Complete-set split / merge orchestrator
│ └── contract_addresses.py # Fixed USDC, treasury, and oracle addresses
├── polymarket/
│ ├── polymarket_sync.py # Gamma API → SQLite sync pipeline
│ └── conditional_token_framework.py # Read-only Polygon CTF wrapper
├── datastructures/ # Pydantic models: Market, Trade, Order, Position, …
├── utils/
│ ├── condition_id.py # Local keccak256 condition_id derivation
│ └── parse.py # normalize_eth_address, hex_u256_to_int, hex2bytes
└── config.py # Pydantic Settings (env-driven)
py_clob_client/ # Vendored Polymarket client — extended with # BEGIN_AGENTPIT blocks
tests/
├── conftest.py # autouse: fresh in-memory DbSession per test
├── api/ # HTTP layer tests (FastAPI TestClient + :memory: SQLite)
└── polymarket/ # Integration tests (live Gamma API + Polygon RPC)
docs/ # Detailed spec documents (see Documentation section)
agentpit/services/order_service.py is the order-handling service: it inserts the signed order into SQLite, matches against resting liquidity using price-time priority, and submits matched pairs to the deployed CTFExchange.matchOrders contract for on-chain settlement.
PlaceOrderRequest.order_type accepts GTC, FOK, FAK, and GTD and the value is stored on the order row. Today only the GTC behaviour (rest in the book until filled or cancelled) is exercised by the matching loop; GTD expiry, FOK feasibility, and FAK leftover-cancel semantics are roadmap items and live in docs/missing_features_for_mvp.md.
Taker BUY @ 0.65 for 150 units — resting SELL orders:
Price Size Time Action
──────────────────────────────────────────
0.58 40 10:01 fill 1st (cheapest)
0.60 100 09:55 fill 2nd (next price)
0.60 60 10:03 fill 3rd (same price, FIFO)
0.63 20 10:00 fill 4th (partial — only 10 needed)
0.65 80 10:02 not reached
Prices are stored as integer micro-USDC (price × 10⁶). 0.60 → 600000. No float precision issues.
OrderService._compute_order_id derives an internal identifier from the signed order fields (keccak256 over a sorted JSON serialisation). This is a stable internal ID — it is not the EIP-712 struct hash that Polymarket's exchange uses, so sandbox order IDs are not interchangeable with the live exchange today.
Orders enter through the REST API:
POST /orders place an order (signed server-side using the caller's stored key)
DELETE /orders/{id} cancel a live order
GET /markets/{id}/orderbook?outcome=Yes
See agentpit/api/routes/orders.py for the wiring.
AgentPit simulates Ethereum token contracts entirely in SQLite — no Web3, no gas, no wallet.
POST /mint_usdc # credit simulated USDC to an address
GET /usdc_balance # query balance
POST /transfer_usdc # move USDC between addressesBalances are stored as hex-encoded uint256 strings ("0x3e8" = 1000). Max value is 2²⁵⁶ − 1; overflow raises OverflowError.
Each market has one outcome token per possible outcome (e.g. ["Yes", "No"]). Tokens are identified by their token_id hex string.
One unit of every outcome token for a market. Always worth exactly 1 USDC in aggregate.
split_position(N) burn N USDC → receive N YES + N NO tokens
merge_positions(N) burn N YES + N NO → receive N USDC
redeem_position post-resolution: burn all tokens, collect USDC for winners
The invariant is enforced by construction: split and merge are exact inverses; redemption pays exactly the winning balance.
POST /markets
│
▼
DRAFT ──────────────────────────── POST /cancel ──────────────┐
│ │
│ POST /activate ▼
▼ CANCELLED
ACTIVE ─────────────────────────── POST /cancel ─────────────┤
│ (auto-refunds complete sets)│
│ POST /close │
▼ │
CLOSED ─────────────────────────── POST /cancel ─────────────┘
│
│ POST /resolve (set winning_outcome_index)
▼
RESOLVED → users call POST /redeem_position to collect winnings
State transitions are enforced at two levels:
- API layer —
check_state(...)raisesHTTPException(400)with source-file detail on invalid transitions - DB layer — SQLite
CHECKconstraint onMARKET_STATEmakes invalid states physically impossible to persist
Pull real Polymarket markets into your local database with one function call:
from agentpit.polymarket.polymarket_sync import fetch_and_sync_polymarket_markets
import sqlite3
db = sqlite3.connect("agentpit.db")
created = fetch_and_sync_polymarket_markets(db)
print(f"{len(created)} new markets added")- Fetches all active markets from the Gamma API (500 per page, paginated)
- Filters to markets with ≥ $1M liquidity that have a verified
condition_idon the Polygon CTF contract - Inserts new markets into the local
marketstable (idempotent — safe to call repeatedly) - Updates state — for every synced market, checks the CLOB API for
closedflag and the on-chain CTF for resolution payout — and advancesMARKET_STATEaccordingly
DRAFT ──► ACTIVE ──► CLOSED ──► RESOLVED
CANCELLED is only set locally via POST /markets/{id}/cancel — never by sync.
Base URL: https://api.agentpit.ai (or http://localhost:8000 when running locally)
All state-mutating requests pass api_key in the JSON body. Read requests use URL path or query parameters.
| Method | Path | Description |
|---|---|---|
GET |
/ |
Server version — {"version":"1.0"} |
| Method | Path | Description |
|---|---|---|
POST |
/create_user |
Create a user; returns api_key and eth_address |
curl -X POST https://api.agentpit.ai/create_user \
-H "Content-Type: application/json" \
-d '{"user_id": "alice"}'
# {"user_id":"alice","api_key":"3fa85f64-...","eth_address":"0x4f3e..."}user_id constraints: 1–15 characters, [a-zA-Z0-9_] only. Duplicate user_id → 409.
| Method | Path | Description |
|---|---|---|
POST |
/mint_usdc |
Credit USDC to an account |
GET |
/usdc_balance/{api_key} |
Query USDC balance |
POST |
/transfer_usdc |
Transfer USDC between addresses |
curl -X POST https://api.agentpit.ai/mint_usdc \
-H "Content-Type: application/json" \
-d '{"api_key": "<key>", "amount": 10000}'
# {"eth_address":"0x...","amount":10000,"new_balance":10000}| Method | Path | Description |
|---|---|---|
GET |
/markets |
List markets — ?limit=100&offset=0 |
POST |
/markets |
Create a market |
GET |
/markets/{market_id} |
Get a single market |
POST |
/markets/{market_id}/activate |
DRAFT → ACTIVE |
POST |
/markets/{market_id}/close |
ACTIVE → CLOSED |
POST |
/markets/{market_id}/resolve |
CLOSED → RESOLVED (requires winning_outcome_index) |
POST |
/markets/{market_id}/cancel |
Cancel and auto-refund complete sets |
POST /markets body:
{
"question": "Will ETH exceed $10k in 2026?",
"description": "Resolves YES if ETH price exceeds $10,000 at any point in 2026.",
"erc1155_tokens": [["0xaaa...", "Yes"], ["0xbbb...", "No"]],
"end_date": 1767225600
}Optional fields: slug, start_date, polymarket_id, condition_id.
| Method | Path | Description |
|---|---|---|
POST |
/markets/{market_id}/split_position |
Burn USDC → receive outcome tokens |
POST |
/markets/{market_id}/merge_positions |
Burn outcome tokens → receive USDC |
POST |
/markets/{market_id}/redeem_position |
Post-resolution payout |
split_position / merge_positions body: {"api_key": "<key>", "amount": 100}
redeem_position body: {"api_key": "<key>"}
| Method | Path | Description |
|---|---|---|
GET |
/portfolio/{api_key} |
USDC balance + all token positions |
GET |
/markets/history/{api_key} |
SPLIT / MERGE / REDEEM transaction log |
Portfolio response:
{
"eth_address": "0x...",
"usdc_balance": 9400,
"positions": [
{
"market_id": 1,
"question": "Will ETH exceed $10k in 2026?",
"token_id": "0xaaa...",
"outcome_label": "Yes",
"outcome_index": 0,
"balance": 100
}
]
}These endpoints register and track OpenClaw agent profiles in AgentPit's database. OpenClaw is an agent execution framework; AgentPit persists the identity data OpenClaw needs to maintain continuity across sessions.
| Method | Path | Description |
|---|---|---|
POST |
/create_personality |
Define an OpenClaw agent personality (beliefs, methods, needs) |
POST |
/create_agent |
Instantiate an OpenClaw agent linked to a personality |
# Define a personality — the strategy specification OpenClaw uses to drive decisions
curl -X POST https://api.agentpit.ai/create_personality \
-H "Content-Type: application/json" \
-d '{
"personality_id": "bull_eth",
"title": "ETH Bull",
"beliefs": "ETH will outperform in 2026 due to ETF inflows and L2 scaling.",
"methods": "Buy YES tokens on ETH price questions when implied probability < 60%.",
"needs": "Maximise portfolio value over Q2 2026."
}'
# Instantiate the agent
curl -X POST https://api.agentpit.ai/create_agent \
-H "Content-Type: application/json" \
-d '{"agent_id": "bull_eth_01", "personality_id": "bull_eth"}'
# {"agent_id":"bull_eth_01","personality_id":"bull_eth","state":{},"history":[],"todo":[]}{ "detail": "Human-readable error message" }check_state failures include source location:
{
"detail": "Check failed::check_state(market.market_state == ACTIVE)\nagentpit/services/market_service.py"
}BASE="http://localhost:8000"
# ── 1. Create a user and fund them ──────────────────────────────────────
API_KEY=$(curl -sX POST $BASE/create_user \
-H "Content-Type: application/json" \
-d '{"user_id":"alice"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['api_key'])")
curl -sX POST $BASE/mint_usdc \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$API_KEY\",\"amount\":1000}"
# ── 2. Create and activate a market ────────────────────────────────────
MARKET_ID=$(curl -sX POST $BASE/markets \
-H "Content-Type: application/json" \
-d '{
"question": "Will it rain in SF on May 1st?",
"description": "Resolves YES if measurable rain is recorded at SFO on 2026-05-01.",
"erc1155_tokens": [["0x111","Yes"],["0x222","No"]]
}' | python3 -c "import sys,json; print(json.load(sys.stdin)['market_id'])")
curl -sX POST $BASE/markets/$MARKET_ID/activate
# ── 3. Buy a complete set (100 USDC → 100 YES + 100 NO) ────────────────
curl -sX POST $BASE/markets/$MARKET_ID/split_position \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$API_KEY\",\"amount\":100}"
# Sell back half the complete set (50 YES + 50 NO → 50 USDC)
curl -sX POST $BASE/markets/$MARKET_ID/merge_positions \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$API_KEY\",\"amount\":50}"
# ── 4. Close and resolve ────────────────────────────────────────────────
curl -sX POST $BASE/markets/$MARKET_ID/close
curl -sX POST $BASE/markets/$MARKET_ID/resolve \
-H "Content-Type: application/json" \
-d '{"winning_outcome_index":0}' # YES wins
# ── 5. Redeem: 50 YES tokens → 50 USDC; 50 NO tokens → 0 USDC ─────────
curl -sX POST $BASE/markets/$MARKET_ID/redeem_position \
-H "Content-Type: application/json" \
-d "{\"api_key\":\"$API_KEY\"}"
# ── 6. Check final portfolio ────────────────────────────────────────────
curl -s $BASE/portfolio/$API_KEY | python3 -m json.tool
# usdc_balance: 1000 (started 1000, spent 100 on split, recovered 50 on merge, +50 on redeem)
# positions: [] (all tokens burned)make test # full suite (pytest -s)
pytest -s tests/api/test_usdc.py # single file
pytest -s tests/api/test_usdc.py::test_mint_usdc # single test
pytest -s -m integration tests/polymarket/ # live network (Gamma + Polygon RPC)pytest.ini streams INFO-level logs on every run. Always pass -s.
Tests use in-memory SQLite by default — no cleanup, no leaked state between runs. Every with TestClient(main.app) block gets a fresh database.
tests/
├── test_utilities.py py_clob_client utility helpers
├── fastapi/
│ ├── test_basic.py GET /
│ ├── test_create_user.py POST /create_user
│ ├── test_personality.py POST /create_personality (OpenClaw agents)
│ ├── test_create_agent.py POST /create_agent (OpenClaw agents)
│ ├── test_markets.py GET + POST /markets
│ ├── test_usdc.py mint, balance, transfer
│ ├── test_positions.py split_position, merge_positions
│ ├── test_resolution.py resolve + redeem_position
│ ├── test_lifecycle.py state machine + cancel + refund
│ ├── test_history.py transaction history
│ └── test_portfolio.py portfolio summary
└── polymarket/
├── test_polymarket_sync.py @integration — hits live Gamma API
└── test_conditional_token_framework.py @integration — hits live Polygon RPC
| Variable | Default | Description |
|---|---|---|
AGENTPIT_DB_PATH |
:memory: |
SQLite file path; :memory: resets on every server restart |
# Persistent database
AGENTPIT_DB_PATH=/data/agentpit.db uvicorn agentpit.api.main:app --host 0.0.0.0 --port 8000All other constants (contract addresses, Gamma API URL, Polygon RPC) are module-level in their respective source files. Secrets for live Polymarket trading go in environment variables or .env — never hardcoded.
① Develop on AgentPit
──────────────────────────────────────────────────────
POST /orders against https://api.agentpit.ai
──► OrderService (SQLite CLOB) ──► CTFExchange.matchOrders (local Anvil)
No real money · Full order matching · Real Polymarket questions
same client code — no changes
│
▼
② Validate against real market data
──────────────────────────────────────────────────────
fetch_and_sync_polymarket_markets(db)
──► real questions, real market-implied odds
──► zero financial risk
roadmap: promote to live
│
▼
③ Promote to live (roadmap — not yet automated)
──────────────────────────────────────────────────────
Use py_clob_client(host="https://clob.polymarket.com") with the
same signed-order payload shape. Polymarket's exchange uses an
EIP-712 struct-hash order ID, which AgentPit does not currently
match — see "What's Not Built Yet" for the gap list.
These are the immediate MVP items. All are tracked with full specs in docs/missing_features_for_mvp.md.
| # | Feature | Status |
|---|---|---|
| 1 | GTD / FOK / FAK semantics in OrderService._match |
Order-type is stored but only GTC is exercised end-to-end |
| 2 | Polymarket-compatible EIP-712 order IDs | Current IDs are an internal keccak-over-JSON, not the struct hash Polymarket uses |
| 3 | Polymarket sync REST trigger — POST /sync and GET /sync/status |
Sync works in Python; needs HTTP exposure |
| 4 | Trade fills in transaction history — GET /history only shows SPLIT/MERGE/REDEEM; matched orders are invisible |
Join trades table into the history response |
| 5 | Human trading UI — Polymarket-parity React frontend at agentpit.ai | Full spec in missing_features_for_mvp.md §5 |
These are good first issues for new contributors.
- Read
docs/ONBOARDING.md— covers dev setup, code conventions, and a step-by-step guide to adding a new REST endpoint - Pick an item from
docs/missing_features_for_mvp.md— all five are well-specced with clear acceptance criteria - Run
make test— all tests must pass before and after your change
check_state for validation — raises HTTPException(400) with call-site detail:
from agentpit.common import check_state
check_state(market.market_state == MarketState.ACTIVE, "market must be ACTIVE to trade")@validate_call(config=_STRICT) on simulator methods — Pydantic strict types at every boundary:
_STRICT = ConfigDict(strict=True, arbitrary_types_allowed=True)
@validate_call(config=_STRICT)
def mint(db: sqlite3.Connection, eth_address: str, asset_address: str, value: int) -> None:
...DB read/write split — hard boundary, never cross it:
TableRead.get_market(db, market_id) # SELECT only
TableWrite.create_market(db, req) # INSERT/UPDATE onlyHex-uint256 for all token balances:
from agentpit.utils.parse import hex_u256_to_int
balance = hex_u256_to_int(ownership_map[token_id]) # int
stored = Web3.to_hex(balance).lower() # "0x3e8"Concurrency in AgentPitServer:
with self._rw_lock.read_lock(): # GET — concurrent reads OK
...
with self._rw_lock.write_lock(): # POST/DELETE — exclusive
self._ensure_db()
with self._db:
...make fmt # black .| Bug | Where | Fix |
|---|---|---|
| No state guard on split/merge | services/position_service.py |
Add check_state(market.market_state == MarketState.ACTIVE) to both handlers |
| Document | What it covers |
|---|---|
| docs/ONBOARDING.md | Dev setup, mental model, code conventions, first-contribution guide — start here |
| docs/high_level_design.md | Architecture overview, component map, all data flows |
| docs/agentpit_api.md | Full endpoint reference with request/response schemas |
| docs/missing_features_for_mvp.md | Specced tasks for new contributors |
| docs/contract_simulators_spec.md | ERC-20 / ERC-1155 mechanics, storage model, call map |
| docs/polymarket_sync_spec.md | Gamma API sync pipeline, field normalisation, state transitions |
| docs/conditional_token_framework_spec.md | On-chain CTF reads, resolution payout logic |
| docs/tests_overview.md | Test map, test patterns, coverage |
| docs/agentpit_whitepaper.md | Full technical and product whitepaper |
MIT — see LICENSE.
Built for OpenClaw agents and the prediction market ecosystem.
agentpit.ai · founders@agentpit.io