{"id":47234789,"url":"https://github.com/0dragosh/cwt","last_synced_at":"2026-04-01T17:33:35.376Z","repository":{"id":344160574,"uuid":"1179067723","full_name":"0dragosh/cwt","owner":"0dragosh","description":"Rust TUI that manages git worktrees as first-class units of work for parallel Claude Code sessions, with tmux integration, automatic snapshots, and one-key PR shipping","archived":false,"fork":false,"pushed_at":"2026-03-13T20:18:10.000Z","size":427,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-13T22:33:37.445Z","etag":null,"topics":["claude","cli","git","ratatui","rust","tmux","tui","worktree"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/cwt","language":"Rust","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/0dragosh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-11T16:51:23.000Z","updated_at":"2026-03-13T20:17:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/0dragosh/cwt","commit_stats":null,"previous_names":["0dragosh/cwt"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/0dragosh/cwt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dragosh%2Fcwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dragosh%2Fcwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dragosh%2Fcwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dragosh%2Fcwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0dragosh","download_url":"https://codeload.github.com/0dragosh/cwt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dragosh%2Fcwt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290537,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["claude","cli","git","ratatui","rust","tmux","tui","worktree"],"created_at":"2026-03-13T22:02:11.716Z","updated_at":"2026-04-01T17:33:35.368Z","avatar_url":"https://github.com/0dragosh.png","language":"Rust","readme":"# cwt — Provider (Claude or Codex) Worktree Manager\n\nA terminal UI for running parallel\nprovider (Claude or Codex) sessions in\nisolated git worktrees. Built in Rust, it uses a local terminal multiplexer for\ninteractive session management, preferring zellij when available and falling\nback to tmux.\n\n\u003e **The worktree is the first-class primitive** — sessions attach to worktrees,\n\u003e not the other way around.\n\n```\nWorktree (unit of work)\n  |-- Branch (auto-created or user-specified)\n  |-- Session (provider instance, 0 or 1 active)\n  |-- Lifecycle: ephemeral | permanent\n  |-- State: idle | running | waiting | done | shipping\n```\n\n## Why cwt?\n\nWhen using a provider (Claude or Codex) on a real codebase, you often want to run multiple tasks\nin parallel — fix a bug, add a feature, write tests — without them stepping on\neach other. Git worktrees give you cheap, isolated copies of your repo. cwt\nmanages the lifecycle of those worktrees and the provider sessions inside them,\nall from a single TUI.\n\n- **Spin up a worktree in seconds** — auto-named, auto-branched, ready to go\n- **Never lose work** — every deletion saves a `.patch` snapshot first\n- **Stay organized** — ephemeral worktrees auto-clean; permanent ones stick\n  around\n- **See everything at once** — two-panel TUI with live session status, diff\n  stats, and transcript previews\n- **Scale up** — dispatch tasks in bulk, import GitHub issues, broadcast prompts\n  across sessions\n\n## Requirements\n\n- **git** (with worktree support)\n- **zellij** or **tmux** (interactive mode needs one local terminal multiplexer;\n  zellij is preferred when both are installed)\n- A provider CLI (`claude` or `codex`)\n\nOptional:\n\n- **gh** ([GitHub CLI](https://cli.github.com/)) — for PR creation and CI status\n- **podman** or **docker** — for per-worktree containers\n- **ssh** — for remote worktrees\n\n## Installation\n\n### Prebuilt binaries with cargo-binstall\n\n```sh\ncargo binstall cwt\n```\n\n`cargo-binstall` downloads the prebuilt release archive when one is available\nfor your target. Install either `zellij` or `tmux` separately and make sure it\nis on your `PATH`.\n\n### Cargo (from crates.io)\n\n```sh\ncargo install cwt\n```\n\n`cargo install` does not install a terminal multiplexer for you. Install\n`zellij` or `tmux` separately and make sure it is on your `PATH` before running\n`cwt`.\n\n### Nix (recommended)\n\ncwt provides a Nix flake with builds for Linux and macOS (x86_64 and aarch64).\nThe Nix package includes `tmux` and `git` as runtime dependencies and wraps the\nbinary so they are always on `PATH`. If `zellij` is also available in your\nenvironment, `cwt` will prefer it automatically for local interactive sessions.\n\n```sh\n# Run without installing\nnix run github:0dragosh/cwt\n\n# Install to your profile\nnix profile install github:0dragosh/cwt\n```\n\nAdd to a flake-based NixOS or home-manager configuration:\n\n```nix\n# flake.nix\n{\n  inputs.cwt.url = \"github:0dragosh/cwt\";\n\n  # Option 1: use the overlay\n  nixpkgs.overlays = [ cwt.overlays.default ];\n  # then add pkgs.cwt to your packages\n\n  # Option 2: reference the package directly\n  environment.systemPackages = [ cwt.packages.${system}.default ];\n\n  # Option 3: home-manager module (generates ~/.config/cwt/config.toml)\n  imports = [ cwt.homeManagerModules.default ];\n  programs.cwt = {\n    enable = true;\n    settings.session.default_permission = \"elevated\";\n  };\n}\n```\n\nSee [docs/nix.md](docs/nix.md) for full home-manager module documentation.\n\n### From source\n\n```sh\ngit clone https://github.com/0dragosh/cwt.git\ncd cwt\ncargo build --release\n# Binary at target/release/cwt — add it to your PATH\n```\n\nMake sure `git` is on your `PATH`, and make sure `zellij` or `tmux` is\ninstalled and on your `PATH`. `cwt` cannot run its interactive workflows\nwithout one of them.\n\n## Quick Start\n\nInteractive mode needs a local terminal multiplexer. If you launch `cwt` from a\nregular shell, it will bootstrap into a `zellij` session when `zellij` is\ninstalled, and otherwise fall back to `tmux`.\n\n```sh\n# 1. Navigate to any git repo\ncd ~/my-project\n\n# 2. Launch the TUI (cwt will bootstrap into zellij or tmux if needed)\ncwt\n\n# 3. Press 'n' to create a worktree (Enter for auto-generated name)\n# 4. Press 's' to launch a provider session in it\n# 5. Press 'Tab' to switch between the worktree list and inspector panels\n```\n\nOr use CLI commands directly:\n\n```sh\ncwt create my-feature --base main     # Create a worktree\ncwt list                               # List all worktrees\ncwt delete my-feature                  # Delete (saves a snapshot first)\n\n# Dispatch parallel tasks — one worktree + session per task\ncwt dispatch \"implement auth\" \"add tests\" \"update docs\"\n\n# Import GitHub issues as worktrees\ncwt import --github --limit 5\n\n# Multi-repo mode\ncwt add-repo ~/code/project-a\ncwt add-repo ~/code/project-b\ncwt forest                             # Launch forest TUI\ncwt status                             # CLI summary across repos\n```\n\n## Features\n\n### Worktree Management\n\n- **Create** with auto-generated slug names or explicit names, from any base\n  branch\n- **Two-tier lifecycle**: ephemeral (auto-GC'd) and permanent (never\n  auto-deleted)\n- **Promote** ephemeral worktrees to permanent with a single keypress\n- **Snapshots**: full diff saved as `.patch` before every deletion\n- **Restore** previously deleted worktrees from their snapshots\n- **Garbage collection**: prune old ephemeral worktrees, skipping those with\n  running sessions, uncommitted changes, or unpushed commits\n- **Setup scripts**: automatically run a script (e.g., `npm install`) after\n  worktree creation\n\n### TUI Interface\n\n- **Two-panel layout**: worktree list (grouped by lifecycle) + inspector\n  (details, diff stat, session info)\n- **Fuzzy filter**: `/` to search/filter worktrees by name\n- **Help overlay**: `?` for a full keybinding reference\n- **Mouse support**: click to select, scroll to navigate\n- **Status bar**: notification badges for waiting/done sessions\n\n### Terminal Multiplexer Support\n\n### Session Providers\n\n- cwt supports two provider options: `claude` and `codex`\n- You can set the default in config with `session.provider = \"claude\"` or `\"codex\"`\n- You can change the active provider at runtime by pressing `o` in the TUI\n- Press `O` to persist the currently selected provider as the default\n- Local interactive mode prefers **zellij** and falls back to **tmux**\n- Launching `cwt` outside a multiplexer auto-attaches to a `cwt` session in the\n  preferred backend\n- In zellij, provider sessions and shells open in named tabs; in tmux, they\n  open in panes/windows\n- **Launch** the provider (Claude or Codex) in the active multiplexer attached\n  to any worktree\n- **Resume** previous sessions using the active provider's resume flow (`--resume` for Claude)\n- **Focus** an existing session tab/pane with a single keypress\n- **Open shell** in any worktree directory via the active multiplexer\n- Sessions survive TUI exit — closing cwt does not kill running sessions\n- Remote sessions still use **tmux** on the remote host today\n\n### Handoff\n\n- **Bidirectional** patch transfer between your main working directory and any\n  worktree\n- Direction picker: worktree-to-local or local-to-worktree\n- Diff preview before applying\n- Gitignore gap warnings for untracked files that won't transfer\n\n### Hooks (Real-Time Provider Integration)\n\n- **Unix domain socket** listener for sub-second event delivery\n- Worktrees created by the provider (Claude or Codex) outside cwt appear in the list within one\n  second\n- `cwt hooks install` patches `.claude/settings.json` and writes hook scripts to\n  `.cwt/hooks/`\n\n### Forest Mode (Multi-Repo)\n\n- Register multiple repos with `cwt add-repo \u003cpath\u003e`\n- Three-panel TUI: repos | worktrees | inspector\n- Aggregate session counts across all repos\n- `cwt status` for a one-line CLI summary\n\n### Agent Orchestration\n\n- **Dispatch** multiple tasks in parallel: `cwt dispatch \"task 1\" \"task 2\" ...`\n- **Import issues** from GitHub or Linear — creates worktrees and sessions per\n  issue\n- **Broadcast** a prompt to all running sessions simultaneously\n\n### Ship Pipeline\n\n- **Create PR** from a worktree with auto-generated body from session transcript\n- **CI status tracking**: pass/fail/pending via `gh run list`\n- **Ship it**: one-keypress macro to push, create PR, and mark as shipping\n\n### Per-Worktree Containers\n\n- Podman or Docker support (prefers Podman for rootless compatibility)\n- Auto-detect `Containerfile`, `Dockerfile`, or\n  `.devcontainer/devcontainer.json`\n- Port management: auto-assign non-conflicting ports per worktree\n\n### Permission Levels\n\ncwt supports three permission tiers for provider sessions (Claude/Codex), giving you\nfine-grained control over how much autonomy the provider gets:\n\n| Level | Badge | Behavior |\n| ----- | ----- | -------- |\n| **Normal** | `N` (gray) | Plain provider command — asks for permission on each tool use (default) |\n| **Elevated** | `E` (yellow) | Injects sandbox settings into `.claude/settings.local.json` — the provider runs autonomously within a sandbox |\n| **Elevated Unsandboxed** | `U!` (red) | Appends `--dangerously-skip-permissions` — full autonomy, no sandbox |\n\n- Press `m` to cycle through modes at runtime\n- Press `M` to save the current mode as the default in your config\n- The active level is shown as a badge in the top bar\n- Each worktree gets its own `.claude/settings.local.json`, so there are no\n  concurrency conflicts between sessions\n\nProvider-specific mode behavior:\n\n- Claude: `Elevated` injects sandbox settings; `Unsandboxed` uses `--dangerously-skip-permissions`.\n- Codex: `Unsandboxed` uses `--full-auto`; `Elevated Unsandboxed` uses `--dangerously-bypass-approvals-and-sandbox`.\n\nThe elevated (sandboxed) provider mode writes these settings before launch:\n\n```json\n{\n  \"permissions\": { \"allow\": [], \"deny\": [] },\n  \"sandbox\": {\n    \"enabled\": true,\n    \"autoAllowBashIfSandboxed\": true,\n    \"allowUnsandboxedCommands\": false\n  }\n}\n```\n\n### Remote Worktrees\n\n- SSH-based remote host management\n- Create and manage worktrees on remote machines\n- Cross-machine handoff via patches\n- Latency-aware polling with network status indicators\n\n## Keybindings\n\n### Worktree Actions\n\n| Key     | Action                               | Context            |\n| ------- | ------------------------------------ | ------------------ |\n| `n`     | New worktree                         | Global             |\n| `s`     | Launch/resume provider session       | Worktree selected  |\n| `h`     | Handoff changes (worktree \u003c-\u003e local) | Worktree selected  |\n| `p`     | Promote to permanent                 | Ephemeral selected |\n| `d`     | Delete (with snapshot)               | Worktree selected  |\n| `g`     | Run garbage collection               | Global             |\n| `r`     | Restore from snapshot                | Global             |\n| `Enter` | Launch/resume provider session       | Worktree selected  |\n| `e`     | Open shell in worktree               | Worktree selected  |\n\n### Orchestration\n\n| Key | Action                           | Context |\n| --- | -------------------------------- | ------- |\n| `t` | Dispatch tasks (multi-worktree)  | Global  |\n| `b` | Broadcast prompt to all sessions | Global  |\n\n### Ship Pipeline\n\n| Key | Action                              | Context           |\n| --- | ----------------------------------- | ----------------- |\n| `P` | Create PR (push + `gh pr create`)   | Worktree selected |\n| `S` | Ship it (push + PR + mark shipping) | Worktree selected |\n| `c` | Open CI logs in browser             | Worktree selected |\n\n### Permissions\n\n| Key | Action                                       | Context |\n| --- | -------------------------------------------- | ------- |\n| `m` | Cycle mode (Normal/Unsandboxed/Elevated Unsandboxed) | Global  |\n| `M` | Save current mode as default               | Global  |\n| `o` | Cycle session provider (Claude/Codex) at runtime | Global  |\n| `O` | Save current provider as default           | Global  |\n\n### Navigation\n\n| Key          | Action                       | Context       |\n| ------------ | ---------------------------- | ------------- |\n| `j` / `Down` | Move down / scroll inspector | Global        |\n| `k` / `Up`   | Move up / scroll inspector   | Global        |\n| `Tab`        | Switch panel focus (forward) | Global        |\n| `Shift+Tab`  | Switch panel focus (back)    | Global        |\n| `R`          | Switch to repo panel         | Forest mode   |\n| `/`          | Filter/search worktrees      | Worktree list |\n| `Esc`        | Clear filter / close dialog  | Global        |\n| `?`          | Toggle help overlay          | Global        |\n| `q`          | Quit                         | Global        |\n| `Ctrl+C`     | Force quit                   | Global        |\n\n## CLI Commands\n\n| Command                             | Description                        |\n| ----------------------------------- | ---------------------------------- |\n| `cwt`                               | Launch the TUI (default)           |\n| `cwt tui`                           | Launch the TUI (explicit)          |\n| `cwt list`                          | List all managed worktrees         |\n| `cwt create [name] --base \u003cbranch\u003e` | Create a new worktree              |\n| `cwt create [name] --remote \u003chost\u003e` | Create on a remote host            |\n| `cwt delete \u003cname\u003e`                 | Delete a worktree (saves snapshot) |\n| `cwt promote \u003cname\u003e`                | Promote ephemeral to permanent     |\n| `cwt gc [--execute]`                | Preview/run garbage collection     |\n| `cwt hooks install`                 | Install provider hook scripts      |\n| `cwt hooks uninstall`               | Remove hook scripts                |\n| `cwt hooks status`                  | Show hook and socket status        |\n| `cwt dispatch \"task\" ...`           | Dispatch parallel tasks            |\n| `cwt import --github [--limit N]`   | Import GitHub issues as worktrees  |\n| `cwt import --linear [--limit N]`   | Import Linear issues as worktrees  |\n| `cwt prompt`                        | Print active cwt worktree name     |\n| `cwt add-repo \u003cpath\u003e`               | Register a repo for forest mode    |\n| `cwt forest`                        | Launch forest (multi-repo) TUI     |\n| `cwt status`                        | Summary of all repos and sessions  |\n\n### Starship prompt integration\n\n`cwt prompt` prints the current managed worktree name when your shell is inside\nthat worktree directory, and prints nothing otherwise. This makes it easy to\nsurface worktree context in [starship](https://starship.rs/) (similar to\nworktrunk):\n\n```toml\n[custom.cwt]\ncommand = \"cwt prompt\"\nwhen = \"cwt prompt | grep -q .\"\nformat = \"[$output]($style) \"\nstyle = \"bold purple\"\n```\n\n## Configuration\n\ncwt reads configuration from `.cwt/config.toml` (per-project) and\n`~/.config/cwt/config.toml` (global). Forest mode uses\n`~/.config/cwt/forest.toml`.\n\n```toml\n[worktree]\ndir = \".claude/worktrees\"        # worktree root (relative to repo root)\nmax_ephemeral = 15               # GC threshold\nauto_name = true                 # generate slug names when no name given\n\n[setup]\nscript = \"\"                      # path to setup script (relative to repo root)\ntimeout_secs = 120               # setup script timeout\n\n[session]\nauto_launch = true               # launch session provider on worktree create\nprovider = \"claude\"              # \"claude\" | \"codex\"\ncommand = \"\"                     # optional command override (defaults to provider binary)\nprovider_args = []               # extra args for provider invocation\ndefault_permission = \"normal\"    # \"normal\", \"elevated\", or \"elevated_unsandboxed\"\n\n# Permission-level overrides (optional — sensible defaults built in)\n# [session.permissions.normal]\n# extra_args = []\n#\n# [session.permissions.elevated]\n# extra_args = []\n# [session.permissions.elevated.settings_override.sandbox]\n# enabled = true\n# autoAllowBashIfSandboxed = true\n#\n# [session.permissions.elevated_unsandboxed]\n# extra_args = [\"--dangerously-skip-permissions\"]\n\n[handoff]\nmethod = \"patch\"                 # \"patch\" or \"cherry-pick\"\nwarn_gitignore = true            # warn about .gitignore gaps\n\n[ui]\ntheme = \"default\"                # color theme\nshow_diff_stat = true            # show file change counts in list\n\n[container]\nenabled = false                  # enable container support\nruntime = \"auto\"                 # \"podman\", \"docker\", or \"auto\"\nauto_ports = true                # auto-assign ports per worktree\n\n# Remote hosts (one [[remote]] block per host)\n[[remote]]\nname = \"build-server\"\nhost = \"build.example.com\"\nuser = \"dev\"\nworktree_dir = \"/data/worktrees\"\n```\n\n## Architecture\n\n```\nsrc/\n  main.rs          # CLI parsing, TUI bootstrap, startup checks\n  app.rs           # App state, event loop, keybinding dispatch, rendering\n  config/          # TOML config loading (project + global fallback)\n  state/           # JSON state persistence (.cwt/state.json)\n  git/             # Git worktree, branch, and diff operations\n  worktree/        # Worktree CRUD, handoff, snapshots, setup, slug generation\n  session/         # provider session launcher, tracker, transcript parser\n  tmux/            # local multiplexer abstraction (zellij + tmux)\n  hooks/           # Unix socket listener, hook events, script installer\n  forest/          # Multi-repo config, global index\n  orchestration/   # Task dispatch, issue import, broadcast, dashboard\n  ship/            # PR creation, CI status, ship pipeline\n  env/             # Containers (Podman/Docker), devcontainer, ports, resources\n  remote/          # SSH host management, remote sessions, cross-machine sync\n  ui/              # ratatui widgets: layout, list, inspector, dialogs, theme\n```\n\n## Troubleshooting\n\n**cwt says \"zellij or tmux is required\"** Install either `zellij` or `tmux`\nfirst, then run `cwt` again. When both are installed locally, `cwt` prefers\n`zellij`; otherwise it falls back to `tmux`.\n\n**Worktrees don't appear after a provider creates them** Run\n`cwt hooks install` to set up the real-time hook integration. Without hooks, cwt\ndiscovers worktrees on periodic refresh (every few seconds).\n\n**`gh` commands fail (PR creation, CI status)** Make sure the\n[GitHub CLI](https://cli.github.com/) is installed and authenticated\n(`gh auth login`).\n\n**Sessions show \"idle\" even though the provider is running** cwt detects session\nstatus by parsing `~/.claude/projects/` transcripts. If the path hash doesn't\nmatch, status won't update. Restarting cwt re-scans the project directory.\n\n**GC skipped a worktree I expected it to prune** GC never prunes worktrees with\nrunning sessions, uncommitted changes, or unpushed commits. Check `cwt list` for\ndetails.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code conventions,\nand how to submit changes.\n\n## Releases\n\nReleases are managed automatically by\n[release-plz](https://release-plz.ieni.dev/). Pushing conventional commits\n(`fix:`, `feat:`, etc.) to `main` triggers a release PR with version bump,\nlockfile update, and changelog. Merging the PR publishes to crates.io and\ncreates a GitHub Release.\n\n## License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0dragosh%2Fcwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0dragosh%2Fcwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0dragosh%2Fcwt/lists"}