muse

Version Anything

One protocol. Any domain. Six methods between you and a complete version control system — branching, merging, conflict resolution, time-travel, and typed diffs — for free.

Build a Domain Plugin VCS Demo → 🎹 Bach BWV 846 × 21 Dimensions
midi code genomics 3d-spatial financial simulation proteomics cad game-state your-domain midi code genomics 3d-spatial financial simulation proteomics cad game-state your-domain
The Contract

The MuseDomainPlugin Protocol

Every domain — MIDI, source code, genomics, 3D spatial, financial models — implements the same six-method protocol. The core engine handles everything else: content-addressed storage, DAG, branches, log, merge base, cherry-pick, revert, stash, tags.

6methods to implement
14CLI commands, free
domains possible
0core changes needed
Method
Signature
Purpose
snapshot
snapshot(live) → StateSnapshot
Capture current state as a content-addressable blob
diff
diff(base, target) → StateDelta
Compute minimal change between two snapshots (added · removed · modified)
merge
merge(base, left, right) → MergeResult
Three-way reconcile divergent state lines; surface conflicts per dimension
drift
drift(committed, live) → DriftReport
Detect uncommitted changes between HEAD and working state
apply
apply(delta, live) → LiveState
Apply a delta during checkout to reconstruct historical state
schema
schema() → DomainSchema
Declare data structure — drives diff algorithm selection per dimension
Registry

Registered Domains

Domains currently registered in this Muse instance. The active domain is the one used when you run muse commit, muse diff, and all other commands.

● active midi

MIDI file versioning with 21-dimension structured merge — notes, CC, pitch bend, tempo, time signatures, and more. Each dimension merges independently…

Typed Deltas Domain Schema OT Merge CRDT Primitives MidiRGA
Dimensions: notes · control_change · pitch_bend · tempo · time_signature · key_signature · program_change · aftertouch · sysex · track_name
● active code

Source-code versioning with symbol-level operational-transform merge. Tree-sitter parses 11 languages into ASTs; functions, classes, and imports merge…

Typed Deltas Domain Schema OT Merge .museattributes
Dimensions: functions · classes · imports · variables · expressions
Ecosystem

The Plugin Ecosystem

MIDI and code are the two shipped domains — both fully active with typed deltas, structured merge, and .museattributes rule control. These are the domains planned next — and the slot waiting for yours.

Genomics
Version sequences, variants, and annotations
sequence · variants · annotations · metadata
coming soon
3D / Spatial
Merge spatial fields, meshes, and simulation frames
geometry · materials · physics · temporal
coming soon
Financial
Track model versions, alpha signals, and risk state
signals · positions · risk · parameters
coming soon
Scientific Simulation
Snapshot simulation state across timesteps and parameter spaces
state · parameters · observables · checkpoints
coming soon
Your Domain
Six methods. Any multidimensional state. Full VCS for free.
your_dim_1 · your_dim_2 · ...
Build it →
Engine Capabilities

What Every Plugin Gets for Free

The core engine provides four advanced capabilities that any domain plugin can opt into. Implement the protocol — the engine does the rest.

Typed Delta Algebra StructuredDelta — every change is a typed operation

Unlike Git's blob diffs, Muse deltas are typed objects: InsertOp, ReplaceOp, DeleteOp — each carrying the address, before/after hashes, and affected dimensions. Machine-readable with muse show --json.

# muse show --json  (any commit, any domain)
{
  "commit_id": "b26f3c99",
  "message": "Resolve: integrate shared-state (A+B reconciled)",
  "operations": [
    {
      "op_type": "ReplaceOp",
      "address": "shared-state.mid",
      "before_hash": "a1b2c3d4",
      "after_hash":  "e5f6g7h8",
      "dimensions":  ["structural"]
    },
    {
      "op_type": "InsertOp",
      "address": "beta-a.mid",
      "after_hash": "09ab1234",
      "dimensions":  ["rhythmic", "dynamic"]
    }
  ],
  "summary": {
    "inserted": 1,
    "replaced": 1,
    "deleted":  0
  }
}
Domain Schema Per-domain dimensions drive diff algorithm selection

Each plugin's schema() method declares its dimensions and merge mode. The engine uses this to select the right diff algorithm per dimension and to surface only the dimensions that actually conflict.

● active midi

MIDI file versioning with 21-dimension structured merge — notes, CC, pitch bend, tempo, time signatures, and more. Each dimension merges independently…

Typed Deltas Domain Schema OT Merge CRDT Primitives MidiRGA
Dimensions: notes · control_change · pitch_bend · tempo · time_signature · key_signature · program_change · aftertouch · sysex · track_name
● active code

Source-code versioning with symbol-level operational-transform merge. Tree-sitter parses 11 languages into ASTs; functions, classes, and imports merge…

Typed Deltas Domain Schema OT Merge .museattributes
Dimensions: functions · classes · imports · variables · expressions
OT Merge Operational transformation — independent ops commute automatically

Plugins implementing StructuredMergePlugin get operational transformation. Operations at different addresses commute automatically — only operations on the same address with incompatible intent surface a conflict.

Scenario A Independent ops at different addresses
left InsertOp "ot-notes-a.mid" tick=0 · C4 E4 G4
right InsertOp "ot-notes-b.mid" tick=480 · D4 F4 A4
transform → no overlap → ops commute Clean merge · both files applied
Scenario B Same address, conflicting intent — conflict surfaced
left ReplaceOp "shared-melody.mid" C4 E4 G4 · major triad
right ReplaceOp "shared-melody.mid" C4 Eb4 G4 · minor triad
transform → same address · non-commuting content Conflict · human resolves
CRDT Primitives Convergent merge — any two replicas always reach the same state

Plugins implementing CRDTPlugin get six battle-tested convergent data structures. No coordination required between replicas. The MIDI plugin extends RGA into MidiRGA — a voice-aware variant that orders concurrent note insertions by voice lane (bass → tenor → alto → soprano) before falling back to op-id, preventing voice crossings without human intervention.

ORSet Observed-Remove Set
Replica A
+ add("GO:0001234")
→ {GO:0001234}
Replica B
× remove("GO:0001234")
→ {}
join(A, B) {GO:0001234} add-wins — A’s new token survives
LWWRegister Last-Write-Wins Register
t=1.0 A "80 BPM"
t=2.0 B "120 BPM" latest ↑
join(A,B) = join(B,A) "120 BPM" commutative — higher timestamp always wins
GCounter Grow-Only Distributed Counter
A ×2
2
B ×3
3
join(A, B) global 5 component-wise max — monotonically non-decreasing
VectorClock Causal Ordering
Agent A
A:1
B:0
Agent B
A:0
B:1
=
merge
A:1
B:1
concurrent_with(A, B) = True
component-wise max — causal happens-before tracking
RGA Replicated Growable Array
Replica A
+ insert("C4", id=1@A)
+ insert("E4", id=2@A)
→ [C4, E4]
Replica B
+ insert("C4", id=1@A)
+ insert("G4", id=1@B) concurrent
→ [C4, G4]
join(A, B) [C4, E4, G4] ID-ordered — larger ID wins leftmost; all elements preserved
AWMap Add-Wins Map
Replica A
+ set("tempo", "120 BPM")
→ {tempo}
Replica B
+ set("key_sig", "C major")
→ {key_sig}
join(A, B) {key_sig, tempo} add-wins — concurrent removes cannot evict new tokens
Diff Algebra

Five Algebras. One Typed Result.

The engine selects the algorithm per dimension from your plugin’s schema(). You declare the shape — the engine handles identity, diffing, and merge selection automatically.

Sequence Myers / LCS on SHA-256 IDs
notes · nucleotides · animation frames · git objects
before
a1b2
C4
c3d4
E4
e5f6
G4
g7h8
B♭4
= match
× DeleteOp
= match
↓ MoveOp
a1b2
C4
k1l2
F4
e5f6
G4
n5o6
A4
g7h8
B♭4
+ InsertOp
+ InsertOp
↑ arrived
after
Identity is hash-based: two elements are equal iff their SHA-256 hashes match — content is never inspected by the core. Delete + insert pairs sharing the same hash are collapsed into MoveOps in a post-pass.
Tree Zhang-Shasha / GumTree
scene graphs · ASTs · track hierarchies
BEFORE session intro verse C4 E4 G4 MoveOp + InsertOp AFTER session intro verse C4 E4 G4 A4 moved inserted
Edit distance over node hierarchy — moves preserve subtree identity across parent changes.
Tensor Sparse / block numerical diff
sim state · voxel grids · weight matrices
t = 0
t = 1 (Δ)
|Δ| = 0 |Δ| ≤ ε (within threshold) |Δ| > ε → PatchOp
Configurable ε threshold. Sparse mode records only changed blocks — efficient for large tensors.
Set Set algebra · add / remove
annotations · tags · gene ontology terms
before
GO:0001234 GO:0005634 GO:0006915 GO:0016020
× del
+ ins
after
GO:0001234 GO:0005634 GO:0016020 GO:0042592
Unordered — no position tracking. Pure membership delta: {removed} and {added}.
Map Recursive key-by-key delegation
metadata · configs · nested structures
tempo 120 → 140 scalar → PatchOp
notes […] → […′] sequence → LCS
tags {…} → {…′} set → algebra
author "Bach" = "Bach" unchanged
Each key is diffed by whichever algorithm matches its declared type — recursively, to arbitrary depth.
diff() → StructuredDelta all five algorithms produce the same typed operation list
InsertOp DeleteOp MoveOp ReplaceOp PatchOp
merge_mode: “three_way”
Operational Transformation — independent ops commute automatically; conflicting ops surface for human resolution
or
merge_mode: “crdt”
CRDT join() — convergent, no coordination required; any two replicas always reach the same state
Build

