A terminal user interface for managing Mutagen sync sessions.
For more development tools, see: https://osteele.com/software/development-tools
- Unified hierarchical view: Projects and their sync specs in a single tree view
- Fold/unfold projects to show or hide individual sync specs
- Auto-unfold when conflicts are detected
- Project discovery: Automatically finds and displays
mutagen.ymlfiles- Searches the specified directory (or current directory) and subdirectories
- Supports multiple config files per directory (
mutagen-<target>.ymlpattern) - Correlates project files with running sessions
- Push mode support: Create one-way sync sessions (alpha → beta)
- Push individual specs or entire projects
- Automatically replaces two-way sessions when creating push
- Clear visual indicators for push mode (⬆ arrow, "(push)" label)
- Light and dark themes: Defaults to light theme, dark theme available via
MUTAGUI_THEME=dark - Auto-refresh: Session list and projects update every 3 seconds automatically
- Real-time activity indicators:
- Connection status icons (✓ connected, ⊗ disconnected, ⟳ scanning)
- Session status icons (👁 watching, 📦 staging, ⚖ reconciling, etc.)
- File and directory counts for each endpoint
- Sync status display with progress percentages
- Interactive keyboard controls for managing syncs:
- Start/stop projects and individual specs
- Create push sessions
- Pause/resume sessions
- Terminate and flush sessions
- View and resolve conflicts
- Edit project configuration files
- Manual refresh
- Last refresh timestamp display
- Mutagen must be installed and in your PATH
- Go 1.21+ (for building from source)
go install github.com/osteele/mutagui@latest# Clone the repository
git clone https://github.com/osteele/mutagui.git
cd mutagui
# Build and install
just install
# Or manually with Go
go install .Simply run the application:
mutaguiOr if building locally:
just runmutagui [OPTIONS]
Options:
-d, --project-dir <DIR> Directory to search for mutagen project files
(default: current directory)
-h, --help Print helpExamples:
# Use current directory (default)
mutagui
# Search for projects starting from ~/code
mutagui --project-dir ~/code
# Short form
mutagui -d ~/projectsThe --project-dir option specifies where to start searching for mutagen.yml files. The application will:
- Search the specified directory and its subdirectories (up to 4 levels deep)
- Also check user config directories (
~/.config/mutagen/projects/,~/.mutagen/projects/)
The TUI displays a hierarchical tree view of projects and their sync specs:
┌─ Sync Projects ─────────────────────────────────────────────────────────────┐
│ ▼ ✓ apollo-research 2/3 running (1 push) │
│ ● apollo-research (push) 👁 ✓~/code/research ⬆ ✓apollo:/data/. │
│ ● apollo-research-tools 👁 ✓~/code/tools ⇄ ✓apollo:/data/... │
│ ○ apollo-datasets Not running │
│ ▶ ○ mercury-ml 0/2 running │
│ ▼ ✓ starship-dev 1/1 running, 1 waiting ⚠ 3 conflicts │
│ ● sync-to-orbit 📦 ✓~/code/starship ⇄ ⊗orbit:/home/. │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Help ───────────────────────────────────────────────────────────────────────┐
│ ↑/↓/j/k Nav │ h/l/↵ Fold │ r Refresh │ e Edit │ s Start/Stop │ P Push │... │
└──────────────────────────────────────────────────────────────────────────────┘
┌─ Status ─────────────────────────────────────────────────────────────────────┐
│ Created 1 push session(s) | Last refresh: 12:34:56 │
└──────────────────────────────────────────────────────────────────────────────┘
Visual Indicators:
- Fold state:
▼(expanded) /▶(collapsed) - Project status:
✓(active) /○(inactive) - Spec status:
●(running) /⏸(paused) /○(not running) - Sync direction:
⇄(two-way) /⬆(push mode, bold/colored) - Transfer direction:
↓(downloading) /↑(uploading) - shown during staging - Push mode label: Specs show
(push)suffix when in push mode - Endpoint status:
✓(connected) /⟳(scanning) /⊗(disconnected) - Session activity:
👁(watching) /📦(staging) /⚖(reconciling) / etc. - Conflicts:
⚠ 3 conflictsshown on project header
| Key | Action |
|---|---|
↑ / k |
Move selection up |
↓ / j |
Move selection down |
h / ← / l / → / Enter |
Toggle fold/unfold project |
| Key | Action |
|---|---|
r |
Refresh session list and projects |
m |
Toggle display mode (show paths vs. last sync time) |
? |
Show help screen with all commands |
q / Ctrl-C |
Quit application |
- Click on a list item to select it
- Click on a project header to fold/unfold
- Shift+click and drag to select text (bypasses app mouse handling for copying)
| Key | Action |
|---|---|
e |
Edit project configuration file |
s |
Start all specs in project |
t |
Terminate all specs in project |
f |
Flush all specs in project |
P |
Create push sessions for all specs |
p / Space |
Pause/resume all running specs |
u |
Resume all paused specs |
| Key | Action |
|---|---|
s |
Start this spec |
t |
Terminate this spec |
f |
Flush this spec |
P |
Create push session (replaces two-way if running) |
p / Space |
Pause/resume spec |
u |
Resume paused spec |
c |
View conflicts |
i |
View sync status details |
When pressing e to edit a project file:
Editor Selection:
$VISUALenvironment variable (if set)$EDITORenvironment variable (if set)vim(default fallback)
Automatic GUI Detection:
The application automatically detects whether your editor is a GUI application or terminal-based and adjusts its behavior accordingly:
- GUI editors (VS Code, Zed, Sublime Text, etc.): The TUI remains active in the background while your editor opens in a separate window. No terminal disruption.
- Terminal editors (vim, nano, emacs, etc.): The TUI suspends and restores your terminal to normal mode, then resumes after you exit the editor.
Supported GUI Editors (automatically detected):
- VS Code (
code,code-insiders) - Zed (
zed) - Sublime Text (
subl,sublime,sublime_text) - Atom (
atom) - GNOME editors (
gedit,gnome-text-editor) - KDE editors (
kate,kwrite) - XFCE editors (
mousepad,xed) - MATE editor (
pluma) - macOS editors (
bbedit,textmate,textedit,xcode) - GUI Vim variants (
macvim,gvim)
Supported Terminal Editors (automatically detected):
- vim, vi, nvim
- nano, pico
- emacs, emacsclient
- helix, hx
- kakoune, kak
- micro, joe, jed
- ed, ex
SSH Behavior: When connected via SSH, the application assumes terminal editors only (GUI editors won't work).
Manual Override: If detection is incorrect for your editor, set:
export MUTAGUI_EDITOR_IS_GUI=true # Force GUI behavior
export MUTAGUI_EDITOR_IS_GUI=false # Force terminal behaviorThe application defaults to light theme. To use dark theme:
export MUTAGUI_THEME=darkThe application automatically discovers mutagen.yml project files to help you manage your sync sessions. Understanding where these files are searched can help you organize your projects effectively.
Starting from the base directory (current directory by default, or specified with --project-dir), the application searches for mutagen.yml and mutagen-*.yml files:
-
Base directory and subdirectories (up to 4 levels deep):
mutagen.yml,mutagen.yamlmutagen-*.yml,mutagen-*.yaml(target-specific configurations)
-
User configuration directories:
~/.config/mutagen/projects/~/.mutagen/projects/
mutagen.yml- Standard project configuration filemutagen-<target>.yml- Target-specific configurations (e.g.,mutagen-apollo.yml,mutagen-mercury.yml).mutagen.ymland.mutagen-<target>.yml- Hidden variants of the above
This naming scheme allows you to maintain multiple Mutagen configurations in the same directory for different sync targets.
The file discovery uses non-recursive glob patterns for fast startup. Deep directory traversal with **/ patterns is avoided to prevent scanning thousands of files unnecessarily.
The TUI shows a unified hierarchical view with:
Shows all projects and their sync specs in a tree structure:
- Project headers:
- Fold indicator: ▼ (expanded) or ▶ (collapsed)
- Status icon: ✓ (active) or ○ (inactive)
- Project name (e.g.,
mutagen-apollo,starship-dev) - Running status: "Running", "Not running", or "X/Y running"
- Push mode count when applicable: "(2 push)"
- Connection issues when present: ", 1 waiting" (disconnected endpoints)
- Conflict indicator when present: "⚠ 3 conflicts"
- Sync specs (shown when project is expanded):
- Status icon: ● (running), ⏸ (paused), or ○ (not running)
- Spec name with push mode label:
sync-name (push) - Session status icon: 👁 (watching), 📦 (staging), ⚖ (reconciling), etc.
- Alpha endpoint with connection status and path
- Direction arrow: ⇄ (two-way) or ⬆ (push mode, in bold color)
- Beta endpoint with connection status and path
| Icon | Status | Description |
|---|---|---|
| 👁 | Watching | Connected and idle, waiting for file changes |
| 🔌 | Connecting | Establishing connection to remote endpoint |
| 🔍 | Scanning | Scanning files for changes |
| 📦 | Staging | Transferring file content that needs to be synced |
| ⚖ | Reconciling | Computing what changes to make on each side |
| ⏳ | Transitioning | Applying changes (writes/deletes/modifications) to the filesystem |
| 💾 | Saving | Saving synchronized changes |
| ⛔ | Halted | Session halted due to error |
| • | Unknown | Unknown or other status |
When syncing, Mutagen progresses through these phases:
- Scanning → Examines both endpoints for changes
- Staging → Transfers file content that needs to be synced
- Reconciling → Computes what changes to make on each side
- Transitioning → Applies the changes to the filesystem
- Watching → Monitors for new file changes
The Status area shows progress percentage during staging (e.g., "Staging (45%)").
| Icon | Status |
|---|---|
| ✓ | Connected and scanned |
| ⟳ | Connected, scanning |
| ⊗ | Disconnected |
- Current status message
- Last refresh timestamp
- When a staging session is selected, shows transfer details:
- Direction indicator:
↓(downloading to local) or↑(uploading to remote) - Progress percentage and current file name
- File size progress:
[16.8M/248.9M] - File count:
3/47 files
- Direction indicator:
Press i when a running spec is selected to open a detailed sync status overlay:
╭─ Sync Status: studio-research (Esc or 'i' to close) ───────────────╮
│ │
│ Direction: ↓ Downloading (staging to local) │
│ Status: Staging │
│ │
│ Current file: LM2/checkpoints/model.safetensors │
│ File progress: [████████░░░░░░░░░░░░░░░░░░░░░░] 27% │
│ 67.2 MB / 248.9 MB │
│ │
│ Overall: 3 / 47 files │
│ Total transferred: 67.2 MB │
│ │
│ Alpha (local): ✓ connected, ✓ scanned │
│ Beta (remote): ✓ connected, ✓ scanned │
│ │
╰─────────────────────────────────────────────────────────────────────╯
Press Esc or i again to close the overlay.
The push feature allows you to create one-way sync sessions (alpha → beta) from a project definition. This is useful for quickly pushing local changes to a remote without starting a full bidirectional sync.
To create push sessions:
For a single spec:
- Select an individual sync spec (navigate to it with arrow keys)
- Press
pto create a push session- If a two-way session is running, it will be automatically terminated and replaced
- A new session named
<spec-name>-pushwill be created
For all specs in a project:
- Select a project header
- Press
pto create push sessions for all specs- All running two-way sessions will be terminated
- Push sessions will be created for each spec defined in the project file
The application creates sessions with:
- Mode:
one-way-replica(alpha → beta) - Endpoints from the project file
- Ignore patterns from the project configuration
Ignore Pattern Support:
✅ Fully Supported:
-
Simple list format in YAML
sync: myproject: alpha: /local/path beta: user@host:/remote/path ignore: - node_modules - .git - "*.tmp"
-
sync.defaultssection (merged with session-specific rules)sync: defaults: ignore: - .git - node_modules myproject: alpha: /local/path beta: user@host:/remote/path ignore: - "*.tmp" # Combined with defaults
-
Object format with
pathskeysync: myproject: alpha: /local/path beta: user@host:/remote/path ignore: paths: - node_modules - .git
-
VCS ignore flag (ignores
.git,.svn,.hg,.bzr,_darcs,.fossil-settings)sync: myproject: alpha: /local/path beta: user@host:/remote/path ignore: vcs: true
-
Combined VCS and custom paths
sync: myproject: alpha: /local/path beta: user@host:/remote/path ignore: vcs: true paths: - node_modules - "*.tmp"
❌ Not yet supported:
- Regular expression patterns (
ignore: { regex: "pattern.*" })
Note: Ignore patterns from sync.defaults are merged with session-specific patterns. Session-specific patterns are added to (not replacing) defaults.
This is a Go project using tview for the terminal UI.
# Build the binary
just build
# Or directly with Go
go build -o mutagui .just test# Format code
just format
# Run linter
just lint
# Run all checks
just checkInterested in contributing? See CONTRIBUTING.md for development setup, architecture details, and guidelines.
MIT
Oliver Steele (@osteele)