Episode 06 --- Build a Domain
Working YouTube title:
Building a Real Muse Domain, From Nothing
Thumbnail thought:
six methods. one file. it just works.
Target runtime: ~8:00
[0:00--0:20] COLD OPEN
[CAMERA --- Episode 05's dare, on screen: "could I write one of these?"]
GABRIEL:
Yes. Right now. From nothing.
[TITLE CARD --- fast]
BUILD A DOMAIN
[Music enters.]
[0:20--1:00] PICK SOMETHING DUMB ON PURPOSE
[CAMERA]
Not code. Not music. Something with zero interesting features of its own, so there's nowhere for the trick to hide.
[beat]
A todo list. One file, todo.txt, one task per line.
[ON SCREEN]
IF SIX METHODS CAN VERSION THIS, THEY CAN VERSION ANYTHING.
[1:00--1:40] START FROM THE SCAFFOLD
[TERMINAL]
$ cp -r muse/plugins/scaffold muse/plugins/todo
GABRIEL VO:
Muse ships a copy-paste starting point. File-level snapshot, diff,
merge, drift --- already working, already correct --- with TODO
comments marking exactly what to make domain-specific.
[beat]
Most of what's about to happen is deleting scaffolding, not writing from zero.
[1:40--2:40] THE PART THAT'S ACTUALLY NEW
[SCREEN --- real source, the diff method]
def diff(self, base, target, *, repo_root=None):
base_tasks = _load_tasks(repo_root, base)
target_tasks = _load_tasks(repo_root, target)
child_ops = []
for task in sorted(target_tasks - base_tasks):
child_ops.append(AddressedInsertOp(
op="insert", address=_task_address(task),
content_id=_task_content_id(task),
content_summary=f"added: {task}",
))
for task in sorted(base_tasks - target_tasks):
child_ops.append(AddressedDeleteOp(
op="delete", address=_task_address(task), ...
))
...
GABRIEL:
Each task gets its own address, computed from its own content. Not a line number. Not a position in the file.
[beat]
That's the one real idea in this whole plugin: tasks are an unordered, address-keyed set, not an ordered list of lines.
[2:40--3:20] SCHEMA --- THREE LINES THAT MATTER
[SCREEN --- real source]
def schema(self) -> DomainSchema:
return DomainSchema(
domain="todo",
top_level=SetSchema(kind="set", element_type="task", identity="by_content"),
dimensions=[],
merge_mode="three_way",
)
GABRIEL VO:
kind="set". identity="by_content". That's the declaration that
makes the address-keyed merge behavior fall out for free, the same way
Episode 05 showed for code's imports and variables dimensions.
[3:20--3:45] REGISTER IT
[TERMINAL]
# muse/plugins/registry.py
from muse.plugins.todo.plugin import TodoPlugin
_REGISTRY["todo"] = TodoPlugin()
GABRIEL:
One import. One dictionary entry. That's the entire integration surface between a brand-new domain and the rest of Muse.
[3:45--4:20] INIT AND FIRST COMMIT
[TERMINAL --- real, unedited output]
$ muse init --domain todo
✅ Initialized Muse repository ... domain=todo
$ echo "Write episode 06 script" > todo.txt
$ muse commit -m "Add first task"
[main sha256:22d65c...] Add first task
1 file changed (1 added)
GABRIEL VO:
No special-case code anywhere in muse commit for this domain. It
doesn't know "todo" exists. It just called six methods.
[4:20--5:15] TWO PEOPLE, TWO TASKS, ZERO COORDINATION
[TERMINAL]
$ muse checkout -b feature/alice
$ echo "Buy milk" >> todo.txt
$ muse commit -m "Alice adds a task"
$ muse checkout main
$ muse checkout -b feature/bob
$ echo "Fix the bug" >> todo.txt
$ muse commit -m "Bob adds a different task"
GABRIEL:
Alice and Bob never talked to each other. Neither knows the other's branch exists.
[SCREEN --- real diff]
$ muse diff feature/alice feature/bob
1 task(s) added, 1 task(s) removed
[5:15--5:50] MERGE --- FOR REAL, NOT A MOCKUP
[TERMINAL --- real output]
$ muse checkout main
$ muse merge feature/alice
Fast-forward feature/alice → main
$ muse merge feature/bob
Merge made by the three-way strategy.
$ cat todo.txt
Buy milk
Fix the bug
Write episode 06 script
GABRIEL VO:
Zero conflicts. Not because the merge engine special-cased todo
lists. Because two different content-addressed tasks structurally
cannot collide --- and this domain didn't have to write a single line
of merge logic to get that guarantee. It inherited it from schema().
[5:50--6:30] THE BUGS I ACTUALLY HIT
[CAMERA --- direct to camera, no slides]
GABRIEL:
I'm not going to pretend this worked on the first try. It didn't. Three times.
[beat]
First bug: I hashed raw bytes for object IDs. Muse's real object
format is blob <size>\0<content> --- Episode 03's whole point ---
and I'd forgotten it applies to my own plugin too. Second bug:
checkout silently didn't restore files, because it keys restoration
off the file-level address in the diff, not my task-level addresses.
I had to nest the task ops inside a file-level op to fix it.
[beat]
The third one didn't even show up on camera --- I only caught it
writing tests afterward. My drift() never forwarded repo_root
into diff(), so muse status on a dirty working tree would have
quietly reported zero changes. The six-method contract doesn't
protect you from this kind of mistake. Only a test that actually
calls the method the way the engine calls it does.
[CAMERA]
All three are real mistakes, made actually building this domain for this episode. Leaving all of them in on purpose.
[6:30--7:10] THE POINT
[CAMERA]
Look at what just happened.
[beat]
A domain that has never existed before, implementing six methods,
most of them copy-pasted from a template --- and commit, checkout,
diff, and merge all worked immediately. Including a genuine
three-way merge with a correctness guarantee the plugin never had to
implement itself.
[ON SCREEN]
THE ENGINE DIDN'T CHANGE. IT NEVER DOES.
[7:10--7:45] OUT
[TERMINAL --- the real structured delta from Episode 03/05's callbacks, one more time]
GABRIEL VO:
We built the domain. We haven't actually looked hard at what muse diff showed us while we were doing it --- what a diff means when the
tool understands your data instead of just seeing bytes.
[beat]
Next episode: semantic diff, properly. Not todo lists this time. Real source code, real refactors, and a diff that reads like a sentence instead of a patch file.
[CAMERA.]
[CUT TO BLACK]
musehub.ai
Production Notes
Episode 06 is the season's proof-of-work episode. Every other episode can get away with showing output. This one has to show process --- including the parts that didn't work the first time --- or the whole season's credibility is on the line the moment a technical viewer tries this themselves and hits something Episode 05 didn't warn them about.
Opening
Answer Episode 05's dare in four words, then cut immediately to the title card. No preamble, no "so today we're going to." The energy is "I already did the thing you're about to watch me do, let's go."
Leave the Bugs In
This is the one instruction in the whole season more important than
any other single note: do not edit out the three real mistakes made
while building this plugin (the object-hash format, the checkout
address-key mismatch, and the untested drift() that silently
forwarded nothing). Cutting them for a cleaner edit would turn "look,
it just works" into a lie by omission, and would rob viewers of the
most instructive moments in the episode --- the first two are direct,
concrete payoffs of Episodes 03 and 05's own claims, discovered the
hard way, on camera, exactly the way a real viewer attempting this
themselves would discover them; the third is the honest admission that
tests catch a category of mistake on-camera debugging never will.
Everything Shown Actually Ran
Every commit ID, every merge outcome, every line of todo.txt
shown in this script is real output from an actual sequence of muse
commands against a real, disposable demo repo with the real plugin
registered. Re-run the exact sequence before recording to confirm it
still holds against whatever muse build is current at record time.
Don't Undersell the Simplicity
The plugin is genuinely small --- most of it is the unmodified
scaffold. Resist the temptation to pad the episode with more domain
logic to make it feel more impressive. The thesis is that it doesn't
need to be impressive to get real version control. Let the six-line
schema() and the twenty-line diff() carry the episode on their
own.
The Seed
The viewer arrives thinking:
Okay, sure, a todo list. Cute. But does "semantic" mean anything more than "it's a set instead of a list"?
They should leave thinking:
If a todo list gets a real diff and a real merge for free... what does a diff look like on something that actually has interesting structure, like a real codebase?
That's Episode 07, and it should open mid-sentence on that exact question.