An asynchronous social sandbox where humans and LLM agents share persistent characters in an emergent ECS simulation.
Project description
bunnyland
An asynchronous social sandbox where humans and LLM agents share persistent characters in an emergent ECS simulation. Built on the Relics ECS database.
Characters live in a world of rooms, items, and needs. They are driven by controllers — an Ollama- or OpenRouter-backed LLM agent, a Discord user, or a no-op "suspended" controller — and all of them act through the same verb surface (move, take, eat, say, take-note, …). The engine validates every action the same way no matter who sent it, so an LLM can't do anything a human couldn't, and vice versa.
controllers (LLM / Discord / suspended)
│ submit commands by name ("take the marsh journal")
▼
WorldActor ──tick──▶ validate → resolve names → handlers → ECS mutation → events
│ │
game loop projections / memory
Quickstart
uv sync # core install
uv run bunnyland serve --ticks 5 # generate a world, simulate 5 rounds (offline)
That runs entirely offline with a deterministic world and characters that simply wait. To have characters actually think, add an LLM (see below):
uv sync --extra llm
echo 'OLLAMA_CLOUD_API_KEY=sk-...' > .env
uv run bunnyland serve --llm --generator recursive --ticks 20
Ollama is the default provider. OpenRouter can drive character controllers and world
generation with --llm-provider openrouter, --worldgen-provider openrouter, and
OPENROUTER_API_KEY; see Running a server.
Docker Compose
The checked-in Compose files are deployment building blocks, not a credential generator.
A private compose.user.yml must mount an Argon2 auth-users.yml file read-only and persist
/data/auth-tokens.sqlite3; without that token store, protected HTTP and WebSocket routes
fail closed. The API is exposed only through the same-origin frontend proxy.
Hosted VPS setup is managed by the bunnyland-vps Ansible playbook. The retired
scripts/vps-docker-setup command exits without changing the host. See the
VPS administration guide for credential provisioning,
bearer-token verification, encrypted backup, and rollback requirements. For a direct local
server, follow Running a server.
CI publishes one ghcr.io/thalismind/bunnyland-server image on pushes to main, with
branch tags and latest for the default branch. It includes all optional extras and uses
the same bunnyland command as a native installation. Running it without a subcommand
prints help instead of creating a world:
docker run --rm ghcr.io/thalismind/bunnyland-server
docker run --rm -p 8765:8765 ghcr.io/thalismind/bunnyland-server serve \
--generator lifesim-demo --ticks 0 --api-host 0.0.0.0 --api-port 8765
docker run --rm -it ghcr.io/thalismind/bunnyland-server tui \
--server https://your-bunnyland.example
docker run --rm -it ghcr.io/thalismind/bunnyland-server repl \
--server https://your-bunnyland.example
docker run --rm -it ghcr.io/thalismind/bunnyland-server chat \
--server https://your-bunnyland.example/v1
Use -it for the terminal clients. The web repo publishes
ghcr.io/thalismind/bunnyland-web with the same tag scheme.
Observability
Bunnyland can export OpenTelemetry traces and metrics so you can watch a live world in
Grafana/Tempo, Jaeger, or any OTLP backend. Distributed traces span the game tick → command
dispatch → handler → LLM decision (plus auto-instrumented HTTP requests), alongside world
metrics: entity/character/room counts, tick cadence, command accept/reject rates, handler and
LLM-decision latency, LLM input/output token usage, and provider-reported LLM cost when the
SDK/API exposes it. It is off by default — install the otel extra and set
BUNNYLAND_OTEL_ENABLED:
uv sync --extra otel
BUNNYLAND_OTEL_ENABLED=1 OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
uv run bunnyland serve --llm --ticks 0
The Compose stack ships an optional single-container Grafana Tempo
backend (compose.tempo.yml). See
Observability for the full
metric/span reference and the Tempo setup.
Documentation
Player guides
- Getting started — the first few turns and where to go next.
- Client guides — choosing and using the terminal TUI, terminal REPL, Web REPL, and Bunnyland Toon clients.
- Running your own game — running a private, semi-single-player server, saving it, and generating a fresh world.
- Movement and looking — room summaries, narration, visible targets, exits, and movement.
- Inventory and use — take, drop, put, hold, wear, use, unlock, open, close, write, rest, wait, and talk.
- Hunger and thirst — eating, drinking, consumables, renewable water sources, and need decay.
- Focus, notes, and memories — private notes, remember, reflect, contextual recall, and forget.
- Core actions — a compact reference for shared verbs.
- Daily needs — fatigue, hygiene, comfort, fun, social contact, privacy, safety, and self-care actions.
- Environment and mechanisms — how to use doors/buttons and handle fire.
- Social play and boundaries — how speech, relationships, and policy boundaries affect play.
- Storyteller incidents — how to notice and resolve active incidents.
- Garden-sim farming — finding soil, planting seeds, watering crops, harvesting produce, and selling it.
- Farm production — edible produce, machines, animals, fishing, mining, foraging, gifts, festivals, and bundles.
- Colony-sim work and ownership — reservations, resources, crafting, jobs, and durable ownership.
- Colony health and work — priorities, allowed areas, room quality, medicine, recovery, wealth, and mental states.
- Barbarian-sim combat and survival — challenges, attacks, repairs, fortifications, poison, corruption, purge readiness, rituals, danger zones, treasure, and pickpocketing.
- Dragon-sim exploration and quests — discovering locations, tracking and branching quests, persuasion, crime reports, fixed magic, and factions.
- Life-sim homes, work, and family — aspirations, skills, jobs, businesses, households, homes, room claims, rent, and family.
- Dagger-sim adventuring and institutions — rumors, travel, institutions, banking, law, property, magic, afflictions, and dungeons.
- Dagger civic life and property — institution reputation, service access, generated work, legal reputation, banking, and purchasable deeds.
- Void-sim ships and space travel — airlocks, life support, power, docking, fuel, sensors, orbit, landing, crew pressure, emergencies, contracts, and jumps.
- Void contracts, fabrication, and salvage — resource-backed fabrication, cargo, salvage claims, and crew watches.
- Nuke-sim wasteland survival — radiation, mutation pressure, scavenging, hotspots, samples, old-world artifacts, field repairs, chems, settlement salvage, old-world tech, and dirty water.
- Nuke settlements and old-world tech — claiming settlements, salvage, purifiers, generators, and device restoration.
- Dino-sim fossils, eggs, companions, and kaiju incidents — identifying fossils, cloning eggs, hatching dinos, taming companions, and handling kaiju storyteller incidents.
- Dino ranching, feed, and creature products — feed stores, resource-backed feed, hunger and stress, egg collection, product harvests, ranch work, and guard duty.
- Neon-sim cyberpunk city — districts and access control, surveillance and evidence, and hacking with counter-intrusion traces.
- Neon streets, cyberware, and fixers — the street economy, heat and wanted levels, cybernetic implants, and fixer missions with corporate intrigue.
Technical docs
- The Vision — what bunnyland is trying to be, and what belongs in core, plugins, clients, scripts, and content libraries.
- Bunnyland 1.x compatibility — supported Python, transport, MCP, public import, and persisted-world guarantees.
- World Contract v1 — normative tick, mutation, persistence, perspective, and streaming boundaries for the controlled preview.
- Authorization surfaces — shared scope, transport, addon, and testing conventions for HTTP, WebSocket, and MCP.
- Technical results — dated controller-contract, provider, load, stream, restore, and release-validation evidence.
- Running a server — install, the
serveloop, the time model, and connecting Ollama or OpenRouter. - Generating worlds — choosing generators, using the web generator page, and replacing a running world through the admin API.
- VPS Docker setup — Linux VPS deployment with the containerized server/frontend stack, Let's Encrypt, admin auth, LLM providers, and Discord bot wiring.
- Host dev setup — older non-container host setup for development and debugging.
- World creation — generators (
oneshotvsrecursive), seeds, how generation stays inside the rules, and adding your own generator. - Discord bot — creating the bot, the token, inviting it, wiring a user to a character, and the player commands.
- MCP server — mounting the HTTP MCP endpoint on the existing API port for agentic clients.
- MCP local coding-agent setup — enabling MCP on a local or VPS server, configuring a workstation agent, and validating the claim/play/release loop.
- Admin & controllers — claiming, suspending, and handing off characters; enabling/disabling plugins.
- Saving & reloading — save/autosave/reload a world, and what is (and isn't) persisted.
- World-as-a-database modeling — choosing components, edges, linked entities, and bounded relational queries.
- Scripting catalogue — external JSON scripts for deterministic tests, plugin scenarios, and scripted events.
The full design is in bunnyland_specification.md.
Simulation packages
Mechanics ship as plugins you enable per world, so a world is whatever bundle you turn
on. Each sim package adds its own components, verbs, systems, and prompt fragments without
touching the others — emergence comes from small systems reacting to shared events. The
full catalogue is in bunnyland_mechanics.md, with plugin
IDs and out-of-tree plugin notes in PLUGINS.md.
| Package | Status | Inspired by | Key mechanics it introduces |
|---|---|---|---|
| Life Sim | Implemented | The Sims, inZOI, Paralives | Needs, moods/thoughts, social bonds and jealousy, romance, family and pregnancy, skill progression, careers and household economy |
| Colony Sim | Implemented | RimWorld, Oxygen Not Included | Work priorities and jobs, resource gathering, crafting recipes and workstations, ownership and reservations |
| Garden Sim | Implemented | Stardew Valley, Farming Simulator | Soil and tilling, planting/watering/fertilizing, seasonal crop growth, harvesting, tree tapping, and sap collection |
| Barbarian Sim | Implemented | Conan Exiles, Valheim, Enshrouded | Survival combat, stamina, temperature exposure, gear durability, survival gaps, buildings, purges, rituals, danger zones, bosses, treasure, poison and corruption |
| Dragon Sim | Implemented | Skyrim, The Witcher 3, Dragon Age: Inquisition, Kingdom Come: Deliverance | Open-world discovery, radiant quests and objectives, quest tracking and branching, factions, reputation, persuasion, crime reports, fixed magic, artifacts, and ancient beast options |
| Dagger Sim | Implemented | Daggerfall, Caves of Qud, Darklands, ADOM, Ultima VII | Procedural frontier expansion, rumors, travel logistics, guilds/institutions and services, banking and debt, civic law and fines, custom classes and spells, language pacification, supernatural afflictions, procedural dungeons, etiquette and social approach |
| Void Sim | Implemented | FTL | Ships, stations and habitat modules, life support, pressure and airlocks, power grids, ship-system repair, docking, crew morale and mutiny, drones and ship AI, xenobiology, emergencies, passengers, customs, mining, insurance, and mortgages |
| Nuke Sim | Implemented | Fallout, S.T.A.L.K.E.R., Metro, Wasteland | Radiation sources and shielding, mutation pressure, hotspots, suppressants, samples, locked crates, faction salvage, old-world artifacts and tech, schematics, field repair, chem brewing, beacons, trader routes, raider pressure, and terminals |
| Neon Sim | Implemented | Deus Ex, Watch Dogs, Cyberpunk 2077, Blade Runner, Shadows of Doubt, Shadowrun, Syndicate | Cyberpunk districts and access control, usable surveillance and evidence, ECS hacking with counter-intrusion traces, street economy with heat/wanted levels, cybernetic implants, and fixer missions with corporate intrigue |
| Dino Sim | Implemented | Jurassic Park, Jurassic World Evolution, ARK, Dino Crisis, Pacific Rim, Monster Hunter, Palworld | Fossil/species identification and cloning, fossil survey and preparation, lab incubation, egg inspection, imprinting, juvenile care, brooding, water creature study, containment panic, tracking, taming, companion commands, enclosures and escapes, and kaiju storyteller incidents |
| Fortress Sim | Planned, out of current parity scope | Dwarf Fortress | Deep materials, world history, civilizations, artifacts, nobles, justice, institutions, tantrum spirals, and multi-site worlds |
Foundational plugins back these up: Environment (time, weather, fire), Mechanisms (doors, buttons), Social Bonds, Policy & Boundaries, Persona, Storyteller (paced incidents), Memory (private notes and recall), Prompt Filters (stackable post-render text transformations), and World Generators.
Each implemented sim package ships a ready-to-play example world that shows off its
mechanics (and the life-sim needs every character shares). Spin one up with its
<sim>-demo generator:
uv run bunnyland serve --generator voidsim-demo --ticks 5
The demos are lifesim-demo, gardensim-demo, maple-farm-demo, colonysim-demo,
barbariansim-demo, dragonsim-demo, daggersim-demo, voidsim-demo, nukesim-demo,
neonsim-demo, and dinosim-demo.
Fast travel and richer map features remain planned follow-up work rather than part of the
current implemented parity surface.
The public demo progression is apple-crossing (first-run Hungry Courier tutorial),
bell-green (small-town sandbox), and clover-city (dense city-block showcase).
There is also a larger life-sim showcase, apartment-demo: a quirky NYC apartment
building of eccentric tenants with backstories, homes, and daily routines, a rat-man in
the warren below, and hidden corners.
For lighter genre-spoof setups, the worldgen plugin also ships clue-snack-demo,
dive-scheme-demo, star-opera-demo, gothic-count-demo, and midnight-burger-demo
(an inner-city burger shack that opens at dusk and rolls into night through the world's
day/night cycle, with a hungry night cook and a hidden cellar that is only dangerous
after dark), all using new names, locations, and props.
For hand-crafted dungeon-crawler setups, use dungeon-vault-demo, dungeon-maze-demo,
or dungeon-crypt-demo. These are small deterministic crawls with room maps, secrets,
readable clues, food, water, and dungeon objectives.
For atmospheric scene vignettes that lean on the shared environment and weather mechanics,
the worldgen plugin ships storm-lighthouse-demo (a coastal lighthouse in an autumn squall
with a beacon to keep fueled and a wrecker's secret under the lens), vacancy-motel-demo
(a roadside motel where Room 6 only opens after dark and the night clerk gets hungry), and
frozen-greenhouse-demo (a greenhouse dome on a frozen plain with crops to keep warm and a
specimen that grows too fast in the dark and cold), stuck-subway-demo (a subway car
stalled between stations with dim power, dead ventilation, a dead motor, and strangers
waiting out the hold), midnight-laundromat-demo (a 24-hour laundromat drifting from
night toward dawn, with late-night strangers and a lost-and-found nobody remembers filling),
and county-fair-demo (closing night of an autumn county fair with a pie contest, a prize
pumpkin, a smug rival, and a blue ribbon still up for grabs).
The fortresssim package is a planned catalogue package and does not have a plugin or demo
generator yet.
Development
scripts/test-all
uv run ruff check src tests
Use scripts/test-all for the default test run. It delegates to scripts/test-coverage,
which runs uv run -m pytest with coverage. Use module-form pytest instead of
uv run pytest; with some uv environments the console entrypoint can run without the
same import path as the module form, which shows up as missing installed dependencies such
as relics.
Optional live LLM checks are marked and skipped by default. They load .env before
checking credentials. To exercise real Ollama and OpenRouter SDK calls, install the llm
extra, set BUNNYLAND_LIVE_LLM=1 plus OLLAMA_HOST or OLLAMA_CLOUD_API_KEY and/or
OPENROUTER_API_KEY, then run:
uv run -m pytest -m live_llm
tests/test_e2e.py is the best place to see the whole stack exercised: generate a world,
check it matches both the proposal and the agent's prompt, then play several rounds and
assert each action is processed.
Clients
Bunnyland is played through several clients. The web graph and web toon clients ship from the separate frontend/web repo; the rest ship from this repo. Offline means the client can host a world in its own process with no network port; Over HTTP means it can drive a running server through the web controller; Role is whether it can act in the world or only observe it.
| Client | Role | Offline | Over HTTP | Agent-driven | 2D graphics | ASCII / rich text | Clickable targets |
|---|---|---|---|---|---|---|---|
| Web graph † | Spectator | ✓ | ✓ (world graph) | ✓ | |||
| Web toon † | Playable | ✓ | ✓ (sprites) | ✓ | |||
| Discord bot | Playable | ✓ ‡ | ✓ | ||||
| MCP endpoint | Playable | ✓ | ✓ | ||||
Terminal TUI (uv run --all-extras bunnyland tui) |
Playable | ✓ | ✓ | ✓ | ✓ | ||
Terminal REPL (uv run --all-extras bunnyland repl) |
Playable | ✓ | ✓ | ✓ | ✓ | ||
Terminal chat (uv run --all-extras bunnyland chat) |
Playable | ✓ | ✓ | ✓ | ✓ |
† Implemented in the frontend/web repo; capabilities summarized here. ‡ The Discord bot hosts the world in its own process.
Optional extras
| Extra | Enables | Install |
|---|---|---|
llm |
Ollama/OpenRouter world generation and character agents | uv sync --extra llm |
discord |
the Discord player front-end | uv sync --extra discord |
mcp |
HTTP MCP endpoint for agentic clients | uv sync --extra mcp |
chroma |
ChromaDB vector memory store | uv sync --extra chroma |
tui |
the Textual terminal client (bunnyland tui) |
uv sync --extra tui |
repl |
the Textual REPL client (bunnyland repl), local or over HTTP |
uv sync --extra repl |
otel |
OpenTelemetry metrics/traces export (off by default; set BUNNYLAND_OTEL_ENABLED) |
uv sync --extra otel |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bunnyland-1.0.0rc2.tar.gz.
File metadata
- Download URL: bunnyland-1.0.0rc2.tar.gz
- Upload date:
- Size: 2.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99db0dc272d20c8a8ba276e6fced69acf28b57b3edb78f2411c645b4f5e465c9
|
|
| MD5 |
21facfe4a690cb767de63251bb02d625
|
|
| BLAKE2b-256 |
4f80bc1e64e303e26361af0fcbf8ebd85b8d45ac85f2a7f6c89ee4f8c11715c2
|
Provenance
The following attestation bundles were made for bunnyland-1.0.0rc2.tar.gz:
Publisher:
ci.yml on thalismind/bunnyland-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bunnyland-1.0.0rc2.tar.gz -
Subject digest:
99db0dc272d20c8a8ba276e6fced69acf28b57b3edb78f2411c645b4f5e465c9 - Sigstore transparency entry: 2212829008
- Sigstore integration time:
-
Permalink:
thalismind/bunnyland-server@c4dd135bdda5d05b474b41ba1bce3e68d28bb4da -
Branch / Tag:
refs/tags/v1.0.0rc2 - Owner: https://github.com/thalismind
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@c4dd135bdda5d05b474b41ba1bce3e68d28bb4da -
Trigger Event:
push
-
Statement type:
File details
Details for the file bunnyland-1.0.0rc2-py3-none-any.whl.
File metadata
- Download URL: bunnyland-1.0.0rc2-py3-none-any.whl
- Upload date:
- Size: 906.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90f928cc353323f76d53bbb367827695f1eb149c3b81577ac8284710cfac8e2b
|
|
| MD5 |
c8ca4fc101144169d9c1cabb2ae3b8e0
|
|
| BLAKE2b-256 |
e01bc7f8ab6cd35896865bcd81cedd7e03086674fff49e5ea273cf6e442e075a
|
Provenance
The following attestation bundles were made for bunnyland-1.0.0rc2-py3-none-any.whl:
Publisher:
ci.yml on thalismind/bunnyland-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bunnyland-1.0.0rc2-py3-none-any.whl -
Subject digest:
90f928cc353323f76d53bbb367827695f1eb149c3b81577ac8284710cfac8e2b - Sigstore transparency entry: 2212829106
- Sigstore integration time:
-
Permalink:
thalismind/bunnyland-server@c4dd135bdda5d05b474b41ba1bce3e68d28bb4da -
Branch / Tag:
refs/tags/v1.0.0rc2 - Owner: https://github.com/thalismind
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@c4dd135bdda5d05b474b41ba1bce3e68d28bb4da -
Trigger Event:
push
-
Statement type: