Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Muster is a Rust library and CLI for terminal session group management built on tmux. It organizes terminal sessions into named, color-coded groups with saved profiles, runtime theming, and push-based state synchronization via tmux control mode.

What Muster Does

  • Organizes terminals by project — group related tabs (shell, server, logs) into a single named session
  • Saves profiles — define reusable templates for your project setups
  • Applies color themes — each group gets a distinct color in the tmux status bar
  • Syncs state via tmux — no polling, no stale state files; tmux is the single source of truth
  • Provides a library API — the CLI is a thin consumer of the muster Rust library; the API is designed for GUI integration

Who It’s For

Developers who work across multiple projects and maintain numerous terminal sessions — development servers, test runners, build watchers — spread across many terminal tabs with no organizational structure. Muster turns that chaos into named, color-coded groups you can launch, switch between, and tear down with single commands.

How It Works

Muster is a tmux interface layer, not a tmux replacement. It creates and manages tmux sessions on your behalf, storing metadata (name, color, profile reference) as tmux user options on the sessions themselves. Profiles are saved templates; running state lives entirely in tmux.

The architecture is a Cargo workspace with three crates:

CratePurpose
musterLibrary — tmux bindings, profiles, theming, control mode
muster-cliCLI binary
muster-notifymacOS notification helper (optional)

Documentation Structure

Installation

Prerequisites

  • tmux — installed and available in PATH
  • Rust — 2021 edition (for building from source)

Install from Source

cargo install --path crates/muster-cli

This installs the muster binary.

Optional: macOS Desktop Notifications

cargo install --path crates/muster-notify
muster notifications setup

This creates a minimal MusterNotify.app bundle at ~/.config/muster/MusterNotify.app/ containing the notification helper binary. The app bundle provides a CFBundleIdentifier (com.muster.notifier) that macOS requires for persistent Notification Center access. See Notifications for details.

Quick Start

Try It: System Dashboard

Here’s a ready-to-use profile you can launch right now. It opens three tabs — a shell, a live process monitor, and a live disk usage view:

muster profile save sysmon --color indigo \
  --tab 'Shell:~' \
  --tab 'Processes:~:top' \
  --tab 'Disk:~:sh -c "while true; do clear; df -h; sleep 5; done"'

muster up sysmon

You’re now inside tmux with three tabs. Switch between them with Ctrl-b n (next) or Ctrl-b 0/1/2. Detach with Ctrl-b d to return to your shell — the session keeps running.

Upgrading to htop

htop is a better process monitor with color output, mouse support, and easier process management. Install it if you don’t have it:

# macOS
brew install htop

# Debian/Ubuntu
sudo apt install htop

# Fedora/RHEL
sudo dnf install htop

Then edit the sysmon profile to swap in htop. From outside tmux, run:

muster profile edit sysmon

This opens the profile in $EDITOR as TOML. Find the Processes tab and change the command:

[[tabs]]
name = "Processes"
cwd = "/Users/you"
command = "top"        # change this to "htop"

Save and close the editor. Then bounce the session to pick up the change:

muster down sysmon
muster up sysmon

The Processes tab now runs htop.

Terminal Configuration

When you run muster up from inside an existing tmux session, muster opens a new terminal window rather than nesting sessions. It needs to know which terminal emulator to use.

Check the current setting:

muster settings

If it shows the wrong terminal, update it:

muster settings --terminal ghostty
muster settings --terminal kitty
muster settings --terminal alacritty
muster settings --terminal wezterm
muster settings --terminal iterm2

On macOS the default is Terminal.app (terminal). On Linux muster probes PATH for a known terminal. You only need to set this once — it persists in ~/.config/muster/settings.json.

See Configuration for all available settings.

Create Your Own Profile

Save a profile for a project:

muster profile save myproject --tab 'Shell:~/work/myproject' --color orange

Multi-tab example for a web project:

muster profile save webapp --color '#3b82f6' \
  --tab 'Shell:~/work/app' \
  --tab 'Server:~/work/app:npm start' \
  --tab 'Logs:~/work/app/logs'

Start a Session

muster up myproject

This creates the tmux session and drops you in. If the session already exists, up reattaches instead of creating a duplicate.

Check What’s Running

From another terminal:

muster status

Reattach

muster up sysmon

Ad-hoc Sessions

Create a throwaway session without saving a profile:

muster new scratch

Typical Workflow

  1. muster profile save — define a project (name, tabs, color)
  2. muster up <name> — start or reattach (execs tmux attach, replacing your shell)
  3. Work inside tmux. Use Ctrl-b d to detach back to your regular shell.
  4. muster up <name> again to reattach later
  5. muster status from another terminal to see all sessions
  6. muster down <name> when done

