{"id":34533215,"url":"https://github.com/osteele/mutagui","last_synced_at":"2026-04-27T14:31:40.916Z","repository":{"id":322761607,"uuid":"1082397371","full_name":"osteele/mutagui","owner":"osteele","description":"A terminal user interface (TUI) for managing Mutagen sync sessions","archived":false,"fork":false,"pushed_at":"2025-12-24T03:40:20.000Z","size":253,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-25T17:12:44.807Z","etag":null,"topics":["file-sync","mutagen","rust","terminal","tui"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/osteele.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-24T07:20:36.000Z","updated_at":"2025-12-24T03:39:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"494fd6bb-2178-4c89-9581-a0dcdbc7d187","html_url":"https://github.com/osteele/mutagui","commit_stats":null,"previous_names":["osteele/mutagui"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/osteele/mutagui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osteele%2Fmutagui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osteele%2Fmutagui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osteele%2Fmutagui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osteele%2Fmutagui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/osteele","download_url":"https://codeload.github.com/osteele/mutagui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/osteele%2Fmutagui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32341447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["file-sync","mutagen","rust","terminal","tui"],"created_at":"2025-12-24T05:53:59.322Z","updated_at":"2026-04-27T14:31:40.910Z","avatar_url":"https://github.com/osteele.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mutagen TUI\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/osteele/mutagui)](https://goreportcard.com/report/github.com/osteele/mutagui)\n[![Go Reference](https://pkg.go.dev/badge/github.com/osteele/mutagui.svg)](https://pkg.go.dev/github.com/osteele/mutagui)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA terminal user interface for managing [Mutagen](https://mutagen.io/) sync sessions.\n\nFor more development tools, see: https://osteele.com/software/development-tools\n\n## Features\n\n- **Unified hierarchical view**: Projects and their sync specs in a single tree view\n  - Fold/unfold projects to show or hide individual sync specs\n  - Auto-unfold when conflicts are detected\n- **Project discovery**: Automatically finds and displays `mutagen.yml` files\n  - Searches the specified directory (or current directory) and subdirectories\n  - Supports multiple config files per directory (`mutagen-\u003ctarget\u003e.yml` pattern)\n  - Correlates project files with running sessions\n- **Push mode support**: Create one-way sync sessions (alpha → beta)\n  - Push individual specs or entire projects\n  - Automatically replaces two-way sessions when creating push\n  - Clear visual indicators for push mode (⬆ arrow, \"(push)\" label)\n- **Light and dark themes**: Defaults to light theme, dark theme available via `MUTAGUI_THEME=dark`\n- **Auto-refresh**: Session list and projects update every 3 seconds automatically\n- **Real-time activity indicators**:\n  - Connection status icons (✓ connected, ⊗ disconnected, ⟳ scanning)\n  - Session status icons (👁 watching, 📦 staging, ⚖ reconciling, etc.)\n  - File and directory counts for each endpoint\n  - Sync status display with progress percentages\n- **Interactive keyboard controls** for managing syncs:\n  - Start/stop projects and individual specs\n  - Create push sessions\n  - Pause/resume sessions\n  - Terminate and flush sessions\n  - View and resolve conflicts\n  - Edit project configuration files\n  - Manual refresh\n- Last refresh timestamp display\n\n## Prerequisites\n\n- [Mutagen](https://mutagen.io/) must be installed and in your PATH\n- Go 1.21+ (for building from source)\n\n## Installation\n\n### Using Go\n\n```bash\ngo install github.com/osteele/mutagui@latest\n```\n\n### From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/osteele/mutagui.git\ncd mutagui\n\n# Build and install\njust install\n\n# Or manually with Go\ngo install .\n```\n\n## Usage\n\nSimply run the application:\n\n```bash\nmutagui\n```\n\nOr if building locally:\n\n```bash\njust run\n```\n\n### Command-Line Options\n\n```bash\nmutagui [OPTIONS]\n\nOptions:\n  -d, --project-dir \u003cDIR\u003e    Directory to search for mutagen project files\n                             (default: current directory)\n  -h, --help                 Print help\n```\n\n**Examples:**\n\n```bash\n# Use current directory (default)\nmutagui\n\n# Search for projects starting from ~/code\nmutagui --project-dir ~/code\n\n# Short form\nmutagui -d ~/projects\n```\n\nThe `--project-dir` option specifies where to start searching for `mutagen.yml` files. The application will:\n- Search the specified directory and its subdirectories (up to 4 levels deep)\n- Also check user config directories (`~/.config/mutagen/projects/`, `~/.mutagen/projects/`)\n\n## Interface Overview\n\nThe TUI displays a hierarchical tree view of projects and their sync specs:\n\n```\n┌─ Sync Projects ─────────────────────────────────────────────────────────────┐\n│ ▼ ✓ apollo-research               2/3 running (1 push)                      │\n│   ● apollo-research (push)           👁  ✓~/code/research ⬆ ✓apollo:/data/. │\n│   ● apollo-research-tools             👁  ✓~/code/tools ⇄ ✓apollo:/data/... │\n│   ○ apollo-datasets                   Not running                            │\n│ ▶ ○ mercury-ml                     0/2 running                               │\n│ ▼ ✓ starship-dev                  1/1 running, 1 waiting  ⚠ 3 conflicts    │\n│   ● sync-to-orbit                     📦  ✓~/code/starship ⇄ ⊗orbit:/home/. │\n└──────────────────────────────────────────────────────────────────────────────┘\n┌─ Help ───────────────────────────────────────────────────────────────────────┐\n│ ↑/↓/j/k Nav │ h/l/↵ Fold │ r Refresh │ e Edit │ s Start/Stop │ P Push │...  │\n└──────────────────────────────────────────────────────────────────────────────┘\n┌─ Status ─────────────────────────────────────────────────────────────────────┐\n│ Created 1 push session(s) | Last refresh: 12:34:56                           │\n└──────────────────────────────────────────────────────────────────────────────┘\n```\n\n**Visual Indicators:**\n- **Fold state**: `▼` (expanded) / `▶` (collapsed)\n- **Project status**: `✓` (active) / `○` (inactive)\n- **Spec status**: `●` (running) / `⏸` (paused) / `○` (not running)\n- **Sync direction**: `⇄` (two-way) / `⬆` (push mode, bold/colored)\n- **Transfer direction**: `↓` (downloading) / `↑` (uploading) - shown during staging\n- **Push mode label**: Specs show `(push)` suffix when in push mode\n- **Endpoint status**: `✓` (connected) / `⟳` (scanning) / `⊗` (disconnected)\n- **Session activity**: `👁` (watching) / `📦` (staging) / `⚖` (reconciling) / etc.\n- **Conflicts**: `⚠ 3 conflicts` shown on project header\n\n### Keyboard Controls\n\n#### Navigation\n| Key | Action |\n|-----|--------|\n| `↑` / `k` | Move selection up |\n| `↓` / `j` | Move selection down |\n| `h` / `←` / `l` / `→` / `Enter` | Toggle fold/unfold project |\n\n#### Global Actions\n| Key | Action |\n|-----|--------|\n| `r` | Refresh session list and projects |\n| `m` | Toggle display mode (show paths vs. last sync time) |\n| `?` | Show help screen with all commands |\n| `q` / `Ctrl-C` | Quit application |\n\n#### Mouse\n- **Click** on a list item to select it\n- **Click** on a project header to fold/unfold\n- **Shift+click and drag** to select text (bypasses app mouse handling for copying)\n\n#### Project Actions (when project selected)\n| Key | Action |\n|-----|--------|\n| `e` | Edit project configuration file |\n| `s` | Start all specs in project |\n| `t` | Terminate all specs in project |\n| `f` | Flush all specs in project |\n| `P` | Create push sessions for all specs |\n| `p` / `Space` | Pause/resume all running specs |\n| `u` | Resume all paused specs |\n\n#### Spec Actions (when individual spec selected)\n| Key | Action |\n|-----|--------|\n| `s` | Start this spec |\n| `t` | Terminate this spec |\n| `f` | Flush this spec |\n| `P` | Create push session (replaces two-way if running) |\n| `p` / `Space` | Pause/resume spec |\n| `u` | Resume paused spec |\n| `c` | View conflicts |\n| `i` | View sync status details |\n\n### Editor Integration\n\nWhen pressing `e` to edit a project file:\n\n**Editor Selection:**\n1. `$VISUAL` environment variable (if set)\n2. `$EDITOR` environment variable (if set)\n3. `vim` (default fallback)\n\n**Automatic GUI Detection:**\n\nThe application automatically detects whether your editor is a GUI application or terminal-based and adjusts its behavior accordingly:\n\n- **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.\n- **Terminal editors** (vim, nano, emacs, etc.): The TUI suspends and restores your terminal to normal mode, then resumes after you exit the editor.\n\n**Supported GUI Editors** (automatically detected):\n- VS Code (`code`, `code-insiders`)\n- Zed (`zed`)\n- Sublime Text (`subl`, `sublime`, `sublime_text`)\n- Atom (`atom`)\n- GNOME editors (`gedit`, `gnome-text-editor`)\n- KDE editors (`kate`, `kwrite`)\n- XFCE editors (`mousepad`, `xed`)\n- MATE editor (`pluma`)\n- macOS editors (`bbedit`, `textmate`, `textedit`, `xcode`)\n- GUI Vim variants (`macvim`, `gvim`)\n\n**Supported Terminal Editors** (automatically detected):\n- vim, vi, nvim\n- nano, pico\n- emacs, emacsclient\n- helix, hx\n- kakoune, kak\n- micro, joe, jed\n- ed, ex\n\n**SSH Behavior**: When connected via SSH, the application assumes terminal editors only (GUI editors won't work).\n\n**Manual Override**: If detection is incorrect for your editor, set:\n```bash\nexport MUTAGUI_EDITOR_IS_GUI=true   # Force GUI behavior\nexport MUTAGUI_EDITOR_IS_GUI=false  # Force terminal behavior\n```\n\n### Theme\n\nThe application defaults to light theme. To use dark theme:\n```bash\nexport MUTAGUI_THEME=dark\n```\n\n## Configuration Files\n\nThe 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.\n\n### Search Locations\n\nStarting from the base directory (current directory by default, or specified with `--project-dir`), the application searches for `mutagen.yml` and `mutagen-*.yml` files:\n\n1. **Base directory and subdirectories** (up to 4 levels deep):\n   - `mutagen.yml`, `mutagen.yaml`\n   - `mutagen-*.yml`, `mutagen-*.yaml` (target-specific configurations)\n\n2. **User configuration directories:**\n   - `~/.config/mutagen/projects/`\n   - `~/.mutagen/projects/`\n\n### Supported File Naming Patterns\n\n- `mutagen.yml` - Standard project configuration file\n- `mutagen-\u003ctarget\u003e.yml` - Target-specific configurations (e.g., `mutagen-apollo.yml`, `mutagen-mercury.yml`)\n- `.mutagen.yml` and `.mutagen-\u003ctarget\u003e.yml` - Hidden variants of the above\n\nThis naming scheme allows you to maintain multiple Mutagen configurations in the same directory for different sync targets.\n\n### Performance Note\n\nThe file discovery uses non-recursive glob patterns for fast startup. Deep directory traversal with `**/` patterns is avoided to prevent scanning thousands of files unnecessarily.\n\n## Display\n\nThe TUI shows a unified hierarchical view with:\n\n### Unified Projects and Specs View\n\nShows all projects and their sync specs in a tree structure:\n- **Project headers**:\n  - Fold indicator: ▼ (expanded) or ▶ (collapsed)\n  - Status icon: ✓ (active) or ○ (inactive)\n  - Project name (e.g., `mutagen-apollo`, `starship-dev`)\n  - Running status: \"Running\", \"Not running\", or \"X/Y running\"\n  - Push mode count when applicable: \"(2 push)\"\n  - Connection issues when present: \", 1 waiting\" (disconnected endpoints)\n  - Conflict indicator when present: \"⚠ 3 conflicts\"\n- **Sync specs** (shown when project is expanded):\n  - Status icon: ● (running), ⏸ (paused), or ○ (not running)\n  - Spec name with push mode label: `sync-name (push)`\n  - Session status icon: 👁 (watching), 📦 (staging), ⚖ (reconciling), etc.\n  - Alpha endpoint with connection status and path\n  - Direction arrow: ⇄ (two-way) or ⬆ (push mode, in bold color)\n  - Beta endpoint with connection status and path\n\n#### Session Status Icons\n\n| Icon | Status | Description |\n|------|--------|-------------|\n| 👁 | Watching | Connected and idle, waiting for file changes |\n| 🔌 | Connecting | Establishing connection to remote endpoint |\n| 🔍 | Scanning | Scanning files for changes |\n| 📦 | Staging | Transferring file content that needs to be synced |\n| ⚖ | Reconciling | Computing what changes to make on each side |\n| ⏳ | Transitioning | Applying changes (writes/deletes/modifications) to the filesystem |\n| 💾 | Saving | Saving synchronized changes |\n| ⛔ | Halted | Session halted due to error |\n| • | Unknown | Unknown or other status |\n\n#### Sync Cycle\n\nWhen syncing, Mutagen progresses through these phases:\n\n1. **Scanning** → Examines both endpoints for changes\n2. **Staging** → Transfers file content that needs to be synced\n3. **Reconciling** → Computes what changes to make on each side\n4. **Transitioning** → Applies the changes to the filesystem\n5. **Watching** → Monitors for new file changes\n\nThe Status area shows progress percentage during staging (e.g., \"Staging (45%)\").\n\n#### Endpoint Connection Icons\n\n| Icon | Status |\n|------|--------|\n| ✓ | Connected and scanned |\n| ⟳ | Connected, scanning |\n| ⊗ | Disconnected |\n\n### Status Bar\n\n- Current status message\n- Last refresh timestamp\n- When a staging session is selected, shows transfer details:\n  - Direction indicator: `↓` (downloading to local) or `↑` (uploading to remote)\n  - Progress percentage and current file name\n  - File size progress: `[16.8M/248.9M]`\n  - File count: `3/47 files`\n\n### Sync Status View\n\nPress `i` when a running spec is selected to open a detailed sync status overlay:\n\n```\n╭─ Sync Status: studio-research (Esc or 'i' to close) ───────────────╮\n│                                                                     │\n│  Direction:  ↓ Downloading (staging to local)                       │\n│  Status:     Staging                                                │\n│                                                                     │\n│  Current file: LM2/checkpoints/model.safetensors                    │\n│  File progress: [████████░░░░░░░░░░░░░░░░░░░░░░] 27%                │\n│                 67.2 MB / 248.9 MB                                  │\n│                                                                     │\n│  Overall:    3 / 47 files                                           │\n│  Total transferred: 67.2 MB                                         │\n│                                                                     │\n│  Alpha (local):  ✓ connected, ✓ scanned                             │\n│  Beta (remote):  ✓ connected, ✓ scanned                             │\n│                                                                     │\n╰─────────────────────────────────────────────────────────────────────╯\n```\n\nPress `Esc` or `i` again to close the overlay.\n\n## Push Sessions\n\nThe 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.\n\n**To create push sessions:**\n\n**For a single spec:**\n1. Select an individual sync spec (navigate to it with arrow keys)\n2. Press `p` to create a push session\n   - If a two-way session is running, it will be automatically terminated and replaced\n   - A new session named `\u003cspec-name\u003e-push` will be created\n\n**For all specs in a project:**\n1. Select a project header\n2. Press `p` to create push sessions for all specs\n   - All running two-way sessions will be terminated\n   - Push sessions will be created for each spec defined in the project file\n\nThe application creates sessions with:\n- Mode: `one-way-replica` (alpha → beta)\n- Endpoints from the project file\n- Ignore patterns from the project configuration\n\n### Push Session Limitations\n\n**Ignore Pattern Support:**\n\n✅ **Fully Supported:**\n- Simple list format in YAML\n  ```yaml\n  sync:\n    myproject:\n      alpha: /local/path\n      beta: user@host:/remote/path\n      ignore:\n        - node_modules\n        - .git\n        - \"*.tmp\"\n  ```\n\n- `sync.defaults` section (merged with session-specific rules)\n  ```yaml\n  sync:\n    defaults:\n      ignore:\n        - .git\n        - node_modules\n    myproject:\n      alpha: /local/path\n      beta: user@host:/remote/path\n      ignore:\n        - \"*.tmp\"  # Combined with defaults\n  ```\n\n- Object format with `paths` key\n  ```yaml\n  sync:\n    myproject:\n      alpha: /local/path\n      beta: user@host:/remote/path\n      ignore:\n        paths:\n          - node_modules\n          - .git\n  ```\n\n- VCS ignore flag (ignores `.git`, `.svn`, `.hg`, `.bzr`, `_darcs`, `.fossil-settings`)\n  ```yaml\n  sync:\n    myproject:\n      alpha: /local/path\n      beta: user@host:/remote/path\n      ignore:\n        vcs: true\n  ```\n\n- Combined VCS and custom paths\n  ```yaml\n  sync:\n    myproject:\n      alpha: /local/path\n      beta: user@host:/remote/path\n      ignore:\n        vcs: true\n        paths:\n          - node_modules\n          - \"*.tmp\"\n  ```\n\n❌ **Not yet supported:**\n- Regular expression patterns (`ignore: { regex: \"pattern.*\" }`)\n\n**Note:** Ignore patterns from `sync.defaults` are merged with session-specific patterns. Session-specific patterns are added to (not replacing) defaults.\n\n## Development\n\nThis 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.\n\n### Building\n\n```bash\n# Build the binary\njust build\n\n# Or directly with Go\ngo build -o mutagui .\n```\n\n### Running Tests\n\n```bash\njust test\n```\n\n### Code Quality\n\n```bash\n# Format code\njust format\n\n# Run linter\njust lint\n\n# Run all checks\njust check\n```\n\n## Contributing\n\nInterested in contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, architecture details, and guidelines.\n\n## License\n\nMIT\n\n## Author\n\nOliver Steele ([@osteele](https://github.com/osteele))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosteele%2Fmutagui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fosteele%2Fmutagui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosteele%2Fmutagui/lists"}