What we actually have across every AI-powered surface, and the economics of the decision taken on 2026-10-02: Claude Haiku 4.5 answers every user, inside per-plan monthly caps, with self-hosted qwen2.5:3b as the fallback. Usage figures on this page are read live from production — they are measurements, not prose, and are fetched on every load. The pricing table and the argument built on it are still written by hand from published API rates; re-check those before acting if the review stamp below is old. See sources & assumptions at the bottom.
Every AI-powered surface on the site, in one place. This site is an AI-first product — the table below is the honest inventory behind that claim, not the pitch.
| Feature | What it does | Backend | Status | Model(s) |
|---|---|---|---|---|
| My Second | Opponent scouting: PGN ingestion, RAG-grounded prep briefs, opening/weakness Q&A chat | Python ai-coach-service | low usage … | Claude Haiku 4.5 for every user since 2026-10-02; qwen2.5:3b when Claude fails |
| AI Coach | Per-game Stockfish analysis + grounded mistake explanations (CCC recipe: concept extraction → LLM verbalizer → hallucination gate) | Python ai-coach-service (same service as My Second — they share the LLM, RAG store, and Stockfish pool) | live … | Same as above |
| Coach (legacy) | Per-game analysis, a separate persistent weakness profile (weakness_profiles table), targeted drills | Node-native — its own game_analyses table, no Python involved | near-dead … | None — fully rule-based/statistical, no LLM anywhere in this path |
| Maia-2 | Human-move prediction, P(move | rating) — "62% of players at your level find this move" | maia2-service container | live — My Second prep, Coach's /maia, and AI Coach's own pipeline (_enrich_with_maia) | Own CNN, not an LLM |
| Model router | Picks the frontier model for chat + verbalizer. Users: exactly one provider, AI_USER_PROVIDER (Claude). Admins: AI_ADMIN_PROVIDER, or the old race. Anything that fails falls back to local Ollama. | ai-coach-service/model_router.py | live — every user since 2026-10-02 (Groq WAF block and an empty Claude balance were both found here in August; a failure now falls back to Ollama and is logged) | Users: Claude Haiku 4.5. Admins: pinned provider, else Groq → Gemini → Claude |
DECIDED AND SHIPPED 2026-08-03 (this page was not updated at the time; corrected 2026-09-26): the weakness-profile and session-history machinery moved into AI Coach. weakness.html now reads /api/ai-coach/weakness-profile, which computeAiCoachWeaknessProfile() builds from ai_coach_analyses and stores in user_skill_profiles. The legacy Coach (coach.html, coachRoutes.ts, game_analyses) is no longer linked from the nav — reachable by URL only, and its live counts in the table above show whether anything still writes to it. What remains is retiring it, apart from its /maia route. The paragraph below is the original framing, kept for the record.
The thing most worth your attention here: Coach and AI Coach are two independently-built per-game analysis systems, live at the same time, linked separately in the main nav, writing to two unrelated database tables (game_analyses vs ai_coach_analyses). That may be intentional (Coach = fast/free rule-based first look, AI Coach = deeper grounded-LLM analysis) — but nothing in the codebase states that as a decision, and a new user landing on either one has no way to know the other exists or why they'd pick one over the other. Worth an explicit call: merge the weakness-profile/drill machinery into AI Coach (it's the more capable pipeline and already has a "no persistent loop" gap — see below — that Coach's weakness_profiles table already half-solves), or clearly differentiate the two in the product itself.
Cross-cutting tasks & challenges (AI Coach-specific detail, diagrams and the grounding-gate design: module health →):
AiSpendCaps.ts, entitlements.monthlyAiAllowance). Numbers and margins: model economics.rag_pipeline._enrich_with_maia() runs on every analysis and attaches a skill line to each mistake (how many players at your rating find the move). The explanation itself is not yet rating-aware (corrected 2026-09-26): Maia-2 runs after the LLM pass and never reaches concepts.py, so the prose is the same at 900 and 2200. Detail: module health →0 free-tier quota until billing is enabled, confirmed directly against Google's API with two separately-issued keys. Groq was added as a third provider — genuinely free at every account region, no billing wall, hosting Llama 3.3 70B — and model_router.py now tries each configured provider in priority order (Groq → Gemini → Claude) and falls through to the next on any failure, not just when a key is blank, since a configured-but-broken provider (exactly what happened here) would otherwise silently block every request forever. The pricing/volume analysis below is unaffected — it's about $/token economics at scale, not which specific provider unblocks testing today.Claude Haiku 4.5 now answers every user, on every AI surface except the Ask box's question translator, with the local qwen2.5:3b answering instead whenever Anthropic fails. What makes that safe is two monthly limits on every account: a spend ceiling of an eighth of the plan's list price (free accounts $0.05, admins $25), checked before every call; and plan counts on the two costliest features, AI Coach analyses (15 / 40 / 100 a month on Standard / Premium / Coach) and My Second chat messages (70 / 110 / 250).
Every plan stays profitable when used to the limit. An eighth of the list price is about a quarter of what an annual plan leaves us after VAT, Stripe and card fees, and about a sixth of a monthly plan, so a subscriber who hits the ceiling still leaves roughly three quarters of the margin. If every account on the site, free and paid, hit its ceiling in the same month, model spend would be about 25% of what monthly plans bring in (41% if everyone paid annually). A typical month is 1–2%. Club is the thin case: ten Premium seats at their ceilings would take 51% of what a club leaves us.
Don't build a GPU box for a bigger local model yet. It breaks even against metered Haiku at roughly 50,000–100,000 chat messages a month (51,000 at the code-read cost of a message, about 104,000 at the measured one), far beyond what the plan counts allow at today's scale. Below that, metered API is cheaper, has no fixed cost, and doesn't compete with Stockfish for CPU.
second_opponent_profiles).Decided and deployed 2026-10-02. Prices are the decided ones, VAT included. Costs are measured on Haiku 4.5 ($1 / $5 per million tokens) from the ai_usage ledger: $0.0029 for a full AI Coach run (four calls) and $0.0026 for a My Second chat message. The dollar ledger is converted at the ECB rate of 2026-10-02 ($1 = €0.891). tests/haikuforall.test.ts re-derives the guarantees below from the code and the billing page, and fails the build if a cap, a price or the ceiling breaks them.
1 · What each plan leaves us. Spanish VAT (21%) is inside the price. Stripe Managed Payments takes 3.5% of the gross, and the card fee is 1.5% + €0.25 a charge. An annual plan is discounted, so it leaves less a month than a monthly one.
| Plan | Price | Net of VAT | Managed Payments | Card fee | Kept a month |
|---|---|---|---|---|---|
| Standard monthly | €2.99 | €2.47 | €0.10 | €0.29 | €2.07 |
| Standard annual | €19.99 | €16.52 | €0.70 | €0.55 | €1.27 |
| Premium monthly | €4.99 | €4.12 | €0.17 | €0.32 | €3.62 |
| Premium annual | €34.99 | €28.92 | €1.22 | €0.77 | €2.24 |
| Coach monthly | €9.99 | €8.26 | €0.35 | €0.40 | €7.51 |
| Coach annual | €79.99 | €66.11 | €2.80 | €1.45 | €5.15 |
| Club monthly | €19.99 | €16.52 | €0.70 | €0.55 | €15.27 |
2 · What a plan costs used to the limit. The counts are what each plan includes; the ceiling is the hard stop on all AI spend for the account, counts included.
| Plan | AI Coach a month | Chat a month | Full counts cost | Spend ceiling | Ceiling vs kept annual · monthly | Left after a maxed ceiling |
|---|---|---|---|---|---|---|
| Free | 1 | — needs a paid plan | $0.003 | $0.05 | — | — |
| Standard | 15 | 70 | $0.23 | $0.37 €0.33 | 26% · 16% | €0.94 |
| Premium | 40 | 110 | $0.40 | $0.62 €0.56 | 25% · 15% | €1.69 |
| Coach | 100 | 250 | $0.94 | $1.25 €1.11 | 22% · 15% | €4.04 |
| Club (owner) | 100 | 250 | $0.94 | $2.50 €2.23 | 15% monthly only | €13.05 |
| Club + 10 Premium seats | — | — | $4.96 | $8.74 €7.78 | 51% monthly only | €7.49 |
anthropic failed, answering from the local model.Who pays: we do, centrally. Every user’s Claude call goes out with one API key (ANTHROPIC_API_KEY on the server) and is charged to our Anthropic organisation’s prepaid credit balance at Haiku 4.5’s rate ($1 in, $5 out per million tokens). Users never deal with Anthropic: they pay us a plan, and the plan’s monthly counts and spend ceiling (the economics card above) keep what each account can cost under an eighth of what it pays. Credits are bought in the Claude Console (Settings → Billing → Buy credits), are non-refundable and expire a year after purchase, so small top-ups with auto-reload beat one large block.
Is central billing the right model? Yes, for a consumer app. The alternatives are worse: asking players to bring their own Anthropic key (no chess player has one), metering each analysis (meters put people off, and VAT and card fees on cent-sized charges eat them), or sending each user to buy credits from Anthropic (no such product). What central billing does need is the safeguards below, because one balance serves everyone: when it stops, it stops for everyone at once.
The limits outside our code (Anthropic’s, from its rate-limits page, checked 2026-10-03):
| Limit | Where it is set | What Anthropic returns | What a user sees |
|---|---|---|---|
| Credit balance reaches zero | Console → Billing: buy credits, auto-reload | Every call refused until credits are added | The local model answers: slower, plainer, never an error |
| The usage tier’s monthly spend cap: Start $500, Build $1,000, Scale $200,000 | By tier; raise it from Console → Settings → Limits | HTTP 429 enforced_spend_limit_reached, no retry-after; paused until 00:00 UTC on the 1st | The local model, until the 1st or until the tier is raised |
| Our own spend limit, below the tier’s cap | Console → Billing → Spend limits | HTTP 400 “You have reached your specified API usage limits” | The local model, until the limit is raised |
| Rate limits. Haiku 4.5 on Start: 1,000 requests, 2M input and 400k output tokens a minute | By tier | HTTP 429 with retry-after | A short wait (retried), then the local model if it persists. Far above our traffic |
Found and fixed 2026-10-03. The gateway retried every 429 three times (about 1 + 2 + 4 seconds). The spend-cap 429 never clears on retry, so once a cap was reached every AI request in the app would have waited 7–9 seconds before the local model answered, for the rest of the month. Now (src/services/AiBudget.ts):
ALERT_EMAIL (already set on the server). An outage is emailed once it has lasted ten minutes.AI_MONTHLY_BUDGET_USD (default $50; set it to the Console’s spend limit). At 50% you get an email; at 80% (AI_FREE_LOCAL_AT) free accounts move to the local model until the 1st, with another email; at 100% a third. Paying accounts are never moved by it: each is capped at an eighth of what it pays, so their use is paid for by their plan. Anthropic’s limit stays the only hard stop, and the emails give you time to raise it.What a user sees at a cut-off: never an error from a central limit. The local model answers instead, and the AI Coach also has its rule-based floor. The only refusal a user ever sees is their own plan’s allowance, with the number and the day it resets.
Owner checklist in the Claude Console:
AI_MONTHLY_BUDGET_USD in the server’s .env set to the same figure.The path as deployed. Green is the default for every user: Claude Haiku, reached from both services. Dashed blue is the local fallback and the ledger read; dashed purple is the one piece still missing.
Solid = deployed · green = Claude Haiku, every user's default since 2026-10-02, and the admin pin (built 2026-09-09) · dashed blue = the local fallback and the ledger read · dashed purple = still missing. The gate sits AFTER the provider on purpose: it is the one guarantee that does not depend on which model answered, which is exactly what makes it the fair yardstick for comparing them.
This whole analysis is a forward projection, not a report on live economics — read every dollar figure below as "if you launch roughly as currently planned," not "what we're making." Two things make that explicit:
What is real: AI Coach is the only surface with sustained use, from dogfooding rather than organic demand — see the live figure above. My Second has almost none yet, because today's fixes are what make it usable enough to actually put in front of people. So the AI Coach numbers below are closer to "current," and the My Second numbers are closer to "if this launches and gets adopted."
UPDATE — 2026-09-13. Three things changed, and one of them means every figure on this page is still a projection.
The trial had measured nothing, and now can. The Anthropic key was invalid — a 401 on every call, for weeks (see the correction above). It was replaced and verified HTTP 200 from inside chessflow-ai-coach on 2026-09-13. But the ledger still holds zero anthropic rows, because a failed call writes none and no successful call has yet flowed through the service. Until an anthropic row appears on 🤖 AI cost, nothing below has been validated against real spend.
RESOLVED 2026-09-15 (commit 9f5187c, “one model switch for both services”): claude_client.py now reads ANTHROPIC_MODEL like the Node gateway, and docker-compose.prod.yml passes it to both containers with the same default, claude-haiku-4-5. The paragraph below is kept as the record of what was wrong. Two different models are billing into one ceiling — unresolved. The Node gateway (My Second briefs, post-mortems) uses ANTHROPIC_MODEL, currently claude-opus-5. The Python coach service has its OWN default, claude_client.DEFAULT_MODEL = claude-haiku-4-5, and does not read that variable at all. Both spend against the same AI_SPEND_ADMIN_CAP_USD ($25/month), and Opus lists at roughly five times Haiku. So "cost per call" on the AI cost page is an average over two different models, and quality-per-dollar cannot be attributed to either. Align them before drawing any verdict from this trial — whichever way, since which one you standardise on materially changes what $25 buys.
The missing denominator now exists. Migration 088 adds ai_chat_turns, which records every chat turn with its provenance: which provider and model answered, input and output tokens, how many knowledge-base snippets reached the prompt, and whether a model was called at all — the Q1-Q6 fast path answers from pre-computed statistics and never reaches one, so its turns must not be counted as model output. ai_usage says what was spent; ai_chat_turns says what it bought. Per-interaction economics on this page have been guesses because only the first half was recorded.
Guardrails are now a registry, not prompt text. The same migration adds ai_guardrails with eight seeded rules — every one in proposed state, including the rules already live in the system prompt today, so the existing policy is inspectable rather than implicit. Nothing is enforced until it is approved, and the chat path reads the table at request time, so denying a rule genuinely disables it. That deliberately includes chat_training_use: storing chats for admin review is one decision, using them as training data is another, and it is left undecided rather than acquired as a side effect of building the log.
Per 1M tokens, list price, from each vendor's own pricing page. The self-hosted row has $0 marginal cost but isn't really free — see the caveats underneath.
| Model | Type | Input $/M | Output $/M | Notes |
|---|---|---|---|---|
| qwen2.5:3b-instruct (current) | Self-hosted, CPU | $0 | $0 | Shares the API box's 4 vCPU with Stockfish; ~18 tok/s; one LLM job at a time in the verbalizer |
| Gemini 3.1 Flash-Lite | Frontier, budget | $0.25 | $1.50 | Cheapest metered option surveyed. This row was labelled “Gemini 3 Flash Preview” until 2026-09-26; Google now lists that model as legacy at $0.50 / $3.00. |
| GPT-5.4 Mini | Frontier, budget | $0.75 | $4.50 | |
| Gemini 3.6 / 3.7 / 3.8 Flash | Frontier, mid | $0.75 | $3.75 | Rate through 2026-12-31; $1.50 / $7.50 from 2027-01-01. 3.8 is the newest Flash. |
| Claude Haiku 4.5 | Frontier, budget | $1.00 | $5.00 | Recommended default below |
| Claude Sonnet 5 | Frontier, mid | $2.00 | $10.00 | Launched as intro pricing through 2026-08-31; Anthropic has since made it the standard price and cancelled the move to $3 / $15. This page used $3 / $15 until 2026-09-26, overstating every Sonnet figure by half. |
| Claude Opus 5.5 | Frontier, flagship | $4.00 | $20.00 | Newest Opus; cheaper than Opus 5 |
| Claude Opus 5 | Frontier, flagship | $5.00 | $25.00 | |
| Claude Fable 5 / 5.1 | Frontier, highest-capability | $10.00 | $50.00 | Overkill for this use case |
What "self-hosted is free" actually hides: qwen2.5:3b's marginal cost per call is $0, but its fixed cost is the ~€30/mo box, shared with Stockfish and everything else. The real cost of the current setup isn't dollars — it's a throughput ceiling (single-threaded generation, ~18 tok/s) and a weak instruction-following track record (documented in today's bug fixes). Frontier pricing above is the dollar cost of removing both problems.
Token estimates from reading the actual prompt-building code, not guesses.
| Feature | Input tok | Output tok | Gemini 3.1 Flash-Lite | Haiku 4.5 | Sonnet 5 | Opus 5.5 | Opus 5 |
|---|---|---|---|---|---|---|---|
| My Second brief generation | — | — | $0 — 100% templated, no LLM call (see today's fix: now grounded in real PGN examples instead) | ||||
| My Second chat message | ~2,800 | ~500 | $0.0015 | $0.0053 | $0.0106 | $0.0212 | $0.0265 |
| AI Coach mistake explanations top 2 mistakes, capped 120 tok output each | ~500 | ~240 | $0.0005 | $0.0017 | $0.0034 | $0.0068 | $0.0085 |
| AI Coach study-plan days first 2 days, same verbalizer and cap; one retry on a gate reject | ~500 | ~240 | $0.0005 | $0.0017 | $0.0034 | $0.0068 | $0.0085 |
| AI Coach, one full run up to 4 calls — earlier versions of this table counted only the first 2 | ~1,000 | ~480 | $0.0010 | $0.0034 | $0.0068 | $0.0136 | $0.0170 |
Every number here is a fraction of a cent. Per-call cost was never going to be the problem — volume is, specifically uncapped chat volume. That's the whole ballgame below.
SCALING.md). Recomputed 2026-10-02 for Haiku-for-all. The previous table used the post-beta review limits of 2 / 5 analyses a month, an uncapped 150-message heavy band and revenue net of VAT only.| Users | Paying | Kept a month monthly · annual plans | Scenario | Haiku 4.5 cost | Share of kept monthly · annual |
|---|---|---|---|---|---|
| 1,000 Launch | 150 | €391 · €241 | Typical | €4.56 | 1.2% · 1.9% |
| Heavy | €16.80 | 4.3% · 7.0% | |||
| Every account at its ceiling | €99.39 | 25.4% · 41.2% | |||
| 5,000 Growth | 750 | €1,961 · €1,209 | Typical | €22.81 | 1.2% · 1.9% |
| Heavy | €84.14 | 4.3% · 7.0% | |||
| Every account at its ceiling | €497.38 | 25.4% · 41.1% | |||
| 10,000 Scale | 1,500 | €3,923 · €2,418 | Typical | €45.64 | 1.2% · 1.9% |
| Heavy | €168.35 | 4.3% · 7.0% | |||
| Every account at its ceiling | €994.99 | 25.4% · 41.1% |
At Haiku pricing the model bill is 1–2% of what we keep in a typical month and 4–7% in a heavy one, at every milestone. The last row of each group is not a forecast but the bound: it is what the limits allow if every account, free and paid, hit its ceiling in the same month, and even that leaves the business in profit. At Sonnet 5's $2 / $10 every cost figure doubles, which is why Sonnet-class models are worth reserving for a specific high-value call rather than every chat turn.
For context: at today's actual AI Coach volume (see the live figure above — tens of analyses a month), the whole feature costs well under $1 a month on Haiku. There is no scenario where AI Coach's model choice is a financial decision at today's scale; it is a quality decision.
Since 2026-10-02. Per-plan monthly counts shipped with the move to Haiku for every user: 70 / 110 / 250 chat messages and 15 / 40 / 100 AI Coach analyses on Standard / Premium / Coach, sized from measured costs rather than the estimates below (see model economics). The spend ceiling that had closed the liability since 2026-09-09 was lowered from half the list price to an eighth. The proposal below is kept as the record of the reasoning.
My Second chat is gated by tier, not by message count — once a user has any entitlement, messages are unlimited, rate-limited only to 10 requests/minute (aiRateLimit in shared.ts). That's a reasonable design when marginal cost is $0. It becomes a real liability the moment each message has a per-token price:
Proposed caps (pick one model tier, then set the cap so worst-case COGS per user stays well under that tier's revenue):
| Tier | Suggested cap | Worst-case cost @ Haiku | Worst-case cost @ Sonnet 5 |
|---|---|---|---|
| Free | 0 msg/mo | — | — |
| Standard (€2.99/mo) | 100 msg/mo | $0.53 | $1.06 |
| Premium (€4.99/mo) | 400 msg/mo | $2.12 | $4.24 |
| Coach / Club | 1,000 msg/mo | $5.30 | $10.60 |
400 msg/mo on Premium is generous — over 13/day, far past what a real prep session needs — while keeping worst-case COGS at Haiku pricing under half of that tier's net revenue ($2.12 of about $4.63 at €4.99) even if every single Premium user maxes it out every month (which none will in practice) — and the spend ceiling stops it at $2.495 regardless. This is a five-minute change: add a monthly counter next to the existing per-minute rate limiter, same pattern as consumeDaily in entitlements.ts.
The infra docs already priced this out (PRODUCTION.md): a dedicated GPU-attached box (CCX43 + GPU, for Ollama) runs ~€250/mo (~$270) — fixed, regardless of volume. A natural upgrade target is Qwen3-14B (same open family as today's 3B model, ~5x the parameters), which needs that GPU to run at usable latency — the current CPU box already struggles at 3B (~18 tok/s, and the codebase notes qwen3:4b was tried and rejected for flooding the CPU with unsuppressable reasoning tokens).
| Path | Fixed cost | Marginal cost | Breakeven vs. Haiku metered |
|---|---|---|---|
| Keep CPU box, swap to Haiku 4.5 API | $0 extra | ~$0.0053/chat msg | — |
| Dedicated GPU box, self-host Qwen3-14B | ~$270/mo | $0 | ~51,000 chat msgs/mo |
$270 ÷ $0.0053/msg ≈ 51,000 My Second chat messages/month to break even against metered Haiku. Cross- referencing the scale table above: only the 10,000-user heavy-usage scenario (78,750 msgs/mo) clears that bar. Every lighter scenario, and every milestone below 10,000 users, is cheaper on metered API.
Recommendation on this path: don't provision the GPU box speculatively. Ship on a metered frontier model now (zero fixed cost, scales down to zero if adoption is slow), and revisit self-hosting only once real telemetry shows sustained chat volume approaching ~50k messages/month — at which point the GPU box also stops being "risk," and starts being an obviously-correct cost optimization on proven demand. This also sidesteps the current architecture's other real problem: the local LLM shares 4 vCPUs with Stockfish analysis, so heavier chat use today would slow down game analysis for everyone, not just cost money.
Users have exactly one provider, Claude Haiku. Admin requests can still be routed another way: with AI_ADMIN_PROVIDER unset they go through the ai-coach service’s chain in a fixed order — Groq, Gemini, Claude — which returns on the first success. Claude is third, so on that chain it is reached only when the other two fail; AI_ADMIN_PROVIDER=claude pins it. Every call is costed in ai_usage, priced at Haiku 4.5’s $1/M input and $5/M output. A free account’s monthly AI Coach allowance (BETA_FREE_MONTHLY_CAP) is 1: one AI Coach run a month.
The trial that led to Haiku for every user ran from 2026-09-05 to 2026-10-02; its write-up is in the git history of this page.
stripe_customer_id rows, 1 second_analysis_runs row. The analyses count in this line was wrong: it recorded 2,037 ai_coach_analyses rows as "in the last 30 days" when that was the ALL-TIME total. Usage figures on this page are now read live from /api/admin/ai-strategy/stats rather than transcribed, which is the only durable fix — see tests/adminfreshness.test.ts, which fails the build if a hand-typed analyses-per-30d figure reappears here.billing.html, terms.html, pricing-data.js, AiSpendCaps.ts and the feature matrix (until then this page used the Terms' $4.99 / $9.99). Revenue is taken net of Spain's 21% VAT; model costs converted at $1 = €0.891 (ECB, 2026-10-02). Credit packs (€4.99/500, €14.99/2000, €7.99/1500+bundle) from MY_SECOND_README.md. The post-beta review limits (0/2/5 a month, REVIEW_LIMIT_* in aiCoachRoutes.ts) only apply if BETA_FREE_MODULES is turned off; the monthly counts above apply now.AI_COACH_MONTHLY_CAPS / AI_CHAT_MONTHLY_CAPS in config.ts; ceiling from SPEND_FRACTION in AiSpendCaps.ts; unit costs from the ai_usage ledger (24 AI Coach calls, 5 chat calls). All of it re-derived by tests/haikuforall.test.ts.SCALING.md / PRODUCTION.md.ai-coach-service/src/api/routes.py (chess_query) and ai-coach-service/src/services/verbalizer.py.