gabriel / muse public
agent-guide.md markdown
1,371 lines 66.4 KB
Raw
sha256:b5ec4e4a3a73cae0cd08224f32090f2a4836afa0a804cb3231e70c42a3e89295 fix adapter for agent config Human patch 4 days ago

Muse Ecosystem — Agent Guide

Drop @path/to/this/file into any CLAUDE.md or agent system prompt for full ecosystem context.


Three Repos, One Platform

Repo Path What it is
muse ~/ecosystem/muse VCS engine and CLI
musehub ~/ecosystem/musehub Remote server — pushes, issues, MCP tooling. https://localhost:1337
agentception ~/ecosystem/agentception Multi-agent orchestration. http://localhost:10003

All three live under ~/ecosystem/ as a muse workspace. When you change a muse CLI command, agentception callers may need updating. When you change a musehub API shape, agentception readers may need updating.


No git. No GitHub. Ever.

  • Never run git, gh, or any git subcommand.
  • Never reference GitHub, GitHub Actions, or GitHub URLs.
  • Muse and MuseHub are the only VCS tools.
  • If you find a git or gh call anywhere — delete it in the same commit. No comment, no fallback. Delete it.

Sub-Agents Must Use Muse Too

Sub-agents start with no ecosystem knowledge. Include this in every sub-agent prompt:

IMPORTANT — this project uses Muse (not git) for version control.
- Never run git, gh, or any git subcommand.
- Repo paths: ~/ecosystem/muse, ~/ecosystem/musehub, ~/ecosystem/agentception
- Use muse code grep / symbols / cat / impact / deps / hotspots / gravity / entangle
  before reading files directly. Every command accepts --json / -j.
- Use muse -C ~/ecosystem/<repo> <command> when CWD differs from the target repo.

Muse Commands

Every command accepts --json. Always use --json for structured reads.

-C — cross-repo targeting

muse -C ~/ecosystem/muse        <command>
muse -C ~/ecosystem/musehub     <command>
muse -C ~/ecosystem/agentception <command>

-C does os.chdir() before dispatch — file paths resolve against the target repo root. Never omit it when your CWD is a different repo:

muse hub — always needs repo context

muse hub commands require a configured hub connection. Running them without -C (or from a repo without a remote) fails with "No hub connected." Always target a repo that has the hub wired up:

# ❌ Wrong — no hub context
muse hub repo list --json

# ✅ Correct
muse -C ~/ecosystem/musehub hub repo list --json
# ❌ Wrong — path resolves against CWD (wrong repo)
muse code add musehub/services/musehub_wire.py

# ✅ Correct
muse -C ~/ecosystem/musehub code add musehub/services/musehub_wire.py
muse -C ~/ecosystem/musehub commit -m "..."

muse push — check remotes exist before pushing

Before pushing to a repo for the first time, verify remotes are configured:

muse -C ~/ecosystem/<repo> remote --json

If the named remote is not found, the error now lists what is configured:

❌ Remote 'local' is not configured.
   Configured remotes: (none)
   Add one with: muse remote add local <url>

No follow-up muse remote --json call needed — the answer is in the error.

muse push — uses remote names, not --hub

--hub <url> is only valid on muse hub subcommands. muse push always takes a named remote. Never mix the two patterns:

# ❌ Wrong — --hub is not a push flag
muse -C ~/ecosystem/maestro push --hub https://staging.musehub.ai local main

# ✅ Correct — use the remote name
muse -C ~/ecosystem/maestro push staging main
muse -C ~/ecosystem/maestro push local main

To see which remotes are configured and their URLs:

muse -C ~/ecosystem/<repo> remote --json

muse push now also accepts --hub <url> as a convenience: it resolves the URL to its configured remote name automatically, so the wrong pattern is corrected rather than crashing.

muse hub — targeting staging vs local

