gabriel / muse public
porcelain.md markdown
1,442 lines 35.7 KB
Raw

Muse Porcelain Commands

Layer guide: Muse commands are organised into three tiers. This document covers Tier 2 — Core Porcelain: the high-level, human-friendly commands that build on the Tier 1 plumbing layer. Tier 3 commands (MIDI, Bitcoin, Code) live in their own reference docs.

All porcelain commands accept --format json where documented below. JSON is printed to stdout; human text goes to stdout too; error messages always go to stderr. Exit codes follow the same convention as the plumbing layer: 0 success · 1 user error · 3 internal error.


Quick Index

Command Description
init Initialise a new Muse repository
commit Record the working tree as a new version
status Show working-tree drift against HEAD
log Display commit history
diff Compare working tree or two commits
show Inspect a commit — metadata, diff, files
branch List, create, or delete branches
checkout Switch branches or restore a snapshot
merge Three-way merge a branch into the current branch
rebase Replay commits onto a new base
reset Move HEAD to a prior commit
revert Undo a commit by creating a new one
cherry-pick Apply a single commit's changes
shelf Shelve and restore uncommitted changes
tag Attach and query semantic tags on commits
blame Line-level attribution for any text file
reflog History of HEAD and branch-ref movements
gc Garbage-collect unreachable objects
archive Export a snapshot as tar.gz or zip
bisect Binary-search through history for a regression
worktree Multiple simultaneous branch checkouts
clean Remove untracked files from the working tree
describe Label a commit by its nearest tag
shortlog Commit summary grouped by author or agent
verify Whole-repository integrity check
snapshot Explicit snapshot management
bundle Pack and unpack commits for offline transfer
content-grep Full-text search across tracked file content
whoami Show the current identity
config Read and write repository configuration

Established Core Porcelain

init — initialise a repository

Create a fresh .muse/ directory in the current folder.

muse init                  # initialise in current dir
muse init --domain midi    # set the active domain
muse init -d code          # short flag

Flags

Flag Short Default Description
--domain -d midi Domain plugin to activate for this repo

Exit codes: 0 success · 1 already initialised


commit — record the working tree

Snapshot the working tree and write a commit pointing to it.

muse commit -m "verse melody"
muse commit --message "Add chorus" --author "gabriel"
muse commit --allow-empty
muse commit --format json

Flags

Flag Short Default Description
--message -m "" Commit message
--author -a config value Override the author name
--allow-empty -e off Commit even when nothing changed
--format -f text text or json

JSON output

{
  "commit_id":    "a3f2...c8d1",
  "branch":       "main",
  "message":      "Add verse melody",
  "author":       "gabriel",
  "committed_at": "2026-03-21T12:00:00+00:00",
  "snapshot_id":  "b7e4...f912",
  "sem_ver_bump": "minor"
}

sem_ver_bump is "none", "patch", "minor", or "major" depending on the domain plugin's assessment of the change.

Exit codes: 0 committed · 1 nothing to commit (and --allow-empty not given)


status — show drift against HEAD

muse status
muse status --short
muse status --json          # machine-readable
muse status -s -j

Flags

Flag Short Default Description
--short -s off Compact one-line-per-file output
--json -j off JSON output (equivalent to --format json)

Text output:

On branch main

Modified:
  tracks/bass.mid
Added:
  tracks/lead.mid

clean when working tree matches HEAD.

JSON output

{
  "branch":   "main",
  "clean":    false,
  "modified": ["tracks/bass.mid"],
  "added":    ["tracks/lead.mid"],
  "deleted":  []
}

Exit codes: 0 always (non-zero drift is shown, not signalled)


log — display commit history

muse log
muse log --limit 20
muse log --branch feat/audio
muse log --format json

Flags

Flag Short Default Description
--branch -b current Branch to walk
--limit -n 50 Max commits to emit
--format -f text text or json

JSON output — envelope with truncated flag and commits array, newest first:

