gabriel / muse public
README.md markdown
131 lines 3.3 KB
bb2f58b3 docs(omzsh-plugin): update for muse:(domain:branch) format and icon-off… Gabriel Cardona <gabriel@tellurstori.com> 3d ago
1 # Muse — Oh My ZSH Plugin
2
3 Minimal shell integration for [Muse](https://github.com/cgcardona/muse).
4 Shows your active domain and branch in the prompt, mirroring what
5 `git:(branch)` does for Git repos.
6
7 ---
8
9 ## Install
10
11 ```bash
12 bash /path/to/muse/tools/install-omzsh-plugin.sh
13 ```
14
15 Then add `muse` to your `plugins` array in `~/.zshrc`:
16
17 ```zsh
18 plugins=(git muse)
19 ```
20
21 ---
22
23 ## Prompt setup
24
25 Add `$(muse_prompt_info)` wherever you want the indicator in your `PROMPT`:
26
27 ```zsh
28 PROMPT='%~ $(muse_prompt_info) %# '
29 ```
30
31 Inside a Muse repo this renders as:
32
33 ```
34 ~/my-song muse:(midi:main) %
35 ```
36
37 Outside a Muse repo it emits nothing.
38
39 ---
40
41 ## What it shows
42
43 | Segment | Meaning |
44 |---------|---------|
45 | `muse:(midi:main)` | `midi` domain, branch `main` |
46 | `muse:(bitcoin:lightning)` | `bitcoin` domain, branch `lightning` |
47 | `muse:(code:feature/x)` | `code` domain, branch `feature/x` |
48 | `muse:(scaffold:main)` | `scaffold` domain |
49 | `muse:(midi:a1b2c3d4)` | detached HEAD (short SHA) |
50 | `muse:(midi:main) ✗ 3` | dirty working tree, 3 changed paths |
51
52 The dirty indicator (`✗ N`) only appears after you run a `muse` command in the
53 same shell session. This keeps the prompt fast on first open.
54
55 ---
56
57 ## Configuration
58
59 Set these in `~/.zshrc` **before** `plugins=(… muse …)`:
60
61 ```zsh
62 MUSE_PROMPT_ICONS=1 # prepend a domain icon, e.g. ♪ muse:(midi:main)
63 MUSE_DIRTY_TIMEOUT=1 # seconds before dirty check gives up
64 ```
65
66 Domain icons are off by default. To enable and override individual icons:
67
68 ```zsh
69 MUSE_PROMPT_ICONS=1
70 MUSE_DOMAIN_ICONS[midi]="🎵"
71 MUSE_DOMAIN_ICONS[bitcoin]="🔑"
72 ```
73
74 ---
75
76 ## Aliases
77
78 | Alias | Command |
79 |-------|---------|
80 | `mst` | `muse status` |
81 | `msts` | `muse status --short` |
82 | `mcm` | `muse commit -m` |
83 | `mco` | `muse checkout` |
84 | `mlg` | `muse log` |
85 | `mlgo` | `muse log --oneline` |
86 | `mlgg` | `muse log --graph` |
87 | `mdf` | `muse diff` |
88 | `mdfst` | `muse diff --stat` |
89 | `mbr` | `muse branch` |
90 | `mtg` | `muse tag` |
91 | `mfh` | `muse fetch` |
92 | `mpull` | `muse pull` |
93 | `mpush` | `muse push` |
94 | `mrm` | `muse remote` |
95
96 ---
97
98 ## Tab completion
99
100 All top-level `muse` commands and common argument types (branches, tags,
101 remotes, config keys, subcommands) complete with `<TAB>`.
102
103 Completion reads directly from `.muse/refs/` using ZSH globbing — no
104 subprocesses, no `ls`, instant response.
105
106 ---
107
108 ## How it works
109
110 1. **On directory change (`chpwd`)** — walks up to find `.muse/`, reads
111 `.muse/HEAD` (pure ZSH, no subprocess), reads `.muse/repo.json` for the
112 domain (one `python3` call).
113
114 2. **After a `muse` command (`precmd`)** — additionally runs
115 `muse status --porcelain` with a timeout to update the dirty indicator.
116
117 3. **On prompt render** — reads only cached shell variables; zero subprocesses.
118
119 ---
120
121 ## Security model
122
123 - No `eval` of any data from disk or environment.
124 - Branch names are regex-validated (`[a-zA-Z0-9/_.-]` only) and
125 `%`-escaped before prompt interpolation to prevent ZSH prompt injection.
126 - Domain names are validated as alphanumeric (max 32 chars) in Python.
127 - Repo paths are passed to Python via environment variables, never
128 interpolated into `-c` strings.
129 - `cd` and `timeout` calls use `--` to prevent option injection.
130 - Completion uses ZSH glob patterns, never `ls` or command substitution
131 on arbitrary file content.