wmux: Instructions file for Claude Code

CLAUDE.md

wmux CLAUDE.md is an instructions file for Claude Code from amirlehmam/wmux. It costs 18,193 tokens per session, scanned E, original, MIT.

Repository instructions for the wmux project, a Windows terminal multiplexer for AI agents. They describe its TypeScript, React, Electron, and terminal-related structure and commands.

In plain words
What is it for?
Building and testing wmux, navigating its source folders, following its development guide, and packaging it around the documented limitation.
Why use it?
They help an agent follow the project's build, test, lint, packaging, and architecture rules. They also document a known packaging problem caused by the project path.

Instructions file for Claude Code

Written for Claude Code: PreToolUse hook event. Also seen: reads .claude/ paths; mentions CLAUDE.md; mentions subagents.

This is amirlehmam/wmux's own configuration. It tells Claude Code how to work on wmux itself, so it is not a mod to install elsewhere. Copy it as a starting point and replace the rules that are about this project. Everything wmux configures →

Needs its repository: it reads a path above its own folder, which exists only inside the repository. The line is rm -rf ../wmux-release-staging.

Reuse

Borrowing it

Nothing to install: this file belongs to amirlehmam/wmux. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.

Copy the file
curl -O https://raw.githubusercontent.com/amirlehmam/wmux/master/CLAUDE.md
Clone the repo
git clone --depth 1 https://github.com/amirlehmam/wmux

Made for: Claude Code.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for wmux CLAUDE.md