{
  "truncated": false,
  "commits": [
    {
      "commit_id":          "sha256:a3f2...c8d1",
      "branch":             "main",
      "message":            "Add verse melody",
      "author":             "gabriel",
      "agent_id":           "claude-code",
      "model_id":           "claude-sonnet-4-6",
      "committed_at":       "2026-03-21T12:00:00+00:00",
      "parent_commit_id":   "sha256:ff01...23ab",
      "parent2_commit_id":  null,
      "snapshot_id":        "sha256:b7e4...f912",
      "sem_ver_bump":       "minor",
      "breaking_changes":   [],
      "metadata":           {},
      "files_added":        ["tracks/drums.mid"],
      "files_removed":      [],
      "files_modified":     [],
      "structured_delta":   {"ops": [...]}
    }
  ]
}

All keys are always present — no dict.get guards needed. structured_delta is a dict with an "ops" key for code commits, null otherwise.

Exit codes: 0 always


diff — compare working tree or two commits

muse diff                       # working tree vs HEAD
muse diff --from HEAD~3
muse diff --from v1.0 --to v2.0
muse diff --format json

Flags

Flag Short Default Description
--from -f HEAD Ref or commit to diff from
--to -t working tree Ref or commit to diff to
--format text text or json

JSON output

{
  "from":          "ff01...23ab",
  "to":            "a3f2...c8d1",
  "added":         ["tracks/lead.mid"],
  "removed":       ["tracks/old.mid"],
  "modified":      ["tracks/bass.mid"],
  "total_changes": 3
}

Note: The JSON field is "total_changes" (not "ops" or "changes").

Exit codes: 0 always


show — inspect a commit

muse read HEAD
muse read abc123
muse read --format json
muse read --stat HEAD        # files changed, not full diff

Flags

Flag Short Default Description
--ref -r HEAD Commit or branch to inspect
--stat -s off Show file-level summary instead of raw diff
--format -f text text or json

JSON output — full diff mode

{
  "commit_id":        "a3f2...c8d1",
  "branch":           "main",
  "message":          "Add verse melody",
  "author":           "gabriel",
  "committed_at":     "2026-03-21T12:00:00+00:00",
  "snapshot_id":      "b7e4...f912",
  "parent_commit_id": "ff01...23ab",
  "delta": {
    "added":    ["tracks/lead.mid"],
    "removed":  [],
    "modified": ["tracks/bass.mid"]
  }
}

JSON output — --stat mode

{
  "commit_id":      "a3f2...c8d1",
  "branch":         "main",
  "message":        "Add verse melody",
  "author":         "gabriel",
  "committed_at":   "2026-03-21T12:00:00+00:00",
  "snapshot_id":    "b7e4...f912",
  "parent_commit_id": "ff01...23ab",
  "files_added":    1,
  "files_removed":  0,
  "files_modified": 1
}

Exit codes: 0 found · 1 commit not found


branch — list, create, or delete branches

muse branch                      # list all
muse branch feat/reverb          # create
muse branch --delete feat/reverb
muse branch -d feat/reverb       # short flag
muse branch --format json        # structured list

Flags

Flag Short Default Description
--delete -d off Delete a branch
--format -f text text or json

JSON output — list

{
  "current": "main",
  "branches": [
    {"name": "dev",  "commit_id": "ff01...23ab", "is_current": false},
    {"name": "main", "commit_id": "a3f2...c8d1", "is_current": true}
  ]
}

JSON output — create / delete

{"action": "created", "branch": "feat/reverb"}
{"action": "deleted", "branch": "feat/reverb"}

Exit codes: 0 success · 1 branch already exists (create) or not found (delete)


checkout — switch branches or restore snapshot

muse checkout main
muse checkout feat/guitar
muse checkout --create feat/new-idea    # create and switch
muse checkout -c feat/new-idea          # short flag
muse checkout --format json             # machine-readable result

Flags

Flag Short Default Description
--create -c off Create branch then switch
--format -f text text or json

JSON output

{
  "action":    "switched",
  "branch":    "feat/guitar",
  "commit_id": "a3f2...c8d1"
}

"action" is one of "switched", "created", or "already_on" (when you check out the branch that is already active).

Exit codes: 0 success · 1 branch not found (and --create not given)


merge — three-way merge

muse merge feat/audio
muse merge --message "Merge audio feature"
muse merge --abort
muse merge --continue
muse merge --format json

Flags

Flag Short Default Description
--message -m auto Override merge commit message
--abort -a off Abort an in-progress merge
--continue -c off Resume after resolving conflicts
--format -f text text or json

