Five AI agents with persistent, evolving memory predict FIFA World Cup 2026 — inside a cinematic 16-bit-inspired pixel-art arcade cabinet. Zero databases. All state lives on Walrus mainnet.
▶ Live Demo — taken.wal.app · Architecture · Memory Design · API Reference · Demo Script
Hackathon entry for the Walrus Memory World Cup · Deadline: June 24, 2026
For Judges — Start Here · Why Moneyball Stands Out · Judging Criteria Map · How Walrus Memory Is Used · Architecture · The Five Agents · Data Sources · Published SDK · MemWal SDK Feedback · Quickstart · Deployment · Demo · Team · Security · License
30-second orientation. Everything below is live on Walrus mainnet — no local setup needed.
-
▶ Open the live demo: taken.wal.app — click any agent to open its dossier. No wallet required; guest mode is full-featured.
-
🧠 See the Memory Moment — open Sofia Mendes → "Day1 vs Now". Her Brier score improved 0.722 → 0.547 (−0.175, lower = better) after a memory-driven evolution, with the exact parameter deltas that produced it:
-
🔗 Verify it on-chain — agent memory lives in a
MemWalAccountshared object on Sui mainnet:0x265869e1…0046e5. The UI also surfaces a Walrus blob link on every memory event. -
📋 Map to the rubric — the Judging Criteria Map below pre-fills your scorecard (C1 Memory · C2 Creativity · C3 Technical), each row anchored to evidence in this repo.
-
🧭 Want the full guided walkthrough? See
docs/JUDGES.md— a 10-minute, step-by-step tour.
Multi-agent memory evolution + zero-database architecture + published open-source SDK — all in one project.
Most prediction apps wrap a single LLM in a chat interface. Moneyball is fundamentally different:
- 🧠 5 specialized AI agents, each with a unique mathematical model — not LLM wrappers, but deterministic prediction engines (Bayesian statistics, contrarian inversion, expected value, narrative sentiment, classical astrology)
- 📈 Agents measurably evolve over time. A sleep/evolve cycle computes Brier scores, per-topic calibration errors, and user disagreement pressure → parameter drift. Day 1 agents are provably different from Day 4+ agents. Every mutation is a Walrus blob.
- 🗄️ Zero databases. No PostgreSQL, no Redis, no Supabase, no IndexedDB. MemWal on Walrus mainnet is the sole persistent storage layer. The in-memory read-model rebuilds from MemWal on every cold boot.
- 📦 Published npm SDK. We extracted production-tested MemWal patterns into
@moneyball-ai/memwal-utils— a reusable open-source package for any builder working with MemWal. - 🐛 13 SDK issues filed upstream on MystenLabs/MemWal — bug reports, feature requests, and documentation gaps discovered during production use.
- 🕹️ 16-bit-inspired pixel-art arcade cabinet built with Phaser 3 — interactive props (TV, coffee machine, flower), animated agent personas with thought bubbles, strict design system enforced by automated tests (no gradients, no rounded corners, pixel-perfect).
- 🎫 Retro pixel ticket generator — shareable 8-bit match tickets with predictions, agent weights, and Walrus blob IDs for social virality.
- 💾 Crash-resilient write journal — JSONL journal on disk ensures pending MemWal writes survive Render cold boots. No provenance gaps, even on ephemeral free-tier hosting.
- 🔒 HMAC-signed guest identity — prevents IDOR spoofing without requiring wallet connection.
- ✅ 567 automated tests (356 FE + 211 BE) with CI design guards (
designDrift.test.tsblocks emoji/gradients/border-radius;contrastWcag.test.tsenforces WCAG AA).
| Criterion | How Moneyball Delivers | Evidence |
|---|---|---|
| C1 · Memory Depth & Authenticity | 5 agents run sleep/evolve cycles: Brier score + per-topic calibration → parameter drift. Day 1 ≠ Day 4. Every mutation is a Walrus blob with provenance badges ([SEED]/[LIVE]). User disagree history persists per Sui wallet. |
docs/memory-design.md · GET /api/public/agents/:id/evolution |
| C2 · Creativity & Flair | 16-bit-inspired pixel-art arcade cabinet (Phaser 3). 5 animated agent personas with thought bubbles. Interactive props. Retro pixel ticket generator for social sharing. Strict design system — no gradients, no rounded corners, pixel-perfect. | docs/design-spec.md · tokens.ts · RetroTicket.tsx |
| C3 · Technical Execution | MemWal is the sole durable store — zero traditional databases. 567 automated tests. Deterministic evolution engine (no LLM in the prediction pipeline). Published npm SDK. HMAC-signed guest identity. Durable JSONL write journal survives cold boots. | packages/memwal-utils · CI pipeline · writeJournal.ts |
Moneyball uses MemWal SDK as its only persistent storage layer. Every agent prediction, parameter evolution, and user interaction flows through a rate-limited write queue to Walrus mainnet blobs. After matches resolve, a deterministic reflection engine computes calibration errors (Brier scores, per-topic accuracy, user disagreement pressure) and adjusts agent parameters — then persists the new version to MemWal. The result is a verifiable, append-only memory trail where every parameter change traces back to specific prediction outcomes stored on-chain.
| Capability | Implementation |
|---|---|
| Persistent predictions | Match picks, confidence, reasoning, outcomes → MemWal blobs on Walrus mainnet. Clickable blob verification links in the UI. |
| Sleep & evolve cycle | Deterministic reflection engine (Brier score, per-topic accuracy, disagree pressure) → parameter calibration. Capped bounds prevent runaway drift. |
| Auditable evolution | Every parameter change links to specific prediction events. Timeline scrubber + before/after overlay in the Memory Moment UI. |
| User memory | Disagree history, interaction milestones persisted per Sui wallet. Agents roast returning users by memory. |
| Provenance badges | Every event in the UI is tagged [SEED] (baseline fixture) or [LIVE] (real MemWal write) — judges always know what's real. |
| Zero-database architecture | MemWal is the sole durable store. MemWalWriteQueue handles rate limits, coalescing, and exponential backoff. In-memory read-model rebuilds from MemWal on cold boot via restore(). |
| Crash-resilient writes | JSONL write journal on disk ensures pending MemWal writes survive Render cold boots — no provenance gaps. |
flowchart LR
M["Match resolved<br/>(result + score)"] --> R["Reflection Engine<br/>(Brier score, per-topic<br/>accuracy, disagree pressure)"]
R --> D["ParamDelta[]<br/>(confidenceBias, hedgingLevel,<br/>topicCalibration)"]
D --> E["Evolution Engine<br/>(CAS versioning,<br/>hard-bound clamping)"]
E --> W["MemWal blob<br/>(immutable on-chain)"]
W --> P["Updated AgentParams<br/>(version N+1)"]
P -->|"shifts picks"| PR["Next prediction<br/>(draw band, EV bar,<br/>consensus threshold)"]
P -->|"shifts confidence"| C["Calibrated confidence<br/>(raw × multiplier + bias)"]
style M fill:#4a6741,color:#fff
style W fill:#8b6914,color:#fff
style PR fill:#6b4226,color:#fff
Memory affects behavior, not just logs. Three agents (Dr. Morgan, Viktor Kane, Sofia Mendes) have their decision thresholds shifted by evolved parameters — a loss streak measurably changes future picks. Scout Alvarez and Madame Pythia are intentionally unaffected: the scout's gut and the oracle's stars don't recalibrate.
Each evolution is recorded as a versioned, dated event with the exact parameter deltas — surfaced in the in-app Evolution tab:
A pnpm monorepo with five packages:
graph LR
Browser["React 18 + Phaser 3<br/>(apps/frontend)"]
Server["Express + Socket.io<br/>(apps/backend)"]
Sleep["sleep-worker<br/>(pure TS package)"]
Shared["packages/shared<br/>(types + socket contract)"]
Utils["@moneyball-ai/memwal-utils<br/>(npm published)"]
MemWal["MemWal Relayer<br/>↓ Walrus Mainnet"]
Browser -- "REST + WebSocket" --> Server
Server -- "in-process import" --> Sleep
Server -- "remember / recall" --> MemWal
Server --> Shared
Server --> Utils
Browser --> Shared
Sleep --> Shared
| Package | Stack | Purpose |
|---|---|---|
apps/frontend |
React 18, Phaser 3, Vite, Zustand, @mysten/dapp-kit | Pixel-art cabinet scene, HUD, agent modals, wallet connect |
apps/backend |
Express, Socket.io, MemWal SDK | REST API, WebSocket world, match pipeline, auth, memory |
sleep-worker |
Pure TypeScript | Reflection engine, evolution engine, param versioning |
packages/shared |
TypeScript | Typed socket events, shared schemas |
packages/memwal-utils |
TypeScript (npm) | Rate-limited write queue, KV overlay, key builder |
Full C4 diagrams: docs/ARCHITECTURE.md
Click any agent in the cabinet to open its dossier — an 8-tab modal (Overview · Method · Predictions · Evolution · Day1 vs Now · Memory · Journal · Chat):
Each agent uses a distinct, deterministic prediction model — no LLM calls in the pipeline. Agents marked with 🧬 have their picks shifted by memory evolution (T38):
| Agent | Methodology | Evolves picks? | Personality |
|---|---|---|---|
| Dr. Morgan | Weighted metrics: teamStrength + homeAdvantage → margin → pick | 🧬 hedgingLevel widens draw band |
Academic statistician. Trusts the numbers — but learns humility. |
| Scout Alvarez | Narrative sentiment: live team form (api-football) or matchday hash | — | Old-school scout. Gut feeling over spreadsheets. |
| Viktor Kane | Contrarian inversion: fades consensus when confidence is high | 🧬 confidenceBias shifts threshold |
Provocateur. The more the crowd is wrong, the bolder he gets. |
| Sofia Mendes | Expected value: true probability vs. Bet365 odds → value bet | 🧬 topicMultiplier raises EV bar |
Sharp bettor. Demands bigger edges on poorly-calibrated topics. |
| Madame Pythia | Deterministic mysticism: Pythagorean numerology + classical astrology | — | Enigmatic oracle. The stars are immutable. |
All five agents participate in a weighted consensus for each match. After match resolution, the sleep-worker runs the evolution engine: Brier score metrics + per-topic calibration errors → parameter deltas → new parameter version persisted to MemWal via CAS (compare-and-swap). For three agents, these evolved parameters feed back into the prediction engine — shifting borderline picks, not just confidence percentages.
Moneyball is honest about what is real and what is synthetic. Every model input declares its provenance via GET /api/public/data-source, surfaced in the UI so users and judges are never misled.
| Input | Source | Detail |
|---|---|---|
| Team strength | Live | FIFA World Ranking mapped to [0.30, 0.70]. 48 WC2026 teams. |
| Match schedule & results | Live | football-data.org v4 API, polled every 120s. |
| Team form (narrative sentiment) | Live | Last 5 match results from api-football.com. Fallback to matchday-salted hash. |
| Bookmaker odds | Live | 1X2 odds from Bet365 via api-football.com. Used by Sofia Mendes for EV calculation. Fallback to synthetic model. |
| Home advantage | Manual | Fixed +0.04 term. A hand-set constant, not measured. |
GET /api/public/data-sourcereports provenance at runtime. Currently: 3 of 4 inputs use live data feeds.
We extracted the production-tested MemWal patterns from Moneyball into a reusable open-source package:
npm install @moneyball-ai/memwal-utilsimport { MemWalWriteQueue, KvOverlay, createKeyBuilder } from '@moneyball-ai/memwal-utils';
const queue = new MemWalWriteQueue(rememberFn);
queue.enqueue('prediction:match-1', JSON.stringify(data)); // non-blocking, coalescedWhat's inside:
- MemWalWriteQueue — coalescing write queue with exponential backoff and 429-aware retry
- KvOverlay — key-value semantics (get/put/CAS) over MemWal's append-only store
- createKeyBuilder — type-safe key construction with namespace prefixes
Full documentation: packages/memwal-utils/README.md
We filed 13 issues on MystenLabs/MemWal based on building Moneyball — covering missing features, SDK bugs, and documentation gaps:
| # | Issue | Author | Status |
|---|---|---|---|
| #312 | feat(sdk): semantic top-K |
alexbelij | Open |
| #311 | feat(sdk): surface blob_id on recall() results |
alexbelij | Open |
| #298 | bug: RecallManualResult union type mismatch |
alexbelij | Open |
| #297 | feat(sdk): TTL option for remember() |
alexbelij | Open |
| #296 | docs: undocumented rate limits and quotas |
anna-stolbovskaja | Open |
| #295 | bug(sdk): SEAL SessionKey 5-min TTL silent failures |
anna-stolbovskaja | Open |
| #294 | feat(sdk): control analyze() fact extraction |
anna-stolbovskaja | Open |
| #293 | bug(sdk): recall() positional overload type error |
anna-stolbovskaja | Open |
| #292 | feat(sdk): structured metadata on remember() |
anna-stolbovskaja | Open |
| #291 | feat(sdk): cursor-based pagination for recall() |
anna-stolbovskaja | Open |
| #290 | feat(sdk): cursor-based pagination (duplicate) |
anna-stolbovskaja | Closed |
| #289 | feat(sdk): exact-match / key-based recall |
anna-stolbovskaja | Open |
| #288 | feat(sdk): exact-match recall (duplicate) |
anna-stolbovskaja | Closed |
See
docs/walrus-memory-integration.mdfor the full lessons-learned reference with workarounds for each issue.
Last verified:
main@e6a496b(2026-06-24) — 567 tests passing (211 backend + 356 frontend)
- Node.js >= 18 (20+ recommended)
- pnpm >= 8
git clone https://github.com/anna-stolbovskaja/moneyball.git
cd moneyball
pnpm install
cp apps/backend/.env.example apps/backend/.env
# Edit .env — at minimum set JWT_SECRET (>= 32 chars)
# Terminal 1 — backend
pnpm dev:backend
# → http://localhost:3001, prints "Server listening on port 3001"
# Terminal 2 — frontend
pnpm dev:frontend
# → http://localhost:5173| Variable | Required | Purpose |
|---|---|---|
JWT_SECRET |
Yes | Sign/verify JWTs (>= 32 chars) |
MEMWAL_KEY |
For MemWal | Ed25519 delegate key from memory.walrus.xyz |
MEMWAL_ACCOUNT_ID |
For MemWal | Account ID on the MemWal relayer |
STORAGE_BACKEND |
No | file (default, local dev) or memwal for Walrus-backed persistence (set in production) |
FOOTBALL_DATA_TOKEN |
For live matches | football-data.org v4 API key |
Full variable reference: apps/backend/.env.example
pnpm -r typecheck # all 5 packages# Frontend — 356 tests
pnpm --filter @moneyball/frontend test
# Backend — 211 tests
pnpm --filter @moneyball/backend test
# Sleep-worker — regressions + simulation
pnpm -C sleep-worker exec tsx test/regressions.ts
pnpm -C sleep-worker exec tsx test/simulation.ts| Component | Platform | URL |
|---|---|---|
| Frontend | Walrus Sites (mainnet) | taken.wal.app |
| Backend | Render (free tier) | taken-api.onrender.com |
Production deployment guide: docs/deploy.md
Step-by-step demo script covering the full match → predict → resolve → evolve cycle:
docs/demo-script.md (2:45 video script with preconditions and shot-by-shot breakdown)
moneyball/
├── apps/
│ ├── frontend/ # React 18 + Phaser 3 SPA
│ │ ├── src/components/ # AgentModal (7 tabs), RetroTicket, HUD
│ │ ├── src/phaser/ # Pixel-art cabinet scene, sprites
│ │ ├── src/styles/tokens.ts # Design system — colors, fonts, spacing
│ │ ├── src/lib/ # journalEntries, explorer, formatDate
│ │ └── test/ # 356 tests incl. designDrift + contrastWcag
│ └── backend/ # Express + Socket.io server
│ ├── src/agents/ # AgentEventService, sleepService
│ ├── src/memory/ # MemWalWriteQueue, writeJournal, UserSummaryStore
│ ├── src/http/ # API routes, auth, rate limiting
│ └── test/ # 211 tests
├── packages/
│ ├── shared/ # Typed socket contract + schemas
│ └── memwal-utils/ # Published npm package (write queue, KV, keys)
├── sleep-worker/ # Deterministic evolution engine
│ ├── src/reflection/ # Brier score metrics → ParamDelta[]
│ ├── src/evolution/ # CAS parameter versioning
│ └── src/sleep/ # SleepWorker orchestrator
├── docs/ # Architecture, memory design, API, deploy, demo
├── adr/ # Architecture Decision Records
├── .github/workflows/ci.yml # CI: typecheck + test + design guards
└── render.yaml # Render deploy blueprint
Moneyball Cabinet is built and submitted by a two-person team:
- Anna Stolbovskaja — @anna-stolbovskaja. This repository is the team's primary working repo (the live deployment, CI, and full commit history all live here).
- Aleksandr Khrol — @alexbelij. Co-author and collaborator across engineering and the on-chain (Walrus / Sui) integration.
Submitted as a single entry for the Walrus Memory World Cup. This repo is a fork within the team's own accounts — both members are credited above.
- Guest identity: HMAC-SHA256 signed tokens prevent IDOR (spoofing another user's guest ID)
- Auth rate limiting: Nonce and verify endpoints rate-limited by IP+address (429 on burst)
- Wallet auth: Sui personal message signature — no gas, no transaction, no private key exposure
- No secrets in client: All MemWal keys server-side only; frontend is a pure SPA
- Dependency provenance:
pnpm-lock.yamlintegrity hashes; no post-install scripts
- Branch from
mainastask/T<NN>-<slug> - Run
pnpm -r typecheck && pnpm --filter @moneyball/frontend test && pnpm --filter @moneyball/backend test - All colors/fonts must use
tokens.ts—designDrift.test.tsblocks emoji, gradients, and border-radius - All text must pass WCAG AA contrast (>= 4.5:1) —
contrastWcag.test.tsenforces this - Minimum font size: 14px (VT323 pixel font is unreadable below that)
- No Cyrillic in UI strings — judges are English-speaking
- PR to
main
MIT



