https://github.com/osteele/mutagui
A terminal user interface (TUI) for managing Mutagen sync sessions
https://github.com/osteele/mutagui
file-sync mutagen rust terminal tui
Last synced: 2 months ago
JSON representation
A terminal user interface (TUI) for managing Mutagen sync sessions
- Host: GitHub
- URL: https://github.com/osteele/mutagui
- Owner: osteele
- Created: 2025-10-24T07:20:36.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-12-24T03:40:20.000Z (6 months ago)
- Last Synced: 2025-12-25T17:12:44.807Z (6 months ago)
- Topics: file-sync, mutagen, rust, terminal, tui
- Language: Go
- Size: 247 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# Mutagen TUI
[](https://goreportcard.com/report/github.com/osteele/mutagui)
[](https://pkg.go.dev/github.com/osteele/mutagui)
[](https://opensource.org/licenses/MIT)
A terminal user interface for managing [Mutagen](https://mutagen.io/) sync sessions.
For more development tools, see: https://osteele.com/software/development-tools
## Features
- **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.yml` files
- Searches the specified directory (or current directory) and subdirectories
- Supports multiple config files per directory (`mutagen-.yml` pattern)
- 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
## Prerequisites
- [Mutagen](https://mutagen.io/) must be installed and in your PATH
- Go 1.21+ (for building from source)
## Installation
### Using Go
```bash
go install github.com/osteele/mutagui@latest
```
### From Source
```bash
# Clone the repository
git clone https://github.com/osteele/mutagui.git
cd mutagui
# Build and install
just install
# Or manually with Go
go install .
```
## Usage
Simply run the application:
```bash
mutagui
```
Or if building locally:
```bash
just run
```
### Command-Line Options
```bash
mutagui [OPTIONS]
Options:
-d, --project-dir Directory to search for mutagen project files
(default: current directory)
-h, --help Print help
```
**Examples:**
```bash
# Use current directory (default)
mutagui
# Search for projects starting from ~/code
mutagui --project-dir ~/code
# Short form
mutagui -d ~/projects
```
The `--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/`)
## Interface Overview
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 conflicts` shown on project header
### Keyboard Controls
#### Navigation
| Key | Action |
|-----|--------|
| `↑` / `k` | Move selection up |
| `↓` / `j` | Move selection down |
| `h` / `←` / `l` / `→` / `Enter` | Toggle fold/unfold project |
#### Global Actions
| 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 |
#### Mouse
- **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)
#### Project Actions (when project selected)
| 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 |
#### Spec Actions (when individual spec selected)
| 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 |
### Editor Integration
When pressing `e` to edit a project file:
**Editor Selection:**
1. `$VISUAL` environment variable (if set)
2. `$EDITOR` environment variable (if set)
3. `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:
```bash
export MUTAGUI_EDITOR_IS_GUI=true # Force GUI behavior
export MUTAGUI_EDITOR_IS_GUI=false # Force terminal behavior
```
### Theme
The application defaults to light theme. To use dark theme:
```bash
export MUTAGUI_THEME=dark
```
## Configuration Files
The 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.
### Search Locations
Starting from the base directory (current directory by default, or specified with `--project-dir`), the application searches for `mutagen.yml` and `mutagen-*.yml` files:
1. **Base directory and subdirectories** (up to 4 levels deep):
- `mutagen.yml`, `mutagen.yaml`
- `mutagen-*.yml`, `mutagen-*.yaml` (target-specific configurations)
2. **User configuration directories:**
- `~/.config/mutagen/projects/`
- `~/.mutagen/projects/`
### Supported File Naming Patterns
- `mutagen.yml` - Standard project configuration file
- `mutagen-.yml` - Target-specific configurations (e.g., `mutagen-apollo.yml`, `mutagen-mercury.yml`)
- `.mutagen.yml` and `.mutagen-.yml` - Hidden variants of the above
This naming scheme allows you to maintain multiple Mutagen configurations in the same directory for different sync targets.
### Performance Note
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.
## Display
The TUI shows a unified hierarchical view with:
### Unified Projects and Specs View
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
#### Session Status Icons
| 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 |
#### Sync Cycle
When syncing, Mutagen progresses through these phases:
1. **Scanning** → Examines both endpoints for changes
2. **Staging** → Transfers file content that needs to be synced
3. **Reconciling** → Computes what changes to make on each side
4. **Transitioning** → Applies the changes to the filesystem
5. **Watching** → Monitors for new file changes
The Status area shows progress percentage during staging (e.g., "Staging (45%)").
#### Endpoint Connection Icons
| Icon | Status |
|------|--------|
| ✓ | Connected and scanned |
| ⟳ | Connected, scanning |
| ⊗ | Disconnected |
### Status Bar
- 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`
### Sync Status View
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.
## Push Sessions
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:**
1. Select an individual sync spec (navigate to it with arrow keys)
2. Press `p` to create a push session
- If a two-way session is running, it will be automatically terminated and replaced
- A new session named `-push` will be created
**For all specs in a project:**
1. Select a project header
2. Press `p` to 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
### Push Session Limitations
**Ignore Pattern Support:**
✅ **Fully Supported:**
- Simple list format in YAML
```yaml
sync:
myproject:
alpha: /local/path
beta: user@host:/remote/path
ignore:
- node_modules
- .git
- "*.tmp"
```
- `sync.defaults` section (merged with session-specific rules)
```yaml
sync:
defaults:
ignore:
- .git
- node_modules
myproject:
alpha: /local/path
beta: user@host:/remote/path
ignore:
- "*.tmp" # Combined with defaults
```
- Object format with `paths` key
```yaml
sync:
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`)
```yaml
sync:
myproject:
alpha: /local/path
beta: user@host:/remote/path
ignore:
vcs: true
```
- Combined VCS and custom paths
```yaml
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.
## Development
This is a Go project built on [Bubble Tea](https://github.com/charmbracelet/bubbletea) and [Lip Gloss](https://github.com/charmbracelet/lipgloss) for the terminal UI.
### Building
```bash
# Build the binary
just build
# Or directly with Go
go build -o mutagui .
```
### Running Tests
```bash
just test
```
### Code Quality
```bash
# Format code
just format
# Run linter
just lint
# Run all checks
just check
```
## Contributing
Interested in contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, architecture details, and guidelines.
## License
MIT
## Author
Oliver Steele ([@osteele](https://github.com/osteele))