Arena

Changelog

Changes to the arena command line, the MCP server and tools, arena-core, the HTTP API and the website, newest first.

Docs: CLI and API. Service health: status.

    • Website: /backtesting runs a stored one-minute replay for a signed-in account. It reads Kalshi game winners, spreads, and totals in the seven leagues from the candles stored for January 2025 through September 28, 2026, decides four hours before close, fills the whole size at that minute's closing ask, and saves the run. The run shows on Design. Polymarket and Novig are not in this fill.
    • Website: the home page’s Historical data timeline was checked again against storage on October 30, 2026. Market listings, settlements, price candles and exchange trades are recorded from June 30, 2021 through September 28, 2026. Imported trades and fills stay recorded from November 2022 through March 4, 2026. Daily exchange trade files run from August 3, 2026 through October 21, 2026, with some days in October still being added. Order books and trades on the games Arena lists are recorded from September 28, 2026 and are still being recorded. None of it is offered as a download.
    • Website: the home page button reads Download for MacOS, beside the install command and again on the row of four surfaces. The signed-out Design page does not show Get the Mac app or a Mac download.
    • Packages: CLI, MCP server and MCP tools 0.6.1 and core 0.5.1 are on npm (npm install -g arena-prediction-cli, npx arena-mcp-server). Python SDK 0.3.0 is on PyPI (pip install arena-predictions). A Kalshi ticker counts as listed only when its listing's instrument is public, arena open ai kimi opens /ai/kimi, and a live buy needs a price you set yourself.
    • Website: signed out, the home page has a Download for Mac button under Get the CLI, and /design has it under Sign up and Sign in. It downloads Arena-Mac.dmg, the latest release of the Mac app, from https://downloads.arena-predictions.com in the same tab. The two lines under it read "Apple silicon, macOS 13 or newer" and "The first time, allow it in System Settings under Privacy & Security.", because the app runs only on Apple silicon and macOS stops its first open until it is allowed there.
    • Docs: /docs/cli has a Mac app section. Download Arena-Mac.dmg, open it and drag Arena to Applications, then open Arena. If macOS says it cannot check the app, open System Settings, then Privacy & Security, choose Open Anyway, then Open. The app shows a notice when a newer version is out. Both /llms.txt and /llms-full.txt name the download and what it needs.
    • Website: the Feed's Biggest trades and Biggest wins come from Signals, not from members' trades. Biggest trades lists the largest buy orders Arena recorded for Signals this month, one row per order, and Biggest wins the recorded buy orders that won and settled this month, by payout at settlement less cost, three of each. The record holds buy orders of $50,000 and up: orders on Kalshi's sports markets from the 1st, orders on its other markets only from the day Arena's server began recording them, so that month's boards miss the ones placed before it, and Polymarket orders only on a sports market Arena matches to a Kalshi one. A Kalshi order counts only the fills the Signals tape recorded, so what it cost and what it won read "at least": the order can be larger. A row names the market, the side and the order's average fill price in percent, what the order cost before fees and, for a win, what it won at settlement before fees, then "A trader on Kalshi" or "A trader on Polymarket" and the day: prints are anonymous, and a Polymarket size is rounded and marked ≈. "Since Oct 1" over the boards is now true: they start at 00:00 US Eastern on the 1st, where they counted the last 30 days. Recent trades shows the AI models' paper trades only, with their prices in percent and their side and status in coloured text with no fill.
    • Keyless routes, website and Mac app: during a game (in progress, or past its scheduled start), Novig's price shows only when Arena knows when Novig itself last updated it and that was within the last minute, and then its as_of is that time. Arena holds Novig's books over Novig's live feed, and while the feed is connected a book's age was the feed's, so on Oct 25 books from before the game showed a second old during it and the ranked list ranked them as gaps. Such a price is now left out with the note "The game is in progress, and Arena cannot confirm when Novig last updated this price, so it is hidden.", or "The game is in progress, and Novig's price is out of date, so it is hidden.". Before the game, once Arena's proxy says when Novig last updated a book, a Novig price Novig has not updated for 5 minutes is left out with "Novig's price is out of date, so it is hidden.", so it never decides the lowest price, a gap or the ranking; a quiet book Novig updated more recently still shows, and an answer from a proxy that does not say changes nothing before the game. On the market page, /ticker and /compare, a Novig price left out as out of date keeps its place and says Out of date, with no price, as a price past a minute does. ProphetX is left out once the game has started ("ProphetX fills before the game only"). On the website, a live Novig update pushed to an open page carries Novig's own update time too, so it never makes a price look newer than that, and during a game an update that does not carry it moves no price. The ranked list (/api/gaps) drops an instrument's Novig and ProphetX prices from before the game once the game starts (Novig's as out of date, unless Arena cannot date it), drops a Novig price that turns out of date while the list holds it, and is never kept, on the server or the CDN, past the moment either would happen to an item it shows; it prices up to 60 instruments a refresh, enough to keep a pool of 240 priced at once, where 40 a refresh kept at most 160, and starts no new batch once a refresh has run 5 seconds. While Arena holds Novig's prices over Novig's live feed, the list's few Novig reads a refresh go to games not started yet; games in progress are still priced from the prices Arena holds.
    • Website: on /compare, the line under each side's prices no longer says which venue is lowest or how many cents it is under the others, on a tie either. The "Lowest" and "Tied lowest" marks on the prices still show which venue is lowest. The other lines stay: a side with one price or none, prices that agree, and the sentence that a ProphetX price is from its sandbox exchange and is not compared.
    • Website: /ticker no longer says "Prices differ by N cents on YES.", and the notes under "Buying both sides" on /compare and the market page no longer say a venue has a lower price or give that price. Where the pair cannot use a venue's price for a side, the note keeps the reason alone, one sentence per venue: "A pair cannot buy both sides on Kalshi, so this pair does not buy Chiefs to win there.", "Polymarket does not accept US persons, so this pair does not buy Raiders to win there." or why that venue's pair is held back. When the reason is that venue's fee, the note says so: "Kalshi's fee for this market is why this pair does not buy Raiders to win there." A venue whose pair costs more after fees for any other reason, or only the same, gets no note. The "Lowest" and "Tied lowest" marks still show which venue is lowest, and the methodology page's Price gaps section now says the price comparisons on the market page, /compare and /ticker print no gap.
    • Website: in the price comparisons on /compare, the market page and /ticker, a price past 15 seconds is "out of date" wherever it is named: the reasons a pair cannot be bought ("Kalshi's price is out of date."), the notes under "Buying both sides", the list of every venue combination ("A price is out of date.") and the venue tile's grey dot, in its tooltip and for screen readers. They said "not current", so one card could use both words for the same price. A price past a minute is still not shown, and now no line says how old it is: on /compare its row says "Out of date" where it said "No current price" and "Kalshi's last price is more than a minute old.", a tile on the market page or /ticker says "Kalshi's price is out of date, so it is not shown." where it said "No price from Kalshi in the last minute.", and a side or pair short of prices says "No venue has a price shown for this side." or "Only Kalshi has prices shown, and buying both sides takes two venues." where it said "from the last minute". The /compare explainer no longer says each price shows how old it is.
    • Website: when a venue's price is far from Kalshi's, the reasons a pair cannot be bought on /compare and the market page say "Arena's checks say the match to Novig's market may be wrong.", as the note under "Buying both sides" does, where they said "Novig's price is more than 10 cents from Kalshi's, which often means the match is wrong.". The list of every venue combination says "Arena's match to Novig's market may be wrong." where it said "Novig's price is far from Kalshi's.", and the /compare explainer gives the reason the same way. The check itself is unchanged.
    • Website and keyless routes: a venue's note on how its contract differs from Kalshi's is printed whole up to 480 characters, and a longer one ends at its last whole sentence. Polymarket's Premier League notes were cut mid-sentence at 300 characters ("...more than 48 hours, and.").
    • Next package release (CLI, MCP server and MCP tools 0.6.1 and core 0.5.1, not on npm yet): a Kalshi ticker counts as listed only when its listing's instrument is public. For a ticker listed on an instrument that is not public, arena quotes, arena gaps, get_cross_venue_quotes and find_price_gaps answer "No Arena instrument lists the Kalshi ticker", as they do for any ticker Arena does not list, and arena open <ticker> links the ticker's own page, which needs arena login. In CLI and MCP server 0.6.0, on core 0.5.0, such a ticker resolves to that instrument's id: the answer is "No Arena instrument matches", about an id you never typed, and arena open prints a page that does not open. A game's ticker answers as before.
    • Hosted MCP server (/mcp): get_cross_venue_quotes and find_price_gaps answer "No Arena instrument lists the Kalshi ticker" for a Kalshi ticker whose listing's instrument is not public, as the next package release does. On the AI board, get_leaderboard links Kimi's row to /ai/kimi, as it links Claude's, ChatGPT's and Gemini's; it linked the trader page /u/Kimi. The hosted server lists the same tools with the same descriptions.
    • AI models: each day Claude, ChatGPT, Gemini and Kimi give a chance for every game on the slate before they see a price, and play only when the edge, pulled toward the market's price, clears the spread and a margin. A day with no play is a normal day.
    • AI models: Kimi, an AI model developed by Moonshot AI, is a public AI model on Arena beside Claude, ChatGPT and Gemini, with its own paper account and the same rules. Its page is /ai/kimi, and it has a column in the Feed's AI picks. Kimi's logo stands in for an avatar wherever the other models' logos do, with the AI tag beside its name.
    • Website: the Feed's AI picks and the pages /ai/claude, /ai/chatgpt, /ai/gemini and /ai/kimi lead with each model's scoreboard over the last 90 days: how many settled trades beat the closing price and by how much, accuracy against the market (the Brier score of the model's stated chances beside the market's own price when it bought), return per trade with its range, and plays and passes. Win rate is no longer shown, because a model wins about as often as the price it pays implies; the won and lost count stays on the model's page and says that wins track the price paid. On a day a model passes on every game it decided on, its column says "No play today: no edge cleared the bar."; on a day the model could not be reached, "No picks today: the model could not be reached."; on a day an order failed, or when the scoreboard does not say, "No picks today."; and when the picks, or a play the model made that day, did not load, "Today’s picks did not load." From midnight UTC until a model has decided on the new day's slate (the US evening and night), its column shows the day before's slate under a dated title, such as "AI picks for Oct 24", so earlier picks are never shown as today's. Picks show their price in percent.
    • HTTP API 1.15.0: new GET /me/scoreboard (portfolio:read), your own scoreboard, the numbers Arena grades its AI models on. days is 1 to 3650 (90 by default). The answer is settled, meanReturn with its 95% interval (returnCiLow, returnCiHigh), clvN, clvMeanCents, beatCloseN and beatCloseShare (trades entered before the game, with a closing line captured before it was decided), brierN, brierModel, brierMarket and brierSkill, your stated probabilities against the market's price at entry, since, and lastTradeAt, your newest standalone trade of any status, open included. Aggregates only: no per-trade row, ticker or price.
    • Next package release (CLI, not on npm yet): arena open ai kimi opens /ai/kimi, and arena open ai names kimi with claude, chatgpt and gemini. In CLI 0.6.0, arena open ai kimi exits 2 and says Arena runs claude, chatgpt and gemini; open https://arena-predictions.com/ai/kimi in a browser instead.
    • HTTP API 1.14.0: every venue on the instrument answers, while venue data is switched on for the keyed API. GET /instruments/{ref} adds venuePrices: each venue’s YES bid and ask (Kalshi, Novig, Polymarket, ProphetX) as a probability and in percent, the contracts shown, asOf, fungibility and note, and lowestAsk; it is null when the prices could not be read this time and absent while venue data is off. GET /instruments/{ref}/quotes and each answer of GET /quotes add lowestAsk: for yes and for no, the venue, price and asOf of the lowest ask among prices at most 15 s old, from venues that sell both sides, never a sandbox price. New: GET /instruments/{ref}/book, the combined order book below in the v1 shape (contracts and cumulativeContracts are null where a venue does not say its size), served only while venue data and the combined book are both switched on for keys; until then it answers 403 venue_data_off or consolidated_book_off. No field changes meaning and no route changes its status codes.
    • Keyless routes (public OpenAPI 1.4.0): GET /api/quotes/{instrumentId}/book, the combined order book. Every venue’s book for one instrument is merged into one ladder in its YES terms, and the same ladder is given seen from NO; each level has its price, its size and cumulative depth in contracts that pay $1, and the venues at it. Equal prices merge and nearby ones never do. A venue whose contract differs on some outcome (condition_scope) is listed at its level with its note and not summed, and a price more than 15 s old at its source is left out, with that reason. ProphetX’s prices come from its sandbox exchange, so they are left out of the ladder with that sentence and never decide its top. A size a venue does not give is null, never 0, and so is the cumulative depth from there down. Kalshi’s and Polymarket’s books come from Arena’s proxy, 8 and 20 levels a side, Kalshi’s in whole cents: on a Kalshi market priced finer than a cent, Kalshi adds its top of book only. Novig adds its top of book only, and the answer says so once. The answer carries the one-instrument quotes answer too, so a page reads it instead of the quotes route: one read, one unit of the same per-address budget, and with view=1 the same view slot. While Arena shows Kalshi only, the book is Kalshi’s alone.
    • Website: the order ticket, the venue prices beside it, the price comparison, the Price history chart, /compare and /ticker age each venue's price on Arena's server clock, which the page learns from the ticket's fresh=1 reads; until a tab has made one, 60 s after its last one, and in a tab that never does, they use the computer's clock. The market page's price panels and the game page's side rows show the same price as the ticket's Yes and No buttons, and a panel with no ask says Estimate. A pick kept by a review follows the cheapest price again once that review's preview expires or is confirmed; a pick the trader taps stays. When a rule of Kalshi's book keeps a picked venue's cheaper price from filling, the line under the chips says which rule.
    • Website: in the terminal's scanner, a market with no price a day ago (listed today) or no trade yet has no 24h move, rather than a move of its whole price, as the screener's own move filter and sort already read it.
    • Website: /backtesting's steps say what a rule can be today, backing the favourite or the underdog or taking every yes or no side, with your own probabilities one row per market at one size, and that the answer gives the Brier score for your own probabilities only and the edge's interval from 20 graded games, which today only markets you send reach. The /agents answer to "Can Arena backtest my strategy?" adds that your own probabilities run on the captured games or on markets you send.
    • HTTP API 1.13.0: while venue data is off, POST /backtest answers no Kalshi ticker and no price. A rule that conditions on price (minCents, maxCents, fadeMoveCents, moveWindowMinutes, side: fade_favorite), predictions that repeat a ticker and predictions of unequal contracts are refused with 400 invalid_request; favorite, underdog, yes and no rules run. A fill is instrument_id (null for a market you post), league, side, decisionAt, outcome and prob, ordered by instrument, a skip is instrument_id and reason, and feeModel gives leagueMultipliers. The summary keeps its counts, gradedGames, win rate and meanBrier; contracts, the edge and its interval, an edge verdict and the dollar figures show only from 20 graded games (distinct games with a won or lost fill), and below that they are null with a note that says why, while too_few_games and no_fills always show. GET /runs, GET /runs/{run_id} and POST /evals follow the same rule for a backtest and a predictions eval: a saved step carries no price, size, stake, fee or P&L, so the Design tab shows no P&L on such a pick, and a run saved before this change shows no money. An account eval follows GET /me/eval: no ticker, entry or exit price or contracts per pick, each pick's P&L stays, and the summary leaves out stake and fee totals as GET /me/eval does. The CLI's --json prints these answers as they come (arena backtest leaves fills out, as before), and arena runs show, arena eval and the MCP tools run_backtest, run_eval and get_run put the summary's note before their own. With venue data on, the answers are unchanged apart from graded_games, a new count in a saved run's summary.
    • Website: a market page opens on Price history. It draws Kalshi's line, from Kalshi's own price history, and a line for each other venue whose price Arena shows, when that venue's market has two outcomes, each in its venue's colour. Where the chart has no price history for a venue, its line is the prices the page has seen from that venue since it opened, so it starts when the page did. Hovering over the chart, or dragging along it on a phone, shows each charted venue's odds in percent at that moment, and No price for a venue that had none then. On a game page the chart does the same for the side picked for the ticket, a team or the draw, under a heading that names it, and picking another side redraws it.
    • Website: an order ticket's Yes and No buttons show the ask its buy button takes whenever a buy can fill on that side, on the game page as on the market page; a side with no ask shows an estimate, and the small print under the buttons says so. While a member's ticket can use another venue's price (Best price offered, another venue listing the market before the game, and the trader has not picked Kalshi alone with the chips), the page asks for that instrument's prices every 5 seconds with fresh=1, with the live price stream connected too, which the CDN never serves from its 30 second stale window: when Arena's proxy priced every venue, the copy it hands out is at most about 3 seconds old. The page asks this way only for an account Arena knows is a member: on a page just opened by one, from before the first answer; while the membership is still being checked, it asks at its own pace. Where Arena's proxy is not reading the venues' books, the ticket does not ask; while its read fails, it leaves the prices to the page's own pace until a read answers, and a page left with no prices asks again at once without fresh=1. When a rule leaves a cheaper price on the chips out of the pick, the line under them says which rule (for example, "Novig's 61¢ is at Kalshi's bid, so it can't fill."); a price too old to use is drawn muted, and the line calls it too old until the trader taps a chip on that market (asking for a review does not count), never for a venue the trader left out. GET /api/quotes/{instrumentId} takes fresh=1 once, right after view=1; fresh with any other value, twice, without view=1 right before it, or on the batch read is 400 (public OpenAPI 1.3.0).
    • Correction: /backtesting said a backtest replays each market's book to the millisecond and the exchange's own trade history with no sampling, that every game the rule touched counts, voids included, and that there is no look-ahead. A backtest replays one-minute candles, Kalshi's own or the ones you send with your markets, never Kalshi's order book or trades. A decision fills the whole size at the closing ask of the last one-minute candle that closed at or before it, and only if that candle closed within 3 minutes of the decision, on Kalshi only, with Kalshi's estimated taker fee, and the edge's interval covers the games that settled yes or no. A rule can name any of seven leagues, and a run is a sample: a run read from Kalshi reads at most the first two leagues the rule names and only markets that settled yes or no, so it holds no voids. No price comes from after a decision, but a rule's decision counts back from Kalshi's close time, which Kalshi moves when the game ends, so /backtesting and the home page's Backtesting paragraph no longer say there is no look-ahead. The home page's Backtesting section also no longer says there are no cherry-picked windows or that the markets are in seven leagues: it says a rule can name game winners in any of seven leagues and that a run is a sample, not a season. The /agents answer to "Can Arena backtest my strategy?" (and its structured data) and the /backtesting summary in /llms-full.txt now say the same. That /agents answer and the /business/sandbox answer said the CLI and the MCP server do not run a backtest: arena backtest and run_backtest, in the 0.6.0 packages on npm, run the same replay and save the run on your account. The HTTP API, the CLI and the MCP server did not change.
    • HTTP API: on a two-way game, each team's Novig outcome and ProphetX side is now a polarity 1 listing on that team's own moneyline instrument, as Polymarket's team tokens are; until now both sat on the home team's instrument, the away side at -1. Every instrument answer (GET /instruments, /instruments/{ref}, /instruments/search, /games/{ref}) now names novig and prophetx in the away team's venues where they list the game and Arena shows other venues. While venue data is on for keys, the away team's quotes (GET /instruments/{ref}/quotes, GET /quotes) carry them too, and in GET /instruments/{ref} their side moves from the home team's buyForNo to the away team's buyForYes. No route or field was added or removed.
    • Website: on a two-way game, the away team's card and market page show Novig's and ProphetX's prices too; until now only the home team's did.
    • Next package release (CLI, not on npm yet): a live buy needs a price you set yourself. arena buy with --live or --poly-intl, or with ARENA_KALSHI_LIVE or ARENA_POLY_INTL_LIVE set, needs --max-price or --limit, sized by --contracts or by --stake, and its dry run needs one too: without one it exits 2 and nothing is sent. For Kalshi the error names the ask now and the same command with that ask as --max-price. --stake on a live buy is sized at your price, never at the ask, and a live buy takes none of the paper steps: no route preview, no paper cash check, and --venue best, --prob and --expires exit 2 with it. In CLI 0.6.0 a live buy sized with --stake and no price is sent, sized and capped at Kalshi's ask, so pass --max-price or --limit yourself. The MCP trade tools already refuse a live buy without limit_price_cents or max_price_cents. A live order is sent with your own venue credentials, saved in Settings, and is real money at the venue, under the venue's rules and terms. Arena is not a broker and never holds your funds.
    • Correction: arena buy --dry-run prints no estimated venue fee and no book walk, in CLI 0.6.0 or the next release. It is the server's preview of the paper fill, and a paper fill pays no fee. The CLI page, the agents page, the sandbox page, the agent prompt and the package README said it did. arena market <ref> --contracts N shows the estimated fee, and so does an MCP place_trade dry run that would fill on Kalshi, with the book walk beside it.
    • Website: the order tickets place paper trades, and their Routing side is greyed out. Live Kalshi orders go through the HTTP API (execution: kalshi on POST /portfolio/orders), the CLI and the MCP server, with the trading key saved in Settings.
    • Website: the market page's order ticket opens on the cheapest venue for the side, with every venue at that price ticked when several tie, counting only prices Best price could fill at. A trader can tick more venues or untick any, and the ticket keeps that pick for the market; it also keeps the pick it showed once the trader asks for a review.
    • Website: a new page, Open-source acknowledgements (/acknowledgements), linked from the footer on every page, lists the open-source code, icons and fonts the website sends to your browser, with their licences and copyright notices. TradingView Lightweight Charts, which draws the price charts, comes first, with its attribution notice and a link to tradingview.com, so the charts carry no TradingView logo.
    • Website: Compare looks at every live game of a league in its 8 days, up to 100 a league, where it looked at the soonest 12. A Champions League week is 18 games, so six of them were never looked at. When a league has no price gaps to show, the board says why when Arena can: no live game, or games Arena has not matched on another venue yet (for example, "Champions League games on Oct 20 and 21 are on Kalshi. Arena has not matched them on another venue yet."). GET /api/gaps adds coverage.games, each league's live games with how many have a match on another venue, and the same sentence in notes (public OpenAPI 1.2.0).
    • HTTP API: a signed-in session token sent as Authorization: Bearer (the CLI after arena login, or an app signed in to Arena) is read as your session on POST /backtest, POST /evals, GET /runs and GET /runs/{run_id}, the same as the website's sign-in. It was refused with "This is not an Arena API key". Every other keyed route still takes only an API key and now says so: 401 unauthorized, "This route takes an API key, not a signed-in session" (or, for a value that is not shaped like a session token, "This route takes an Arena API key, and the token sent is not one"). A value that starts with arena_sk_ is still checked as a key, and a guest session or a connected app's token is still refused.
    • Website: Claude, ChatGPT and Gemini show their own logos in place of an avatar in the Feed (recent trades, biggest wins and trades, comments and the AI picks), on their profile pages and in Versus, and before their name in the eval board's rows, with an AI tag beside the name.
    • Website and API docs: the docs are always dark. A Light or System choice in Settings no longer changes the website's docs pages, and the HTTP API docs site has no light theme or toggle.
    • Website: a price no longer says how old it is. Compare cards and the market page's venue tiles drop "Over 15 s old" and show every price at full strength; a tile past 15 seconds has a grey dot, and past a minute it says Out of date. Where a pair is not arbitrage because a price is stale, the reason reads that the price is not current.
    • Website: the top bar no longer shows Pricing to a signed-in account. Signed out, it still does.
    • Website: no counter beside a price counts the seconds since the last refresh. On a compare card the line under each venue reads the size, "17,415 available", and a price over 15 seconds old is dimmed and says Over 15 s old after it; the compare board no longer says how long ago it updated; a venue tile shows a green dot on a fresh price, says Over 15 s old on an older one and Live on a price held over the venue's feed, and none of it ticks; the pair notes no longer list each price's age; the route preview says what size it was checked for; and the leaderboard prints the time of its daily snapshot in Eastern time instead of an age. A trade's time on the feed, a print's time on Signals and a chart's time axis are unchanged.
    • Website: Settings has an Appearance panel, at the top, for everyone, with a link to it in the footer. Appearance is Default (light everywhere and dark on the docs, as before), Light, Dark or System (follows the device). Font is SF Pro with SF Mono, as before, or Geist with Geist Mono. Each choice applies at once and is saved on the device, not on the account, so it works signed out, and the page keeps the choice on its first paint.
    • Website: the example workflow on /design and in the home page's Design section no longer carries the chip that called it an example, and the Design workspace has no View example button. The copy beside the canvas names the example instead. Signed out, the sentence under Sign in still says the workflow below is an example. On the home page the Design section's paragraph ends with the same sentence, and in the workspace the Runs column says the workflow shown is an example. An account with no runs still sees the example in the work area, read-only, with Replay, and an account with runs sees its runs.
    • Website: on Invest, a price that moves shows it. A dot beside the price pulses once, green when the price rose and red when it fell, and the number runs from the old value to the new one over about 400 ms in that colour before it returns to the text colour. The dot's room is always there, so the row never shifts. The first price on screen and a price that arrives where there was none show no dot, and an unchanged price, or a move too small to change the four decimals shown, does nothing. With reduced motion the number jumps and the dot shows its colour for a moment without moving.
    • Packages: CLI, MCP server and MCP tools 0.6.0 and core 0.5.0 are on npm (npm install -g arena-prediction-cli, npx arena-mcp-server). Everything this changelog calls the next package release, or not on npm yet, for those four packages is in them: API keys and key mode, arena perps, arena backtest, --venues, and live orders with your own venue credentials (--live, --poly-intl; live: true, poly_intl: true). Python SDK 0.3.0 is not on PyPI yet.
    • Website: a game chart marks what moved the price in every league Arena lists, not only the leagues with a universal ticker. A goal, a touchdown, a made shot, a run or a red card is a pin on the line of the team it concerns, with the sport's icon. Under the chart, Key moments lists each play with the team, the game clock, the time of day in your time zone and what that price did ("Rose from 38% to 63%."). Scores and red cards lead, and plays that barely moved the price wait behind Show all.
    • Website: a market page has an About this market block under the chart: what the market asks and what Yes resolves for, when it closes and settles, contracts traded, the bid, ask and spread in percent while it is open, the result once it has one, the last trade and the venue the price is from.
    • Website: Design needs a sign-in to show your runs. Signed out, /design says what Design is and shows a labelled example workflow you can replay, with Sign up and Sign in. Signed in, an account with no runs sees that example in the work area. The work area is taller with the workflow centred in it, the connections between nodes are drawn in orange with an arrowhead, and the small labels above node titles are in sentence case. The home page has a Design section between Backtesting and The line, with the same example.
    • Website: labels across the site are written in sentence case, not in capitals. That covers the small label above a heading, group and column titles, chart and code captions, chips and tags, and the small labels on share cards. On a chip or a ticket a contract side reads Yes or No, and a trade's status reads Won, Lost, Live, Sold, Push or Void. Tickers, team and league abbreviations and other codes keep their capitals.
    • Website: ProphetX is the fourth venue. Where Arena has matched a ProphetX market to an instrument, ProphetX’s price appears next to Kalshi’s, Novig’s and Polymarket’s on market, game and compare pages, as a percent like every other price and never as American odds. ProphetX is switched on separately from this release: until it is, no ProphetX price is shown and paper fills are priced as before. ProphetX prices come from its sandbox exchange until Arena’s production access is approved, and every place a ProphetX price is shown says so. In the comparison a sandbox price is a labelled row only: it is never marked Lowest, it is no part of a gap figure or of the compare page’s ranking, and a pair with a ProphetX price carries the reason sandbox_prices and is never labelled arbitrage. Once ProphetX is on, a member’s paper fill can take ProphetX’s price before a game starts (ProphetX fills before the game only; a tie there returns the stake where Kalshi pays 50): it is a Sandbox fill in Arena’s own records, and every ProphetX order stays switched off. HTTP API 1.12.1 adds prophetx to the venue enums of the keyed quotes, instruments and fills, and the keyless routes (public OpenAPI 1.1.1) answer ProphetX rows on /api/quotes and /api/gaps, feed on a ProphetX row, and sandbox_prices among a pair’s reason codes. The hosted MCP server lists ProphetX in get_cross_venue_quotes and find_price_gaps now, and in the gaps tool’s yes_prices and no_prices a ProphetX price comes last, marked (sandbox); the CLI, the npm MCP server and the Python SDK read ProphetX rows from their next release, which also adds arena buy --venues novig,prophetx and venues on place_trade to narrow a best-price paper fill to named venues. See /docs/methodology.
    • Production is live: a member sends live orders to Kalshi and, outside the US, Polymarket International with their own venue credentials, saved in Settings (Arena Basic). On the website, the order ticket has "Send this order live to Kalshi". On the HTTP API, POST /portfolio/orders takes execution kalshi (scope trade:write:kalshi) or poly-intl (scope trade:write:poly-intl; a US person is refused with 403). A live order is real money at the venue, under the venue's rules and terms. Arena is not a broker and never holds your funds. Paper stays the default, and paper trading is the sandbox. A ProphetX account can be connected in Settings, and every ProphetX order is switched off. The website, the docs, llms.txt, agent.txt, llms-full.txt, /agents.md, both OpenAPI documents and the hosted MCP server's instructions say so, and none describes live orders as a later step. The hosted MCP server itself places paper trades only: a trade call that asks for a live order is refused (live_not_hosted). /docs/execution has a Live orders section, the agent instructions tell an agent never to ask for a live order on its own, and Settings links Positions, the read-only view of your venue accounts.
    • HTTP API 1.12.1: GET /me answers paperOnly false for a key that carries a live-order scope (trade:write:kalshi, trade:write:poly-intl or trade:write:prophetx); it was true for every key. mode stays paper, because the account these routes read is the paper account. The document's summary, its description, its server line and its scope notes say what a key can do today. No route or field was added or removed.
    • Website: Invest, a tab for signed-in accounts. It lists Kalshi perpetual markets with live marks, and positions there are paper positions in paper dollars. Marks update over Arena’s live stream, with a 5-second read as the fallback.
    • MCP server (not on npm yet): list_perps and get_perp_mark read Kalshi perpetual markets from the live perps book for a signed-in account: the active tickers with their live settlement mark, bid and ask in dollars, and one ticker’s mark. get_perp_history is there too, for recent stored snapshots (limit default 20, max 50, plus since, until and source; since and until take an ISO 8601 time, a YYYY-MM-DD date or unix seconds), but perp history is switched off on Arena’s server: until Arena switches it on, the tool answers not_available, “Perp history is not available yet.”, which is not an error about the ticker. 28 tools register by default (32 with trading on). The hosted server at arena-predictions.com/mcp does not list the three perp tools yet.
    • CLI (not on npm yet): arena perps, arena perps list and arena perps mark <ticker> read Kalshi perpetual markets from the live perps book with your login: active tickers with their live settlement mark, bid and ask in contract dollars, --status for inactive, closed or all, and one ticker’s mark. arena perps history <ticker> is there too, for recent stored snapshots, but perp history is switched off on Arena’s server: until Arena switches it on, it prints “Perp history is not available yet.” and exits 6 not_available, which is not an error about the ticker.
    • Website: search engines and assistants see more of the site. robots.txt lets crawlers fetch the cached market reads the browse, category and AI pages render from (that JSON stays noindex); every page keeps og:type and og:site_name; the /search category filters are links; game and market pages carry breadcrumb data, and game pages an H1 and a canonical in the server HTML; /terms, /privacy and /support have canonicals; every sitemap entry carries a real date; URL bases fall back to arena-predictions.com, never localhost; every host but arena-predictions.com sends X-Robots-Tag: noindex; and llms.txt drops the Sports ETFs link, states the paper balance, the leagues and the iPhone app, and has every link checked against the site's routes.
    • HTTP API 1.12.0: execution "prophetx" on POST /portfolio/orders and ?execution=prophetx&externalId= on DELETE /portfolio/orders/{orderId} are how a key asks for a live ProphetX order with the key owner's own ProphetX connection (scope trade:write:prophetx), and ProphetX orders ship switched off: the scope is not issued and the route answers 503 trading_off until Arena opens them. A ProphetX order names externalId, strikeId, price as American odds (the answer carries the percent beside it) and quantity in dollars. Paper orders are unchanged.
    • Website: Settings has a ProphetX section. A paying account connects its own ProphetX account with the key pair ProphetX issued it. Arena signs in with the pair to check it, stores the secret encrypted, and shows the key's last four, the environment and the available balance. Live ProphetX orders are switched off until Arena opens them.
    • HTTP API: the docs, /llms-full.txt and llms.txt now list POST /portfolio/orders/{orderId}/amend (scope trade:write:kalshi), which openapi.json has carried since the opt-in Kalshi trading key shipped. Nothing about the route changed.
    • Website: Novig prices now arrive over Novig’s live feed via Arena’s Fly proxy, and by polling when that feed is not connected, so a quiet market can sit unchanged for minutes. Compare prices, the chart venue strip and game pages show Novig next to Kalshi and Polymarket, and a fresh Novig tile the proxy holds over the feed, while it is connected, says Live. The keyless quote routes (/openapi-public.json 1.1.0) answer feed (stream or poll) on a Novig price when the proxy says how it holds it. The note that said Novig’s public prices can be 5 to 10 seconds old now says how its prices arrive, in the CLI, the MCP tools, the Python SDK and the docs.
    • Website: the home page’s Historical data timeline shows earlier market history, as checked on September 29, 2026. Market listings and settlements are recorded from July 2021. Price candles are being added across that window, with no finished stretch. Imported trades and fills are recorded from November 2022 through March 4, 2026. Earlier trade history goes back to June 30, 2021, with the days before September 17, 2026 still being added and the landed late-September days recorded. Order books and trades on the games Arena lists stay recorded from September 28, 2026, and daily exchange trade files from August 2026. None of it is offered as a download.
    • HTTP API 1.11.0: GET /history, GET /history/candles, GET /history/as_of and GET /history/export (markets:read) forward the query string to the Fly history service. The caller's key is checked here. The Fly server key stays on the server. The service's JSON comes back unchanged, and export may be CSV. While venue data is off for keys these answer 403 venue_data_off and Fly is not called. Paper only.
    • HTTP API 1.10.2: GET /portfolio and GET /portfolio/trades with X-Arena-Org return that organization's paper sandbox (its cash, positions, resting orders and trades) and organization.slug. They do not return the personal account. With no header these stay the personal account. Paper only.
    • HTTP API 1.10.1: GET /organizations lists the organizations a personal API key belongs to. The call is forwarded to the organizations edge function with that key, and the function's JSON comes back with mode paper. Each organization's id is what X-Arena-Org takes on the portfolio and paper-order routes. Any valid key. Paper only.
    • HTTP API 1.10.0: send X-Arena-Org (an organization id) on GET /portfolio, GET /portfolio/trades, POST /portfolio/orders and DELETE /portfolio/orders/{orderId} to use that organization's paper sandbox. With no header these stay the key owner's personal paper account. A value that is not an organization id is 400. An unknown organization is 404 organization_not_found and one this key cannot use is 403 organization_forbidden. The personal account is never the fallback. This header does not select a Combine evaluation account. Paper only.
    • HTTP API: GET /me adds paperOnly (always true) and limits, the plan's minute and month, the same numbers as the RateLimit and Arena-Quota headers. limits is null when the server could not read them. With no login, arena whoami uses ARENA_API_KEY and prints the key's scopes, that it is paper only, and those limits.
    • HTTP API 1.9.0: POST /backtest (markets:read) forwards a paper replay of settled Kalshi game-winner markets to the backtest edge function. The JSON body goes through and the function's JSON comes back, with mode paper. GET answers 405 method_not_allowed and is not forwarded.
    • HTTP API 1.8.0: GET /traders/{traderId}/track-record (records:read) is served while venue data is off for keys. It asks promote-record for audience=keyed: the same scores, signed with the same key, with no Kalshi series ticker and no venue name in the signed bytes. Quotes stay 403 venue_data_off until that switch is on. The CLI, the Python SDK and hosted MCP verify still read the public envelope, which names series.
    • Docs: public/llms.txt is a short index. Commands, flags, MCP tools and endpoints in full are in /llms-full.txt. /agents.md and /AGENTS.md serve the agent instructions as markdown. The docs describe arena-prediction-cli, arena-mcp-server and arena-mcp-tools 0.6.0, and arena-core 0.5.0. Python SDK 0.3.0 is not on PyPI yet.
    • Docs: the HTTP API docs are at https://docs.arena-predictions.com, with an API playground. /docs and /docs/api redirect there. The CLI, MCP server, agents, execution, instruments, methodology and Python pages stay under /docs.
    • HTTP API 1.7.0: paper trading with a key. POST /portfolio/orders places a market or limit paper order (buy by instrumentId or ticker, side and count; sell a whole position by tradeId; limitPriceCents, timeInForce gtc, ioc or fok, expiresAt, maxPriceCents, minPriceCents, route, statedProbPct) and DELETE /portfolio/orders/{orderId} cancels a resting one, at Kalshi's paths. Both need the scope trade:write. idempotencyKey (or Kalshi's clientOrderId) is required: the same key again answers the stored order with replayed: true and places nothing, as in the CLI and on the MCP server; the same key with a different order is 409 idempotency_key_reused. Hard trade limits, always enforced: per key 10 new orders a minute, 50 a day and 20 sells and cancels a minute; per account, shared with connected apps, 20, 100 and 40. New error codes: trading_off, insufficient_balance, market_not_found, no_tradable_listing, market_not_open, market_resolved, no_liquidity, price_moved, trade_not_found, already_closed, order_not_found and idempotency_key_reused. Paper only: nothing is sent to Kalshi or any venue, and no ticker, title or price comes back while venue data is off for keys.
    • API keys: trade:write is issued when you ask for it by name, and never by default. Settings on the website has an "Allow paper trading" box, unticked, and CLI 0.6.0 takes arena keys create --trade. Every other key stays read-only. GET /api_keys says whether trade:write can be issued right now (tradeWriteAvailable).
    • HTTP API 1.6.0: GET /traders/{traderId}/track-record (records:read), a trader’s Ed25519-signed 90-day record exactly as Arena signed it, with where the keys are and how to check it (the signature is over the RFC 8785 bytes of the record without its signature field, not over their SHA-256); a trader whose numbers others cannot see, private or public with earlier trades still hidden, answers numbersShown: false and no record. It names Kalshi series inside its signed bytes, so it answers 403 venue_data_off until venue data is switched on for the keyed API. Each GET /eval row has tiedWithAbove, the tie mark the CLI, the MCP tool and the SDK call tied_with_above: null, never false, while the intervals are not available. The keyless website routes (GET /api/quotes/{instrumentId}, /api/quotes/batch, /api/gaps and /api/gaps/{instrumentId}) have their own OpenAPI document, /openapi-public.json.
    • Next package release (CLI and MCP server 0.6.0, core 0.5.0, Python SDK 0.3.0; not on npm or PyPI yet), from the third scored review: words with a day that match nothing ("jets ml tonight" on a night off) name the next game in arena quotes, market and buy, the MCP tools resolve_market and get_market, and the SDK, with that game’s id to use; nothing is changed silently. get_market takes instrument_id and place_trade takes ref, like every tool that takes an instrument, and get_market and arena market and quotes say game_state and when prices are in play; explain_a_bet uses the next game not yet started. arena record --verify says why a record is not eligible, with dates in words and no raw hash; the stake lines say "a bet on YES", not "YES pays"; the quote notes name no flag value; trader X picks --limit 5 keeps the record over the last 25 picks; a cut list says truncated; a usage error the command raised itself (--window 5y, an unknown --fields name) has the corrected command in help[]; arena gaps --all-venues says it lets a pair with Polymarket be labelled arbitrage after fees (without it the pair is still listed, never labelled arbitrage). The SDK’s payout() counts whole contracts in integer tenths of a cent ($56 at 56¢ is 100, as in the CLI and MCP), its eval rows answer to the CLI’s names and say intervals_available, tied_with_above is None while the intervals are unknown, and a 429 with no Retry-After waits 60 s like the CLI and MCP (retry_after_source says whose wait it is). Each arena://schemas/<tool> resource says what its rows carry.
    • Hosted MCP server (https://arena-predictions.com/mcp), with its next update: signed out, get_market says what a stake buys and pays on an Arena instrument (stake_dollars), and the explain_a_bet prompt walks through it; a tool that is not open on the server yet answers not_in_this_phase with the tools there are, not a bare error, and one it never offers (reset_account, the key tools, get_my_eval) says where the person does it instead; initialize names the arena-mcp-tools build it runs; a miss names the hosted tools, never a terminal, and arena://rules/errors never sends the person to one either.
    • Website: while the eval board has no 95% intervals yet, /eval says the intervals are not available and that its order is the point scores only, and each rank says it is not tested, in words under the rank as well as on hover. With intervals, a rank whose account has none says interval unknown.
    • Next package release (CLI and MCP server 0.6.0; not on npm yet), from the third scored review: a signed track record reaches you exactly as Arena signed it, so a saved copy verifies on its own. arena record --json and MCP get_track_record renamed max_drawdown_points inside the record to max_drawdown_dollars, which broke its signature and showed a figure on the record’s bankroll-scaled curve (33794) as dollars. No key inside a signed record is renamed now. In agent mode and with --fields signed_record, arena record carries the record as one JSON string; at a terminal the drawdown reads as the share of the peak it fell from, never as dollars. The hosted MCP server gets it with its next update.
    • HTTP API 1.5.0: GET /eval (records:read), the public eval board with 95% intervals clustered by game on each row’s scores. The /eval page shows the same intervals under the ranked score and marks with ≈ a rank its sample does not separate from the one above (once the database has them). The keyless quote and gap routes send X-Request-Id on every answer the CDN does not share, a batch quote read costs one unit per two ids, gap_cents sits beside gap_points, and one instrument’s gaps name every venue left out with a reason. The hosted MCP server answers a retryable temporarily_unavailable when its settings cannot be read, instead of switching its tools off.
    • Next package release (CLI and MCP server 0.6.0, core 0.5.0, Python SDK 0.3.0; not on npm or PyPI yet), from the second scored review: arena evalboard and arena record <trader> --verify (MCP get_eval_board, get_track_record; the SDK’s eval_board() rows carry the intervals). A game past its start while still scheduled is started, with in-play prices, never pregame. One paper trade a day is free once signed in, and every surface says so. A person’s trader, eval and quotes views read in words. The MCP tool list types every output field and serves each tool’s full schema as arena://schemas/<tool>; with trading off its instructions say so first; arena-mcp --version answers. The SDK’s games() is today’s slate in every league with each moneyline’s chance, leaderboard() answers the AI board when no person qualifies, and payout() says what a stake pays.
    • Website: the eval board has its own page, /eval (it redirected to the docs): public accounts scored on their settled picks, with Brier score and log loss beside the market's own, closing-line value, hit rate, return after the fee Kalshi would charge and the largest fall in dollars, never ranked by profit. When no public profile qualifies, /leaderboard shows the AI models' board under a note, as the CLI and the MCP server do. Market and game pages are titled in words ("NYY ML: BOS at NYY"), not by ticker. The home page and /pro say that every account starts with $100,000 in paper dollars and that a contract pays $1 if its side wins, and link today's games. /backtesting says what the engine covers: game-winner markets in seven leagues at each minute's best Kalshi ask, a rule as a JSON spec or your own probabilities. A 401 on the HTTP API says where a key is made (Settings or arena keys create), and every metered operation lists its 429. The keyless quote and gap routes add code and X-Request-Id to every error, and the hosted MCP server's answers carry X-Request-Id. The docs say how the same account's numbers differ between the leaderboard, the eval board, a trader's recent record and your stats, and which drawdown field to read.
    • Next package release (CLI and MCP server 0.6.0, core 0.5.0; not on npm yet), from the first scored review: a person's tables print no machine fields (totalCount, limit, signedIn) and name their columns in words; arena market --stake 100 says what $100 buys and pays on each side, signed out too, and arena quotes says it for the YES; arena games and arena game read prices 20 at a time, and signed out arena game prices every line; every help[] hint runs as printed; a mistyped flag is the error envelope with the corrected command; arena eval and get_my_eval read with your sign-in, and ~/.config/arena/arena.key is the one default key file for the CLI, the MCP server and the Python SDK; a refused key is invalid_token; arena trader and get_trader name their tally recentRecord (the last 25 picks) and never answer a record when the read failed; dry runs and stats use Kalshi's MLB fee multiplier. MCP: an unknown argument is refused by name, get_market takes stake_dollars, get_trader and the stats and eval picks are snake_case, a read that got no answer may be asked once more (retry: "after"), find_price_gaps is 10 short items by default, and a new prompt, explain_a_bet.
    • Copy: paper trading is Arena's sandbox, where a strategy is tested against live prices, and routing orders to a live venue is production, which is coming and not available yet. The website, the docs, llms.txt, agent.txt, llms-full.txt, the OpenAPI document and the hosted MCP server say so, and so do the READMEs, tool text and notes of the next package release (CLI and MCP server 0.6.0, core 0.5.0, Python SDK 0.3.0; not on npm or PyPI yet): paper trades fill in Arena's sandbox and are not sent to Kalshi, Novig or Polymarket, and each price is the venue's own. The disclaimer of the price notes, the quotes API and the best-price answer has the new sentences, and the best-price answer's reason says "best-price fills" where it said "routing" (for example "best-price fills are for members; this fill takes Kalshi's price"); the field names, "mode": "paper", route, --venue best and fill_venue are unchanged. The docs call a fill that takes another venue's price a best-price fill. Signed track records issued from the next server update carry a sandbox disclosure; a record signed before keeps its own and still verifies. The Terms and the Privacy Policy are unchanged.
    • Next package release, CLI 0.6.0: at a terminal, a --stake buy whose price moved above the price the stake was sized at is not asked about, because the order is capped at that price and a yes would likely be refused. The summary shows that one price, nothing is placed (exit 6, price_moved), and the hint is the same order sized at the new price, which asks first. A limit order with --expires says when it stops resting ("good until Tue, Sep 29, 2:12 PM EDT (in 4 h), unless canceled first"), not "good until canceled".
    • Next package release (CLI and MCP server 0.6.0, core 0.5.0, Python SDK 0.3.0; not on npm or PyPI yet), from a second review: in agent mode a CLI error carries retryAfterSeconds as --json does, and a rate limit's help[] is empty (every command spends the same minute's limit); a rate-limited place_trade or sell_trade dry run answers retry: "after" with retry_after_s, and arena://rules/engine says to retry as retry says. When Arena rate-limits the price reads behind arena games, list_games or get_game, they stop and say so, with the wait. A soccer draw reads Draw. A buy at a terminal shows its plain summary before the y/N question too, says "Nothing was placed." on a no, names the NO side of a moneyline by its outcome ("NYY does not win"), and says a limit order's time in force in words. The MCP tools ask the agent to tell the person what a bet pays and can lose before placing it, and to ask the person for their probability, never supply one. The Python SDK never falls back to the profiles table when the profile lookup fails.
    • Hosted MCP server (https://arena-predictions.com/mcp): the tools carry the next release's changes. list_games with no league is today's games in every league with each team's chance (a league alone is priced too), get_game gives each moneyline's chance, and the tool list is trimmed as the local server's is. Every rate limit answers retry: "after" with retry_after_s: a 429 from Arena's quote and gap routes, and the connector's own budget (it said retry: "no", with the wait only in the message).
    • Website and HTTP API: a private account's id is no longer needed to show its page or its record. /u/<name> resolves the name through Arena's profile lookup and shows a private account's name and that it is private, never a 404; GET /traders/{traderId} answers a private account's name and private: true with traderId null unless the key is its owner's; the owner's key, by name or id, still reads its own picks from /traders/{traderId}/picks; and GET /me keeps a private key owner's display name. The Python SDK 0.3.0 (not on PyPI yet) raises TraderPrivateError for a private account by name even where the database still answers its id.
    • Next package release, MCP server 0.6.0: the tool list an agent reads at the start of every session is smaller: 23,786 characters for the 25 default tools and 34,659 for the 29 with trading on (0.5.0 on npm lists 33,659 for 21 tools and 47,471 for 25), each output field typed, with a test that holds it under 24,000 and 35,000. The long-form rules the tool descriptions carried, such as the resolver's grammar and how prices across venues age, are in arena://rules/engine.
    • Next package release, MCP server 0.6.0: the MCP tools catch up with the CLI. get_game gives each instrument's chance (yes_pct: every row signed in, the moneylines signed out) and the game's game_state; get_market works signed out for an Arena instrument; place_trade takes stake_dollars in place of contracts (the dry run answers contracts and sized_at_cents) and a dry run over your cash answers insufficient_balance with the most that fits; get_balance and get_positions list recently_settled, the bets that settled in the last 24 hours.
    • Next package release, CLI 0.6.0: a buy dry run at a terminal reads as a plain summary: the bet, when it starts, the contracts and the price, what it costs, what it pays if it wins and can lose, and where it fills, then the fee sentence. --verbose shows every field (the ask, the cap, the book walk, the venue fee estimate); agent mode, TOON and --json are unchanged.
    • Next package release, CLI and MCP server 0.6.0 with core 0.5.0: tonight's odds in one command. arena games with no --league (and arena games --date today) lists the day's games in every league Arena covers, grouped by league, each start in your own time and each team's chance to win from Kalshi's price; a day with none says the next day that has games, and a league with none that day says what the others have, as runnable arena games --date commands. --league all works, and --league nfl alone keeps the upcoming list, now with each team's chance. arena games with no flags now lists every league (it listed the NFL's upcoming games), and in agent mode and --json it is one games table with league on each row, with limit kept. --date tonight is today, and today keeps last night's games still being played. The MCP tool list_games answers the same with no league (leagues, each game's moneylines with yes_pct, and next_date on an empty day).
    • Next package release (CLI and MCP server 0.6.0, core 0.5.0, Python SDK 0.3.0; not on npm or PyPI yet): a rate limit on arena quotes and arena gaps is exit 7 rate_limited and retryable like every other 429 except the month's quota (quota_exceeded: exit 5, retry: "no") (it was exit 6), with retryAfterSeconds always set (the server's wait, else 60) and the wait in the message, never a bare repeat of the command in help[]. The MCP tools answer every 429 but the quota with retry: "after" and retry_after_s, get_cross_venue_quotes and find_price_gaps included, and the Python SDK's privacy check raises RateLimitedError.
    • Hosted MCP server, no install: https://arena-predictions.com/mcp. Add it in Claude as a custom connector (Settings > Connectors) or in Claude Code with claude mcp add --transport http arena https://arena-predictions.com/mcp. The tools that work signed out need no sign-in. Connecting your Arena account (a consent page on the website; Settings > Connected apps lists and disconnects apps) and paper trading for an app you allow there open in stages.
    • Next package release, CLI and MCP server 0.6.0 with core 0.5.0 and Python SDK 0.3.0 (not on npm or PyPI yet), from the batch 4 review: any 429 but the month's quota is exit 7, rate_limited and retryable, with retryAfterSeconds from Retry-After (60 when the server says "in a minute"), so a rate-limited dry run no longer reads as no_liquidity. key_required (exit 4) is in the code list. The hints fill in what the CLI knows: after arena keys create --save FILE, arena keys check --key-file FILE and arena eval --key-file FILE, never the key; the first key's prefix, game, bet, trade or order id; the trader just shown; --stake 100 in place of --contracts N; arena login first when an owner page is opened signed out; and a person's placing command without --yes, so the payout question is asked. A stake dry run whose preview came back above its cap says the order would be refused as priced and offers a dry run instead. arena open flattens what it looked up (resolvedId, resolvedLabel), treats your profile as the public page it is, and --print --json answers JSON. arena picks works signed out; arena market signed in says what YES means and when the game starts; gaps and orders take --top; a no-match is not_found everywhere; key-mode rows carry id and bet; arena keys --json gives scopes as a list. A person's tables fit 80 columns with sentences wrapped last, and whoami, privacy, stats by band, trader picks, empty lists and bare arena signed out read in words. fee_drag_est_dollars counts the fee at entry and sale on bets sold early. MCP: get_leaderboard answers the AI board when no person qualifies, get_my_eval answers key_required before any sign-in check, a resting limit's dry run estimates no taker fee, and trading_session names settle_open only with trading on. Python SDK: only a value shaped like an Arena key is ever sent, a private account by name raises TraderPrivateError, and any 429 is exit 7.
    • Website: /leaderboard reads the board a link names (?window=90d&kind=ai), the links arena open leaderboard and the MCP server's web_url give; a pick on the page wins over the link.
    • Next package release, CLI 0.6.0 with core 0.5.0: run arena open to see it on the web. arena open (alias arena dashboard) is your portfolio, and arena open trade <id>, market <ref>, game <ref>, stats, settings privacy|reset|keys, profile, trader <name>, ai <model>, leaderboard and docs open those pages; it opens a browser only for a person at a terminal, and an agent gets the link with who can see it (audience) and nothing opens. Answers that have a page carry webUrl, and shareUrl only when the page is public; a person at a terminal gets one "See it on the web" line (arena config set webLinks false turns it off). arena login ends with your dashboard link. help[] holds commands, never a link or a sentence (arena open pro in place of the /pro link; a <placeholder> stays only where nothing is known or the value is a venue's ticker), and no hint suggests the command that printed it. arena login opens the browser without a shell, which fixes sign-in on Windows.
    • Next package release, CLI 0.6.0: arena buy takes a bet in words (arena buy steelers ml --stake 100 --dry-run) and resolves it first; several matches exit 6 ambiguous with each one’s dry run. Every buy dry run and confirmation says what the bet pays if it wins and the most it can lose, in dollars (payoutDollars, maxLossDollars), and a sell dry run says what selling pays next to keeping it. For an instrument id or a bet in words, the command a dry run suggests is exactly the order it priced (after a Kalshi-ticker dry run it says <ticker> in the ticker’s place): it keeps --prob, the idempotency key, your --max-price and only the venue you chose. A dry run over your cash exits 6 insufficient_balance and suggests the largest one that fits; a side nobody sells (a 100% ask) exits 6 no_liquidity and says when the game is in progress or over. arena sell with no id works on your one open position. Signed out, a trade command says what Arena is and that trading needs Arena Basic. Route reasons and notes are never cut; a terminal wraps them. One fee sentence in the CLI: paper trades pay no fee, and the eval board’s grades subtract the fee Kalshi would charge.
    • Next package release, CLI 0.6.0 with core 0.5.0: the read screens in words. positions, history, orders and picks say the bet ("PHI ML (PHI at CHI)", "Under 44.5 (PHI at CHI)"), with what you paid and what it is worth now in percent, and history says how each bet ended, newest close first; the Kalshi ticker stays in --json. arena game shows each bet’s chance and whether the game is pregame, live or final, and arena market works signed out for an Arena instrument. arena stats speaks in sentences, leaves out empty price bands and adds the drawdown in dollars. Bare arena says which bets settled since you last looked. An empty people leaderboard shows the AI models’ board. A person’s tables fit the terminal, show times in your own zone and name money in words; arena --help is grouped (Start, Prices, Trade, Your results, Account); a mistyped command gets a "did you mean"; and --top and --limit are one flag on every list that takes either (gaps and orders too).
    • Next package release, CLI and MCP server 0.6.0 with core 0.5.0: arena eval and the MCP tool get_my_eval score your own settled picks the way the eval board scores them, picks placed while private included (Brier score and log loss of your stated probability, P&L after the fee Kalshi would charge, the largest fall of that P&L in dollars), read with an API key through GET /me/eval; without a key they say how to make one, and nothing makes one for you. arena stats and get_my_stats grade your stated probability beside the entry price on the same trades. The MCP server: 25 tools by default (29 with trading on); signed out it says Open a terminal and run npx -y arena-prediction-cli@latest login once; web_url on the results that have a page; what a bet pays on positions and dry runs; a limit order’s dry run with its hold and fee, and Kalshi’s fee and book walk on a market dry run; each side’s chance in percent next to prices; ref on get_game and get_orders; get_price_history in cents.
    • Next package release (CLI, MCP server and tools 0.6.0, core 0.5.0, Python SDK 0.3.0; not on npm or PyPI yet): every package is MIT licensed, with the LICENSE file inside it, names https://github.com/ZBGC/arena-agent-kit for its repository and issues, and pins the other Arena packages to exact versions. The Python SDK adds Arena(retries=3) (it retries what is retryable and waits the Retry-After the server names), request_id on every error (the X-Request-Id to quote when you ask for help), track_record(trader) for an account’s signed 90-day record and verify_track_record() to check its Ed25519 signature against the key at /.well-known/arena-track-record-keys.json, and named max_drawdown_dollars and max_drawdown_percent on eval rows. With no key set it reads ~/.config/arena/arena.key, the file arena keys create --save ~/.config/arena/arena.key writes, and never the CLI’s sign-in.
    • Next package release, CLI and MCP server 0.6.0 with core 0.5.0: arena trader and get_trader on someone else’s private account answer its name and private: true with a null id (traderId, trader_id), even while the database still sends one.
    • Website: /dashboard goes to your portfolio, keeping the query. /portfolio answers #positions, #orders and #history, and Settings #privacy, #reset and #api-keys, each scrolled to once the page has loaded. /portfolio?trade=<id> marks that trade’s row (an open position, a resting order or one of your latest 200 closed trades; the full id, or 6 or more of its first characters), and a trade that is not yours reads exactly like one that does not exist. These are the pages arena open (CLI 0.6.0) links to.
    • Docs: /docs/python, the Python SDK’s page: install, every call and where it reads from, API keys and their limits, the eval board, errors and what it does not do. /methodology goes to /docs/methodology, and /eval to a new section of /docs/execution about the eval board (who is on it, how picks are scored, fees, ranking, where to read it) until the board has a page. /docs/methodology documents the keyless routes GET /api/quotes/{instrumentId}, GET /api/quotes/batch?ids= (up to 20 ids) and GET /api/gaps.
    • Docs: a first session to paste in order, arena games, arena resolve "steelers ml", arena quotes "steelers ml", arena buy <ins_id> --side yes --stake 100 --dry-run and arena open, in the shapes CLI 0.5.0 prints (/docs/cli and /llms-full.txt). Version minimums name only releases on npm: 0.5.0 or later for the instrument, quote, gap and best-price fill features (0.3.x and 0.4.0 were never published), and each 0.6.0 feature says it is not on npm yet.
    • Copy: the website, the docs and the CLI say fees one way, "Paper trades pay no fee. The eval board’s grades subtract the fee Kalshi would charge." (the eval board’s P&L after fees; arena stats and get_my_stats show the fee separately, as fee_drag_est_dollars). API keys cost nothing extra: any signed-in account can make one, with 1,000 requests a month without a plan and 10,000 with Arena Basic, and there is no free trading tier; /pro, /data, /business and llms.txt agree. The docs name the unit where a field’s name does not: yes_bid is whole cents from arena market and a fraction of 1 from arena quotes --json, gap_cents has two decimals, and resolved_price_cents is a sold trade’s sale price. /business and the sandbox page list the resolver’s six leagues, and the keyed API’s position and trade reads as live.
    • Eval board: two drawdown fields in fixed units, max_drawdown_dollars (paper dollars, the pnl_points basis) and max_drawdown_percent (the largest fall in a time-weighted index of your paper equity: the balance the row stands on, the grant and then each deposit, plus the realized P&L of the row’s picks since then; a 7d, 30d or 90d row starts from the grant. The Sep 27 top-up and a reset’s refill count as deposits, not gains, so it stays between 0 and 100, and it reads 100 once the equity on the row’s curve reaches $0. The board row others see leaves it empty while the account’s balance numbers are hidden). max_drawdown_points and max_drawdown_pct are deprecated and keep their values, because signed /promote records carry them. The Python SDK 0.2.0 has the two new fields only in each row’s raw dict; Python SDK 0.3.0 (not on PyPI yet) names them, row.max_drawdown_dollars and row.max_drawdown_percent. See /docs/execution.
    • Website: the home page has a Historical data section, a timeline of what Arena holds and from when, as checked on September 29, 2026: order books and trades on the games it lists (from September 28, 2026), daily exchange trade files (from August 2026), the AI models’ graded picks, and dated context stored point-in-time (economic series with revisions, weather at settlement stations, sports results, 2026 election data), with what is still being added and what is planned. Backtesting is in early access, and none of it is offered as a download.
    • Website: /portfolio and /portfolio/analytics answer for themselves. A visitor gets “Sign in to see your portfolio”, and an account without Arena Basic sees its own positions and history, with an Arena Basic link only where a paid action would be (best-price selling, a first trade). Selling at Kalshi’s bid and cancelling an order stay open to every account. /market/ins_… and /game/game_… (and their slugs) send an Arena id to its market or game page and keep the link’s side, stake, utm_*, fbclid, src and alert. An id that is not a public bet or game answers 404, and a lookup that cannot answer gives a 500 page with Try again. A Kalshi ticker that does not exist still shows the market page’s own not-found message.
    • API keys in Settings on the website: list, create, rotate (with a grace period) and revoke your keys, and see this month’s requests. Key management takes a person’s session, never a key. The CLI gets the same commands in 0.6.0 (arena keys create --save ~/.config/arena/arena.key, written with mode 0600 and never printed unless you pass --print-token; arena keys, arena keys rotate <prefix> --grace 10m, arena keys revoke <prefix> --yes and arena keys check), with core 0.5.0; neither is on npm yet.
    • HTTP API 1.4.0: GET /portfolio and /portfolio/trades (your positions, resting orders and trades, private picks included); GET /instruments, /instruments/search, /instruments/{ref}, /games and /games/{ref} under a new scope, markets:read; GET /instruments/{ref}/quotes and /quotes, which answer 403 venue_data_off until venue data is switched on for the keyed API; GET /usage; POST /api_keys/{id}/rotate. Every keyed answer carries your plan’s counts (RateLimit-*, Arena-Quota-*, Arena-Plan): 1,000 requests a month without a plan, 10,000 with Arena Basic. The limits count now and refuse nothing yet.
    • HTTP API: every 401 carries its WWW-Authenticate: Bearer challenge, including the one GET /portfolio, /portfolio/trades and /me/eval answer when a key is revoked or expires during the request. Keyed instrument, game and quote answers, which a client may keep for a few seconds (Cache-Control: private), carry Vary: Authorization, X-Arena-Key, as records reads do.
    • Next package release (CLI and MCP server 0.6.0, Python SDK 0.3.0; not on npm or PyPI yet): key mode, where on a machine with no login ARENA_API_KEY lets arena balance, positions, orders and history (and the MCP tools get_balance, get_positions and get_orders) read with a key. The MCP server adds list_api_keys, and revoke_api_key when you set ARENA_MCP_ALLOW_KEYS=1; no tool makes or rotates a key. A rate limit is exit 7 in the CLI and retry: "after" on the MCP server. The Python SDK adds usage(), portfolio(), trades(), list_instruments(), instrument_v1() and ARENA_API_KEY_FILE; it never makes or revokes a key.
    • Website: /compare and the market page's price comparison say each bet in words with team logos ("Chicago Bears win by 2 or more points"), list every venue's price for each side with its age, mark the lowest (and ties), price the best pair at the prices shown, and say plainly when a pair costs more than the $1 the winning side pays. Kalshi, Novig and Polymarket show their own logos.
    • Website: one slow answer from Arena’s price service no longer hides Novig’s price and Polymarket’s last trade per outcome for 20 seconds. Arena asks again at once, counts one slow moment once however many prices were waiting on it, pauses only after failures in a row (2 seconds at first, 20 at most) and ends the pause as soon as the service answers again. A market page keeps its fast refresh through a short pause, and Novig’s price returns with the service’s next answer. /docs/changelog leads to /changelog.
    • Games: once Kalshi settles a game’s markets with one winner, the game shows as final within the hour, in every league, even while Kalshi’s own game status still says in progress or scheduled. The NFL, college football and NHL games of September 26 to 28 that still showed as in progress or scheduled on the website and in GET /games are corrected. A postponed or voided game is never marked final.
    • Docs: /docs/mcp lists the MCP server's two resources (arena://rules/engine, arena://rules/errors) and two prompts (trading_session, evaluate_market), the HTTP API reference has a block for GET /me/eval, /llms-full.txt lists every public page of the website, and robots.txt names the AI crawlers it lets in.
    • Website: game cards and the game and market pages show "$X volume", the value of the contracts traded on the game across Kalshi, Polymarket and Novig (the last two while Arena shows other venues’ prices), each contract counted at its $1 payout. Novig counts through the last day it has published. What is counted, and how often it is read: /docs/methodology (Volume).
    • Agent kit: https://github.com/ZBGC/arena-agent-kit is public (README, AGENTS.md, examples, a skill and a copy of llms.txt), and the MCP server is in the official MCP registry as com.arena-predictions/arena.
    • On npm: CLI 0.5.0, MCP server and tools 0.5.0, core 0.4.0. arena balance and get_balance show the run, P&L since your last reset and lifetime P&L. arena reset and the MCP tool reset_account reset an account after the owner turns resets on; scripts and agents need ARENA_ALLOW_RESET=1 too. arena leaderboard --window 30d|90d|all --ai and get_leaderboard window and kind (30 days by default, as on the website; win percentage as winPct / win_pct, 0 to 100). arena history, arena stats, get_history and get_my_stats take window, since, until and run: current. arena buy takes --stake in dollars and needs no --side on one team’s win market. Balance fields name their unit (balanceDollars); the short names stay as aliases, listed under aliases.
    • CLI 0.5.0 fixes: --stake never spends more than the stake (with --max-price the order is sized at that price); --idempotency-key on buy (a replayed key answers the stored trade marked replayed; with --stake it needs --max-price or --limit), echoed on sell; sell --min-price; every error carries a machine code, and with --json it is JSON on stdout; buy --json is { receipt, trade }; money fields name their unit (balanceDollars, netWorthDollars) and the short names are permanent aliases; positions is marked to live prices; help[] offers every buy as a dry run first; arena gaps ranks by opportunity and prints cents. MCP 0.5.0: get_orders registers with trading off; a dry run never answers same_key; an unknown ticker is not_found; idempotency_key_reused. Python SDK 0.2.0 (arena-predictions, on PyPI): real dtypes in to_frame() and TraderNotFoundError from eval_account.
    • Private by default: every account is private until its owner makes the profile public in Settings on the website. Others then see none of its trades, balance, rank or record, and it is left out of the leaderboards, the evaluation board and Promote. Only a person in Settings can make an account public; the CLI (arena privacy on), the MCP server (set_privacy) and API keys can only make it private. Trades placed while private stay hidden after going public unless the owner ticks "Also show my earlier trades". The AI models stay public.
    • HTTP API 1.3.0, for private accounts: a private trader answers private: true with every number null and no picks, and a public trader whose earlier trades are still hidden answers numbersShown: false. New GET /me/eval (portfolio:read): your own settled picks, scored the way the evaluation board scores them, picks placed while private included. No key can make an account public.
    • Your probability: when you place a trade you can state your probability that the side wins, in percent. It is saved with the trade, shown back to you, and scored once the pick settles. Settled public picks are scored on the eval board (Brier score and log loss), and a public account that states one on every scored pick is ranked on log loss. It never changes the fill. The website’s order ticket has the field; CLI 0.5.0 arena buy --prob, MCP 0.5.0 place_trade.stated_prob_pct, core 0.4.0 statedProbPct, and EvalPick.stated_prob_pct in the Python SDK 0.2.0. The AI models now state a probability on every pick; their confidence score stays as it was.
    • HTTP API: every /api/v1 response but the cached GET /openapi.json carries X-Request-Id and advisory RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and RateLimit-Policy headers (nothing is refused on them yet). A method a path does not serve answers 405 method_not_allowed with Allow. GET /status is never cached. A records read without a key says why a key is asked for. place-trade answers a reused idempotency key on a different order with 409 idempotency_key_reused.
    • Account resets: turn them on in Settings, then reset at most once every 30 days. A reset sets your cash back to $100,000 and starts a new run. It shows on your profile when the profile is public, and your all-time profit keeps every run.
    • Leaderboards: All time (profit since Sep 1, 2026 across every reset; 20 closed trades and a first trade 30 or more days ago), 30 days and 90 days, for people and AI models, with resets and busts on every row. Boards are as of the daily snapshot, about 05:10 UTC (refreshedAt).
    • HTTP API 1.2.0: GET /status and the records carry no season. GET /leaderboard takes window (all, 30d, 90d) and kind (people, ai) and answers pnlDollars, tradesClosed, winRate, resets and busts. GET /traders/{traderId} answers standing and resets. New GET /account (portfolio:read), with run=current for the owner’s view of one run. New error code 404 account_not_found.
    • Balances carry over and no longer reset. A gtc order rests for up to 365 days.
    • In CLI 0.4.0, MCP server and tools 0.4.0 and core 0.3.0 (not published separately; shipped in CLI 0.5.0 and core 0.4.0), arena stats and get_my_stats with no month grade every closed trade since 2026-09-01. Bare arena, arena whoami and arena balance no longer print month by default. arena whoami shows the balance as balance; whoami --json keeps balanceDollars for 0.4.x and lists it under deprecations. arena stats and arena leaderboard no longer print season by default, and whoami --json and balance --json list monthKey under deprecations: it is the ledger key, 2026-09, not the current month. --month and month read the trades that closed in that calendar month in America/New_York, so October and later months are not empty.
    • HTTP API: GET /status reads season from the database, so it matches the key /leaderboard rows carry.
    • CLI 0.4.0, MCP server and tools 0.4.0, core 0.3.0 (not published separately; shipped in CLI 0.5.0 and core 0.4.0) add best-price paper routing. arena buy and arena sell take --venue best|kalshi, and the MCP tools place_trade and sell_trade take route and dry_run. With best, the default, a paper fill can take Novig’s or Polymarket’s price for the same instrument when it passes Arena’s checks, and every receipt names the venue. The iPhone app sends no route and fills at Kalshi’s price. Arena still sends no order to any venue.
    • arena gaps and the MCP tool find_price_gaps (CLI and MCP 0.4.0, shipped in 0.5.0) show price gaps for the same instrument across Kalshi, Novig and Polymarket, worked out after each venue’s taker fees. Both work signed out.
    • Universal ticker: instruments and the resolver cover college football, MLB, the NHL, the NBA and the Premier League as well as the NFL. Prices on other venues cover all of them except the NBA so far.
    • Docs: new page /docs/methodology (how Arena matches the same bet across venues, reads and times each price, works out fees and gaps, and routes paper fills), and /docs/execution covers best-price routing.
    • Website: /compare lists the bets Arena matched on Kalshi, Novig and Polymarket, ranked by how far apart their prices are, with each price's venue and age. The first page is rendered on the server, and visitors can open it without an account.
    • CLI 0.3.1, MCP server and tools 0.3.1, core 0.2.1 (not published separately; shipped in CLI 0.5.0 and core 0.4.0) add arena quotes and the MCP tool get_cross_venue_quotes, which show one instrument’s price on Kalshi and, while Arena shows them, on Novig and Polymarket for the same instrument, each with its venue, its time and how its contract differs. Display only: Arena does not route orders to Kalshi, Novig or Polymarket. Both work signed out.
    • CLI 0.3.0, MCP server and tools 0.3.0, core 0.2.0 (not published separately; shipped in CLI 0.5.0 and core 0.4.0): instrument and game lookups that work signed out (arena instrument, arena game, arena games; get_instrument, get_game, list_games); instrument ids accepted wherever a quote or a trade takes a ticker; arena chart and screener (get_price_history, screen_markets); arena stats and get_my_stats; an estimated venue fee on quotes, not charged on paper; seasons documented in America/New_York.
    • HTTP API: GET /leaderboard, /traders/{traderId} and /traders/{traderId}/picks ship (scope records:read, Arena-owned data only). New error code 404 trader_not_found. Successful records reads are Cache-Control: private, max-age=30.
    • Docs: new pages /docs/execution (how Arena fills, grades and ranks) and /docs/instruments (the universal ticker), and Add to Cursor and Add to VS Code buttons on /docs/mcp.
    • CLI 0.2.1, MCP server 0.2.0 and MCP tools 0.2.0 (not published separately; shipped in 0.5.0) and core 0.1.2 (shipped in core 0.4.0): arena resolve and the MCP tool resolve_market turn a bet in words, such as "chiefs ml" or "kc -3.5", into an Arena instrument id, the ticker and the side to buy. NFL moneylines, spreads and totals only for now. Both work signed out.
    • HTTP API: key management moved from /keys to /api_keys, Kalshi’s path. GET /status (no auth) and GET /openapi.json added. Unknown /api/v1 paths now answer the JSON error envelope with 404 route_not_found instead of an HTML page.
    • HTTP API: timestamps on key records are RFC 3339 UTC at second precision (…Z), as the conventions say.
    • Docs: restructured: a Quickstart first (install the CLI, a prompt for your coding agent, the MCP server), then the CLI, the AXI contract, API basics, an HTTP reference with one block per endpoint, and this changelog.
    • CLI 0.2.0: guest sign-in removed. arena login is Google or Apple only.
    • CLI and MCP: every request identifies its client (x-arena-client: cli/<version> from the CLI, mcp/<version> from the MCP server).
    • Membership renamed Arena Basic; exit 5 says so.
    • CLI 0.2.0: limit orders. arena buy and arena sell take --limit, --tif (gtc, ioc, fok) and --expires; arena orders lists your orders and arena cancel withdraws a resting one.
    • MCP server and tools 0.2.0 (not published separately; shipped in 0.5.0): place_trade and sell_trade take limit_price_cents, time_in_force and expires_at; new tools get_orders and cancel_order.
    • core 0.1.1: the order functions, and getBalance reports the points held by resting orders.
    • CLI 0.2.0: money in every payload is paper dollars, named dollars / *Dollars; arena leaderboard and arena trader work signed out.
    • MCP server 0.2.0 and MCP tools 0.2.0 (not published separately; shipped in 0.5.0): the same paper-dollar naming, and the records tools work signed out.
    • core 0.1.1: public reads fall back to the publishable key when there is no session.
    • HTTP API: key-management refusals (guest session, key limit, reserved scope) answer 403/409 with the error envelope instead of 500.
    • HTTP API: API keys (POST, GET, DELETE /api_keys) and GET /me ship. Keys are read-only, shown once, stored hashed.
    • CLI 0.1.0 and the MCP server 0.1.0 published; this page goes live.