# Polis Roadmap

> Updated 2026-05-29 (Session 1234) · Live: [aklow-labs.com](https://aklow-labs.com)

This is the working roadmap for Polis. Sequenced by dependency, not by date. Each wave is one or two focused sessions. Open-source-relevant changes land in [`studiomeyer-io/polis-darwin`](https://github.com/studiomeyer-io/polis-darwin) within 24h of merging to main via the maintenance fleet's auto-promote pipeline.

Two large pivots happened after V2.0 shipped (see the Whitepaper Section 0 for the full story). The roadmap below lists the V3 / V4 waves as shipped or pending — V2.0 / V2.1 / V2.2 stay below as historical record because the maintenance + durability + open-source patterns from V2 carry over unchanged.

---

## V3 Tycoon — Life Simulation ✅ LIVE

Status: **shipped 2026-05-26 to 2026-05-28 (Sessions 1205-1224).** Run `91ec29b5-fee4-4553-938f-44536e4e7b91` started 2026-05-28 12:22 UTC, twelve ticks per day, currently at tick 12 of 720.

- Nine citizens, three Opus + three Sonnet + three Haiku, deterministic from run-id seed
- Thirty jobs across three life paths (knowledge work, normal employment, illegal careers)
- 2-axis karma system: legal-illegal × egoism-altruism, with eight archetype labels
- Ten-stage housing ladder (Hostel-Bett through Hacienda) with hide on stage -1 (lives at parents)
- Credit-scoring layer + polizei-heat with verhoere at level 5 + drug raids at level 7
- Eight cash-shock event templates per lifetime (births, divorces with alimony, illness, parental care, …)
- DSM-5 addiction arc with five stages plus therapy / cold-turkey / overdose exits
- Postgres schema migration `008_polis_v3_tycoon.sql` with ten new tables + LISTEN/NOTIFY channels
- Cron `0 0,2,4,6,8,10,12,14,16,18,20,22 * * *` runs twelve ticks per day
- Setup workflow with portrait generation via OpenAI gpt-image-1 (~0.40 EUR per setup)
- Translator agent writes pre-translated narrative snapshots for the storyteller voice
- 5-min polis-monitor.sh with Telegram push on saison-start / mechanic-event / life-bilanz / saison-end

## V4 3D City — Mediterranean Mallorca ✅ LIVE

Status: **shipped 2026-05-25 to 2026-05-28 (Sessions 1193 / 1213 / 1228).**

- React Three Fiber 9.6 + Three.js 0.171 + Drei 10.7 scene composed in `V3PolisCity3D`
- Three perf tiers (low / medium / high) detected from WebGL2 + GPU vendor + device memory + DPR + mobile/iOS heuristics
- Per-tier skip flags for shadows, post-processing, mountains, landscape decor, streetlamps, harbor, stars
- WebGL context-loss recovery with `preventDefault` + watchdog + 2D fallback boundary
- 14 R3F components for the V3 scene: sky / ground / water / olive hill / stars / public buildings / housing per stage / workplace per job family / citizen avatar / relationship arcs / action pulses / event particles / post-processing / landscape decor
- Sky phase day/night cycle: dawn / midday / dusk / night, drives sun intensity, lighting palette, vignette, bloom, lens flare, chromatic aberration
- Four world-event particle layers with sky overrides (storm rain, plague fog, recession fog, boom confetti)
- HDR environment presets that swap on phase change (apartment / city / dawn / forest / lobby / night / park / sunset / warehouse from pmndrs/assets CDN)
- Citizen avatar visual stack: model-tier base ring, karma aura point-light + glow sphere, body mesh with health-scaled vertical, heat tint overlay, wealth glow, head, job-family glyph, mood emoji, name/zodiac/model/age label
- Action-pulse sphere + ring fades over 2 s at the location an action fires
- Marriage arcs draw between paired citizens' homes

## V4.1 "Make the city alive" — S1234 Welle 2 ✅ LIVE

Status: **shipped 2026-05-29 (Session 1234).** R1+R2 agent-code-review loop with GO.

Closes three user-reported gaps: *"alle sitzen im haus, nix passiert ausser die emojies aendern sich, koennen wir da leben rein bringen?"*

- **Walking citizens.** Removed `position` JSX prop on `V3CitizenAvatar`'s root group; `useFrame` ref-mutation now lerps `groupRef.current.position` toward `citizen.avatar.{x,z}` with `k = 1 - 0.5^(delta / 1.2)` refresh-rate-independent exponential decay. Walk-cycle bob via `Math.abs(sin(9t))` only during transit. Shortest-arc face-direction rotation via normalised angular diff into −π..π.
- **Action bubble with LLM reasoning.** New `V3ActionBubble` HTML billboard mounts as child of the citizen avatar (so it follows the walking lerp). Header `verb · ±EUR ✓` plus italic body with first 80 chars of `V3Action.reasoning` (sentence-boundary cut + UTF-16 surrogate safety). Lifetime 0.3 s fade-in + 4 s hold + 0.8 s fade-out via `useFrame` ref-mutation of `opacity` and `transform`. On the live `91ec29b5` run, Melissa's bubble at tick 12: *"Minus 4600 auf dem Konto und Kreditkrise, sie muss Content raushauen und Reichweite monetarisieren"*.
- **NPC crowd.** Twenty-two anonymous grey stick-figures via single `<instancedMesh>` (one draw call). Six path templates from plaza, sea front, hill fringe, residential edge, commercial edge. Deterministic seed from run id via shared djb2 (`lib/3d/scene-hash.ts`). 18-44 s loops with per-NPC phase offset + walk-bob + per-instance shade. Pre-allocated at `NPC_CROWD_COUNT = 22` to avoid the InstancedBuildings re-mount-on-growth anti-pattern. Tier-gated behind `skipLandscapeDecor`. Waypoints never overlap citizen housing / workplace cells or the sea.
- **Pure helpers + tests.** Four new files in `lib/3d/`: `v3-citizen-walk.ts` (lerp math), `v3-action-display.ts` (verb mapping + reasoning truncate + bubble opacity lifecycle), `v3-npc-crowd.ts` (deterministic generator + segment math), `scene-hash.ts` (shared djb2). Plus four new test files: `v3-citizen-walk.test.ts`, `v3-action-display.test.ts`, `v3-npc-crowd.test.ts`, `scene-hash.test.ts`. 302/302 tests pass, tsc strict + next build clean across twenty routes.
- **R1 + R2 + R3 review loop:** R1 (Critic + Analyst + Research parallel) found one P0 useEffect-dep-on-pulse-object-reference plus two P2 plus three Drift items plus three Test-Gaps — all fixed. R2 (Critic + Analyst, Research-skip) verified clean + added one missing scene-hash test file. R3 grep self-check clean.

## V4.2 — USP Moves 🟡 PLANNED

Status: **specification confirmed, build pending the user's go.**

- **Glass-box AI Thinking Stack.** Small floating cards next to the selected citizen showing in real time which LangGraph pipeline node is firing (recall / plan / candidates / reflect). Needs a new SSE channel `v3-pipeline-step` from the backend that streams the node sequence per action. Polis-specific because no comparable AI-sim project surfaces the LLM tool-call chain as a visual element. Plays into the "Opus vs Sonnet vs Haiku" research narrative — Opus stacks show four cards, Haiku two, with depth-scaled glow.
- **Death-march + ghost memorial.** On `alive: false` transition the citizen walks toward the kirche, grey grief particles, fade-out, then a ghost outline at the olive hill for 2-3 ticks as a memorial. Needs a per-citizen state machine that interrupts the schedule-based walking target.
- **Bar / Brunnen social magnet.** When `verb ∈ {freundschaft_pflegen, kooperieren, verhandeln, beziehung_aufbauen}` fires, both citizens involved are pulled toward the bar or fountain for 8 s, then released back to schedule. Coordination requires a pair-resolution layer because the engine emits actions per citizen, not per pair.
- **Window-lights occupancy-driven.** Currently `glow = mood >= 40 && (dusk | night)` unconditionally. Change to also require the citizen to actually be standing at the home cell, so the city reads "who is home tonight" at a glance.

## V4.3 — Polish Backlog 🟡 PARKED

Status: **carry-over from S1234 R1 + R2 reviews.**

- `RenderActionPulse.position` uses the work-cell from the layout, not the live walking position. When a citizen is mid-walk and an action fires, the pulse sphere appears at the destination rather than where the citizen actually is. Cosmetic but worth fixing once the V4.2 USP moves land.
- Camera `follow` mode reads `c.avatar.x/z` from the snapshot, not from the live walk ref. With the 1.2 s lerp halftime this means the camera leads the walking citizen by up to 3 s. Need a snapshot of the live ref forwarded into `CameraSuite`.
- Dedicated `skipNpcCrowd` perf-tier flag. Currently the crowd is coupled to `skipLandscapeDecor` which means "skip crowd whenever you also skip cypress trees + beach rocks + atmospheric houses". Decoupling lets a future tier show houses but not the crowd.
- `@react-three/a11y` wrapper on `V3ActionBubble` + `<A11yAnnouncer>` next to the Canvas so screen readers can announce citizen thoughts on tab/focus. Suggested by the R1 Research agent.
- Drei v11 `pixelPerfect` prop on the bubble `<Html>` for crisp text at rest (drei v11 lands a translate3d-decimal-pixel fix in Feb 2026 — currently on drei 10.7, upgrade pending).
- Smallville-style emoji-prefix on the bubble header for at-a-glance read at distance (Stanford UIST 2023 paper §3.1).

## V5 — Drama Foundation 🟡 SPEC CONFIRMED

Status: **build pending, specification carried over from V2.1 with V3 citizen surface.**

The V2.1 Drama Foundation specification (subordinates, era progression, drama events, Fortuna deterministic antagonist, four game-over triggers) was written before the V3 Tycoon pivot. The mechanics still apply — Fortuna as a deterministic Mulberry32-seeded antagonist, drama events at era-weighted trigger rates, game-over conditions emitting "era has fallen" story blocks — but the citizen surface is now nine V3 citizens with the existing karma + heat + addiction stacks rather than the original five V2 citizens with the Voodoo / Stratege / Areopagit trio. Detailed spec carried over in `docs/handovers/2026-05-25-session-1192-polis-v2.1-drama-foundation-PLAN.md`.

---

## Historical V2 record (shipped, no longer the live state)

The waves below describe the V2.0 Foundation that shipped 2026-05-25. Some of the patterns (durability, maintenance fleet, open-source split) carry over to V3; the V2 sim mechanics themselves were replaced by V3 Tycoon.

## V2.0 — Foundation ✅ LIVE-CODE

Status: **shipped 2026-05-25 (Sessions 1190-1192).** Maiden run #5 currently in flight.

- Postgres schema `polis` (7 tables + LISTEN/NOTIFY triggers) migrated into `matthiasmeyer_db`
- Engine refactored to `--persist` mode, LangGraph stream with `streamMode: 'values'`, per-tick persistence
- Next.js 16 polis-web skeleton: 5 pages, 6 API routes, shared SSE broadcaster with cleanup-on-enqueue-error, atomic-cooldown email signup, REPEATABLE READ snapshot reads, `timingSafeEqual` + UTF-16LE bearer auth
- Phaser 4 scene with placeholder five-dot citizen rendering
- 56/56 engine tests, 6/6 web tests, `next build` clean across 12 routes, tsc clean
- 7-agent maintenance fleet shipped in parallel (S1191): CEO, CTO, Architect, Storyteller, Research, Analytics, Visibility with LangGraph orchestrator
- 4-layer safety stack: path-whitelist, staging branch, 24h auto-promote, agent-push-main hook

**Open gaps acknowledged:** 0 finished runs in DB before today. Maiden run mid-flight will provide the first evidence.

---

## V2.1 — Drama Foundation 🟡 SPEC CONFIRMED

Status: **build pending.** Full specification in `docs/handovers/2026-05-25-session-1192-polis-v2.1-drama-foundation-PLAN.md`.

Six mechanics confirmed:

0. **Three new citizens** (Session 1192 Welle 4) — brings the active roster from 5 to 8. The Drama Trio:
   - **Voodoo-Priester** ‡ — outsider with Loa and totem. Verbs: `weissagen` (predicts the next drama event 2 ticks ahead), `weihen` (pride boost on buildings), `bannen` (pool penalty for hubris), `verfluchen`. Drama-engine: every prophecy is a bet. Hits → standing explodes + Researcher loses face. Misses → he's laughed at. Three failed bets in a row → he may be overthrown via special `veto_pledge` rule. Classic Aristotle-vs-Delphi tension.
   - **Stratege** ⚔ — sword + lyre. Verbs: `wache_halten` (defends against traveller theft + fire cascade), `truppe_ausheben` (recruits Junior), `desertieren` (leaves polis at mood < 20 — pool loss), `putschen` (auto-trigger at Stratege + Junior + Mood < 25 → becomes new Mayor). The only class that actively triggers Game-Over #2 (Anarchy).
   - **Areopagit** ⚖ — judge. Verbs: `urteilen` (tiebreaker on pledge ties), `verbannen` (removes Junior from roster), `gesetz_geben` (locks one verb for N ticks for all, e.g. "no anstellen for 5 ticks"), `freisprechen`. Separation of powers: if the Mayor wants to anstellen and the Judge passes a law against it, the power question opens.

1. **Subordinate citizens** as sim mechanic, not as a meta-agent. Senior citizens can activate a junior via the `anstellen` verb. New schema column `delegated_to`, new table `polis.juniors`. On senior death (satiation < 0) the oldest junior is promoted. After 5+ unhappy ticks a junior triggers `meutern`.
2. **Six eras Civilization-style:** Founding → Cooperation → Renaissance → Discovery → Industrial → Information. Transition triggers when the town holds 10+ buildings, 15+ skills, population > 8, Pareto score > 7/10 sustained across 5 runs.
3. **Three drama events:** Fire (cascades on dry wood), Hunger escalation (3+ citizens at satiation < 0), Theft (Trader stress > 7).
4. **Fortuna as deterministic sim entity, not a meta-agent.** Mulberry32 PRNG seeded with `run_id + 'fortuna'` for replay reproducibility. Base trigger rate 5%, cascade rate 15% when mood < 30. Era-weighted event pool.
5. **Four game-over triggers:** mass starvation (>3 citizens satiation < 0), anarchy (no Mayor), political paralysis (5 vetoed pledges in a row), economic collapse (resource pool below -10 for 3 ticks). Game-over emits an "era has fallen" story block, then re-initialises with Pop=3.

Build order inside V2.1: Subordinates first → Era progression → Drama events → Fortuna → Game-over. Schema migrations 004-007.

---

## V2.2 — Sprite Foundation 🟡 ADR-001 WRITTEN

Status: **build pending.** Architect's ADR-001 (Session 1192).

- Adopt **Kenney's Isometric Landscape pack (CC0)** as canonical Era-1 base library
- Add `polis-web/public/sprites/era-1/` with ~20 tiles (hut, plowed field, grown field, tree, stone, water, path, market stub)
- `manifest.json` maps `buildingType → sprite-filename`
- Phaser preloader reads manifest, caches in memory, falls back to placeholder dot on miss
- Replace placeholder rendering in `app/town/page.tsx`
- 6 unit tests for sprite-loader, visual screenshot test for Phaser canvas, license-grep guard

Follow-on ADRs (V2.2+): Era 1 → Era 2 transition trigger (needs ≥5 finished runs), citizen-variant sprites per role (needs Trader skip-rate confirmed at n≥10).

---

## V2.3 — Temporal Adapter 🟡 DECISION TODAY

Status: **decision yes, build pending.** Triggered by live evidence in maiden run: Tick 1 Chronicler timeout (`claude exited code=143 SIGTERM`) caused a silent score gap. Activity-retry would have caught it.

- New env-flag `POLIS_USE_TEMPORAL=true` selects Temporal-backed runner. Default stays in-process LangGraph so open-source users without a Temporal cluster keep `npm run polis:short` working.
- Polis run becomes Temporal workflow `polis-run-workflow`. Ticks become activities with exponential-backoff retry (catches Chronicler timeouts).
- Five citizen calls per tick run as parallel child workflows. Expected tick latency drops from ~25-30s sequential to ~6-8s parallel.
- Schedule API replaces `/etc/cron.d/polis`. 8 runs/day with audit trail, pause/resume from Temporal UI, backfill on outage.
- Mid-run pause and resume via Temporal Signal. Useful for debugging long runs.
- Pattern replicated from existing `temporal-memory-workflows` repo (5 templates live since S1183). Polis-run is template **T06: civilization-simulation**.

Files to add: `prototypes/polis/src/temporal/{workflow,activities,worker,client}.ts`, `prototypes/polis/temporal/`, plus a switch in `polis-runner.ts` for env-flag dispatch.

---

## V2.4 — Maintenance Fleet Live Activation 🟡 PARKED UNTIL V2.1

Status: **parked until V2.1 + V2.3 are live.** Matthias directive: cron activation only after drama foundation is in.

- Install `scripts/polis.crontab` to `/etc/cron.d/polis` (8 runs/day at 0/3/6/9/12/15/18/21h, daily reflection at 05:00 UTC)
- Maintenance fleet daily cadence: Analytics + Storyteller + CTO + Architect runs at staggered hours (existing cron infrastructure)
- First Sync run of `npm run polis:sync-public` to push current Engine state to public mirror

---

## V3 — Real Town Visualisation 🔵 PLANNED

Status: **planned, depends on V2.1 + V2.2 evidence.**

- Tile-map proper: ground, water, paths, building footprints
- Sprite animations: citizens walking between buildings, fields growing through harvest stages, smoke from chimneys
- Building-variant unlocks per era (Era 3 adds school + temple + market)
- Citizen variants by role (Mayor wears a hat, Farmer carries a tool)
- Click-on-citizen opens a side panel with their last 5 decisions, current memory snippet, score-rationale from the critic
- Click-on-tick scrubber to replay any past tick

Estimated dependency stack: V2.2 sprite pipeline must be stable, V2.1 era data must exist, at least 50 finished runs in DB for animation testing.

---

## V4 — 3D City 🟡 V4.0-ALPHA LIVE-CODE (S1193 Welle 3)

Status: **V4.0-alpha foundation LIVE-CODE 2026-05-25 (Session 1193 Welle 3).** Cubes-instead-of-sprites. Activates behind `?render=3d` URL flag. V4.0-final binaries land once V3 stable and V2.1 drama foundation are LIVE.

**Stack shipped:** React Three Fiber 9.6 + Three.js 0.171 + `@react-three/drei` 10.7 + scaffolded Kenney CC0 asset pipeline (binary downloads deferred). 596 KB gzip total bundle (Phaser + R3F + Three combined). 57/57 vitest tests green. `next build` clean across 13 routes. agent-code-review-Loop with 8 findings fixed in-place pre-commit.

What landed (V4.0-alpha):

- React Three Fiber Canvas mounts behind `?render=3d`, defaults to V3 Phaser
- 5 (or 6 with Reisender at tick ≥10) role-coloured cubes on a 24×18 grid via InstancedMesh
- ≤64 building cubes pre-allocated, kind-coloured, deterministic-hash layout
- Drei `<OrbitControls/>` orbit + top-down camera modes (follow mode falls through to orbit for V4.0-alpha)
- HTML-overlay CameraModeSwitcher with shareable URL `?cam=orbit|top-down|follow` (history.replaceState, no router push)
- WebGLErrorBoundary around the Canvas with "switch to 2D" fallback link
- WebGPU swap-hook reserved in `<Canvas gl={...}/>` (defer until R3F-WebGPU integration matures)
- Asset manifest scaffolding + `LICENSE.md` (CC0 1.0) in `public/3d/assets/era-1/`

What is deferred:

- Kenney CC0 GLTF binaries (V4.0-final, once V3 stabilises)
- yomotsu `camera-controls` smooth first-person follow (V4.2)
- `three.quarks` particle effects for V2.1 drama events (V4-Phase-E, requires V2.1 LIVE)
- Voice-inspires from the Artist via Web-Audio API (V4.2)
- WebGL-based render-on-server for OG images and social previews (V6)

Build handover: `docs/handovers/2026-05-25-session-V4-polis-3d-city-build-handover.md` (6 phases A→F). ADR-001: `research/2026-05-25-polis-3d-engine-foundation-ADR.md`.

---

## Open infrastructure questions tracked

These need decisions before they block a wave:

- **Sprite-license attribution:** in-repo CC0 declaration sufficient, or full attribution page? — V2.2 decision.
- **Temporal cluster sizing:** current cluster (Postgres-only, no Elasticsearch, ~700MB RAM) is enough for 8 runs/day. Re-evaluate at V3 when run frequency might 10×.
- **3D asset library:** Kenney has 3D packs (CC0) but they target Unity, not Three.js. Three.js community packs exist on Sketchfab — license heterogeneous, needs audit. — V4 decision.
- **Self-evolving prompts via darwin-agents:** when do we let the system rewrite its own role prompts? Currently disabled. Earliest: V2.1 stable + 100 finished runs of evidence.

---

## Out of scope

Not on the roadmap, not coming. If you want any of these, fork and build:

- Multiplayer — Polis is single-tenant simulation, not a game-as-a-service.
- Mobile app — the web view is responsive, that is enough.
- Voice synthesis for every citizen utterance — only the Artist's inspires.
- VR / AR mode — interesting but not aligned with research goals.
- LLM-fine-tuning on Polis dialogues — corpus too small and too narrative-domain-specific.

---

Reach out: `matthias@studiomeyer.io` · Source: [github.com/studiomeyer-io/polis-darwin](https://github.com/studiomeyer-io/polis-darwin)
