code-domain.md
markdown
| 1 | # Code Domain — Complete Reference |
| 2 | |
| 3 | > **Engine:** `muse/plugins/code/` · **No external deps for core analysis** |
| 4 | > **Scope:** Every command, module, type, and protocol in the code domain plugin |
| 5 | |
| 6 | --- |
| 7 | |
| 8 | ## Overview |
| 9 | |
| 10 | The code domain plugin treats a codebase as a **typed, content-addressed symbol graph** — not as a bag of text lines. Every function, class, method, variable, and import becomes a `SymbolRecord` with a stable content-addressed identity (SHA-256). This unlocks operations that are structurally impossible in Git: |
| 11 | |
| 12 | - Track a function through renames and cross-file moves with perfect identity. |
| 13 | - Cherry-pick a single named function out of a historical commit. |
| 14 | - Detect exact and near-duplicate code across an entire snapshot in O(1). |
| 15 | - Predict merge conflicts before writing a single byte. |
| 16 | - Enforce architectural invariants as committed rules. |
| 17 | - Assign semantic version bumps automatically at commit time. |
| 18 | - Coordinate thousands of parallel agents without a central lock server. |
| 19 | |
| 20 | --- |
| 21 | |
| 22 | ## Contents |
| 23 | |
| 24 | 1. [Selective Staging (`muse code add`)](#1-selective-staging-muse-code-add) |
| 25 | 2. [Symbol Identity Model](#2-symbol-identity-model) |
| 26 | 3. [Provenance & Topology Commands](#3-provenance--topology-commands) |
| 27 | 4. [Query & Temporal Search](#4-query--temporal-search) |
| 28 | 5. [Index Infrastructure](#5-index-infrastructure) |
| 29 | 6. [Symbol Identity Detail](#6-symbol-identity-detail) |
| 30 | 7. [Multi-Agent Coordination Layer](#7-multi-agent-coordination-layer) |
| 31 | 8. [Merge Engine & Architectural Enforcement](#8-merge-engine--architectural-enforcement) |
| 32 | 9. [Semantic Versioning](#9-semantic-versioning) |
| 33 | 10. [Call-Graph Tier Commands](#10-call-graph-tier-commands) |
| 34 | 11. [Architecture Internals](#11-architecture-internals) |
| 35 | 12. [Type Reference](#12-type-reference) |
| 36 | |
| 37 | --- |
| 38 | |
| 39 | <a id="1-selective-staging"></a> |
| 40 | ## 1. Selective Staging (`muse code add`) |
| 41 | |
| 42 | The code domain adds a **Git-style staging index** to Muse. By default, |
| 43 | `muse commit` snapshots the entire working tree. Once you run `muse code add`, |
| 44 | the next commit includes *only* what you have explicitly staged — everything |
| 45 | else carries forward from the previous commit unchanged. |
| 46 | |
| 47 | This lets you commit a coherent, working subset of your in-progress changes |
| 48 | without committing half-finished code. |
| 49 | |
| 50 | ### Stage index location |
| 51 | |
| 52 | `.muse/code/stage.json` — a JSON file that maps workspace-relative paths to |
| 53 | their staged object IDs and mode (`A` added / `M` modified / `D` deleted`). |
| 54 | |
| 55 | ### `muse code add` |
| 56 | |
| 57 | ``` |
| 58 | muse code add <file> [<file> …] # stage one or more files |
| 59 | muse code add <dir> # stage every file under a directory |
| 60 | muse code add . # stage everything in the working tree |
| 61 | muse code add -A / --all # stage all changes, including new files |
| 62 | muse code add -u / --update # stage only tracked (already-committed) files |
| 63 | # modified or deleted on disk — no new files |
| 64 | muse code add -p / --patch <file> # interactive hunk-by-hunk staging |
| 65 | muse code add -n / --dry-run … # show what would be staged without staging |
| 66 | muse code add -v / --verbose … # print each file as it is staged |
| 67 | ``` |
| 68 | |
| 69 | #### Patch mode (`-p`) |
| 70 | |
| 71 | Interactive hunk-by-hunk staging, mirroring `git add -p`. For each diff |
| 72 | hunk you are prompted: |
| 73 | |
| 74 | | Key | Action | |
| 75 | |-----|--------| |
| 76 | | `y` | Stage this hunk | |
| 77 | | `n` | Skip this hunk | |
| 78 | | `q` | Quit; commit hunks accepted so far | |
| 79 | | `a` | Stage this and all remaining hunks in this file | |
| 80 | | `d` | Skip the rest of this file | |
| 81 | | `?` | Show help | |
| 82 | |
| 83 | The partial file (accepted hunks only) is hashed, written to the object store, |
| 84 | and recorded in the stage index. The working tree is **never modified**. |
| 85 | |
| 86 | Agents should use explicit file paths (`muse code add <file>`) and avoid |
| 87 | `--patch`, which requires an interactive terminal. |
| 88 | |
| 89 | ### `muse code reset` |
| 90 | |
| 91 | ``` |
| 92 | muse code reset # unstage everything |
| 93 | muse code reset <file> # unstage a specific file |
| 94 | muse code reset HEAD <file> # same — mirrors Git syntax |
| 95 | ``` |
| 96 | |
| 97 | Removes files from the stage index without touching the working tree. The |
| 98 | working tree copy is always preserved. |
| 99 | |
| 100 | ### `muse commit` with an active stage |
| 101 | |
| 102 | When `.muse/code/stage.json` exists and is non-empty: |
| 103 | |
| 104 | - Staged files → committed at their **staged** object ID. |
| 105 | - Tracked-but-unstaged files → carried forward at their **committed** (HEAD) object ID. |
| 106 | - Untracked files → not included in the commit. |
| 107 | |
| 108 | After a successful commit the stage index is **cleared automatically**. |
| 109 | |
| 110 | ### `muse status` with an active stage |
| 111 | |
| 112 | When a stage is active, `muse status` renders a three-bucket view: |
| 113 | |
| 114 | ``` |
| 115 | On branch main |
| 116 | |
| 117 | Changes staged for commit: |
| 118 | (use "muse code reset HEAD <file>" to unstage) |
| 119 | |
| 120 | new file: src/auth.py |
| 121 | modified: src/models.py |
| 122 | |
| 123 | Changes not staged for commit: |
| 124 | (use "muse code add <file>" to update what will be committed) |
| 125 | |
| 126 | modified: src/broken_wip.py |
| 127 | |
| 128 | Untracked files: |
| 129 | (use "muse code add <file>" to include in what will be committed) |
| 130 | |
| 131 | tmp_experiment.py |
| 132 | ``` |
| 133 | |
| 134 | With `--format json`: |
| 135 | |
| 136 | ```json |
| 137 | { |
| 138 | "branch": "main", |
| 139 | "clean": false, |
| 140 | "staged": { |
| 141 | "src/auth.py": {"mode": "A", "object_id": "<sha256>"} |
| 142 | }, |
| 143 | "unstaged": { |
| 144 | "src/broken_wip.py": "modified" |
| 145 | }, |
| 146 | "untracked": ["tmp_experiment.py"] |
| 147 | } |
| 148 | ``` |
| 149 | |
| 150 | ### Workflow example |
| 151 | |
| 152 | ```bash |
| 153 | # Edit freely — nothing is committed until you stage. |
| 154 | vim src/auth.py src/models.py src/wip.py |
| 155 | |
| 156 | # Stage only the production-ready files. |
| 157 | muse code add src/auth.py src/models.py |
| 158 | |
| 159 | # Verify what will be committed. |
| 160 | muse status |
| 161 | |
| 162 | # Commit exactly what was staged. |
| 163 | muse commit -m "feat: add auth + models" |
| 164 | |
| 165 | # The working-tree copy of wip.py is untouched. |
| 166 | ``` |
| 167 | |
| 168 | --- |
| 169 | |
| 170 | <a id="2-symbol-identity-model"></a> |
| 171 | ## 2. Symbol Identity Model |
| 172 | |
| 173 | Every symbol carries four content-addressed hashes and two stable keys: |
| 174 | |
| 175 | | Field | Description | |
| 176 | |---|---| |
| 177 | | `content_id` | SHA-256 of the full normalized AST (signature + body + metadata). Two symbols are identical iff their `content_id` matches. | |
| 178 | | `body_hash` | SHA-256 of the function/class body only (excluding signature and decorators). Matches across renames and decorator changes. | |
| 179 | | `signature_id` | SHA-256 of the normalized parameter list and return annotation. Matches across implementation-only changes. | |
| 180 | | `metadata_id` *(v2)* | SHA-256 of decorator list + async flag + base classes. Matches when only the implementation or signature changed. | |
| 181 | | `canonical_key` *(v2)* | `{file}#{scope}#{kind}#{name}#{lineno}` — stable machine handle for agent-to-agent symbol handoff. | |
| 182 | | `qualified_name` | Dotted path within the file (e.g. `MyClass.my_method`). | |
| 183 | |
| 184 | ### Exact Refactor Classification |
| 185 | |
| 186 | Two symbols are classified by comparing their four hashes: |
| 187 | |
| 188 | | Classification | Condition | |
| 189 | |---|---| |
| 190 | | `unchanged` | `content_id` matches | |
| 191 | | `rename` | `body_hash` matches, name differs, same file | |
| 192 | | `move` | `content_id` matches, different file, same name | |
| 193 | | `rename+move` | `body_hash` matches, different file, different name | |
| 194 | | `signature_only` | `body_hash` matches, `signature_id` differs | |
| 195 | | `impl_only` | `signature_id` matches, `body_hash` differs | |
| 196 | | `metadata_only` | `body_hash` + `signature_id` match, `metadata_id` differs | |
| 197 | | `full_rewrite` | Both signature and body changed | |
| 198 | |
| 199 | --- |
| 200 | |
| 201 | <a id="3-provenance--topology-commands"></a> |
| 202 | ## 3. Provenance & Topology Commands |
| 203 | |
| 204 | ### `muse code lineage ADDRESS` |
| 205 | |
| 206 | Full provenance chain of a named symbol from its first appearance to the present. |
| 207 | |
| 208 | ``` |
| 209 | muse code lineage src/billing.py::compute_total |
| 210 | muse code lineage src/billing.py::compute_total --commit HEAD~10 |
| 211 | muse code lineage src/billing.py::compute_total --json |
| 212 | ``` |
| 213 | |
| 214 | **How it works:** Walks all commits in chronological order, scanning `InsertOp`/`DeleteOp`/`ReplaceOp` entries in each `structured_delta`. Rename detection uses `content_id` matching across Insert+Delete pairs within a single commit. |
| 215 | |
| 216 | **Output events:** `created`, `modified`, `renamed_from`, `moved_from`, `deleted`. |
| 217 | |
| 218 | **Flags:** |
| 219 | - `--commit REF` — stop history walk at this commit (default: HEAD) |
| 220 | - `--json` — emit a JSON array of event objects |
| 221 | |
| 222 | **JSON schema:** |
| 223 | ```json |
| 224 | [ |
| 225 | { |
| 226 | "event": "created", |
| 227 | "commit_id": "a1b2c3d4...", |
| 228 | "committed_at": "2026-01-01T00:00:00+00:00", |
| 229 | "message": "Initial commit", |
| 230 | "address": "src/billing.py::compute_total", |
| 231 | "content_id": "sha256..." |
| 232 | } |
| 233 | ] |
| 234 | ``` |
| 235 | |
| 236 | --- |
| 237 | |
| 238 | ### `muse code api-surface` |
| 239 | |
| 240 | Public API surface of a snapshot — every non-underscore function, class, and method. |
| 241 | |
| 242 | ``` |
| 243 | muse code api-surface |
| 244 | muse code api-surface --commit v1.0 |
| 245 | muse code api-surface --diff v1.0 |
| 246 | muse code api-surface --json |
| 247 | ``` |
| 248 | |
| 249 | **With `--diff REF`:** Shows three sections — **Added** (new public symbols), **Removed** (deleted public symbols), **Changed** (same address, different `content_id`). |
| 250 | |
| 251 | **Public** means: `kind` in `{function, class, method, async_function}` and `name` not starting with `_`. |
| 252 | |
| 253 | --- |
| 254 | |
| 255 | ### `muse code codemap` |
| 256 | |
| 257 | Semantic topology of the entire codebase at a snapshot. |
| 258 | |
| 259 | ``` |
| 260 | muse code codemap |
| 261 | muse code codemap --top 10 |
| 262 | muse code codemap --commit HEAD~5 |
| 263 | muse code codemap --json |
| 264 | ``` |
| 265 | |
| 266 | **What it shows:** |
| 267 | - **Modules by size** — ranked by symbol count |
| 268 | - **Import graph** — in-degree (how many modules import this one) |
| 269 | - **Cycles** — import cycles detected via DFS (a hard architectural smell) |
| 270 | - **High-centrality symbols** — functions called from many places (blast-radius risk) |
| 271 | - **Boundary files** — high fan-out (imports many), zero fan-in (nothing imports them) |
| 272 | |
| 273 | **Flags:** |
| 274 | - `--top N` — show top N entries per section (default: 5) |
| 275 | - `--commit REF` — snapshot to analyse |
| 276 | - `--json` — structured output |
| 277 | |
| 278 | --- |
| 279 | |
| 280 | ### `muse code clones` |
| 281 | |
| 282 | Find exact and near-duplicate symbol clusters across the snapshot. |
| 283 | |
| 284 | ``` |
| 285 | muse code clones |
| 286 | muse code clones --tier exact |
| 287 | muse code clones --tier near |
| 288 | muse code clones --tier both |
| 289 | muse code clones --commit HEAD~3 --json |
| 290 | ``` |
| 291 | |
| 292 | **Exact clones:** Same `body_hash` at different addresses. These are literal copy-paste duplicates — same implementation, possibly different name. |
| 293 | |
| 294 | **Near-clones:** Same `signature_id`, different `body_hash`. Same public contract (parameters + return type), diverged implementation — a maintainability risk. |
| 295 | |
| 296 | **Output:** Clusters, one per group, listing all member addresses. |
| 297 | |
| 298 | --- |
| 299 | |
| 300 | ### `muse code checkout-symbol ADDRESS --commit REF` |
| 301 | |
| 302 | Restore a single named symbol from a historical commit into the current working tree. Only the target symbol's lines change; everything else is untouched. |
| 303 | |
| 304 | ``` |
| 305 | muse code checkout-symbol src/billing.py::compute_total --commit v1.0 |
| 306 | muse code checkout-symbol src/billing.py::compute_total --commit abc123 --dry-run |
| 307 | muse code checkout-symbol src/billing.py::compute_total --commit v1.0 --json |
| 308 | ``` |
| 309 | |
| 310 | **Flags:** |
| 311 | - `--commit REF` *(required)* — source commit |
| 312 | - `--dry-run` — print the unified diff without writing |
| 313 | - `--json` — emit result as JSON for agent consumption |
| 314 | |
| 315 | **JSON output:** |
| 316 | |
| 317 | ```json |
| 318 | { |
| 319 | "address": "src/billing.py::compute_total", |
| 320 | "file": "src/billing.py", |
| 321 | "restored_from": "abc12345", |
| 322 | "dry_run": false |
| 323 | } |
| 324 | ``` |
| 325 | |
| 326 | **Safety:** Rejects the operation if the target file cannot be parsed (syntax error) or if the symbol no longer exists at the destination location and the file cannot be safely patched. |
| 327 | |
| 328 | **Security:** The file path component of ADDRESS is validated via `contain_path()` before any disk access. Paths that escape the repo root (e.g. `../../etc/passwd::foo`) are rejected with exit 1. |
| 329 | |
| 330 | --- |
| 331 | |
| 332 | ### `muse code semantic-cherry-pick ADDRESS... --from REF` |
| 333 | |
| 334 | Cherry-pick one or more named symbols from a historical commit. Applies each symbol patch to the working tree at the symbol's current location; appends at the end of the file if the symbol is not present in the current tree. |
| 335 | |
| 336 | ``` |
| 337 | muse code semantic-cherry-pick src/billing.py::compute_total --from v1.0 |
| 338 | muse code semantic-cherry-pick src/billing.py::f1 src/billing.py::f2 --from abc123 |
| 339 | muse code semantic-cherry-pick src/billing.py::compute_total --from v1.0 --dry-run --json |
| 340 | ``` |
| 341 | |
| 342 | **Flags:** |
| 343 | - `--from REF` *(required)* — source commit |
| 344 | - `--dry-run` — show what would change without writing |
| 345 | - `--json` — structured output with per-symbol patch results |
| 346 | |
| 347 | **JSON output:** |
| 348 | |
| 349 | ```json |
| 350 | { |
| 351 | "from_commit": "abc12345", |
| 352 | "dry_run": false, |
| 353 | "results": [ |
| 354 | {"address": "src/billing.py::compute_total", "status": "applied", |
| 355 | "detail": "lines 10–25 → 12 lines", "old_lines": 16, "new_lines": 12} |
| 356 | ], |
| 357 | "applied": 1, |
| 358 | "failed": 0, |
| 359 | "already_current": 0 |
| 360 | } |
| 361 | ``` |
| 362 | |
| 363 | **Security:** Every file path extracted from ADDRESS arguments is validated via `contain_path()` before any disk I/O or directory creation. Paths that escape the repo root are recorded as `not_found` and the remaining symbols continue to be processed. |
| 364 | |
| 365 | --- |
| 366 | |
| 367 | <a id="4-query--temporal-search"></a> |
| 368 | ## 4. Query & Temporal Search |
| 369 | |
| 370 | ### `muse code query PREDICATE...` |
| 371 | |
| 372 | Symbol graph predicate DSL — SQL for your codebase. |
| 373 | |
| 374 | ``` |
| 375 | muse code query kind=function language=Python |
| 376 | muse code query "(kind=function OR kind=method) name^=_" |
| 377 | muse code query "NOT kind=import file~=billing" |
| 378 | muse code query kind=function name~=validate --all-commits |
| 379 | muse code query hash=a3f2c9 --all-commits --first |
| 380 | muse code query --commit v1.0 kind=class |
| 381 | muse code query kind=function --json |
| 382 | ``` |
| 383 | |
| 384 | #### Predicate Grammar (v2) |
| 385 | |
| 386 | ``` |
| 387 | expr = or_expr |
| 388 | or_expr = and_expr ( "OR" and_expr )* |
| 389 | and_expr = not_expr ( and_expr )* # implicit AND |
| 390 | not_expr = "NOT" primary | primary |
| 391 | primary = "(" expr ")" | atom |
| 392 | atom = KEY OP VALUE |
| 393 | ``` |
| 394 | |
| 395 | #### Operators |
| 396 | |
| 397 | | Operator | Meaning | |
| 398 | |---|---| |
| 399 | | `=` | Exact match (case-insensitive for strings) | |
| 400 | | `~=` | Contains substring | |
| 401 | | `^=` | Starts with | |
| 402 | | `$=` | Ends with | |
| 403 | | `!=` | Not equal | |
| 404 | | `>=` | Greater than or equal (lineno keys only) | |
| 405 | | `<=` | Less than or equal (lineno keys only) | |
| 406 | |
| 407 | #### Keys |
| 408 | |
| 409 | | Key | Type | Description | |
| 410 | |---|---|---| |
| 411 | | `kind` | string | `function`, `class`, `method`, `variable`, `import`, … | |
| 412 | | `language` | string | `Python`, `Go`, `Rust`, `TypeScript`, … | |
| 413 | | `name` | string | Bare symbol name | |
| 414 | | `qualified_name` | string | Dotted qualified name (e.g. `MyClass.save`) | |
| 415 | | `file` | string | File path (relative to repo root) | |
| 416 | | `hash` | string | `content_id` prefix (hex) | |
| 417 | | `body_hash` | string | `body_hash` prefix | |
| 418 | | `signature_id` | string | `signature_id` prefix | |
| 419 | | `lineno_gt` | integer | Symbol starts *after* this line number | |
| 420 | | `lineno_lt` | integer | Symbol starts *before* this line number | |
| 421 | |
| 422 | #### Flags |
| 423 | |
| 424 | | Flag | Description | |
| 425 | |---|---| |
| 426 | | `--commit REF` | Query a specific commit (mutually exclusive with `--all-commits`) | |
| 427 | | `--all-commits` | Walk all commits, deduplicate by `content_id`, annotate first-seen commit | |
| 428 | | `--first` | With `--all-commits`: keep only the first appearance of each unique body | |
| 429 | | `--json` | JSON output with `schema_version: 2` wrapper | |
| 430 | |
| 431 | --- |
| 432 | |
| 433 | ### `muse code query-history PREDICATE... [--from REF] [--to REF]` |
| 434 | |
| 435 | Temporal symbol search — track matching symbols across a commit range. |
| 436 | |
| 437 | ``` |
| 438 | muse code query-history kind=function language=Python |
| 439 | muse code query-history name~=validate --from v1.0 --to HEAD |
| 440 | muse code query-history kind=class --json |
| 441 | ``` |
| 442 | |
| 443 | **Output:** For each matching symbol address, reports `first_seen`, `last_seen`, `commit_count` (how many commits touched it), and `change_count` (how many times its `content_id` changed). |
| 444 | |
| 445 | **JSON schema:** |
| 446 | ```json |
| 447 | { |
| 448 | "schema_version": 2, |
| 449 | "query": "kind=function language=Python", |
| 450 | "from_ref": "v1.0", |
| 451 | "to_ref": "HEAD", |
| 452 | "results": [ |
| 453 | { |
| 454 | "address": "src/billing.py::compute_total", |
| 455 | "first_seen": "commit_id...", |
| 456 | "last_seen": "commit_id...", |
| 457 | "commit_count": 12, |
| 458 | "change_count": 3 |
| 459 | } |
| 460 | ] |
| 461 | } |
| 462 | ``` |
| 463 | |
| 464 | --- |
| 465 | |
| 466 | <a id="5-index-infrastructure"></a> |
| 467 | ## 5. Index Infrastructure |
| 468 | |
| 469 | ### `muse code index status` |
| 470 | |
| 471 | Show present/absent/corrupt status and entry counts for all local indexes. |
| 472 | |
| 473 | ``` |
| 474 | muse code index status |
| 475 | muse code index status --json |
| 476 | ``` |
| 477 | |
| 478 | **Flags:** |
| 479 | - `--json` — emit status array as JSON |
| 480 | |
| 481 | **JSON output:** |
| 482 | |
| 483 | ```json |
| 484 | [ |
| 485 | {"name": "symbol_history", "status": "present", "entries": 1024, "updated_at": "2026-03-21T12:00:00"}, |
| 486 | {"name": "hash_occurrence", "status": "absent", "entries": 0, "updated_at": null} |
| 487 | ] |
| 488 | ``` |
| 489 | |
| 490 | ### `muse code index rebuild` |
| 491 | |
| 492 | Rebuild one or all indexes by walking the full commit history. |
| 493 | |
| 494 | ``` |
| 495 | muse code index rebuild |
| 496 | muse code index rebuild --json |
| 497 | muse code index rebuild --index symbol_history |
| 498 | muse code index rebuild --index hash_occurrence --verbose |
| 499 | ``` |
| 500 | |
| 501 | **Flags:** |
| 502 | - `--index NAME` — rebuild only this index (default: all) |
| 503 | - `--verbose, -v` — show progress while building |
| 504 | - `--json` — emit rebuild summary as JSON |
| 505 | |
| 506 | **JSON output:** |
| 507 | |
| 508 | ```json |
| 509 | { |
| 510 | "rebuilt": ["symbol_history", "hash_occurrence"], |
| 511 | "symbol_history_addresses": 512, |
| 512 | "symbol_history_events": 2048, |
| 513 | "hash_occurrence_clusters": 31, |
| 514 | "hash_occurrence_addresses": 87 |
| 515 | } |
| 516 | ``` |
| 517 | |
| 518 | ### Index Design |
| 519 | |
| 520 | Indexes live under `.muse/indices/` and are: |
| 521 | - **Derived** — computed entirely from the commit history. |
| 522 | - **Optional** — no command requires them for correctness; they only provide speed. |
| 523 | - **Fully rebuildable** — `muse code index rebuild` reconstructs them from scratch in one pass. |
| 524 | - **Versioned** — `schema_version` field for forward compatibility. |
| 525 | |
| 526 | #### `symbol_history` index |
| 527 | |
| 528 | Maps `symbol_address → list[HistoryEntry]` (chronological). Enables O(1) lineage lookups instead of O(commits × files) scans. |
| 529 | |
| 530 | #### `hash_occurrence` index |
| 531 | |
| 532 | Maps `body_hash → list[symbol_address]`. Enables O(1) clone detection and `muse code find-symbol hash=` queries. |
| 533 | |
| 534 | --- |
| 535 | |
| 536 | <a id="6-symbol-identity-detail"></a> |
| 537 | ## 6. Symbol Identity Detail |
| 538 | |
| 539 | ### New `SymbolRecord` fields |
| 540 | |
| 541 | `SymbolRecord` gains two backward-compatible fields (empty string `""` for pre-v2 records): |
| 542 | |
| 543 | **`metadata_id`** |
| 544 | : SHA-256 of the symbol's *metadata wrapper* — decorators + async flag for Python functions, decorator list + base classes for Python classes. Allows distinguishing a decorator change from a body change. |
| 545 | |
| 546 | **`canonical_key`** |
| 547 | : `{file}#{scope}#{kind}#{name}#{lineno}` — a stable, unique machine handle for a symbol within a snapshot. Enables agent-to-agent symbol handoff without re-querying. Disambiguates overloaded names and nested scopes. |
| 548 | |
| 549 | ### `muse code detect-refactor` (v2 output) |
| 550 | |
| 551 | With `--json`, emits `schema_version: 2` with a richer classification: |
| 552 | |
| 553 | ```json |
| 554 | { |
| 555 | "schema_version": 2, |
| 556 | "from_commit": "abc...", |
| 557 | "to_commit": "def...", |
| 558 | "total": 3, |
| 559 | "events": [ |
| 560 | { |
| 561 | "old_address": "src/billing.py::compute_total", |
| 562 | "new_address": "src/billing.py::compute_invoice_total", |
| 563 | "old_kind": "function", |
| 564 | "new_kind": "function", |
| 565 | "exact_classification": "rename", |
| 566 | "inferred_refactor": "none", |
| 567 | "confidence": 1.0, |
| 568 | "evidence": ["body_hash matches a1b2c3d4"], |
| 569 | "old_content_id": "ab12cd34", |
| 570 | "new_content_id": "ef56gh78", |
| 571 | "old_body_hash": "a1b2c3d4", |
| 572 | "new_body_hash": "a1b2c3d4" |
| 573 | } |
| 574 | ] |
| 575 | } |
| 576 | ``` |
| 577 | |
| 578 | **`exact_classification`** values: `rename`, `move`, `rename+move`, `signature_only`, `impl_only`, `metadata_only`, `full_rewrite`, `unchanged`. |
| 579 | |
| 580 | **`inferred_refactor`** values: `extract`, `inline`, `split`, `merge`, `none`. |
| 581 | |
| 582 | --- |
| 583 | |
| 584 | <a id="7-multi-agent-coordination-layer"></a> |
| 585 | ## 7. Multi-Agent Coordination Layer |
| 586 | |
| 587 | The coordination layer enables thousands of agents to work on the same codebase simultaneously without stepping on each other. It is **purely advisory** — the VCS engine never reads coordination data for correctness decisions. Agents that ignore it still produce correct commits. |
| 588 | |
| 589 | ### Storage Layout |
| 590 | |
| 591 | ``` |
| 592 | .muse/coordination/ |
| 593 | reservations/<uuid>.json advisory symbol lease |
| 594 | intents/<uuid>.json declared operation before edit |
| 595 | ``` |
| 596 | |
| 597 | All records are **write-once** (never mutated) and use TTL-based expiry. Expired records are kept for audit purposes but ignored by all commands. |
| 598 | |
| 599 | --- |
| 600 | |
| 601 | ### `muse coord reserve ADDRESS... [OPTIONS]` |
| 602 | |
| 603 | Announce intent to edit one or more symbol addresses. |
| 604 | |
| 605 | ``` |
| 606 | muse coord reserve src/billing.py::compute_total |
| 607 | muse coord reserve src/billing.py::f1 src/billing.py::f2 --run-id agent-007 --ttl 7200 |
| 608 | muse coord reserve src/billing.py::compute_total --op rename |
| 609 | muse coord reserve src/billing.py::compute_total --json |
| 610 | ``` |
| 611 | |
| 612 | **Flags:** |
| 613 | - `--run-id ID` — identifier for this agent/run (default: random UUID) |
| 614 | - `--ttl SECONDS` — reservation expiry in seconds (default: 3600) |
| 615 | - `--op OPERATION` — declared operation: `rename`, `move`, `extract`, `modify`, `delete` |
| 616 | - `--json` — JSON output |
| 617 | |
| 618 | **Conflict detection:** Warns (but never blocks) if any of the requested addresses are already reserved by another active reservation. |
| 619 | |
| 620 | **Reservation schema (v1):** |
| 621 | ```json |
| 622 | { |
| 623 | "schema_version": 1, |
| 624 | "reservation_id": "<uuid>", |
| 625 | "run_id": "<agent-supplied ID>", |
| 626 | "branch": "<current branch>", |
| 627 | "addresses": ["src/billing.py::compute_total"], |
| 628 | "created_at": "2026-03-18T12:00:00+00:00", |
| 629 | "expires_at": "2026-03-18T13:00:00+00:00", |
| 630 | "operation": "rename" |
| 631 | } |
| 632 | ``` |
| 633 | |
| 634 | --- |
| 635 | |
| 636 | ### `muse coord intent ADDRESS... --op OPERATION [OPTIONS]` |
| 637 | |
| 638 | Declare a specific operation before executing it. More precise than a reservation; enables `muse coord forecast` to produce accurate conflict predictions. |
| 639 | |
| 640 | ``` |
| 641 | muse coord intent src/billing.py::compute_total --op rename --detail "rename to compute_invoice_total" |
| 642 | muse coord intent src/billing.py::compute_total --op modify --reservation-id <uuid> |
| 643 | ``` |
| 644 | |
| 645 | **Flags:** |
| 646 | - `--op OPERATION` *(required)* — `rename`, `move`, `extract`, `modify`, `delete`, `refactor` |
| 647 | - `--detail TEXT` — free-text description of the planned change |
| 648 | - `--reservation-id UUID` — link to an existing reservation |
| 649 | - `--run-id ID` — agent identifier |
| 650 | - `--json` — JSON output |
| 651 | |
| 652 | **Intent schema (v1):** |
| 653 | ```json |
| 654 | { |
| 655 | "schema_version": 1, |
| 656 | "intent_id": "<uuid>", |
| 657 | "reservation_id": "<uuid or empty>", |
| 658 | "run_id": "<agent ID>", |
| 659 | "branch": "<current branch>", |
| 660 | "addresses": ["src/billing.py::compute_total"], |
| 661 | "operation": "rename", |
| 662 | "created_at": "2026-03-18T12:00:00+00:00", |
| 663 | "detail": "rename to compute_invoice_total" |
| 664 | } |
| 665 | ``` |
| 666 | |
| 667 | --- |
| 668 | |
| 669 | ### `muse coord forecast [OPTIONS]` |
| 670 | |
| 671 | Predict merge conflicts from active reservations and intents — **before** writing any code. |
| 672 | |
| 673 | ``` |
| 674 | muse coord forecast |
| 675 | muse coord forecast --branch feature-x |
| 676 | muse coord forecast --json |
| 677 | ``` |
| 678 | |
| 679 | **Conflict types detected:** |
| 680 | |
| 681 | | Type | Confidence | Condition | |
| 682 | |---|---|---| |
| 683 | | `address_overlap` | 1.0 | Two reservations on the same symbol address | |
| 684 | | `blast_radius_overlap` | 0.75 | Reservations on symbols that call each other (via call graph) | |
| 685 | | `operation_conflict` | 0.9 | Two reservations declare incompatible operations (e.g. both `rename`) | |
| 686 | |
| 687 | **Flags:** |
| 688 | - `--branch BRANCH` — restrict to reservations on this branch |
| 689 | - `--json` — structured conflict list |
| 690 | |
| 691 | --- |
| 692 | |
| 693 | ### `muse coord plan-merge OURS THEIRS [OPTIONS]` |
| 694 | |
| 695 | Dry-run semantic merge plan — classify all symbol conflicts without writing anything. |
| 696 | |
| 697 | ``` |
| 698 | muse coord plan-merge main feature-x |
| 699 | muse coord plan-merge HEAD~5 HEAD --json |
| 700 | ``` |
| 701 | |
| 702 | **Output:** Classifies each diverging symbol into one of: |
| 703 | - `no_conflict` — diverged in disjoint symbols |
| 704 | - `symbol_edit_overlap` — both sides modified the same symbol |
| 705 | - `rename_edit` — one side renamed, the other modified |
| 706 | - `delete_use` — one side deleted a symbol still used by the other |
| 707 | |
| 708 | **Flags:** |
| 709 | - `--json` — structured output with full classification details |
| 710 | |
| 711 | --- |
| 712 | |
| 713 | ### `muse coord shard --agents N [OPTIONS]` |
| 714 | |
| 715 | Partition the codebase into N low-coupling work zones for parallel agent assignment. |
| 716 | |
| 717 | ``` |
| 718 | muse coord shard --agents 4 |
| 719 | muse coord shard --agents 8 --language Python |
| 720 | muse coord shard --agents 4 --json |
| 721 | ``` |
| 722 | |
| 723 | **Algorithm:** Builds the import graph, finds connected components, greedily merges small components into N balanced shards (by symbol count). Reports cross-shard edges as a coupling score (lower is better). |
| 724 | |
| 725 | **Flags:** |
| 726 | - `--agents N` *(required)* — number of shards |
| 727 | - `--language LANG` — restrict to files of this language |
| 728 | - `--json` — shard assignments as JSON |
| 729 | |
| 730 | --- |
| 731 | |
| 732 | ### `muse coord reconcile [OPTIONS]` |
| 733 | |
| 734 | Recommend merge ordering and integration strategy from the current coordination state. |
| 735 | |
| 736 | ``` |
| 737 | muse coord reconcile |
| 738 | muse coord reconcile --json |
| 739 | ``` |
| 740 | |
| 741 | **Output:** For each active branch with reservations, recommends: |
| 742 | - **Merge order** — branches with fewer predicted conflicts should merge first |
| 743 | - **Integration strategy** — `fast-forward`, `rebase`, or `manual` (when conflicts are predicted) |
| 744 | - **Conflict hotspots** — addresses that appear in the most reservations |
| 745 | |
| 746 | --- |
| 747 | |
| 748 | <a id="8-merge-engine--architectural-enforcement"></a> |
| 749 | ## 8. Merge Engine & Architectural Enforcement |
| 750 | |
| 751 | ### `ConflictRecord` — Structured Conflict Taxonomy |
| 752 | |
| 753 | `MergeResult` now carries `conflict_records: list[ConflictRecord]` alongside the existing `conflicts: list[str]`. Each `ConflictRecord` provides structured metadata for programmatic conflict handling: |
| 754 | |
| 755 | ```python |
| 756 | @dataclass |
| 757 | class ConflictRecord: |
| 758 | path: str |
| 759 | conflict_type: str = "file_level" # see taxonomy below |
| 760 | ours_summary: str = "" |
| 761 | theirs_summary: str = "" |
| 762 | addresses: list[str] = field(default_factory=list) |
| 763 | ``` |
| 764 | |
| 765 | **`conflict_type` taxonomy:** |
| 766 | |
| 767 | | Value | Meaning | |
| 768 | |---|---| |
| 769 | | `symbol_edit_overlap` | Both branches modified the same symbol | |
| 770 | | `rename_edit` | One branch renamed, the other modified | |
| 771 | | `move_edit` | One branch moved, the other modified | |
| 772 | | `delete_use` | One branch deleted a symbol still used by the other | |
| 773 | | `dependency_conflict` | Conflicting changes to interdependent symbols | |
| 774 | | `file_level` | Legacy — no symbol-level information available | |
| 775 | |
| 776 | --- |
| 777 | |
| 778 | ### `muse code breakage` |
| 779 | |
| 780 | Detect symbol-level structural breakage in the current working tree vs HEAD. |
| 781 | |
| 782 | ``` |
| 783 | muse code breakage |
| 784 | muse code breakage --language Python |
| 785 | muse code breakage --json |
| 786 | ``` |
| 787 | |
| 788 | **Checks performed:** |
| 789 | |
| 790 | 1. **`stale_import`** — a `from X import Y` where `Y` no longer exists in the committed version of `X` (detected via symbol graph, not execution). |
| 791 | 2. **`missing_interface_method`** — a class body is missing a method that exists in the HEAD snapshot's version of that class. |
| 792 | |
| 793 | **What it does NOT do:** Execute code, install packages, run mypy or a type checker, or access the network. Pure structural analysis. |
| 794 | |
| 795 | **JSON output:** |
| 796 | ```json |
| 797 | { |
| 798 | "breakage_count": 2, |
| 799 | "issues": [ |
| 800 | { |
| 801 | "issue_type": "stale_import", |
| 802 | "file": "src/billing.py", |
| 803 | "description": "imports compute_total from src/utils.py but compute_total was removed" |
| 804 | } |
| 805 | ] |
| 806 | } |
| 807 | ``` |
| 808 | |
| 809 | --- |
| 810 | |
| 811 | ### `muse code invariants` |
| 812 | |
| 813 | Enforce architectural rules declared in `.muse/invariants.toml`. |
| 814 | |
| 815 | ``` |
| 816 | muse code invariants |
| 817 | muse code invariants --commit HEAD~5 |
| 818 | muse code invariants --json |
| 819 | ``` |
| 820 | |
| 821 | **Rule types:** |
| 822 | |
| 823 | #### `no_cycles` |
| 824 | ```toml |
| 825 | [[rules]] |
| 826 | type = "no_cycles" |
| 827 | name = "no import cycles" |
| 828 | ``` |
| 829 | The import graph must be a DAG. Reports every cycle as a violation. |
| 830 | |
| 831 | #### `forbidden_dependency` |
| 832 | ```toml |
| 833 | [[rules]] |
| 834 | type = "forbidden_dependency" |
| 835 | name = "core must not import cli" |
| 836 | source_pattern = "muse/core/" |
| 837 | forbidden_pattern = "muse/cli/" |
| 838 | ``` |
| 839 | Files matching `source_pattern` must not import from files matching `forbidden_pattern`. |
| 840 | |
| 841 | #### `layer_boundary` |
| 842 | ```toml |
| 843 | [[rules]] |
| 844 | type = "layer_boundary" |
| 845 | name = "plugins must not import from cli" |
| 846 | lower = "muse/plugins/" |
| 847 | upper = "muse/cli/" |
| 848 | ``` |
| 849 | Files in `lower` must not import from files in `upper` (enforces layered architecture). |
| 850 | |
| 851 | #### `required_test` |
| 852 | ```toml |
| 853 | [[rules]] |
| 854 | type = "required_test" |
| 855 | name = "all billing functions must have tests" |
| 856 | source_pattern = "src/billing.py" |
| 857 | test_pattern = "tests/test_billing.py" |
| 858 | ``` |
| 859 | Every public function in `source_pattern` must have a corresponding test function in `test_pattern` (matched by bare name). |
| 860 | |
| 861 | **Bootstrapping:** If `.muse/invariants.toml` does not exist, `muse code invariants` creates it with a commented template and exits with a guided onboarding message. |
| 862 | |
| 863 | --- |
| 864 | |
| 865 | <a id="9-semantic-versioning"></a> |
| 866 | ## 9. Semantic Versioning |
| 867 | |
| 868 | Muse automatically assigns semantic version bumps at commit time based on the `StructuredDelta`. |
| 869 | |
| 870 | ### `SemVerBump` |
| 871 | |
| 872 | ```python |
| 873 | SemVerBump = Literal["major", "minor", "patch", "none"] |
| 874 | ``` |
| 875 | |
| 876 | ### Inference rules (`infer_sem_ver_bump`) |
| 877 | |
| 878 | | Change type | Bump | Breaking? | |
| 879 | |---|---|---| |
| 880 | | Delete a public symbol | `major` | yes — address added to `breaking_changes` | |
| 881 | | Rename a public symbol | `major` | yes — old address added to `breaking_changes` | |
| 882 | | `signature_only` change | `major` | yes — callers may break | |
| 883 | | Insert a new public symbol | `minor` | no | |
| 884 | | `impl_only` change (body only) | `patch` | no | |
| 885 | | `metadata_only` change | `none` | no | |
| 886 | | Formatting-only change | `none` | no | |
| 887 | | Non-public symbol changes | `patch` or `none` | no | |
| 888 | |
| 889 | **Public** = name does not start with `_` and kind is `function`, `class`, `method`, or `async_function`. |
| 890 | |
| 891 | ### Storage |
| 892 | |
| 893 | Both `StructuredDelta` and `CommitRecord` carry: |
| 894 | - `sem_ver_bump: SemVerBump` (default `"none"`) |
| 895 | - `breaking_changes: list[str]` (default `[]`) |
| 896 | |
| 897 | These fields are backward-compatible — pre-v2 commits read as `"none"` / `[]`. |
| 898 | |
| 899 | ### `muse log` display |
| 900 | |
| 901 | When a commit's `sem_ver_bump` is non-`none`, long-form `muse log` output appends: |
| 902 | ``` |
| 903 | SemVer: MAJOR |
| 904 | Breaking: src/billing.py::compute_total, src/billing.py::Invoice (+2 more) |
| 905 | ``` |
| 906 | |
| 907 | --- |
| 908 | |
| 909 | <a id="10-call-graph-tier-commands"></a> |
| 910 | ## 10. Call-Graph Tier Commands |
| 911 | |
| 912 | ### `muse code impact ADDRESS [OPTIONS]` |
| 913 | |
| 914 | Transitive blast-radius analysis — what else breaks if this function changes? |
| 915 | |
| 916 | ``` |
| 917 | muse code impact src/billing.py::compute_total |
| 918 | muse code impact src/billing.py::compute_total --commit HEAD~5 |
| 919 | muse code impact src/billing.py::compute_total --json |
| 920 | ``` |
| 921 | |
| 922 | **Algorithm:** BFS over the reverse call graph (Python only via `ast`). Traverses until the transitive closure is exhausted, annotating each affected symbol with its depth. |
| 923 | |
| 924 | **Risk levels:** 🟢 (0–2 callers), 🟡 (3–9 callers), 🔴 (10+ callers). |
| 925 | |
| 926 | --- |
| 927 | |
| 928 | ### `muse code dead [OPTIONS]` |
| 929 | |
| 930 | Dead code detection — symbols with no callers and no importers. |
| 931 | |
| 932 | ``` |
| 933 | muse code dead |
| 934 | muse code dead --kind function |
| 935 | muse code dead --exclude-tests |
| 936 | muse code dead --json |
| 937 | ``` |
| 938 | |
| 939 | **Detection logic:** A symbol is a dead-code candidate when: |
| 940 | 1. Its bare name appears in no `ast.Call` node in the snapshot **and** |
| 941 | 2. Its module is not imported anywhere in the snapshot. |
| 942 | |
| 943 | **Distinction:** `definite_dead` (module never imported) vs `soft_dead` (module imported but function never called directly). |
| 944 | |
| 945 | --- |
| 946 | |
| 947 | ### `muse code coverage CLASS_ADDRESS [OPTIONS]` |
| 948 | |
| 949 | Class interface call-coverage — which methods of a class are actually called? |
| 950 | |
| 951 | ``` |
| 952 | muse code coverage src/billing.py::Invoice |
| 953 | muse code coverage src/billing.py::Invoice --show-callers |
| 954 | muse code coverage src/billing.py::Invoice --json |
| 955 | ``` |
| 956 | |
| 957 | **Output:** Lists every method of the class, marks which ones appear in `ast.Call` nodes anywhere in the snapshot, and prints a coverage percentage. No test suite required. |
| 958 | |
| 959 | --- |
| 960 | |
| 961 | ### `muse code deps ADDRESS_OR_FILE [OPTIONS]` |
| 962 | |
| 963 | Import graph + call-graph analysis. |
| 964 | |
| 965 | ``` |
| 966 | muse code deps src/billing.py |
| 967 | muse code deps src/billing.py --reverse |
| 968 | muse code deps src/billing.py::compute_total |
| 969 | muse code deps src/billing.py::compute_total --reverse |
| 970 | muse code deps src/billing.py --commit v1.0 --json |
| 971 | ``` |
| 972 | |
| 973 | **File mode:** Lists all `import`-kind symbols from the file (what does it import?). With `--reverse`: which other files import this one. |
| 974 | |
| 975 | **Symbol mode** (`address` contains `::`): Python-only call extraction — which functions does this function call? With `--reverse`: which functions call this one. |
| 976 | |
| 977 | --- |
| 978 | |
| 979 | ### `muse code find-symbol [OPTIONS]` |
| 980 | |
| 981 | Cross-commit, cross-branch symbol search by hash, name, or kind. |
| 982 | |
| 983 | ``` |
| 984 | muse code find-symbol --hash a3f2c9 |
| 985 | muse code find-symbol --name compute_total |
| 986 | muse code find-symbol --name compute_* --kind function |
| 987 | muse code find-symbol --hash a3f2c9 --all-branches --first |
| 988 | muse code find-symbol --name validate --json |
| 989 | ``` |
| 990 | |
| 991 | **Flags:** |
| 992 | - `--hash HEX` — match `content_id` prefix (exact body match across history) |
| 993 | - `--name NAME` — exact name or prefix glob with `*` |
| 994 | - `--kind KIND` — restrict to symbol kind |
| 995 | - `--all-branches` — also scan all branch tips in `.muse/refs/heads/` |
| 996 | - `--first` — deduplicate on `content_id`, keeping only the first appearance |
| 997 | - `--json` — structured output |
| 998 | |
| 999 | --- |
| 1000 | |
| 1001 | ### `muse code patch ADDRESS SOURCE [OPTIONS]` |
| 1002 | |
| 1003 | Surgical semantic patch — replace exactly one named symbol in the working tree. |
| 1004 | |
| 1005 | ``` |
| 1006 | muse code patch src/billing.py::compute_total new_impl.py |
| 1007 | echo "def compute_total(x): return x * 2" | muse code patch src/billing.py::compute_total - |
| 1008 | muse code patch src/billing.py::compute_total new_impl.py --dry-run |
| 1009 | muse code patch src/billing.py::compute_total new_impl.py --json |
| 1010 | ``` |
| 1011 | |
| 1012 | **Syntax validation:** Before writing, validates the replacement source with: |
| 1013 | - `ast.parse` for Python |
| 1014 | - `tree-sitter` CST error-node check for all 11 supported languages |
| 1015 | |
| 1016 | Rejects the patch and exits non-zero if the source has syntax errors. |
| 1017 | |
| 1018 | **Flags:** |
| 1019 | - `--body, -b FILE` *(required)* — file containing the replacement source (`-` for stdin) |
| 1020 | - `--dry-run, -n` — print what would change without writing |
| 1021 | - `--json` — emit result as JSON for agent consumption |
| 1022 | |
| 1023 | **JSON output:** |
| 1024 | |
| 1025 | ```json |
| 1026 | { |
| 1027 | "address": "src/billing.py::compute_total", |
| 1028 | "file": "src/billing.py", |
| 1029 | "lines_replaced": 12, |
| 1030 | "new_lines": 9, |
| 1031 | "dry_run": false |
| 1032 | } |
| 1033 | ``` |
| 1034 | |
| 1035 | **Security:** The file path component of ADDRESS is validated via `contain_path()` before any disk access. Paths that escape the repo root (e.g. `../../etc/passwd::foo`) are rejected with exit 1. |
| 1036 | |
| 1037 | --- |
| 1038 | |
| 1039 | ### `muse grep PATTERN [OPTIONS]` |
| 1040 | |
| 1041 | Search the typed symbol graph by name — not file text. Every result is a real symbol declaration; no false positives from comments, string literals, or call sites. |
| 1042 | |
| 1043 | ``` |
| 1044 | muse grep validate |
| 1045 | muse grep "^handle" --regex |
| 1046 | muse grep Invoice --kind class |
| 1047 | muse grep compute --language Go |
| 1048 | muse grep total --commit HEAD~5 |
| 1049 | muse grep validate --json |
| 1050 | ``` |
| 1051 | |
| 1052 | **Flags:** |
| 1053 | |
| 1054 | | Flag | Short | Description | |
| 1055 | |---|---|---| |
| 1056 | | `--regex, -e` | | Treat PATTERN as a Python regex (default: substring match) | |
| 1057 | | `--kind KIND, -k` | | Restrict to symbols of this kind (function, class, method, …) | |
| 1058 | | `--language LANG, -l` | | Restrict to files of this language (Python, Go, …) | |
| 1059 | | `--commit REF, -c` | | Search a historical commit instead of HEAD | |
| 1060 | | `--hashes` | | Include 8-char content-ID prefix in output | |
| 1061 | | `--json` | | Emit results as JSON | |
| 1062 | |
| 1063 | **JSON output:** |
| 1064 | |
| 1065 | ```json |
| 1066 | [ |
| 1067 | { |
| 1068 | "address": "src/auth.py::validate_token", |
| 1069 | "kind": "function", |
| 1070 | "name": "validate_token", |
| 1071 | "qualified_name": "validate_token", |
| 1072 | "file": "src/auth.py", |
| 1073 | "lineno": 14, |
| 1074 | "language": "Python", |
| 1075 | "content_id": "cb4afa1234567890..." |
| 1076 | } |
| 1077 | ] |
| 1078 | ``` |
| 1079 | |
| 1080 | **Security:** Patterns are capped at 512 characters to prevent ReDoS. Invalid regex syntax is caught and reported as exit 1 rather than crashing. |
| 1081 | |
| 1082 | --- |
| 1083 | |
| 1084 | ### `muse code-check [COMMIT] [OPTIONS]` |
| 1085 | |
| 1086 | Enforce semantic code invariants against a commit snapshot. |
| 1087 | |
| 1088 | ``` |
| 1089 | muse code-check # check HEAD |
| 1090 | muse code-check abc1234 # check specific commit |
| 1091 | muse code-check --strict # exit 1 on any error-severity violation |
| 1092 | muse code-check --json # machine-readable JSON output |
| 1093 | muse code-check --rules my_rules.toml # custom rules file inside the repo |
| 1094 | ``` |
| 1095 | |
| 1096 | **Flags:** |
| 1097 | |
| 1098 | | Flag | Description | |
| 1099 | |---|---| |
| 1100 | | `COMMIT` | Commit ID to check (default: HEAD) | |
| 1101 | | `--strict` | Exit 1 when any error-severity violation is found | |
| 1102 | | `--json` | Emit machine-readable JSON | |
| 1103 | | `--rules FILE` | Path to a TOML invariants file **inside the repo** (default: `.muse/code_invariants.toml`) | |
| 1104 | |
| 1105 | **Security:** `--rules FILE` is validated via `contain_path()` — paths that escape the repo root are rejected with exit 1. |
| 1106 | |
| 1107 | --- |
| 1108 | |
| 1109 | <a id="11-architecture-internals"></a> |
| 1110 | ## 11. Architecture Internals |
| 1111 | |
| 1112 | ### Module Map |
| 1113 | |
| 1114 | ``` |
| 1115 | muse/ |
| 1116 | plugins/code/ |
| 1117 | plugin.py MidiPlugin → CodePlugin (MuseDomainPlugin + StructuredMergePlugin) |
| 1118 | ast_parser.py Python AST → SymbolRecord; validate_syntax() for all 11 languages |
| 1119 | symbol_diff.py diff_symbol_trees() — O(n) diffing, rename/move annotation |
| 1120 | _query.py symbols_for_snapshot(), walk_commits(), language_of() |
| 1121 | _predicate.py Predicate DSL parser — tokenise → recursive descent → Predicate callable |
| 1122 | _callgraph.py ForwardGraph, ReverseGraph, build_*, transitive_callers BFS |
| 1123 | _refactor_classify.py classify_exact(), classify_composite(), RefactorClassification |
| 1124 | core/ |
| 1125 | coordination.py Reservation, Intent, create/load helpers, .muse/coordination/ |
| 1126 | indices.py SymbolHistoryIndex, HashOccurrenceIndex, save/load/rebuild |
| 1127 | ``` |
| 1128 | |
| 1129 | ### Language Support |
| 1130 | |
| 1131 | | Language | Extension(s) | Parser | Symbol types | |
| 1132 | |---|---|---|---| |
| 1133 | | Python | `.py` | `ast` (stdlib) | function, async_function, class, method, variable, import | |
| 1134 | | JavaScript | `.js` `.jsx` `.mjs` `.cjs` | tree-sitter | function, class, method | |
| 1135 | | TypeScript | `.ts` `.tsx` | tree-sitter | function, class, method, interface, type_alias, enum | |
| 1136 | | Go | `.go` | tree-sitter | function (method qualified as `Type.Method`) | |
| 1137 | | Rust | `.rs` | tree-sitter | function (impl method qualified as `Type.method`) | |
| 1138 | | Java | `.java` | tree-sitter | class, interface, method, constructor, enum | |
| 1139 | | C | `.c` `.h` | tree-sitter | function_definition | |
| 1140 | | C++ | `.cpp` `.cc` `.cxx` `.hpp` | tree-sitter | function, class, struct | |
| 1141 | | C# | `.cs` | tree-sitter | class, interface, struct, method, constructor, enum | |
| 1142 | | Ruby | `.rb` | tree-sitter | class, module, method, singleton_method | |
| 1143 | | Kotlin | `.kt` `.kts` | tree-sitter | function, class, method | |
| 1144 | | Markdown / RST | `.md` `.rst` `.txt` | tree-sitter-markdown | section (ATX headings) | |
| 1145 | | HTML | `.html` `.htm` | tree-sitter-html | section (semantic elements, id-bearing elements) | |
| 1146 | | CSS / SCSS | `.css` `.scss` | tree-sitter-css | rule (rule-sets, @keyframes, @media) | |
| 1147 | | TOML | `.toml` | `tomllib` (stdlib, zero deps) | section (`[table]`, `[[array]]`), variable (scalar key-value) | |
| 1148 | |
| 1149 | ### Layer Rules |
| 1150 | |
| 1151 | - `muse/core/*` is domain-agnostic — never imports from `muse/plugins/*` |
| 1152 | - `muse/cli/commands/*` are thin — delegate all logic to `muse/core/*` or plugin helpers |
| 1153 | - `muse/plugins/code/*` is the only layer that imports domain-specific AST logic |
| 1154 | - `muse/core/coordination.py` and `muse/core/indices.py` are domain-agnostic helpers |
| 1155 | |
| 1156 | --- |
| 1157 | |
| 1158 | <a id="12-type-reference"></a> |
| 1159 | ## 12. Type Reference |
| 1160 | |
| 1161 | ### `SymbolRecord` (TypedDict) |
| 1162 | |
| 1163 | ```python |
| 1164 | class SymbolRecord(TypedDict): |
| 1165 | kind: str # function | class | method | variable | import | … |
| 1166 | name: str # bare name |
| 1167 | qualified_name: str # dotted path (e.g. MyClass.save) |
| 1168 | lineno: int |
| 1169 | end_lineno: int |
| 1170 | content_id: str # SHA-256 of full normalized AST |
| 1171 | body_hash: str # SHA-256 of body only |
| 1172 | signature_id: str # SHA-256 of signature only |
| 1173 | metadata_id: str # SHA-256 of decorators + async + bases (v2, "" for pre-v2) |
| 1174 | canonical_key: str # {file}#{scope}#{kind}#{name}#{lineno} (v2, "" for pre-v2) |
| 1175 | ``` |
| 1176 | |
| 1177 | ### `StructuredDelta` |
| 1178 | |
| 1179 | ```python |
| 1180 | class StructuredDelta(TypedDict): |
| 1181 | domain: str |
| 1182 | ops: list[DomainOp] |
| 1183 | summary: str |
| 1184 | sem_ver_bump: SemVerBump # default "none" |
| 1185 | breaking_changes: list[str] # default [] |
| 1186 | ``` |
| 1187 | |
| 1188 | ### `DomainOp` union |
| 1189 | |
| 1190 | ```python |
| 1191 | DomainOp = InsertOp | DeleteOp | ReplaceOp | MoveOp | PatchOp |
| 1192 | ``` |
| 1193 | |
| 1194 | Each op is a `TypedDict` discriminated by a `Literal` `"op"` field. |
| 1195 | |
| 1196 | ### `ConflictRecord` (dataclass) |
| 1197 | |
| 1198 | ```python |
| 1199 | @dataclass |
| 1200 | class ConflictRecord: |
| 1201 | path: str |
| 1202 | conflict_type: str = "file_level" |
| 1203 | ours_summary: str = "" |
| 1204 | theirs_summary: str = "" |
| 1205 | addresses: list[str] = field(default_factory=list) |
| 1206 | ``` |
| 1207 | |
| 1208 | ### `Reservation` |
| 1209 | |
| 1210 | ```python |
| 1211 | class Reservation: |
| 1212 | reservation_id: str |
| 1213 | run_id: str |
| 1214 | branch: str |
| 1215 | addresses: list[str] |
| 1216 | created_at: datetime |
| 1217 | expires_at: datetime |
| 1218 | operation: str | None |
| 1219 | def is_active(self) -> bool: ... |
| 1220 | def to_dict(self) -> dict[str, str | int | list[str] | None]: ... |
| 1221 | @classmethod |
| 1222 | def from_dict(cls, d) -> Reservation: ... |
| 1223 | ``` |
| 1224 | |
| 1225 | ### `Intent` |
| 1226 | |
| 1227 | ```python |
| 1228 | class Intent: |
| 1229 | intent_id: str |
| 1230 | reservation_id: str |
| 1231 | run_id: str |
| 1232 | branch: str |
| 1233 | addresses: list[str] |
| 1234 | operation: str |
| 1235 | created_at: datetime |
| 1236 | detail: str |
| 1237 | def to_dict(self) -> dict[str, str | int | list[str]]: ... |
| 1238 | @classmethod |
| 1239 | def from_dict(cls, d) -> Intent: ... |
| 1240 | ``` |
| 1241 | |
| 1242 | ### `SemVerBump` |
| 1243 | |
| 1244 | ```python |
| 1245 | SemVerBump = Literal["major", "minor", "patch", "none"] |
| 1246 | ``` |
| 1247 | |
| 1248 | ### `Predicate` |
| 1249 | |
| 1250 | ```python |
| 1251 | Predicate = Callable[[str, SymbolRecord], bool] |
| 1252 | # first arg: file_path |
| 1253 | # second arg: SymbolRecord |
| 1254 | # returns: True if the symbol matches the predicate |
| 1255 | ``` |
| 1256 | |
| 1257 | ### `ExactClassification` |
| 1258 | |
| 1259 | ```python |
| 1260 | ExactClassification = Literal[ |
| 1261 | "rename", "move", "rename+move", |
| 1262 | "signature_only", "impl_only", "metadata_only", |
| 1263 | "full_rewrite", "unchanged", |
| 1264 | ] |
| 1265 | ``` |
| 1266 | |
| 1267 | ### `InferredRefactor` |
| 1268 | |
| 1269 | ```python |
| 1270 | InferredRefactor = Literal["extract", "inline", "split", "merge", "none"] |
| 1271 | ``` |
| 1272 | |
| 1273 | --- |
| 1274 | |
| 1275 | ## Further Reading |
| 1276 | |
| 1277 | - [Plugin Authoring Guide](plugin-authoring-guide.md) — implementing `MuseDomainPlugin` |
| 1278 | - [Type Contracts](type-contracts.md) — strict typing rules and enforcement |
| 1279 | - [CRDT Reference](crdt-reference.md) — CRDT and OT merge primitives |
| 1280 | - [Demo — Code](../demo/demo-code.md) — full narrative walkthrough of all code commands |
| 1281 | - [Demo — MIDI](../demo/midi-demo.md) — MIDI domain demo walkthrough |