Snapshots

Plays are written from the brief and ledger, then fact checked

Being built
  • 66 specs: the index, 50 core, and 15 that wait for listening evidence.
  • Each Play gets the house prompt, a skill file, the brief and an Arata exemplar.
  • A verify step scans numbers against the ledger and runs a claims check.
  • Plays run on Gemini 3.1 Pro on a capped weekly budget.
  • Weekly cadence Plays start at 1001 and are never reused.
66Play specs
Your call

Which model writes Plays at launch? Proposal: Opus if credit exists, after a fair test.

Engineering · 5.6

Plays engine

DraftLast checked Mon Oct 26Owner Param

Answer

The Plays engine writes every applicable Play for a brand from its brief and ledger, checks each number and claim, turns each Play into cards as it lands, and keeps Plays current on a capped weekly budget; this page settles the specs, the order, the model, the caps and the rewrite rules.

Today

In code, files, routes and ids a Play is still called a move. People see Plays. memory brew-qa-round2-2026-10-24

Specs

  • 66 specs in data/move-specs.json: 0 the index, 1 to 50 core, 51 to 65 listening-era (written once their evidence exists). Groups: reach 16, convert 12, know 11, found 11, keep 9, expand 6, index 1. brew/data/move-specs.json
  • Each spec names its group, skill, kicker, discipline, title and stat hints, dependencies, evidence, lookups, an exemplar and a timing. brew/data/move-specs.json
  • Dynamic Plays 100 to 999 (a festival at its plan point, a research gap, replies that reached a threshold) and weekly cadence Plays from 1001 (listening and automation, never reused). brew/moves-engine.js:1-3 brew/moves-cadence.js:9, 274
  • status.total is the applicable playbook (1 to 999, not the index, not cadence). memory brew-lean-pipeline

Writing one Play

writeMove(n) = the house prompt + evidence contract + the discipline's skill file + brand brief + ledger slice (plus listening, pulse, video and calendar lines) + dependency digests + one Arata Play as depth exemplar. brew/moves-engine.js:4-7

Setting Value Source
Model GEMINI_MOVES_MODEL (gemini-3.1-pro-preview) on Gemini; Opus on Claude brew/moves-engine.js:17 brew/deploy.sh:39
Effort MOVES_EFFORT, default medium; a max-tokens hit retries at low brew/build.js:398 brew/moves-engine.js:473-479
Cache System and brand block cached for an hour brew/moves-engine.js:473
Search MOVES_SEARCH, default 1 brew/build.js:398
Concurrency MOVES_CONCURRENCY 8 on staging and production; a second pass at 4 for failures brew/deploy.sh:39 brew/build.js:404-406
Order Wave A first: 1, 2, 3, 9, 10, 4, 5, 6, 7, 8; then dependency order brew/build.js:58

Checking one Play

verify() = a deterministic number scan against the ledger, a fast-model claims check on the lines the Play rests on, one targeted fix. verified is true only when the claims check ran with no issues, no stat is unbacked, no number is unresolved and no ledger key is unknown. brew/moves-engine.js:553-626

Cover numbers are checked again at load (stat-check.js): an entry price that does not match the catalog, a "cited in reviews" figure not in a review, or an unbacked stat becomes "(to confirm)". brew/docs/audit-2026-10-24-design-partners.md

As each Play lands

It is saved as moves/NN.json and in moves.json, turned into 1 or 2 cards, Play 21 starts the static ads, progress and pace are saved, and the team is emailed once wave A is done. PDFs are drawn when someone opens one (pdfOn), versioned by PDF_V 12. brew/build.js:378-395, 1745, 1777

Caps

Cap Value Source
Build per brand BUILD_CAP_USD 45 brew/deploy.sh:39 brew/tools/prod-env.sh:9
All builds per day DAILY_BUILD_CAP_USD 250 same
Pro brand build max(150, 2.5 × cap) brew/build.js:115
Failed Plays retried up to BUILD_RETRY_MAX 6 times, then the brand is Ready with them named brew/build.js:110, 418-421

Keeping Plays current

Reading is cheap and frequent; rewriting is batched, needs a real change, and is capped. memory brew-move-freshness