For more detailed workflows — including adopting existing tmux sessions, saving a session as a profile, and releasing sessions back to plain tmux — see Workflows.

Concepts

Terminal Group

A named tmux session containing one or more windows (tabs), each with a working directory and optional startup command. Groups have a display name, color, and optional profile reference.

App Concepttmux Concept
Terminal GroupSession
TabWindow
TerminalPane

Profile

A saved template for creating a group. Stored in ~/.config/muster/profiles.json. Contains the group’s name, color, and tab definitions.

Profiles are not running state — they’re blueprints. You can have a profile without a running session, or a running session created ad-hoc without a profile.

Session

A running tmux session managed by muster. Session names are prefixed with muster_ to distinguish them from personal tmux sessions. Application metadata (name, color, profile ID) is stored as tmux user options (@muster_name, @muster_color, @muster_profile) on the session itself — no separate state file.

Sources of Truth

There are exactly two sources of truth:

SourceOwns
tmuxAll running state: windows, CWDs, active window, plus @muster_* metadata
Config directorySaved profiles and settings — never runtime state

There is no application-level cache. When you need session state, muster asks tmux. This eliminates state synchronization bugs entirely.

Session Naming

All managed sessions use the prefix muster_ followed by a slugified profile ID:

muster_myproject
muster_web-app

This lets muster distinguish its sessions from your personal tmux sessions.

Workflows

Muster is flexible about how you get to a managed session — you can start from a saved profile or from a running tmux session. This page makes the common workflows concrete.

The Core Concepts

  • Profile — a saved template in ~/.config/muster/profiles.json. Defines name, color, and tabs. Persists across reboots.
  • Session — a live tmux session. May or may not have a backing profile.
  • Pinned tab — a window tied to the profile. Shows the session color. Recreated when you muster up.
  • Unpinned tab — a window with no profile backing. Shows a red . Lost when the session dies.

Profile First (The Happy Path)

You know what you want before you start.

muster profile save myproject \
  --tab 'Shell:~/work/myproject' \
  --tab 'Server:~/work/myproject:npm run dev' \
  --color blue

muster up myproject        # creates session and attaches

Next time:

muster up myproject        # reattaches if running, creates if not

When done:

muster down myproject      # kills the session (profile is kept)

Session First (Build Then Save)

You start working without a profile, then decide to keep it.

muster new scratch          # ad-hoc session, attaches immediately

Inside the session, open more tabs however you like (Ctrl-b c). When you’re happy with the layout:

muster profile save myproject --from-session scratch

This snapshots the current tabs, saves a profile, and pins all windows in the live session (red dots clear immediately). The session is now fully managed:

muster down scratch
muster up myproject         # recreates from profile

Adopting a Plain tmux Session

You have existing tmux sessions that predate muster.

tmux ls
# work: 3 windows (created ...)
# scratch: 1 window (created ...)

Bring one under muster management:

muster adopt work --name "Work" --color orange

This renames workmuster_work, applies the theme, and attaches. The session keeps running.

To also save a profile so the session can be recreated:

muster adopt work --name "Work" --color orange --save

--save snapshots the tabs into a profile and pins all windows in one step.


Formalizing an Ephemeral Muster Session

You have a muster-managed session (already has muster_ prefix) but no saved profile — tabs show red .

muster list
# Sessions:
#   ● muster_232 — 232 (2 windows, 2 unpinned)

Save it:

muster profile save 232 --from-session 232

This saves the profile and pins the live windows. The red dots clear immediately. Now muster up 232 can recreate the session if it ever dies.


Editing a Profile and Bouncing

Make changes to a saved profile and apply them to a fresh session.

muster profile edit myproject   # opens in $EDITOR as TOML

Or update inline:

muster profile update myproject --color teal
muster profile add-tab myproject --name Logs --cwd ~/work/myproject/logs

To pick up changes in a running session, bounce it:

muster down myproject
muster up myproject

Releasing a Session

Remove muster management while keeping the session alive. Useful if you want to hand off to plain tmux or clean up muster’s theming.

muster release myproject
# Released: muster_myproject → myproject

The session keeps running as plain tmux with no muster theme, hooks, or metadata. The profile is kept — you can muster up myproject later to create a fresh managed session.


Lifecycle Summary

plain tmux session ──── muster adopt ────► muster session
                                                │
                                         muster release
                                                │
                                                ▼
                                        plain tmux session

