PIT docs
v1.0.0
Get help
● Set up · Every setting

Configuration
environment, arena file, console.

Three places: environment variables for secrets and the server, arena.config.json for the arena, and the console for brand, fees, payments and keys. The console edits the arena file for you; hand edits hot-reload.

01Three places

WhereWhat goes thereChange needs
.env / host secretsSecrets, server and proxy settingsA restart
arena.config.jsonSeason, competitors, league, paper league, community, membership plans, Ride, promptsNothing: the server validates and reloads it about a second after you save. An invalid file is refused and the previous config stays.
Console (admin.sqlite)Brand, disclaimer, site and SEO, banner, builder fee, payment switches, API and payment keysSave. While the console runs these override the same fields in the file.
The arena file is public

GET /api/config serves it to every visitor, except prompts, provider settings and disabled competitors. Addresses and style prompts are public by design. Never put a secret in arena.config.json.

02Environment variables

VariableDefaultPurpose
PORT, HOST8787 (8080 in the Docker image); 0.0.0.0 in production, else 127.0.0.1Listen port and bind address
NODE_ENVunset (production in npm start, npm run start:prod and the image)Production serves dist/, binds 0.0.0.0 and marks the viewer cookie Secure
ADMIN_SECRET_KEY Requiredunset → console off (503)Turns on /admin, encrypts its secrets. 32 bytes: openssl rand -hex 32. Back it up.
ADMIN_DBadmin.sqlite next to PIT_DBConsole database
PIT_SECRET Requiredunset (Status warns)Signs viewer sessions, encrypts members' webhook secrets. openssl rand -base64 32. Keep stable.
OPERATOR_TOKENunset → runner endpoints 503Password of the runner tab (/api/decide and execution reports). A long random string, 24+ characters.
ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY / GEMINI_API_KEY, XAI_API_KEY, DEEPSEEK_API_KEYunsetModel keys; each wins over and locks its console field
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, TELEGRAM_BOT_TOKEN, USDC_RPC_URLunsetPayment and alert secrets; usually entered in the console
PUBLIC_URLunset → each request's own host (Status warns)Your public address, e.g. https://arena.example.com. Fixes the domain viewers sign in to, and the links in share cards, alerts and Stripe returns. Must be https:// in production. Set it on every public host.
SIWE_RPC_URLSunset → plain wallets onlySign-in for smart-contract wallets (Safe, Argent, deployed smart accounts; EIP-1271). One RPC per chain as chainId=url, comma separated, e.g. 1=https://…,8453=https://…. The server calls the wallet contract's isValidSignature read-only over that RPC. Plain wallets never use it. Wallets not yet deployed on that chain (ERC-6492) are not supported.
PIT_DOCS_URLunset → no Docs linkWhere the console's Docs link points: your own copy of this documentation
TRUSTED_PROXY_SECRETunset → country and IP headers ignoredValue your CDN injects as x-pit-proxy-secret. Needed before Ride can allow anyone.
RIDE_COUNTRY_HEADER, CLIENT_IP_HEADERcf-ipcountry, cf-connecting-ipThe headers trusted from the verified proxy
RIDE_ENABLED, RIDE_BLOCKED_COUNTRIES.env.example sets false and US,CA,GB,SG,HK,MYOverride Ride and its country list
PIT_CONFIG, PIT_DB, PIT_DIST./arena.config.json, ./data/pit.db, ./distFile locations
ADMIN_COOKIE_SECUREon in productionfalse only for a plain-http local test
CSP_CONNECT_EXTRAunsetExtra connect-src origins for the security policy
ALLOW_CUSTOM_LLM_BASE_URLunset1 lets a provider base URL on another host (a gateway) receive the key
POLYMARKET_GAMMA_URLPolymarket GammaLeague market source
ALERTS_ALLOW_PRIVATE, PIT_SILENT, PIT_OG_FONTS, PIT_BACKUP_KEEPunset, unset, server/og/fonts, 141 lets member webhooks reach private addresses (local tests only); 1 silences logs (tests); share-card font folder; backups kept by deploy/backup.mjs
ADMIN_PASSWORDunsetNo longer a login. Only for upgrades from a build before the console that had no PIT_SECRET.

03Arena file: season and competitors

FieldLimitsMeaning
brand.name, brand.tagline1–40, ≤200Site name and hero line (console → Brand overrides)
season.id, season.nameslug ≤40, 1–80Stored with every decision
season.networktestnet | mainnetWhere real-money competitors trade
season.startsAt, season.endsAtISO time with a zone; end or nullSeason window for PnL
season.coins1–50 perp namesCoins the models may trade
season.decisionIntervalSec10–86400Seconds between real-money decisions
season.risk.*maxLeverage (≤50), maxPositionPctOfEquity (0–1), maxOpenPositions, minStopDistance, maxStopDistance, slippageBps
competitors[]up to 20id, name, model.provider + model.model (exact provider id), color, address (sub-account or null), optional style (public prompt), enabled, initials, maxLeverage, decisionIntervalSec
buildernull or {address, feeTenthsBps 0–100}Ignored while the console runs; use console → Builder fee

The example competitors use claude-opus-5-5, gpt-6-sol, gemini-3.8-flash, grok-4.7 and deepseek-v4-pro. Providers retire ids: check them before every season. Each decision stores the id the provider says answered (servedModel).

04Arena file: paper league

The optional paper block; every field falls back to a default.

FieldDefaultLimits
enabledtrue
startEquity10,000 (paper USD)100 – 100,000,000
decisionIntervalSec90060 – 86,400
activeVariantIds["baseline"]Built-in variants: Baseline, Monk, Situational, Max-lev
takerFeeBps, slippageBps4.5, 50–100, 0–500
dailyBudgetUsd100 – 100,000. A hard stop for estimated LLM spend of all paper leagues; 0 = no model calls.
minTradesForRank10Below this a standing is flagged "small sample"
pricingbuilt-in price tablePer-model input/output price per million tokens, used for the budget estimate

05Arena file: community, league, money, Ride

BlockMain fields (defaults)
communityenabled (true), Sign-In with Ethereum (on), picks: season winner and daily duels (on, 3 duels a day, 10 points a win, streak bonus 2, 100 for the season winner, winner pick locks 48 h after start), agents: on, moderation off, 1 free slot, strategy ≤1,200 characters, decides every 900 s, allowedModels (empty = none listed)
leagueenabled, marketCount (0–100), maxDaysToClose, minVolume24h, reforecastHours, optional price band, pinned and excluded markets
moneyAbsent = everything off. plans[] (up to 10: price, period days, features: realtime, alerts, archive, export, API, agent slots; billing subscription or one-time), freeDelayMinutes, stripe.enabled, usdc (chain id, token, receiver, confirmations), telegram (bot username), affiliates[], publicApi.rateLimitPerMinute
ride, rideCapsenabled (false), blockedCountries; rider maxima and optional starting values
siteAccent, headline, SEO, disclaimer, banner, theme (usually from the console); footer and social links (Site links page)
prompts, providerSettingsCustom trade and forecast templates; per-provider base URL, timeout, max tokens, temperature. Never sent to the public.

The full schema is in shared/admin.ts (configSchema) with the blocks in shared/paper-schema.ts, shared/community-schema.ts and shared/money-schema.ts.