README.md
[![agentmods](https://agentmods.dev/badge/instructions/amirlehmam/wmux/claude-md.svg)](https://agentmods.dev/instructions/amirlehmam/wmux/claude-md)
Your own site
<a href="https://agentmods.dev/instructions/amirlehmam/wmux/claude-md"><img src="https://agentmods.dev/badge/instructions/amirlehmam/wmux/claude-md.svg" alt="Measured on agentmods" height="20"></a>
Per session 18,193 This file is loaded in full into every session.
When invoked 18,193 The same file — it is already loaded in full.
Security scan E 2 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.18193 $0.18193
Opus 5 $0.09097 $0.09097
Sonnet 5 $0.03639 $0.03639
Haiku 4.5 $0.01819 $0.01819

Measured today against content hash 24dc0db2fe7e, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-06, from the pricing page.

Security

Grade E, and why

wmux CLAUDE.md scanned grade E with 2 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Reaches for credential fileshighPrivilege escalation

SSH keys, cloud credentials, git-credentials, .npmrc, /etc/shadow: reading these is how a config file becomes a credential leak.

| `code-file.ts` | Which files the code viewer will read **and write**, and how. Sibling to `markdown-file.ts`, and it deliberately neither imports from it nor changes it: markdown's extension whitelist stays exactly as

Recursive force deletehighDestructive command

rm -rf with a variable or a broad path is one typo away from removing the wrong tree.

rm -rf .asar-staging build-out
CLAUDE.md · 781 lines

How it starts

The opening of the file, as written. The whole thing — 781 lines — stays where its author put it; the contents beside it link to each section on GitHub.

wmux — Development Guide

Electron-based Windows terminal multiplexer for AI agents. TypeScript, React 19, Zustand, xterm.js, node-pty.

Owner: amirlehmam (GitHub) — speaks French, prefers fast pragmatic solutions, tests live. Repo: github.com/amirlehmam/wmux | Site: wmux.org (Netlify, static from site/) Version: 2.9.3


Build & Dev

npm run dev            # Vite (port 5199) + Electron hot-reload
npm run build:main     # tsc main/preload/cli only (fast iteration)
npm run build:renderer # Vite production build (renderer only)
npm run build          # Full: tsc + vite + electron-builder
npm test               # Vitest unit tests
npm run test:watch     # Vitest watch mode
npm run lint           # ESLint src/

Known Build Gotcha

Project lives in OneDrive - Pulsa (path with spaces). This breaks:

  • npm link / node-gyp (can't build node-pty)
  • electron-builder winCodeSign (symlink errors)

Workaround: Don't use electron-builder for the final package. Use ASAR-based manual packaging (see Release Process below).


Architecture

src/
  main/           Electron main process
  renderer/       React UI (Vite)
  preload/        contextBridge (window.wmux)
  cli/            CLI → named pipe (\\.\pipe\wmux)
  shared/         Shared types (IPC channels, branded IDs)
  shell-integration/  Shell hooks (bash/zsh/PowerShell/cmd)

resources/        Runtime assets (icons, themes, sounds, shell-integration, CLI)
  wmux-orchestrator/  Claude Code plugin (auto-installed on startup)
site/             Landing page (static HTML, Netlify)
tests/            Unit + e2e (Vitest)
docs/             Planning docs

Main Process (src/main/)

File Role
index.ts Entry point, AppUserModelId, auto-save (30s), pipe server startup, V2 pipe handlers (workspace/pane/surface/markdown/sidebar/notification)
pty-manager.ts PTY lifecycle (create with surfaceId, write, resize, kill)
pty-crash-guard.ts Keeps a PTY-side error from killing the whole app (issue #150). Every pane's PTY lives in main, so a throw there takes the window down: wraps node-pty's _$onProcessExit (a throw there becomes an unhandled C++ Napi::Error in conpty.nodeabort()) and claims each terminal's error event (node-pty re-throws socket errors when fewer than 2 listeners exist, and registers none). Installed at module load — after pty.spawn is too late
pipe-server.ts Named pipe \\.\pipe\wmux — V1 text (shell hooks), V2 JSON-RPC (CLI/agents). Every reply is socket.write(text, () => socket.destroy()), and the clients (wmux.ts, wmux-hook.ts) destroy() on the first reply chunk — never end(). libuv on Windows arms a 50 ms eof_timeout after a half-close on a named pipe (src/win/pipe.c) and only releases the handle on the peer's EOF or on expiry; the server never closed its side, so every CLI verb and every hook process paid the full timer plus slop: wmux ping 94 → 33 ms, a hook process 94 → 32 ms, against a raw pipe round trip of 1 ms. A server-side end() does NOT fix it (both sides arm the same timer, measured 93 ms unchanged), which is why the comment there says destroy and means it. Safe only because every client sends one request per connection — the framing loop still gates the destroy on "no further complete line buffered", pinned by a test
cdp-bridge.ts Browser webview control via Chrome DevTools Protocol
cdp-proxy.ts CDP WebSocket proxy
agent-browser-cli.ts Where agent-browser is on this machine, and how to run it. Two traps, both found by running the real binary rather than by reading its docs. (1) execFile never returns. Its callback fires on stdio CLOSE, not on process exit, and every command that starts the daemon — the first open of a session, dashboard start — leaves that daemon holding the inherited stdout pipe open for as long as it lives. Measured against 0.35.0: an identical cold open had the child exit 0 at 787 ms while execFile's callback had still not fired at 3 min, so the verb burned its whole timeout and was reported as a FAILURE despite having succeeded. Hence spawn, resolving on 'exit' (the event that actually means "done"), with a 50 ms drain window so output is not truncated — 'close' lands right behind 'exit' when nothing holds the pipe, so the wait is only ever paid by the daemon-spawning commands. Anyone "simplifying" this back to execFile breaks agent mode completely and silently. (2) Never a .cmd. Node refuses to spawn .bat/.cmd without shell: true (the CVE-2024-27980 mitigation) and throws a synchronous EINVAL — in main that is an uncaught throw, not a failed command. shell: true is not available as a fix: argv carries agent-controlled URLs and eval snippets, and routing them through cmd.exe's parser is the exact trap powershell-shim.ts documents (#154). The npm package ships real per-platform binaries under its own node_modules/agent-browser/bin/, so resolution targets those first and the shim is never a candidate. Memoised like node-runtime.ts (#187) because it is read on the pane path (#176), and keyed on the configured path so a Settings change invalidates without every caller remembering to ask
agent-browser-verbs.ts The pure wmux-verb → argv table. I/O-free on purpose: it is the piece most likely to drift as agent-browser's CLI evolves, so it must be exhaustively testable with no daemon, no Chrome, no Electron. Returns an ARRAY, never a joined string — params arrive from a pipe command an agent controls. A missing ref on click/type/fill throws -32602 rather than putting undefined on a command line, and an unknown verb throws the same -32601 the web engine does so a caller cannot tell the engines apart by their error. Also where the one engine divergence is recorded in code: wait has no per-call timeout in agent-browser, so a caller ms sent alongside a ref is unrepresentable in argv and deliberately dropped — see CLI Reference
agent-browser-session.ts surfaceId → session name + wmux-allocated stream port. Sessions are ephemeral — nothing persisted, no profile dir, a session's process lifetime equals its surface's — and that is what makes orphan handling correct by construction rather than by heuristic: no wmux-owned session can legitimately survive, so any prefixed session with no live surface is garbage. That is the property the #139 post-mortem wanted and did not have. But the registry is in-memory and starts EMPTY, so it is not ground truth after a crash — the sessions that actually survived are precisely the ones it cannot see, and reconciliation asks agent-browser session list instead. wmux allocates the stream port ITSELF (9300+, above the CDP proxy's 9222-9230) because the dashboard deep-links by ?port=, and discovering an OS-assigned port after the fact races the webview load; ensureBindable verifies each candidate with a real listen first, since the registry tracks only what it handed out and never what the OS holds — an orphan from a previous run may still be bound. isWmuxSessionName is a security boundary, not tidiness: names come out of a machine-global namespace anyone can write into and go straight back onto a command line as --session <name> close, so both the instance prefix AND the full surf-<uuid> shape are required. WMUX_INSTANCE gets its own prefix — a side-by-side wmux is exactly as much "not us" as a human's hand-made session
agent-browser-daemon.ts The observability dashboard, refcounted by live agent-mode surfaces: first acquire starts it, last release stops it. Adopt, never fight — if :4848 already answers, a human or another wmux started it, so wmux uses it, records adopted, and NEVER stops it: not on the last release, not on shutdown. adopted is a getter with deliberately no setter, since anything that could write it could make teardown kill a dashboard wmux does not own. A failed acquire() rolls back its own increment (clamped — refs must never go negative) so a phantom ref cannot strand a dashboard no later release can reach zero on, and release()/shutdown() wait out an in-flight start before deciding there is nothing to stop — otherwise a start that settles just after shutdown leaks a child process that outlives wmux entirely
agent-browser-runtime.ts The single home for the singletons — exactly one SessionRegistry, exactly one DashboardDaemon — plus the impure halves the pure modules take by injection. A second copy silently corrupts both: two registries hand 9300 to two surfaces, two daemons each believe they own the dashboard and the first release() to hit zero stops it out from under the other. It also owns the per-surface dashboard reference, because two paths take one for the SAME surface (the renderer enabling agent mode, and a wmux browser verb arriving for that pane) and when each kept its own Set the pane took two references and gave back one, so the dashboard outlived every agent pane until quit. Readiness is the PORT, never the exit: dashboard start exits at 58 ms having daemonised while :4848 does not accept a connection for ~500 ms, and in some configurations it does not exit at all. reconcileOrphanSessions runs at startup off session list because a crash reaches none of the other teardown paths and Windows reparents rather than kills (#139); a close that hangs (observed after a daemon version-mismatch restart) is deadlined and left for the next launch rather than resolved by killing a PID — agent-browser exposes no per-session PID and its daemon fronts several sessions, so leaking one Chrome beats killing somebody else's browser
agent-manager.ts Agent PTY spawning, round-robin distribution across panes. The agent command travels as a startupCommands entry that the PowerShell integration runs during init (see pty-manager.ts), not as keystrokes typed after a sniffed prompt: the prompt regex stopped matching the moment #207 wrapped the prompt in OSC 133 marks, so every wmux agent spawn silently fell into the 1500 ms debounce (first output 1.71 s → 0.56 s). The sniffing path survives for shells without the integration, with looksLikePrompt tolerating trailing OSC/CSI sequences
window-manager.ts Electron BrowserWindow creation/management
ipc-handlers.ts All IPC channel handlers
claude-context.ts Injects wmux instructions into ~/.claude/CLAUDE.md, configures hooks, installs wmux-orchestrator plugin — and the inverse of each, since 0.40.0. The per-tool-call hooks (PreToolUse, PostToolUse, UserPromptSubmit) are written with async: true: they are pure observers, and Claude Code waited a measured 125-145 ms on each of them on the critical path of every tool call. Ordering is already handled — every report carries the wall-clock it fired at and agent-state.ts drops anything older than what it accepted (#151). SessionStart, Stop and SessionEnd stay sync. applyWmuxHooks rewrites its own entries on every launch, so an install that predates the flag picks it up without a migration
agent-integration.ts Consent gate for every write outside %APPDATA%\wmux (issue #132). Asks on first launch, stores unset/granted/declined in wmux's own settings.json, and reconciles ~/.claude + ~/.config/opencode + ~/.kiro to match. Nothing in claude-context.ts, opencode-context.ts or kiro-context.ts may be called directly from startup any more — route it through here
kiro-context.ts Kiro CLI support (issue #148). Writes ~/.kiro/steering/wmux.md — a dedicated global steering file, since Kiro loads every .md in that dir, so there is no shared file to splice into. No hooks: Kiro's are per-project (.kiro/hooks/), and writing into every repo the user opens is the #132 mistake. State comes from wmux report-agent instead
opencode-context.ts Installs resources/opencode-plugin/wmux.js into ~/.config/opencode/plugin/, gated on the // wmux-plugin-version: marker (pluginNeedsUpdate compares it verbatim, so any change to the plugin needs a bump or it reaches nobody — every broken install already has the old file on disk). That plugin file must export WmuxPlugin and nothing else (#191): OpenCode's auto-discovery loader calls EVERY export as a plugin factory and then invokes a config hook on the result, so an exported helper returning a plain value crashes OpenCode at startup. Helpers hang off WmuxPlugin.__wmuxInternals for the tests; a source-level test pins the export count
claude-observer.ts Monitors Claude Code activity for sidebar display
claude-resume.ts claude --resume on workspace restore (#186), behind workspacePrefs.restoreClaudeSessions (default off — every such pane starts an agent at once). Stamps each terminal's live session id into the PERSISTED tree only, the way freezeSurfaceCwds stamps cwd; a live surface never carries one. Main-side rather than renderer-side because the id lives in agent-state.ts's record map. The id reaches a command line, so CLAUDE_SESSION_ID_RE is a security boundary, enforced at reportAgentSession AND again in claude-resume-command.ts (session.json is user-editable). handleHookEvent must skip SessionEnd: it carries a session_id like every hook, but releaseAgent() has just run for it, and recording there would resume a Claude the user deliberately quit
agent-state.ts Declared agent run state — blocked/working/idle, run refcount, seq dedupe, metadata TTL (issue #128). Also the back-channel: declared choices + answerAgent. Answering never clears blocked — the agent must confirm, or a mis-declared key silently stops a stuck pane asking for help
agent-state-rpc.ts pane.report_agent & friends, routed off the main V2 switch
agent-hook-bridge.ts Claude Code hooks → declared state, so it works with no plugin to install
quit-sequence.ts When quit may let the process leave (#214). The 0xc0000409 aborts reported there are shutdown crashes: all six land on a will-quit line in the reporter's own main.log, to the second, and logDiagnostic('will-quit', …) is that handler's first statement. Six across thirteen quits at PTY counts 2–7 — a race, not the file explorer it was filed against. The mechanism is the one the session-end comment in index.ts already describes: killAll() fires N node-pty ConPTY exit callbacks and the process then walks into Node's environment teardown, where a napi call that loses throws off the top of the stack into __fastfail(7). pty-crash-guard.ts closes the route where the JS callback throws and cannot close this one, because JS is never reached. Two moves: drain (hold the quit ~250 ms so the callbacks land while the environment is healthy — the strategy session-end argues for, applied to the ordinary quit), then leave hard (app.exit(), so whatever did not land never sees the teardown). A quit with no PTYs defers nothing and exits normally: the hard exit skips Chromium's own shutdown, so it is a treatment for a condition and not a new way of quitting. Pure, because will-quit needs a real Electron app to reach and the part worth pinning is the decision
changelog.ts Release notes in the app (#211). GETs /releases and caches every success under %APPDATA%\wmux\cache — inside wmux's own dir, so no part of the #132 consent gate. Every failure falls back to that cache, including a manual Refresh: a refresh that fails must not blank the list being read. No Authorization header ever; the moment this could carry a token it becomes a thing that can leak one. toChangelogEntries is pure and is where everything that can be wrong lives — drafts dropped, a body that is null rather than absent, a name that is '' on a bare-tag release (so ?? keeps the wrong thing), and ORDER: the API returns releases by CREATION date, which stops being version order the moment a patch for an older line ships after a newer minor
session-persistence.ts Auto-save/restore window state. saveSession is atomic in the sense the comment always claimed and the code did not (#214): it used to unlink the live session.json before renaming the temp over it, a window with no session file at all — die there and the next launch has nothing to restore, comes up as a fresh Session 1, and re-mints every pane and surface id, which is that issue's "surfaces come back with new ids and lose their customTitle". The unlink was never needed: libuv's uv_fs_rename uses MoveFileExW with MOVEFILE_REPLACE_EXISTING, so a plain renameSync over an existing file is legal. It survives only as a fallback for a real sharing violation (antivirus, a sync client), where not saving at all is worse than a brief window
port-scanner.ts Active port detection for running dev servers
powershell-shim.ts The wmux.ps1 gate (issue #154). PowerShell resolves a .ps1 ahead of every PATHEXT entry, which is how cmd.exe's argument parser is kept out of the PowerShell path — but a .ps1 PowerShell refuses (Restricted policy, or Mark of the Web under RemoteSigned) is a hard error with NO fallback to the .cmd beside it. So the shim dir goes on PATH only after a probe script in that same dir has actually run in every installed host
node-runtime.ts Which binary on this machine can run a .js file (#187). Everything wmux hands an agent is "a script plus something to run it", and every consumer had been assuming node was on PATH or that the host process was itself a JS runtime — false under OpenCode, whose process.execPath is a compiled opencode.exe. Resolved once (memoised: it is read on the synchronous pane-create path, see #176) and declared as WMUX_NODE. The last resort is wmux's own Electron binary, which is Node under ELECTRON_RUN_AS_NODE=1, so the chain never dead-ends — but that flag is what makes it a runtime instead of a second wmux window, hence the separate WMUX_NODE_ELECTRON signal
ssh-argv.ts Parses an ssh command line into the facts scp needs to reach the same host (#195). Pure, and the single funnel for all three detection sources so they cannot disagree about what a command line means. Returning null is the safe outcome — a mis-parse does not fail loudly, it uploads a file to the wrong host — so port forwards (-N/-W), one-shot remote commands and RequestTTY=no all abandon the parse rather than guess
ssh-detect.ts Is this surface sitting inside ssh, and where? Three layers: managed (wmux ssh put the command line in the shell spec), reported (shell-integration preexec hook), probed (Win32_Process ancestry sweep). The precedence rule is a security boundary, not a preference: Windows has no tty foreground process group, so a descendant ssh.exe may be a background process — the probe may only corroborate an authoritative layer, never establish one. refresh() short-circuits with no sweep when neither authoritative layer has an entry, because it runs on the paste path
remote-upload.ts scp/ssh argv construction and the transfer itself. BatchMode=yes throughout: these run with no TTY, so a passphrase prompt would hang to the timeout. All-or-nothing — a failed batch deletes its private /tmp/wmux-drop-<uuid>/ before returning, since half a batch gives the user remote paths and silence with no way to tell which is which
remote-insert.ts What a paste or drop types into a terminal. Lives in main because every input to the decision does (clipboard, detector, filesystem, scp, config). Quoting is per-side: Windows-conditional locally, always single-quoted for a remote sh
win32-process.ts One Get-CimInstance Win32_Process invocation for both the orphan reaper and the ssh probe. Shared so the security-relevant part — resolving powershell.exe by ABSOLUTE path, so a writeable PATH dir cannot shadow it — is stated once
system32.ts Absolute paths to Windows-owned tools. opensshPath() prefers Program Files OpenSSH over System32 (#193): Git for Windows puts an MSYS2 ssh ahead of System32 on PATH, and it cannot talk to the Windows named-pipe ssh-agent — so a bare ssh spec died on "Permission denied (publickey)" wherever keys live only in an agent
shell-context-menu.ts "Open in wmux" Explorer verb — HKCU shell keys for Directory/Directory\Background/Drive, plus directoryFromArgv for the launch path. Win11 places it under "Show more options"; the modern menu needs a signed MSIX, which unsigned wmux cannot ship
theme-loader.ts Theme loading
explorer-fs.ts The file explorer's jailed directory enumeration, and the path policy every explorer and code read goes through. resolveInRoot is the security boundary: the renderer sends a surfaceId and a RELATIVE path and NEVER an absolute one, because a renderer-supplied root would not be a jail — a compromised renderer would simply pass C:\. Containment is path.relative, plus a Windows-spelling prefix check beside it (the root is realpath'd on the way in, so 8.3 short names and junction aliases are already gone). Two traps live here: rel.startsWith('..') also rejects a legitimately-named ..foo, which the user sees as a folder that silently refuses to open; and a drive root ALREADY ends in a separator, so appending one unconditionally spells c:\\ and locks a pane at C:\ out of every folder below it. The walk lstats EVERY segment rather than only the leaf — root\link\sub follows link before a leaf-only lstat ever runs, and libuv maps reparse points onto symlinks so mklink /J junctions are covered by the same check
explorer-roots.ts surfaceId → the explorer root for that pane. The root is the pane's TERMINAL cwd, not its active surface's — a pane showing a markdown tab still belongs to the folder its shell is in — and it is normalized through trustedWindowsCwd, so a Git Bash /c/Users/... report and a PowerShell junction alias both land on the same spelling main can jail against
code-file.ts Which files the code viewer will read and write, and how. Sibling to markdown-file.ts, and it deliberately neither imports from it nor changes it: markdown's extension whitelist stays exactly as narrow as it is, for exactly the callers it already has. The threat model is INVERTED — markdown names its whitelist as the thing stopping a renderer bug from reading ~/.ssh/id_rsa into a visible pane, and this module has no whitelist at all because the whole point is to read the files that whitelist rejects. What replaces it is explorer-fs.ts's path jail, applied by the code:read-file handler before anything here runs. BINARY_EXT and the content sniff are a UX filter — they keep .png out of the tree and mojibake out of the pane — and a future reader who treats them as the boundary will draw the wrong conclusion about what may be relaxed. writeCodeFile adds two things a naive save gets wrong and that both show up as a whole-file rewrite in the next commit: a <textarea> normalizes its value to LF, so a CRLF file's endings are restored from what is on disk, and the file's encoding (UTF-8, UTF-8+BOM, UTF-16LE) is probed from the preamble of the file being overwritten rather than round-tripped through the renderer. The size cap is measured on the ENCODED buffer — UTF-16 doubles most source text, so a string check lets a file through at twice the limit the read side then refuses to reopen
file-grants.ts Which paths a renderer may write to — the single gate for every renderer→disk write, checked by both markdown:save-file and code:write-file. Was markdown-grants.ts; renamed when the code surface became editable, because it was always a generic Map<webContentsId, Set<path>> and two grant sets would be two answers to "may this be written", whose drift shows up as a silent write to a file one of them would have refused. Records a partial reversal of #210, deliberately: that PR refused a jailed read that mints a grant on the grounds that "jailed to a pane root" is not consent, which was right while the pane was read-only. The editor's transaction is different — the user clicks a row, types, presses Ctrl+S — so the rule is now "a write lands only on a path opened into a live pane in THIS window, in this session, through the jail, and only if it has not changed on disk since". Still not a grant source: markdown:read-file, which takes a renderer-supplied ABSOLUTE path; a renderer that can mint its own grants makes the set meaningless. That is why the jailed markdown read had to be a separate channel rather than a flag on the existing one
config-loader.ts WT/Ghostty config import. Reachable from Settings → Terminal → Import. WT spells opacity two ways — modern opacity (0-100, independent of useAcrylic) and pre-1.12 acrylicOpacity (0-1, only with useAcrylic)
shell-detector.ts Available shells detection
updater.ts Auto-update. Routes by install layout: NSIS → electron-updater, portable zip → zip-updater.ts (#184). initAutoUpdater() returns before registering NsisUpdater on a zip extract, so a portable install can never enter the #96 "update ready" loop
zip-updater.ts In-place update for portable zip extracts (#184). Detection is the whole contract: wmux.exe present, Uninstall wmux.exe absent — that name is electron-builder's Uninstall ${productFilename}.exe, so it moves if productName/executableName ever change. Download via net.request, extract via System32 tar.exe (PowerShell Expand-Archive fallback), then a detached cmd helper waits on the old PID and robocopies over the install root. The helper's relaunch is unconditional — wmux has already quit, so bailing out on a copy failure is the one outcome the user can't recover from

Read the full file on GitHub · 781 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. today Changed 24dc0db2fe7e
  2. yesterday Changed f86a07ffc1f2
  3. 2d ago Changed · +29 lines · +1,933 tokens per session fd8e15a00c3c
  4. 6d ago First seen · 752 lines · 16,260 tokens per session scan E 95bd65f0819b

Subscribe to this mod's changes

wmux CLAUDE.md is an instructions file published in the GitHub repository amirlehmam/wmux (368 stars, last pushed yesterday), licensed MIT. It adds 18,193 tokens to every session, about $0.0910 per session on Opus 5. A static security scan graded it E with 2 findings (reaches for credential files, recursive force delete). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.

Related

Other instructions, from other repositories

next.js AGENTS.md

AGENTS.md instructions for vercel/next.js, covering next.js development guide, codebase structure, monorepo overview, core package: packages/next and other important packages.

vercel/next.js · 7,296 tokens

codex AGENTS.md

AGENTS.md instructions for openai/codex, covering rust/codex-rs, the codex-core crate, code review rules, crate api surface and model visible context.

openai/codex · 5,182 tokens

vscode buildNext.instructions.md

Working notes and architecture documentation for the new esbuild-based build system in build/next. Use when making changes to the new build pipeline (transpile/bundle commands, NLS plugin, source-map handling, resource copying, or self-hosting watch tasks).

microsoft/vscode · 6,785 tokens

vscode oss-third-party-notices.instructions.md

Instructions for microsoft/vscode, covering vs code oss third-party-notices pipeline, architecture, pipeline flow in ci, applying the notice (cutover) and fallback chain (never fail the build).

microsoft/vscode · 5,001 tokens

langchain AGENTS.md

AGENTS.md instructions for langchain-ai/langchain, covering global development guidelines for the langchain monorepo, corridor security analysis, project architecture and context, monorepo structure and development tools & commands.

langchain-ai/langchain · 4,469 tokens

spec-kit AGENTS.md

AGENTS.md instructions for github/spec-kit, covering agents.md, about spec kit and specify, quickstart — add a new integration in 5 steps, integration architecture and integrationmanifest — file tracking.

github/spec-kit · 7,104 tokens