agents-are-first-class-citizens.md markdown
327 lines 10.2 KB
Raw
sha256:5472be4fece32b606c308fad9d57295ce327955fb2b87b8beec6ea1626050473 Add published YouTube URL to Episode 00 Sonnet 5 6 hours ago

Episode 13 --- Agents Are First-Class Citizens

Working YouTube title:
1,093 Commits. Zero Of Them Typed By A Human.

Thumbnail thought:
two keys. one pipe. no password.

Target runtime: ~8:00


[0:00--0:20] COLD OPEN

[CAMERA --- Episode 12's closing line, on screen: "the author of half these commits was never a person sitting at a keyboard."]

GABRIEL:

Not half. Let's check the actual number.

[TITLE CARD --- fast]

AGENTS ARE FIRST-CLASS CITIZENS

[Music enters.]


[0:20--1:10] THE ACTUAL NUMBER

[TERMINAL --- run against ~/ecosystem/muse itself]

$ muse shortlog --group-by model --json | jq -r '.groups[] | "\(.key) \(.count)"'
(no model)          242
claude-opus-4-7      1
claude-sonnet-4-6   1052
claude-sonnet-5      40

GABRIEL VO:

Not a demo number. This is the real commit history of the tool you've been watching all season. 1,093 commits carry a real model identifier. 242 don't. The tool that builds Muse has been built, by commit count, mostly by something that isn't a person.

[beat]

That's a strange sentence to say out loud. Let's find out what it actually means, mechanically.


[1:10--2:00] TWO LAYERS OF "WHO DID THIS"

[TERMINAL]

$ muse read HEAD~50 --json | jq '{author, agent_id, model_id, signer_public_key}'
{
  "author": "gabriel",
  "agent_id": "claude-code",
  "model_id": "claude-sonnet-5",
  "signer_public_key": "ed25519:..."
}

GABRIEL:

Four fields, two different kinds of truth. author, agent_id, model_id --- free text. Descriptive. Nobody enforces them. signer_public_key --- a real Ed25519 key, cryptographically tied to an actual signature over the actual commit bytes. That one's not a label. Let's prove it, and let's also prove the label side is exactly as unenforced as I just said.


[2:00--2:40] THE LABELS LIE SOMETIMES, HONESTLY

[TERMINAL]

$ muse shortlog --group-by agent --json | jq -r '.groups[] | "\(.key) \(.count)"'
(no agent)          244
claude-code         1078
claude-sonnet-4-6     13

GABRIEL VO:

See that third line? Thirteen commits where --agent-id got typed as a model name by mistake, months ago, in this exact codebase. Muse didn't catch it, because agent_id is descriptive metadata --- it trusts whoever calls muse commit. That's a real, honest gap, and it's the perfect setup for what's actually enforced.


[2:40--4:20] THE PART THAT ISN'T A LABEL

[CAMERA]

Here's the mechanism that can't typo its way into being wrong.

$ python3 -c "
from muse.core.hdkeys import derive_agent_sub_seed, DOMAIN_IDENTITY
import os
operator_seed = os.urandom(64)   # stand-in for a real BIP39 seed
agent_sub_seed = derive_agent_sub_seed(operator_seed, domain=DOMAIN_IDENTITY, agent_id=0)
print(len(agent_sub_seed), 'bytes, SLIP-0010 hardened')
"
64 bytes, SLIP-0010 hardened

GABRIEL VO:

An operator's real seed never leaves their machine. What gets handed to an agent process is a sub-seed --- scoped to one domain, one agent slot. SLIP-0010's hardened derivation makes this mathematically one-directional: the sub-seed can derive its own keys forward, but it cannot derive the operator's key backward. Not "shouldn't." Cannot.

[beat --- TERMINAL, injecting it]

$ python3 -c "
import os, sys
read_fd, write_fd = os.pipe()
pid = os.fork()
if pid == 0:
    os.close(write_fd)
    env = dict(os.environ, MUSE_AGENT_KEY_FD=str(read_fd), MUSE_AGENT_HANDLE='agent-slot-0')
    os.execvpe('muse', ['muse','commit','-m','Agent-signed commit via pipe fd',
                         '--agent-id','claude-code','--model-id','claude-sonnet-5',
                         '--sign','--json'], env)
else:
    os.close(read_fd); os.write(write_fd, agent_sub_seed); os.close(write_fd)
    os.waitpid(pid, 0)
"
{ "signer_public_key": "ed25519:ZmAXQOIl-c5gUycEMBinNEZQMi7ptdE0eJbJxs_gaUM" }

GABRIEL:

Not an environment variable --- a pipe. MUSE_AGENT_KEY_FD is a file descriptor number; the actual 64 bytes travel through the kernel's pipe buffer, never through argv, never through /proc/<pid>/environ, never through anything a sibling process could read.


[4:20--5:10] PROVING IT'S A DIFFERENT KEY, NOT A DIFFERENT STRING

[TERMINAL]

$ muse verify-commit HEAD --json
{ "valid": true, "signer": "claude-code", "key_status": "unknown" }

GABRIEL VO:

valid: true --- the signature really does verify against that public key, over these exact commit bytes. And that public key is provably not the operator's: derived from a sub-seed the operator's own identity key derivation never touches. Two different Ed25519 keys, two different holders, one of them mathematically forbidden from ever learning the other.

[beat]

key_status: unknown --- because this demo key was never registered with a hub. That's expected, and it's an important distinction on its own: verification of the signature and verification of the key's registration status are two separate checks. A perfectly valid signature from an unregistered key still says "valid," it just can't yet tell you whose key it provably is beyond what you already know.


[5:10--6:10] THE HONEST GAP UNDERNEATH THIS

[CAMERA]

While building this, I found a real inconsistency, not a security hole. derive_identity_key's own docstring shows the documented way to derive an agent's key: pass entity_type=ENTITY_AGENT. The actual code that handles MUSE_AGENT_KEY_FD --- the function I just ran --- never passes that. It uses the default, ENTITY_HUMAN.

[beat]

Does that break the isolation guarantee I just demonstrated? No --- the sub-seed was already scoped before it got here; whichever branch it takes next, the operator still can't reach it and the agent still can't reach the operator's key. What it means is: the one real caller and the one documented example don't agree with each other. Filed as staging#205. Low severity, real drift, worth closing either direction.


[6:10--7:00] WHY THIS MATTERS MORE THAN A NICE-TO-HAVE

[CAMERA]

Go back to the number that opened this episode. 1,093 real commits, each one carrying a model_id string that could be wrong --- we just found thirteen that were. If that string were the only thing establishing who wrote what, the entire provenance story of this season would rest on nothing stronger than a --flag nobody double-checks.

[beat]

It isn't the only thing. Underneath every one of those commits sits a key an agent process held and a human never did. The label can be sloppy. The signature can't be forged into being sloppy along with it.


[7:00--7:40] OUT

[TERMINAL --- fading to black]

GABRIEL VO:

One agent, one commit, one key. Real coordination needs more than that --- dozens of agents, the same repository, at the same time, without stepping on each other.

[beat]

That's next.

[CUT TO BLACK]

musehub.ai


Production Notes

Episode 13 opens the season's third movement (Agents and the network) with a number, not a claim --- the 1,093-vs-242 split is real data from the actual ~/ecosystem/muse repository this season has been building in front of the camera the whole time. Don't round it, don't paraphrase it as "most" without also showing the exact shortlog output; the specificity is the point.

The Labels-vs-Keys Structure Is The Whole Episode

Everything else hangs off one distinction: agent_id/model_id are trusted strings, signer_public_key is enforced cryptography. The 13-commit typo (real, found live, in this exact codebase) exists to make the audience feel the weakness of the label side before the key side arrives to fix it. Don't cut the typo beat for pacing --- it's what makes the pipe-fd demonstration land as necessary rather than decorative.

The Pipe, Not The Env Var, Is The Detail Worth Lingering On

Agents in this season's world are not trusted with an operator's real seed, ever. The demo deliberately uses os.pipe() plus os.fork() / execvpe() rather than just setting an environment variable, because that mechanical choice is the actual security property: MUSE_AGENT_KEY_FD carries a file descriptor number, not a secret; the secret itself never touches argv, environment, or anything visible via /proc.

The Ticket Discipline Continues, At A Different Scale

staging#205 is explicitly the season's first low-severity finding --- say so on camera. Naming severity honestly (staging#90/93/203/204 were all higher-stakes; this one genuinely isn't) is what keeps the audience trusting the higher-stakes calls later. Don't inflate this one for drama.

Everything Here Is Real

The operator seed is os.urandom(64) --- explicitly not a real BIP39 mnemonic, said out loud in-script. Every derivation, the pipe injection, the resulting signature, and verify-commit's response were run against the actual current build and reproduced before this script was written. Re-run make-identity-episode13-demo.sh at record time; if staging#205 has been fixed, the entity_type beat should note the fix rather than silently drop it.

The Seed

The viewer arrives thinking:

Sure, commits have an "agent" field. Cute metadata.

They should leave thinking:

That field is decoration. The actual thing establishing "an agent wrote this, and specifically this one, not the operator" is a key nobody but that agent process ever held. What happens when there isn't just one agent anymore, but a dozen, all reaching for the same repository at once?

That's Episode 14.

File History 1 commit
sha256:5472be4fece32b606c308fad9d57295ce327955fb2b87b8beec6ea1626050473 Add published YouTube URL to Episode 00 Sonnet 5 6 hours ago