A native macOS menu bar app for tmux session management + caffeinate toggle.
Use it for: tmux session manager · Keep Awake toggle · headless clamshell (closed-lid mode — no external display required) · long-running script launcher (OCI / cloud capacity polling / backups / batch jobs).
- Session list — All tmux sessions at a glance, sorted by attached first and creation date (latest first within each group)
- Attach — Open the selected session in Terminal.app / iTerm2 / Warp / Alacritty / kitty
- Kill — Drop a session from the menu
- Live Preview — Click a session row or pick "Preview" to see recent output (ANSI-rendered via SwiftTerm)
- Keep Awake — Toggle
caffeinate -dimsas a tracked tmux session (_muxbar-awake). Detects external caffeinate too (any tmux session running it, or any system-level process), and stops all of them with one click. - Closed-lid mode (headless clamshell) — A "clamshell-without-the-external-display" toggle: keep the CPU running with the lid shut so your build / CI / remote session survives a bag commute. Toggle → 30m/1h/4h/8h/∞ → admin password (Touch ID). Auto-disables on timer / AC unplug / lid open / quit — timer expiry never blocks on a password prompt. See Closed-lid mode below.
- Multilingual — English + 한국어. Settings → Language to switch (Auto / English / 한국어).
- Templates / script launcher — Built-in + user-defined session layouts (YAML). Use them as one-click toggles for long-running scripts (OCI instance creation, cloud capacity polling, backups, batch jobs) — launch from the menu bar, detach/re-attach anytime, the script keeps running. See Long-running script launcher below.
- Global hotkeys —
⌘⇧Atoggles Keep Awake,⌘⇧1~⌘⇧9attach the top N sessions. - Open at Login — Registers as a macOS Login Item under Settings (when installed as a bundled
.app).
- 0 sessions: plain coffee cup
- Active sessions: cup + session count badge
- Keep Awake active: steaming cup, orange tint
- Closed-lid mode active: red lock icon (priority over Keep Awake)
┌ ▣ muxbar ● ┐ ← header (name + connection dot)
├──────────────────────────────┤
│ ● api 1w ⋯ │ ← attached (green dot)
│ /Users │ cwd as subtitle
├──────────────────────────────┤
│ ○ dev 2w ⋯ │ ← detached
│ /Users/kgd/msa │
├──────────────────────────────┤
│ ○ logs 1w ⋯ │
│ /var/log │
├──────────────────────────────┤
│ ☕ Keep Awake ON │ ← toggle (⌘⇧A)
├──────────────────────────────┤
│ 🔒 Closed-lid mode OFF │ ← prevent sleep on lid close
├──────────────────────────────┤
│ ⊞ New Session ▸ │ ← templates submenu
├──────────────────────────────┤
│ ⚙ Settings ▸ │ ← Open at Login, future prefs
├──────────────────────────────┤
│ Quit muxbar ⌘Q │
└──────────────────────────────┘
- Session rows show attached (●) first, then detached (○) — each group newest-first
- More than 5 rows → list scrolls inside the menu
⋯on a row opens the action menu (Attach / Preview / Kill)- Tapping the session name itself opens the live preview popover
A toggle that prevents system sleep — including when the MacBook lid is closed — so unattended work keeps running.
- Long-running build / test / CI job you want to keep going while you commute
- Remote SSH session you don't want to drop while the laptop is in your bag
- Watcher / poller / data-pull script that has to stay alive overnight without an external display
Combines two layers so the system actually stays awake under closed-lid:
| Layer | Effect |
|---|---|
pmset -a disablesleep 1 (kernel-level) |
Blocks the lid-close → forced sleep path |
caffeinate -is in _muxbar-closed-lid tmux session |
Backs up the kernel hint with idle + system IOPM assertions |
The display is intentionally not kept on — -d is omitted. With the lid closed the lid sensor turns the internal display off in hardware anyway, which is exactly what you want for a bag-mode workload.
| Trigger | Why |
|---|---|
| ⏱ Timer expires | The duration you picked at toggle time |
| 🔌 AC adapter unplugged (transition only) | Prevent surprise battery drain. Doesn't fire if you toggled on while already on battery — your in-bag use case still works. |
| 💻 Lid opens | You're back at the laptop — flip back to normal sleep policy |
| 🚪 muxbar quits | applicationShouldTerminate waits for pmset to be restored before exiting |
Manual OFF: if you cancel the admin password prompt the state stays ON and the AC/lid monitors are re-armed — no zombie state.
Auto-off (timer / AC / lid): no password dialog is ever shown. sudo -n pmset is attempted silently — if the NOPASSWD rule (below) is set it succeeds; if not, the caffeinate session is killed, state goes to OFF, and a notification asks you to toggle OFF once from the menu to restore pmset. The timer's "off after N minutes" promise is honored unconditionally.
Functionally similar — both keep the CPU running with the lid closed — but the trigger and intent differ. Closed-lid mode is essentially a headless clamshell (caffeinate -is + pmset disablesleep 1) that works without an external display, so the laptop can keep working inside a bag or on AC alone.
| macOS clamshell mode | Closed-lid mode | |
|---|---|---|
| Trigger | Auto when AC + external display + external keyboard/mouse all plugged in | Manual toggle |
| External display required | Yes | No |
| Display while lid closed | Output to external monitor | None if no external display; routes to external monitor if one is plugged in |
| AC required | Yes | No |
| External keyboard/mouse required | Yes | No |
| CPU while lid closed | Running | Running |
| Auto-off | Lid open / external display unplug | Timer / AC unplug / lid open |
Bonus — closed-lid mode is a superset of Apple's clamshell. If you happen to plug in an external display while closed-lid mode is on, macOS routes output there automatically — same desk-mode experience as Apple's clamshell, without Apple's "AC + external keyboard + external mouse" gate. The single toggle covers both bag mode (headless, on battery) and desk mode (external monitor, no peripherals required).
Apple's clamshell mode is for "MacBook on a stand at my desk with full peripherals." Closed-lid mode is for "MacBook in a bag" or "MacBook on the desk with just an HDMI cable."
- No Apple Developer Program needed — uses an AppleScript admin prompt for
sudo pmset - No helper daemon, no kernel extension
- The system caches the admin password for ~5 minutes, so toggle on → toggle off → back on doesn't re-prompt
To skip the password prompt entirely (including when the timer expires or auto-off fires after the 5-minute credential cache), allow pmset via sudoers:
echo "$(whoami) ALL = (root) NOPASSWD: /usr/bin/pmset" | sudo tee /etc/sudoers.d/muxbar > /dev/null
sudo chmod 440 /etc/sudoers.d/muxbarmuxbar tries sudo -n pmset first; if the rule is set it runs without a prompt. For manual OFF the AppleScript admin dialog is used as a fallback when the rule is missing. Auto-off (timer / AC / lid) never shows a dialog — without the rule, the caffeinate session is killed and a notification is posted; you restore pmset on the next manual OFF toggle.
To revert: sudo rm /etc/sudoers.d/muxbar.
Security scope: only pmset (system sleep policy) is allowed without password — file system, network, process, and user permissions are not affected.
Use tmux sessions as one-click toggles for scripts that have to keep running — polling, batch jobs, infrastructure waits — without leaving a terminal window open or living inside a shell prompt.
- OCI / cloud instance creation —
oci compute instance launch ...that retries until capacity opens up. Hours of polling, no terminal to babysit. - Capacity polling — AWS Spot / GCP preemptible / Vast.ai loops that keep trying until you get the resource at your target price.
- Long backups / data sync —
rsync,restic,aws s3 syncof large datasets. Kick off and detach. - Batch jobs — overnight DB migrations, large
terraform apply, training loops you launched from a personal box. - Local watchers / pollers —
gh run watch,kubectl logs -f, repeatable scripts that should outlive a terminal close.
- Drop a YAML template under
~/Library/Application Support/muxbar/Templates/:
name: OCI Create
description: Oracle Cloud instance create (polling until capacity is available)
sessionNameHint: oci
windows:
- name: create
command: ~/oci-create-instance.sh; exec $SHELL- New Session → OCI Create in the menu bar. The session appears immediately, with a count badge on the icon.
⌘⇧1-⌘⇧9to attach in your terminal, or click the row for a live preview. Detach with⌃b d— the script keeps running.- Pair with Closed-lid mode to toss the laptop in your bag and let the script finish on the way home.
The ; exec $SHELL tail drops you into an interactive shell when the script finishes (or you Ctrl+C it) so the output stays — no surprise window close.
See Custom templates for the YAML schema.
- macOS 13 (Ventura) or later
tmux—brew install tmux- Xcode Command Line Tools —
xcode-select --install(if you haven't already)
Copy-paste, in one shot:
git clone https://github.com/1989v/muxbar.git
cd muxbar
./build.sh install
open /Applications/muxbar.appThat's it. The coffee-cup icon appears in your menu bar. Click it, and you'll see your tmux sessions.
Works with just Command Line Tools — Xcode not required.
git clone https://github.com/1989v/muxbar.git
cd muxbar
./build.sh # Release build + .app bundle (creates ./muxbar.app)
./build.sh open # Build + launch from the repo directory
./build.sh install # Build + copy to /ApplicationsWhat build.sh actually does:
swift build -c release- Wraps the binary into
muxbar.app/Contents/{MacOS,Info.plist} - Ad-hoc signs it with
codesign --sign -(no Apple Developer account needed) - Strips the quarantine attribute so the app can launch without Gatekeeper prompts
Once the first release is out:
brew install --cask 1989v/tap/muxbarA signed-by-hand .dmg will be attached to each GitHub Release. On first launch, right-click → Open to pass Gatekeeper (the app uses ad-hoc signing, not notarized).
Run from sources (some features are disabled in unbundled mode — see table below):
swift build
swift run muxbarRun the test suite (requires Xcode for XCTest):
swift test| Feature | swift run (unbundled) |
.app bundle |
|---|---|---|
| Session list / Attach / Kill / Preview | ✅ | ✅ |
| Keep Awake, Templates, Hotkeys | ✅ | ✅ |
| Open at Login (Login Item) | ⚠ (Settings → shown disabled) | ✅ |
| User notifications | ❌ | ✅ |
Features that need a proper .app bundle (Open at Login, notifications) fall back gracefully when running unbundled — the menu shows the item but disables the toggle with a hint.
| Shortcut | Action |
|---|---|
⌘⇧A |
Toggle Keep Awake |
⌘⇧1 ~ ⌘⇧9 |
Attach the N-th visible session |
Put YAML files under ~/Library/Application Support/muxbar/Templates/:
name: MyDev
description: My dev setup
sessionNameHint: mydev
windows:
- name: edit
command: nvim .
cwd: ~
- name: run
command: npm run dev
- name: logs
command: tail -f logs/app.log- Files starting with
_are ignored (so_example.yamlstays as a reference) - Reload via menu: New Session → Reload Templates
- Open the folder: New Session → Edit Templates…
- For real-world examples (OCI polling, capacity wait, backups) see Long-running script launcher above.
MIT © 2026 kgd
