gabriel / muse public
README.md markdown
131 lines 3.3 KB
Raw
sha256:660fcac1df3ab28f61862e961890bd2ca8b754fa0242079d93ca1e25037ec8a6 chore(tests): add docstring to tests/__init__.py so rc14 tr… Human 26 days ago

Muse — Oh My ZSH Plugin

Minimal shell integration for Muse. Shows your active domain and branch in the prompt, mirroring what git:(branch) does for Git repos.


Install

bash /path/to/muse/tools/install-omzsh-plugin.sh

Then add muse to your plugins array in ~/.zshrc:

plugins=(git muse)

Prompt setup

Add $(muse_prompt_info) wherever you want the indicator in your PROMPT:

PROMPT='%~ $(muse_prompt_info) %# '

Inside a Muse repo this renders as:

~/my-song muse:(midi:main) %

Outside a Muse repo it emits nothing.


What it shows

Segment Meaning
muse:(midi:main) midi domain, branch main
muse:(bitcoin:lightning) bitcoin domain, branch lightning
muse:(code:feature/x) code domain, branch feature/x
muse:(scaffold:main) scaffold domain
muse:(midi:a1b2c3d4) detached HEAD (short SHA)
muse:(midi:main) ✗ 3 dirty working tree, 3 changed paths

The dirty indicator (✗ N) only appears after you run a muse command in the same shell session. This keeps the prompt fast on first open.


Configuration

Set these in ~/.zshrc before plugins=(… muse …):

MUSE_PROMPT_ICONS=1       # prepend a domain icon, e.g. ♪ muse:(midi:main)
MUSE_DIRTY_TIMEOUT=1      # seconds before dirty check gives up

Domain icons are off by default. To enable and override individual icons:

MUSE_PROMPT_ICONS=1
MUSE_DOMAIN_ICONS[midi]="🎵"
MUSE_DOMAIN_ICONS[bitcoin]="🔑"

Aliases

Alias Command
mst muse status
msts muse status --short
mcm muse commit -m
mco muse checkout
mlg muse log
mlgo muse log --oneline
mlgg muse log --graph
mdf muse diff
mdfst muse diff --stat
mbr muse branch
mtg muse tag
mfh muse fetch
mpull muse pull
mpush muse push
mrm muse remote

Tab completion

All top-level muse commands and common argument types (branches, tags, remotes, config keys, subcommands) complete with <TAB>.

Completion reads directly from .muse/refs/ using ZSH globbing — no subprocesses, no ls, instant response.


How it works

  1. On directory change (chpwd) — walks up to find .muse/, reads .muse/HEAD (pure ZSH, no subprocess), reads .muse/repo.json for the domain (one python3 call).

  2. After a muse command (precmd) — additionally runs muse status --porcelain with a timeout to update the dirty indicator.

  3. On prompt render — reads only cached shell variables; zero subprocesses.


Security model

  • No eval of any data from disk or environment.
  • Branch names are regex-validated ([a-zA-Z0-9/_.-] only) and %-escaped before prompt interpolation to prevent ZSH prompt injection.
  • Domain names are validated as alphanumeric (max 32 chars) in Python.
  • Repo paths are passed to Python via environment variables, never interpolated into -c strings.
  • cd and timeout calls use -- to prevent option injection.
  • Completion uses ZSH glob patterns, never ls or command substitution on arbitrary file content.
File History 3 commits
sha256:660fcac1df3ab28f61862e961890bd2ca8b754fa0242079d93ca1e25037ec8a6 chore(tests): add docstring to tests/__init__.py so rc14 tr… Human 26 days ago
sha256:d8316ffae901be06347e16ab55be11868eb519dd16ade3e8aa16a99e662f7e62 baseline: rc14 re-baseline after rc3 store corruption recovery Human patch 26 days ago
sha256:1c4b3e3a9a1f300774c3ee662b572a698d5fd405bf765a71e6011a2e9c3eaaaa feat: Muse — version control for the agent era Human 101 days ago