Skip to content

Repository files navigation

Township

Put a civic question in a living pixel town. Watch AI residents reason, talk, disagree, and change their minds.

Explore the live demo · Read the docs · Add a resident or scenario

Backend CI Frontend CI Zero-key smoke test MIT license Static demo

The living town of Dover from above: residents go about their routines, the camera closes on two neighbors talking through the election in readable speech bubbles, one changes their mind with a burst of confetti, then dusk settles and lamplit night falls

Township is an open-source engine for making civic deliberation visible. A scenario package defines the question, options, towns, fictional residents, local context, and news beats. The Python engine runs a configurable sequence of seed → converse → news → opinion → decide; a typed event stream brings every walk, conversation, reaction, and opinion shift to a React + Phaser world.

It is designed for research, education, media literacy, and agent development, and it is deliberately easy to inspect: personas are Markdown, scenarios are JSON, runs are portable event logs, and a deterministic mock runs the whole pipeline without credentials.

Important

Township is a simulation, not a poll. Its outputs do not measure real public opinion and must never be presented as if they do. Residents are fictional composites and every output is an LLM artifact. Read Responsible Use before creating or publishing a real-world scenario.

The District Atlas: a pixel overworld built from the towns' own tileset, with framed town vignettes, nameplates, and a hover card showing Montclair's leading option The replay player paused mid-conversation in Dover, the camera close enough that a resident's recorded line is readable in its speech bubble, with the timeline transport below Chatting with Maria Santos in Dover: the visitor asks what candidates should understand about Dover and she answers in her own voice beside the live town canvas
Open the storybook atlas
The overworld is drawn from the towns' own tiles; hover a town for its cast and leading option.
Scrub the recorded run
Pause any beat of a replay and read the dialogue where it happened.
Talk to a resident
They answer in voice, remember you, and warm up — or don't.
God's View results after injecting a healthcare-premium scenario: current versus projected opinion donuts and per-resident reaction cards for Dover and Montclair The district dashboard mid-run: a round progress bar, live district-wide sentiment counts, per-town stance donuts, and top issues while the simulation streams Dover at night in the replay player: lit windows, lamplight, and residents still out on the streets
Ask "what if"
God's View injects a hypothetical and shows every resident's reaction, before and after.
Watch the district live
Stances shift town by town mid-run; a narrative recap lands when it ends.
Stay past dusk
One world clock drives lighting, routines, windows, and lamplight in every town.

Why Township

  • A world, not a spreadsheet. Residents follow routines through distinct towns, meet at local landmarks, speak in-world, react to news, and carry their changing stance into a district dashboard.
  • Scenario-first by construction. Candidates, budget choices, places, personas, and news live under scenarios/<id>/—never hardcoded in the engine.
  • Zero-key from the first clone. The deterministic mock exercises every phase and powers offline tests. The Pages demo replays committed runs with no backend and no API calls.
  • Live and replay share one path. Both publish the same discriminated event union, so a saved run drives the same pixel town and charts as live inference — and successful persistence leaves each run under runs/ as a portable event log, structured summary, and (when generation succeeds) narrative recap.
  • Bring the model you trust. Bedrock, Anthropic, OpenAI, OpenRouter, Ollama, LM Studio, and the built-in mock implement one provider contract.
  • Human-readable agents. Each resident is one Markdown file with structured frontmatter, prose voice, routines, concerns, goals, and relationships.

Meet a few residents

Fictional composites authored as people rather than demographic rows, with portraits cropped from the sprite sheets that walk through the live town.

Carlos Restrepo
Carlos
Restrepo
Maria Santos
Maria
Santos
Miguel Hernandez
Miguel
Hernandez
Rosa Chen
Rosa
Chen
Jordan Williams
Jordan
Williams
Vikram Iyer
Vikram
Iyer
Jen Russo
Jen
Russo
Mike Brennan
Mike
Brennan
Frank DeLuca
Frank
DeLuca

Try it in two minutes

Requirements: Python 3.11+ and Node ^20.19.0 or >=22.12.0.

git clone https://github.com/StevenWang-CY/township.git
cd township
make install
SCENARIO=millbrook-budget make demo

Open localhost:8001. make demo builds and serves the complete app with the deterministic mock provider: offline, free, and with no .env file required. Use make dev for backend/frontend hot reload on ports 8001 and 5173. If uv is installed, make install honors the committed lock exactly; pip remains the supported fallback.

Prefer the terminal?

township run --scenario millbrook-budget --provider mock

That command runs the full deliberation and, when the best-effort finalization steps succeed, prints a recap and leaves a portable artifact in runs/<run_id>/. Useful next commands:

township scenarios
township replay --demo --scenario nj11-2026

The Python wheel is intentionally API/headless-only (CLI + scenario packages, no compiled web UI); use the Docker image or this source checkout for the full application. The hosted demo is a static replay player — zero network model calls, recorded runs clearly labeled; live chat, new simulations, voice, and God's View need a local backend.

What you can explore

Surface What it reveals
Living town The landing view: routines, weather, time of day, conversations, gossip, gestures, and opinion ripples rendered in Phaser
District atlas A storybook pixel overworld drawn from the towns' own tileset — vignettes, nameplates, and each town's cast and leading option
Resident chat In-character conversation with private relationship context, trust, voice hooks, and a capability-protected personal journal
Dashboard Cross-town patterns, issue fault lines, conversations, and stance trajectories
God's View A transparent intervention sandbox for asking how agents react to a hypothetical development
Replay timeline Pause, seek, change speed, or jump between rounds in a recorded run

How it works

flowchart LR
    P["Scenario package<br/>JSON + Markdown"] --> O["FastAPI orchestrator<br/>towns run in parallel"]
    O <--> L["LLM provider<br/>or deterministic mock"]
    O --> E["Typed event stream<br/>WebSocket + EventBus"]
    E --> W["React + Phaser<br/>town, chat, dashboard"]
    E --> R[("Portable run<br/>events + summary<br/>recap when available")]
    R --> Q["Replay"]
    Q --> E
Loading

The frontend's simulation timeline sees exactly what the event log sees; Pydantic event models in the backend mirror a TypeScript discriminated union in the frontend, guarded by a contract test. Recorded, live, headless, and visual runs are different views of the same simulation—not products that can drift.

Read the architecture guide for the prompt pipeline, wire contract, persistence model, cost accounting, and module-by-module tour.

Author a civic world

Scaffold a package that already loads and lints:

township new-scenario school-boundary-vote
township new-agent school-boundary-vote townsville --name "Maya Brooks"
township run --scenario school-boundary-vote --provider mock
scenarios/school-boundary-vote/
├── scenario.json              # question, options, rounds, news, town order
├── towns/*.json               # place, demographics, landmarks, map metadata
├── options/*.json             # arguments, positions, evidence, sources
├── agents/<town>/*.md         # fictional resident personas
├── context/*.json             # logistics or other shared evidence
└── god-scenarios.json         # optional intervention presets

The package can describe an election, a budget, a zoning hearing, a school-board decision, or another shared civic choice. The engine does not know the names of your towns or options. Start with the complete scenario format, the persona authoring guide, or copy the fully annotated persona template.

Providers

Set LLM_PROVIDER explicitly, or leave it unset and Township will detect a configured credential before falling back—loudly—to mock.

Provider LLM_PROVIDER Credential / endpoint
Deterministic mock mock None
AWS Bedrock bedrock AWS_BEARER_TOKEN_BEDROCK or the standard AWS credential chain
Anthropic API anthropic ANTHROPIC_API_KEY
OpenAI API openai OPENAI_API_KEY
OpenRouter openrouter OPENROUTER_API_KEY
Ollama ollama Local OpenAI-compatible endpoint
LM Studio lmstudio Local OpenAI-compatible endpoint

Source installs and the Docker image include the OpenAI client; a plain wheel install needs pip install 'township[openai]' for the OpenAI-compatible four. Concurrency, model IDs, prompt caching, endpoints, CORS, and deployment options are documented in Deployment and .env.example. Secrets belong only in environment variables.

Included scenarios

Scenario Cast What ships
The Millbrook Surplus 8 residents · 2 towns A fictional direct-democracy vote over a one-time $12M surplus, plus a zero-cost mock replay. It proves the engine is not election-specific.
NJ-11 Special Election 26 residents · 4 towns A retrospective of the certified April 2026 race, with a complete Bedrock/Claude replay and a published error analysis.

The shipped NJ run, without spin

The included NJ-11 replay contains 883 events, 405 model calls, 1,501,405 metered token units, and zero failed agents. Its provider usage after generating the recap was $7.3298; the district summary, finalized just before that last recap call, records $7.3192.

The 26 fictional characters ended at 19 Mejia, 5 Hathaway, 0 Bond, and 2 undecided. Those are character states, not votes, percentages, a sample, or a forecast. The NJ-11 retrospective compares the run with certified results and documents selection bias, consensus drift, turnout blindness, and where the simulation failed. The exact event log is committed with the scenario, so the claims are reproducible.

Repository map

Path Purpose
backend/core/ Pydantic domain models, scenario/persona loading, wire DTOs, storage, EventBus
backend/simulation/ Multi-round loop, multi-town orchestration, replay, recap, run persistence
backend/providers/ Bedrock, Anthropic, OpenAI-compatible, local, and mock adapters
backend/routes/ Simulation, chat, God's View, scenarios, towns, journal, runs, voice
frontend/src/game/ Phaser world, resident sprites, clock, weather, routines, capture hooks
frontend/src/components/ Map, town, chat, journal, dashboard, replay player, accessibility controls
scenarios/<id>/ All domain-specific content and optional demo replay
tests/ Offline backend, provider, persona, scenario, CLI, replay, and wire-contract tests

Documentation

Contributing

Personas are the best first contribution: they need empathy and local texture, not Python. Scenarios add whole new civic worlds; engine, research, frontend, art, accessibility, and documentation work are equally welcome.

Read CONTRIBUTING.md, choose a good first issue, or propose a new resident or scenario. Community participation follows the Code of Conduct.

Citation, license, and provenance

Township is released under the MIT License. Cite the software using CITATION.cff; academic work building on its generative-agent architecture should also cite Park et al., Generative Agents (UIST 2023), as recorded in that file.

Vendored and derivative pixel assets remain subject to their asset-specific licenses and documented provenance qualifications. Every source, modification, and license is listed in THIRD_PARTY_NOTICES.md. Press and project media include the social preview and the brand kit.


Township — AI residents. Real trade-offs. A living town.

Build a town worth listening to.

About

AI residents deliberate civic questions in a living pixel town — a replayable, scenario-first simulation engine.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages