#!/usr/bin/env python3 """Muse Domain Registry โ standalone HTML generator. Produces a self-contained, shareable page that explains the MuseDomainPlugin protocol, shows the registered plugin ecosystem, and guides developers through scaffolding and publishing their own domain plugin. Stand-alone usage ----------------- python tools/render_domain_registry.py python tools/render_domain_registry.py --out artifacts/domain_registry.html """ from __future__ import annotations import json import pathlib import subprocess import sys _ROOT = pathlib.Path(__file__).resolve().parent.parent # --------------------------------------------------------------------------- # Live domain data from the CLI # --------------------------------------------------------------------------- def _load_domains() -> list[dict]: """Run `muse domains --json` and return parsed output.""" try: result = subprocess.run( [sys.executable, "-m", "muse", "domains", "--json"], capture_output=True, text=True, cwd=str(_ROOT), timeout=15, ) if result.returncode == 0: raw = result.stdout.strip() data: list[dict] = json.loads(raw) return data except Exception: pass # Fallback: static reference data return [ { "domain": "music", "active": "true", "capabilities": ["Typed Deltas", "Domain Schema", "OT Merge"], "schema": { "schema_version": "1", "merge_mode": "three_way", "description": "MIDI and audio file versioning with note-level diff and semantic merge", "dimensions": [ {"name": "melodic", "description": "Note pitches and durations over time"}, {"name": "harmonic", "description": "Chord progressions and key signatures"}, {"name": "dynamic", "description": "Velocity and expression curves"}, {"name": "structural", "description": "Track layout, time signatures, tempo map"}, ], }, } ] # --------------------------------------------------------------------------- # Scaffold template (shown in the "Build in 3 steps" section) # --------------------------------------------------------------------------- _SCAFFOLD_SNIPPET = """\ from __future__ import annotations from muse.domain import ( MuseDomainPlugin, LiveState, StateSnapshot, StateDelta, DriftReport, MergeResult, DomainSchema, ) class GenomicsPlugin(MuseDomainPlugin): \"\"\"Version control for genomic sequences.\"\"\" def snapshot(self, live_state: LiveState) -> StateSnapshot: # Serialize current genome state to a content-addressable blob raise NotImplementedError def diff(self, base: StateSnapshot, target: StateSnapshot) -> StateDelta: # Compute minimal delta between two snapshots raise NotImplementedError def merge(self, base: StateSnapshot, left: StateSnapshot, right: StateSnapshot) -> MergeResult: # Three-way merge โ surface conflicts per dimension raise NotImplementedError def drift(self, committed: StateSnapshot, live: LiveState) -> DriftReport: # Detect uncommitted changes in the working state raise NotImplementedError def apply(self, delta: StateDelta, live_state: LiveState) -> LiveState: # Reconstruct historical state from a delta raise NotImplementedError def schema(self) -> DomainSchema: # Declare dimensions โ drives diff algorithm selection raise NotImplementedError """ # --------------------------------------------------------------------------- # Planned / aspirational domains # --------------------------------------------------------------------------- _PLANNED_DOMAINS = [ { "name": "Genomics", "icon": "๐งฌ", "status": "planned", "tagline": "Version sequences, variants, and annotations", "dimensions": ["sequence", "variants", "annotations", "metadata"], "color": "#3fb950", }, { "name": "3D / Spatial", "icon": "๐", "status": "planned", "tagline": "Merge spatial fields, meshes, and simulation frames", "dimensions": ["geometry", "materials", "physics", "temporal"], "color": "#58a6ff", }, { "name": "Financial", "icon": "๐", "status": "planned", "tagline": "Track model versions, alpha signals, and risk state", "dimensions": ["signals", "positions", "risk", "parameters"], "color": "#f9a825", }, { "name": "Scientific Simulation", "icon": "โ๏ธ", "status": "planned", "tagline": "Snapshot simulation state across timesteps and parameter spaces", "dimensions": ["state", "parameters", "observables", "checkpoints"], "color": "#ab47bc", }, { "name": "Your Domain", "icon": "โฆ", "status": "yours", "tagline": "Six methods. Any multidimensional state. Full VCS for free.", "dimensions": ["your_dim_1", "your_dim_2", "..."], "color": "#4f8ef7", }, ] # --------------------------------------------------------------------------- # Distribution model description # --------------------------------------------------------------------------- _DISTRIBUTION_LEVELS = [ { "tier": "Local", "icon": "๐ป", "title": "Local plugin (right now)", "color": "#3fb950", "steps": [ "muse domains --new <name>", "Implement 6 methods in muse/plugins/<name>/plugin.py", "Register in muse/plugins/registry.py", "muse init --domain <name>", ], "desc": "Works today. Scaffold โ implement โ register. " "Your plugin lives alongside the core.", }, { "tier": "Shareable", "icon": "๐ฆ", "title": "pip-installable package (right now)", "color": "#58a6ff", "steps": [ "Package your plugin as a Python module", "pip install git+https://github.com/you/muse-plugin-genomics", "Register the entry-point in pyproject.toml", "muse init --domain genomics", ], "desc": "Share your plugin as a standard Python package. " "Anyone with pip can install and use it.", }, { "tier": "MuseHub", "icon": "๐", "title": "Centralized registry (coming โ MuseHub)", "color": "#bc8cff", "steps": [ "musehub publish muse-plugin-genomics", "musehub search genomics", "muse init --domain @musehub/genomics", "Browse plugins at musehub.io", ], "desc": "MuseHub is a planned centralized registry โ npm for Muse plugins. " "Versioned, searchable, one-command install.", }, ] # --------------------------------------------------------------------------- # HTML template # --------------------------------------------------------------------------- def _render_domain_card(d: dict) -> str: domain = d.get("domain", "unknown") active = d.get("active") == "true" schema = d.get("schema", {}) desc = schema.get("description", "") dims = schema.get("dimensions", []) caps = d.get("capabilities", []) cap_html = " ".join( f'{c}' for c in caps ) dim_html = " ยท ".join( f'{dim["name"]}' for dim in dims ) status_cls = "active-badge" if active else "reg-badge" status_text = "โ active" if active else "โ registered" dot = '' if active else "" short_desc = desc[:150] + ("โฆ" if len(desc) > 150 else "") return f"""
{short_desc}
{s}{d['desc']}
One protocol. Any domain. Six methods between you and a complete version control system โ branching, merging, conflict resolution, time-travel, and typed diffs โ for free.
Every domain โ music, genomics, 3D spatial, financial models โ implements the same six-method protocol. The core engine handles everything else: content-addressed storage, DAG, branches, log, merge base, cherry-pick, revert, stash, tags.
One command scaffolds the entire plugin skeleton. You fill in six methods. The full VCS follows.
raise NotImplementedError with your domain's
snapshot, diff, merge, drift, apply, and schema logic.
registry.py, then every Muse command works
for your domain out of the box.
muse domains --new genomics producesA fully typed, immediately runnable plugin skeleton. Every method has the correct signature. You replace the stubs โ the protocol does the rest.
Full walkthrough โ docs/guide/plugin-authoring-guide.md ยท CRDT extension โ docs/guide/crdt-reference.md
Domains currently registered in this Muse instance. The active domain
is the one used when you run muse commit, muse diff,
and all other commands.
Music is the reference implementation. These are the domains planned next โ and the slot waiting for yours.
Three tiers of distribution โ from local prototype to globally searchable registry. Start local, publish when ready.
A centralized, searchable registry for Muse domain plugins โ think npm or crates.io, but for any multidimensional versioned state. One command to publish. One command to install.
muse init --domain @musehub/genomics