Production-grade Rust + Ratatui reimplementation inspired by gwq (worktrees + status + tasks), with CLI compatibility and a modern mux backend (Zellij).
Key points:
- Binary:
gwtui - Rust edition: 2024, no
unsafe - Shells out to
git(git is the source of truth) - Interactive UI only when stdout is a TTY
gwtui tmux ...is a compatibility alias that routes to Zellij
From the repo:
cargo build --release
./target/release/gwtui --helpRunning with no arguments opens the main TUI on a TTY (and prints a single status table in non-TTY contexts):
gwtuiAll examples below assume gwtui is on your PATH. If you just built from source, use ./target/release/gwtui instead.
Open the main multi-tab UI:
gwtuiUseful first keys:
aadd a worktree (interactive)/filter/search:command palette (run anygwtuiCLI subcommand)qquit
Create a new worktree for a new feature branch (from inside a git repo):
gwtui add -b feature/authList worktrees (local to the current repo, or global from worktree.base_dir):
gwtui list
gwtui list -gJump into a worktree directory:
cd "$(gwtui get feature/auth)"Watch status in an interactive dashboard:
gwtui status --watch
gwtui status -g --watchRun a command inside a worktree (note the required -- separator):
gwtui exec feature/auth -- cargo test
gwtui exec -g feature/auth -- cargo testFrom inside a Zellij session (or with exactly one active session):
gwtui zellij list
gwtui zellij run -w feature/auth -- cargo test
gwtui zellij attach -iCommands:
gwtui add [-b] [-i] [-f] <branch> [path]gwtui list [-v] [--json] [-g]gwtui get [-g] [-0] [pattern]gwtui exec [gwq-compatible flags...] -- <cmd...>gwtui remove|rm [-f] [-d] [-g] [-b] [--force-delete-branch] [pattern]gwtui status [-g] [-v] [--json|--csv] [--watch] [--filter ...] [--sort ...]gwtui prunegwtui config list|set|getgwtui completion <shell>gwtui tmux list|run|attach|kill(routes to Zellij)gwtui zellij list|run|attach|kill(same astmux)gwtui task add|list|show|logs|workergwtui version/ global--version
Config file:
- macOS/Linux:
~/.config/gwtui/config.toml - Windows: platform config dir (also honors the Unix path if present)
Resolved config:
gwtui config listSet values (dot-path keys):
gwtui config set worktree.base_dir "~/worktrees"
gwtui config set ui.icons true
gwtui config set mux.backend zellij # or: none
gwtui config set tmux.enabled false # gwq-compat alias → mux.backend=none
gwtui config set worktree.sanitize./ "-"Schema (defaults shown):
[worktree]
base_dir = "~/worktrees"
auto_mkdir = true
naming_template = "{{host}}/{{owner}}/{{repo}}/{{branch}}"
sanitize = { "/" = "-", ":" = "-", " " = "-" }
[discovery]
mode = "auto" # auto | local | global
global_scan_depth = 6
cache_ttl_seconds = 3
dedupe_by_main_repo = true
[ui]
icons = true
tilde_home = true
picker_preview = true
picker_preview_lines = 20
[mux]
backend = "zellij" # zellij | none
zellij_command = "zellij"
require_session_for_run = true
[status]
refresh_interval_ms = 2000
concurrency = 8
default_sort = "activity"
default_filter = "all"
[tasks]
enabled = true
queue_dir = "~/.config/gwtui/tasks"
log_retention_days = 30
max_log_size_mb = 100
auto_cleanup = true
runner = "codex" # codex | claude
codex_executable = "codex"
codex_timeout = "30m"
claude_executable = "claude"
claude_timeout = "30m"
max_parallel = 3gwtui config set accepts several gwq-style keys and maps them to the TOML schema, including:
worktree.basedir→worktree.base_dirnaming.template→worktree.naming_templatefinder.preview→ui.picker_previewtmux.tmux_command→mux.zellij_commandclaude.*→tasks.*tmux.enabled→mux.backend(true→zellij,false→none)
Main TUI (gwtui on a TTY):
1-5orh/l: switch tabs:: command palette (run anygwtuiCLI subcommand; output opens in a viewer)q/Esc: exit
Status tab:
j/kor arrows: movea: add worktree (interactive)A: add worktree (manual)/: filter/search (status keywords or substring)s: cycle sortv: toggle verbose columnsw: toggle watch (auto-refresh)i: set refresh intervaln: toggle remote fetcht: set stale-days thresholdT: new task for selected worktreeP: toggle process detectiong: toggle local/globalr: refreshd: remove selected worktree (confirm;fforce,ddry-run,bdelete-branch,Bforce-delete-branch)p:git worktree prune(current repo)
Tasks tab:
j/kor arrows: move/: searchn: new taskEnter: open logs for selected taskW: start worker (daemon)S: stop workerR: reset selected task → pendingD: delete selected task (confirm)l: list executionsw: worker status
Output viewer (shown for logs/command output):
j/kor arrows: scrollPgUp/PgDn: pageg/G: top/bottomr: refreshf: toggle follow (execution logs)p: toggle pretty/raw (execution logs)q/Esc: close
Mux tab:
j/kor arrows: movea: attach to selected sessionx: kill selected session (confirm)
Config tab:
j/kor arrows: scrollr: reload resolved confige: set config key/value
Picker (used by add -i, ambiguous get, session selection, etc.):
j/kor arrows: movePgUp/PgDn: page- Type to filter (substring)
Backspace: edit queryEnter: acceptEsc/q: cancel (non-zero exit)Tab: toggle selection (multi-select pickers)?: help
Status dashboard (gwtui status --watch on a TTY):
/: filter/search (status keywords or substring)s: cycle sortg: toggle local/globalr: refreshEnter: detail popupq/Esc: exit
Task log viewer (gwtui task logs):
j/kor arrows: scrollPgUp/PgDn: pageg/G: top/bottomq/Esc: exit
gwtui uses Zellij as its mux backend. gwtui tmux ... is kept as an alias for gwq compatibility.
Notes:
tmux list/attach/killoperate on Zellij sessions.tmux runruns a command in the current Zellij session (requires a determinable session; usesZELLIJ_SESSION_NAME/ZELLIJ_SESSIONor a single active session fallback).- Some tmux concepts do not map 1:1 to Zellij; behavior is best-effort and documented by command output when relevant.
Runners: codex (default) and claude.
Queue storage: tasks.queue_dir (default ~/.config/gwtui/tasks)
Add a task:
gwtui task add codex -w feature/auth "Implement JWT authentication"
gwtui task add codex -w feature/api --base develop "REST API endpoints" -p 80Batch add from YAML (version 1.0):
gwtui task add codex --file tasks.yamlList tasks:
gwtui task list
gwtui task list --filter running
gwtui task list --priority-min 75
gwtui task list --json
gwtui task list --csvWorker:
gwtui task worker start
gwtui task worker start --parallel 3 --wait
gwtui task worker status --json
gwtui task worker stop --timeout 5mLogs:
gwtui task logs
gwtui task logs exec-a1b2c3
gwtui task logs --status failed --limit 50
gwtui task logs clean --older-than 30dStable machine-readable output is available where supported:
gwtui status --json|--csvgwtui tmux list --json|--csvgwtui task list --json|--csvgwtui task logs --json(list mode)
- Uses Zellij instead of tmux;
gwtui tmux ...routes to Zellij. - Configuration is TOML-based (
gwtui config list/set) and layered over defaults. - Interactive UIs are Ratatui-based and only enabled when stdout is a TTY.
cargo fmt
cargo clippy --all-targets --all-features -D warnings
cargo test