Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# cwt — Provider (Claude or Codex) Worktree Manager
# cwt — Provider (Claude, Codex, or Pi) Worktree Manager

A TUI worktree manager for the provider (Claude or Codex). The worktree is the first-class primitive — sessions attach to worktrees, not the other way around.
A TUI worktree manager for the provider (Claude, Codex, or Pi). The worktree is the first-class primitive — sessions attach to worktrees, not the other way around.

## Project Overview

`cwt` is a Rust TUI (ratatui + crossterm) that manages git worktrees purpose-built for parallel provider (Claude or Codex) sessions. It runs inside tmux and manages panes for each active session.
`cwt` is a Rust TUI (ratatui + crossterm) that manages git worktrees purpose-built for parallel provider (Claude, Codex, or Pi) sessions. It runs inside tmux and manages panes for each active session.

### Core Mental Model

Expand Down Expand Up @@ -59,7 +59,7 @@ src/
session/
mod.rs
launcher.rs # Launch provider in tmux pane
tracker.rs # Parse ~/.claude/ for session status
tracker.rs # Parse provider session directories for session status
transcript.rs # Read last N messages from session JSONL
tmux/
mod.rs
Expand Down Expand Up @@ -155,7 +155,8 @@ src/
- Status check: `tmux list-panes -F '#{pane_title} #{pane_current_command}'`

### Session Transcript Preview
- The provider stores sessions at `~/.claude/projects/<path-hash>/` (Claude-compatible transcript path).
- Claude/Codex store sessions at `~/.claude/projects/<path-hash>/`.
- Pi stores sessions at `~/.pi/agent/sessions/--<path-hash>--/`.
- Each session is a `.jsonl` file with conversation turns
- Parse the last 2-3 assistant messages for the "Last msg" preview
- Show token count / cost if available in the transcript
Expand All @@ -169,7 +170,8 @@ src/

### Hooks (Provider Integration)

cwt integrates with the provider (Claude or Codex) via its hook system for real-time state sync.
cwt integrates with providers for session management, and currently integrates with Claude hooks for real-time state sync.
Pi and Codex do not get hook installation or hook-driven worktree import in this phase.

