● Start · Architecture
How it fits together
one process, one disk, your keys.
A one-page map of PIT: what runs in the browser, what runs on your server, what is stored on disk and which outside services it talks to. Every arrow below was checked against the code.
01The map
The short version
One Node.js process serves the web app, the API, the live stream and the console. It keeps everything on one disk. It calls AI providers with your keys, reads public market data, and never holds a trading key.
02Every arrow, with its source
| Arrow | What travels | In the code |
|---|---|---|
| Visitor ↔ server | JSON over HTTPS (/api/config, /api/decisions, paper, community, money) and one Server-Sent Events stream (/api/stream) that pushes decisions and config changes. | server/app.ts, server/stream.ts |
| Your browser ↔ /admin | The console UI and its API, mounted inside the same server. | server/app.ts (kit.handle), server/admin-kit/ |
| Server ↔ disk | pit.db: decisions, forecasts, paper accounts, community, memberships, arena config versions. admin.sqlite: console users, settings, encrypted secrets, audit log. arena.config.json: watched and hot-reloaded. | server/db.ts, server/admin-kit/index.ts, server/config.ts |
| Server → AI providers | Prompts with market data; the answer is a decision or forecast. Your key goes only to the provider's own host unless ALLOW_CUSTOM_LLM_BASE_URL=1. | server/llm/ |
| Hyperliquid → server | Public prices: an allMids WebSocket with an HTTP fallback, plus asset data and funding. No key, nothing signed. The feed follows season.network (mainnet or testnet). | server/paper/feed.ts, server/admin/hl.ts |
| Polymarket → server | Market list and prices from the Gamma API for the prediction league, every 10 minutes. | server/league/gamma.ts |
| Server ↔ Stripe | The server creates a Checkout session; Stripe calls back /api/money/webhook/stripe, signed with your webhook secret. | server/money/stripe.ts, server/money/service.ts |
| Server → alerts | Telegram bot messages (the server polls the bot with getUpdates; no inbound webhook), Discord webhooks, members' signed webhooks. | server/money/alerts.ts |
| Server → EVM RPC | Read-only calls: USDC transfer checks (USDC_RPC_URL) and smart-wallet sign-in (SIWE_RPC_URLS). | server/money/usdc.ts, server/community/eip1271.ts |
| Runner tab ↔ server | The tab sends a market and account snapshot to /api/decide; the server asks the model and answers with a decision. The tab reports what it executed and sends heartbeats. Needs OPERATOR_TOKEN. | server/app.ts, server/decide.ts |
| Browser tabs → Hyperliquid | Public reads for the ticker and real-money figures. In the runner and Ride tabs, orders signed by an agent key that exists only in that tab. | web/src/data/market.ts, web/src/hl/, web/src/ride/ |
03What this means for hosting
- One instance only. The live stream, the timers and SQLite assume one process. Two machines would run every timer twice.
- A persistent disk. Everything you would hate to lose is in
pit.db,admin.sqliteandarena.config.json(backups). - Outbound internet. The server must reach the AI providers, Hyperliquid and, for the prediction league, Polymarket (diagnose it).
- Inbound only from browsers and Stripe. Nothing else calls your server.