Muse Ecosystem — Agent Guide
Drop
@path/to/this/fileinto anyCLAUDE.mdor 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
gitorghcall 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:
muse conflicts --json— see what needs resolving- Read the file — understand
<<<<<<< ours,||||||| base,>>>>>>> theirs - Edit the file manually to produce the correct result
muse resolve <path>— mark resolved (stages automatically)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 fingerprint —
SHA-256(sorted(ours_id, theirs_id)). Exact-replay only; different content never matches. - Semantic fingerprint — provided by a
HarmonyPluginimplementation. 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_resolutionstwice with the sameoutcome_blobproduces exactly one resolution — no duplicates. - Symbol-path aware: conflict paths like
config.py::MAX_CONNECTIONSare handled correctly — file portion used for manifest lookups, full address stored in the pattern. - Original conflict paths preserved:
checkout --ours/--theirsclearsconflict_pathsin MERGE_STATE, butoriginal_conflict_pathsis preserved through all writes socommitalways has the full list to learn from. - Path traversal guard:
auto_applyresolves..before any filesystem access — tampered MERGE_STATE cannot escape the repo root. - Human-verified wins:
best_resolutionranks 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:], nopartition(":")inline. Usesplit_sig/split_pubkey/split_id. - Never store or transmit bare bytes — always encode with
encode_sig/encode_pubkeybefore serialisation. split_sigvsdecode_sig: usesplit_sigwhen you need the base64 string (e.g. to pass to another API, embed in JSON, or validate format); usedecode_sigonly when you need raw bytes for cryptographic operations.split_sigvssplit_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
# deprecatedannotations. 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 rm → muse 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.nullfor domains with no staging concept (non-code domains).untracked— files on disk not tracked by Muse. Non-empty list makesclean=false.untracked_count—len(untracked). Use this when you need to distinguish "only untracked files" (total_changes == 0anduntracked_count > 0) from "tracked changes" (total_changes > 0). Do not checkdirtyalone 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 == 0withdirty == truemeans only untracked files are present.clean—trueonly when no staged changes, no unstaged changes, and no untracked files. Matches git: "untracked files present" is not a clean working tree.dirty— alwaysnot 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 stash → muse 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.