Muse VCS — Type Contracts Reference
Updated: 2026-04-06 | Reflects every named entity in the Muse VCS surface.
Anyandobjectdo not exist in any production file. Every type boundary is named. The typing audit ratchet enforces zero violations on every CI run.
This document is the single source of truth for every named entity —
TypedDict, dataclass, Protocol, Enum, TypeAlias — in the Muse
codebase. It covers the full contract of each type: fields, types,
optionality, and intended use.
Table of Contents
- Design Philosophy
- Domain Protocol Types (
muse/domain.py) - Domain Schema Types (
muse/core/schema.py) - Diff Algorithm Types (
muse/core/diff_algorithms/) - OT Merge Types (
muse/core/op_transform.py) - Op Log Types (
muse/core/op_log.py) - CRDT Primitive Types (
muse/core/crdts/) - Store Types (
muse/core/store.py) - Merge Engine Types (
muse/core/merge_engine.py) - Attributes Types (
muse/core/attributes.py) - MIDI Dimension Merge Types (
muse/plugins/midi/midi_merge.py) - Code Plugin Types (
muse/plugins/code/) - Configuration Types (
muse/cli/config.py) - MIDI / MusicXML Import Types (
muse/cli/midi_parser.py) - Stash Types (
muse/cli/commands/stash.py) - Error Hierarchy (
muse/core/errors.py) - Entity Hierarchy
- Entity Graphs (Mermaid)
Design Philosophy
Every entity in this codebase follows five rules:
No
Any. Noobject. Ever. Both collapse type safety for downstream callers. Every boundary is typed with a concrete named entity —TypedDict,dataclass,Protocol, or a specific union. The CI typing audit enforces this with a ratchet of zero violations.No covariance in collection aliases.
dict[str, str]andlist[str]are used directly. If a function's return mixes value types, create aTypedDictfor that shape instead of usingdict[str, str | int].Boundaries own coercion. When external data arrives (JSON from disk, TOML from config, MIDI bytes from disk), the boundary module coerces it to the canonical internal type using
isinstancenarrowing. Downstream code always sees clean types.Wire-format TypedDicts for serialisation, dataclasses for in-memory logic.
CommitDict,SnapshotDict,TagDictare JSON-serialisable and used byto_dict()/from_dict().CommitRecord,SnapshotRecord,TagRecordare rich dataclasses with typeddatetimefields used in business logic.The plugin protocol is the extension point. All domain-specific logic lives behind
MuseDomainPlugin. The core DAG engine, branching, and merge machinery know nothing about music, genomics, or any other domain. Swapping domains is a one-file operation.
Banned → replacement table
| Banned | Use instead |
|---|---|
Any |
TypedDict, dataclass, specific union |
object |
The actual type or a constrained union |
list (bare) |
list[X] with concrete element type |
dict (bare) |
dict[K, V] with concrete key/value types |
dict[str, X] with known keys |
TypedDict — name the keys |
Optional[X] |
X \| None |
Legacy List, Dict, Set, Tuple |
Lowercase builtins |
cast(T, x) |
Fix the callee to return T |
# type: ignore |
Fix the underlying type error |
Domain Protocol Types
Path: muse/domain.py
The six-interface contract that every domain plugin must satisfy. The core
engine implements the DAG, branching, merge-base finding, and lineage walking.
A domain plugin provides the six methods and gets the full VCS for free.
Two optional protocol extensions (StructuredMergePlugin, CRDTPlugin) unlock
richer merge semantics.
Type Aliases
| Alias | Definition | Description |
|---|---|---|
DomainAddress |
str |
Stable human-readable address of an element within the domain namespace (e.g. "note:4:60" in MIDI, "src/mod.py#Foo.bar" in code) |
SemVerBump |
Literal["major", "minor", "patch", "none"] |
Semantic version impact of a delta |
LeafDomainOp |
InsertOp \| DeleteOp \| MoveOp \| ReplaceOp \| MutateOp |
All non-recursive operation variants |
DomainOp |
LeafDomainOp \| PatchOp |
The complete discriminated union; PatchOp.child_ops is list[DomainOp] (recursive) |
LiveState |
SnapshotManifest \| pathlib.Path |
Current domain state — either an in-memory snapshot or the state/ directory path |
StateSnapshot |
SnapshotManifest |
A content-addressed, immutable capture of state at a point in time |
StateDelta |
StructuredDelta |
The typed delta between two snapshots |
Operation TypedDicts
Every DomainOp variant is a TypedDict with an op discriminator and an
address identifying the element within the domain's namespace.
InsertOp
TypedDict — Add a new element.
| Field | Type | Description |
|---|---|---|
op |
Literal["insert"] |
Discriminator |
address |
DomainAddress |
Stable address of the new element |
position |
int \| None |
Insertion position; None for unordered collections |
content_id |
str |
SHA-256 of the inserted element's serialised content |
content_summary |
str |
Human-readable one-liner for display |
DeleteOp
TypedDict — Remove an existing element.
| Field | Type | Description |
|---|---|---|
op |
Literal["delete"] |
Discriminator |
address |
DomainAddress |
Address of the element being removed |
position |
int \| None |
Position at time of deletion; None for unordered collections |
content_id |
str |
SHA-256 of the removed element (for reverse-application) |
content_summary |
str |
Human-readable one-liner for display |
MoveOp
TypedDict — Reposition an element within a sequence.
| Field | Type | Description |
|---|---|---|
op |
Literal["move"] |
Discriminator |
address |
DomainAddress |
Address of the element being moved |
from_position |
int |
Original position |
to_position |
int |
Target position |
content_id |
str |
SHA-256 of the element content (unchanged by the move) |
ReplaceOp
TypedDict — Atomic swap of one content version for another.
| Field | Type | Description |
|---|---|---|
op |
Literal["replace"] |
Discriminator |
address |
DomainAddress |
Address of the replaced element |
position |
int \| None |
Position within its container; None for unordered |
old_content_id |
str |
SHA-256 of the previous content |
new_content_id |
str |
SHA-256 of the new content |
old_summary |
str |
Human-readable description of the before state |
new_summary |
str |
Human-readable description of the after state |
FieldMutation
TypedDict — A single field change within a MutateOp. Used as the value
type of MutateOp.fields.
| Field | Type | Description |
|---|---|---|
old |
str |
Serialised previous field value |
new |
str |
Serialised new field value |
MutateOp
TypedDict — Partial field-level update of a structured entity. More precise
than ReplaceOp when only certain fields change (e.g. velocity on a note,
author on a code symbol).
| Field | Type | Description |
|---|---|---|
op |
Literal["mutate"] |
Discriminator |
address |
DomainAddress |
Address of the mutated entity |
entity_id |
str |
Stable domain-assigned entity identifier |
old_content_id |
str |
SHA-256 of the entity before mutation |
new_content_id |
str |
SHA-256 of the entity after mutation |
fields |
dict[str, FieldMutation] |
Field name → before/after values for each changed field |
old_summary |
str |
Human-readable before state |
new_summary |
str |
Human-readable after state |
position |
int \| None |
Position within its container; None for unordered |
PatchOp
TypedDict — Container op for hierarchical or multi-file changes. Carries a
list of child DomainOps belonging to a sub-domain or nested structure.
child_ops is list[DomainOp] — the type is recursive.
| Field | Type | Description |
|---|---|---|
op |
Literal["patch"] |
Discriminator |
address |
DomainAddress |
Address of the patched container element |
child_ops |
list[DomainOp] |
Nested operations in the child domain |
child_domain |
str |
Identifier of the sub-domain (e.g. "midi_track") |
child_summary |
str |
Human-readable summary of the child ops |
Snapshot and Delta TypedDicts
SnapshotManifest
TypedDict — Content-addressed snapshot of domain state. JSON-serialisable
and content-addressable via SHA-256. Aliased as StateSnapshot.
| Field | Type | Description |
|---|---|---|
files |
dict[str, str] |
Workspace-relative POSIX paths → SHA-256 content digests |
domain |
str |
Plugin identifier that produced this snapshot (e.g. "midi") |
StructuredDelta
TypedDict (total=False) — The typed delta produced by MuseDomainPlugin.diff().
Aliased as StateDelta. All fields are optional to support format-version
evolution: older records have fewer fields.
| Field | Type | Description |
|---|---|---|
domain |
str |
Plugin identifier that produced this delta |
ops |
list[DomainOp] |
Ordered list of typed domain operations |
summary |
str |
Human-readable summary (e.g. "3 inserts, 1 delete") |
sem_ver_bump |
SemVerBump |
Semantic version impact ("major", "minor", "patch", "none") |
breaking_changes |
list[str] |
Addresses of public symbols that were removed or incompatibly changed |
CRDTSnapshotManifest
TypedDict — Extended snapshot format for CRDT-mode plugins. Wraps the plain
snapshot manifest with a vector clock and serialised CRDT state per dimension.
| Field | Type | Description |
|---|---|---|
schema_version |
Literal[1] |
Always 1 |
domain |
str |
Plugin domain name |
files |
dict[str, str] |
POSIX path → SHA-256 object digest (same as SnapshotManifest) |
vclock |
dict[str, int] |
Vector clock: agent ID → logical clock value |
crdt_state |
dict[str, str] |
Dimension name → hash of serialised CRDT primitive state in object store |
EntityProvenance
TypedDict (total=False) — Optional causal provenance attached to a domain entity.
All fields are optional; older records have none.
| Field | Type | Description |
|---|---|---|
entity_id |
str |
Stable domain-assigned identifier for this entity |
origin_op_id |
str |
OpEntry.op_id of the op that created this entity |
last_modified_op_id |
str |
OpEntry.op_id of the most recent mutation |
created_at_commit |
str |
Commit ID of the commit that first introduced this entity |
actor_id |
str |
Agent or human identity of the creator |
Result Dataclasses
ConflictRecord
@dataclass — Structured description of a single merge conflict. More
informative than a bare path string; carries the conflict type and per-branch
summaries.
| Field | Type | Default | Description |
|---|---|---|---|
path |
str |
required | Workspace-relative path of the conflicting file |
conflict_type |
str |
"file_level" |
One of: "file_level", "symbol_edit_overlap", "rename_edit", … |
ours_summary |
str |
"" |
Human-readable description of the change on our branch |
theirs_summary |
str |
"" |
Human-readable description of the change on their branch |
addresses |
list[str] |
[] |
DomainAddress values of all conflicting elements |
Methods: to_dict() -> dict[str, str | list[str]]
MergeResult
@dataclass — Outcome of a three-way merge between two divergent state lines.
An empty conflicts list means the merge was clean.
| Field | Type | Default | Description |
|---|---|---|---|
merged |
StateSnapshot |
required | The reconciled snapshot |
conflicts |
list[str] |
[] |
Workspace-relative paths that could not be auto-merged |
applied_strategies |
dict[str, str] |
{} |
Path → strategy applied by .museattributes (e.g. {"drums/kick.mid": "ours"}) |
dimension_reports |
dict[str, dict[str, str]] |
{} |
Path → per-dimension winner map; only populated for MIDI files that went through dimension-level merge |
op_log |
list[DomainOp] |
[] |
Ordered list of ops that were auto-merged from both branches |
conflict_records |
list[ConflictRecord] |
[] |
Structured conflict descriptions; parallel to conflicts paths |
Property:
| Name | Returns | Description |
|---|---|---|
is_clean |
bool |
True when conflicts is empty |
DriftReport
@dataclass — Gap between committed state and current live state. Produced by
MuseDomainPlugin.drift() and consumed by muse status.
| Field | Type | Default | Description |
|---|---|---|---|
has_drift |
bool |
required | True when live state differs from committed snapshot |
summary |
str |
"" |
Human-readable description (e.g. "2 added, 1 modified") |
delta |
StateDelta |
empty StructuredDelta |
Machine-readable diff for programmatic consumers |
MuseDomainPlugin Protocol
@runtime_checkable Protocol — The six interfaces a domain plugin must
implement. Runtime-checkable so that assert isinstance(plugin, MuseDomainPlugin)
works as a module-load sanity check.
| Method | Signature | Description |
|---|---|---|
snapshot |
(live_state: LiveState) -> StateSnapshot |
Capture current state as a content-addressed dict; must honour .museignore (TOML — call load_ignore_config + resolve_patterns(config, domain) from muse.core.ignore) |
diff |
(base: StateSnapshot, target: StateSnapshot, *, repo_root: pathlib.Path \| None = None) -> StateDelta |
Compute the typed delta between two snapshots |
merge |
(base, left, right: StateSnapshot, *, repo_root: pathlib.Path \| None = None) -> MergeResult |
Three-way merge; when repo_root is provided, load .museattributes and perform dimension-level merge for supported formats |
drift |
(committed: StateSnapshot, live: LiveState) -> DriftReport |
Compare committed state vs current live state |
apply |
(delta: StateDelta, live_state: LiveState) -> LiveState |
Apply a delta to produce a new live state |
schema |
() -> DomainSchema |
Declare the structural shape of the domain's data (drives diff algorithm selection) |
The MIDI plugin (muse.plugins.midi.plugin) is the reference implementation.
Every other domain implements these six methods and registers itself as a plugin.
Optional Protocol Extensions
StructuredMergePlugin
@runtime_checkable Protocol — Extends MuseDomainPlugin with operation-level
OT merge. When both branches produce StructuredDeltas, the merge engine detects
isinstance(plugin, StructuredMergePlugin) and calls merge_ops() instead of
merge().
| Method | Signature | Description |
|---|---|---|
merge_ops |
(base, ours_snap, theirs_snap, ours_ops, theirs_ops, *, repo_root) -> MergeResult |
Operation-level three-way merge using OT commutativity rules |
CRDTPlugin
@runtime_checkable Protocol — Extends MuseDomainPlugin with convergent merge.
join always succeeds — no conflict state ever exists.
| Method | Signature | Description |
|---|---|---|
crdt_schema |
() -> list[CRDTDimensionSpec] |
Per-dimension CRDT primitive specification |
join |
(a: CRDTSnapshotManifest, b: CRDTSnapshotManifest) -> CRDTSnapshotManifest |
Convergent join satisfying commutativity, associativity, idempotency |
to_crdt_state |
(snapshot: StateSnapshot) -> CRDTSnapshotManifest |
Convert a snapshot into CRDT state |
from_crdt_state |
(crdt: CRDTSnapshotManifest) -> StateSnapshot |
Convert CRDT state back to a plain snapshot |
Domain Schema Types
Path: muse/core/schema.py
The DomainSchema family of TypedDicts allows a plugin to declare its data
structure. The core engine uses this to select diff algorithms per-dimension
and to drive informed conflict reporting during OT merge.
Element Schema TypedDicts
SequenceSchema
TypedDict — Ordered sequence of homogeneous elements (LCS-diffable).
| Field | Type | Description |
|---|---|---|
kind |
Literal["sequence"] |
Discriminator |
element_type |
str |
Domain name for elements (e.g. "note", "nucleotide") |
identity |
Literal["by_id", "by_position", "by_content"] |
How two elements are considered the same |
diff_algorithm |
Literal["lcs", "myers", "patience"] |
LCS variant to use |
alphabet |
list[str] \| None |
Optional closed set of valid values for validation |
TreeSchema
TypedDict — Hierarchical labeled ordered tree (tree-edit-diffable).
| Field | Type | Description |
|---|---|---|
kind |
Literal["tree"] |
Discriminator |
node_type |
str |
Domain name for tree nodes (e.g. "ast_node", "scene_node") |
diff_algorithm |
Literal["zhang_shasha", "gumtree"] |
Tree edit algorithm |
TensorSchema
TypedDict — N-dimensional numerical array (numerical-diffable).
| Field | Type | Description |
|---|---|---|
kind |
Literal["tensor"] |
Discriminator |
dtype |
Literal["float32", "float64", "int8", "int16", "int32", "int64"] |
Element data type |
rank |
int |
Number of dimensions |
epsilon |
float |
Floating-point drift below this threshold is not a change |
diff_mode |
Literal["sparse", "block", "full"] |
Output granularity: element-level, range-grouped, or whole-array |
SetSchema
TypedDict — Unordered collection of elements (set-algebra-diffable).
| Field | Type | Description |
|---|---|---|
kind |
Literal["set"] |
Discriminator |
element_type |
str |
Domain name for elements |
identity |
Literal["by_content", "by_id"] |
How two elements are considered the same |
MapSchema
TypedDict — Key-value map whose values follow a sub-schema.
| Field | Type | Description |
|---|---|---|
kind |
Literal["map"] |
Discriminator |
key_type |
str |
Domain name for keys |
value_schema |
ElementSchema |
Schema applied to each value (forward reference — resolved lazily) |
identity |
Literal["by_key"] |
Elements are always identified by key |
ElementSchema (Type Alias)
TypeAlias = SequenceSchema | TreeSchema | TensorSchema | MapSchema | SetSchema
The discriminated union of all element-level schema variants. The kind field
is the discriminator.
Dimension Schema TypedDicts
DimensionSpec
TypedDict — Schema for one orthogonal dimension within a domain.
| Field | Type | Description |
|---|---|---|
name |
str |
Dimension name (e.g. "notes", "pitch_bend") |
description |
str |
Human-readable description |
schema |
ElementSchema |
Element schema governing diff algorithm selection for this dimension |
independent_merge |
bool |
When True, this dimension can be auto-merged even when another dimension conflicts |
CRDTPrimitive (Type Alias)
TypeAlias = Literal["lww_register", "or_set", "rga", "aw_map", "g_counter"]
The set of valid CRDT primitive names for use in CRDTDimensionSpec.crdt_type.
CRDTDimensionSpec
TypedDict — Schema for a dimension using CRDT convergent-merge semantics.
| Field | Type | Description |
|---|---|---|
name |
str |
Dimension name |
description |
str |
Human-readable description |
crdt_type |
CRDTPrimitive |
CRDT primitive governing this dimension |
independent_merge |
bool |
Whether this dimension merges independently |
Top-Level Schema
DomainSchema
TypedDict — Top-level schema declaration returned by MuseDomainPlugin.schema().
| Field | Type | Description |
|---|---|---|
domain |
str |
Plugin domain name |
description |
str |
Human-readable domain description |
dimensions |
list[DimensionSpec] |
Orthogonal dimension declarations |
top_level |
ElementSchema |
Schema for the domain's root container |
merge_mode |
Literal["three_way", "crdt"] |
"three_way" uses OT merge; "crdt" uses convergent join |
schema_version |
Literal[1] |
Always 1 |
Diff Algorithm Types
Path: muse/core/diff_algorithms/
Input TypedDicts
Each ElementSchema variant has a paired input TypedDict consumed by
diff_by_schema(). The kind discriminator matches.
SequenceInput
| Field | Type | Description |
|---|---|---|
kind |
Literal["sequence"] |
Discriminator |
items |
list[str] |
Ordered content IDs (SHA-256 digests) |
SetInput
| Field | Type | Description |
|---|---|---|
kind |
Literal["set"] |
Discriminator |
items |
frozenset[str] |
Set of content IDs |
TensorInput
| Field | Type | Description |
|---|---|---|
kind |
Literal["tensor"] |
Discriminator |
values |
list[float] |
Flat array of numerical values |
MapInput
| Field | Type | Description |
|---|---|---|
kind |
Literal["map"] |
Discriminator |
entries |
dict[str, str] |
Key → content ID |
TreeInput
| Field | Type | Description |
|---|---|---|
kind |
Literal["tree"] |
Discriminator |
root |
TreeNode |
Root of the labeled ordered tree |
DiffInput (Type Alias)
TypeAlias = SequenceInput | SetInput | TensorInput | MapInput | TreeInput
LCS Types (muse/core/diff_algorithms/lcs.py)
EditKind (Type Alias)
TypeAlias = Literal["keep", "insert", "delete"]
EditStep
@dataclass (frozen=True) — One step in the edit script produced by
myers_ses(). Applying all steps in order to base reproduces target.
| Field | Type | Description |
|---|---|---|
kind |
EditKind |
"keep" (copy from base), "insert" (add from target), "delete" (skip from base) |
base_index |
int |
Index in the base content-ID list; -1 for pure inserts |
target_index |
int |
Index in the target content-ID list; -1 for pure deletes |
item |
str |
Content ID of the element |
Tree Types (muse/core/diff_algorithms/tree_edit.py)
TreeNode
@dataclass (frozen=True) — A node in a labeled ordered tree. Two nodes are
considered equal when their content_id values match. Used as TreeInput.root.
| Field | Type | Description |
|---|---|---|
id |
str |
Stable unique identifier for this node (persists across edits) |
label |
str |
Human-readable name (element tag, AST node type) |
content_id |
str |
SHA-256 of this node's own value, excluding children |
children |
tuple[TreeNode, ...] |
Ordered recursive children tuple |
OT Merge Types
Path: muse/core/op_transform.py
Operational Transformation types for the StructuredMergePlugin extension.
MergeOpsResult
@dataclass — Result of merge_op_lists(). Carries auto-merged ops and any
unresolvable conflicts as pairs.
| Field | Type | Default | Description |
|---|---|---|---|
merged_ops |
list[DomainOp] |
[] |
Operations that were auto-merged (commuting ops from both branches) |
conflict_ops |
list[tuple[DomainOp, DomainOp]] |
[] |
Pairs of non-commuting operations: (our_op, their_op) |
Property: is_clean: bool — True when conflict_ops is empty.
Lattice contract: merged_ops contains every auto-merged op exactly once;
conflict_ops contains every unresolvable pair exactly once.
Op Log Types
Path: muse/core/op_log.py
The op log records every domain operation in causal order, enabling CRDT-style replay and session-level undo.
OpEntry
TypedDict — One entry in the op log. Persisted as JSONL under
.muse/op_log/<session_id>.jsonl.
| Field | Type | Description |
|---|---|---|
op_id |
str |
UUID4; deduplication key |
actor_id |
str |
Agent or human identity that produced this op |
lamport_ts |
int |
Logical Lamport timestamp; monotonically increasing per session |
parent_op_ids |
list[str] |
Causal parents — op IDs this op depends on |
domain |
str |
Domain identifier (e.g. "midi", "code") |
domain_op |
DomainOp |
The typed domain operation |
created_at |
str |
ISO-8601 UTC timestamp |
intent_id |
str |
Coordination intent linkage ("" when not used) |
reservation_id |
str |
Coordination reservation linkage ("" when not used) |
OpLogCheckpoint
TypedDict — Snapshot of op-log state at a point in time. Allows replay to
start from the checkpoint rather than replaying the full log.
| Field | Type | Description |
|---|---|---|
session_id |
str |
Session identifier |
snapshot_id |
str |
Muse snapshot ID capturing all ops to date |
lamport_ts |
int |
Highest Lamport timestamp at checkpoint time |
op_count |
int |
Total number of ops included up to this checkpoint |
created_at |
str |
ISO-8601 UTC timestamp |
OpLog
Class (not a TypedDict). Session-scoped append-only log of OpEntry records.
| Method | Signature | Description |
|---|---|---|
next_lamport_ts |
() -> int |
Return and increment the Lamport clock |
append |
(entry: OpEntry) -> None |
Append one entry to the log |
read_all |
() -> list[OpEntry] |
Read every entry from disk |
replay_since_checkpoint |
() -> list[OpEntry] |
Read only entries after the most recent checkpoint |
to_structured_delta |
(domain: str) -> StructuredDelta |
Fold all ops into a single StructuredDelta |
checkpoint |
(snapshot_id: str) -> OpLogCheckpoint |
Write a checkpoint and return it |
read_checkpoint |
() -> OpLogCheckpoint \| None |
Load the most recent checkpoint, or None |
session_id |
() -> str |
The session identifier |
CRDT Primitive Types
Path: muse/core/crdts/
Every CRDT class exposes a join() method satisfying the lattice laws
(commutativity, associativity, idempotency). Each also has to_dict() /
from_dict() for serialisation to/from a named wire-format TypedDict.
VectorClock (muse/core/crdts/vclock.py)
VClockDict (Type Alias)
Wire format: dict[str, int] mapping agent ID → event count. Absent keys
default to 0. Produced by VectorClock.to_dict().
VectorClock
Class — Partially-ordered logical clock tracking causal relationships across agents.
| Method | Signature | Description |
|---|---|---|
increment |
(agent_id: str) -> VectorClock |
Return a new clock with agent's count incremented |
merge |
(other: VectorClock) -> VectorClock |
Lattice join: per-agent maximum |
happens_before |
(other: VectorClock) -> bool |
True if self causally precedes other |
concurrent_with |
(other: VectorClock) -> bool |
True if neither happens before the other |
equivalent |
(other: VectorClock) -> bool |
Component-wise equality |
to_dict |
() -> dict[str, int] |
Serialise to wire format |
from_dict |
(data: dict[str, int]) -> VectorClock |
Deserialise from wire format (classmethod) |
LWWRegister (muse/core/crdts/lww_register.py)
LWWValue
TypedDict — Wire format for a Last-Write-Wins Register.
| Field | Type | Description |
|---|---|---|
value |
str |
Stored payload |
timestamp |
float |
Unix seconds or logical clock value |
author |
str |
Agent ID; used as lexicographic tiebreaker for equal timestamps |
LWWRegister
Class — Last-Write-Wins Register. Conflict-free: higher (timestamp, author, value) tuple always wins.
| Method | Signature | Description |
|---|---|---|
read |
() -> str |
Return the current value |
write |
(value, timestamp, author: str) -> LWWRegister |
Return a new register with the given value |
join |
(other: LWWRegister) -> LWWRegister |
Lattice join: argmax on (timestamp, author, value) |
equivalent |
(other: LWWRegister) -> bool |
All three fields equal |
to_dict |
() -> LWWValue |
Serialise |
from_dict |
(data: LWWValue) -> LWWRegister |
Deserialise (classmethod) |
ORSet (muse/core/crdts/or_set.py)
ORSetEntry
TypedDict — One observed-remove token in the ORSet.
| Field | Type | Description |
|---|---|---|
element |
str |
The string value tracked in the set |
token |
str |
UUID4 unique to this specific addition event |
ORSetDict
TypedDict — Wire format for an Observed-Remove Set.
| Field | Type | Description |
|---|---|---|
entries |
list[ORSetEntry] |
All live addition events |
tombstones |
list[str] |
Token strings that have been removed |
ORSet
Class — Observed-Remove Set. Add-wins: concurrent add and remove of the same element results in the element being present.
| Method | Signature | Description |
|---|---|---|
add |
(element: str) -> tuple[ORSet, str] |
Add element, return (new_set, token) |
remove |
(element: str, observed_tokens: set[str]) -> ORSet |
Remove all observed tokens for element |
join |
(other: ORSet) -> ORSet |
Lattice join: union entries, union tombstones |
elements |
() -> frozenset[str] |
Live elements (entries not in tombstones) |
tokens_for |
(element: str) -> set[str] |
All live token IDs for an element |
equivalent |
(other: ORSet) -> bool |
Same live elements |
to_dict |
() -> ORSetDict |
Serialise |
from_dict |
(data: ORSetDict) -> ORSet |
Deserialise (classmethod) |
RGA (muse/core/crdts/rga.py)
RGAElement
TypedDict — One element in an RGA sequence.
| Field | Type | Description |
|---|---|---|
id |
str |
"{timestamp}@{author}" — globally unique, stable after creation |
value |
str |
Content hash referencing the object store |
deleted |
bool |
True = tombstoned (logically removed, never physically deleted) |
parent_id |
str \| None |
ID of the predecessor element; None = prepend to head |
RGA
Class — Replicated Growable Array. Provides a convergent ordered sequence;
concurrent inserts at the same position are deterministically ordered by
descending element_id.
| Method | Signature | Description |
|---|---|---|
insert |
(after_id: str \| None, value: str, *, element_id: str) -> RGA |
Insert value after after_id (or at head if None) |
delete |
(element_id: str) -> RGA |
Tombstone an element |
join |
(other: RGA) -> RGA |
Lattice join: union on IDs; deleted in either → deleted in result |
to_sequence |
() -> list[str] |
Visible values in order (tombstones excluded) |
equivalent |
(other: RGA) -> bool |
Same sequence including tombstone state |
to_dict |
() -> list[RGAElement] |
Serialise |
from_dict |
(data: list[RGAElement]) -> RGA |
Deserialise (classmethod) |
AWMap (muse/core/crdts/aw_map.py)
AWMapEntry
TypedDict — One observed-remove token for an AWMap key-value pair.
| Field | Type | Description |
|---|---|---|
key |
str |
Map key |
value |
str |
Stored value for this token |
token |
str |
UUID4 unique to this specific set() event |
AWMapDict
TypedDict — Wire format for an Add-Wins Map.
| Field | Type | Description |
|---|---|---|
entries |
list[AWMapEntry] |
All live set-events |
tombstones |
list[str] |
Token strings that have been removed |
AWMap
Class — Add-Wins Map. Concurrent set and remove of the same key results in
the key being present. For concurrent sets to the same key, the entry with the
highest token (lexicographic) wins.
| Method | Signature | Description |
|---|---|---|
set |
(key: str, value: str) -> AWMap |
Set key→value; tombstones all previous tokens for key |
remove |
(key: str) -> AWMap |
Tombstone all tokens for key |
join |
(other: AWMap) -> AWMap |
Lattice join: union entries minus union tombstones |
get |
(key: str) -> str \| None |
Current value for key; None if absent |
keys |
() -> frozenset[str] |
All live keys |
to_plain_dict |
() -> dict[str, str] |
Projection to a simple dict |
equivalent |
(other: AWMap) -> bool |
Same live key→value mapping |
to_dict |
() -> AWMapDict |
Serialise |
from_dict |
(data: AWMapDict) -> AWMap |
Deserialise (classmethod) |
GCounter (muse/core/crdts/g_counter.py)
GCounterDict (Type Alias)
Wire format: dict[str, int] mapping agent ID → per-agent count. Absent keys
default to 0. Monotonically non-decreasing per slot.
GCounter
Class — Grow-only Counter. The global value is the sum of all per-agent counts.
join takes the per-slot maximum — the resulting counter is always ≥ both
inputs.
| Method | Signature | Description |
|---|---|---|
increment |
(agent_id: str, by: int = 1) -> GCounter |
Increment agent's slot |
join |
(other: GCounter) -> GCounter |
Lattice join: per-slot maximum |
value |
() -> int |
Sum of all per-agent counts |
value_for |
(agent_id: str) -> int |
Count for a specific agent |
equivalent |
(other: GCounter) -> bool |
All slots equal |
to_dict |
() -> dict[str, int] |
Serialise |
from_dict |
(data: dict[str, int]) -> GCounter |
Deserialise (classmethod) |
Store Types
Path: muse/core/store.py
All commit and snapshot metadata is stored as JSON files under .muse/.
Wire-format TypedDicts are the JSON-serialisable shapes. In-memory
dataclasses are the rich representations used in business logic.
Wire-Format TypedDicts
CommitDict
TypedDict (total=False) — JSON-serialisable representation of a commit
record. All fields are optional to support reading older records that lack
newer fields. from_dict() populates defaults for absent fields.
| Field | Type | Description |
|---|---|---|
commit_id |
str |
SHA-256 hex digest of the commit's canonical inputs |
repo_id |
str |
UUID identifying the repository |
branch |
str |
Branch name at time of commit |
snapshot_id |
str |
SHA-256 hex digest of the attached snapshot |
message |
str |
Commit message |
committed_at |
str |
ISO-8601 UTC timestamp |
parent_commit_id |
str \| None |
First parent commit ID; None for initial commit |
parent2_commit_id |
str \| None |
Second parent commit ID; non-None only for merge commits |
author |
str |
Author name |
metadata |
dict[str, str] |
Extensible string→string metadata bag |
structured_delta |
StructuredDelta \| None |
Typed delta from plugin diff() at commit time; None for initial commit |
sem_ver_bump |
SemVerBump |
Semantic version impact of this commit |
breaking_changes |
list[str] |
Public addresses removed or incompatibly changed |
agent_id |
str |
Stable identity string for the committing agent or human |
model_id |
str |
Model identifier when author is an AI agent; "" for human |
toolchain_id |
str |
Toolchain that produced the commit |
prompt_hash |
str |
SHA-256 of the instruction/prompt (privacy-preserving) |
signature |
str |
Base64url-encoded Ed25519 signature (86 chars) over provenance payload |
signer_public_key |
str |
Base64url-encoded raw Ed25519 public key (43 chars) — for offline verification |
signer_key_id |
str |
First 16 hex chars of SHA-256(raw public key bytes) — for logging |
format_version |
int |
Schema evolution counter (1–7); see version table below |
reviewed_by |
list[str] |
ORSet logical state: list of reviewer IDs (format_version ≥ 5) |
test_runs |
int |
GCounter: monotonically increasing test-run count (format_version ≥ 5) |
format_version evolution table:
| Version | Fields added |
|---|---|
| 1 | commit_id, snapshot_id, parent_commit_id, message, author |
| 2 | structured_delta |
| 3 | sem_ver_bump, breaking_changes |
| 4 | agent_id, model_id, toolchain_id, prompt_hash, signature, signer_key_id |
| 5 | reviewed_by (ORSet), test_runs (GCounter) |
| 6 | Legacy HMAC signing (removed — treat as unsigned) |
| 7 | Ed25519 signing: signer_public_key field added; signature is now base64url Ed25519 |
SnapshotDict
TypedDict — JSON-serialisable representation of a snapshot record.
| Field | Type | Description |
|---|---|---|
snapshot_id |
str |
SHA-256 hex digest of the manifest |
manifest |
dict[str, str] |
POSIX path → SHA-256 object digest |
created_at |
str |
ISO-8601 UTC timestamp |
TagDict
TypedDict — JSON-serialisable representation of a semantic tag.
| Field | Type | Description |
|---|---|---|
tag_id |
str |
UUID identifying the tag |
repo_id |
str |
UUID identifying the repository |
commit_id |
str |
SHA-256 commit ID this tag points to |
tag |
str |
Tag name string (e.g. "v1.0") |
created_at |
str |
ISO-8601 UTC timestamp |
RemoteCommitPayload
TypedDict (total=False) — Wire format received from a remote during push/pull.
All fields optional; callers validate required fields before constructing a
CommitRecord.
| Field | Type | Description |
|---|---|---|
commit_id |
str |
Commit identifier |
repo_id |
str |
Repository UUID |
branch |
str |
Branch name |
snapshot_id |
str |
Snapshot identifier |
message |
str |
Commit message |
committed_at |
str |
ISO-8601 timestamp |
parent_commit_id |
str \| None |
First parent |
parent2_commit_id |
str \| None |
Second parent (merge commits) |
author |
str |
Author name |
metadata |
dict[str, str] |
Metadata bag |
manifest |
dict[str, str] |
Inline snapshot manifest (remote optimisation) |
In-Memory Dataclasses
CommitRecord
@dataclass — In-memory representation of a commit. All datetime fields are
datetime.datetime objects with UTC timezone.
| Field | Type | Default | Description |
|---|---|---|---|
commit_id |
str |
required | SHA-256 hex digest |
repo_id |
str |
required | Repository UUID |
branch |
str |
required | Branch name |
snapshot_id |
str |
required | Attached snapshot digest |
message |
str |
required | Commit message |
committed_at |
datetime.datetime |
required | UTC commit timestamp |
parent_commit_id |
str \| None |
None |
First parent; None for root commits |
parent2_commit_id |
str \| None |
None |
Second parent for merge commits |
author |
str |
"" |
Author name |
metadata |
dict[str, str] |
{} |
Extensible string→string metadata |
structured_delta |
StructuredDelta \| None |
None |
Typed delta from commit time |
sem_ver_bump |
SemVerBump |
"none" |
Semantic version impact |
breaking_changes |
list[str] |
[] |
Removed/incompatible public symbol addresses |
agent_id |
str |
"" |
Agent or human identity |
model_id |
str |
"" |
AI model identifier; "" for human |
toolchain_id |
str |
"" |
Toolchain identifier |
prompt_hash |
str |
"" |
SHA-256 of the prompt |
signature |
str |
"" |
Base64url Ed25519 signature over provenance payload |
signer_public_key |
str |
"" |
Base64url raw Ed25519 public key (43 chars) |
signer_key_id |
str |
"" |
SHA-256[:16] of raw public key bytes |
format_version |
int |
7 |
Schema evolution counter |
reviewed_by |
list[str] |
[] |
ORSet of reviewer IDs |
test_runs |
int |
0 |
GCounter of test-run events |
Methods:
| Method | Returns | Description |
|---|---|---|
to_dict() |
CommitDict |
Serialise to JSON-ready TypedDict |
from_dict(d) |
CommitRecord |
Deserialise from JSON-loaded TypedDict (classmethod) |
SnapshotRecord
@dataclass — In-memory representation of a content-addressed snapshot.
| Field | Type | Default | Description |
|---|---|---|---|
snapshot_id |
str |
required | SHA-256 hex digest of the manifest |
manifest |
dict[str, str] |
required | POSIX path → SHA-256 object digest |
created_at |
datetime.datetime |
UTC now | Creation timestamp |
Methods: to_dict() -> SnapshotDict, from_dict(d: SnapshotDict) -> SnapshotRecord
TagRecord
@dataclass — In-memory representation of a semantic tag.
| Field | Type | Default | Description |
|---|---|---|---|
tag_id |
str |
required | UUID |
repo_id |
str |
required | Repository UUID |
commit_id |
str |
required | Tagged commit's SHA-256 digest |
tag |
str |
required | Tag name |
created_at |
datetime.datetime |
UTC now | Creation timestamp |
Methods: to_dict() -> TagDict, from_dict(d: TagDict) -> TagRecord
Merge Engine Types
Path: muse/core/merge_engine.py
MergeStatePayload
TypedDict (total=False) — JSON-serialisable form of an in-progress merge
state. Written to .muse/MERGE_STATE.json when a merge has unresolved
conflicts.
| Field | Type | Description |
|---|---|---|
base_commit |
str |
Common ancestor commit ID |
ours_commit |
str |
Current branch HEAD at merge start |
theirs_commit |
str |
Incoming branch HEAD at merge start |
conflict_paths |
list[str] |
POSIX paths with unresolved conflicts |
other_branch |
str |
Name of the branch being merged in (optional) |
MergeState
@dataclass (frozen=True) — Loaded in-memory representation of
MERGE_STATE.json. Immutable to prevent accidental mutation during resolution.
| Field | Type | Default | Description |
|---|---|---|---|
conflict_paths |
list[str] |
[] |
Paths with unresolved conflicts |
base_commit |
str \| None |
None |
Common ancestor commit ID |
ours_commit |
str \| None |
None |
Our HEAD at merge start |
theirs_commit |
str \| None |
None |
Their HEAD at merge start |
other_branch |
str \| None |
None |
Name of the incoming branch |
Attributes Types
Path: muse/core/attributes.py
Parse and resolve .museattributes TOML merge-strategy rules.
VALID_STRATEGIES
frozenset[str] — The set of legal strategy strings:
{"ours", "theirs", "union", "auto", "manual"}.
AttributesMeta
TypedDict (total=False) — The [meta] section of .museattributes.
| Field | Type | Description |
|---|---|---|
domain |
str |
Domain name this file targets (optional) |
AttributesRuleDict
TypedDict — A single [[rules]] entry as parsed from TOML.
| Field | Type | Description |
|---|---|---|
path |
str |
fnmatch glob matched against workspace-relative POSIX paths |
dimension |
str |
Domain axis name (e.g. "notes") or "*" to match all |
strategy |
str |
One of the VALID_STRATEGIES strings |
MuseAttributesFile
TypedDict (total=False) — The complete .museattributes file structure after
TOML parsing.
| Field | Type | Description |
|---|---|---|
meta |
AttributesMeta |
Optional [meta] section |
rules |
list[AttributesRuleDict] |
Ordered [[rules]] array |
AttributeRule
@dataclass (frozen=True) — A single resolved rule from .museattributes.
| Field | Type | Default | Description |
|---|---|---|---|
path_pattern |
str |
required | fnmatch glob matched against workspace-relative POSIX paths |
dimension |
str |
required | Domain axis name (e.g. "notes", "pitch_bend") or "*" to match all |
strategy |
str |
required | One of the VALID_STRATEGIES strings |
source_index |
int |
0 |
0-based index of the rule in the [[rules]] array |
Public functions:
load_attributes(root, *, domain=None) -> list[AttributeRule]— reads.museattributesTOML, validates domain, returns rules in file order.read_attributes_meta(root) -> AttributesMeta— returns the[meta]section only.resolve_strategy(rules, path, dimension="*") -> str— first-match lookup; returns"auto"when no rule matches.
MIDI Dimension Merge Types
Path: muse/plugins/midi/midi_merge.py
The multidimensional merge engine for the MIDI domain. MIDI events are bucketed
into 21 orthogonal dimension slices; each slice has a content hash for fast
change detection. A three-way merge resolves each dimension independently using
.museattributes strategies, then reconstructs a valid MIDI file.
Constants
| Name | Type | Description |
|---|---|---|
INTERNAL_DIMS |
list[str] |
21 canonical dimension names in priority order: "tempo_map", "time_signatures", "key_signatures", "track_structure", "notes", "pitch_bend", "channel_pressure", "poly_pressure", "cc_modulation", "cc_volume", "cc_pan", "cc_expression", "cc_sustain", "cc_portamento", "cc_sostenuto", "cc_soft_pedal", "cc_reverb", "cc_chorus", "program_change", "markers", "track_names" |
NON_INDEPENDENT_DIMS |
frozenset[str] |
Dimensions that block the entire merge on bilateral conflict: {"tempo_map", "time_signatures", "track_structure"} |
DIM_ALIAS |
dict[str, str] |
User-facing names → internal bucket names |
_MsgVal (Type Alias)
type _MsgVal = int | str | list[int] — The set of value types that appear
in the serialised form of a MIDI message field. Avoids dict[str, object].
DimensionSlice
@dataclass — All MIDI events belonging to one dimension of a parsed file.
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
required | Internal dimension name (e.g. "notes") |
events |
list[tuple[int, mido.Message]] |
[] |
(abs_tick, message) pairs sorted by ascending absolute tick |
content_hash |
str |
"" |
SHA-256 of the canonical JSON serialisation; computed in __post_init__ |
MidiDimensions
@dataclass — All 21 dimension slices extracted from one MIDI file, plus
file-level metadata.
| Field | Type | Description |
|---|---|---|
ticks_per_beat |
int |
MIDI timing resolution (pulses per quarter note) |
file_type |
int |
MIDI file type (0 = single-track, 1 = multi-track synchronous) |
slices |
dict[str, DimensionSlice] |
Internal dimension name → slice |
Method:
| Name | Signature | Description |
|---|---|---|
get |
(dim: str) -> DimensionSlice |
Resolve a user-facing alias or internal name to the correct slice |
Public functions:
| Function | Signature | Description |
|---|---|---|
extract_dimensions |
(midi_bytes: bytes) -> MidiDimensions |
Parse MIDI bytes and bucket events by dimension |
dimension_conflict_detail |
(base, left, right: MidiDimensions) -> dict[str, str] |
Per-dimension change report: "unchanged", "left_only", "right_only", or "both" |
merge_midi_dimensions |
(base_bytes, left_bytes, right_bytes: bytes, attrs_rules: list[AttributeRule], path: str) -> tuple[bytes, dict[str, str]] \| None |
Three-way dimension merge; returns (merged_bytes, dimension_report) or None on unresolvable conflict |
Code Plugin Types
Path: muse/plugins/code/
The code domain plugin introduces typed representations for source code
symbols parsed from Python (via ast) and other languages (via tree-sitter).
SymbolKind (Type Alias)
SymbolKind = Literal[
"function", "async_function", "class", "method",
"async_method", "variable", "import"
]
SymbolRecord
TypedDict — Metadata for one named symbol extracted from a source file.
The hashing strategy uses multiple content IDs so that rename detection,
signature-only changes, and full body changes can each be distinguished.
| Field | Type | Description |
|---|---|---|
kind |
SymbolKind |
Symbol kind discriminator |
name |
str |
Short symbol name (e.g. "calculate") |
qualified_name |
str |
Dotted name within the file (e.g. "MyClass.calculate") |
content_id |
str |
SHA-256 of full normalised AST (name + signature + body) |
body_hash |
str |
SHA-256 of body statements only — for rename detection |
signature_id |
str |
SHA-256 of "name(args)->return" — for implementation-only changes |
metadata_id |
str |
SHA-256 of decorators/async/bases; "" for pre-v2 records |
canonical_key |
str |
"{file}#{scope}#{kind}#{name}#{lineno}" — stable handle across renames |
lineno |
int |
Line number of the symbol definition |
end_lineno |
int |
Last line number of the symbol definition |
SymbolTree (Type Alias)
TypeAlias = dict[str, SymbolRecord] — Maps DomainAddress strings to
SymbolRecord instances for all symbols in a file.
LanguageAdapter
@runtime_checkable Protocol — Abstraction over language-specific AST parsing.
Implemented by PythonAdapter, TreeSitterAdapter, and FallbackAdapter.
| Method | Signature | Description |
|---|---|---|
supported_extensions |
() -> frozenset[str] |
File extensions this adapter handles (e.g. {".py"}) |
parse_symbols |
(source: bytes, file_path: str) -> SymbolTree |
Parse source bytes and return a SymbolTree |
file_content_id |
(source: bytes) -> str |
SHA-256 of the entire file (fallback content address) |
LangSpec
TypedDict — Tree-sitter per-language configuration used to construct a
TreeSitterAdapter.
| Field | Type | Description |
|---|---|---|
extensions |
frozenset[str] |
File extensions for this language |
module_name |
str |
Python import name (e.g. "tree_sitter_javascript") |
lang_func |
str |
Attribute name on the module returning the raw grammar capsule |
query_str |
str |
Tree-sitter S-expression query with @sym and @name captures |
kind_map |
dict[str, SymbolKind] |
Tree-sitter node type → SymbolKind |
class_node_types |
frozenset[str] |
Node types treated as class containers |
class_name_field |
str |
Field name that carries the class identifier node |
receiver_capture |
str |
Go-style receiver capture name; "" to skip |
Concrete adapter classes (not TypedDicts):
PythonAdapter— implementsLanguageAdapterviaast.parse/ast.unparseFallbackAdapter(extensions)— returns emptySymbolTree, raw-bytes SHA-256TreeSitterAdapter(spec, parser, language)— tree-sitter CST, error-tolerant
Identity Types
Path: muse/core/identity.py, muse/core/keypair.py
Global identity store at ~/.muse/identity.toml.
IdentityEntry
TypedDict (total=False) — one authenticated identity, keyed by hub hostname
(human) or compound "hostname#agent_id" (agent).
| Field | Type | Description |
|---|---|---|
type |
str |
"human" or "agent" |
handle |
str |
Hub-assigned handle, e.g. "gabriel" or "agentception-abc123" |
key_path |
str |
Absolute path to Ed25519 private key PEM file |
algorithm |
str |
"ed25519" (only implemented algorithm) |
fingerprint |
str |
SHA-256 hex of raw public key bytes (64 chars) |
capabilities |
list[str] |
Agent capability strings; empty for humans |
provisioned_by |
str |
For agents: handle of the human who provisioned this key |
TOML file format (~/.muse/identity.toml):
["localhost:10003"]
type = "human"
handle = "gabriel"
key_path = "/Users/gabriel/.muse/keys/localhost_10003.pem"
algorithm = "ed25519"
fingerprint = "<64-hex-chars>"
["localhost:10003#agentception-abc123"]
type = "agent"
handle = "agentception-abc123"
key_path = "/Users/gabriel/.muse/keys/localhost_10003__agentception-abc123.pem"
algorithm = "ed25519"
fingerprint = "<64-hex-chars>"
provisioned_by = "gabriel"
capabilities = ["push", "pull"]
Key path naming convention:
- Human:
~/.muse/keys/{hostname_safe}.pem(:and/replaced by_) - Agent:
~/.muse/keys/{hostname_safe}__{agent_id}.pem
Public functions:
| Function | Signature | Description |
|---|---|---|
load_identity |
(hub_url, agent_id=None) → IdentityEntry \| None |
Load entry; compound key when agent_id provided |
save_identity |
(hub_url, entry, agent_id=None) → None |
Save with exclusive lock |
clear_identity |
(hub_url, agent_id=None) → bool |
Remove entry |
resolve_signing_identity |
(hub_url, agent_id=None) → (handle, key) \| None |
Agent key → human key fallback |
list_all_identities |
() → dict[str, IdentityEntry] |
All entries keyed by TOML section name |
Configuration Types
Path: muse/cli/config.py
The structured view of .muse/config.toml.
RemoteEntry
TypedDict (total=False) — [remotes.<name>] section.
| Field | Type | Description |
|---|---|---|
url |
str |
Remote Hub URL |
branch |
str |
Upstream branch tracked by this remote |
MuseConfig
TypedDict (total=False) — Structured view of the entire .muse/config.toml.
| Field | Type | Description |
|---|---|---|
remotes |
dict[str, RemoteEntry] |
Named remote sections |
domain |
dict[str, str] |
Domain-specific key/value pairs; ignored by core, read only by the active plugin (e.g. ticks_per_beat for music) |
RemoteConfig
TypedDict — Public-facing remote descriptor returned by list_remotes().
| Field | Type | Description |
|---|---|---|
name |
str |
Remote name (e.g. "origin") |
url |
str |
Remote URL |
MIDI / MusicXML Import Types
Path: muse/cli/midi_parser.py
Types used by muse import to parse Standard MIDI Files and MusicXML documents
into Muse's internal note representation.
MidiMeta
TypedDict — Format-specific metadata for Standard MIDI Files.
| Field | Type | Description |
|---|---|---|
num_tracks |
int |
Number of MIDI tracks in the file |
MusicXMLMeta
TypedDict — Format-specific metadata for MusicXML files.
| Field | Type | Description |
|---|---|---|
num_parts |
int |
Number of parts (instruments) in the score |
part_names |
list[str] |
Display names of each part |
RawMeta (Type Alias)
TypeAlias = MidiMeta | MusicXMLMeta — Discriminated union of all
format-specific metadata shapes.
NoteEvent
@dataclass — A single sounding note extracted from an imported file.
| Field | Type | Description |
|---|---|---|
pitch |
int |
MIDI pitch number (0–127) |
velocity |
int |
MIDI velocity (0–127; 0 = note-off) |
start_tick |
int |
Onset tick relative to file start |
duration_ticks |
int |
Note length in MIDI ticks |
channel |
int |
MIDI channel (0–15) |
channel_name |
str |
Track/part name for this channel |
MuseImportData
@dataclass — Complete parsed result returned by parse_file().
| Field | Type | Description |
|---|---|---|
source_path |
pathlib.Path |
Absolute path to the source file |
format |
str |
"midi" or "musicxml" |
ticks_per_beat |
int |
MIDI timing resolution (pulses per quarter note) |
tempo_bpm |
float |
Tempo in beats per minute |
notes |
list[NoteEvent] |
All sounding notes, in onset order |
tracks |
list[str] |
Track/part names present in the file |
raw_meta |
RawMeta |
Format-specific metadata |
Stash Types
Path: muse/cli/commands/stash.py
StashEntry
TypedDict — A single entry in the stash stack, persisted to
.muse/stash.json as one element of a JSON array. Push prepends; pop
removes index 0.
| Field | Type | Description |
|---|---|---|
snapshot_id |
str |
SHA-256 content digest of the stashed snapshot |
manifest |
dict[str, str] |
POSIX path → SHA-256 object digest of stashed files |
branch |
str |
Branch name active when the stash was saved |
stashed_at |
str |
ISO-8601 UTC timestamp of the stash operation |
Error Hierarchy
Path: muse/core/errors.py
ExitCode
IntEnum — Standardised CLI exit codes.
| Value | Integer | Meaning |
|---|---|---|
SUCCESS |
0 |
Command completed successfully |
USER_ERROR |
1 |
Bad arguments or invalid user input |
REPO_NOT_FOUND |
2 |
Not inside a Muse repository |
INTERNAL_ERROR |
3 |
Unexpected internal failure |
MuseCLIError
Exception — Base exception for all Muse CLI errors.
| Field | Type | Description |
|---|---|---|
exit_code |
ExitCode |
Exit code to use when this exception terminates the process |
RepoNotFoundError
MuseCLIError — Raised when a command is invoked outside a Muse repository.
Default message: "Not a Muse repository. Run muse init." Default exit
code: ExitCode.REPO_NOT_FOUND.
Alias: MuseNotARepoError = RepoNotFoundError
Entity Hierarchy
Muse VCS
│
├── Domain Protocol (muse/domain.py)
│ │
│ ├── Type Aliases
│ │ ├── DomainAddress — str
│ │ ├── SemVerBump — Literal["major","minor","patch","none"]
│ │ ├── LeafDomainOp — InsertOp | DeleteOp | MoveOp | ReplaceOp | MutateOp
│ │ ├── DomainOp — LeafDomainOp | PatchOp (recursive via PatchOp.child_ops)
│ │ ├── LiveState — SnapshotManifest | pathlib.Path
│ │ ├── StateSnapshot — SnapshotManifest
│ │ └── StateDelta — StructuredDelta
│ │
│ ├── Operation TypedDicts
│ │ ├── InsertOp — op="insert" · address · position · content_id · content_summary
│ │ ├── DeleteOp — op="delete" · address · position · content_id · content_summary
│ │ ├── MoveOp — op="move" · address · from_position · to_position · content_id
│ │ ├── ReplaceOp — op="replace" · address · position · old/new content_id · summaries
│ │ ├── FieldMutation — old: str · new: str (used as dict[str,FieldMutation] in MutateOp)
│ │ ├── MutateOp — op="mutate" · address · entity_id · old/new content_id · fields · summaries
│ │ └── PatchOp — op="patch" · address · child_ops: list[DomainOp] · child_domain
│ │
│ ├── Snapshot / Delta TypedDicts
│ │ ├── SnapshotManifest — {files: dict[str,str], domain: str}
│ │ ├── StructuredDelta — total=False: domain · ops · summary · sem_ver_bump · breaking_changes
│ │ ├── CRDTSnapshotManifest — files · domain · vclock · crdt_state · schema_version
│ │ └── EntityProvenance — total=False: entity_id · origin_op_id · last_modified_op_id · …
│ │
│ ├── Result Dataclasses
│ │ ├── ConflictRecord — path · conflict_type · summaries · addresses
│ │ ├── MergeResult — merged · conflicts · applied_strategies · dimension_reports · op_log · conflict_records
│ │ └── DriftReport — has_drift · summary · delta
│ │
│ └── Protocols
│ ├── MuseDomainPlugin — @runtime_checkable: snapshot/diff/merge/drift/apply/schema
│ ├── StructuredMergePlugin — extends MuseDomainPlugin: +merge_ops()
│ └── CRDTPlugin — extends MuseDomainPlugin: +crdt_schema/join/to_crdt_state/from_crdt_state
│
├── Domain Schema (muse/core/schema.py)
│ ├── ElementSchema (type alias)
│ │ ├── SequenceSchema — kind="sequence" · element_type · identity · diff_algorithm · alphabet
│ │ ├── TreeSchema — kind="tree" · node_type · diff_algorithm
│ │ ├── TensorSchema — kind="tensor" · dtype · rank · epsilon · diff_mode
│ │ ├── SetSchema — kind="set" · element_type · identity
│ │ └── MapSchema — kind="map" · key_type · value_schema: ElementSchema (recursive)
│ ├── CRDTPrimitive — Literal["lww_register","or_set","rga","aw_map","g_counter"]
│ ├── DimensionSpec — name · description · schema: ElementSchema · independent_merge
│ ├── CRDTDimensionSpec — name · description · crdt_type: CRDTPrimitive · independent_merge
│ └── DomainSchema — domain · description · dimensions · top_level · merge_mode · schema_version
│
├── Diff Algorithms (muse/core/diff_algorithms/)
│ ├── DiffInput (type alias)
│ │ ├── SequenceInput — kind="sequence" · items: list[str]
│ │ ├── SetInput — kind="set" · items: frozenset[str]
│ │ ├── TensorInput — kind="tensor" · values: list[float]
│ │ ├── MapInput — kind="map" · entries: dict[str,str]
│ │ └── TreeInput — kind="tree" · root: TreeNode
│ ├── EditKind — Literal["keep","insert","delete"]
│ ├── EditStep — frozen dataclass: kind · base_index · target_index · item
│ └── TreeNode — frozen dataclass: id · label · content_id · children: tuple[TreeNode,…]
│
├── OT Merge (muse/core/op_transform.py)
│ └── MergeOpsResult — merged_ops: list[DomainOp] · conflict_ops: list[tuple[DomainOp,DomainOp]]
│
├── Op Log (muse/core/op_log.py)
│ ├── OpEntry — TypedDict: op_id · actor_id · lamport_ts · parent_op_ids · domain · domain_op · …
│ ├── OpLogCheckpoint — TypedDict: session_id · snapshot_id · lamport_ts · op_count · created_at
│ └── OpLog — class: append/read_all/replay_since_checkpoint/checkpoint
│
├── CRDT Primitives (muse/core/crdts/)
│ ├── VectorClock — class: increment/merge/happens_before/concurrent_with ↔ dict[str,int]
│ ├── LWWRegister — class: read/write/join ↔ LWWValue{value,timestamp,author}
│ ├── ORSet — class: add/remove/join/elements ↔ ORSetDict{entries:list[ORSetEntry],tombstones}
│ ├── RGA — class: insert/delete/join/to_sequence ↔ list[RGAElement{id,value,deleted,parent_id}]
│ ├── AWMap — class: set/remove/join/get/keys ↔ AWMapDict{entries:list[AWMapEntry],tombstones}
│ └── GCounter — class: increment/join/value ↔ dict[str,int]
│
├── Store (muse/core/store.py)
│ ├── Wire-Format TypedDicts
│ │ ├── CommitDict — total=False: all commit fields · sem_ver_bump · agent provenance · CRDT annotations
│ │ ├── SnapshotDict — snapshot_id · manifest · created_at
│ │ ├── TagDict — tag_id · repo_id · commit_id · tag · created_at
│ │ └── RemoteCommitPayload — total=False: wire commit + inline manifest
│ └── In-Memory Dataclasses
│ ├── CommitRecord — typed datetime · structured_delta · sem_ver_bump · provenance · reviewed_by/test_runs
│ ├── SnapshotRecord — snapshot_id · manifest: dict[str,str] · datetime
│ └── TagRecord — tag_id · repo_id · commit_id · tag · datetime
│
├── Merge Engine (muse/core/merge_engine.py)
│ ├── MergeStatePayload — total=False: MERGE_STATE.json shape
│ └── MergeState — frozen dataclass: conflict_paths · base/ours/theirs commits · other_branch
│
├── Attributes (muse/core/attributes.py)
│ ├── VALID_STRATEGIES — frozenset{ours,theirs,union,auto,manual}
│ ├── AttributesMeta — total=False: domain: str
│ ├── AttributesRuleDict — path · dimension · strategy
│ ├── MuseAttributesFile — total=False: meta + rules
│ └── AttributeRule — frozen dataclass: path_pattern · dimension · strategy · source_index
│
├── MIDI Dimension Merge (muse/plugins/midi/midi_merge.py)
│ ├── INTERNAL_DIMS — list[str]: 21 dimension names
│ ├── NON_INDEPENDENT_DIMS — frozenset{tempo_map,time_signatures,track_structure}
│ ├── DIM_ALIAS — dict[str,str]: user alias → internal name
│ ├── _MsgVal — type alias: int | str | list[int]
│ ├── DimensionSlice — dataclass: name · events · content_hash
│ └── MidiDimensions — dataclass: ticks_per_beat · file_type · slices: dict[str,DimensionSlice]
│
├── Code Plugin (muse/plugins/code/)
│ ├── SymbolKind — Literal["function","async_function","class","method",…]
│ ├── SymbolRecord — TypedDict: kind · name · qualified_name · content_id · body_hash · signature_id · …
│ ├── SymbolTree — type alias: dict[str, SymbolRecord]
│ ├── LanguageAdapter — Protocol: supported_extensions/parse_symbols/file_content_id
│ └── LangSpec — TypedDict: extensions · module_name · lang_func · query_str · kind_map · …
│
├── Configuration (muse/cli/config.py)
│ ├── RemoteEntry — total=False: url · branch
│ ├── MuseConfig — total=False: remotes · domain: dict[str,str]
│ └── RemoteConfig — name · url
│
├── MIDI / MusicXML Import (muse/cli/midi_parser.py)
│ ├── MidiMeta — num_tracks: int
│ ├── MusicXMLMeta — num_parts · part_names
│ ├── RawMeta — MidiMeta | MusicXMLMeta
│ ├── NoteEvent — pitch · velocity · start_tick · duration_ticks · channel · channel_name
│ └── MuseImportData — source_path · format · ticks_per_beat · tempo_bpm · notes · tracks · raw_meta
│
├── Stash (muse/cli/commands/stash.py)
│ └── StashEntry — snapshot_id · manifest · branch · stashed_at
│
└── Errors (muse/core/errors.py)
├── ExitCode — IntEnum: SUCCESS=0 USER_ERROR=1 REPO_NOT_FOUND=2 INTERNAL_ERROR=3
├── MuseCLIError — Exception: exit_code: ExitCode
├── RepoNotFoundError — MuseCLIError: default REPO_NOT_FOUND
└── MuseNotARepoError — alias for RepoNotFoundError
Entity Graphs (Mermaid)
Arrow conventions:
*--composition (owns, lifecycle-coupled)-->association (references by ID or field)..>dependency (uses, produces, or implements)
Diagram 1 — Domain Protocol and Plugin Contract
The MuseDomainPlugin protocol and the types that flow through its six methods.
Optional extensions StructuredMergePlugin and CRDTPlugin unlock richer
semantics. MidiPlugin is the reference implementation.
classDiagram
class SnapshotManifest {
<<TypedDict>>
+files : dict~str, str~
+domain : str
}
class StructuredDelta {
<<TypedDict total=False>>
+domain : str
+ops : list~DomainOp~
+summary : str
+sem_ver_bump : SemVerBump
+breaking_changes : list~str~
}
class MergeResult {
<<dataclass>>
+merged : StateSnapshot
+conflicts : list~str~
+applied_strategies : dict~str, str~
+dimension_reports : dict~str, dict~str, str~~
+op_log : list~DomainOp~
+conflict_records : list~ConflictRecord~
+is_clean : bool
}
class ConflictRecord {
<<dataclass>>
+path : str
+conflict_type : str
+ours_summary : str
+theirs_summary : str
+addresses : list~str~
}
class DriftReport {
<<dataclass>>
+has_drift : bool
+summary : str
+delta : StateDelta
}
class MuseDomainPlugin {
<<Protocol runtime_checkable>>
+snapshot(live_state) StateSnapshot
+diff(base, target) StateDelta
+merge(base, left, right, *, repo_root) MergeResult
+drift(committed, live) DriftReport
+apply(delta, live_state) LiveState
+schema() DomainSchema
}
class StructuredMergePlugin {
<<Protocol extends MuseDomainPlugin>>
+merge_ops(base, ours, theirs, ours_ops, theirs_ops) MergeResult
}
class CRDTPlugin {
<<Protocol extends MuseDomainPlugin>>
+crdt_schema() list~CRDTDimensionSpec~
+join(a, b) CRDTSnapshotManifest
+to_crdt_state(snapshot) CRDTSnapshotManifest
+from_crdt_state(crdt) StateSnapshot
}
class MidiPlugin {
<<MuseDomainPlugin implementation>>
+snapshot(live_state) StateSnapshot
+diff(base, target) StateDelta
+merge(base, left, right, *, repo_root) MergeResult
+drift(committed, live) DriftReport
+apply(delta, live_state) LiveState
+schema() DomainSchema
}
MuseDomainPlugin ..> SnapshotManifest : StateSnapshot
MuseDomainPlugin ..> StructuredDelta : StateDelta
MuseDomainPlugin --> MergeResult : merge returns
MuseDomainPlugin --> DriftReport : drift returns
StructuredMergePlugin --|> MuseDomainPlugin
CRDTPlugin --|> MuseDomainPlugin
MidiPlugin ..|> MuseDomainPlugin : implements
MergeResult --> SnapshotManifest : merged
MergeResult *-- ConflictRecord : conflict_records
DriftReport --> StructuredDelta : delta
Diagram 2 — DomainOp Discriminated Union
The typed operation algebra. PatchOp is recursive via child_ops.
MutateOp carries per-field deltas via FieldMutation.
classDiagram
class DomainOp {
<<type alias>>
LeafDomainOp | PatchOp
}
class InsertOp {
<<TypedDict op=insert>>
+address : DomainAddress
+position : int | None
+content_id : str
+content_summary : str
}
class DeleteOp {
<<TypedDict op=delete>>
+address : DomainAddress
+position : int | None
+content_id : str
+content_summary : str
}
class MoveOp {
<<TypedDict op=move>>
+address : DomainAddress
+from_position : int
+to_position : int
+content_id : str
}
class ReplaceOp {
<<TypedDict op=replace>>
+address : DomainAddress
+position : int | None
+old_content_id : str
+new_content_id : str
+old_summary : str
+new_summary : str
}
class FieldMutation {
<<TypedDict>>
+old : str
+new : str
}
class MutateOp {
<<TypedDict op=mutate>>
+address : DomainAddress
+entity_id : str
+old_content_id : str
+new_content_id : str
+fields : dict~str, FieldMutation~
+old_summary : str
+new_summary : str
}
class PatchOp {
<<TypedDict op=patch>>
+address : DomainAddress
+child_ops : list~DomainOp~
+child_domain : str
+child_summary : str
}
DomainOp ..> InsertOp : variant
DomainOp ..> DeleteOp : variant
DomainOp ..> MoveOp : variant
DomainOp ..> ReplaceOp : variant
DomainOp ..> MutateOp : variant
DomainOp ..> PatchOp : variant
MutateOp *-- FieldMutation : fields values
PatchOp *-- DomainOp : child_ops (recursive)
Diagram 3 — Domain Schema and Diff Input Pairing
Each ElementSchema variant is paired with a DiffInput variant sharing
the same kind discriminator. diff_by_schema() uses this to dispatch to
the correct algorithm.
classDiagram
class ElementSchema {
<<type alias>>
SequenceSchema | TreeSchema | TensorSchema | SetSchema | MapSchema
}
class SequenceSchema {
<<TypedDict kind=sequence>>
+element_type : str
+identity : by_id | by_position | by_content
+diff_algorithm : lcs | myers | patience
+alphabet : list~str~ | None
}
class TreeSchema {
<<TypedDict kind=tree>>
+node_type : str
+diff_algorithm : zhang_shasha | gumtree
}
class TensorSchema {
<<TypedDict kind=tensor>>
+dtype : float32 | float64 | int8 | ...
+rank : int
+epsilon : float
+diff_mode : sparse | block | full
}
class SetSchema {
<<TypedDict kind=set>>
+element_type : str
+identity : by_content | by_id
}
class MapSchema {
<<TypedDict kind=map>>
+key_type : str
+value_schema : ElementSchema
+identity : by_key
}
class SequenceInput {
<<TypedDict kind=sequence>>
+items : list~str~
}
class TreeInput {
<<TypedDict kind=tree>>
+root : TreeNode
}
class TensorInput {
<<TypedDict kind=tensor>>
+values : list~float~
}
class SetInput {
<<TypedDict kind=set>>
+items : frozenset~str~
}
class MapInput {
<<TypedDict kind=map>>
+entries : dict~str, str~
}
ElementSchema ..> SequenceSchema : variant
ElementSchema ..> TreeSchema : variant
ElementSchema ..> TensorSchema : variant
ElementSchema ..> SetSchema : variant
ElementSchema ..> MapSchema : variant
MapSchema --> ElementSchema : value_schema recursive
SequenceSchema ..> SequenceInput : paired input
TreeSchema ..> TreeInput : paired input
TensorSchema ..> TensorInput : paired input
SetSchema ..> SetInput : paired input
MapSchema ..> MapInput : paired input
Diagram 4 — CRDT Primitive Lattice
Each CRDT has a class with join() satisfying lattice laws and a wire-format
TypedDict for serialisation. All are used by CRDTPlugin and the CRDT annotation
fields in CommitRecord.
classDiagram
class VectorClock {
<<class CRDT>>
+increment(agent_id) VectorClock
+merge(other) VectorClock
+happens_before(other) bool
+concurrent_with(other) bool
+to_dict() dict~str, int~
}
class LWWValue {
<<TypedDict wire>>
+value : str
+timestamp : float
+author : str
}
class LWWRegister {
<<class CRDT>>
+read() str
+write(value, ts, author) LWWRegister
+join(other) LWWRegister
+to_dict() LWWValue
}
class ORSetEntry {
<<TypedDict>>
+element : str
+token : str
}
class ORSetDict {
<<TypedDict wire>>
+entries : list~ORSetEntry~
+tombstones : list~str~
}
class ORSet {
<<class CRDT add-wins>>
+add(element) tuple~ORSet, str~
+remove(element, tokens) ORSet
+join(other) ORSet
+elements() frozenset~str~
+to_dict() ORSetDict
}
class RGAElement {
<<TypedDict>>
+id : str
+value : str
+deleted : bool
+parent_id : str | None
}
class RGA {
<<class CRDT sequence>>
+insert(after_id, value, element_id) RGA
+delete(element_id) RGA
+join(other) RGA
+to_sequence() list~str~
+to_dict() list~RGAElement~
}
class AWMapEntry {
<<TypedDict>>
+key : str
+value : str
+token : str
}
class AWMapDict {
<<TypedDict wire>>
+entries : list~AWMapEntry~
+tombstones : list~str~
}
class AWMap {
<<class CRDT add-wins map>>
+set(key, value) AWMap
+remove(key) AWMap
+join(other) AWMap
+get(key) str | None
+to_dict() AWMapDict
}
class GCounter {
<<class CRDT g-counter>>
+increment(agent_id, by) GCounter
+join(other) GCounter
+value() int
+to_dict() dict~str, int~
}
LWWRegister ..> LWWValue : to_dict
ORSet ..> ORSetDict : to_dict
ORSetDict *-- ORSetEntry : entries
RGA ..> RGAElement : to_dict items
AWMap ..> AWMapDict : to_dict
AWMapDict *-- AWMapEntry : entries
Diagram 5 — Store Wire-Format and In-Memory Dataclasses
The two-layer design: wire-format TypedDicts for JSON serialisation, rich
dataclasses for in-memory logic. CommitRecord now carries agent provenance
and CRDT annotation fields.
classDiagram
class CommitDict {
<<TypedDict total=False wire>>
+commit_id : str
+repo_id : str
+branch : str
+snapshot_id : str
+message : str
+committed_at : str
+parent_commit_id : str | None
+parent2_commit_id : str | None
+structured_delta : StructuredDelta | None
+sem_ver_bump : SemVerBump
+agent_id : str
+model_id : str
+format_version : int
+reviewed_by : list~str~
+test_runs : int
}
class CommitRecord {
<<dataclass>>
+commit_id : str
+repo_id : str
+branch : str
+snapshot_id : str
+message : str
+committed_at : datetime
+parent_commit_id : str | None
+parent2_commit_id : str | None
+structured_delta : StructuredDelta | None
+sem_ver_bump : SemVerBump
+agent_id : str
+model_id : str
+format_version : int
+reviewed_by : list~str~
+test_runs : int
+to_dict() CommitDict
+from_dict(d) CommitRecord
}
class SnapshotDict {
<<TypedDict wire>>
+snapshot_id : str
+manifest : dict~str, str~
+created_at : str
}
class SnapshotRecord {
<<dataclass>>
+snapshot_id : str
+manifest : dict~str, str~
+created_at : datetime
+to_dict() SnapshotDict
+from_dict(d) SnapshotRecord
}
class TagDict {
<<TypedDict wire>>
+tag_id : str
+repo_id : str
+commit_id : str
+tag : str
+created_at : str
}
class TagRecord {
<<dataclass>>
+tag_id : str
+repo_id : str
+commit_id : str
+tag : str
+created_at : datetime
+to_dict() TagDict
+from_dict(d) TagRecord
}
class RemoteCommitPayload {
<<TypedDict total=False>>
+commit_id : str
+snapshot_id : str
+manifest : dict~str, str~
}
CommitRecord ..> CommitDict : to_dict / from_dict
SnapshotRecord ..> SnapshotDict : to_dict / from_dict
TagRecord ..> TagDict : to_dict / from_dict
RemoteCommitPayload ..> CommitDict : store_pulled_commit builds
CommitRecord --> SnapshotRecord : snapshot_id reference
Diagram 6 — Op Log Types
The op log records every domain operation in causal order. OpEntry carries a
DomainOp; OpLog accumulates entries and can fold them into a
StructuredDelta.
classDiagram
class OpEntry {
<<TypedDict>>
+op_id : str
+actor_id : str
+lamport_ts : int
+parent_op_ids : list~str~
+domain : str
+domain_op : DomainOp
+created_at : str
+intent_id : str
+reservation_id : str
}
class OpLogCheckpoint {
<<TypedDict>>
+session_id : str
+snapshot_id : str
+lamport_ts : int
+op_count : int
+created_at : str
}
class OpLog {
<<class>>
+append(entry) None
+read_all() list~OpEntry~
+replay_since_checkpoint() list~OpEntry~
+to_structured_delta(domain) StructuredDelta
+checkpoint(snapshot_id) OpLogCheckpoint
+read_checkpoint() OpLogCheckpoint | None
}
OpLog *-- OpEntry : appends
OpLog --> OpLogCheckpoint : checkpoint produces
OpEntry --> OpLogCheckpoint : lamport_ts tracks progress
Diagram 7 — Merge Engine State
The in-progress merge state written to disk on conflict and loaded on continuation.
classDiagram
class MergeStatePayload {
<<TypedDict total=False>>
+base_commit : str
+ours_commit : str
+theirs_commit : str
+conflict_paths : list~str~
+other_branch : str
}
class MergeState {
<<dataclass frozen>>
+conflict_paths : list~str~
+base_commit : str | None
+ours_commit : str | None
+theirs_commit : str | None
+other_branch : str | None
}
class MergeOpsResult {
<<dataclass>>
+merged_ops : list~DomainOp~
+conflict_ops : list~tuple~DomainOp, DomainOp~~
+is_clean : bool
}
MergeStatePayload ..> MergeState : read_merge_state produces
MergeState ..> MergeStatePayload : write_merge_state serialises
Diagram 8 — Attributes and MIDI Dimension Merge
The .museattributes rule pipeline flowing into the 21-dimension MIDI merge
engine.
classDiagram
class AttributeRule {
<<dataclass frozen>>
+path_pattern : str
+dimension : str
+strategy : str
+source_index : int
}
class DimensionSlice {
<<dataclass>>
+name : str
+events : list~tuple~int, Message~~
+content_hash : str
}
class MidiDimensions {
<<dataclass 21 dims>>
+ticks_per_beat : int
+file_type : int
+slices : dict~str, DimensionSlice~
+get(dim) DimensionSlice
}
class MergeResult {
<<dataclass>>
+merged : StateSnapshot
+conflicts : list~str~
+applied_strategies : dict~str, str~
+dimension_reports : dict~str, dict~str, str~~
}
class MidiPlugin {
<<MuseDomainPlugin>>
+merge(base, left, right, *, repo_root) MergeResult
}
MidiPlugin ..> AttributeRule : load_attributes
MidiPlugin ..> MidiDimensions : extract_dimensions
MidiPlugin --> MergeResult : returns
MidiDimensions *-- DimensionSlice : slices (21 buckets)
AttributeRule ..> DimensionSlice : resolve_strategy selects winner
MergeResult --> AttributeRule : applied_strategies reflects rules
Diagram 9 — Code Plugin Types
Symbol extraction pipeline for the code domain. LanguageAdapter is the
per-language abstraction; PythonAdapter and TreeSitterAdapter are the
concrete implementations.
classDiagram
class LanguageAdapter {
<<Protocol runtime_checkable>>
+supported_extensions() frozenset~str~
+parse_symbols(source, file_path) SymbolTree
+file_content_id(source) str
}
class LangSpec {
<<TypedDict tree-sitter config>>
+extensions : frozenset~str~
+module_name : str
+lang_func : str
+query_str : str
+kind_map : dict~str, SymbolKind~
}
class SymbolRecord {
<<TypedDict>>
+kind : SymbolKind
+name : str
+qualified_name : str
+content_id : str
+body_hash : str
+signature_id : str
+metadata_id : str
+canonical_key : str
+lineno : int
+end_lineno : int
}
class PythonAdapter {
<<LanguageAdapter>>
ast.parse / ast.unparse
}
class TreeSitterAdapter {
<<LanguageAdapter>>
tree-sitter CST, error-tolerant
}
class FallbackAdapter {
<<LanguageAdapter>>
empty SymbolTree, SHA-256 only
}
LanguageAdapter ..> SymbolRecord : parse_symbols returns dict
PythonAdapter ..|> LanguageAdapter
TreeSitterAdapter ..|> LanguageAdapter
FallbackAdapter ..|> LanguageAdapter
TreeSitterAdapter --> LangSpec : configured by
Diagram 10 — Configuration, Import, Stash, and Errors
Supporting types for CLI infrastructure.
classDiagram
class MuseConfig {
<<TypedDict total=False>>
+remotes : dict~str, RemoteEntry~
+domain : dict~str, str~
}
class RemoteEntry {
<<TypedDict total=False>>
+url : str
+branch : str
}
class RemoteConfig {
<<TypedDict public API>>
+name : str
+url : str
}
class StashEntry {
<<TypedDict>>
+snapshot_id : str
+manifest : dict~str, str~
+branch : str
+stashed_at : str
}
class MuseImportData {
<<dataclass>>
+source_path : Path
+format : str
+notes : list~NoteEvent~
+raw_meta : RawMeta
}
class NoteEvent {
<<dataclass>>
+pitch : int
+velocity : int
+start_tick : int
+duration_ticks : int
}
class ExitCode {
<<IntEnum>>
SUCCESS = 0
USER_ERROR = 1
REPO_NOT_FOUND = 2
INTERNAL_ERROR = 3
}
class MuseCLIError {
<<Exception>>
+exit_code : ExitCode
}
class RepoNotFoundError {
<<MuseCLIError>>
default REPO_NOT_FOUND
}
MuseConfig *-- RemoteEntry : remotes
RemoteEntry ..> RemoteConfig : list_remotes projects to
MuseImportData *-- NoteEvent : notes
RepoNotFoundError --|> MuseCLIError
MuseCLIError --> ExitCode : exit_code
Diagram 11 — Full Entity Dependency Overview
All named entities grouped by layer, showing the dependency flow from domain protocol down through diff algorithms, CRDTs, store, and plugins.
classDiagram
class MuseDomainPlugin {
<<Protocol>>
snapshot · diff · merge · drift · apply · schema
}
class StructuredDelta {
<<TypedDict StateDelta>>
domain · ops: list~DomainOp~ · sem_ver_bump
}
class SnapshotManifest {
<<TypedDict StateSnapshot>>
files: dict~str,str~ · domain
}
class MergeResult {
<<dataclass>>
merged · conflicts · op_log · conflict_records
}
class DomainOp {
<<type alias>>
Insert | Delete | Move | Replace | Mutate | Patch
}
class DomainSchema {
<<TypedDict>>
dimensions: list~DimensionSpec~ · top_level: ElementSchema
}
class CommitRecord {
<<dataclass>>
commit_id · structured_delta · sem_ver_bump · reviewed_by · test_runs
}
class SnapshotRecord {
<<dataclass>>
snapshot_id · manifest: dict~str,str~
}
class MergeState {
<<dataclass frozen>>
conflict_paths · base/ours/theirs commits
}
class OpEntry {
<<TypedDict>>
op_id · domain_op: DomainOp · lamport_ts
}
class GCounter {
<<CRDT>>
increment · join · value
}
class ORSet {
<<CRDT add-wins>>
add · remove · join · elements
}
class AttributeRule {
<<dataclass frozen>>
path_pattern · dimension · strategy
}
class MidiDimensions {
<<dataclass>>
slices: dict~str,DimensionSlice~
}
class SymbolRecord {
<<TypedDict>>
kind · content_id · body_hash · signature_id
}
MuseDomainPlugin ..> SnapshotManifest : StateSnapshot
MuseDomainPlugin ..> StructuredDelta : StateDelta
MuseDomainPlugin --> MergeResult : merge
MuseDomainPlugin --> DomainSchema : schema
StructuredDelta *-- DomainOp : ops
OpEntry --> DomainOp : domain_op
CommitRecord --> SnapshotRecord : snapshot_id
CommitRecord --> StructuredDelta : structured_delta
CommitRecord --> ORSet : reviewed_by uses
CommitRecord --> GCounter : test_runs uses
MergeState ..> CommitRecord : references commits
AttributeRule ..> MidiDimensions : resolve_strategy selects slices
SymbolRecord ..> DomainOp : drives code plugin ops