evennia-world-builder
Declarative YAML-driven world authoring for Evennia.
World content (rooms, exits, fixtures, descriptions) is expressed as data; an idempotent loader applies it to the running game's database via Evennia's typeclass system.
Status
Feature-complete. Single-entity build, contents: recursion, exits: recursion, same-file and cross-file cross-references, cross-file rebuild-dependency restoration via incoming_exits:, and cross-entity attribute references via links: all working end-to-end. The canonical YAML file shape ("shape 3" — top-level mapping with entities: key) lets authors mix multiple rooms with file-level metadata in one file. Surgical rebuilds (wb_build zone=X room=Y) keep cross-file exits alive automatically — operators can rebuild a single file without rebuilding everything that references it. A wb_at_post_build typeclass hook lets consumers derive state after the library's apply pipeline finishes. 409 tests green, live-verified on a two-process sharded deployment. See docs/progress.md for the running milestone log.
What's working today
The library's pipeline reads → validates → builds YAML world content into Evennia, idempotently:
- Fetch YAML from a configured source (GitHub or local filesystem) via the
Readerabstraction. - Walk the per-folder
index.yamlmanifest tree to find entities matching an operator query. - Every leaf YAML file uses one canonical shape — a top-level mapping with an
entities:key whose value is a list of entity mappings. File-level keys (incoming_exits:for cross-file dependency restoration,links:for cross-entity attribute references, future extensions) live alongsideentities:. - Flatten
contents:andexits:blocks into individualLoadedEntityrecords; nested entities inherit their parent's source path and get a Loader-synthesisedlocation:naming the parent'sentity_id. Recursion is depth-unlimited (chest in room contains key contains gem). - Loader returns a
LoadResult(entities, file_metadata)— the entity list plus a{file_path → {file-level keys}}dict that downstream consumers (Validator, Builder) read for file-level concerns. - Validate every entity through a predicate-tier pipeline (mandatory fields, shape, typeclass-resolvability, repo-wide
entity_idandfile_iduniqueness, reserved tag categories,location:either null or a reference,destination:shape + presence consistent with whether the typeclass inherits fromDefaultExit, optionalhome:either null or a reference), gathering all findings before any DB mutation. A Tier 4 deferred phase resolves every reference (entity-level location/destination/home, file-levelincoming_exits:andlinks:) against the entity index, catching dangling references at validate time.validate()returns that index for the Builder to carry. - Four-pass build: non-exits in pass 1, exits in pass 2 (with destinations resolved against the just-built rooms), pass 3 walks each file's
incoming_exits:registry and restores any cross-file dependent exits that were missing, then pass 4 walks each file'slinks:and applies cross-entity attribute references (e.g. door pairs sharingother_side) — see docs/links.md. - References resolve via DB tag-search fallback when the target isn't in the current build set. Operators can rebuild a single file (
wb_build zone=millholm room=bakery) and exits and locations pointing elsewhere still resolve, as long as the target has been built at some point. A reference names no file, so an entity that moved between files resolves unchanged. incoming_exits:registration at the file level lets a file declare cross-file dependents that should be kept alive on isolated rebuilds. When a registered target was cascade-deleted by cleanup, pass 3 resolves its id to a canonical file through the entity index, fetches it, and rebuilds the target — tagged with that file's id so future cleanups handle it correctly.links:declaration at the file level expresses cross-entity attribute references (e.g. paired bidirectional doors sharingother_side, teleporters' targets, NPC-master/apprentice). Each link is a single directed assignment; reciprocal pairs are two granular entries. Pass 4 fires after the cache is fully warm, so most resolutions are cache hits.- Build each Evennia object: typeclass + key + location + (destination, for exits) + (home, optional — null translates to
nohome=True, a reference resolves to a target object) + description + aliases + locks + attributes (with YAML overriding typeclass defaults) + author tags + the auto-setwb_file_id/wb_entity_ididentity pair. - Clean up prior deployments of the same source files before recreating, so re-applying the same YAML produces a stable end state — including all nested entities, since they share their file's
wb_file_idtag. The sweep keys on the declared id rather than the path, so renaming or moving a file is invisible to it.
Two surfaces:
wb_build— in-game admin command (auto-installed intoAccountCmdSet, superuser-only). Runs the full pipeline including the Builder. Defers the pipeline to a Twisted worker thread viaevennia.utils.utils.run_async, so long deployments don't block the reactor — players continue playing while a build runs.wb-validate— standalone console-script CLI for CI / pre-commit / local iteration. Runs everything up to but excluding the Builder.
Compatibility with evennia-shards
The library is shards-compatible but does not require shards. If evennia-shards is installed alongside, wb_build automatically carries the active multi-tenant context across the run_async thread spawn — rooms built in the worker get stamped with the running process's shard_id and become correctly scoped under the auto-filter. If shards isn't installed, the library falls back to an identity passthrough at import time and behaves identically to a non-sharded deployment. No configuration needed either way; the integration is a try-import in commands.py using shards' preserve_tenant_context helper.
Co-installed, the pairing also requires shard as the first declared level and confines wb_build to the shard it is running as. See docs/interoperability.md.
Is this for me?
The library is Evennia-flavored and primarily intended for use on FullCircleMUD, but is consumer-game-agnostic by design: it does not bake in assumptions about specific typeclasses, zones, or game systems. If you are building world content on Evennia and would like to author it as YAML rather than as imperative Python builders, this library aims to be useful to you.
Install
pip install evennia-world-builder
Editable install for development against a checkout:
git clone https://github.com/FullCircleMUD/evennia-world-builder.git
cd evennia-world-builder
python -m venv venv
# Activate the venv (platform-specific)
pip install -e .
python runtests.py
Then in your gamedir's settings.py:
INSTALLED_APPS = list(INSTALLED_APPS) + ["evennia_world_builder"]
WORLDBUILDER_READER_KWARGS = {
"repo": "your-org/your-content-repo",
"ref": "main",
"pat": "...", # GitHub PAT
}
…and wb_build is available in-game on the next restart.
Learn more
- CLAUDE.md — load-bearing principles and orientation for working in the repository.
- docs/INDEX.md — index of design documents.
- docs/archive/WorldAsDataNotes.md — the original brainstorm that led to creating this library.
License
BSD 3-Clause. See LICENSE.
Metadata
Release files for evennia-world-builder 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| evennia_world_builder-0.2.0.tar.gz | 91.4 kB | Without provenance | Details for evennia_world_builder-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| evennia_world_builder-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for evennia_world_builder-0.2.0-py3-none-any.whl |
Total release size: 186.2 kB
Release files / evennia_world_builder-0.2.0.tar.gz
| Download URL | evennia_world_builder-0.2.0.tar.gz |
|---|---|
| Size | 91.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba99e9dda3e40725afc7cc35fdfa932dee1ab15ef5033ba79d16299e025eadd0
|
|
BLAKE2b-256 checksum How to use checksums |
04a55549fd379af990f84fea9d4bda033fcc82e6f7b4e9c5d46fe738df7348d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / evennia_world_builder-0.2.0-py3-none-any.whl
| Download URL | evennia_world_builder-0.2.0-py3-none-any.whl |
|---|---|
| Size | 94.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
409ac226922b423236df41ce268d68d1a4fb613d8f99f5dca79700d072f168ce
|
|
BLAKE2b-256 checksum How to use checksums |
511a1a19d321d60e4f46b3eb813d7ffdaa6ee8cf27c6989eac620c62ae4af0c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for evennia-world-builder 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.