By default muse hub targets the hub configured for the repo (usually https://localhost:1337). To target staging, pass --hub https://staging.musehub.ai:

# local (default)
muse -C ~/ecosystem/musehub hub repo list --json

# staging
muse -C ~/ecosystem/musehub hub repo list --hub https://staging.musehub.ai --json

muse hub repo list — exact flags

hub repo list lists repos for the authenticated user only. It has NO --owner flag. Valid flags: --limit N, --cursor CURSOR, --hub URL, --json. Filter by owner or name in Python after fetching:

muse -C ~/ecosystem/musehub hub repo list --limit 100 --json \
  | python3 -c "import sys,json; [print(r['slug']) for r in json.load(sys.stdin)['repos'] if r['owner']=='gabriel']"

Never pipe 2>&1 into a JSON parser

2>&1 | redirects stderr into the pipe. If the muse command fails, the error text lands in stdin and Python raises JSONDecodeError: Expecting value — hiding the real error.

# ❌ Wrong — error text swallowed as fake JSON
muse hub repo list --owner gabriel --json 2>&1 | python3 -c "json.load(sys.stdin)..."

# ✅ Correct — check exit code first, or let stderr print to terminal
muse -C ~/ecosystem/musehub hub repo list --json \
  | python3 -c "import sys,json; [print(r['name']) for r in json.load(sys.stdin)['repos']]"

Core commands

Task Command
Status muse status --json
Diff working tree muse diff
Diff staged muse diff --staged
Stage additions/modifications muse code add <file> / muse code add .
Unstage muse code reset <file>
Remove file (disk + stage deletion) muse rm <file>
Untrack file (keep on disk) muse rm --cached <file>
Commit (agent — standard) muse commit -m "msg" --agent-id <id> --model-id <id> --sign
Commit (human — manual only) muse commit -m "message"
History muse log --json
Inspect commit muse read --json
Inspect commit + full manifest muse read --json --manifest
Branches muse branch --json
Create / switch muse checkout -b <name> [--intent "..." --resumable] / muse checkout <branch>
Delete branch muse branch -d <name>
Merge muse merge <branch>
Dry-run merge muse merge --dry-run <branch> --json
Push muse push local dev
Pull muse pull <remote> <branch>
Shelf / pop muse shelf save [-m "msg"] / muse shelf pop
Workspace status muse workspace status --json
Tag muse tag add "label" [<ref>]
Release muse release add <semver>

muse content-grep — regex gotchas

Uses Python re (ERE). Metacharacters ( ) . [ * + ? { } ^ $ must be escaped for literal matches:

muse content-grep "session\.add\(obj_row\)"   # ✅ escaped
muse content-grep "session.add(obj_row)"       # ❌ fails — ( opens a group

OR syntax: muse content-grep "TODO|FIXME"

muse content-grep — JSON output shape

{
  "results": [
    {
      "path": "src/main.py",        # ← "path" — matches all other muse commands
      "object_id": "sha256:...",
      "match_count": 2,
      "matches": [
        {
          "line_number": 42,
          "line": "matched line text",  # ← "line", not "text"
          "context_before": [],
          "context_after": []
        }
      ]
    }
  ]
}

Iteration idiom:

for r in data["results"]:
    for m in r["matches"]:
        print(r["path"], m["line_number"], m["line"])

Branch Flow

main          ← production; tagged releases; never direct-pushed
  ↑
dev           ← integration; latest deliverable state
  ↑    ↑    ↑
feat/* task/* bugfix/*   ← short-lived; one atomic task; hours not days

hotfix/*      ← from main; merges into main AND dev
experiment/*  ← exploratory; time-boxed; promoted or deleted

Never work directly on dev or main. Branch first, always.

Branch semantic flags

Every agent branch should carry intent and resumability metadata. --intent and --resumable are accepted by both muse checkout -b (create + switch atomically) and muse branch (create or annotate only):

# Create, annotate, and switch in one command — the canonical agent pattern
muse -C ~/ecosystem/<repo> checkout -b task/my-thing \
  --intent "implement OAuth token rotation" \
  --resumable

# Annotate an existing branch (no switch)
muse -C ~/ecosystem/<repo> branch task/my-thing \
  --intent "implement OAuth token rotation" \
  --resumable

# Discover all resumable branches (handoff discovery)
muse -C ~/ecosystem/<repo> branch --resumable --json

# JSON listing always includes intent, resumable, created_by on every entry
muse -C ~/ecosystem/<repo> branch --json
# → [{"name": "task/my-thing", "intent": "...", "resumable": true, "created_by": "claude-code", ...}]

Why: --intent lets any agent reading branch --json understand what each branch is for without inspecting commit history. --resumable marks branches as safe for another agent to pick up — use it for any task that may be interrupted.

Standard cycle

# Start — create, annotate, and switch in one command
muse -C ~/ecosystem/<repo> checkout dev
muse -C ~/ecosystem/<repo> checkout -b task/my-thing \
  --intent "describe what this task does" \
  --resumable

# Work — always commit with full agent provenance
muse code add .    # stages new + modified + deleted tracked files
muse commit -m "feat: ..." --agent-id claude-code --model-id claude-sonnet-4-6 --sign

# Merge back
muse -C ~/ecosystem/<repo> checkout dev
muse -C ~/ecosystem/<repo> merge task/my-thing
muse -C ~/ecosystem/<repo> branch -d task/my-thing
muse -C ~/ecosystem/<repo> push local dev

# When dev is ready for main
muse -C ~/ecosystem/<repo> checkout main
muse -C ~/ecosystem/<repo> merge dev
muse -C ~/ecosystem/<repo> push local main
muse -C ~/ecosystem/<repo> push local dev
muse -C ~/ecosystem/<repo> checkout dev

Harmony — Resolution Intelligence

Harmony is Muse's conflict-resolution memory system — a three-tier intelligence layer:

Tier 1 — Policy       declarative rule fires automatically on pattern match
Tier 2 — Exact replay blob fingerprint matches a saved resolution
Tier 3 — Semantic     domain plugin similarity score ≥ threshold
Tier 4 — Escalate     create hub issue; flag for human or specialist agent

How Harmony learns

The learning loop is automatic when --harmony-autoupdate is on (the default):

muse merge <branch>          ← harmony auto-applies any saved resolutions
                               conflicts that have no resolution → patterns recorded
                               (future merges will try to replay them)

# Resolve conflicts manually, then:
muse commit -m "merge: ..."  ← harmony records the outcome as a human-verified
                               resolution (confidence=1.0) for every conflict path

Idiomatic harmony workflow

# 1. Merge — harmony tries to auto-resolve using saved resolutions
muse merge feature-x --json
# ✔ [harmony] auto-resolved: config.py::MAX_CONNECTIONS   ← replayed
# CONFLICT: src/server.py::timeout                         ← new, no prior resolution

# 2. Inspect what harmony knows
muse harmony patterns --json          # all saved conflict patterns
muse harmony resolutions --json       # all saved resolutions
muse harmony audit --json             # full tamper-evident action log

# 3. List remaining conflicts
muse conflicts --json
# → [{path: "src/server.py::timeout", kind: "symbol"}]

# 4. Read the conflicted file — understand BOTH sides before touching anything
#    Conflict markers show three versions:
#    <<<<<<< ours [modified]       ← what your branch has
#    (ours content)
#    ||||||| base                  ← common ancestor (what both started from)
#    (base content)
#    ======= theirs [modified]     ← what the incoming branch has
#    (theirs content)
#    >>>>>>> end conflict
#
#    Understand WHY each side changed what it did.
#    Never blindly pick --ours or --theirs — that silently discards real work.

# 5. Manually edit the file to produce the correct merged result
#    (incorporate the intent of BOTH sides, not just one)

# 6. Mark resolved — this stages the file and clears it from the conflict list
muse resolve src/server.py::timeout --json
# or to resolve all at once:
muse resolve --all --json

# 7. Commit — harmony automatically records the resolution
muse commit -m "merge: resolve timeout conflict" \
  --agent-id claude-code --model-id claude-sonnet-4-6 --sign
# ✅ harmony: recorded resolution for 'src/server.py::timeout'

# 8. Next time the same conflict recurs → auto-resolved without human input
muse merge feature-y --json
# ✔ [harmony] auto-resolved: src/server.py::timeout

⚠️ Never blindly pick --ours or --theirs

muse checkout --ours <path> and muse checkout --theirs <path> exist for when you have verified that one side is entirely correct and the other is entirely wrong. In practice this is rare. Using them without reading both sides discards real work.

The safe pattern for every conflict:

  1. muse conflicts --json — see what needs resolving
  2. Read the file — understand <<<<<<< ours, ||||||| base, >>>>>>> theirs
  3. Edit the file manually to produce the correct result
  4. muse resolve <path> — mark resolved (stages automatically)
  5. muse commit — complete the merge

Only use --ours / --theirs when:

  • You have read both sides and confirmed one is entirely superseded
  • You are deliberately reverting one branch's changes to a specific file
  • The conflict is in generated/derived content that should always come from one side

Harmony storage layout

.muse/harmony/
  patterns/
    <pattern_id>/
      pattern.json              ← ConflictPattern (blob + semantic fingerprint)
      resolutions/
        <resolution_id>.json   ← Resolution (outcome_blob, confidence, strategy)
  policies/
    <policy_id>.json           ← declarative Policy rules
  audit/
    <YYYYMMDD>-<id>.json       ← append-only tamper-evident log
  escalations/
    <escalation_id>.json       ← Tier 4 escalation records

Harmony CLI reference

Task Command
List all patterns muse harmony patterns --json
List resolutions for a pattern muse harmony resolutions --pattern-id <id> --json
Show best resolution muse harmony best --pattern-id <id> --json
Add a policy muse harmony policy-add --id <id> --action prefer-ours --path-pattern "*.mid"
List policies muse harmony policies --json
View audit log muse harmony audit --json
Run the engine on a conflict muse harmony engine <path> <ours-id> <theirs-id> --json
GC stale unresolved patterns muse harmony gc --age-days 90 --json
Clear all patterns muse harmony clear --json
View escalations muse harmony escalations --json

Pattern fingerprinting

Two fingerprints identify each conflict:

  • Blob fingerprintSHA-256(sorted(ours_id, theirs_id)). Exact-replay only; different content never matches.
  • Semantic fingerprint — provided by a HarmonyPlugin implementation. Enables cross-content replay: two conflicts with different blob IDs but the same semantic shape (e.g. the same musical phrase at different tempo) share one pattern and replay the same resolution.

When a HarmonyPlugin is active and returns semantic_fp != blob_fp, the pattern_id is keyed on semantic_fp alone — enabling cross-content replay. Without a plugin, semantic_fp == blob_fp and the system degenerates to exact replay with full provenance.

Key behaviours to remember

  • Idempotent learning: calling record_resolutions twice with the same outcome_blob produces exactly one resolution — no duplicates.
  • Symbol-path aware: conflict paths like config.py::MAX_CONNECTIONS are handled correctly — file portion used for manifest lookups, full address stored in the pattern.
  • Original conflict paths preserved: checkout --ours/--theirs clears conflict_paths in MERGE_STATE, but original_conflict_paths is preserved through all writes so commit always has the full list to learn from.
  • Path traversal guard: auto_apply resolves .. before any filesystem access — tampered MERGE_STATE cannot escape the repo root.
  • Human-verified wins: best_resolution ranks by (human_verified, confidence, applied_count) descending — a human-verified resolution always beats an unverified one regardless of confidence score.

Bundle — Off-Network Transfer

Bundles are self-contained msgpack files carrying commits, snapshots, and objects. Use them to transfer repo slices over SSH, USB, or email — no network connection required.

Agent decision chain

Always follow this sequence before applying a bundle:

# 1. What's in it?
muse bundle inspect bundle.muse --json
# → total_commits, branches map, per-commit message + agent_id

# 2. Is it clean?
muse bundle verify bundle.muse -q
# → exit 0 = clean; exit 1 = corrupt; no output in -q mode

# 3. What's new relative to my local repo?
muse bundle diff bundle.muse --json
# → new_commits, known_commits, refs_to_advance

# 4. Apply safely (verify before any write)
muse bundle unbundle bundle.muse --verify --json
# → verified=true in JSON if integrity passed before writes

Skip step 4 if new_commits == 0 — the repo is already up-to-date. Abort if step 2 exits 1 — the bundle is corrupt.

Create

muse bundle create repo.bundle --json                      # all of HEAD
muse bundle create out.bundle feat/audio --json            # specific branch
muse bundle create out.bundle HEAD --have <old-id> --json  # incremental

Subcommand reference

Subcommand Needs repo? Purpose
inspect No Show commits + branch heads — no writes
verify No Hash-check every object — no writes
list-heads No Print branch → commit_id map
diff Yes Show commits not yet in local repo
unbundle Yes Apply bundle; --verify guards writes
create Yes Pack commits into a bundle file

Deploy (MuseHub)

Docker + ECR + AWS SSM. Always staging first.

bash ~/ecosystem/musehub/deploy/push.sh staging
bash ~/ecosystem/musehub/deploy/push.sh prod
bash ~/ecosystem/musehub/deploy/push.sh staging prod          # both in sequence
IMAGE_TAG=<prev-tag> bash ~/ecosystem/musehub/deploy/push.sh staging  # rollback

Full details: musehub/docs/infrastructure.md.


Auth — MSign (Ed25519)

No passwords, no JWTs. Ed25519 key pairs. Keys in ~/.muse/identity.toml.

muse auth keygen --hub https://localhost:1337
muse auth register --hub https://localhost:1337 --handle <handle>
muse auth whoami
muse auth logout --hub https://localhost:1337   # decommission / key rotation

Mnemonic backup — critical

keygen stores the BIP-39 mnemonic in the OS keychain and never prints it to the terminal (scrollback is not safe). Back it up immediately after keygen by piping from the keychain directly to your password manager — the mnemonic never touches the terminal display:

# macOS — copies to clipboard; paste into 1Password / Bitwarden immediately
security find-generic-password -s muse -a mnemonic -w | pbcopy

# Linux
secret-tool lookup service muse account mnemonic | xclip -selection clipboard

Losing the mnemonic means permanent loss of all derived keys. The keychain entry uses service=muse, account=mnemonic.

Key rotation

# Generate a fresh mnemonic and rotate to a new key (IRREVERSIBLE)
muse auth keygen --hub https://localhost:1337 --force --destroy-mnemonic
# Then back up the new mnemonic immediately (see above)

Push returns 404 ("Repository not found on remote")? The repo doesn't exist on MuseHub yet — create it via the API, then retry muse push local.

Agentception injects keys into spawned agents via MUSE_AGENT_KEY_FD (pipe fd carrying 64-byte sub-seed) and MUSE_AGENT_HANDLE env vars. get_signing_identity() reads MUSE_AGENT_KEY_FD first, derives the Ed25519 key via SLIP-0010, then falls back to ~/.muse/identity.toml.


Cryptographic Value Codec — muse.core.types

Every cryptographic value is always canonically prefixed — never a bare hex string or bare base64 blob. The prefix embeds the algorithm so the value is self-describing across storage, wire, and log output.

Wire format

sha256:<64-hex>         — content-addressed object / commit / snapshot ID
ed25519:<base64url>     — Ed25519 signature or public key (no padding)
mldsa65:<base64url>     — future post-quantum signature (reserved)

Utility functions (all in muse.core.types)

Need Function Returns
Object ID → (algo, hex_str) split_id(id) ("sha256", "<64-hex>")
Signature string → (algo, b64_str) split_sig(value) ("ed25519", "<base64url>")
Public key string → (algo, b64_str) split_pubkey(value) ("ed25519", "<base64url>")
Signature string → (algo, raw_bytes) decode_sig(value) ("ed25519", b"...")
Public key string → (algo, raw_bytes) decode_pubkey(value) ("ed25519", b"...")
Raw bytes → prefixed sig string encode_sig(algo, raw) "ed25519:<base64url>"
Raw bytes → prefixed pubkey string encode_pubkey(algo, raw) "ed25519:<base64url>"
Just the algo name sig_algo(value) "ed25519" or ""

Rules

  • Never strip prefixes manually — no removeprefix("ed25519:"), no [10:], no partition(":") inline. Use split_sig / split_pubkey / split_id.
  • Never store or transmit bare bytes — always encode with encode_sig / encode_pubkey before serialisation.
  • split_sig vs decode_sig: use split_sig when you need the base64 string (e.g. to pass to another API, embed in JSON, or validate format); use decode_sig only when you need raw bytes for cryptographic operations.
  • split_sig vs split_pubkey: semantically distinct — never pass a signature where a public key is expected.

Agent Config

One canonical source per level. IDE adapter files are derived outputs — never edit them by hand.

<repo>/.muse/agent.md          — repo-specific rules
<workspace>/.muse/agent.md     — shared rules inherited by all members

First-time setup

# Once — globally, across every repo on this machine (like ~/.gitconfig).
# Survives branch switches and merges. Never needs to be repeated.
muse agent-config set --global --adapters claude

# At the workspace root (if inside a workspace)
muse -C ~/ecosystem agent-config init

# At each member repo
muse -C ~/ecosystem/<repo> agent-config init

# Generate adapter files (uses the global config set above)
muse -C ~/ecosystem/<repo> agent-config sync

--global writes to ~/.muse/config.toml. Without --global, the setting goes into the repo's .muse/config.toml and only applies to that repo. The repo-level setting takes priority over the global setting when both exist.

Keeping adapters in sync

After editing .muse/agent.md:

muse agent-config sync --force   # regenerate from updated source
muse agent-config status         # verify all adapters are in sync

sync requires adapter configuration (global or repo-level). It exits with an error if neither source has an [agent-config] section — no silent "generate everything" fallback.

Adapter files generated

Adapter File Style
claude CLAUDE.md @include reference
codex AGENTS.md embedded content
cursor .cursorrules embedded content
windsurf .windsurfrules embedded content

Claude's adapter uses @path include syntax — it stays minimal and Claude resolves the content at read time. All others embed the full content inline.

Inside a workspace, Claude's CLAUDE.md includes both levels:

@../.muse/agent.md   ← workspace rules
@.muse/agent.md      ← repo-specific rules

Commands

Task Command
Create agent.md muse agent-config init [--force]
Set adapters globally (once) muse agent-config set --global --adapters claude
Set adapters for this repo only muse agent-config set --adapters claude,codex
Generate adapters muse agent-config sync [--force] [--adapters a,b]
Read content muse agent-config read [--scope repo\|workspace\|merged]
Check sync state muse agent-config status [--json]

No Legacy. No Deprecated. No Exceptions.

  • Delete on sight. Dead code, deprecated shapes, backward-compat shims — delete in the same commit.
  • No fallback paths. The current shape is the only shape.
  • No # deprecated annotations. Delete it, don't annotate it.
  • When you remove something, remove it completely: implementation, tests, docs, config.

Code Intelligence — Replace Your Reflexes

Before you grep or read a file, ask: which muse code command answers this?

Layered intel — three altitudes, one repo

Micro  (symbol-level)   grep · symbols · cat · find-symbol · symbol-log
Meso   (file-level)     deps · impact · coverage · breakage
Macro  (repo-level)     gravity · hotspots · entangle · dead · detect-refactor · velocity

Start at the altitude that matches the question. Never reach for a file read when a Micro command answers it. Never reach for Micro when a Macro command gives you the full picture in one call.

Reflex replacement table

Old reflex Muse command
git ls-files / ls / find . — list tracked files muse ls-files --json
git ls-files src/ — list tracked files under a path muse ls-files --path-prefix src/ --json
rg "FunctionName" to find a declaration muse code grep "FunctionName" --json
Read raw file bytes muse cat file.py --json
Read file to find one function muse code cat "file.py::FunctionName" --json
muse code cat "file.py" (no ::) ❌ always errors — use muse cat file.py (file-level) or muse code symbols --file file.py (symbol list)
Understand a file's structure muse code symbols --file path/to/file.py --json
Find a symbol across all branches muse code find-symbol "Name" --json
Map scope before a refactor muse code impact "file.py::Symbol" --json
Find all callers of a function muse code impact "file.py::Symbol" --json
Understand imports muse code deps "path/to/file.py" --json
Update one function body muse code patch "file.py::Symbol" --body /tmp/new.py
Dead-code hunt muse code dead --high-confidence-only --json
Check refactor safety muse code breakage --json
Run tests for what changed muse code test --json
Find the most unstable symbols muse code hotspots --json
Rank symbols by downstream blast radius muse code gravity --json
Find files that always change together muse code entangle --json
Detect latent refactor opportunities muse code detect-refactor --json
Measure test coverage at symbol level muse code semantic-test-coverage --json
Summarise repo activity over time muse code velocity --json
How much of a symbol's original code survives? muse code age --json
When was a symbol last fundamentally rewritten? muse code age --explain file.py::Fn --json
Generate an agent keypair muse agent keygen --json
List registered agents muse agent list --json
Register an agent identity muse agent register --handle <name> --json
Create agent.md config muse agent-config init [--force] --json
Set adapters globally (once, all repos) muse agent-config set --global --adapters claude --json
Set adapters for this repo muse agent-config set --adapters claude,codex --json
Generate adapter files muse agent-config sync [--force] --json
Read merged agent config muse agent-config read --scope merged --json
Check adapter sync state muse agent-config status --json
Add inline annotation to a symbol muse annotate "file.py::Fn" --note "..." --json
List all annotations muse annotate list --json
Show API surface (public symbols) muse api-surface --json
API surface diff between refs muse api-surface --from v1.0 --to HEAD --json
Apply a unified diff .patch file muse apply my.patch --json
Apply a Muse .mpatch file muse apply-patch patch.mpatch --json
Export snapshot as tar.gz / zip muse archive --json
List .museattributes merge rules muse attributes list --json
Resolve strategy for a path muse attributes check src/foo.py --json
Validate .museattributes file muse attributes validate --json
Generate Ed25519 keypair muse auth keygen --hub <url> --json
Register key with hub muse auth register --hub <url> --handle <name> --json
Show current identity muse auth whoami --json
Remove stored credentials muse auth logout --json
Recover key from mnemonic muse auth recover --hub <url> --json
Rotate key to next HD index muse auth rotate --hub <url> --json
Show full HD identity details muse auth show --json
Start a regression bisect muse bisect start --bad HEAD --good v1.0.0 --json
Automate bisect with a test command muse bisect run "pytest -x" --json
Mark current commit bad/good/skip muse bisect bad --json / muse bisect good --json
Show bisect session state muse bisect status --json
End bisect session muse bisect reset --json
Blame a symbol's change history muse blame "file.py::Symbol" --json
Rank symbols by blast-risk score muse code blast-risk --json
List / create / delete branches muse branch --json / muse branch -b feat/x --json / muse branch -d feat/x --json
Detect working-tree structural breakage muse code breakage --json
Create a portable bundle muse bundle create repo.bundle --json
Inspect bundle contents muse bundle inspect repo.bundle --json
Verify bundle integrity muse bundle verify repo.bundle --json
Show new commits in bundle muse bundle diff repo.bundle --json
Apply a bundle muse bundle unbundle repo.bundle --verify --json
List bundle branch heads muse bundle list-heads repo.bundle --json
Print one symbol's source muse code cat "file.py::Symbol" --json
Print all symbols in a file muse code cat "file.py" --all --json
Read a raw object by ID muse cat-object sha256:<id> --json
Run domain invariant checks muse check --json / muse check --base HEAD~1 --json
Query merge-strategy attributes muse check-attr tracks/drums.mid --json
Test paths against ignore rules muse check-ignore build/ --json
Validate branch names muse check-ref-format feat/my-thing --json
Switch / create branch muse checkout dev --json / muse checkout -b task/x --intent "..." --resumable --json
Restore a symbol from history muse checkout-symbol "file.py::Fn" --commit HEAD~5 --json
Cherry-pick a commit muse cherry-pick <ref> --json
Remove untracked files muse clean --dry-run --json / muse clean --force --json
Clone a remote repository muse clone <url> --json
Find duplicate symbols muse code clones --json
Enforce code invariant rules muse code check --json
Query commit history by predicate muse code query "symbol == 'X'" --json
Stage files for commit muse code add . --json / muse code reset --json
Repo semantic topology map muse code codemap --json
Create a commit muse commit -m "feat: X" --agent-id claude-code --model-id claude-sonnet-4-6 --sign --json
Walk commit DAG muse commit-graph --tip dev --stop-at main --json
Create commit from snapshot ID muse commit-tree sha256:<id> -m "msg" --json
Symbol-level diff between refs muse code compare HEAD~10 HEAD --json
Read / get / set config muse config read --json / muse config get user.handle --json / muse config set user.type agent --json
List merge conflicts muse conflicts --json
Search file content muse content-grep "TODO\|FIXME" --json
Validate smart contract invariants muse contract check --json / muse contract list --json
GC expired coordination records muse coord gc --json
Recommend merge order / conflict hotspots muse coord reconcile --json
Release a reservation (mark done) muse coord release <id> --run-id agent-42 --json
Release all reservations for a run muse coord release --all-for-run agent-42 --run-id agent-42 --json
Sync coordination state from remote muse coord sync --json
Enqueue a work item for agents muse coord enqueue "title" --run-id orch --json
Claim the next pending task muse coord claim --run-id agent-1 --json / muse coord claim --queue hotfix --run-id agent-1 --json
Mark a task completed muse coord complete <task-id> --run-id agent-1 --json
Mark a task failed muse coord fail-task <task-id> --run-id agent-1 --error "msg" --json
Cancel a pending or claimed task muse coord cancel-task <task-id> --run-id orch --json
List tasks with filtering muse coord tasks --json / muse coord tasks --status pending --json
Line-level blame for any text file muse blame README.md --json / muse blame src/main.py --range 10-20 --json
Print raw file content muse cat file.py --json / muse cat file.py --at HEAD~5 --json
Count objects in the object store muse count-objects --json / muse count-objects --unreachable --json
Find co-changing file pairs muse code coupling --json / muse code coupling --file src/billing.py --json
Measure symbol-level test coverage muse code coverage --json / muse code coverage --symbol "file.py::Fn" --json
Inspect coordination DAG muse coord dag --json / muse coord dag --active-only --json
Find dead code candidates muse code dead --high-confidence-only --json
Show import / call graph muse code deps src/billing.py --json / muse code deps "file.py::Fn" --transitive --json
Label commit by nearest tag muse describe --json / muse describe --exact-match --json
Detect semantic refactoring events muse code detect-refactor --json / muse code detect-refactor --from v1.0.0 --to v2.0.0 --json
Show working-tree diff muse diff --json / muse diff --staged --json / muse diff HEAD~3 HEAD --json
Render / gate symbol documentation muse docs --json / muse docs --ci --json / muse docs --diff v1 v2 --json
Inspect active domain plugin muse domain-info --json / muse domain-info --all-domains --json
List registered domain plugins muse domains --json
Find entangled symbol pairs muse code entangle --json / muse code entangle --min-rate 0.8 --json
Download commits from a remote muse fetch local --json / muse fetch --all --json
Search all branches for a symbol muse code find-symbol --name validate_amount --json / muse code find-symbol --hash a3f2c9 --json
Iterate all branch refs muse for-each-ref --format json / muse for-each-ref --pattern "feat/*" --format json
Predict merge conflicts muse coord forecast --format json / muse coord forecast --branch feat/x --format json
Export commit as patch file muse format-patch --json / muse format-patch HEAD~3 --json
GC unreachable objects muse gc --json / muse gc --dry-run --json / muse gc --full --json
Compute structural gravity scores muse code gravity --json / muse code gravity --explain "file.py::Fn" --json
Search symbols by name muse code grep "validate" --json / muse code grep "compute.*" --regex --json
Manage harmony conflict patterns muse harmony patterns --format json / muse harmony audit --format json
Hash file or stdin content muse hash-object file.py --format json / echo x \| muse hash-object --stdin --format json
Refresh coordination heartbeat muse coord heartbeat <id> --run-id agent-42 --format json
Show symbol churn leaderboard muse code hotspots --json / muse code hotspots --top 20 --json
Map blast radius for a symbol muse code impact "file.py::Symbol" --json / muse code impact "file.py::Fn" --reverse --json
Initialise a new Muse repository muse init --json / muse init --domain audio --json
Check architectural invariants muse code invariants --json / muse code invariants --strict --json
Show language breakdown by commit muse languages --json / muse languages HEAD~5 HEAD --json
Trace symbol lineage across commits muse code lineage "file.py::Symbol" --json
List active coordination sessions muse coord list --json / muse coord list --active-only --json
Walk commit history muse log --json / muse log -n 20 --branch feat/x --json
Inspect ref movement history muse reflog --json / muse reflog --branch dev --json
List all refs with a reflog muse reflog --all --json
List tracked files in snapshot muse ls-files --json / muse ls-files --path-prefix src/ --json
List branch heads on a remote muse ls-remote --json / muse ls-remote local --json
Inspect snapshot tree structure muse ls-tree --json / muse ls-tree -r HEAD --json
Run scheduled store maintenance muse maintenance run --all --json / muse maintenance status --json
Merge a branch into current muse merge feat/x --format json / muse merge feat/x --dry-run --format json
Find common ancestor of two commits muse merge-base dev feat/x --json / muse merge-base HEAD sha256:<id> --json
Three-way merge without touching workdir muse merge-tree dev feat/x --json / muse merge-tree dev feat/x --write-objects --json
Rewrite commit DAG to v2 ID formula (+ optional re-sign) muse code migrate --dry-run --json / muse code migrate --sign --json / muse code migrate --force-resign --json
Rename a tracked file muse mv src/old.py src/new.py --json / muse mv src/old.py src/new.py --dry-run --json
Map commit IDs to branch-relative names muse name-rev sha256:<id> --json
Render a symbol's life story muse code narrative "file.py::Symbol" --json
Build a pack bundle (dry-run) muse pack-objects HEAD --dry-run --json
Surgical symbol replacement muse code patch "file.py::Symbol" --body /tmp/new.py --json
Compute patch fingerprint muse patch-id --json / muse patch-id HEAD~3 --json
Dry-run plan a merge (conflict prediction) muse plan-merge feat/x --json
Predict merge risk between branches muse predict feat/x dev --json
GC dangling objects muse prune --json / muse prune --dry-run --json
Fetch from a remote muse pull local dev --json
Push branch to remote muse push local dev --json
Query commit history with predicates muse query "author == 'gabriel'" --json
Query symbol change history muse query-history "file.py::Fn" --json
Show diffs between two commit ranges muse range-diff main..feat/a main..feat/b --json
Inspect HEAD commit muse read --json
Inspect HEAD commit + full file list muse read --json --manifest
Inspect a specific commit muse read sha256:<id> --json
Read a commit record by ID muse read-commit sha256:<id> --json
Read a snapshot manifest muse read-snapshot sha256:<id> --json
Replay commits onto a new base muse rebase main --json / muse rebase --squash main --json
Preview rebase commits muse rebase --dry-run main --json
Resume a paused rebase muse rebase --continue --json / muse rebase --abort --json
Inspect in-progress rebase muse rebase --status --json
Create a local release muse release add v1.2.0 --json / muse release add v1.3.0-beta.1 --channel beta --draft --json
List releases muse release list --json / muse release list --channel stable --json
Read a single release muse release read v1.2.0 --json
Infer next version from commit graph muse release suggest --json / muse release suggest --base v1.1.0 --json
Push a release to remote muse release push v1.2.0 --json / muse release push v1.2.0 --dry-run --json
Delete a release label muse release delete v1.2.0 --yes --json / muse release delete v1.2.0 --dry-run --json
List configured remotes muse remote --json
Add a remote muse remote add origin https://musehub.ai/user/repo --json
Get a remote's URL muse remote get-url origin --json
Update a remote's URL muse remote set-url origin https://... --json
Rename a remote muse remote rename origin upstream --json
Remove a remote muse remote remove origin --json
Check remote reachability muse remote status origin --json
AST-level symbol rename muse code rename billing.py::compute_total compute_invoice_total --json --yes
Preview rename without writing muse code rename billing.py::compute_total new_name --dry-run --json
Rename only the definition muse code rename billing.py::compute_total new_name --scope definition --json --yes
Reserve symbol addresses (advisory) muse coord reserve "billing.py::compute_total" --run-id agent-42 --json
Reserve with operation and TTL muse coord reserve "auth.py::validate" --run-id agent-42 --op modify --ttl 7200 --json
Reserve with dependency ordering muse coord reserve "billing.py::Fn" --run-id agent-B --depends-on <id> --json
Soft reset (branch pointer only) muse reset HEAD~1 --json
Hard reset (branch + working tree) muse reset HEAD~1 --hard --json
Preview reset without writing muse reset HEAD~3 --dry-run --json
Restore working-tree file from HEAD muse restore a.py --json
Unstage a file (reset stage to HEAD) muse restore --staged a.py --json
Full restore: stage + working tree muse restore --staged --worktree a.py --json
Restore from an arbitrary ref muse restore --source HEAD~3 a.py b.py --json
Stream filtered commit IDs muse rev-list HEAD --json / muse rev-list -n 10 HEAD --json
Count commits in a range muse rev-list --count main..feat --json
Filter by author or date muse rev-list --author alice --after 2026-01-01 HEAD --json
Resolve ref to full commit ID muse rev-parse HEAD --json / muse rev-parse main --json
Get current branch name muse rev-parse --abbrev-ref HEAD --json
Revert a commit (creates new commit) muse revert HEAD --json
Revert to working tree only (no commit) muse revert HEAD --no-commit --json
Preview revert without writing muse revert HEAD --dry-run --json
Remove file from tracking + disk muse rm song.txt --json
Untrack file (keep on disk) muse rm --cached compiled/app.css --json
Recursive untrack of directory muse rm -r --cached build/ --json
Cherry-pick a symbol from a commit muse code semantic-cherry-pick "src/billing.py::compute_total" --from abc123 --json
Cherry-pick multiple symbols muse code semantic-cherry-pick "src/auth.py::validate_token" "src/auth.py::refresh_token" --from feat --json
Preview semantic cherry-pick muse code semantic-cherry-pick "src/core.py::Fn" --from HEAD~5 --dry-run --json
Static symbol-level test coverage muse code semantic-test-coverage --json
Coverage for one file muse code semantic-test-coverage --file billing.py --json
Show only uncovered symbols muse code semantic-test-coverage --uncovered-only --json
CI coverage gate muse code semantic-test-coverage --min-coverage 80 --json
Partition codebase into work zones muse coord shard --agents 4 --json
Shard for a specific language muse coord shard --agents 4 --language Python --json
Shard at a historical commit muse coord shard --agents 8 --commit HEAD~10 --json
Save working-tree checkpoint muse shelf save --json / muse shelf save name --intent-type handoff -m "desc" --json
List all shelf entries muse shelf list --json / muse shelf list --resumable --json
Inspect a shelf entry muse shelf read --json / muse shelf read name --json
Preview what a shelf apply would change muse shelf diff --json / muse shelf diff name --json
Restore shelf entry (keep entry) muse shelf apply --json / muse shelf apply name --json
Restore shelf entry and remove it muse shelf pop --json / muse shelf pop name --json
Discard a shelf entry muse shelf drop --json / muse shelf drop name --json
Commit summary by author muse shortlog --json / muse shortlog --numbered --json
Commit summary by agent muse shortlog --group-by agent --json
Commit summary by model muse shortlog --group-by model --numbered --json
List all branch refs muse show-ref --json / muse show-ref --pattern 'refs/heads/task/*' --json
Check if a ref exists muse show-ref --verify refs/heads/feat/my-task --json
Show HEAD ref muse show-ref --head --json
Count all branches muse show-ref --count --json
Produce an MSign Authorization header muse sign header --method POST --path /owner/repo/push --hub URL --json
Verify an MSign header muse sign verify --header 'MSign ...' --method POST --url URL --public-key-b64 KEY --json
Sign and execute an HTTP request muse sign request --method POST --url URL --body-file payload.json --json
Sign an MPay micropayment muse sign payment --from alice --to bob --amount 1000000 --nonce HEX --json
Capture working-tree checkpoint muse snapshot create --json / muse snapshot create -m "before refactor" --json
List all snapshots muse snapshot list --json / muse snapshot list -n 5 --json
Inspect a snapshot manifest muse snapshot read sha256:abc123 --json
Export snapshot as archive muse snapshot export sha256:abc123 --json / muse snapshot export sha256:abc123 -f zip -o out.zip --json
Diff two snapshots muse snapshot-diff main dev --json / muse snapshot-diff sha256:abc sha256:def --json
Diff — only added files muse snapshot-diff main dev --only added --json
Diff — scope to subdirectory muse snapshot-diff main dev --path-prefix src/ --json
Attach a tag to a commit muse tag add emotion:joyful --json / muse tag add section:chorus HEAD --json
List all tags muse tag list --json / muse tag list --match 'emotion:*' --json
Remove a tag muse tag remove emotion:joyful --json
List all symbols in a file muse code symbols --file src/utils.py --json
List symbols by kind muse code symbols --kind function --json
Read HEAD symbolic ref muse symbolic-ref HEAD --json
Point HEAD at a branch muse symbolic-ref HEAD --set main --json
Track a symbol's full lifecycle muse code symbol-log "file.py::Fn" --json
Symbol log since a tag muse code symbol-log "file.py::Fn" --from v1.0.0 --json
Switch to existing branch muse switch feat --json
Create and switch (with intent) muse switch -c task/x --intent "implement X" --resumable --json
Return to previous branch muse switch - --json
Working-tree status muse status --json / muse status --exit-code --json
Branch + upstream info only muse status --branch --json
Find most stable (unchanged) symbols muse code stable --json / muse code stable --top 20 --json
Stable symbols since a release muse code stable --since v2.0.0 --json
Enable sparse-checkout (cone mode) muse sparse-checkout init --json
Enable sparse-checkout (glob mode) muse sparse-checkout init --no-cone --json
Replace active pattern list muse sparse-checkout set 'src/' 'tests/' --json
Append patterns to sparse config muse sparse-checkout add 'docs/' --json
List active patterns muse sparse-checkout list --json
Count matching vs. excluded files muse sparse-checkout stats --json
Disable sparse-checkout muse sparse-checkout disable --json
Type-health report for HEAD muse code type --json
Trace Any-annotation blast radius muse code type --any-blast-radius billing.py::compute --json
Type coverage trend over commits muse code type --drift --json
Rank untyped symbols by typing ROI muse code type --migration-targets --top 10 --json
Type-signature diff since a ref muse code type --diff HEAD~5 --json
Run tests for changed files muse code test --json
Run one test file python3 -m pytest tests/test_foo.py -q --tb=short
List trusted paths muse trust list --json
Add a trusted path muse trust add /path/to/repo --json
Remove a trusted path muse trust remove /path/to/repo --json
List trusted hub fingerprints muse trust hub-list --json
Reset a hub fingerprint muse trust hub-reset hostname --json
Unpack a MPack from stdin muse unpack-objects --json
Move a branch HEAD (low-level) muse update-ref main sha256:<id> --json
Compare-and-swap branch update muse update-ref main sha256:<new> --old-value sha256:<expected> --json
Symbol growth rate by module muse code velocity --json
Whole-repo integrity check muse verify --json / muse verify --no-objects --json
Verify Ed25519 commit signatures muse verify-commit HEAD --json
Verify stored object integrity muse verify-object --all --json
Verify a MPack muse verify-pack --file bundle.muse --json
Verify tag signatures muse verify-tag v1.0 --json
Stream coordination events muse coord watch --json / muse coord watch --once --json
Add workspace member muse workspace add core https://musehub.ai/acme/core --json
List workspace members muse workspace list --json
Workspace member status muse workspace status --json
Remove workspace member muse workspace remove core --json
Sync workspace members muse workspace sync --workers 8 --json
List worktrees muse worktree list --json
Create linked worktree muse worktree add feat-x feat/x --json
Worktree status muse worktree status feat-x --json
Remove a worktree muse worktree remove feat-x --json
Prune stale worktree records muse worktree prune --json
Repair worktree paths muse worktree repair --json
Rebuild code intelligence indexes muse code index rebuild --json
Index rebuild dry-run muse code index rebuild --dry-run --json
Index status muse code index status --json
Purge indexes muse code index purge --json

Trigger phrases → commands

When you find yourself thinking this… run this instead.

Thought Command
"Let me read the whole file to understand it" muse code symbols --file f.py --json → then muse code cat "f.py::X" --json for the symbol you need
"Where is this function defined?" muse code grep "FunctionName" --json
"I wonder which branch has the latest version" muse code find-symbol "Name" --json
"What would break if I change this?" muse code impact "file.py::Symbol" --json
"What does this file import?" muse code deps "file.py" --json
"Which functions change most often?" muse code hotspots --top 10 --json
"What is the most dangerous symbol to touch?" muse code gravity --top 1 --json
"Are these two files suspiciously coupled?" muse code entangle --json
"Is there dead code I can delete?" muse code dead --high-confidence-only --json
"What tests cover this symbol?" muse code semantic-test-coverage --json
"Is it safe to commit?" muse code breakage --json && muse code test --json

Eight questions, eight commands — do not confuse them

  • muse code grep "X" — find symbols whose name matches X (declarations only)
  • muse code find-symbol "X" — same, but searches across all branches (multi-branch discovery)
  • muse code impact "file.py::X" — find everything that calls or imports X (blast radius)
  • muse code deps "file.py" — find what file.py imports (outbound dependency graph)
  • muse code hotspots — find symbols that change most often (churn leaderboard)
  • muse code gravity — find symbols with the largest downstream blast radius (change risk)
  • muse code entangle — find file pairs that always change together (hidden coupling)
  • muse code dead — find symbols that are never called (safe to delete)

Task-typed rituals

Before modifying a symbol

muse code grep "SymbolName" --json              # confirm declaration location
muse code cat "file.py::Symbol" --json          # read the current body
muse code impact "file.py::Symbol" --json       # map blast radius
muse code semantic-test-coverage --json         # what tests already cover it?

Before a refactor

muse code gravity --top 20 --json               # which symbols carry the most risk?
muse code hotspots --top 20 --json              # which symbols are most volatile?
muse code entangle --json                       # which files move together?
muse code deps "file.py" --json                 # outbound dependency map
muse code breakage --json                       # current structural health

Before deleting a symbol or file

muse code impact "file.py::Symbol" --json       # blast radius — anything still calls it?
muse code dead --high-confidence-only --json    # confirm dead-code classification

Before merging / releasing

muse code breakage --json                       # structural safety gate
muse code test --json                           # tests for what changed
muse code hotspots --top 5 --json               # flag high-churn symbols for review

muse read --json — what the output contains

muse read --json gives commit metadata and a file-level diff (files_added, files_modified, files_removed). It does not include the full snapshot manifest by default.

To get the complete path → object_id map for every tracked file at that commit, add --manifest:

muse read --json --manifest          # HEAD
muse read <ref> --json --manifest    # any commit or branch tip

The manifest key is absent unless --manifest is given — default JSON stays compact.

muse cat vs muse code cat — two different commands

Command Level Use for
muse cat file.py --json File-level Raw file bytes — any domain
muse code cat "file.py::Symbol" --json Symbol-level One function/class body
muse code cat "file.py" --all --json Symbol-level All symbols in a file

muse cat accepts --at <branch|sha> for historical reads. muse code cat accepts --at too.


Gitism Glossary

Every wrong pattern on the left is burned into agent training data from Git.

JSON key names

Git term / wrong key Muse JSON key Location
sha / hash / id commit_id everywhere
msg / commit_message message muse log, muse read
date / timestamp / time committed_at muse log, muse read
parent parent_commit_id muse log, muse read
entries / log / data commits muse log
active / checked_out current muse branch
branch_name name muse branch list entries
index as integer string keys "1", "2" muse code impact blast_radius
callers / caller_list blast_radius["1"] muse code impact
coverage coverage_pct muse code semantic-test-coverage
churn changes muse code hotspots
score / risk_score gravity_pct muse code gravity
files (combined) added + modified + deleted muse diff, muse status
muse log top-level { "truncated": bool, "commits": [...] } muse log --json
muse branch top-level a list — no wrapper key muse branch --json
muse hub repo list top-level { "total": N, "next_cursor": null, "repos": [...] } muse hub repo list --json
blast_radius key type strings "1" "2" — not integers muse code impact

Deletion muscle memory — git rmmuse rm

Git has two patterns for staging a file deletion. Both have exact Muse equivalents:

Git reflex Muse equivalent Effect
git rm <file> muse rm <file> delete from disk and stage deletion
git rm --cached <file> muse rm --cached <file> stage deletion only (keep on disk)
git rm -r <dir> muse rm -r <dir> recursive — required for directories
git add <deleted-path> muse code add <deleted-path> stage deletion of already-deleted file
git add -u muse code add -u stage all tracked changes incl. deletions
git add . muse code add . stage all tracked changes incl. deletions

The wrong reflex that burns agents: reaching for muse code add --deleted (flag doesn't exist) or muse code reset <file> (that unstages — the opposite of what you want).

Rule: deleting a file in a task? Use muse rm <file> — it does the rm and stages the deletion in one step. muse code add <path> also works if the file is already gone from disk, but muse rm is clearer intent.

muse status --json — always the same shape

The schema is identical regardless of domain or staging state. Every key is always present — no dict.get guards needed.

{
  "branch":             "dev",
  "head_commit":        "sha256:abc…",
  "upstream":           null,
  "ahead":              null,
  "behind":             null,
  "clean":              true,
  "dirty":              false,
  "total_changes":      0,
  "untracked_count":    0,
  "added":              [],
  "modified":           [],
  "deleted":            [],
  "renamed":            {},
  "staged":             {"added": [], "modified": [], "deleted": []},
  "unstaged":           {"added": [], "modified": [], "deleted": []},
  "untracked":          [],
  "conflict_paths":     [],
  "merge_in_progress":  false,
  "merge_from":         null,
  "conflict_count":     0,
  "checkout_interrupted": false,
  "checkout_target":    null
}

Key rules:

  • added / modified / deleted — flat union of staged + unstaged. Primary interface for "what changed".
  • staged / unstaged{added, modified, deleted} sub-objects for staging detail. null for domains with no staging concept (non-code domains).
  • untracked — files on disk not tracked by Muse. Non-empty list makes clean=false.
  • untracked_countlen(untracked). Use this when you need to distinguish "only untracked files" (total_changes == 0 and untracked_count > 0) from "tracked changes" (total_changes > 0). Do not check dirty alone for this.
  • total_changes — counts only tracked-file changes (len(added) + len(modified) + len(deleted) + len(renamed)). It is not a count of all dirtiness — total_changes == 0 with dirty == true means only untracked files are present.
  • cleantrue only when no staged changes, no unstaged changes, and no untracked files. Matches git: "untracked files present" is not a clean working tree.
  • dirty — always not clean.

Git muscle-memory traps for muse status --json:

Git reflex What Muse actually has
data["index"] or data["worktree"] (git status --porcelain=v2) data["staged"] / data["unstaged"]
"untracked" in data as a flag data["untracked"] is always a list
data["staged"] is a path→object map data["staged"] is {added, modified, deleted} lists
dirty means only tracked-content changes dirty is also true when untracked files exist

Hub command shape — noun then verb, not verb-noun

Git flattens everything to git <verb> or gh <verb>-<noun>. Muse uses muse hub <noun> <verb>. The wrong reflex produces commands that don't exist.

Wrong reflex (git/gh pattern) Correct Muse command
muse hub delete-repo muse hub repo delete
muse hub create-repo muse hub repo create
muse hub list-repos muse hub repo list
muse hub show-repo muse hub repo read
muse hub get-repo muse hub repo read
muse hub update-repo muse hub repo update
muse hub transfer-repo muse hub repo transfer-ownership
muse hub create-issue muse hub issue create
muse hub list-issues muse hub issue list
muse hub show-issue muse hub issue read
muse hub get-issue muse hub issue read
muse hub close-issue muse hub issue update <n> --status closed
muse hub reopen-issue muse hub issue update <n> --status open
muse hub comment-issue muse hub issue comment <n> --body "..."
muse hub assign-issue muse hub issue assign <n> --assignee <handle>
muse hub label-issue muse hub issue label <n> --set <label>
muse hub create-proposal muse hub proposal create
muse hub merge-proposal muse hub proposal merge
muse hub list-proposals muse hub proposal list
muse hub show-proposal muse hub proposal read
muse hub get-proposal muse hub proposal read
muse hub review-proposal muse hub proposal review submit --verdict approve
muse hub request-reviewer muse hub proposal reviewer request <id> <handle>
muse hub add-label muse hub label create
muse hub list-labels muse hub label list
muse hub delete-label muse hub label delete --name <name>
muse hub add-collaborator muse hub collaborator invite <handle>
muse hub list-collaborators muse hub collaborator list
muse hub remove-collaborator muse hub collaborator remove <handle>
muse hub create-webhook muse hub webhook create --url <url> --events push
muse hub list-webhooks muse hub webhook list
muse hub delete-webhook muse hub webhook delete <webhook-id>
muse hub create-release muse hub release create --tag v1.0.0
muse hub list-releases muse hub release list
muse hub get-release muse hub release read <tag>
muse hub delete-release muse hub release delete <tag>
muse hub fork-repo muse hub fork create --repo owner/repo
muse hub list-forks muse hub fork list --repo owner/repo
muse hub get-user muse hub user read <handle>
muse hub update-user muse hub user update <handle> --bio "..."
muse hub list-topics muse hub topic list
muse hub set-topics muse hub topic set --topic jazz --topic midi

Always check muse hub <noun> --help when unsure — the subcommand tree is the canonical reference, not any git/gh mental model.

muse hub — full command reference

Every command returns a JSON envelope with muse_version, schema, exit_code, duration_ms, timestamp, warnings plus domain fields. Always pipe --json output through jq or Python — never parse text.

Connection

muse hub connect --hub https://localhost:1337 --json
muse hub status --json
muse hub ping --json
muse hub disconnect --json

Repos

muse hub repo create --name muse --visibility public --json
muse hub repo list --json | jq '.repos[].slug'
muse hub repo read --json                          # reads current repo
muse hub repo update --description "new desc" --json
muse hub repo delete --json
muse hub repo transfer-ownership --to carol --json

Proposals (= pull requests)

muse hub proposal create --title "feat: x" --from-branch feat/x --json
muse hub proposal list --state open --json | jq '.proposals[].proposalId'
muse hub proposal read af54753d --json
muse hub proposal merge af54753d --strategy squash --json
muse hub proposal comment create af54753d --body "LGTM" --json
muse hub proposal comment list af54753d --json
muse hub proposal reviewer request af54753d alice --json
muse hub proposal reviewer remove af54753d alice --json
muse hub proposal review list af54753d --json
muse hub proposal review submit af54753d --verdict approve --json

Issues

muse hub issue create --title "bug: crash" --label bug --json
muse hub issue list --state open --json | jq '.issues[].number'
muse hub issue read 42 --json
muse hub issue update 42 --status closed --json
muse hub issue close 42 --json
muse hub issue reopen 42 --json
muse hub issue comment 42 --body "Fixed in abc" --json
muse hub issue comment-list 42 --json
muse hub issue comment-delete 42 --comment-id <id> --json
muse hub issue assign 42 --assignee gabriel --json
muse hub issue label 42 --set bug enhancement --json

Labels

muse hub label create --name bug --color '#d73a4a' --json
muse hub label list --json | jq '.labels[].name'
muse hub label update --name bug --new-color '#b60205' --json
muse hub label delete --name obsolete --json

Collaborators

muse hub collaborator list --json
muse hub collaborator invite carol --permission write --json
muse hub collaborator update-permission carol --permission admin --json
muse hub collaborator remove carol --json

Webhooks

muse hub webhook create --url https://ci.example.com/hook --events push --json
muse hub webhook list --json
muse hub webhook delete <webhook-id> --json
muse hub webhook delivery-list --webhook-id <id> --json
muse hub webhook redeliver --webhook-id <id> --delivery-id <id> --json

Releases

muse hub release create --tag v1.0.0 --title "First release" --json
muse hub release list --json | jq '.releases[].tag'
muse hub release read v1.0.0 --json
muse hub release delete v1.0.0 --json
muse hub release asset-list v1.0.0 --json
muse hub release asset-attach v1.0.0 --name track.mid --url <url> --json
muse hub release asset-delete v1.0.0 --asset-id <id> --json

Users, topics, forks

muse hub user read gabriel --json
muse hub user update gabriel --bio "Composer" --json
muse hub topic list --query jazz --json
muse hub topic set --topic jazz --topic midi --json
muse hub fork create --repo gabriel/muse --json
muse hub fork list --repo gabriel/muse --json

git stashmuse shelf

Git's stash is delta-based and unnamed. Muse shelf is snapshot-based, content-addressed, and optionally named. Every subcommand maps directly:

Git reflex Muse equivalent Notes
git stash muse shelf save Shelves all tracked changes
git stash push -m "msg" muse shelf save -m "msg" Named shelf entry
git stash pop muse shelf pop Restore + drop most recent entry
git stash list muse shelf list --json All entries; structured output
git stash drop muse shelf drop Delete most recent without restoring
git stash show muse shelf show --json Inspect the top entry
git stash apply stash@{n} muse shelf pop --index <n> Restore by index

Rule: never reach for stash as a verb or concept — it is a Gitism. Use shelf / shelve / shelved in all code, comments, and docs.

File History 2 commits
sha256:b5ec4e4a3a73cae0cd08224f32090f2a4836afa0a804cb3231e70c42a3e89295 fix adapter for agent config Human patch 4 days ago
sha256:99f8eb388d9a9c353e68b9a4e5bebe1b4240a8f511e6f0928e58c0e95153e103 feat: branch --prune-config, fix hub repo delete docstrings… Sonnet 4.6 minor 5 days ago