Build in Three Steps

One command scaffolds the entire plugin skeleton. You fill in six methods. The full VCS follows.

Step 1 · Scaffold
Generate the skeleton
One command creates the plugin directory, class, and all six method stubs with full type annotations.
muse domains --new genomics
Step 2 · Implement
Fill in the six methods
Replace each raise NotImplementedError with your domain's snapshot, diff, merge, drift, apply, and schema logic.
vim muse/plugins/genomics/plugin.py
Step 3 · Use
Full VCS, instantly
Register in registry.py, then every Muse command works for your domain out of the box.
muse init --domain genomics
The Scaffold

What muse domains --new genomics produces

A fully typed, immediately runnable plugin skeleton. Every method has the correct signature. You replace the stubs — the protocol does the rest.

muse/plugins/genomics/plugin.py
from muse.domain import ( MuseDomainPlugin, LiveState, StateSnapshot, StateDelta, DriftReport, MergeResult, DomainSchema, ) class GenomicsPlugin(MuseDomainPlugin): """Version control for genomic sequences.""" def snapshot(self, live_state: LiveState) -> StateSnapshot: # Serialize current genome state to a content-addressable blob raise NotImplementedError def diff(self, base: StateSnapshot, target: StateSnapshot) -> StateDelta: # Compute minimal delta between two snapshots raise NotImplementedError def merge(self, base: StateSnapshot, left: StateSnapshot, right: StateSnapshot) -> MergeResult: # Three-way merge — surface conflicts per dimension raise NotImplementedError def drift(self, committed: StateSnapshot, live: LiveState) -> DriftReport: # Detect uncommitted changes in the working state raise NotImplementedError def apply(self, delta: StateDelta, live_state: LiveState) -> LiveState: # Reconstruct historical state from a delta raise NotImplementedError def schema(self) -> DomainSchema: # Declare dimensions — drives diff algorithm selection raise NotImplementedError

Full walkthrough → docs/guide/plugin-authoring-guide.md · CRDT extension → docs/guide/crdt-reference.md

Distribution

How to Share Your Plugin

Three tiers of distribution — from local prototype to globally searchable registry. Start local, publish when ready.

Local
Local plugin (right now)

Works today. Scaffold → implement → register. Your plugin lives alongside the core.

  1. muse domains --new <name>
  2. Implement 6 methods in muse/plugins/<name>/plugin.py
  3. Register in muse/plugins/registry.py
  4. muse init --domain <name>
Shareable
pip-installable package (right now)

Share your plugin as a standard Python package. Anyone with pip can install and use it.

  1. Package your plugin as a Python module
  2. pip install git+https://github.com/you/muse-plugin-genomics
  3. Register the entry-point in pyproject.toml
  4. muse init --domain genomics
MuseHub
Centralized registry (coming — MuseHub)

MuseHub is a planned centralized registry — npm for Muse plugins. Versioned, searchable, one-command install.

  1. musehub publish muse-plugin-genomics
  2. musehub search genomics
  3. muse init --domain @musehub/genomics
  4. Browse plugins at musehub.io

MuseHub is coming

A centralized, searchable registry for Muse domain plugins — think npm or crates.io, but for any multidimensional versioned state. One command to publish. One command to install.

Searchable
Find plugins by domain, capability, or keyword
Versioned
Semantic versioning, pinned installs, changelogs
Private registries
Self-host for enterprise or research teams
One command
muse init --domain @musehub/genomics
MuseHub — planned · building in public at github.com/cgcardona/musehub