JSON output — clean merge

{
  "action":    "merged",
  "branch":    "feat/audio",
  "commit_id": "a3f2...c8d1",
  "message":   "Merge feat/audio into main"
}

JSON output — conflict

{
  "action":    "conflict",
  "branch":    "feat/audio",
  "conflicts": ["tracks/bass.mid"]
}

Conflict flow:

  1. muse merge <branch> → conflict reported, writes MERGE_STATE.json
  2. Resolve files manually
  3. muse merge --continue → commit the merge
  4. Or muse merge --abort → restore original HEAD

Exit codes: 0 merged · 1 conflict or bad arguments


rebase — replay commits onto a new base

Muse rebase replays a sequence of commits onto a new base using the same three-way merge engine as muse merge. Because commits are content-addressed, each replayed commit gets a new ID — the originals are untouched in the store.

muse rebase main                          # replay current branch onto main
muse rebase --onto newbase upstream       # replay onto a specific base
muse rebase --squash main                 # collapse all commits into one
muse rebase --squash -m "feat: all in"   # squash with custom message
muse rebase --abort                       # restore original HEAD
muse rebase --continue                    # resume after conflict resolution
muse rebase --format json

Flags

Flag Short Description
--onto <ref> -o New base commit
--squash -s Collapse all commits into one
--message <msg> -m Message for squash commit
--abort -a Abort and restore original HEAD
--continue -c Resume after resolving a conflict
--format <fmt> -f text or json

JSON output — squash rebase

{
  "action":          "squash_rebase",
  "onto":            "main",
  "new_commit_id":   "a3f2...c8d1",
  "commits_squashed": 4,
  "branch":          "feat/audio"
}

JSON output — normal rebase

{
  "action":           "rebase",
  "onto":             "main",
  "branch":           "feat/audio",
  "commits_replayed": 4,
  "new_tip":          "a3f2...c8d1"
}

Conflict flow:

  1. muse rebase main → conflict reported, writes REBASE_STATE.json and MERGE_STATE.json
  2. Resolve files manually
  3. muse rebase --continue → commit the resolved state and continue
  4. Or muse rebase --abort → restore the original branch pointer

State file: .muse/REBASE_STATE.json — tracks remaining/completed commits and the onto base. Cleared automatically on successful completion or --abort.

Exit codes: 0 clean · 1 conflict or bad arguments


reset — move HEAD to a prior commit

muse reset HEAD~1          # move back one commit
muse reset abc123          # move to specific commit
muse reset --hard          # also reset working tree
muse reset --format json

Flags

Flag Short Default Description
--hard -H off Also update the working tree to match
--format -f text text or json

JSON output

{
  "action":         "reset",
  "branch":         "main",
  "previous_commit": "a3f2...c8d1",
  "new_commit":     "ff01...23ab",
  "hard":           false
}

Exit codes: 0 success · 1 commit not found


revert — undo a commit by creating a new one

Non-destructive: the original commit remains in history. A new commit is created whose effect is the inverse of the target commit.

muse revert HEAD
muse revert abc123
muse revert --message "Undo broken change"
muse revert --format json

Flags

Flag Short Default Description
--message -m auto Override revert commit message
--format -f text text or json

JSON output

{
  "action":          "reverted",
  "reverted_commit": "a3f2...c8d1",
  "new_commit_id":   "b7e4...f912",
  "branch":          "main",
  "message":         "Revert \"Add verse melody\""
}

Exit codes: 0 success · 1 commit not found or nothing to revert


cherry-pick — apply a single commit's changes

muse cherry-pick abc123
muse cherry-pick abc123 --message "Cherry: verse fix"
muse cherry-pick abc123 --format json

Flags

Flag Short Default Description
--message -m auto Override the cherry-picked commit message
--format -f text text or json

JSON output

{
  "action":          "cherry_picked",
  "source_commit":   "abc1...2345",
  "new_commit_id":   "a3f2...c8d1",
  "branch":          "main",
  "message":         "Cherry: verse fix"
}

Exit codes: 0 success · 1 commit not found or conflict


shelf — shelve and restore changes

muse shelf save -m "WIP: bridge section"
muse shelf list
muse shelf list --format json
muse shelf pop
muse shelf drop 0