muster profile save ──────────────────► profile (file only)
                                                │
                                           muster up
                                                │
                                                ▼
                                         muster session ── muster down ──► dead
GoalCommand
Create profilemuster profile save <name> --tab ...
Start / reattachmuster up <name>
Tear downmuster down <name>
Ad-hoc sessionmuster new <name>
Save running session as profilemuster profile save <name> --from-session <session>
Adopt plain tmux sessionmuster adopt <session> --name <name>
Release from mustermuster release <session>
Edit profilemuster profile edit <name>

Profiles

Profiles are saved templates for creating terminal groups. They define the group’s name, color, and tab layout.

Creating Profiles

# Basic profile with one tab
muster profile save myproject --tab 'Shell:~/work/myproject' --color '#f97316'

# Multi-tab profile
muster profile save webapp --color '#3b82f6' \
  --tab 'Shell:~/work/app' \
  --tab 'Server:~/work/app:npm run dev' \
  --tab 'Logs:~/work/app/logs'

The --tab flag uses colon-delimited format: name:cwd or name:cwd:command. It is repeatable for multiple tabs. If omitted, defaults to a single “Shell” tab at $HOME.

Listing Profiles

muster profile list

Viewing a Profile

muster profile show myproject

Editing Profiles

Interactive Editing

Open the profile in your $EDITOR as TOML:

muster profile edit myproject

Inline Updates

Update specific fields without opening an editor:

muster profile update myproject --name renamed --color '#22c55e'

Managing Tabs

# Add a tab
muster profile add-tab myproject --name Tests --cwd ~/work/myproject --command 'cargo test --watch'

# Remove a tab (by name or 0-based index)
muster profile remove-tab myproject Tests
muster profile remove-tab myproject 2

Snapshotting a Running Session

Capture the current tabs and working directories of a live tmux session as a new profile:

muster profile save myproject --from-session <session-name>

This queries the session’s windows, captures their names and CWDs, and saves them as a profile. Useful for formalizing a workflow you built interactively.

Environment Variables

Set per-session environment variables in a profile by editing the TOML:

muster profile edit myproject
[env]
NODE_ENV = "development"
DATABASE_URL = "postgres://localhost/myapp"

These are applied via set-environment -t <session> when the session is created.

Per-Session tmux Options

Override tmux settings for a session without touching your global ~/.tmux.conf:

[tmux_options]
mouse = "on"
status-position = "top"

These are applied via set-option -t <session> at session creation.

Deleting Profiles

muster profile delete myproject

This removes the profile from profiles.json. It does not affect any running sessions that were launched from this profile.

Storage

Profiles are stored in ~/.config/muster/profiles.json:

{
  "profiles": {
    "myproject": {
      "id": "myproject",
      "name": "myproject",
      "color": "#f97316",
      "tabs": [
        { "name": "Shell", "cwd": "/Users/you/work/myproject", "command": null }
      ]
    }
  }
}

The config directory can be overridden with --config-dir or the MUSTER_CONFIG_DIR environment variable.

Sessions

Sessions are running tmux sessions managed by muster.

Starting Sessions

# From a profile (creates or reattaches)
muster up webapp

# Attach and switch to a specific tab
muster up webapp --tab 2

# Create without attaching
muster up webapp --detach

up is idempotent — if the session already exists, it attaches. If not, it creates from the profile and attaches.

up replaces the current process with exec tmux attach. Use --detach to create the session in the background without attaching.

Ad-hoc Sessions

Create a session without a saved profile:

muster new scratch --tab 'Shell:~/work' --color '#808080'
muster new scratch --detach

If --tab is omitted, defaults to a single “Shell” tab at $HOME.

Status

# Show all sessions with tab details
muster status

# List profiles and running sessions
muster list

Inspecting Sessions

# Show processes running inside sessions
muster ps
muster ps webapp

# Show listening ports
muster ports
muster ports webapp

Changing Colors

muster color webapp orange
muster color webapp '#22c55e'
muster colour webapp teal-dark   # colour is accepted as an alias

The tmux status bar updates instantly and the profile is updated, so the color persists on next muster up. If no session is running, updates the profile directly.

See Colors for the full list of named colors and shade variants.

Adopting Existing Sessions

Bring an existing (non-muster) tmux session under muster management:

muster adopt mysession --name webapp --color '#3b82f6'

This renames the session to muster_webapp and applies the muster status-bar theme. The --name flag defaults to the original session name. No profile is written — the session is managed live.

To also save a profile from the session’s current tabs:

muster adopt mysession --name webapp --color '#3b82f6' --save

