omzsh-plugin.md
markdown
| 1 | # Muse Oh My ZSH Plugin — Full Reference |
| 2 | |
| 3 | This document is the complete reference for the Muse Oh My ZSH plugin. For a quick-start guide see [`tools/omzsh-plugin/README.md`](../../tools/omzsh-plugin/README.md). |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Architecture |
| 8 | |
| 9 | The plugin is divided into 14 sections (§0–§13) inside `tools/omzsh-plugin/muse.plugin.zsh`. The companion file `tools/omzsh-plugin/_muse` contains the ZSH completion function. |
| 10 | |
| 11 | ### Performance model |
| 12 | |
| 13 | The prompt segment must never block the shell. The plugin achieves this by: |
| 14 | |
| 15 | 1. **Zero-subprocess file reads** for branch (`.muse/HEAD`), merge state (`.muse/MERGE_STATE.json`), and domain (`.muse/repo.json`) — all raw file reads inside ZSH. |
| 16 | 2. **One python3 subprocess** per full refresh for JSON/TOML parsing (domain, user type, merge state, SemVer). This is batched into a single call. |
| 17 | 3. **One muse subprocess** for dirty detection (`muse status --porcelain`), guarded by `$MUSE_DIRTY_TIMEOUT`. Only runs after a muse command (`$_MUSE_CMD_RAN=1`) or on a cold cache. |
| 18 | 4. **Cached state** in `$MUSE_*` env vars, invalidated by `chpwd` and `preexec`. |
| 19 | |
| 20 | ``` |
| 21 | chpwd ─────────────────────────────────► invalidate → _muse_refresh_fast |
| 22 | (head + meta only) |
| 23 | preexec (muse cmd) ─► _MUSE_CMD_RAN=1 |
| 24 | precmd ─────────────────────────────────► _MUSE_CMD_RAN? → _muse_refresh |
| 25 | (full: + dirty + semver) |
| 26 | _MUSE_CACHE_VALID=0? → _muse_refresh |
| 27 | ``` |
| 28 | |
| 29 | ### Environment variables |
| 30 | |
| 31 | All `$MUSE_*` variables are exported and visible to subprocesses. This is the machine-to-machine interface — an orchestrating AI agent can read any of these. |
| 32 | |
| 33 | | Variable | Type | Content | |
| 34 | |---|---|---| |
| 35 | | `MUSE_REPO_ROOT` | string | Absolute path to the repo root, or `""` | |
| 36 | | `MUSE_DOMAIN` | string | Active domain plugin (`midi`, `code`, `bitcoin`, …) | |
| 37 | | `MUSE_BRANCH` | string | Current branch name, or 8-char SHA if detached | |
| 38 | | `MUSE_DETACHED` | 0/1 | 1 when HEAD is detached | |
| 39 | | `MUSE_DIRTY` | 0/1 | 1 when working tree has uncommitted changes | |
| 40 | | `MUSE_DIRTY_COUNT` | integer | Number of changed paths | |
| 41 | | `MUSE_DIRTY_STATE` | string | `"clean"` \| `"dirty"` \| `"?"` (timeout) | |
| 42 | | `MUSE_MERGING` | 0/1 | 1 when `MERGE_STATE.json` exists | |
| 43 | | `MUSE_MERGE_BRANCH` | string | The branch being merged in | |
| 44 | | `MUSE_CONFLICT_COUNT` | integer | Number of conflict paths | |
| 45 | | `MUSE_USER_TYPE` | string | `"human"` \| `"agent"` (from `config.toml`) | |
| 46 | | `MUSE_LAST_SEMVER` | string | `"major"` \| `"minor"` \| `"patch"` \| `""` | |
| 47 | | `MUSE_CONTEXT_JSON` | JSON string | Full compact context (see below) | |
| 48 | | `MUSE_SESSION_MODEL_ID` | string | Active agent session model | |
| 49 | | `MUSE_SESSION_AGENT_ID` | string | Active agent session ID | |
| 50 | | `MUSE_SESSION_START` | ISO-8601 | When the agent session started | |
| 51 | | `MUSE_SESSION_LOG_FILE` | path | Path to the active session `.jsonl` log | |
| 52 | |
| 53 | --- |
| 54 | |
| 55 | ## Prompt Functions |
| 56 | |
| 57 | ### `muse_prompt_info()` |
| 58 | |
| 59 | Primary left-prompt segment. Outputs nothing if not in a muse repo. |
| 60 | |
| 61 | **Human mode** (default): |
| 62 | ``` |
| 63 | ♪ midi:main ✓ |
| 64 | ♪ midi:feat/x ✗ 3Δ |
| 65 | ♪ midi:main ⚡ ← feature/exp (2 conflicts) |
| 66 | ♪ midi:main ✓ [🤖 claude-4.6-sonnet] |
| 67 | ``` |
| 68 | |
| 69 | **Agent mode** (`MUSE_AGENT_MODE=1`): |
| 70 | ``` |
| 71 | [midi|main|clean|no-merge] |
| 72 | [midi|main|dirty:3|merging:feature/exp:2|agent:coding-assistant] |
| 73 | ``` |
| 74 | |
| 75 | ### `muse_rprompt_info()` |
| 76 | |
| 77 | Right-prompt SemVer indicator. Shows the `sem_ver_bump` field of the HEAD commit. |
| 78 | |
| 79 | ``` |
| 80 | [MINOR] (yellow) |
| 81 | [MAJOR] (red) |
| 82 | [PATCH] (green) |
| 83 | ``` |
| 84 | |
| 85 | ### `prompt_muse_vcs()` and `instant_prompt_muse_vcs()` |
| 86 | |
| 87 | Powerlevel10k segment implementations. Use by adding `muse_vcs` to |
| 88 | `POWERLEVEL9K_LEFT_PROMPT_ELEMENTS` or `POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS`. |
| 89 | |
| 90 | --- |
| 91 | |
| 92 | ## Workflow Functions |
| 93 | |
| 94 | ### Branch creation |
| 95 | |
| 96 | ```zsh |
| 97 | muse-new-feat <name> # creates and switches to feat/<name> |
| 98 | muse-new-fix <name> # creates and switches to fix/<name> |
| 99 | muse-new-refactor <name> # creates and switches to refactor/<name> |
| 100 | ``` |
| 101 | |
| 102 | ### Commits |
| 103 | |
| 104 | ```zsh |
| 105 | muse-wip |
| 106 | ``` |
| 107 | Commits with message `[WIP] 2026-03-20T14:30:00Z`. Useful for checkpointing |
| 108 | before switching context. |
| 109 | |
| 110 | ```zsh |
| 111 | muse-quick-commit |
| 112 | ``` |
| 113 | Interactive guided commit. Prompts for message and domain-specific metadata: |
| 114 | - **midi**: section (verse/chorus/bridge), track name, emotion |
| 115 | - **code**: module/package, breaking change flag |
| 116 | |
| 117 | ```zsh |
| 118 | muse-agent-commit "message" [extra flags…] |
| 119 | ``` |
| 120 | Wraps `muse commit` and auto-injects `--agent-id` and `--model-id` from the |
| 121 | active agent session (`$MUSE_SESSION_AGENT_ID`, `$MUSE_SESSION_MODEL_ID`). |
| 122 | Use this instead of bare `muse commit` when inside an agent session. |
| 123 | |
| 124 | ### Sync & merge |
| 125 | |
| 126 | ```zsh |
| 127 | muse-sync |
| 128 | ``` |
| 129 | Runs `muse fetch && muse pull && muse status` in sequence. |
| 130 | |
| 131 | ```zsh |
| 132 | muse-safe-merge <branch> |
| 133 | ``` |
| 134 | Runs `muse merge`. If conflicts occur, prints a structured conflict list and |
| 135 | optionally opens conflict paths in `$EDITOR`. |
| 136 | |
| 137 | ### Health & provenance |
| 138 | |
| 139 | ```zsh |
| 140 | muse-health |
| 141 | ``` |
| 142 | Shows a formatted health summary: dirty state, merge state, stash count, configured remotes, domain, user type, active agent session. |
| 143 | |
| 144 | ```zsh |
| 145 | muse-who-last |
| 146 | ``` |
| 147 | Shows authorship provenance of the HEAD commit. Distinguishes human vs agent authorship and shows model ID if present. |
| 148 | |
| 149 | ```zsh |
| 150 | muse-agent-blame [N] |
| 151 | ``` |
| 152 | Scans the last N commits (default 10) and prints a provenance table: |
| 153 | |
| 154 | ``` |
| 155 | Agent provenance — last 10 commits on main |
| 156 | SHA Date Type Author/Model Message |
| 157 | ────────── ────────── ────── ────────────────────────────── ────────────── |
| 158 | a1b2c3d4 2026-03-20 agent claude-4.6-sonnet Refactor notes |
| 159 | e5f6a7b8 2026-03-19 human gabriel Add bass track |
| 160 | ``` |
| 161 | |
| 162 | ```zsh |
| 163 | muse-overview |
| 164 | ``` |
| 165 | Domain-specific live state overview. Calls `muse midi notes` for MIDI repos, |
| 166 | `muse code symbols` for code repos. |
| 167 | |
| 168 | --- |
| 169 | |
| 170 | ## Agent-Native Functions |
| 171 | |
| 172 | ### `muse-context [--json|--toml|--oneline]` |
| 173 | |
| 174 | Outputs a compact, token-efficient repo context block. Designed to be injected |
| 175 | into an AI agent's context window. |
| 176 | |
| 177 | **Default (human)**: |
| 178 | ``` |
| 179 | MUSE REPO CONTEXT ♪ midi:main |
| 180 | ────────────────────────────────────────────────────── |
| 181 | domain midi |
| 182 | branch main |
| 183 | commit a1b2c3d4 "Add verse melody" (2026-03-20) |
| 184 | last author gabriel [human] |
| 185 | semver MINOR |
| 186 | dirty yes — 3 changed |
| 187 | merging no |
| 188 | remotes origin |
| 189 | user human |
| 190 | ``` |
| 191 | |
| 192 | **`--json`**: pretty-printed JSON (uses `$MUSE_CONTEXT_JSON` as source) |
| 193 | |
| 194 | **`--toml`**: TOML format (two sections: `[repo]` and `[commit]`) |
| 195 | |
| 196 | **`--oneline`**: `midi:main dirty:3 commit:a1b2c3d4` |
| 197 | |
| 198 | ### `muse-agent-session <model_id> [agent_id]` |
| 199 | |
| 200 | Begins a named agent session: |
| 201 | - Exports `$MUSE_SESSION_MODEL_ID`, `$MUSE_SESSION_AGENT_ID`, `$MUSE_SESSION_START` |
| 202 | - Creates a `.jsonl` session log in `$MUSE_SESSION_LOG_DIR` |
| 203 | - Exports `$MUSE_SESSION_LOG_FILE` pointing to the log |
| 204 | - Updates the prompt to show `[🤖 <model_id>]` |
| 205 | |
| 206 | ```zsh |
| 207 | muse-agent-session claude-4.6-sonnet coding-assistant |
| 208 | # model claude-4.6-sonnet |
| 209 | # agent coding-assistant |
| 210 | # log ~/.muse/sessions/20260320-143000-12345.jsonl |
| 211 | ``` |
| 212 | |
| 213 | ### `muse-agent-end` |
| 214 | |
| 215 | Ends the current session, writes a `session_end` entry to the log, unsets all |
| 216 | `$MUSE_SESSION_*` variables, and refreshes the prompt. |
| 217 | |
| 218 | ### `muse-sessions [file]` |
| 219 | |
| 220 | Without arguments: lists the 20 most recent session `.jsonl` files with model ID, agent ID, and start time. |
| 221 | |
| 222 | With a file argument: replays the session log, showing each command with its timestamp, exit code, and elapsed milliseconds: |
| 223 | |
| 224 | ``` |
| 225 | 2026-03-20T14:23:11 SESSION START model=claude-4.6-sonnet agent=coding-assistant |
| 226 | 2026-03-20T14:23:15 $ muse status |
| 227 | 2026-03-20T14:23:16 EXIT 0 (312ms) |
| 228 | 2026-03-20T14:23:20 $ muse commit -m "Refactor velocity normalisation" |
| 229 | 2026-03-20T14:23:21 EXIT 0 (891ms) |
| 230 | 2026-03-20T14:24:00 SESSION END |
| 231 | ``` |
| 232 | |
| 233 | ### Session log format |
| 234 | |
| 235 | Each `.jsonl` file contains one JSON object per line: |
| 236 | |
| 237 | ```jsonl |
| 238 | {"t":"2026-03-20T14:23:11Z","event":"session_start","model_id":"claude-4.6-sonnet","agent_id":"coding-assistant","domain":"midi","branch":"main","repo_root":"/proj","pid":12345} |
| 239 | {"t":"2026-03-20T14:23:15Z","cmd":"muse status","cwd":"/proj","domain":"midi","branch":"main","pid":12345} |
| 240 | {"t":"2026-03-20T14:23:16Z","event":"cmd_end","exit":0,"elapsed_ms":312} |
| 241 | {"t":"2026-03-20T14:24:00Z","event":"session_end","model_id":"claude-4.6-sonnet","agent_id":"coding-assistant","start":"2026-03-20T14:23:11Z"} |
| 242 | ``` |
| 243 | |
| 244 | The `cmd_end` entry always immediately follows the `cmd` entry it closes. All timestamps are UTC ISO-8601. |
| 245 | |
| 246 | --- |
| 247 | |
| 248 | ## Visual Tools |
| 249 | |
| 250 | ### `muse-graph [log flags…]` |
| 251 | |
| 252 | Wraps `muse log --graph --oneline` with Python-driven ANSI colorisation: |
| 253 | |
| 254 | - Graph chrome (`*`, `|`, `/`, `\`) coloured with the domain's theme colour |
| 255 | - Commit SHAs highlighted in yellow |
| 256 | - `HEAD -> branch` highlighted in bold green |
| 257 | - `[MAJOR]` in red, `[MINOR]` in yellow, `[PATCH]` in green |
| 258 | - `[agent:id]` markers in cyan |
| 259 | |
| 260 | Passes any extra flags through to `muse log`: |
| 261 | |
| 262 | ```zsh |
| 263 | muse-graph -n 20 |
| 264 | muse-graph --since "2026-01-01" |
| 265 | ``` |
| 266 | |
| 267 | ### `muse-timeline [N]` |
| 268 | |
| 269 | Vertical timeline of the last N commits (default 20). Uses domain colours and Unicode box-drawing characters: |
| 270 | |
| 271 | ``` |
| 272 | ♪ TIMELINE — main (last 5 commits) |
| 273 | ──────────────────────────────────────────────────────────── |
| 274 | ◉ a1b2c3d4 Add verse melody |
| 275 | │ |
| 276 | ○ e5f6a7b8 Transpose chorus up 2 semitones |
| 277 | │ |
| 278 | ○ c9d0e1f2 Add bass line |
| 279 | │ |
| 280 | ○ a3b4c5d6 Initial commit |
| 281 | ╵ |
| 282 | ``` |
| 283 | |
| 284 | ### `muse-diff-preview [ref…]` |
| 285 | |
| 286 | Pipes `muse diff` output through `delta` (preferred) or `bat` for syntax |
| 287 | highlighting. Falls back to plain output if neither is installed. |
| 288 | |
| 289 | ### `muse-commit-browser` |
| 290 | |
| 291 | fzf-powered commit browser. Requires `fzf`. |
| 292 | |
| 293 | - Left pane: `muse log --oneline` |
| 294 | - Right pane: `muse show <selected>` preview |
| 295 | - `↵` — checkout the selected commit |
| 296 | - `ctrl-d` — show full diff in `less` |
| 297 | - `ctrl-y` — copy commit SHA to clipboard |
| 298 | - `ctrl-s` — open `muse show` in `less` |
| 299 | |
| 300 | ### `muse-branch-picker` |
| 301 | |
| 302 | fzf-powered branch switcher. Also bound to `Ctrl+B`. Requires `fzf`. |
| 303 | |
| 304 | - Right pane: last 8 commits on the highlighted branch |
| 305 | - `↵` — checkout the selected branch |
| 306 | - `ctrl-d` — delete the selected branch |
| 307 | |
| 308 | ### `muse-stash-browser` |
| 309 | |
| 310 | fzf-powered stash browser. Requires `fzf`. |
| 311 | |
| 312 | - Right pane: `muse stash show` preview |
| 313 | - `↵` — pop the selected stash |
| 314 | - `ctrl-d` — drop the selected stash |
| 315 | |
| 316 | --- |
| 317 | |
| 318 | ## Completion Reference |
| 319 | |
| 320 | ### Top-level commands |
| 321 | |
| 322 | All ~50 top-level muse commands are listed with one-line descriptions. Descriptions are intentionally domain-aware (not generic VCS language). |
| 323 | |
| 324 | ### Per-command argument completion |
| 325 | |
| 326 | | Command | What completes | |
| 327 | |---|---| |
| 328 | | `checkout` | branch names + `-b` flag | |
| 329 | | `merge` | branch names + `--strategy` values | |
| 330 | | `branch` | branch names for `-d`, flags | |
| 331 | | `tag` | tag names, short SHAs | |
| 332 | | `push` | remote names, branch names, `--force` | |
| 333 | | `pull` | remote names, branch names, `--rebase` | |
| 334 | | `fetch` | remote names, branch names, `--all` | |
| 335 | | `remote` | `add/remove/rename/list/show/set-url` → remote names | |
| 336 | | `log` | all flags with values where applicable | |
| 337 | | `diff` | short SHAs + `--stat`/`--patch` | |
| 338 | | `show` | short SHAs | |
| 339 | | `reset` | short SHAs + `--hard`/`--soft` | |
| 340 | | `revert` | short SHAs + `--no-commit` | |
| 341 | | `cherry-pick` | short SHAs | |
| 342 | | `blame` | short SHAs | |
| 343 | | `commit` | `--meta key=val`, `--agent-id`, `--model-id`, `--toolchain-id` | |
| 344 | | `stash` | `push/pop/drop/list/show` | |
| 345 | | `config` | `show/get/set/edit` → config key paths | |
| 346 | | `auth` | `login/logout/whoami` | |
| 347 | | `hub` | `connect/status/disconnect/ping` | |
| 348 | | `worktree` | `add/list/remove/prune` | |
| 349 | | `workspace` | `create/list/switch/delete` | |
| 350 | | `bisect` | `start/good/bad/reset/log` | |
| 351 | | `plumbing` | all 12 plumbing subcommands + context-aware ref/remote/file args | |
| 352 | | `midi` | all 25 midi subcommands with MIDI-specific descriptions | |
| 353 | | `code` | all 28 code subcommands with code-analysis descriptions | |
| 354 | | `coord` | all 6 coordination subcommands | |
| 355 | | `clone` | `--branch`, `--depth`, remote URL, local directory | |
| 356 | | `archive` | `--format (tar/zip)`, `--output`, tree-ish | |
| 357 | | `annotate` | tracked file paths | |
| 358 | | `attributes` | `list/check` → tracked file paths | |
| 359 | |
| 360 | ### Config key completions |
| 361 | |
| 362 | | Key | Description | |
| 363 | |---|---| |
| 364 | | `user.name` | Display name (human or agent handle) | |
| 365 | | `user.email` | Email address | |
| 366 | | `user.type` | `"human"` or `"agent"` | |
| 367 | | `hub.url` | MuseHub fabric endpoint URL | |
| 368 | | `domain.ticks_per_beat` | MIDI ticks per beat | |
| 369 | | `domain.default_channel` | MIDI default channel | |
| 370 | |
| 371 | --- |
| 372 | |
| 373 | ## Hook System |
| 374 | |
| 375 | Set these in `.zshrc` to run custom commands after muse operations: |
| 376 | |
| 377 | ```zsh |
| 378 | # Desktop notification on commit (macOS) |
| 379 | MUSE_POST_COMMIT_CMD='osascript -e "display notification \"Committed\" with title \"Muse\""' |
| 380 | |
| 381 | # Rebuild a local index after checkout |
| 382 | MUSE_POST_CHECKOUT_CMD='make index 2>/dev/null || true' |
| 383 | |
| 384 | # Trigger CI after a clean merge |
| 385 | MUSE_POST_MERGE_CMD='curl -X POST https://ci.example.com/trigger' |
| 386 | ``` |
| 387 | |
| 388 | The `MUSE_POST_MERGE_CMD` fires only after a **clean** merge (no conflicts). During a conflicted merge, the hook is suppressed until you resolve and commit. |
| 389 | |
| 390 | --- |
| 391 | |
| 392 | ## Keybinding Reference |
| 393 | |
| 394 | | Binding | Widget | Action | |
| 395 | |---|---|---| |
| 396 | | `Ctrl+B` | `_muse_widget_branch_picker` | Open fzf branch picker | |
| 397 | | `ESC-M` | `_muse_widget_commit_browser` | Open fzf commit browser | |
| 398 | | `ESC-H` | `_muse_widget_health` | Print repo health and reset prompt | |
| 399 | |
| 400 | Set `MUSE_BIND_KEYS=0` to disable all keybindings. |
| 401 | |
| 402 | --- |
| 403 | |
| 404 | ## Agent Mode Reference |
| 405 | |
| 406 | `MUSE_AGENT_MODE=1` is a master switch that transforms the plugin for agent |
| 407 | orchestration use: |
| 408 | |
| 409 | | Feature | Normal mode | Agent mode | |
| 410 | |---|---|---| |
| 411 | | Prompt | `♪ midi:main ✗ 3Δ` | `[midi\|main\|dirty:3\|no-merge]` | |
| 412 | | `$MUSE_CONTEXT_JSON` | Set silently | Also emitted to stderr before each prompt | |
| 413 | | Emoji | Yes | No (ASCII only) | |
| 414 | | `muse_rprompt_info()` | Shows SemVer | Suppressed | |
| 415 | |
| 416 | Typical use — start a subshell for an agent, set the flag, and have the |
| 417 | orchestrator read `$MUSE_CONTEXT_JSON` from stderr: |
| 418 | |
| 419 | ```python |
| 420 | import subprocess, json |
| 421 | |
| 422 | proc = subprocess.Popen( |
| 423 | ["zsh", "--interactive"], |
| 424 | env={**os.environ, "MUSE_AGENT_MODE": "1"}, |
| 425 | stderr=subprocess.PIPE, |
| 426 | ) |
| 427 | # Each prompt draw emits $MUSE_CONTEXT_JSON to stderr |
| 428 | context = json.loads(proc.stderr.readline()) |
| 429 | print(context["domain"], context["branch"], context["dirty"]) |
| 430 | ``` |
| 431 | |
| 432 | --- |
| 433 | |
| 434 | ## Upgrading |
| 435 | |
| 436 | Because the install script uses symlinks, `git pull` inside the muse repo |
| 437 | automatically updates the plugin. Run `source ~/.zshrc` to pick up changes |
| 438 | in the current shell session. |
| 439 | |
| 440 | --- |
| 441 | |
| 442 | ## Troubleshooting |
| 443 | |
| 444 | **Prompt shows nothing in a muse repo** |
| 445 | |
| 446 | 1. Verify `muse` is in your `$PATH`: `which muse` |
| 447 | 2. Verify you are inside a muse repo: `ls .muse/HEAD` |
| 448 | 3. Check `_MUSE_CACHE_VALID` is being set: `echo $_MUSE_CACHE_VALID` (should be 1) |
| 449 | 4. Run `_muse_refresh` manually and check for errors |
| 450 | |
| 451 | **Dirty check shows `?`** |
| 452 | |
| 453 | The `muse status --porcelain` call timed out. Increase `MUSE_DIRTY_TIMEOUT`: |
| 454 | |
| 455 | ```zsh |
| 456 | MUSE_DIRTY_TIMEOUT=3 # allow 3 seconds before giving up |
| 457 | ``` |
| 458 | |
| 459 | **Completions not showing** |
| 460 | |
| 461 | Ensure the `_muse` file is in your `$fpath`. The install script handles this |
| 462 | via symlinks. If you installed manually, add the plugin directory: |
| 463 | |
| 464 | ```zsh |
| 465 | fpath=("$ZSH_CUSTOM/plugins/muse" $fpath) |
| 466 | autoload -Uz compinit && compinit |
| 467 | ``` |
| 468 | |
| 469 | **`muse-commit-browser` / `muse-branch-picker` not working** |
| 470 | |
| 471 | Install [fzf](https://github.com/junegunn/fzf): `brew install fzf` (macOS) or `apt install fzf` (Debian/Ubuntu). |
| 472 | |
| 473 | **Session logs not written** |
| 474 | |
| 475 | Verify `$MUSE_SESSION_LOG_DIR` exists and is writable: |
| 476 | |
| 477 | ```zsh |
| 478 | mkdir -p "$MUSE_SESSION_LOG_DIR" |
| 479 | ls -la "$MUSE_SESSION_LOG_DIR" |
| 480 | ``` |