Subcommands

Subcommand Description
push Shelf current working-tree changes
list List saved shelf entries
pop Restore the most recent shelf entry and drop it
apply <n> Restore shelf entry N without dropping it
drop <n> Delete shelf entry N
show <n> Show what a shelf entry contains

Flags — push

Flag Short Description
--message -m Label for the shelf entry

Flags — list / show

Flag Short Description
--format -f text or json

JSON output — list

[
  {
    "index":      0,
    "message":    "WIP: bridge section",
    "created_at": "2026-03-21T12:00:00+00:00",
    "branch":     "feat/audio"
  }
]

Exit codes: 0 success · 1 shelf index out of range or nothing to shelve


tag — semantic tags on commits

muse tag v1.0.0
muse tag v1.0.0 --commit abc123
muse tag list
muse tag list --format json
muse tag delete v0.9.0
muse tag show v1.0.0 --format json

Subcommands

Subcommand Description
<name> Create a tag on HEAD (or --commit)
list List all tags
show <name> Inspect a tag
delete <name> Delete a tag

Flags — create

Flag Short Description
--commit -c Attach tag to a specific commit ID
--message -m Optional annotation
--format -f text or json

JSON output — create

{"action": "created", "name": "v1.0.0", "commit_id": "a3f2...c8d1"}

JSON output — list

[
  {"name": "v1.0.0", "commit_id": "a3f2...c8d1", "created_at": "2026-03-21T12:00:00+00:00"}
]

Exit codes: 0 success · 1 tag or commit not found


blame — line-level attribution

muse blame song.mid
muse blame --format json song.mid

Flags

Flag Short Default Description
--format -f text text or json
--ref -r HEAD Branch or commit to blame against

JSON output

[
  {
    "line":       1,
    "content":    "tempo: 120",
    "commit_id":  "a3f2...c8d1",
    "author":     "gabriel",
    "committed_at": "2026-03-21T12:00:00+00:00",
    "message":    "Add verse melody"
  }
]

Exit codes: 0 success · 1 file or ref not found


reflog — HEAD and branch movement history

muse reflog
muse reflog --branch feat/audio
muse reflog --limit 50
muse reflog --format json

Flags

Flag Short Default Description
--branch -b HEAD Branch to show reflog for
--limit -n 50 Max entries to show
--format -f text text or json

The reflog is the "undo safety net" — every ref movement is recorded so you can recover from accidental resets, force-pushes, or botched rebases.

JSON output

[
  {
    "index":      0,
    "commit_id":  "a3f2...c8d1",
    "action":     "commit",
    "message":    "Add verse melody",
    "author":     "gabriel",
    "moved_at":   "2026-03-21T12:00:00+00:00"
  }
]

"index" is 0-based, with 0 being the most recent entry. "action" describes what caused the ref movement: "commit", "merge", "rebase", "reset", "checkout", etc.

Exit codes: 0 always


gc — garbage collect

Removes objects that are not reachable from any branch or tag ref. Orphaned commits (e.g. after a reset), dangling snapshots, and unreferenced blobs are all eligible.

muse gc                    # remove unreachable objects
muse gc --dry-run          # preview what would be removed
muse gc -n                 # short flag for --dry-run
muse gc --format json

Flags

Flag Short Default Description
--dry-run -n off Preview without deleting
--format -f text text or json

JSON output

{
  "commits_removed":   2,
  "snapshots_removed": 2,
  "objects_removed":   11,
  "bytes_freed":       204800,
  "dry_run":           false
}

Exit codes: 0 always


archive — export a snapshot

muse archive HEAD
muse archive HEAD --format zip --output release.zip
muse archive v1.0.0 --prefix project/

Flags

Flag Short Default Description
--format -f tar.gz Archive format: tar.gz or zip
--output -o <commit>.tar.gz Output file path
--prefix -p "" Directory prefix inside the archive

All archive entries use the prefix/ directory. Tar-slip / zip-slip are prevented: entry paths are validated to stay within the prefix.

Exit codes: 0 archive written · 1 ref not found · 3 I/O error


bisect — binary-search for a regression

Muse bisect works on any domain — not just code. Use it to find which commit introduced a melody change, a tuning drift, or a data regression.

