cli-tiers.md
markdown
| 1 | # Muse CLI — Three-Tier Architecture Reference |
| 2 | |
| 3 | Muse CLI is organized into three formally separated tiers. Each tier has a |
| 4 | distinct contract, audience, and stability guarantee. |
| 5 | |
| 6 | ``` |
| 7 | ┌──────────────────────────────────────────────────────────────────┐ |
| 8 | │ Tier 3 — Semantic Porcelain │ |
| 9 | │ muse midi … muse code … muse coord … │ |
| 10 | │ Domain-specific multidimensional commands │ |
| 11 | ├──────────────────────────────────────────────────────────────────┤ |
| 12 | │ Tier 2 — Core Porcelain │ |
| 13 | │ muse init / commit / status / log / diff / show … │ |
| 14 | │ Human and agent VCS operations (domain-agnostic) │ |
| 15 | ├──────────────────────────────────────────────────────────────────┤ |
| 16 | │ Tier 1 — Plumbing │ |
| 17 | │ muse plumbing hash-object / cat-object / rev-parse … │ |
| 18 | │ Machine-readable, JSON-outputting, pipeable primitives │ |
| 19 | └──────────────────────────────────────────────────────────────────┘ |
| 20 | ``` |
| 21 | |
| 22 | --- |
| 23 | |
| 24 | ## Tier 1 — Plumbing |
| 25 | |
| 26 | **Namespace:** `muse plumbing <command>` |
| 27 | |
| 28 | ### Contract |
| 29 | |
| 30 | Every Tier 1 command: |
| 31 | |
| 32 | - **Outputs JSON by default** — machine-stable schema, versioned, agent-parseable. |
| 33 | - **Accepts `--format text`** — human-readable fallback where meaningful. |
| 34 | - **Never prompts** — strictly non-interactive; safe for agent pipelines. |
| 35 | - **Exit codes** — `0` success, `1` user error (bad args, missing ref), `3` internal error. |
| 36 | - **Pipeable** — reads from stdin (`unpack-objects`) or writes to stdout (`pack-objects`, `cat-object`). |
| 37 | - **Stable API** — output schemas do not break across Muse versions. |
| 38 | |
| 39 | Tier 1 commands are the atoms from which Tier 2 porcelain is composed. They |
| 40 | expose the raw engine directly, enabling MuseHub, agent orchestrators, CI |
| 41 | pipelines, and shell scripts to interact with the store without going through |
| 42 | the higher-level VCS logic. |
| 43 | |
| 44 | ### Commands |
| 45 | |
| 46 | | Command | Description | |
| 47 | |---------|-------------| |
| 48 | | `muse plumbing hash-object [--write] <file>` | SHA-256 a file; optionally store it in `.muse/objects/` | |
| 49 | | `muse plumbing cat-object [--format raw\|info] <object_id>` | Emit raw bytes of a stored blob to stdout | |
| 50 | | `muse plumbing rev-parse [--format json\|text] <ref>` | Resolve branch / HEAD / SHA prefix → full commit ID | |
| 51 | | `muse plumbing ls-files [--commit <id>] [--format json\|text]` | List all tracked files and their object IDs | |
| 52 | | `muse plumbing read-commit <id>` | Emit full commit metadata as JSON | |
| 53 | | `muse plumbing read-snapshot <id>` | Emit full snapshot manifest and metadata as JSON | |
| 54 | | `muse plumbing commit-tree --snapshot <id> [--parent <id>]… [--message <msg>]` | Create a commit from an explicit snapshot ID | |
| 55 | | `muse plumbing update-ref [--delete\|--no-verify] <branch> [<commit_id>]` | Move or delete a branch HEAD | |
| 56 | | `muse plumbing commit-graph [--tip <id>] [--stop-at <id>] [--max N]` | Emit the commit DAG as a JSON node list | |
| 57 | | `muse plumbing pack-objects [--have <id>]… <want_id>…` | Build a `PackBundle` JSON and write to stdout | |
| 58 | | `muse plumbing unpack-objects` | Read `PackBundle` JSON from stdin, write to local store | |
| 59 | | `muse plumbing ls-remote [--json] <remote-or-url>` | List remote branch heads without modifying local state | |
| 60 | |
| 61 | ### JSON Output Schemas |
| 62 | |
| 63 | #### `hash-object` |
| 64 | |
| 65 | ```json |
| 66 | { |
| 67 | "object_id": "<sha256-hex-64>", |
| 68 | "stored": false |
| 69 | } |
| 70 | ``` |
| 71 | |
| 72 | #### `cat-object --format info` |
| 73 | |
| 74 | ```json |
| 75 | { |
| 76 | "object_id": "<sha256-hex-64>", |
| 77 | "present": true, |
| 78 | "size_bytes": 1234 |
| 79 | } |
| 80 | ``` |
| 81 | |
| 82 | With `--format raw` (default): raw bytes written to stdout. |
| 83 | |
| 84 | #### `rev-parse` |
| 85 | |
| 86 | ```json |
| 87 | { |
| 88 | "ref": "main", |
| 89 | "commit_id": "<sha256-hex-64>" |
| 90 | } |
| 91 | ``` |
| 92 | |
| 93 | Error (exit 1): |
| 94 | ```json |
| 95 | { |
| 96 | "ref": "nonexistent", |
| 97 | "commit_id": null, |
| 98 | "error": "not found" |
| 99 | } |
| 100 | ``` |
| 101 | |
| 102 | #### `ls-files` |
| 103 | |
| 104 | ```json |
| 105 | { |
| 106 | "commit_id": "<sha256>", |
| 107 | "snapshot_id": "<sha256>", |
| 108 | "file_count": 3, |
| 109 | "files": [ |
| 110 | {"path": "tracks/drums.mid", "object_id": "<sha256>"}, |
| 111 | {"path": "tracks/bass.mid", "object_id": "<sha256>"} |
| 112 | ] |
| 113 | } |
| 114 | ``` |
| 115 | |
| 116 | #### `read-commit` |
| 117 | |
| 118 | Full `CommitRecord` JSON — see `store.py` for the complete schema. |
| 119 | Key fields: |
| 120 | |
| 121 | ```json |
| 122 | { |
| 123 | "commit_id": "<sha256>", |
| 124 | "repo_id": "<uuid>", |
| 125 | "branch": "main", |
| 126 | "snapshot_id": "<sha256>", |
| 127 | "message": "Add verse melody", |
| 128 | "committed_at": "2026-03-18T12:00:00+00:00", |
| 129 | "parent_commit_id": "<sha256> | null", |
| 130 | "parent2_commit_id": null, |
| 131 | "author": "gabriel", |
| 132 | "agent_id": "", |
| 133 | "sem_ver_bump": "none" |
| 134 | } |
| 135 | ``` |
| 136 | |
| 137 | #### `read-snapshot` |
| 138 | |
| 139 | ```json |
| 140 | { |
| 141 | "snapshot_id": "<sha256>", |
| 142 | "created_at": "2026-03-18T12:00:00+00:00", |
| 143 | "file_count": 3, |
| 144 | "manifest": { |
| 145 | "tracks/drums.mid": "<sha256>", |
| 146 | "tracks/bass.mid": "<sha256>" |
| 147 | } |
| 148 | } |
| 149 | ``` |
| 150 | |
| 151 | #### `commit-tree` |
| 152 | |
| 153 | ```json |
| 154 | {"commit_id": "<sha256>"} |
| 155 | ``` |
| 156 | |
| 157 | #### `update-ref` |
| 158 | |
| 159 | ```json |
| 160 | { |
| 161 | "branch": "main", |
| 162 | "commit_id": "<sha256>", |
| 163 | "previous": "<sha256> | null" |
| 164 | } |
| 165 | ``` |
| 166 | |
| 167 | Delete (`--delete`): |
| 168 | ```json |
| 169 | {"branch": "todelete", "deleted": true} |
| 170 | ``` |
| 171 | |
| 172 | #### `commit-graph` |
| 173 | |
| 174 | ```json |
| 175 | { |
| 176 | "tip": "<sha256>", |
| 177 | "count": 42, |
| 178 | "truncated": false, |
| 179 | "commits": [ |
| 180 | { |
| 181 | "commit_id": "<sha256>", |
| 182 | "parent_commit_id": "<sha256> | null", |
| 183 | "parent2_commit_id": null, |
| 184 | "message": "Add verse melody", |
| 185 | "branch": "main", |
| 186 | "committed_at": "2026-03-18T12:00:00+00:00", |
| 187 | "snapshot_id": "<sha256>", |
| 188 | "author": "gabriel" |
| 189 | } |
| 190 | ] |
| 191 | } |
| 192 | ``` |
| 193 | |
| 194 | #### `pack-objects` / `unpack-objects` |
| 195 | |
| 196 | `pack-objects` writes a `PackBundle` JSON to stdout: |
| 197 | |
| 198 | ```json |
| 199 | { |
| 200 | "commits": [{ ...CommitDict... }], |
| 201 | "snapshots": [{ ...SnapshotDict... }], |
| 202 | "objects": [{"object_id": "<sha256>", "content_b64": "<base64>"}], |
| 203 | "branch_heads": {"main": "<sha256>"} |
| 204 | } |
| 205 | ``` |
| 206 | |
| 207 | `unpack-objects` reads a `PackBundle` from stdin and outputs: |
| 208 | |
| 209 | ```json |
| 210 | { |
| 211 | "commits_written": 12, |
| 212 | "snapshots_written": 12, |
| 213 | "objects_written": 47, |
| 214 | "objects_skipped": 3 |
| 215 | } |
| 216 | ``` |
| 217 | |
| 218 | #### `ls-remote --json` |
| 219 | |
| 220 | ```json |
| 221 | { |
| 222 | "repo_id": "<uuid>", |
| 223 | "domain": "midi", |
| 224 | "default_branch": "main", |
| 225 | "branches": { |
| 226 | "main": "<sha256>", |
| 227 | "dev": "<sha256>" |
| 228 | } |
| 229 | } |
| 230 | ``` |
| 231 | |
| 232 | --- |
| 233 | |
| 234 | ## Tier 2 — Core Porcelain |
| 235 | |
| 236 | **Namespace:** top-level `muse <command>` |
| 237 | |
| 238 | These are the human and agent VCS commands — the interface most users interact |
| 239 | with. They compose Tier 1 plumbing primitives into user-friendly workflows. |
| 240 | |
| 241 | | Command | Description | |
| 242 | |---------|-------------| |
| 243 | | `muse init` | Initialise a new Muse repository | |
| 244 | | `muse commit` | Record the current working tree as a new version | |
| 245 | | `muse status` | Show working-tree drift against HEAD | |
| 246 | | `muse log` | Display commit history | |
| 247 | | `muse diff` | Compare working tree against HEAD, or two commits | |
| 248 | | `muse show` | Inspect a commit: metadata, diff, files | |
| 249 | | `muse branch` | List, create, or delete branches | |
| 250 | | `muse checkout` | Switch branches or restore working tree | |
| 251 | | `muse merge` | Three-way merge a branch into the current branch | |
| 252 | | `muse reset` | Move HEAD to a prior commit | |
| 253 | | `muse revert` | Create a commit that undoes a prior commit | |
| 254 | | `muse cherry-pick` | Apply a specific commit's changes on top of HEAD | |
| 255 | | `muse stash` | Shelve and restore uncommitted changes | |
| 256 | | `muse tag` | Attach and query semantic tags on commits | |
| 257 | | `muse domains` | Domain plugin dashboard | |
| 258 | | `muse attributes` | Display `.museattributes` merge-strategy rules | |
| 259 | | `muse remote` | Manage remote connections (add/remove/list/set-url) | |
| 260 | | `muse clone` | Create a local copy of a remote Muse repository | |
| 261 | | `muse fetch` | Download commits/snapshots/objects from a remote | |
| 262 | | `muse pull` | Fetch from a remote and merge into current branch | |
| 263 | | `muse push` | Upload local commits/snapshots/objects to a remote | |
| 264 | | `muse check` | Domain-agnostic invariant check | |
| 265 | | `muse annotate` | CRDT-backed commit annotations | |
| 266 | |
| 267 | --- |
| 268 | |
| 269 | ## Tier 3 — Semantic Porcelain |
| 270 | |
| 271 | **Namespaces:** `muse midi …`, `muse code …`, `muse coord …` |
| 272 | |
| 273 | Domain-specific commands that interpret multidimensional state. These are |
| 274 | impossible to implement in Git — they require awareness of the domain's |
| 275 | semantic model (note events, symbol graphs, agent coordination). |
| 276 | |
| 277 | ### `muse midi …` — MIDI Domain |
| 278 | |
| 279 | | Command | Description | |
| 280 | |---------|-------------| |
| 281 | | `muse midi notes` | List every note in a MIDI track as musical notation | |
| 282 | | `muse midi note-log` | Note-level commit history | |
| 283 | | `muse midi note-blame` | Per-bar attribution | |
| 284 | | `muse midi harmony` | Chord analysis and key detection | |
| 285 | | `muse midi piano-roll` | ASCII piano roll visualization | |
| 286 | | `muse midi hotspots` | Bar-level churn leaderboard | |
| 287 | | `muse midi velocity-profile` | Dynamic range and velocity histogram | |
| 288 | | `muse midi transpose` | Transpose all notes by N semitones | |
| 289 | | `muse midi mix` | Combine two MIDI tracks into one | |
| 290 | | `muse midi query` | MIDI DSL predicate query over commit history | |
| 291 | | `muse midi check` | Enforce MIDI invariant rules | |
| 292 | |
| 293 | ### `muse code …` — Code Domain |
| 294 | |
| 295 | | Command | Description | |
| 296 | |---------|-------------| |
| 297 | | `muse code symbols` | List every semantic symbol in a snapshot | |
| 298 | | `muse code symbol-log` | Track a symbol through commit history | |
| 299 | | `muse code detect-refactor` | Detect renames, moves, extractions | |
| 300 | | `muse code grep` | Search the symbol graph by name/kind/language | |
| 301 | | `muse code blame` | Which commit last touched a specific symbol? | |
| 302 | | `muse code hotspots` | Symbol churn leaderboard | |
| 303 | | `muse code stable` | Symbol stability leaderboard | |
| 304 | | `muse code coupling` | File co-change analysis | |
| 305 | | `muse code compare` | Deep semantic comparison between snapshots | |
| 306 | | `muse code languages` | Language and symbol-type breakdown | |
| 307 | | `muse code patch` | Surgical semantic patch on a single symbol | |
| 308 | | `muse code query` | Symbol graph predicate DSL | |
| 309 | | `muse code query-history` | Temporal symbol search across a commit range | |
| 310 | | `muse code deps` | Import graph + call-graph | |
| 311 | | `muse code find-symbol` | Cross-commit, cross-branch symbol search | |
| 312 | | `muse code impact` | Transitive blast-radius | |
| 313 | | `muse code dead` | Dead code candidates | |
| 314 | | `muse code coverage` | Class interface call-coverage | |
| 315 | | `muse code lineage` | Full provenance chain of a symbol | |
| 316 | | `muse code api-surface` | Public API surface at a commit | |
| 317 | | `muse code codemap` | Semantic topology | |
| 318 | | `muse code clones` | Exact and near-duplicate symbols | |
| 319 | | `muse code checkout-symbol` | Restore a historical version of one symbol | |
| 320 | | `muse code semantic-cherry-pick` | Cherry-pick named symbols from a commit | |
| 321 | | `muse code index` | Manage local indexes | |
| 322 | | `muse code breakage` | Detect symbol-level structural breakage | |
| 323 | | `muse code invariants` | Enforce architectural rules | |
| 324 | | `muse code check` | Semantic invariant enforcement | |
| 325 | | `muse code code-query` | Predicate query over code commit history | |
| 326 | |
| 327 | ### `muse coord …` — Multi-Agent Coordination |
| 328 | |
| 329 | | Command | Description | |
| 330 | |---------|-------------| |
| 331 | | `muse coord reserve` | Advisory symbol reservation | |
| 332 | | `muse coord intent` | Declare a specific operation before executing it | |
| 333 | | `muse coord forecast` | Predict merge conflicts | |
| 334 | | `muse coord plan-merge` | Dry-run semantic merge plan | |
| 335 | | `muse coord shard` | Partition the codebase into N work zones | |
| 336 | | `muse coord reconcile` | Recommend merge ordering and integration strategy | |
| 337 | |
| 338 | --- |
| 339 | |
| 340 | ## Extending with New Domains |
| 341 | |
| 342 | To add a new domain (e.g. `muse genomics …`): |
| 343 | |
| 344 | 1. Create `muse/plugins/genomics/plugin.py` implementing `MuseDomainPlugin`. |
| 345 | 2. Create `muse/cli/commands/genomics_*.py` command modules. |
| 346 | 3. Add a `genomics_cli = typer.Typer(name="genomics", …)` in `muse/cli/app.py`. |
| 347 | 4. Register commands under `genomics_cli` and add `cli.add_typer(genomics_cli, name="genomics")`. |
| 348 | 5. Write tests under `tests/` and docs under `docs/reference/`. |
| 349 | |
| 350 | The core engine (`muse/core/`) is **never modified** for a new domain. |
| 351 |