#### Communication Path
```
Expand Down Expand Up @@ -214,7 +216,7 @@ Unix sockets are used instead of file polling for sub-second latency and clean a
| `Tab` | Switch panel focus | Global |
| `/` | Filter/search worktrees | Worktree list |
| `?` | Help overlay | Global |
| `o` | Cycle session provider (Claude/Codex) at runtime | Global |
| `o` | Cycle session provider (Claude/Codex/Pi) at runtime | Global |
| `O` | Save current provider as default | Global |
| `q` | Quit | Global |

Expand All @@ -233,7 +235,7 @@ timeout_secs = 120 # setup script timeout

[session]
auto_launch = true # launch provider on worktree create
provider = "claude" # "claude" | "codex"
provider = "claude" # "claude" | "codex" | "pi"
provider_args = [] # extra args for provider invocation

[handoff]
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "cwt"
version = "0.2.11"
edition = "2021"
description = "Claude Worktree Manager — TUI for managing git worktrees with Claude Code"
description = "Provider Worktree Manager — TUI for managing git worktrees with Claude, Codex, or Pi"
license = "MIT"
repository = "https://github.com/0dragosh/cwt"
homepage = "https://github.com/0dragosh/cwt"
Expand Down
49 changes: 27 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# cwt — Provider (Claude or Codex) Worktree Manager
# cwt — Provider (Claude, Codex, or Pi) Worktree Manager

A terminal UI for running parallel
provider (Claude or Codex) sessions in
provider (Claude, Codex, or Pi) sessions in
isolated git worktrees. Built in Rust, it uses a local terminal multiplexer for
interactive session management, preferring zellij when available and falling
back to tmux.
Expand All @@ -19,7 +19,7 @@ Worktree (unit of work)

## Why cwt?

When using a provider (Claude or Codex) on a real codebase, you often want to run multiple tasks
When using a provider (Claude, Codex, or Pi) on a real codebase, you often want to run multiple tasks
in parallel — fix a bug, add a feature, write tests — without them stepping on
each other. Git worktrees give you cheap, isolated copies of your repo. cwt
manages the lifecycle of those worktrees and the provider sessions inside them,
Expand All @@ -39,7 +39,7 @@ all from a single TUI.
- **git** (with worktree support)
- **zellij** or **tmux** (interactive mode needs one local terminal multiplexer;
zellij is preferred when both are installed)
- A provider CLI (`claude` or `codex`)
- A provider CLI (`claude`, `codex`, or `pi`)

Optional:

Expand Down Expand Up @@ -189,18 +189,19 @@ cwt status # CLI summary across repos

### Session Providers

- cwt supports two provider options: `claude` and `codex`
- You can set the default in config with `session.provider = "claude"` or `"codex"`
- cwt supports three provider options: `claude`, `codex`, and `pi`
- You can set the default in config with `session.provider = "claude"`, `"codex"`, or `"pi"`
- You can change the active provider at runtime by pressing `o` in the TUI
- Press `O` to persist the currently selected provider as the default
- Local interactive mode prefers **zellij** and falls back to **tmux**
- Launching `cwt` outside a multiplexer auto-attaches to a `cwt` session in the
preferred backend
- In zellij, provider sessions and shells open in named tabs; in tmux, they
open in panes/windows
- **Launch** the provider (Claude or Codex) in the active multiplexer attached
- **Launch** the active provider in the active multiplexer attached
to any worktree
- **Resume** previous sessions using the active provider's resume flow (`--resume` for Claude)
- **Resume** previous sessions using the active provider's resume flow
(`--resume` for Claude, `resume <id>` for Codex, `--session <id>` for Pi)
- **Focus** an existing session tab/pane with a single keypress
- **Open shell** in any worktree directory via the active multiplexer
- Sessions survive TUI exit — closing cwt does not kill running sessions
Expand All @@ -216,11 +217,12 @@ cwt status # CLI summary across repos

### Hooks (Real-Time Provider Integration)

- cwt provider support includes `pi`, but hook automation is still Claude-only in this phase
- **Unix domain socket** listener for sub-second event delivery
- Worktrees created by the provider (Claude or Codex) outside cwt appear in the list within one
second
- Worktrees created by Claude outside cwt appear in the list within one second
- `cwt hooks install` patches `.claude/settings.json` and writes hook scripts to
`.cwt/hooks/`
- Pi and Codex sessions do not currently get hook installation or real-time worktree import support

### Forest Mode (Multi-Repo)

Expand Down Expand Up @@ -251,25 +253,26 @@ cwt status # CLI summary across repos

### Permission Levels

cwt supports three permission tiers for provider sessions (Claude/Codex), giving you
cwt supports three permission tiers for provider sessions, giving you
fine-grained control over how much autonomy the provider gets:

| Level | Badge | Behavior |
| ----- | ----- | -------- |
| **Normal** | `N` (gray) | Plain provider command — asks for permission on each tool use (default) |
| **Elevated** | `E` (yellow) | Injects sandbox settings into `.claude/settings.local.json` — the provider runs autonomously within a sandbox |
| **Elevated Unsandboxed** | `U!` (red) | Appends `--dangerously-skip-permissions` — full autonomy, no sandbox |
| **Elevated** | `E` (yellow) | Uses provider-specific elevated behavior; for Claude this injects sandbox settings into `.claude/settings.local.json` |
| **Elevated Unsandboxed** | `U!` (red) | Uses provider-specific unsandboxed behavior or configured extra args |

- Press `m` to cycle through modes at runtime
- Press `M` to save the current mode as the default in your config
- The active level is shown as a badge in the top bar
- Each worktree gets its own `.claude/settings.local.json`, so there are no
concurrency conflicts between sessions
- Claude worktrees get their own `.claude/settings.local.json`, so there are no
concurrency conflicts between Claude sessions

Provider-specific mode behavior:

- Claude: `Elevated` injects sandbox settings; `Unsandboxed` uses `--dangerously-skip-permissions`.
- Codex: `Unsandboxed` uses `--full-auto`; `Elevated Unsandboxed` uses `--dangerously-bypass-approvals-and-sandbox`.
- Pi: cwt passes only the configured `session.permissions.<level>.extra_args`; no Claude settings injection or Codex-specific flags are applied.

The elevated (sandboxed) provider mode writes these settings before launch:

Expand Down Expand Up @@ -328,7 +331,7 @@ The elevated (sandboxed) provider mode writes these settings before launch:
| --- | -------------------------------------------- | ------- |
| `m` | Cycle mode (Normal/Unsandboxed/Elevated Unsandboxed) | Global |
| `M` | Save current mode as default | Global |
| `o` | Cycle session provider (Claude/Codex) at runtime | Global |
| `o` | Cycle session provider (Claude/Codex/Pi) at runtime | Global |
| `O` | Save current provider as default | Global |

### Navigation
Expand Down Expand Up @@ -358,9 +361,9 @@ The elevated (sandboxed) provider mode writes these settings before launch:
| `cwt delete <name>` | Delete a worktree (saves snapshot) |
| `cwt promote <name>` | Promote ephemeral to permanent |
| `cwt gc [--execute]` | Preview/run garbage collection |
| `cwt hooks install` | Install provider hook scripts |
| `cwt hooks uninstall` | Remove hook scripts |
| `cwt hooks status` | Show hook and socket status |
| `cwt hooks install` | Install Claude hook scripts |
| `cwt hooks uninstall` | Remove Claude hook scripts |
| `cwt hooks status` | Show Claude hook and socket status |
| `cwt dispatch "task" ...` | Dispatch parallel tasks |
| `cwt import --github [--limit N]` | Import GitHub issues as worktrees |
| `cwt import --linear [--limit N]` | Import Linear issues as worktrees |
Expand Down Expand Up @@ -402,7 +405,7 @@ timeout_secs = 120 # setup script timeout

[session]
auto_launch = true # launch session provider on worktree create
provider = "claude" # "claude" | "codex"
provider = "claude" # "claude" | "codex" | "pi"
command = "" # optional command override (defaults to provider binary)
provider_args = [] # extra args for provider invocation
default_permission = "normal" # "normal", "elevated", or "elevated_unsandboxed"
Expand Down Expand Up @@ -470,14 +473,16 @@ first, then run `cwt` again. When both are installed locally, `cwt` prefers

**Worktrees don't appear after a provider creates them** Run
`cwt hooks install` to set up the real-time hook integration. Without hooks, cwt
discovers worktrees on periodic refresh (every few seconds).
discovers worktrees on periodic refresh (every few seconds). Hook-based import is
currently Claude-only.

**`gh` commands fail (PR creation, CI status)** Make sure the
[GitHub CLI](https://cli.github.com/) is installed and authenticated
(`gh auth login`).

**Sessions show "idle" even though the provider is running** cwt detects session
status by parsing `~/.claude/projects/` transcripts. If the path hash doesn't
status by parsing provider session transcripts. Claude/Codex use
`~/.claude/projects/`; Pi uses `~/.pi/agent/sessions/`. If the path hash doesn't
match, status won't update. Restarting cwt re-scans the project directory.

**GC skipped a worktree I expected it to prune** GC never prunes worktrees with
Expand Down
Loading