This document provides essential context for AI models interacting with the DjangoMOO project. Adhering to these guidelines will ensure consistency and maintain code quality standards established by the project.
- Primary Goal: DjangoMOO is a modern game server for hosting text-based MOO-like games. It reimplements the core concepts of LambdaMOO on the Django framework, providing an interactive online environment where players can create, manipulate, and interact with persistent virtual objects through both web and SSH interfaces.
- Business Domain: Game Development - specifically text-based interactive fiction and MUD-like games.
- Key Innovation: Combines Django's robust ORM and admin interface with RestrictedPython's sandboxed code execution to allow dynamic verb programming within the game server itself.
- Languages:
- Python 3.11+ (primary language)
- Restricted Python for in-game verb code (compiled via RestrictedPython)
- Frameworks & Runtimes:
- Django 5.x (web framework)
- Celery 5.4+ (task queue and distributed task processing)
- AsyncSSH 2.14+ (SSH server implementation)
- uWSGI (application server)
- prompt-toolkit (interactive shell/REPL)
- Databases:
- PostgreSQL (primary data store, required for production)
- Redis (caching, Celery message broker, session storage)
- Key Libraries/Dependencies:
- RestrictedPython (sandboxed code execution for verbs)
- prompt-toolkit (interactive SSH/shell terminal experience)
- asyncssh with bcrypt (SSH authentication)
- Django SimpleSSHKey (SSH key management for user authentication)
- django-ace (ACE code editor for verb editing in admin)
- watchdog (file monitoring for development)
- Rich (formatted console output)
- ptpython (enhanced Python REPL)
- Django Celery Results/Beat (task result storage and scheduling)
- WebSSH (browser-based SSH client interface)
- Platforms: Linux (primary), Docker/Kubernetes, cloud-agnostic via Docker Compose and Helm charts
- Package Manager: uv (Python dependencies) with semantic versioning
-
Overall Architecture:
- Monolithic game server with modular components: DjangoMOO is primarily a monolithic Django application that manages the entire game state and logic. However, it's designed with clear separation of concerns:
- Core Game Engine (
moo.core): Handles objects, properties, verbs, permissions, and the fundamental MOO object model - Robust Boostrapping (
moo.bootstrap): Utilities and code to populate brand new MOO universes - Shell/SSH Interface (
moo.shell): Asynchronous SSH server providing player access via terminal - Web Interface: Django admin for wizard (administrator) access and configuration
- Task Processing (Celery): All code executions run in celery tasks, includes asynchronous operations like scheduled tasks
- Bootstrap System: Initialization of game datasets (
defaultandtest)
- Core Game Engine (
- Sandboxed Code Execution: User-written verb code is compiled and executed within RestrictedPython's restricted environment to prevent malicious or accidental damage to the server.
- Inheritance-based Object Model: Objects inherit from parent objects, forming a hierarchy similar to traditional MOO systems. Properties and verbs are inherited and can be overridden.
- Monolithic game server with modular components: DjangoMOO is primarily a monolithic Django application that manages the entire game state and logic. However, it's designed with clear separation of concerns:
-
Directory Structure Philosophy:
/moo: Main DjangoMOO package/moo/core: Core game engine, models (Object, Verb, Player, Property, Permission/ACL), and code execution/moo/core/models: Django ORM models defining the game object hierarchy, properties, verbs, permissions, and ACLs/moo/core/management/commands: Django management commands (moo_init, moo_enableuser, etc.)/moo/core/tests: Unit and integration tests using pytest
/moo/bootstrap: Dataset initialization system.default/is a package whose__init__.pyorchestrates numbered scripts (010_core_classes.py,020_utility_objects.py, ...) executed in sorted order.test.pyis a flat module providing the minimal test dataset./moo/bootstrap/default/verbs: Verb sources fordefault, organised by root-class name (player/,room/,thing/,programmer/, ...).default/verbs/tests/contains pytest integration tests for those verbs.- Bootstrap helpers
get_or_create_object,load_verb_source, andload_verbs(inmoo/bootstrap/__init__.py) are idempotent — use them instead ofObject.objects.create()in any bootstrap file intended to supportmoo_init --sync
/moo/shell: SSH server implementation and interactive prompt system/moo/settings: Django configuration modules (base.py, dev.py, test.py, local.py)/docs: End-user documentation generated by Sphinx from ReStructuredText and Markdown/extras: Non-Python support assets:/extras/helm: Kubernetes Helm 3 chart for production deployment/extras/nginx: Nginx configuration for reverse proxy routing (WebSSH, Admin, static files)/extras/uwsgi: uWSGI configuration for application server/extras/webssh: Updated WebSSH HTML template for browser-based SSH access
/tests: Integration and higher-level tests (as opposed to unit tests in modules)/static: Django static assets (CSS, JavaScript, images)
-
Module Organization:
- The core game logic is organized around Django's MVT (Model-View-Template) pattern, plus additional layers:
- Models (
moo.core.models.*): Represent game entities (Object, Verb, Property, Player, Permission) - Management Commands (
moo.core.management.commands): CLI entry points for setup and administration - Code Execution (
moo.core.code): Handles RestrictedPython compilation and verb execution - Permissions/ACL (
moo.core.models.acl): Access control list implementation for object permissions - Admin (
moo.core.admin): Django admin interface - Shell/REPL (
moo.shell.prompt): Interactive command line interface for players - SSH Server (
moo.shell.server): AsyncSSH server implementation - Bootstrap (
moo.bootstrap): Database initialization and default object creation - Mail (
moo.core.models.mail):MessageandMessageRecipientDjango models; all verb-facing operations are inmoo.sdk(send_message,get_mailbox, etc.) - Public SDK (
moo.sdk): Canonical import location for all verb authors —lookup,create,write,open_editor,open_paginator, mail functions, and exceptions
- Models (
- Modules follow Django conventions with
models.py,admin.py,apps.pyfor each app
- The core game logic is organized around Django's MVT (Model-View-Template) pattern, plus additional layers:
DjangoMOO includes an in-database mail system for player-to-player messaging.
Messages are stored in moo.core.models.mail (Message, MessageRecipient)
rather than as MOO Objects, enabling efficient indexed SQL queries. Verb code
accesses mail only through moo.sdk.
| Verb | File | Behaviour |
|---|---|---|
@mail |
player/at_mail.py |
list, read, delete, undelete, stats |
@send <player> |
player/at_send.py |
compose via editor; first line = subject |
@reply <n> |
player/at_reply.py |
editor pre-filled with quoted body, Re: subject |
@forward <n> to <player> |
player/at_mail_forward.py |
forward with Fwd: subject |
@gripe |
player/at_gripe.py |
sends to _.gripe_recipients on the system object |
confunc |
player/confunc.py |
shows unread count on login via count_unread |
Security: Message.save() on an existing row and Message.delete() require
wizard permissions. Non-wizard players may only update their own MessageRecipient
rows (read, deleted fields). Verb authors should use SDK functions exclusively.
Admin setup: @gripe sends to the gripe_recipients property on the system
object (_). A wizard must set this to a list of player Objects before @gripe is
usable.
A single deployment can host independent worlds. Each universe is a Django
Site row. SSH has no protocol-level hostname indication, so connections
either encode the Site domain in the username (ssh user+sitedomain@host)
or are routed via the post-auth picker; webssh injects the suffix from the
browser Host header automatically. Queries through Object.objects /
Property.objects / Verb.objects are silently filtered to the active
site by SiteManager (moo/core/managers.py). Use Object.global_objects
for cross-site queries (diagnostics, migrations).
| Mechanism | Purpose |
|---|---|
Player(user, site, avatar, wizard) |
Per-site avatar; same User may have one Player per Site |
UniversalWizard(user) |
Opt-in cross-universe wizard rights; auto-provisions a wizard avatar on first SSH connection to any Site without an existing Player row |
moo_init --bootstrap NAME --hostname H |
Bootstrap an additional universe at hostname H |
moo_make_universal username [--remove] |
Grant or revoke universal-wizard status |
code.ContextManager(player, ..., site=site) |
Set the active site for a block (management commands, Celery tasks) |
User.is_superuser does not grant cross-site wizard rights — universal
status is opt-in via moo_make_universal. See {doc}how-to/multi-universe
in Sphinx for the operational walkthrough.
| Dataset | Source | Purpose |
|---|---|---|
default |
moo/bootstrap/default/ |
Production game world; LambdaCore-style classes and verbs |
zork1 |
moo/bootstrap/zork1/ |
Example bootstrap mirroring Infocom Zork I; demonstrates a from-scratch class hierarchy and command vocabulary independent of default |
test |
moo/bootstrap/test.py |
Minimal flat module used by t_init fixture in moo/conftest.py; not loadable via moo_init |
For datasets where players accumulate runtime state (turn counters, doors
opened, score, inventory placement), moo_save_state snapshots the world
to a Django fixture, and moo_reset restores from that fixture and clears
per-player zstate_* properties on Player avatars. Bootstrap-level
zstate_* (e.g. ZIL <LTABLE> data on $zork_sdk) is preserved across
resets so the world remains playable without a follow-up --sync.
extras/zil_import/ parses Infocom ZIL source and emits a DjangoMOO
bootstrap; the zork1 dataset is its output. The package is a four-stage
pipeline (parser → converter → translator → generator) under
extras/zil_import/{parser,converter,translator,generator}.py. See
{doc}reference/zil-importer and {doc}explanation/zil-importer in Sphinx
for the API surface and rationale. Tests live in
extras/zil_import/tests/test_translator.py.
-
Formatting:
- Follows PEP 8 with some relaxations as defined in the project's pylintrc
- Black formatter with line length of 120 characters (see pyproject.toml)
- 4-space indentation (Python standard)
- Comments are complete sentences ending with a period
- Docstrings follow Google/NumPy style conventions
-
Naming Conventions:
- Variables and Functions:
snake_case(my_variable,do_something()) - Classes:
PascalCase(MyClass,Object,Verb) - Constants:
SCREAMING_SNAKE_CASE(MAX_BUFFER_SIZE,DEFAULT_PERMISSIONS) - File Names:
snake_case(models.py,verb_parser.py) - Django Models: Singular, PascalCase, e.g.,
Object,Verb,Property - Model Fields:
snake_case(owner,parent_classes,location) - URLs/Endpoints: Use kebab-case for URL paths (Django convention)
- Variables and Functions:
-
API Design:
- Style: Primarily object-oriented with some procedural patterns. The game API exposes through:
- Django ORM for database operations (query sets, model instantiation)
- Verb code execution via
code.interpret()andcode.compile_verb_code() - Access to current user context (current player and current verb caller) through the public
moo.sdk.contextobject
- Abstraction: The API abstracts away database details through Django models. Verb code execution is sandboxed through RestrictedPython.
- Extensibility:
- New verbs can be added to objects dynamically via the Verb model
- Properties are dynamically added to objects and inherited
- Custom permissions can be created in the ACL system
- Wizards can create their own object hierarchies and classes
- Trade-offs:
- Performance vs. Safety: RestrictedPython adds overhead but provides security guarantees for user-written code
- Simplicity vs. Power: The MOO object model is simpler than traditional OOP or procedural systems but is powerful enough for complex game logic
- Database vs. In-Memory: Uses PostgreSQL for durability; Redis is used for caching and Celery message storage
- Attribute Lookup Caching: Verb and property lookups use a three-tier cache: (1) a per-
ContextManagersession dict, (2) a Redis cross-session store keyed bymoo:verb:…/moo:prop:…, and (3) theAncestorCachedenormalized table that replaces recursive CTEs on the hot dispatch path. The Redis TTL is controlled byMOO_ATTRIB_CACHE_TTL(default 120 s; set to 0 in tests).
- Style: Primarily object-oriented with some procedural patterns. The game API exposes through:
-
Common Patterns & Idioms:
- Inheritance & Properties: Objects inherit from parent objects. Properties are created via
Object.set_property()and retrieved viaObject.get_property()or model access. Inherited properties are propagated to child objects automatically, optionally inheriting ownership. - Verb Code Execution: Verbs are Python functions compiled and executed within a restricted environment. The entry point is
def verb(this, passthrough, _, *args, **kwargs), but verb source files only contain the body of this function. - Permissions/ACL: Access control uses a permission string model (
"read","write","execute", etc.). Objects check permissions viacan_caller()methods. - Async/Concurrency: SSH server and task processing leverage asyncio and Celery for handling concurrent player sessions and background tasks.
- Type Hints: Modern code uses Python type hints for clarity; some legacy code may lack them.
- Django Admin Integration: Administrative access is primarily through Django's admin interface at
/admin.
- Inheritance & Properties: Objects inherit from parent objects. Properties are created via
-
Error Handling:
- Exceptions are used for error signaling (e.g.,
PermissionDenied,Object.DoesNotExist) - Django ValidationError is used for model validation
- RestrictedPython compile errors are caught and reported to players
- Verb execution errors are caught and reported to the player executing the verb
- Exceptions are used for error signaling (e.g.,
-
Main EntryPoint:
/manage.py- Django management interface (entry point for all administrative and startup commands)- SSH Server starts via management command in
moo.shell.server:python manage.py moo_shell - Web application served via uWSGI (see
/extras/uwsgi/uwsgi.ini)wsgi --ini /etc/uwsgi.ini
-
Configuration:
moo/settings/base.py- Core Django settingsmoo/settings/dev.py- Development overridesmoo/settings/local.py- Local/Docker environment overridesmoo/settings/test.py- Test environment (used by pytest)pyproject.toml- uv dependency and project configurationcompose.yml- Multi-container orchestration for local development and simple deploymentsDockerfile- Container image definition for all services/extras/helm/Chart.yaml- Kubernetes Helm chart for production deployments
-
CI/CD Pipeline:
.gitlab-ci.yml- GitLab CI/CD configuration defining lint, test, release, and deploy stages.readthedocs.yaml- ReadTheDocs configuration for automatic documentation building.pre-commit-config.yaml- Pre-commit hooks for local development
-
Local Development Environment:
-
Prerequisites: Ensure Python 3.11+, Docker, and Docker Compose are installed
-
Clone and Setup:
git clone https://gitlab.com/bubblehouse/django-moo cd django-moo pre-commit install -
Install Dependencies:
uv sync
-
Start Services:
docker compose up
-
Initialize Database:
docker compose run webapp manage.py migrate docker compose run webapp manage.py moo_init docker compose run webapp manage.py createsuperuser --username wizard docker compose run webapp manage.py moo_enableuser --wizard wizard Wizard
-
Access Services:
- Web Admin: https://localhost/admin
- WebSSH: https://localhost/
- SSH Direct:
ssh localhost -p 8022
-
-
Task Configuration:
- uv: Defined in
pyproject.toml. Runuv run <command> - Django Management Commands: Run via
python manage.py <command>ordocker compose run webapp manage.py <command> - Common Commands:
uv run pytest -n auto- Run all tests (always use-n autofor parallel execution)uv run pylint moo- Lint codeuv run coverage report- View coverage reportpython manage.py shell- Django shell for debuggingpython manage.py moo_init- Initialize default game worldpython manage.py moo_enableuser --wizard <username> Wizard- Make a user a wizard
- uv: Defined in
-
Testing:
-
Framework: pytest with pytest-django, pytest-xdist (parallel execution), pytest-cov (coverage)
-
Test Organization:
- Core tests in
moo/core/tests/operate on thetestdataset - Bootstrap-related tests in
moo/bootstrap/default/verbs/tests/ - Test data defined in
moo/bootstrap/test.py - Game data defined in the
moo/bootstrap/default/package (orchestrator + numbered scripts)
- Core tests in
-
Running Tests:
uv run pytest -n auto --cov uv run ruff format moo uv run pylint moo --load-plugins pylint_django --django-settings-module=moo.settings.test
Always run Ruff format, then pylint, after pytest. All three must pass before a change is considered complete. Ruff format runs before pylint at commit time — if it reformats a file, pylint sees the reformatted version, so formatting must be run first when checking manually.
-
Ruff format and pylint interaction:
# pylint: disable=...comments must appear on the specific line containing the offending code, not on a closing bracket or the next line. Ruff format may reformat expressions such that a comment on a closing)is no longer adjacent to the flagged code, making the suppression ineffective. -
Verb files: Black silently skips verb files in
moo/bootstrap/default/verbs/because they contain module-levelreturnstatements, which are aSyntaxErrorin standard Python. Black cannot parse them and leaves them unchanged. -
Test Coverage: Must not decrease with new code. Target: >= 80% coverage
-
New Features: Every feature or bug fix must include corresponding unit tests
-
Django Settings: Tests automatically use
moo.settings.test(set in pyproject.toml)
-
-
CI/CD Process:
- On Commit to Any Branch:
- Lint Stage: PyLint checks code quality (minimum score 8.0), generates coverage badge
- Test Stage: pytest runs with coverage tracking, generates JUnit XML report
- Artifacts: Coverage reports, lint reports uploaded to GitLab
- On Commit to
mainBranch:- Release Stage: Semantic versioning via
semantic-release, builds/pushes Docker images - Deploy Stage: ReadTheDocs automatically builds documentation
- Release Stage: Semantic versioning via
- Failure Conditions:
- PyLint score drops below 8.0
- Test coverage drops below configured threshold
- Any test fails
- Docker image build fails
- On Commit to Any Branch:
-
Contribution Guidelines:
- Code Review Checklist:
- All tests must pass (
uv run pytest -n auto) - Ruff formatting passes (
uv run ruff format moo) - PyLint score must not go down (
uv run pylint moo) - Test coverage must not go down (
uv run pytest -n auto --cov) - Add new tests for any feature or bug fix
- Update documentation for user-facing changes
- All tests must pass (
- Pull Request Requirements:
- Every PR should answer: What changed? Why? Are there breaking changes?
- Follow Conventional Commits specification for commit messages (see below)
- Target the
mainbranch for merges
- Code Style:
- Follow existing code style in the codebase
- Use Black formatter (line length 120)
- Write complete sentences in comments and docstrings, ending with a period
- Import organization: stdlib → third-party → local (Black compliant)
- Use type hints for clarity in modern code
- Code Review Checklist:
-
Commit Messages:
- Follow the Conventional Commits specification
- Format:
<type>(<scope>): <subject><CRLF><CRLF><body> - Types:
feat,fix,docs,style,refactor,test,chore,ci - Scope: Module or component affected (e.g.,
core,shell,admin,bootstrap) - Subject: Lowercase, imperative mood, no period. Max 50 characters.
- Body: Explain what and why, not how. Wrap at 72 characters. Optional for simple changes.
- Examples:
feat(core): add object property inheritancefix(shell): handle SSH disconnect during verb executiondocs(readme): update quick start instructionstest(core): add coverage for permission denial cases
-
Security:
- RestrictedPython Safety: User-written verb code is executed in a restricted environment. Do not bypass this for performance reasons; it's a security boundary.
- SQL Injection: Use Django ORM exclusively; never construct raw SQL with user input.
- SSH Key Management: SSH keys are stored securely in the database. Do not log them or expose them in error messages.
- Secrets: Never hardcode API keys, database passwords, or other secrets. Use environment variables and Django settings.
- Input Validation: Validate and sanitize all player input before processing or storing.
-
Dependencies:
- Adding New Dependencies:
- Run
uv add <package>oruv add --group dev <package>for dev dependencies - Verify the package doesn't conflict with existing dependencies
- Update documentation if the dependency is a significant addition
uv.lockis automatically updated
- Run
- Updating Dependencies:
- Run
uv lock --upgradeto update all dependencies to latest compatible versions - Test thoroughly after updates
- Be cautious with major version updates; review changelogs for breaking changes
- Run
- Dependency Rationale: Document why a new dependency is needed in the PR description or code comments
- Adding New Dependencies:
-
AsyncSSH + prompt_toolkit Integration:
- The SSH server (
moo/shell/server.py) must passline_editor=Falsetoasyncssh.create_server(). asyncssh'sline_editor=Truedefault wraps every channel withSSHLineEditorChannel, which intercepts ALL output throughSSHLineEditor.process_output(). This is incompatible with prompt_toolkit: it does a second\n→\r\nreplacement (causing\r\r\r\ntriples), tracks cursor position with a naive parser that only ends escape sequences onm(corrupting column tracking for all other VT100 codes), and injects' \b'at column-80 boundaries — overwriting characters in the terminal. - prompt_toolkit handles all terminal I/O itself. The asyncssh line editor must be disabled.
- The SSH server (
-
MOO Verb Code Development:
-
File Organization: Verbs for the
defaultdataset are organized inmoo/bootstrap/default/verbs/. Thetestdataset uses no additional verb files. -
Shebang Line: Every verb file starts with
#!moo verb <names> --on <object>and optional flags. Example:#!moo verb accept --on $room return True
The
--onparameter supports the$<name>syntax to refer to properties on the system object. -
Verb Function Signature: When executed, verb code is wrapped in this function signature before being called with the required parameters.
def verb(this, passthrough, _, *args, **kwargs): """ this: The object where the verb was found passthrough: Call this to invoke the verb on parent objects _: Reference to the system (#1) object args: Function arguments when called as a method kwargs: Keyword arguments when called as a method """
-
RestrictedPython Caveats: Ignore warnings about undefined variables for
this,passthrough,_,args, andkwargs. These are injected by the execution environment. -
Return Behavior: Verbs can use
returnfrom anywhere, not just at function end (courtesy of RestrictedPython compilation). -
Testing Verbs: Tests for
defaultverbs live inmoo/bootstrap/default/verbs/tests/.
-
-
Documentation:
- Code Documentation: Use docstrings (Google/NumPy style) for all classes, functions, and modules
- User Documentation: Update
.mdor.rstfiles in/docsfor user-facing changes - Auto-Generated Docs: API documentation is generated via Sphinx from docstrings and published to ReadTheDocs
- README Updates: Keep README.md current with quick start instructions and key information
- Contributor Docs: Update this file if adding new components or significant architectural changes
-
Performance Considerations:
- Database Queries: Use Django QuerySet
.select_related()and.prefetch_related()to minimize N+1 queries - Attribute Caching: Verb and property lookups are automatically cached at three levels — do not implement separate caching for these. See
docs/source/reference/caching.mdfor the full architecture. - Caching: Redis is available for caching other frequently accessed data (room contents, player locations, etc.)
- Celery Tasks: All code and command-parser invocations are executed as tasks inside Celery workers. Creating new Celery Tasks is uncommon.
- Verb Time Limits: Verbs called with
__getattr__syntax (obj.someverb()) add to the total execution time for a verb, which is limited to 3 seconds. For verbs with effective runtimes that are longer than this, themoo.sdk.invoke()command can be used to asynchronously execute another verb with its own 3-second time limit. - Indexing: Add database indexes to frequently queried fields (Django
db_index=True)
- Database Queries: Use Django QuerySet
-
Testing Best Practices:
- Three test types: Core unit tests (
moo/core/tests/) test models and the verb execution engine without a full bootstrap. App integration tests (e.g.,moo/shell/tests/) test Django features (forms, views) that interact with MOO objects — use@pytest.mark.parametrize("t_init", ["default"], indirect=True)when the full default world is needed. Verb integration tests (moo/bootstrap/default/verbs/tests/) test verb behaviour against a fully bootstrappeddefaultworld. Thet_initparametrize pattern is not exclusive todefault/verbs/tests/— any test file can use it. - Bootstrap test fixtures: Both
t_init(bootstrapsdefault.py) andt_wizard(returns the Wizard player) come frommoo/conftest.py.t_initmust be requested with@pytest.mark.parametrize("t_init", ["default"], indirect=True)and@pytest.mark.django_db(transaction=True, reset_sequences=True). - Output capture: Pass a
_writercallback tocode.ContextManagerto capture everythingprint()ed to the player during a test. - State assertions: Call
obj.refresh_from_db()afterparse.interpretor a direct verb call before asserting locations or other database-backed fields. - Direct verb calls: Inside a
code.ContextManagerblock, verbs are callable as Python methods —widget.drop_succeeded_msg()— useful for testing helpers without going through the command parser. - Lock testing: Set
key = ["!", obj.id]on a destination to block a specific object;key = None(the default) means unlocked.
- Three test types: Core unit tests (
# Install dependencies
uv sync
# Run tests with coverage
uv run pytest -n auto --cov
# Run specific test file
uv run pytest -n auto moo/core/tests/test_parser.py
# Run linting (always run after pytest)
uv run pylint moo --load-plugins pylint_django --django-settings-module=moo.settings.test
# View coverage report
uv run coverage report
# Format code with Ruff
uv run ruff format moo
# Start development server
docker compose up
# Run Django migrations
docker compose run webapp manage.py migrate
# Access Django shell
docker compose run webapp manage.py shell
# Initialize game world
docker compose run webapp manage.py moo_init
# Create Django superuser
docker compose run webapp manage.py createsuperuser --username wizard
# Connect Django user to MOO wizard player (--wizard grants in-game wizard privileges)
docker compose run webapp manage.py moo_enableuser --wizard wizard Wizard
# Create a non-wizard user and avatar in one step (test accounts, regular players)
docker compose run webapp manage.py moo_createuser username AvatarName --password secret
# Snapshot world state (objects, properties, verb names, aliases) for a dataset
docker compose run webapp manage.py moo_save_state --bootstrap zork1 --output zork1_world.json
# Reset a dataset to its snapshot fixture (clears per-player zstate_* state)
docker compose run webapp manage.py moo_reset --bootstrap zork1
# Mark a Django user as wizard on every Site (multi-universe deployments)
docker compose run webapp manage.py moo_make_universal alice- Create a feature branch:
git checkout -b feat/my-feature - Make code changes following style guidelines
- Add tests for new functionality
- Run tests locally:
uv run pytest -n auto --cov - Run Ruff format:
uv run ruff format moo - Run linting:
uv run pylint moo --load-plugins pylint_django --django-settings-module=moo.settings.test - Fix any issues — repeat steps 4–6 until all pass cleanly
- Commit with Conventional Commits:
git commit -m "feat(core): add new feature" - Push and create merge request targeting
main - Address review feedback
- After merge, automated CI/CD handles testing and deployment
- Core Logic:
moo/core/models/andmoo/core/code.py - Game Logic:
moo/bootstrap/ - SSH/Interactive:
moo/shell/ - Testing:
moo/core/tests/ - Configuration:
moo/settings/ - Game Data:
moo/bootstrap/ - Django Admin:
moo/core/admin.py - Documentation:
docs/source/