Episode 02 --- Inside a Muse Repository
Working YouTube title:
What's Actually Inside .muse/?
Thumbnail thought:
no magic. just files.
Target runtime: ~7:30
[0:00--0:20] COLD OPEN
[CAMERA --- exact terminal Episode 01 ended on. hello-muse, main
branch, five commits deep.]
GABRIEL:
Last episode I ran the whole workflow and never once told you what
.muse actually is.
[beat]
Let's fix that.
[TITLE CARD --- fast]
INSIDE A MUSE REPOSITORY
[Music enters.]
[0:20--1:10] THE SHAPE OF THE DIRECTORY
[TERMINAL]
$ ls .muse
[ENTER.]
HEAD cache config.toml logs objects refs remotes repo.json shelf tags
GABRIEL VO:
Ten entries. That's it. That's the entire engine underneath everything we ran last episode.
[CAMERA --- point at each name as it's said]
HEAD and refs are pointers.
objects is where content actually lives.
repo.json and config.toml are identity and configuration.
cache, logs, shelf, tags, remotes are exactly what they
sound like --- nothing sinister in any of them.
[beat]
No proprietary binary format. No database you need a special tool to
open. Every one of these is something cat can read.
[1:10--1:55] HEAD AND REFS
[TERMINAL]
$ cat .muse/HEAD
ref: refs/heads/main
$ cat .muse/refs/heads/main
sha256:d51cb8...
GABRIEL:
HEAD doesn't point at a commit. It points at a name.
That name --- main --- points at a commit.
[SCREEN --- simple arrow diagram: HEAD → refs/heads/main → commit]
That indirection is the entire mechanism behind checkout and
branch. Moving to a different branch is just repointing one text
file at a different ref.
[beat]
Committing on that branch is just overwriting one line in another text file with a new hash.
That's it. That's branching.
[1:55--2:35] REPO IDENTITY AND CONFIG
[TERMINAL]
$ cat .muse/repo.json
{
"repo_id": "sha256:2a7766...",
"domain": "code",
"schema_version": 1,
"muse_version": "0.2.1rc4"
}
$ cat .muse/config.toml
[user]
type = "human"
[hub]
url = "https://localhost:1337"
[remotes.local]
url = "https://localhost:1337/gabriel/hello-muse"
GABRIEL VO:
repo.json answers one question: what kind of repository is this.
We picked code when we ran muse init. That single field is why
hello.py got treated as source, not as an opaque blob --- and it's
why a MIDI file would have been treated completely differently.
[CAMERA]
We'll spend an entire episode on domains later. For now, just notice: the domain isn't inferred, and it isn't hardcoded into the engine. It's one string, sitting in a JSON file, that you can read right now.
[2:35--3:20] INSIDE OBJECTS/
[TERMINAL]
$ find .muse/objects -type f | wc -l
13
$ find .muse/objects/sha256 -maxdepth 1
.muse/objects/sha256/09
.muse/objects/sha256/25
.muse/objects/sha256/47
.muse/objects/sha256/55
.muse/objects/sha256/72
.muse/objects/sha256/80
...
GABRIEL:
Thirteen objects for five commits. More objects than commits, because commits, snapshots, and file contents are all stored as separate objects.
[beat]
And notice the folder names. Two hex characters, then a subfolder with the rest of the hash.
[SCREEN --- full path highlighted]
.muse/objects/sha256/e7/967762d936553ad4f8264b72d1b0d7390ee8276a0cec0a6e3dd3d4ad33d20c
That's not decoration. That is the object's address. The filename is the SHA-256 hash of the thing inside it.
[CAMERA]
Why that matters --- really matters, not just "feels tidy" --- is next episode. Today we're just confirming it's real, and it's just files on disk.
[3:20--4:05] READ A COMMIT
[TERMINAL]
$ muse read-commit sha256:d51cb8... --json
[SCREEN --- JSON, key fields highlighted as spoken]
{
"commit_id": "sha256:d51cb8...",
"message": "Merge branch 'feature/farewell' into main",
"snapshot_id": "sha256:25ed18...",
"parent_commit_id": "sha256:e5e7da...",
"parent2_commit_id": "sha256:09218e...",
"author": "gabriel",
"agent_id": "",
"model_id": "",
"signature": ""
}
GABRIEL VO:
A commit is not the content. A commit is a record --- a message, an author, a pointer to exactly one snapshot, and pointers to its parents.
[beat]
Look at parent2_commit_id. Most commits only have one parent. This
one has two --- because this is our merge commit. Both branches'
history, right there as two plain hash strings.
[CAMERA --- slow down here]
And look at these three fields. agent_id. model_id. signature.
All empty. Because I typed this commit myself, by hand, with no signing key configured.
[beat]
They're not empty because the feature doesn't exist. They're empty because nobody asked for it yet. That's an entire episode, coming up.
[4:05--4:45] READ A SNAPSHOT
[TERMINAL]
$ muse read-snapshot sha256:25ed18... --json
{
"snapshot_id": "sha256:25ed18...",
"file_count": 1,
"manifest": {
"hello.py": "sha256:e79677..."
}
}
GABRIEL:
If the commit is the record, the snapshot is the state.
[beat]
One file in our case, but the shape doesn't change at ten files or ten thousand. A snapshot is just a map: path, to the hash of that path's content.
Nothing here knows or cares that hello.py is Python. That
distinction lives one layer up, in the domain. Down here, it's just a
name and an address.
[4:45--5:20] READ THE ACTUAL BYTES
[TERMINAL]
$ muse cat-object sha256:e79677...
def greet(name):
return f"Hey there, {name}!"
if __name__ == "__main__":
print(greet("world"))
def farewell(name):
return f"See you, {name}!"
GABRIEL VO:
That's it. That's the object. Not a wrapper, not a container format --- the literal file, exactly as it existed at that commit, both merged changes present.
[CAMERA]
Commit, to snapshot, to object, to bytes. Every arrow in that chain is just a hash lookup.
[5:20--5:55] VERIFY
[TERMINAL]
$ muse verify --json
{
"refs_checked": 3,
"commits_checked": 5,
"snapshots_checked": 5,
"objects_checked": 13,
"all_ok": true,
"failures": []
}
GABRIEL:
Every ref, every commit, every snapshot, every object --- rehashed and checked against its own filename.
[beat]
If one byte of hello.py had flipped on disk since we committed it,
this would fail, loudly, and tell us exactly which object.
[CAMERA]
That's not a feature bolted on top. That's a direct consequence of everything being named after its own content.
[5:55--6:30] THE POINT
[CAMERA]
There is no black box in here.
[beat]
Ten folders and files. A pointer chain you can trace by hand. Records
you can print with cat. Content you can read directly off disk.
[ON SCREEN]
IT'S JUST FILES. THAT'S THE WHOLE TRICK.
Everything from Episode 01 --- every branch, every merge, every push --- was built entirely out of the ten things you just looked at.
[6:30--7:10] OUT
[TERMINAL --- back at the objects/ listing from earlier]
GABRIEL VO:
We kept saying the folder name is the hash, and moving on.
[beat]
Next episode, we stop moving on. Why SHA-256, specifically. What a snapshot really buys you that a plain file tree doesn't. And why a commit DAG --- not a list, not a tree, a DAG --- is the shape that makes merging even possible.
[CAMERA.]
Same repository. One layer deeper.
[CUT TO BLACK]
musehub.ai
Production Notes
Episode 02 should feel like opening the hood on a car you already drove. The viewer trusted the machine enough to use it in Episode 01; this episode is the reward for that trust, not a prerequisite for it. Nothing here should feel like homework.
Opening
No recap of what a commit or a branch is conceptually --- Episode 01
already demonstrated that behaviorally. Open directly on the same
terminal, same repo, and go straight to ls .muse. The cold open
is the first shot of the episode's actual content.
Everything Shown Must Be cat-able
This is the episode's one hard rule: every artifact shown on screen
must be something the viewer could open themselves with cat, ls,
or a muse read-* command, on the exact repository Episode 01 built.
No diagrams standing in for real output. If a concept can't be shown
as real bytes on real disk, it belongs in a later episode, not this
one.
Plant Three Seeds, Pay Off None of Them
This episode should visibly gesture at three things it deliberately does not explain yet:
- The empty
agent_id/model_id/signaturefields --- Episode 04. - The domain field in
repo.jsondetermining how content is interpreted --- Episode 05 and 06. - The fanout folder name literally being a hash --- Episode 03, immediately next.
Naming the tease explicitly on screen (as dialogue, not just a visual) is deliberate. It tells the viewer these aren't loose threads being forgotten, they're a released trailer for what's coming.
Production Style
Slower and calmer than Episode 01. Episode 01's energy was a stopwatch; this episode's energy is a flashlight. Let shots of raw JSON and file contents sit on screen a beat longer than feels necessary in the edit --- the viewer needs time to actually read what's there, not just be told it exists.
The Seed
The viewer arrives thinking:
.museis probably some database or binary format I'll never actually understand.
They should leave thinking:
Wait --- that's a hash of a hash of a hash. Why SHA-256 specifically, and why does chaining it like that actually matter?
That's Episode 03, and the final shot should point straight at the
objects/ fanout folder that started the question.