muse bisect start
muse bisect bad HEAD         # mark HEAD as bad (broken)
muse bisect good v1.0.0     # mark v1.0.0 as good (working)
muse bisect bad              # mark the currently-tested commit as bad
muse bisect good             # mark the currently-tested commit as good
muse bisect skip             # skip an untestable commit
muse bisect log              # show the current session log
muse bisect reset            # end the session and restore HEAD
muse bisect run pytest       # automated bisect: run command, 0=good, 1=bad

Subcommands

Subcommand Description
start Begin a new bisect session
bad [<ref>] Mark a commit as bad; omit to mark current
good [<ref>] Mark a commit as good; omit to mark current
skip [<ref>] Skip a commit that cannot be tested
log Print the current session state
reset End the session; restore the original branch
run <cmd> Automate: run command, exit 0 = good, exit 1 = bad

Bisect narrows the search range using binary search. On each step, Muse checks out the midpoint commit and waits for a verdict (good/bad/skip). The search converges in O(log N) steps regardless of domain.

Exit codes: 0 session active or found · 1 bad arguments · 3 I/O error


worktree — multiple simultaneous checkouts

muse worktree add /path/to/dir feat/audio
muse worktree list
muse worktree list --format json
muse worktree remove feat/audio
muse worktree prune

Subcommands

Subcommand Description
add <path> <branch> Check out branch into path
list List registered worktrees
remove <branch> Remove a linked worktree
prune Remove entries for deleted directories

Flags — list

Flag Short Description
--format -f text or json

JSON output — list

[
  {"path": "/home/g/muse-main",  "branch": "main",       "is_main": true},
  {"path": "/home/g/muse-audio", "branch": "feat/audio", "is_main": false}
]

Exit codes: 0 success · 1 path or branch conflict


clean — remove untracked files

Scans the working tree against the HEAD snapshot and removes files not tracked in any commit. --force is required to actually delete files (safety guard).

muse clean -n               # dry-run: show what would be removed
muse clean -f               # delete untracked files
muse clean -f -d            # also delete empty directories
muse clean -f -x            # also delete .museignore-excluded files
muse clean -f -d -x         # everything untracked + ignored + empty dirs

Flags

Flag Short Description
--dry-run -n Preview without deleting
--force -f Required to actually delete
--directories -d Remove empty untracked directories
--include-ignored -x Also remove .museignore-excluded files

Exit codes: 0 clean or cleaned · 1 untracked exist but --force not given


describe — label by nearest tag

Walks backward from a commit and finds the nearest tag. Returns <tag>~N where N is the hop count. N=0 gives the bare tag name.

muse describe                       # → v1.0.0~3
muse describe --ref feat/audio      # describe the tip of a branch
muse describe --long                # → v1.0.0-3-sha256:abc123456789
muse describe --require-tag         # exit 1 if no tags exist
muse describe --format json         # machine-readable

Flags

Flag Short Description
--ref <ref> -r Branch or commit to describe
--long -l Always show <tag>-<dist>-g<sha>
--require-tag -t Fail if no tag found
--format <fmt> -f text or json

JSON output schema:

{
  "commit_id": "string (full SHA-256)",
  "tag":       "string | null",
  "distance":  0,
  "short_sha": "string (12 chars)",
  "name":      "string (e.g. v1.0.0~3)"
}

Exit codes: 0 description produced · 1 ref not found or --require-tag with no tags


shortlog — commit summary by author or agent

Groups commits by author or agent_id and prints a count + message list. Especially expressive in Muse because both human and agent contributions are tracked with full metadata.

muse shortlog                      # current branch
muse shortlog --all                # all branches
muse shortlog --numbered           # sort by commit count (most active first)
muse shortlog --email              # include agent_id alongside author name
muse shortlog --limit 100          # cap commit walk at 100
muse shortlog --format json        # JSON for agent consumption

Flags

Flag Short Description
--branch <br> -b Branch to summarise
--all -a Summarise all branches
--numbered -n Sort by commit count
--email -e Include agent_id
--limit <N> -l Max commits to walk
--format <fmt> -f text or json

JSON output schema:

[
  {
    "author": "string",
    "count":  12,
    "commits": [
      {"commit_id": "...", "message": "...", "committed_at": "..."}
    ]
  }
]

