Repository navigation
Description
First off — I really love that this tool exists and lets Windows users catch up to macOS developers. I've been testing wmux for my work and wanted to share constructive feedback on a few things I struggled with, plus one feature suggestion. Code references included in case they help.
1. Notification sounds never play
The Sound setting (Settings → Notifications, Default/None) looks functional but is a no-op:
notificationPrefs.soundis defined (settings-slice.ts:246-260) and shown in the UI (NotificationSettings.tsx:51-65) but never read anywhere.- There's no audio playback code at all (no
new Audio/.play()), andresources/sounds/is empty (only.gitkeep) despite being bundled into every release. - Only the Electron toast + taskbar flash + pane ring fire (
notification-manager.ts:4-14).
Suggestion: ship a default sound asset and play it in the NOTIFICATION_FIRE path when sound !== 'none', or remove the setting until implemented so it's not misleading.
2. Proper installer / Microsoft Store distribution + PATH
The portable zip works but limits discoverability and makes PATH setup manual. electron-builder.json already has NSIS config (currently unused) and electron-builder supports MSIX/appx. Rough effort, lowest-friction first:
| Option | Est. effort | Cost / prereqs | Notes & risks |
|---|---|---|---|
Winget (microsoft/winget-pkgs) |
~0.5–1 day | Free. No code-signing required to publish. | Lowest-friction win — a YAML manifest pointing at the existing release zip/exe + SHA256, fully automatable per release via the winget-releaser GitHub Action. Caveat: unsigned binaries still trip SmartScreen on first run, so this improves install UX, not trust. |
| NSIS installer (already configured) | ~1–2 days | Code-signing cert is the real cost (below). | Config mostly exists; work is building off the OneDrive/spaces path (the documented winCodeSign blocker), wiring signing into the release pipeline, and testing shortcut/PATH registration. Unsigned, NSIS trips SmartScreen more than the zip — only pays off once signing is in place. |
| Microsoft Store (MSIX/AppX) | ~3–5 days + review latency | Partner Center account ($19 one-time individual). Store signs the package — no cert purchase needed. | Biggest visibility upside and solves signing "for free," but highest technical risk: MSIX runs in a sandboxed container that can break wmux core behaviors — named pipe (\\.\pipe\wmux), spawning external shells/node-pty, writing to ~/.claude. Needs a validation spike before committing; budget extra time if those need workarounds (runFullTrust, packaged-path handling). |
Code-signing is the dominant variable for the installer path:
- Cheapest modern route: Azure Trusted Signing (~$10/mo), integrates with electron-builder.
- Traditional OV cert (
$200–400/yr) builds SmartScreen reputation slowly; EV ($300–700/yr) clears it immediately. - The Store path sidesteps cert purchase entirely (Microsoft signs Store MSIX).
Suggested sequencing: Winget first (cheap, fast), then Azure Trusted Signing + the existing NSIS installer mid-term, and treat Store/MSIX as a separate spike gated on confirming the sandbox doesn't break the pipe/PTY architecture. A proper installer would also register a real wmux CLI on PATH automatically — which fixes issue #3.
3. wmux browser open launches a NEW instance instead of using the running one
When Claude Code runs wmux browser open <url> it spawns a fresh wmux window rather than driving the existing one. Two confirmed root causes:
- Stale compiled CLI:
resources/cli/wmux.js:8hardcodesconst PIPE_PATH = '\\\\.\\pipe\\wmux', dropping theprocess.env.WMUX_PIPEsupport that exists in source (src/cli/wmux.ts:7). The shipped artifact predates the feature and needs a rebuild. - No single-instance lock:
src/main/index.tshas noapp.requestSingleInstanceLock()/second-instancehandler, so a second launch just opens another window instead of focusing the existing one. - Underlying trigger: outside a wmux-spawned shell,
wmuxisn't the CLI (noWMUX_CLIenv var /wmuxshell function), so the name resolves to the GUI exe on PATH → new instance, args ignored. The CLI script itself never launches the GUI (on pipe failure it just prints "wmux is not running" and exits), confirming the new window comes from the exe being invoked directly.
Suggested fixes: add requestSingleInstanceLock with a second-instance focus handler; rebuild/verify resources/cli/wmux.js; ship a dedicated wmux CLI shim on PATH distinct from wmux.exe (ties into issue #2).
4. Feature request: configurable quick-launch profiles next to the + button
I'd love to configure quick-launch shortcuts next to each pane's + button — to open tools, auto-cd into directories, run a startup command, etc. This already exists in cmux as project "custom commands" (cmux.json), and Windows Terminal has the profile-dropdown precedent — wmux is well-positioned because the UI hook is already there.
Current state:
- The
+already has a caret dropdown (SurfaceTabBar.tsx:272-297) but it only offers Terminal / Browser / Markdown — pure type selection. - There are no profiles, no startup commands, and no per-tab cwd (
pty-manager.tsacceptscwdbut no startup command; WT import atconfig-loader.ts:157-178keeps only the color scheme and discards profiles /commandline/startingDirectory).
Proposed shape:
- Profile model:
{ name, icon, type, shell?, cwd?, startupCommands[] }— e.g. "Backend → cd ./server,npm run dev", "lazygit", "btop". - Two config scopes: global in
settings.json(alongside the existing 45 shortcuts), and a project-level.wmux.jsoncommitted to a repo (mirrors cmux'scmux.json). - Surfacing: populate the existing
+caret dropdown with these profiles; each entry creates a surface oftypeincwdrunningstartupCommands. - Free wins: bind any profile to the existing keyboard-shortcut / command-palette infra, and finish the WT import to pull real profiles (
commandline+startingDirectory), giving WT users an instant launcher library.
Comparatively small lift (dropdown + PTY cwd/startup-command plumbing + config schema) for a high-visibility quality-of-life feature.
Thanks again for building this — happy to help test fixes or open separate issues if you'd prefer these tracked individually.
Activity
feat: address issue #32 (notification sounds, single-instance CLI, qu…
amirlehmam commentedon Jun 15, 2026
Hey @kevmtt — this is genuinely one of the most useful issues the project has gotten. Thank you for the code references; they made every one of these fast to land. Shipped in v0.8.6:
1. Notification sounds ✅ fixed
You were exactly right —
notificationPrefs.soundwas read nowhere andresources/sounds/was empty. wmux now ships a default chime and plays it on every notification fire, gated on theDefault/Nonesetting. The main process can't play audio, so it emits anotification:play-soundsignal on the singleNOTIFICATION_FIREchokepoint (covers OSC 9/99/777 + the activity watcher), and one renderer listener plays the bundled WAV iffsound !== 'none'.3.
wmux browser openspawning a new instance ✅ fixedBoth root causes you found are addressed:
app.requestSingleInstanceLock()+ asecond-instancefocus handler. A straywmux …launch now focuses the running window instead of spawning a second one. NamedWMUX_INSTANCEinstances point Electron'suserDataat their own dir, so the lock is per-instance and dev/prod still coexist.resources/cli/wmux.js— it honorsprocess.env.WMUX_PIPEagain (the shipped artifact had drifted behind source, exactly as you spotted).4. Quick-launch profiles ✅ implemented
Built close to your proposed shape:
{ name, icon, type, shell?, cwd?, startupCommands[], url? }.commandline→ shell,startingDirectory→ cwd)..wmux.jsonat a workspace root (mirrors cmux'scmux.json). Example:{ \"profiles\": [ { \"name\": \"Backend\", \"type\": \"terminal\", \"cwd\": \"./server\", \"startupCommands\": [\"npm run dev\"] }, { \"name\": \"lazygit\", \"icon\": \"🌿\", \"type\": \"terminal\", \"startupCommands\": [\"lazygit\"] }, { \"name\": \"Grafana\", \"type\": \"browser\", \"url\": \"http://localhost:3000\" } ] }+caret dropdown (project entries get aprojectbadge). Terminal profiles auto-cdand run their startup commands once on fresh PTY creation (re-mounting a keep-alive tab won't re-run them); relativecwdresolves against the workspace cwd.2. Installer / Store distribution — partially shipped 🟡
I took your sequencing recommendation and started with the cheap, no-signing win:
winget/) + an auto-publish GitHub Action (vedantmgoyal9/winget-releaser). wmux is modeled as a portable-zip install with a nestedwmuxcommand alias on PATH. The first submission tomicrosoft/winget-pkgs+ theWINGET_TOKENsecret are a one-time owner step — documented inwinget/README.md.The rest of #2 comes down to spending decisions that are mine to make, not code, so I'm leaving them as deliberate follow-ups rather than pretending they're done:
\.\pipe\wmux, node-pty shell spawning,~/.claudewrites) before committing.Winget improves install UX, not trust — fully agreed, and called out as such in the release notes.
Everything except the signing/Store spend is in v0.8.6 now. If you grab the build, please right-click → Unblock the zip (or
Get-ChildItem -Recurse | Unblock-File) before running. Would genuinely love a second pass from you on the profiles UX and the new-instance behavior — and yes, please do open separate issues for the CLI-shim and Store-spike if you'd like them tracked individually. 🙏kevmtt commentedon Jun 16, 2026
@amirlehmam For me the dropdown isn't working, eventhough I've created profiles.
fix(updater): ship signed NSIS installer so Windows auto-update installs
fix(shell-integration): resync all three packaged copies with src