# XZBT-NGN Exhibit Engine A minimal, single-exhibit engineering host for XZBT Exhibit Contract 5.2. It discovers controls from `describe`, tracks the exhibit's reported state, and exposes set/invoke operations, events, sessions, and protocol errors. ## Run locally Requires Node.js 22 or later. No npm dependencies or build step are needed. ```powershell npm start ``` Open `http://127.0.0.1:4173`. Enter a same-origin exhibit path and select **Load exhibit**. The host negotiates a real session, calls `describe` and `state.get`, then renders the discovered catalog. **Reconnect** establishes a new session without reloading the exhibit; **Refresh state** requests a new authoritative snapshot. **Disconnect** removes the exhibit frame. Included test fixture paths: ```text /test-fixtures/reference-exhibits/aquarium/index.html /test-fixtures/reference-exhibits/planetarium/index.html /test-fixtures/reference-exhibits/haunted-house/index.html ``` These copied fixtures have documented compatibility corrections; see [fixture provenance](test-fixtures/PROVENANCE.md). They are not NGN product logic. Additional trusted HTML exhibits can be placed in a directory under `public/` and loaded by their same-origin URL. The server exposes only `public/`, `src/`, and `test-fixtures/`, and binds to `127.0.0.1`. Set the `PORT` environment variable to change the default port. ## Verification ```powershell npm test python devlog_editor.py --validate git diff --check ``` With the server running, open `http://127.0.0.1:4173/test-fixtures/host-verification.html` and select **Run verification** for repeatable real-browser transport tests against all three exhibits. Manual admin UI and native exhibit gesture checks are recorded in [the Step 4 report](STEP4-MVP-REPORT.md). ## Implementation boundaries - `src/host.js`: session/request correlation, catalog, state cache, events, synchronization, and control operations. - `src/validation.js`: descriptor, value, and clarified argument validation. - `src/transport/post-message.js`: same-origin frame transport only. - `src/ui.js` and `public/`: descriptor-driven engineering interface. - `server/serve.js`: loopback static server with explicit served directories. - `tests/`: focused automated host and server tests. - `test-fixtures/`: copied reference exhibits and real-browser verification. The state display is a cache of exhibit reports. Events update reported values; editable fields are drafts and are submitted only when Set/Invoke is selected. Draft fields start from the first snapshot and do not overwrite themselves on each incoming event. Registry/capability rediscovery rebuilds the controls. Logs retain the latest 200 entries in memory. The interface intentionally has no persistence, accounts, MIDI, scenarios, webhooks, packaging, or orchestration. ## Template and publishing records A starter template and baseline structure for projects compatible with [Labyricorn](https://www.labyricorn.com). This template provides the required `.labyricorn/` publishing records, assistant guidance files (`AGENTS.md`), devlog structure, and the standalone `devlog_editor.py` management utility for local validation and GUI editing. --- ## Overview Projects published on Labyricorn maintain their own exhibition pages and development logs directly inside their Git repositories under the `.labyricorn/` directory. The Labyricorn site importer periodically synchronizes these records as read-only content. This template includes: - **`.labyricorn/` publishing structure**: Validated Lektor-format records for project identity and development logs. - **`devlog_editor.py`**: Standalone GUI and CLI tool for managing devlog entries, validating publishing contracts, and safely publishing changes. - **`AGENTS.md` instructions**: Scoped assistant instructions at repository root and publishing directories to ensure AI assistants adhere to the publishing contract. - **`.gitignore`**: Configured exclusions for Python environments, caches, and build artifacts. --- ## Directory Structure ```text . ├── .gitignore ├── .labyricorn/ │ ├── AGENTS.md # Assistant instructions for publishing content │ ├── README.md # Publishing structure documentation │ ├── project/ │ │ ├── AGENTS.md # Instructions for the project exhibition record │ │ ├── contents.lr # Project identity and exhibition narrative │ │ └── # Project logo (PNG, JPEG, WebP) │ └── devlog/ │ ├── AGENTS.md # Instructions for devlog records │ ├── contents.lr # Devlog index record │ └── / # (Optional) Devlog entry directories │ ├── contents.lr # Devlog entry record │ └── # Entry attachments (PNG, JPEG, WebP) ├── AGENTS.md # Assistant instructions for the repository ├── devlog_editor.py # Standalone devlog editor & validator ├── LICENSE # License file └── README.md # Project documentation ``` --- ## Getting Started ### 1. Configure the Project Identity Edit `.labyricorn/project/contents.lr` to set your project details: ```ini _model: project --- schema_version: 1 --- project_id: my-project-id --- title: My Project Title --- summary: A concise summary of the project for listings and cards. --- status: active --- started: 2026-08-23 --- author: Author Name --- repository_url: https://git.labyricorn.com/Owner/my-project --- default_branch: main --- tags: python, web, tool --- body: An exhibition narrative describing the project background, goals, and features. ``` #### Project Fields: - `project_id`: Stable lowercase hyphenated slug (e.g. `my-project`). - `title`: Display title for the project. - `summary`: Short multi-line summary. - `status`: One of `active`, `released`, `maintained`, or `archived`. - `started`: Start date in `YYYY-MM-DD` format. - `author`: Author or organization name. - `repository_url`: Public credential-free HTTPS Git URL. - `default_branch`: Target branch name (e.g. `main`). - `logo`: (Optional) Local filename of an image inside `.labyricorn/project/`. - `tags`: Comma-separated technology or topic labels. - `body`: Markdown narrative of the project. ### 2. Configure the Devlog Index Edit `.labyricorn/devlog/contents.lr` to customize the devlog title and summary: ```ini _model: devlog --- schema_version: 1 --- title: My Project development log --- summary: Milestones and development updates for My Project. ``` ### 3. Add Devlog Entries To add an entry manually, create a directory under `.labyricorn/devlog//` containing `contents.lr`: ```ini _model: devlog-entry --- schema_version: 1 --- title: Initial Project Milestone --- date: 2026-08-23 --- author: Author Name --- summary: Overview of the milestone accomplishments. --- tags: release, setup --- source_commit: <40-character-commit-hash> --- body: Detailed Markdown description of the milestone, technical decisions, and progress. ``` Alternatively, use `devlog_editor.py` to create and edit entries interactively. --- ## Devlog Editor The included `devlog_editor.py` script is a standalone utility with zero external dependencies (uses Python standard library and Tkinter). ### CLI Validation Validate all project and devlog records without opening a GUI: ```bash python devlog_editor.py --validate ``` ### Graphical Editor Launch the Tkinter management interface to view repository status, draft entries, and publish updates: ```bash python devlog_editor.py ``` Features of the GUI editor: - **Repository status**: Displays current branch, remote, and ahead/behind counts. - **Entry manager**: Create, edit, and delete devlog entries with automatic slug and date handling. - **Publishing safety**: Stages and commits only `.labyricorn/` publishing files, leaving application source files untouched. --- ## Publishing Rules & Constraints The Labyricorn site importer enforces strict validation rules on imported repositories: 1. **Native Lektor Records**: Records must be named `contents.lr` and declare `schema_version: 1`. 2. **No Raw HTML**: HTML tags (`