Exit codes: 0 always


verify — whole-repository integrity check

Walks every reachable commit from every branch ref and performs a three-tier check:

  1. Every branch ref points to an existing commit.
  2. Every commit's snapshot exists.
  3. Every object referenced by every snapshot exists, and (unless --no-objects) its SHA-256 is recomputed to detect silent data corruption.

This is Muse's equivalent of git fsck.

muse verify                   # full integrity check (re-hashes all objects)
muse verify --no-objects      # existence-only check (faster)
muse verify --quiet           # exit code only — no output
muse verify -q && echo "healthy"
muse verify --format json | jq '.failures'

Flags

Flag Short Description
--quiet -q No output; exit 0 = clean, 1 = failure
--no-objects -O Skip SHA-256 re-hashing
--format <fmt> -f text or json

JSON output schema:

{
  "refs_checked":      3,
  "commits_checked":   42,
  "snapshots_checked": 42,
  "objects_checked":   210,
  "all_ok":            true,
  "failures": [
    {
      "kind":  "object",
      "id":    "abc123...",
      "error": "hash mismatch — data corruption detected"
    }
  ]
}

Failure kinds: ref · commit · snapshot · object

Exit codes: 0 all checks passed · 1 one or more failures


snapshot — explicit snapshot management

A snapshot is Muse's fundamental unit of state: an immutable, content-addressed record mapping workspace paths to their SHA-256 object IDs.

muse snapshot exposes snapshots as a first-class operation — capture, list, show, and export them independently of commits. Useful for mid-work checkpoints in agent pipelines.

snapshot create

muse snapshot create
muse snapshot create -m "WIP: before refactor"
muse snapshot create --format json    # prints snapshot_id

JSON output:

{
  "snapshot_id": "string",
  "file_count":  42,
  "note":        "string",
  "created_at":  "ISO8601"
}

snapshot list

muse snapshot list
muse snapshot list --limit 5
muse snapshot list --format json

snapshot show

muse snapshot show <snapshot_id>
muse snapshot show abc123            # prefix lookup
muse snapshot show abc123 --format text

snapshot export

muse snapshot export <snapshot_id>
muse snapshot export abc123 --format zip --output release.zip
muse snapshot export abc123 --prefix project/

Archive formats: tar.gz (default) · zip

Flags (export):

Flag Short Description
--format <fmt> -f tar.gz or zip
--output <path> -o Output file path
--prefix <str> Directory prefix inside archive

Exit codes: 0 success · 1 snapshot not found


bundle — offline commit transfer

A bundle is a self-contained JSON file carrying commits, snapshots, and objects. Copy it over SSH, USB, or email — no network connection required.

The bundle format is identical to the plumbing MPack and is human-inspectable.

bundle create

muse bundle create out.bundle              # bundle from HEAD
muse bundle create out.bundle feat/audio  # bundle a specific branch
muse bundle create out.bundle HEAD --have old-sha  # delta bundle

bundle unbundle

muse bundle unbundle repo.bundle            # apply and update branch refs
muse bundle unbundle repo.bundle --no-update-refs  # objects only

bundle verify

muse bundle verify repo.bundle
muse bundle verify repo.bundle --quiet
muse bundle verify repo.bundle --format json

bundle list-heads

muse bundle list-heads repo.bundle
muse bundle list-heads repo.bundle --format json

Bundle value-add over plumbing: unbundle updates local branch refs from the bundle's branch_heads map, so the receiver's repo reflects the sender's branch state automatically.

Exit codes: 0 success · 1 file not found, corrupt, or bad args


content-grep — full-text search across tracked files

Searches every file in the HEAD snapshot for a pattern. Files are read from the content-addressed object store. Binary files and non-UTF-8 files are silently skipped.

Muse-specific: the search target is the immutable object store — you're searching a specific point in history, not the working tree.

muse content-grep --pattern "Cm7"
muse content-grep --pattern "TODO|FIXME" --files-only
muse content-grep --pattern "verse" --ignore-case
muse content-grep --pattern "tempo" --format json
muse content-grep --pattern "chord" --ref feat/harmony
muse content-grep --pattern "hit" --count

Flags

