domains.md
markdown
| 1 | # `muse domains` — Domain Plugin Dashboard & Marketplace Publisher |
| 2 | |
| 3 | Domain plugins are the extensibility engine of Muse. Every new type of |
| 4 | multidimensional state — MIDI, source code, genomic sequences, spatial |
| 5 | scenes — is a new domain plugin. The `muse domains` command surfaces |
| 6 | the plugin registry, guides scaffold creation, and publishes plugins to |
| 7 | the [MuseHub marketplace](https://musehub.ai/domains). |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## Table of Contents |
| 12 | |
| 13 | 1. [Overview](#overview) |
| 14 | 2. [Commands](#commands) |
| 15 | - [muse domains (dashboard)](#muse-domains-dashboard) |
| 16 | - [muse domains --new](#muse-domains---new) |
| 17 | - [muse domains publish](#muse-domains-publish) |
| 18 | 3. [Capability Levels](#capability-levels) |
| 19 | 4. [Publishing to MuseHub](#publishing-to-musehub) |
| 20 | - [Capabilities manifest](#capabilities-manifest) |
| 21 | - [Authentication](#authentication) |
| 22 | - [HTTP semantics](#http-semantics) |
| 23 | - [Agent usage (--json)](#agent-usage---json) |
| 24 | 5. [Plugin Architecture](#plugin-architecture) |
| 25 | 6. [Examples](#examples) |
| 26 | |
| 27 | --- |
| 28 | |
| 29 | ## Overview |
| 30 | |
| 31 | ``` |
| 32 | muse domains # human-readable dashboard |
| 33 | muse domains --json # machine-readable registry dump |
| 34 | muse domains --new <name> # scaffold a new plugin directory |
| 35 | muse domains publish # register a plugin on MuseHub |
| 36 | ``` |
| 37 | |
| 38 | All four modes operate without an active Muse repository (though `publish` |
| 39 | benefits from having one — it auto-derives capability metadata from the |
| 40 | repo's active domain plugin). |
| 41 | |
| 42 | --- |
| 43 | |
| 44 | ## Commands |
| 45 | |
| 46 | ### `muse domains` (dashboard) |
| 47 | |
| 48 | Print a human-readable table of every registered domain plugin. |
| 49 | |
| 50 | ``` |
| 51 | ╔══════════════════════════════════════════════════════════════╗ |
| 52 | ║ Muse Domain Plugin Dashboard ║ |
| 53 | ╚══════════════════════════════════════════════════════════════╝ |
| 54 | |
| 55 | Registered domains: 2 |
| 56 | ────────────────────────────────────────────────────────────── |
| 57 | |
| 58 | ● midi ← active repo domain |
| 59 | Module: plugins/midi/plugin.py |
| 60 | Capabilities: Typed Deltas · Domain Schema · OT Merge |
| 61 | Schema: v0.1.3 · top_level: set · merge_mode: three_way |
| 62 | Dimensions: notes, pitch_bend, tempo_map, … (21 total) |
| 63 | |
| 64 | ○ scaffold |
| 65 | Module: plugins/scaffold/plugin.py |
| 66 | Capabilities: Typed Deltas · Domain Schema · OT Merge · CRDT |
| 67 | Schema: v0.1.3 · top_level: set · merge_mode: three_way |
| 68 | Dimensions: primary, metadata |
| 69 | ────────────────────────────────────────────────────────────── |
| 70 | ``` |
| 71 | |
| 72 | The `●` marker identifies the active domain of the current repository. |
| 73 | `○` means registered but not active in this repo. |
| 74 | |
| 75 | **Options:** |
| 76 | |
| 77 | | Flag | Description | |
| 78 | |------|-------------| |
| 79 | | `--json` | Emit registry as machine-readable JSON (see [Agent usage](#agent-usage---json)) | |
| 80 | |
| 81 | --- |
| 82 | |
| 83 | ### `muse domains --new` |
| 84 | |
| 85 | Scaffold a new domain plugin directory from the built-in scaffold template. |
| 86 | |
| 87 | ``` |
| 88 | muse domains --new genomics |
| 89 | ``` |
| 90 | |
| 91 | Creates `muse/plugins/genomics/` by copying `muse/plugins/scaffold/` and |
| 92 | renaming `ScaffoldPlugin` → `GenomicsPlugin` throughout. The scaffold |
| 93 | implements the minimal `MuseDomainPlugin` protocol so `muse domains` shows |
| 94 | it immediately. |
| 95 | |
| 96 | **What gets created:** |
| 97 | |
| 98 | ``` |
| 99 | muse/plugins/genomics/ |
| 100 | __init__.py |
| 101 | plugin.py # GenomicsPlugin implements MuseDomainPlugin |
| 102 | ``` |
| 103 | |
| 104 | After scaffolding, implement the six required methods in `plugin.py`: |
| 105 | |
| 106 | | Method | Required | Description | |
| 107 | |--------|----------|-------------| |
| 108 | | `name()` | yes | Canonical domain name string | |
| 109 | | `diff(base, head)` | yes | Compute semantic delta | |
| 110 | | `apply(state, delta)` | yes | Apply a delta to a state | |
| 111 | | `merge(base, ours, theirs)` | yes | Three-way merge | |
| 112 | | `schema()` | recommended | Return `DomainSchema` for rich tooling | |
| 113 | | `serialize(state)` / `deserialize(blob)` | yes | Round-trip to bytes | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ### `muse domains publish` |
| 118 | |
| 119 | Register a Muse domain plugin on the [MuseHub marketplace](https://musehub.ai/domains) |
| 120 | so agents and users can discover and install it. |
| 121 | |
| 122 | ``` |
| 123 | muse domains publish \ |
| 124 | --author <slug> \ |
| 125 | --slug <slug> \ |
| 126 | --name <display-name> \ |
| 127 | --description <text> \ |
| 128 | --viewer-type <type> |
| 129 | ``` |
| 130 | |
| 131 | **Required options:** |
| 132 | |
| 133 | | Flag | Description | |
| 134 | |------|-------------| |
| 135 | | `--author SLUG` | Your MuseHub username (owner of the domain) | |
| 136 | | `--slug SLUG` | URL-safe domain identifier (e.g. `genomics`, `spatial-3d`) | |
| 137 | | `--name NAME` | Human-readable marketplace display name | |
| 138 | | `--description TEXT` | What this domain models and why it benefits from semantic VCS | |
| 139 | | `--viewer-type TYPE` | Primary viewer identifier (`midi`, `code`, `spatial`, `genome`, …) | |
| 140 | |
| 141 | **Optional options:** |
| 142 | |
| 143 | | Flag | Default | Description | |
| 144 | |------|---------|-------------| |
| 145 | | `--version SEMVER` | `0.1.0` | Semantic version string | |
| 146 | | `--capabilities JSON` | _(auto-derived)_ | Full capabilities manifest as JSON (see below) | |
| 147 | | `--hub URL` | `.muse/config.toml` | Override MuseHub base URL | |
| 148 | | `--json` | off | Emit server response as machine-readable JSON | |
| 149 | |
| 150 | --- |
| 151 | |
| 152 | ## Capability Levels |
| 153 | |
| 154 | Every domain plugin is classified by the capabilities it implements: |
| 155 | |
| 156 | | Capability | Protocol | Description | |
| 157 | |------------|----------|-------------| |
| 158 | | **Typed Deltas** | `MuseDomainPlugin` | Core — every domain gets this | |
| 159 | | **Domain Schema** | `schema()` method returns `DomainSchema` | Declares dimensions, merge mode, version | |
| 160 | | **OT Merge** | `StructuredMergePlugin` | Operational-transform three-way merge | |
| 161 | | **CRDT** | `CRDTPlugin` | Convergent replicated data type merge | |
| 162 | |
| 163 | The dashboard shows `Typed Deltas · Domain Schema · OT Merge · CRDT` in |
| 164 | ascending capability order. These are also reflected in the `capabilities` |
| 165 | field of the published marketplace manifest. |
| 166 | |
| 167 | --- |
| 168 | |
| 169 | ## Publishing to MuseHub |
| 170 | |
| 171 | ### Capabilities manifest |
| 172 | |
| 173 | When `--capabilities` is **omitted**, the command reads the active repo's |
| 174 | domain plugin schema and derives the manifest automatically: |
| 175 | |
| 176 | ```python |
| 177 | schema = plugin.schema() |
| 178 | capabilities = { |
| 179 | "dimensions": [{"name": d["name"], "description": d["description"]} for d in schema["dimensions"]], |
| 180 | "merge_semantics": schema["merge_mode"], # "three_way" or "crdt" |
| 181 | "supported_commands": ["commit", "diff", "merge", "log", "status"], |
| 182 | } |
| 183 | ``` |
| 184 | |
| 185 | When `--capabilities` is provided, it must be a JSON object with any |
| 186 | subset of these keys: |
| 187 | |
| 188 | ```json |
| 189 | { |
| 190 | "dimensions": [ |
| 191 | {"name": "geometry", "description": "3-D mesh vertex and face data"}, |
| 192 | {"name": "materials", "description": "PBR material assignments"} |
| 193 | ], |
| 194 | "artifact_types": ["glb", "usdz", "obj"], |
| 195 | "merge_semantics": "three_way", |
| 196 | "supported_commands": ["commit", "diff", "merge", "log", "status"] |
| 197 | } |
| 198 | ``` |
| 199 | |
| 200 | ### Authentication |
| 201 | |
| 202 | `muse domains publish` uses the same bearer token as `muse push`: |
| 203 | |
| 204 | ``` |
| 205 | muse auth login # stores token in ~/.muse/identity.toml |
| 206 | muse hub connect <url> # sets hub URL in .muse/config.toml |
| 207 | ``` |
| 208 | |
| 209 | The token is read by `get_auth_token()` from the hub URL configured in |
| 210 | `.muse/config.toml`. If no token is found, the command exits `1` with |
| 211 | instructions for `muse auth login`. |
| 212 | |
| 213 | ### HTTP semantics |
| 214 | |
| 215 | The command POSTs to `POST /api/v1/domains` on the configured MuseHub |
| 216 | instance. Possible responses: |
| 217 | |
| 218 | | HTTP status | Meaning | CLI behaviour | |
| 219 | |-------------|---------|---------------| |
| 220 | | `200 OK` | Domain registered | Prints `✅ Domain published: @author/slug` | |
| 221 | | `409 Conflict` | Slug already registered | Exits `1` with "already registered" hint | |
| 222 | | `401 Unauthorized` | Invalid or expired token | Exits `1` with re-login instructions | |
| 223 | | `5xx` | Server error | Exits `1` with raw HTTP status | |
| 224 | | Network error | DNS / connection failure | Exits `1` with "Could not reach" message | |
| 225 | |
| 226 | ### Agent usage (`--json`) |
| 227 | |
| 228 | ```bash |
| 229 | muse domains publish \ |
| 230 | --author alice --slug spatial \ |
| 231 | --name "Spatial 3D" \ |
| 232 | --description "Version 3-D scenes as structured state" \ |
| 233 | --viewer-type spatial \ |
| 234 | --json |
| 235 | ``` |
| 236 | |
| 237 | Output (JSON, stdout): |
| 238 | |
| 239 | ```json |
| 240 | { |
| 241 | "domain_id": "dom-abc123", |
| 242 | "scoped_id": "@alice/spatial", |
| 243 | "manifest_hash": "sha256:def456..." |
| 244 | } |
| 245 | ``` |
| 246 | |
| 247 | Non-zero exit codes are always accompanied by a human-readable error on |
| 248 | stderr. The `--json` flag affects stdout only. |
| 249 | |
| 250 | --- |
| 251 | |
| 252 | ## Plugin Architecture |
| 253 | |
| 254 | Every domain plugin lives under `muse/plugins/<name>/plugin.py` and |
| 255 | implements the `MuseDomainPlugin` protocol defined in `muse/domain.py`. |
| 256 | |
| 257 | ``` |
| 258 | muse/ |
| 259 | domain.py ← MuseDomainPlugin protocol + DomainSchema type |
| 260 | plugins/ |
| 261 | registry.py ← _REGISTRY: dict[str, MuseDomainPlugin] |
| 262 | midi/ |
| 263 | plugin.py ← MidiPlugin (reference implementation) |
| 264 | scaffold/ |
| 265 | plugin.py ← ScaffoldPlugin (copy template for new domains) |
| 266 | <your-domain>/ |
| 267 | plugin.py ← YourPlugin implements MuseDomainPlugin |
| 268 | ``` |
| 269 | |
| 270 | The core engine in `muse/core/` **never imports** from `muse/plugins/`. |
| 271 | Domain dispatch is achieved entirely through the `MuseDomainPlugin` |
| 272 | protocol — the engine calls the six methods; it does not know or care |
| 273 | about MIDI, DNA, or spatial geometry. |
| 274 | |
| 275 | **Registering a new plugin:** |
| 276 | |
| 277 | ```python |
| 278 | # muse/plugins/registry.py |
| 279 | from muse.plugins.genomics.plugin import GenomicsPlugin |
| 280 | |
| 281 | _REGISTRY: dict[str, MuseDomainPlugin] = { |
| 282 | "midi": MidiPlugin(), |
| 283 | "scaffold": ScaffoldPlugin(), |
| 284 | "genomics": GenomicsPlugin(), # add your plugin here |
| 285 | } |
| 286 | ``` |
| 287 | |
| 288 | --- |
| 289 | |
| 290 | ## Examples |
| 291 | |
| 292 | ### List all registered domains (machine-readable) |
| 293 | |
| 294 | ```bash |
| 295 | muse domains --json | jq '.[].name' |
| 296 | ``` |
| 297 | |
| 298 | ### Scaffold and immediately publish a new domain |
| 299 | |
| 300 | ```bash |
| 301 | # 1. Scaffold |
| 302 | muse domains --new genomics |
| 303 | |
| 304 | # 2. Implement plugin.py |
| 305 | # ... implement MuseDomainPlugin methods ... |
| 306 | |
| 307 | # 3. Register in muse/plugins/registry.py |
| 308 | # ... add GenomicsPlugin() to _REGISTRY ... |
| 309 | |
| 310 | # 4. Publish to MuseHub |
| 311 | muse domains publish \ |
| 312 | --author alice \ |
| 313 | --slug genomics \ |
| 314 | --name "Genomics" \ |
| 315 | --description "Version DNA sequences as multidimensional state" \ |
| 316 | --viewer-type genome \ |
| 317 | --version 0.1.0 |
| 318 | ``` |
| 319 | |
| 320 | ### Override capabilities for an out-of-repo publish |
| 321 | |
| 322 | ```bash |
| 323 | muse domains publish \ |
| 324 | --author alice \ |
| 325 | --slug spatial-3d \ |
| 326 | --name "Spatial 3D" \ |
| 327 | --description "3-D scene version control" \ |
| 328 | --viewer-type spatial \ |
| 329 | --capabilities '{ |
| 330 | "dimensions": [ |
| 331 | {"name": "geometry", "description": "Mesh data"}, |
| 332 | {"name": "materials", "description": "PBR material assignments"}, |
| 333 | {"name": "lights", "description": "Light rig"} |
| 334 | ], |
| 335 | "artifact_types": ["glb", "usdz"], |
| 336 | "merge_semantics": "three_way", |
| 337 | "supported_commands": ["commit", "diff", "merge", "log"] |
| 338 | }' \ |
| 339 | --json |
| 340 | ``` |
| 341 | |
| 342 | ### Use via agent (`musehub_publish_domain` MCP tool) |
| 343 | |
| 344 | Agents do not need the CLI. MuseHub exposes `musehub_publish_domain` |
| 345 | as a first-class MCP tool: |
| 346 | |
| 347 | ```json |
| 348 | { |
| 349 | "jsonrpc": "2.0", |
| 350 | "id": 1, |
| 351 | "method": "tools/call", |
| 352 | "params": { |
| 353 | "name": "musehub_publish_domain", |
| 354 | "arguments": { |
| 355 | "author_slug": "alice", |
| 356 | "slug": "genomics", |
| 357 | "display_name": "Genomics", |
| 358 | "description": "Version DNA sequences", |
| 359 | "viewer_type": "genome", |
| 360 | "version": "0.1.0" |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 | ``` |
| 365 | |
| 366 | See [`musehub_publish_domain`](https://musehub.ai/mcp/docs#musehub_publish_domain) |
| 367 | in the MuseHub MCP reference for the full schema. |