Stopping Sessions

muster down webapp

Accepts a profile name, session ID, or full session name. Session metadata dies with the tmux session — no file cleanup needed.

JSON Output

All commands support --json for machine-readable output:

muster status --json
muster list --json
muster peek webapp --json

Colors

Muster sessions have a color applied to the tmux status bar. Colors can be set when creating a profile or changed live on a running session.

Usage

# Set by name
muster color webapp orange

# Set by hex
muster color webapp '#f97316'

# Set a shade variant
muster color webapp red-dark

# List available named colors
muster color --list

# colour is accepted as an alias
muster colour webapp teal

color accepts a profile name, session ID, or full session name. If a session is running, the status bar updates instantly and the profile is also updated. If no session is running, the profile is updated directly.

Named Colors

SwatchNameAliasesHex
black#000000
red#cc0000
green#4e9a06
yellow#c4a000
blue#3465a4
magenta#75507b
cyan#06989a
white#d3d7cf
orange#f97316
pink#ec4899
purpleviolet#a855f7
teal#14b8a6
lime#84cc16
amber#f59e0b
rose#f43f5e
indigo#6366f1
sky#0ea5e9
emerald#10b981
fuchsia#d946ef
coral#ff7f50
tomato#ff6347
crimson#dc143c
gold#ffd700
navy#000080
brownchocolate#8b4513
slate#64748b
graygrey#808080

Shade Variants

Append -light or -dark to any color name for a lighter or darker variant:

muster color webapp orange-light
muster color webapp orange-dark

The following families have curated Tailwind CSS shade values. Other named colors compute light/dark by mixing toward white or scaling channels.

Family-light-dark
slate#cbd5e1#334155
gray#d1d5db#374151
red#fca5a5#b91c1c
orange#fdba74#c2410c
amber#fcd34d#b45309
yellow#fde047#a16207
lime#bef264#4d7c0f
green#86efac#15803d
emerald#6ee7b7#047857
teal#5eead4#0f766e
cyan#67e8f9#0e7490
sky#7dd3fc#0369a1
blue#93c5fd#1d4ed8
indigo#a5b4fc#4338ca
violet#c4b5fd#6d28d9
purple#d8b4fe#7e22ce
fuchsia#f0abfc#a21caf
pink#f9a8d4#be185d
rose#fda4af#be123c

Hex Colors

Any hex color is accepted directly:

muster color webapp '#a855f7'
muster color webapp '#10b981'

Peek

Check on a session’s terminal output without attaching:

muster peek myproject               # all tabs, last 50 lines each
muster peek myproject Shell         # specific tab only
muster peek myproject -n 10         # last 10 lines per tab
muster peek myproject --json        # machine-readable output

Peek uses tmux capture-pane to grab scrollback from each tab. It’s a read-only operation that doesn’t affect the session.

Death Snapshots

When a tab’s process exits, muster captures the last 50 lines of output before cleaning up the dead tab. Snapshots are saved to ~/.config/muster/logs/<session_name>/<tab_name>.last.

Files are overwritten on each death event per tab name, keeping the directory small. The last few lines are included in the desktop notification body when notifications are enabled.

This preserves output that would otherwise be lost when tmux cleans up dead tabs — useful for seeing why a build or server crashed without having been attached at the time.

Pin & Unpin

Pin and unpin sync the current tab’s state back to the session’s profile.

Pin

muster pin

Run this from inside a muster-managed tmux session. It saves the current tab’s name, working directory, and command to the session’s profile. This is useful when you’ve customized a tab at runtime and want those changes persisted.

Unpin

muster unpin

Removes the current tab from the session’s profile. The tab continues to exist in the running session but won’t be recreated when the profile is run again.

Tab Rename Sync

Muster installs a tmux hook that automatically syncs tab renames to the profile when a tab is pinned. This means renaming a tab with Ctrl-b , updates the profile if the tab is pinned.

Notifications

Muster sends notifications on session events — pane exits (with last output lines) and terminal bell alerts.

Default Behavior

By default, notifications appear as tmux status bar messages. No setup required.

macOS Desktop Notifications

On macOS, you can enable native desktop notifications (Notification Center):

cargo install --path crates/muster-notify
muster notifications setup

This creates a minimal MusterNotify.app bundle at ~/.config/muster/MusterNotify.app/ containing the muster-notify helper binary. The app bundle provides a CFBundleIdentifier (com.muster.notifier) that macOS requires for persistent Notification Center access.

macOS may prompt you to allow notifications from Muster on first use.