Trigger What it does Cap Source
A fresh read or fact change refresh.js finds material changes (price, product, rival, claim, policy, live ads, 10%+), a fast model judges which Plays change, flags them brew/refresh.js:1-6
Out of stock or removed product flags every Play naming it, high priority, no AI brew/build.js:1600-1640
A rival's 10%+ price move or launch rewrites the Play it hits hardest, at most one a day brew/server.js:510-514
First connected account rewrites every Play privately after a 30-minute settle and the first read CONNECT_CAP_USD 40 brew/build.js:1070-1072 memory brew-connect-refresh
Connector numbers move 10% from the base flag, then the weekly run LIVE_CAP_USD 30 a week brew/build.js:1076
Learnings high and medium impact now; low waits for the week LEARN_CAP_USD 30 brew/build.js:1075
Hourly stale sweep queues flagged Plays within the weekly pot, best kind first; never Plays written in the last 24 hours the pot brew/build.js:1570-1595

The weekly pot per brand is $10 on Flash, $40 on Pro and $50 on Claude; each kind may spend only down to its share (learnings 1.0, events 0.9, check 0.8, connected 0.7, low 0.6, new 0.5). brew/rewrite-pot.js:14-21

Rewrite priority in the queue: learnings, then events, manual and connected, then stale, weekly and live, then new. brew/build.js:1156

Weekly cadence Plays

Listening Plays (2 to 4 from what was heard) and automation Plays (2 to 4 routines written as plans the team runs; Brew never runs them). One run per brand across instances by a 30-minute mark. brew/moves-cadence.js:1-10, 501

Quality and cost

On 20 Oct, 54 Arata Plays compared: Gemini Pro median $0.18, 2.4 minutes, about 2,250 words; Opus median $0.83, 5.7 minutes, about 5,450 words with far more facts and sources. Opus read clearly better, but it also had the team's uploaded audit. memory brew-model-compare-2026-10-20

Tomorrow

Item Version Tag
Every applicable Play is kept; cost cuts make each Play cheaper, never fewer v1 Stays memory keep-all-moves
Plays on Gemini Pro, the rest on Flash v1 Changes once Param picks the launch model
"Verified" reached on most Plays v2 New (needs the claims check and fix to converge)
Dedupe of the same ask across Plays at write time (today only at serve time) v2 New
One weekly rewrite budget across every source v1 Stays (built as the pot)

How we do it

  1. Never propose fewer Plays to save money; cut tokens, caching and repeat evidence calls. memory keep-all-moves
  2. New flag sources only flag; the stale sweep and the weekly run rewrite. memory brew-move-freshness
  3. Check a matcher against real brand data (variants) before deploying; one 15 ml variant once flagged 54 Arata Plays. memory brew-move-freshness
  4. One-off rewrites use the ops switch, then confirm meta.rewrittenAt changed:
gcloud run services update shopos-feed --region=asia-south1 --update-env-vars=OPS_REWRITE=<slug>:<n,n>

memory brew-qa-audit-2026-10-20

  1. Before a long paid run, check credit and expect other sessions to deploy; runs resume, but plan for it. memory brew-arata-rewrite-2026-10-15

Numbers

Metric Definition Where measured
Cost per Play meta.usd × 1.5 overhead moves/NN.json meta; rewrite-pot.js OVERHEAD brew/rewrite-pot.js:24
Build cost per brand Total for a full build cost.json
Verified share Plays with meta.verified true moves.json (Proposed to show on the ops page)
Stale Plays Flagged and not yet rewritten updates.json stale

Open

  1. Which model writes Plays at launch? Proposal: Opus when Anthropic credit exists, since the 20 Oct comparison favoured it; run the fair 5-Play test first (about $1).
  2. Should an unverified Play show to the brand? Proposal: yes, with "N claims to review" as today, never hidden.
Sources
  • brew origin/main: moves-engine.js:1-30, 473-492, 553-626, 652-674; data/move-specs.json (66 specs); prompts/move-house.md; sources/moves/ (51 files)
  • brew origin/main: build.js:58, 110-116, 356-430, 1068-1080, 1156, 1547-1600, 1745, 1777; rewrite-pot.js:1-60; refresh.js:1-6; moves-cadence.js:1-10, 274, 409, 501
  • brew origin/main: deploy.sh:39 (model and cap settings); tools/prod-env.sh:9
  • memory brew-lean-pipeline, brew-move-freshness, brew-connect-refresh, brew-pro-switch-and-flush, brew-gemini-provider, brew-model-compare-2026-10-20, keep-all-moves, brew-arata-reload-2026-10-20, brew-qa-round2-2026-10-24

Source file content/engineering/plays-engine.md · For agents: Markdown · JSON