Flag Short Description
--pattern <regex> -p Python regex to search for
--ref <ref> -r Branch or commit to search
--ignore-case -i Case-insensitive matching
--files-only -l Print only matching file paths
--count -c Print match count per file
--format <fmt> -f text or json

JSON output schema:

[
  {
    "path":        "song.txt",
    "object_id":   "abc123...",
    "match_count": 3,
    "matches": [
      {"line_number": 4, "text": "chord: Cm7"}
    ]
  }
]

Exit codes: 0 at least one match · 1 no matches


whoami — show the current identity

A shortcut for muse auth whoami.

muse whoami
muse whoami --json          # JSON output for agent consumers
muse whoami --all           # show identities for all configured hubs

Flags

Flag Short Description
--json -j JSON output
--all -a Show all hub identities

Text output:

  hub:    app.musehub.ai
  type:   agent
  name:   mozart-agent-v2
  id:     usr_abc123
  token:  set

JSON output:

{
  "hub":          "app.musehub.ai",
  "type":         "agent",
  "name":         "mozart-agent-v2",
  "id":           "usr_abc123",
  "token_set":    true,
  "capabilities": ["push", "pull", "share"]
}

"token_set" is a boolean. "capabilities" lists the operations the current token is authorised for on the configured hub.

Exit codes: 0 identity found · 1 no identity stored (not authenticated)


Domain Auth & Config

auth — identity management

muse auth keygen --hub app.musehub.ai
muse auth register --hub app.musehub.ai --handle alice
muse auth register --hub app.musehub.ai --handle mozart-v2 --agent
muse auth whoami
muse auth logout

config — repository configuration

Read and write repository configuration stored in .muse/config.toml.

muse config show                        # full config as text
muse config show --format json          # machine-readable
muse config get core.author             # single value
muse config set core.author "Gabriel"   # write a value

Subcommands

Subcommand Description
show Print the entire config
get <key> Print a single key's value
set <key> <value> Write a key/value pair

Flags — show

Flag Short Description
--format -f text or json

JSON output — show

{
  "user": {
    "author": "gabriel",
    "email":  ""
  },
  "hub": {
    "url": "https://app.musehub.ai"
  },
  "remotes": {
    "origin": "https://app.musehub.ai/repos/my-repo"
  },
  "domain": {
    "my.key": "value"
  }
}

Top-level sections:

  • user — local author identity
  • hub — MuseHub connection (HTTPS URLs only)
  • remotes — named remote URLs
  • domain — domain-specific key/value pairs (any domain.* key is permitted)

Blocked namespaces: auth.* and remotes.* keys cannot be written via config set — use dedicated commands (muse auth keygen/register, muse remote add).

Exit codes: 0 success · 1 key not found, blocked namespace, or bad format


hub — MuseHub connection

muse hub connect https://app.musehub.ai
muse hub status
muse hub disconnect

Composability Patterns

Muse porcelain commands are designed to compose cleanly in pipelines.

Check integrity before every push:

muse verify --quiet || { echo "repo corrupt!"; exit 1; }
muse push

Offline collaboration via bundle:

# Sender:
muse bundle create session.bundle
scp session.bundle colleague:/tmp/

# Receiver:
muse bundle verify /tmp/session.bundle --quiet
muse bundle unbundle /tmp/session.bundle

Generate a release label in CI:

VERSION=$(muse describe --format json | jq -r .name)
echo "Building $VERSION..."
muse snapshot export HEAD --output "${VERSION}.tar.gz"

Find which commits touched a melody line:

muse content-grep --pattern "tempo: 120" --format json | jq '.[].path'

Agent activity summary:

muse shortlog --all --numbered --email --format json \
  | jq '.[] | select(.author | test("agent")) | {agent: .author, count: .count}'

Checkpoint before a risky refactor:

SNAP=$(muse snapshot create -m "pre-refactor" --format json | jq -r .snapshot_id)
# ... do the work ...
muse snapshot show "$SNAP" --format json | jq '.manifest | keys'

Binary-search for the broken commit (automated):

muse bisect start
muse bisect bad HEAD
muse bisect good v1.0.0
muse bisect run pytest tests/regression.py
# Muse prints the first bad commit and resets automatically.

Audit all recent changes by agents:

muse log --format json | jq '[.[] | select(.author | startswith("agent-"))]'
File History 1 commit