When the helper is installed, notifications are delivered to Notification Center instead of the tmux status bar.

SSH Fallback

Over SSH (SSH_CONNECTION is set), muster falls back to tmux display-message automatically, regardless of whether the notification helper is installed.

Removing Notifications

muster notifications remove

This removes the MusterNotify.app bundle. Notifications revert to tmux status bar messages.

How It Works

Muster installs tmux hooks (pane-died and alert-bell) that invoke CLI subcommands to deliver notifications. The hooks are set per-session when a session is created.

Pane death notifications include the last few lines of terminal output in the notification body, so you can see at a glance why something crashed.

Configuration

Config Directory

Muster stores configuration in ~/.config/muster/ by default. Override with --config-dir or the MUSTER_CONFIG_DIR environment variable.

~/.config/muster/
├── profiles.json             # Saved terminal group profiles
├── settings.json             # Global settings
├── logs/                     # Death snapshots
│   └── <session_name>/
│       └── <window_name>.last
└── Muster.app/               # macOS notification helper (optional)

Settings (settings.json)

{
  "terminal": "ghostty",
  "shell": "/usr/local/bin/fish",
  "tmux_path": null
}

Settings can be viewed and updated with the muster settings command:

# Show current settings
muster settings

# Update a setting
muster settings --terminal ghostty
muster settings --shell /usr/local/bin/fish
muster settings --tmux-path /usr/local/bin/tmux

terminal

The terminal emulator to open when launching a session from inside tmux. If omitted, muster uses the platform default (Terminal.app on macOS; detected from PATH on Linux).

Supported values: ghostty, kitty, alacritty, wezterm, terminal (Terminal.app), iterm2.

shell

Overrides the default shell for new tmux panes. If omitted, muster uses $SHELL. Set this if your $SHELL differs from the shell you actually use (common on macOS where $SHELL defaults to /bin/zsh).

tmux_path

Overrides tmux discovery from $PATH. Set this if tmux is installed in a non-standard location.

Profiles (profiles.json)

See Profiles for the full profile schema and management commands.

Shell Integration

Muster can suggest launching profiles when you cd into a directory associated with one. Add the shell hook to your shell config:

Fish — add to ~/.config/fish/config.fish:

muster shell-init fish | source

Bash — add to ~/.bashrc or ~/.bash_profile:

eval "$(muster shell-init bash)"

Zsh — add to ~/.zshrc:

eval "$(muster shell-init zsh)"

After setup, when you cd into a directory that matches a profile tab’s CWD, muster prints a suggestion:

muster: profile 'webapp' matches this directory. Run: muster up webapp

Command-Line Help for muster

This document contains the help content for the muster command-line program.

Command Overview:

muster

Terminal session group management built on tmux.

Muster organizes terminal sessions into named, color-coded groups with saved profiles, runtime theming, and push-based state synchronization via tmux control mode.

Usage: muster [OPTIONS] <COMMAND>

Subcommands:
  • list — List profiles and running sessions
  • up — Create or attach to a profile’s session
  • down — Destroy a session
  • new — Create an ad-hoc session
  • color — Manage session colors
  • ps — Show processes running inside sessions
  • ports — Show listening ports inside sessions
  • top — Show resource usage (CPU, memory, GPU) for session processes
  • status — Show all sessions with details
  • peek — Peek at recent terminal output
  • pin — Pin the current tab to the session’s profile
  • unpin — Unpin the current tab from the session’s profile
  • profile — Profile management
  • notifications — Notification management
  • release — Release a muster-managed session back to plain tmux
  • adopt — Adopt an existing tmux session under muster management
  • shell-init — Output shell integration code for automatic profile suggestions on cd
  • settings — Show or update settings
Options:
  • --config-dir <CONFIG_DIR> — Path to the config directory
  • --json — Output in JSON format

muster list

List profiles and running sessions

Usage: muster list

muster up

Create or attach to a profile’s session

Usage: muster up [OPTIONS] <PROFILE>

Arguments:
  • <PROFILE> — Profile name or ID
Options:
  • --tab <TAB> — Switch to this tab index on attach
  • --detach — Create session but don’t attach

muster down

Destroy a session

Usage: muster down <SESSION>

Arguments:
  • <SESSION> — Profile name, ID, or session name

muster new

Create an ad-hoc session

Usage: muster new [OPTIONS] <NAME>

Arguments:
  • <NAME> — Display name
Options:
  • --tab <TAB> — Tab definition (name:cwd[:command]), repeatable

  • --color <COLOR> — Color (hex)

    Default value: #808080

  • --detach — Create session but don’t attach

