# Claude Focus Workflow
Automated workflow that creates an isolated git worktree, tmux session, and Claude Code instance per task. Each issue gets its own branch, directory, and AI session — fully isolated from other work.
Config files: `~/.zsh/aliases/claude.zsh`, `~/.local/bin/claude-review`
> [!info] Mental Model
> One task = one worktree = one branch = one tmux session = one Claude session. The session ID is deterministic (uuid5 of `repo/branch`), so reconnecting to the same branch always resumes the same Claude conversation.
## Quick Reference
| Alias | Command | Purpose |
|-------|---------|---------|
| `cf` | `claude-focus` | Create worktree + tmux + Claude Code |
| `cfd` | `claude-focus-done` | Tear down worktree + session + branch |
| `cfl` | `claude-focus-list` | List active focus sessions |
| `cfr` | `claude-focus-resume` | Re-attach to a focus session |
| `cfgc` | `claude-focus-gc` | Garbage-collect merged/closed sessions |
| `csb` | `claude-session-branch` | Claude session tied to current branch |
## Setup
The workflow is defined in two files:
- **`~/.zsh/aliases/claude.zsh`** — all shell functions and aliases
- **`~/.local/bin/claude-review`** — standalone review script for neovim
Both are sourced/available automatically via `~/.zshrc`.
### Requirements
- `git` with worktree support (2.5+)
- `tmux` (any recent version)
- `python3` (for uuid5 generation)
- `nvim` (for review panes)
- `fzf` (optional, for session picker in `cfr`)
## Usage
### Start a Focus Session
```bash
# From any git repository — always forks from main/master/trunk
cf issue-42 # named session
cf # auto-named: <repo>-<timestamp>
# Fork from a specific branch
cf --current fix # fork from whichever branch is currently checked out
cf --from develop x # fork from "develop" explicitly
```
This creates:
1. A git worktree at `~/Workspace/.worktrees/<repo>/<name>/`
2. A new branch forked from `main` (default), current branch (`--current`), or a named branch (`--from`)
3. A tmux session named after the branch
4. Claude Code running with a deterministic session ID
### Resume a Session
```bash
cfr issue-42 # by name
cfr # fzf picker (if fzf is installed)
```
### List Active Sessions
```bash
cfl
# Output:
# issue-42 branch=issue-42 ~/Workspace/.worktrees/myrepo/issue-42/
# feature-auth branch=feature-auth ~/Workspace/.worktrees/myrepo/feature-auth/
```
## Review
### tmux Keybindings
| Keys | Action | Mode |
|------|--------|------|
| `prefix + R` | Split right with branch review | All changes since diverging from main |
| `prefix + E` | Split below with working review | Staged + unstaged + untracked |
Both open neovim with changed files. The pane closes when you exit neovim.
> [!tip] Prefix Key
> The tmux prefix is `Ctrl+Space`. So `Ctrl+Space` then `R` opens a branch review pane.
### Standalone Review Script
The `claude-review` script works independently of tmux:
```bash
claude-review # working mode (default)
claude-review --staged # only staged changes
claude-review --branch # all changes since main + uncommitted
```
For 4 or fewer files, neovim opens with vertical splits (`-O`). For more files, it opens a plain buffer list.
## Cleanup
### Single session (`cfd`)
```bash
cfd issue-42 # interactive confirmation
cfd # current session (when inside tmux)
cfd --force issue-42 # skip confirmation + force-delete unmerged branch
```
Removes the tmux session, worktree directory, branch, and empty parent dirs.
### Bulk garbage-collect (`cfgc`)
Scans all worktrees under `~/Workspace/.worktrees/` and removes those whose branches are merged or closed.
```bash
cfgc # interactive — prompts per session
cfgc --dry-run # preview only, nothing touched
cfgc --all # clean everything merged/closed without prompts
```
Merge detection (in priority order):
1. **GitHub PR state** via `gh pr view` — handles regular, squash, and rebase merges
2. **Git ancestry** — `git merge-base --is-ancestor` for regular merges
3. **Diff fingerprint** — `cksum` match against commits in `main` (catches squash merges without a PR)
## How It Works
### Directory Structure
```
~/Workspace/
├── Sandbox/
│ └── myrepo/ ← main clone (origin)
└── .worktrees/
└── myrepo/
├── issue-42/ ← worktree (branch: issue-42)
└── feature-auth/ ← worktree (branch: feature-auth)
```
### Session ID Generation
Claude Code session IDs are generated deterministically using uuid5:
```
session_id = uuid5(NAMESPACE_DNS, "<repo-name>/<branch-name>")
```
This means the same repo + branch combination always produces the same session ID. Resuming a worktree reconnects to the exact same Claude conversation.
### tmux Metadata
Each focus session stores metadata as tmux environment variables:
| Variable | Example | Purpose |
|----------|---------|---------|
| `CF_WORKTREE_PATH` | `~/Workspace/.worktrees/myrepo/issue-42/` | Worktree location |
| `CF_BRANCH_NAME` | `issue-42` | Branch name |
| `CF_GIT_ROOT` | `~/Workspace/Sandbox/myrepo` | Original repo path |
| `CF_SESSION_ID` | `a1b2c3d4-...` | Claude session ID |
| `CF_BASE_BRANCH` | `main` | Branch this worktree was forked from |
Read by `cfd` for cleanup, `cfl` for listing, and `cfgc` for merge-back flows.
### Session Branch (csb)
The `csb` alias is a simpler variant — it launches Claude Code with a session ID tied to the current branch, without creating a worktree or tmux session. Useful when you want session continuity but not full isolation:
```bash
cd ~/Workspace/Sandbox/myrepo
git checkout feature-x
csb # launches Claude with session tied to "feature-x"
```