Skip to main content

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

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 serve loop, 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 (oneshot vs recursive), 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bunnyland-1.0.0rc2.tar.gz (2.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bunnyland-1.0.0rc2-py3-none-any.whl (906.6 kB view details)

Uploaded Python 3

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

Hashes for bunnyland-1.0.0rc2.tar.gz
Algorithm Hash digest
SHA256 99db0dc272d20c8a8ba276e6fced69acf28b57b3edb78f2411c645b4f5e465c9
MD5 21facfe4a690cb767de63251bb02d625
BLAKE2b-256 4f80bc1e64e303e26361af0fcbf8ebd85b8d45ac85f2a7f6c89ee4f8c11715c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for bunnyland-1.0.0rc2.tar.gz:

Publisher: ci.yml on thalismind/bunnyland-server

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for bunnyland-1.0.0rc2-py3-none-any.whl
Algorithm Hash digest
SHA256 90f928cc353323f76d53bbb367827695f1eb149c3b81577ac8284710cfac8e2b
MD5 c8ca4fc101144169d9c1cabb2ae3b8e0
BLAKE2b-256 e01bc7f8ab6cd35896865bcd81cedd7e03086674fff49e5ea273cf6e442e075a

See more details on using hashes here.

Provenance

The following attestation bundles were made for bunnyland-1.0.0rc2-py3-none-any.whl:

Publisher: ci.yml on thalismind/bunnyland-server

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page