muster color

Manage session colors

Usage: muster color [OPTIONS] [SESSION] [COLOR]

Arguments:
  • <SESSION> — Profile name, ID, or session name
  • <COLOR> — New color (hex or named)
Options:
  • --list — List available named colors

muster ps

Show processes running inside sessions

Usage: muster ps [PROFILE]

Arguments:
  • <PROFILE> — Profile name or ID (shows all sessions if omitted)

muster ports

Show listening ports inside sessions

Usage: muster ports [PROFILE]

Arguments:
  • <PROFILE> — Profile name or ID (shows all sessions if omitted)

muster top

Show resource usage (CPU, memory, GPU) for session processes

Usage: muster top [PROFILE]

Arguments:
  • <PROFILE> — Profile name or ID (shows all sessions if omitted)

muster status

Show all sessions with details

Usage: muster status

muster peek

Peek at recent terminal output

Usage: muster peek [OPTIONS] <SESSION> [TABS]...

Arguments:
  • <SESSION> — Profile name, ID, or session name
  • <TABS> — Tab names to show (all if omitted)
Options:
  • -n, --lines <LINES> — Lines of output per tab

    Default value: 50

muster pin

Pin the current tab to the session’s profile

Usage: muster pin

muster unpin

Unpin the current tab from the session’s profile

Usage: muster unpin

muster profile

Profile management

Usage: muster profile <COMMAND>

Subcommands:
  • list — List all profiles
  • delete — Delete a profile
  • save — Save a new profile (or snapshot a running session with –from-session)
  • add-tab — Add a tab to an existing profile
  • show — Show a profile’s full definition
  • edit — Edit a profile in $EDITOR
  • update — Update profile fields inline
  • remove-tab — Remove a tab from a profile

muster profile list

List all profiles

Usage: muster profile list

muster profile delete

Delete a profile

Usage: muster profile delete <ID>

Arguments:
  • <ID> — Profile name or ID

muster profile save

Save a new profile (or snapshot a running session with –from-session)

Usage: muster profile save [OPTIONS] <NAME>

Arguments:
  • <NAME> — Profile name
Options:
  • --tab <TAB> — Tab definition (name:cwd[:command]), repeatable

  • --color <COLOR> — Color (hex or named)

    Default value: #808080

  • --from-session <SESSION> — Snapshot tabs from a running tmux session

muster profile add-tab

Add a tab to an existing profile

Usage: muster profile add-tab [OPTIONS] --name <NAME> --cwd <CWD> <PROFILE>

Arguments:
  • <PROFILE> — Profile name or ID
Options:
  • --name <NAME> — Tab name
  • --cwd <CWD> — Working directory
  • --command <COMMAND> — Startup command

muster profile show

Show a profile’s full definition

Usage: muster profile show <ID>

Arguments:
  • <ID> — Profile name or ID

muster profile edit

Edit a profile in $EDITOR

Usage: muster profile edit <ID>

Arguments:
  • <ID> — Profile name or ID

muster profile update

Update profile fields inline

Usage: muster profile update [OPTIONS] <ID>

Arguments:
  • <ID> — Profile name or ID
Options:
  • --name <NAME> — New display name
  • --color <COLOR> — New color (hex or named)

muster profile remove-tab

Remove a tab from a profile

Usage: muster profile remove-tab <PROFILE> <TAB>

Arguments:
  • <PROFILE> — Profile name or ID
  • <TAB> — Tab name or 0-based index

muster notifications

Notification management

Usage: muster notifications <COMMAND>

Subcommands:
  • setup — Install macOS notification app bundle
  • remove — Remove macOS notification app bundle
  • test — Send a test notification to verify the notification system works

muster notifications setup

Install macOS notification app bundle

Usage: muster notifications setup

muster notifications remove

Remove macOS notification app bundle

Usage: muster notifications remove

muster notifications test

Send a test notification to verify the notification system works

Usage: muster notifications test

muster release

Release a muster-managed session back to plain tmux

Usage: muster release [OPTIONS] <SESSION>

Arguments:
  • <SESSION> — Profile name, ID, or session name
Options:
  • --name <NAME> — New name for the released session (defaults to session name without muster_ prefix)

muster adopt

Adopt an existing tmux session under muster management

Usage: muster adopt [OPTIONS] <SESSION>

Arguments:
  • <SESSION> — Existing tmux session name
Options:
  • --name <NAME> — Display name (defaults to session name)

  • --color <COLOR> — Color (hex or named)

    Default value: #808080

  • --save — Also save as a persistent profile

  • --detach — Adopt without attaching

