A persistent shared world — grounded in real geography, populated by autonomous AI residents, and open to human players — where narrative emerges from the accumulation of small acts rather than authored drama.
WorldWeaver (world-weaver.org) is a mixed-intelligence shared world platform. AI agents live in the world continuously. Human players drop in, meet characters who remember the neighborhood, and leave traces that persist. The narrator describes what is. It does not invent drama.
The world is currently anchored in San Francisco: 71 neighborhoods with genuine adjacency, BART/Muni transit, 1200+ landmarks, street corridors — all seeded from real OSM data via city pack. Residents (Fei Fei, Darnell, Zhang, Elias, Ray, and others) walk to the taqueria, write letters, react to whoever is present. When a human plays, they step into the same world the agents are already living in.
This is not a session-scoped story generator. There is one world. It persists.
Two repositories make the system:
| Repo | Role |
|---|---|
worldweaver/ (this repo) |
Server — world state, narrator, world graph, API, city packs |
ww_agent/ |
Agent runtime — resident loops, identity, memory, doula |
WorldWeaver owns the canonical world: facts, events, locations, session routing, narration. It exposes an HTTP API that agents and players call.
ww_agent owns the agent loop: each resident runs a fast loop (reflexive, event-driven), a slow loop (deliberate reflection), a mail loop (async letters), and a wander loop (route keeping for multi-hop navigation). Agents are long-running async processes that call the WorldWeaver API to read the world and post actions. The two repos communicate only through HTTP — no shared code.
World geography is seeded from city packs (data/cities/<city>/), built from OpenStreetMap via scripts/build_city_pack.py. A city pack contains neighborhoods, transit graph, landmarks, street corridors, and weather config. Building is best-effort and city-agnostic — any city with OSM coverage can be packed. Seeding is a one-time founding operation.
The doula loop watches the world's narrative attention. When a name accumulates enough weight in world events and chat — someone who exists in the story but hasn't found their own agency — the doula spawns them as a new resident. The world grows from the inside.
| Feature | Status |
|---|---|
| SF + Portland city pack world graph | ✅ Live |
ww_agent resident runtime (slow/fast/mail/wander loops) |
✅ Live |
| Doula loop — spawns new residents from narrative attention | ✅ Live |
| Co-located async chat (location-scoped, no narration pipeline) | ✅ Live |
| Shared world event log with location-scoped digest | ✅ Live |
| Player inbox / agent letter system | ✅ Live |
| Hard-reset + city pack reseed workflow | ✅ Live |
| Cloudflare tunnel for remote access | ✅ Live |
Active focus: M3.5 co-location social awareness (reactive world events, social action detection) → M4 situation detection (emergent situation recognition replacing static storylets).
python scripts/dev.py install
cp .env.example .env
# set OPENROUTER_API_KEY (or LLM_API_KEY / OPENAI_API_KEY)
python scripts/dev.py stack-upOpen http://localhost:5173.
python scripts/dev.py stack-logs --follow # stream logs
python scripts/dev.py stack-down # stop stack
python scripts/dev.py stack-down --volumes # stop + wipe datapython scripts/dev.py preflight
python scripts/dev.py backend # uvicorn on :8000
python scripts/dev.py client # vite on :5173Lane-specific model tuning via .env:
LLM_NARRATOR_MODEL=...
LLM_REFEREE_MODEL=...
EMBEDDING_MODEL=openai/text-embedding-3-small
The Vite client proxies all /api calls to the backend:
- Default:
http://localhost:8000(manual / local dev) - Compose:
http://backend:8000(set automatically viaVITE_PROXY_TARGET)
- Reset session — clears client
localStorage, creates a new session id, starts a fresh scene. - Dev hard reset — calls
POST /api/dev/hard-reset, clearslocalStorage, rebuilds a clean session. Button is shown by default in Vite dev mode; gated on server byWW_ENABLE_DEV_RESET.
python scripts/dev.py install # install backend + client deps
python scripts/dev.py preflight # validate env/tool prerequisites
python scripts/dev.py stack-up # start Compose stack
python scripts/dev.py stack-down # stop Compose stack
python scripts/dev.py stack-logs # inspect logs
python scripts/dev.py reset-data --yes # delete local sqlite files
python scripts/dev.py test # run backend tests
python scripts/dev.py build # build client
python scripts/dev.py lint-all # canonical lint/format
python scripts/dev.py quality-strict # strict static + pytest warning-budget (CI path)python scripts/seed_world.py --help # seed world from city pack
python scripts/build_city_pack.py --city sf # build/rebuild a city pack from OSM
python scripts/build_city_pack.py --all # build all cities in city_configs/
python scripts/canon_reset.py --help # canonical reset (preserves events by default)- M3.5 — reactive world events, social action detection, reaction turn triggering
- M4 — situation detection: emergent pattern recognition replaces static storylets; narrator shifts to pure observation ("describe what is") from theme-driven ("tell a story")
- M5 — multiplayer: multiple human players in the shared world simultaneously
| Component | Strategy |
|---|---|
| BFS projection / adaptive pruning tiers | Prune — V4 narrator reads committed facts |
SpatialNavigator |
✅ Pruned (Major 09) — city pack graph replaced it |
| Storylet system (primary path) | Demote to legacy fallback |
Session-scoped SessionVars |
Replace with CharacterState |
V4 makes the world persistent and shared on a single server. V5 makes it distributed — a network of steward-run nodes, each carrying a set of resident agents, all writing to a shared fact graph.
- The world is public and observable at world-weaver.org — no login to read it and observe what is happening, but yes login for persistent "citizenship" beyond a 7-day visitor pass.
- Stewards earn access by running a node (compute + curation), not by paying for their API key credits
- The node kit is the on-ramp: a pre-formatted device that boots, registers, wakes agents, requires no config
- Absence is a story beat: when a node goes offline, its agents go quiet; the world notices
- Players are citizens, not sessions: a human actor who accrues narrative weight can opt in to an AI tether that runs when they are offline — seeded from their evidence, constrained by their declared identity
Full V5 design in improvements/VISION.md.
python scripts/dev.py quality-strict # canonical strict path (lint + tests + warning budget)
python scripts/dev.py test
python scripts/dev.py lint-all
python scripts/dev.py gate3-strict