muster shell-init

Output shell integration code for automatic profile suggestions on cd

Usage: muster shell-init <SHELL>

Arguments:
  • <SHELL> — Shell type: fish, bash, or zsh

muster settings

Show or update settings

Usage: muster settings [OPTIONS]

Options:
  • --terminal <TERMINAL> — Set terminal emulator (e.g. ghostty, alacritty, kitty, wezterm, terminal, iterm2)
  • --shell <SHELL> — Set default shell
  • --tmux-path <TMUX_PATH> — Set tmux binary path

This document was generated automatically by clap-markdown.

Architecture Overview

Muster is organized as a Cargo workspace with three crates:

crates/
├── muster/         # Library — tmux bindings, profiles, theming, control mode
├── muster-cli/     # CLI binary
└── muster-notify/  # macOS notification helper (minimal binary for Muster.app bundle)

Design Principles

  1. tmux is the runtime — muster is an organizational layer on top of tmux, not a replacement
  2. Library-first — the CLI is a thin consumer of the muster library crate; the API is designed to support GUI applications without modification
  3. No application state — running session metadata lives in tmux user options, not in files
  4. Push-based sync — control mode provides structured notifications; no polling for state

Library Modules

ModulePurpose
tmux::clientCommand execution, output parsing, session/window CRUD
tmux::controlControl mode connection, event stream parsing (MusterEvent)
tmux::typesTmuxSession, TmuxWindow, SessionInfo
config::profileProfile CRUD with atomic JSON persistence
config::settingsSettings (tmux path, shell preference)
sessionSession lifecycle — create from profile, destroy
session::themeHex color parsing, dimming, tmux status bar styling
musterMuster facade tying everything together

Data Flow

Commands:    CLI (or GUI) → library → tmux / config
State:       Runtime state always from tmux, metadata from config files
Events:      tmux control mode → library → subscribers

Control mode notifications cover window lifecycle, session lifecycle, and active tab changes. CWD tracking uses tmux’s native pane_current_path with on-demand queries.

Component Diagram

        ┌──────────────┐
        │              │
        │  CLI binary  │
        │   (muster)   │
        │              │
        └──────┬───────┘
               │
        ┌──────▼──────┐
        │             │
        │   muster    │
        │  (library)  │
        │             │
        └──┬───────┬──┘
           │       │
     ┌─────▼──┐ ┌──▼──────────────┐
     │ Config │ │      tmux       │
     │  dir   │ │  (sessions,     │
     │ (JSON) │ │   control mode) │
     └────────┘ └─────────────────┘

tmux Interface

Sources of Truth

SourceOwns
tmuxAll running state: windows, CWDs, active window, plus @muster_* metadata
Config directorySaved profiles and settings — never runtime state

There is no application-level cache of tmux state. When a consumer needs to know what tabs a group has, it asks tmux.

Session Metadata

Running session metadata is stored as tmux user options:

tmux User OptionValueExample
@muster_nameDisplay name"Web App"
@muster_colorHex color"#f97316"
@muster_profileProfile ID"web-app"

Set on creation, queryable at any time:

tmux show-option -t muster_web-app -v @muster_color
tmux list-sessions -F '#{session_name} #{@muster_name} #{@muster_color}'

Control Mode

For long-running consumers (GUI applications), muster establishes tmux control mode connections. Control mode is a persistent stdin/stdout pipe via tmux -CC attach -t <session> that provides push-based notifications:

Events Consumed

Window lifecycle:

NotificationLibrary Action
%window-addQuery window details, emit tab-added event
%window-closeEmit tab-closed event
%window-renamedEmit tab-renamed event
%session-window-changedEmit active-tab-changed event

Session lifecycle:

NotificationLibrary Action
%sessions-changedRe-query session list
%session-changedUpdate active session tracking

Output notifications (%output) are suppressed via refresh-client -f no-output.

Response Framing

Commands sent through control mode produce structured output blocks:

%begin <timestamp> <command_number> <flags>
<output lines>
%end <timestamp> <command_number> <flags>

tmux Hooks

Muster uses tmux hooks selectively for fire-and-forget actions:

  • pane-died — invokes muster _pane-died to capture death snapshots and send notifications
  • alert-bell — invokes muster _bell to send bell notifications
  • window-renamed — invokes muster sync-rename to sync pinned window names to profiles

Hooks are appropriate here because they trigger one-shot external commands rather than feeding a stateful event stream.

Color Theming

Each session’s color is applied to the tmux status bar:

tmux set-option -t <session> status-style "bg=<color>,fg=#000000"
tmux set-option -t <session> status-left "#[bg=<darker>,fg=#ffffff,bold] <name> #[default]"
tmux set-option -t <session> window-status-current-format "#[fg=<color>,bg=#000000,bold] #I: #W #[default]"

Color changes are live — no session restart required.

Library Usage

The muster library crate provides a Rust API for terminal session group management.

Basic Usage

#![allow(unused)]
fn main() {
use muster::{Muster, Profile, TabProfile};
use std::path::Path;

let m = Muster::init(Path::new("~/.config/muster"))?;

// Create a profile
let profile = Profile {
    id: "my-project".into(),
    name: "My Project".into(),
    color: "#f97316".into(),
    tabs: vec![
        TabProfile {
            name: "Shell".into(),
            cwd: "/home/user/project".into(),
            command: None,
            layout: None,
            panes: vec![],
        },
        TabProfile {
            name: "Server".into(),
            cwd: "/home/user/project".into(),
            command: Some("npm run dev".into()),
            layout: None,
            panes: vec![],
        },
    ],
};
m.save_profile(profile.clone())?;

// Launch a session
let info = m.launch(&profile.id)?;

// List running sessions
let sessions = m.list_sessions()?;

// Subscribe to events (for GUI integration)
let rx = m.subscribe();
}

Event Subscription

The library provides push-based event notifications via tokio::broadcast:

#![allow(unused)]
fn main() {
let mut rx = muster.subscribe();
tokio::spawn(async move {
    while let Ok(event) = rx.recv().await {
        match event {
            MusterEvent::TabAdded { session, window_index, name } => { /* ... */ },
            MusterEvent::TabClosed { session, window_index } => { /* ... */ },
            MusterEvent::SessionEnded { session } => { /* ... */ },
            // ...
        }
    }
});
}

API Documentation

Full API documentation is available at the API Reference, generated from rustdoc comments on all public types, functions, and modules.

Testing

Unit Tests

Unit tests do not require tmux:

# With cargo-nextest
cargo nextest run

# With cargo test
cargo test

Integration Tests

Integration tests create real tmux sessions and require tmux to be installed:

# With cargo-nextest
cargo nextest run --run-ignored all

# With cargo test
cargo test -- --ignored

Integration tests create sessions with unique names and clean up after themselves. They do not interfere with your personal tmux sessions.

What’s Tested

Unit tests (no tmux required):

  • Profile CRUD (reads/writes JSON files in a temp directory)
  • Color computation (hex parsing, dimming, tmux style string generation)
  • Session name convention (encoding/decoding profile IDs)
  • Control mode stream parser (given raw control mode output, verify parsed events)

Integration tests (tmux required):

  • Session lifecycle: create from profile, verify tabs exist, destroy
  • Tab operations: add, close, rename, verify via tmux queries
  • Theme application: set color, verify tmux options
  • Control mode: connect, receive events on window add/close

Contributing

Development Commands

cargo t              # alias for cargo nextest run
cargo clippy         # lint
cargo fmt --check    # format check
cargo doc --no-deps  # build docs (check for warnings)

Project Structure

crates/
├── muster/             # Library crate (tmux bindings, profiles, theming, control mode)
├── muster-cli/         # CLI binary crate
│   └── src/
│       ├── main.rs         # Entry point, CLI dispatch (~125 lines)
│       ├── cli.rs          # Clap command definitions (library target)
│       ├── commands/       # One module per command (list, up/launch, down/kill, etc.)
│       ├── format.rs       # Terminal formatting (color dots, memory display)
│       ├── tabs.rs         # Tab definition parsing
│       ├── editing.rs      # TOML profile editing types
│       ├── terminal.rs     # tmux attach, notification helpers
│       ├── proctree.rs     # Process tree building/rendering
│       ├── ports.rs        # Listening port detection
│       └── resources.rs    # CPU/memory/GPU resource collection
└── muster-notify/      # macOS notification helper
docs/                   # mdBook documentation (this site)

Documentation

Building Docs Locally

# mdBook user guide
mdbook serve docs

# API reference (rustdoc)
cargo doc --no-deps --open

# Regenerate CLI reference
cargo run --example gen_cli_docs -p muster-cli > docs/src/cli-reference.md

Writing Doc Comments

All public types, functions, and modules should have rustdoc comments:

  • //! for module-level docs
  • /// for public types, functions, and methods

Code Quality

The workspace enforces:

  • unsafe_code = "deny" — no unsafe Rust
  • clippy::all and clippy::pedantic — comprehensive linting
  • All public items documented