git_worktree_manager/operations/
setup_claude.rs1use std::path::PathBuf;
3
4use console::style;
5
6use crate::constants::home_dir_or_fallback;
7use crate::error::Result;
8
9const SKILL_DIR: &str = "gw";
10const LEGACY_SKILL_DIR: &str = "gw-delegate";
11const SKILL_FILE: &str = "SKILL.md";
12const REFERENCE_FILE: &str = "gw-commands.md";
13
14fn skill_dir() -> PathBuf {
16 home_dir_or_fallback()
17 .join(".claude")
18 .join("skills")
19 .join(SKILL_DIR)
20}
21
22pub fn skill_path() -> PathBuf {
24 skill_dir().join(SKILL_FILE)
25}
26
27fn reference_path() -> PathBuf {
29 skill_dir().join("references").join(REFERENCE_FILE)
30}
31
32pub fn is_skill_installed() -> bool {
34 skill_path().exists()
35}
36
37fn write_if_changed(
40 path: &PathBuf,
41 new_content: &str,
42) -> std::result::Result<bool, std::io::Error> {
43 if path.exists() {
44 let existing = std::fs::read_to_string(path).unwrap_or_default();
45 if existing == new_content {
46 return Ok(false);
47 }
48 }
49 if let Some(parent) = path.parent() {
50 std::fs::create_dir_all(parent)?;
51 }
52 std::fs::write(path, new_content)?;
53 Ok(true)
54}
55
56fn remove_legacy_skill() {
58 let legacy_dir = home_dir_or_fallback()
59 .join(".claude")
60 .join("skills")
61 .join(LEGACY_SKILL_DIR);
62 if legacy_dir.exists() {
63 let _ = std::fs::remove_dir_all(&legacy_dir);
64 }
65}
66
67pub fn setup_claude() -> Result<()> {
69 remove_legacy_skill();
70
71 let skill = skill_path();
72 let reference = reference_path();
73
74 let skill_changed = write_if_changed(&skill, skill_content())?;
75 let ref_changed = write_if_changed(&reference, reference_content())?;
76
77 if !skill_changed && !ref_changed {
78 println!(
79 "{} Claude Code skill is already up to date.\n",
80 style("*").green()
81 );
82 println!(" Location: {}", style(skill_dir().display()).dim());
83 return Ok(());
84 }
85
86 let action = if !skill_changed && ref_changed {
87 "updated"
88 } else if skill.exists() && skill_changed {
89 "updated"
91 } else {
92 "installed"
93 };
94
95 println!(
96 "{} Claude Code skill {} successfully!\n",
97 style("*").green().bold(),
98 action
99 );
100 println!(" Location: {}", style(skill_dir().display()).dim());
101 println!(
102 " Use {} in Claude Code to delegate tasks to worktrees.",
103 style("/gw").cyan()
104 );
105 println!(
106 " Or just ask Claude about {} — it will use gw automatically.\n",
107 style("worktree management").cyan()
108 );
109
110 Ok(())
111}
112
113fn skill_content() -> &'static str {
114 r#"---
115name: gw
116description: "Delegate coding tasks to isolated git worktrees. Invoke with: /gw <natural language task description>. Also handles worktree management: list, sync, clean, PR, merge, etc."
117allowed-tools: Bash
118---
119
120# git-worktree-manager (gw)
121
122CLI tool integrating git worktree with AI coding assistants. Single binary, ~3ms startup.
123
124## Natural Language Task Delegation
125
126When the user invokes `/gw <task description>` (e.g., `/gw fix the auth token expiration bug`), follow these steps:
127
128### Step 1: Parse the user's intent
129From the natural language input, determine:
130- **Task description** — what to pass as `--prompt`
131- **Branch name** — generate a short, descriptive branch name from the task (e.g., `fix-auth-token-expiration`). Use conventional prefixes: `fix-`, `feat-`, `refactor-`, `docs-`, `test-`, `chore-`.
132- **Base branch** — use the default unless the user specifies otherwise
133
134### Step 2: Confirm and execute
135Show the user what you're about to run, then execute:
136```bash
137gw new <branch-name> -T <terminal-method> --prompt "<task description>"
138```
139
140### Branch name rules
141- Lowercase, hyphen-separated, max ~50 chars
142- Strip filler words (the, a, an, for, in, on, etc.)
143- Examples:
144 - "Fix the JWT token expiration check in auth" → `fix-jwt-token-expiration`
145 - "Add user avatar upload feature" → `feat-avatar-upload`
146 - "Refactor the database connection pool" → `refactor-db-connection-pool`
147
148### Terminal method selection
149- **Default: omit the `-T` flag** to use the system default (`gw config get launch.method`). Only add `-T` if the user explicitly requests a specific terminal method.
150- If the user explicitly asks for a specific method, use it. Common methods: `w-t` (WezTerm tab), `w-t-b` (WezTerm tab, background — no focus steal), `i-t` (iTerm2 tab), `t` (tmux session), `d` (detached/background)
151- Once the user specifies a method, remember it for subsequent calls in the same session.
152
153## Quick Reference
154
155| Command | Description |
156|---------|-------------|
157| `gw new <branch> [--prompt "..."]` | Create worktree + optionally launch AI with task |
158| `gw delete <branch>` | Delete worktree and branch |
159| `gw list` | List all worktrees with status |
160| `gw status` | Show current worktree info |
161| `gw resume [branch]` | Resume AI session in worktree |
162| `gw pr [branch]` | Create GitHub Pull Request |
163| `gw merge [branch]` | Merge branch into base |
164| `gw sync [--all]` | Rebase worktree(s) onto base branch |
165| `gw clean [--merged]` | Batch cleanup of worktrees |
166| `gw diff <b1> <b2>` | Compare two branches |
167| `gw change-base <new> [branch]` | Change base branch |
168| `gw config <action>` | Configuration management |
169| `gw doctor` | Run diagnostics |
170| `gw tree` / `gw stats` | Visual hierarchy / statistics |
171| `gw backup <action>` | Backup and restore worktrees |
172| `gw stash <action>` | Worktree-aware stash management |
173| `gw shell [worktree]` | Open shell in worktree |
174
175## Delegate a task to a new worktree
176
177```bash
178gw new <branch-name> -T <terminal-method> --prompt "<task description>"
179```
180
181Example:
182```bash
183gw new fix-auth -T w-t --prompt "Fix JWT token expiration check in src/auth.rs"
184```
185
186This will:
1871. Create a new git worktree on a new branch based on the current base branch
1882. Open a new terminal (e.g. WezTerm tab)
1893. Start Claude Code with the given prompt in interactive mode
190
191### Terminal methods (use with -T flag)
192- `w-t` — WezTerm new tab
193- `w-t-b` — WezTerm new tab (background, no focus steal)
194- `w-w` — WezTerm new window
195- `i-t` — iTerm2 new tab
196- `i-w` — iTerm2 new window
197- `t` — tmux new session
198- `t-w` — tmux new window
199- `d` — detached (background, no terminal)
200
201Use the method matching the user's terminal. If unsure, ask.
202
203## Common Workflows
204
205### Feature development
206```bash
207gw new feature-x --prompt "Implement feature X"
208# ... work is done in the new worktree ...
209gw pr feature-x # create PR
210gw delete feature-x # cleanup after merge
211```
212
213### Keep worktrees in sync
214```bash
215gw sync --all # rebase all worktrees onto their base
216gw sync --all --ai-merge # use AI to resolve conflicts
217```
218
219### Batch cleanup
220```bash
221gw clean --merged # delete worktrees for merged branches
222gw clean --older-than 30d --dry-run # preview old worktree cleanup
223```
224
225### Global mode (across repos)
226```bash
227gw -g list # list worktrees across all repos
228gw -g scan --dir ~/projects # discover repositories
229```
230
231## Guidelines
232
233- Use descriptive branch names: `fix-auth`, `feat-login-page`, `refactor-api`
234- Specify base branch if not main/master: `gw new fix-auth --base develop -T w-t --prompt "..."`
235- One focused task per worktree
236- The delegated Claude Code instance works independently in its own worktree directory
237- You can delegate multiple tasks in parallel to different worktrees
238- **Fire-and-forget**: Once a worktree task is spawned, you CANNOT stop it, send follow-up messages, or interact with it. The `--prompt` is the ONLY instruction the delegated instance receives. Therefore:
239 - Make the `--prompt` comprehensive — include all requirements, constraints, and acceptance criteria upfront
240 - If the user's request is vague or ambiguous, ask clarifying questions BEFORE spawning
241 - Do NOT spawn a task assuming you can "correct course later" — you cannot
242
243## Full command reference
244
245For detailed flags and options for all commands, see [gw-commands.md](references/gw-commands.md).
246"#
247}
248
249fn reference_content() -> &'static str {
250 r#"# gw Command Reference
251
252Complete reference for all gw (git-worktree-manager) commands.
253
254## Core Worktree Management
255
256### `gw new <branch> [OPTIONS]`
257Create new worktree for feature branch.
258- `-p, --path <PATH>` — Custom worktree path (default: `../<repo>-<branch>`)
259- `-b, --base <BASE>` — Base branch to create from (default: from config or auto-detect)
260- `--no-term` — Skip AI tool launch
261- `-T, --term <METHOD>` — Terminal launch method. Accepts canonical name (e.g., `tmux`, `wezterm-tab`) or alias (e.g., `t`, `w-t`). Supports `method:session-name` for tmux/zellij (e.g., `tmux:mywork`). See Terminal Launch Methods section below.
262- `--bg` — Launch AI tool in background
263- `--prompt <PROMPT>` — Initial prompt to pass to AI tool (interactive session)
264
265### `gw delete [target] [OPTIONS]`
266Delete a worktree.
267- `-k, --keep-branch` — Keep the branch (only remove worktree directory)
268- `-r, --delete-remote` — Also delete the remote branch
269- `--no-force` — Don't use --force flag
270- `-w, --worktree` — Resolve target as worktree directory name
271- `-b, --branch` — Resolve target as branch name
272
273### `gw list`
274List all worktrees with status indicators (active, clean, modified, stale). Alias: `gw ls`.
275
276### `gw status`
277Show detailed info about the current worktree.
278
279### `gw resume [branch] [OPTIONS]`
280Resume AI work in a worktree. Auto-detects existing Claude sessions and uses `--continue`.
281- `-T, --term <METHOD>` — Terminal launch method (same format as `gw new`)
282- `--bg` — Launch AI tool in background
283- `-w, --worktree` — Resolve as worktree name
284- `-b, --by-branch` — Resolve as branch name
285
286### `gw shell [worktree] [COMMAND...]`
287Open interactive shell in a worktree, or execute a command.
288```bash
289gw shell feature-x # interactive shell
290gw shell feature-x npm test # run command
291```
292
293## Git Workflow
294
295### `gw pr [branch] [OPTIONS]`
296Create GitHub Pull Request from worktree.
297- `-t, --title <TITLE>` — PR title
298- `-B, --body <BODY>` — PR body
299- `-d, --draft` — Create as draft PR
300- `--no-push` — Skip pushing to remote
301- `-w, --worktree` / `-b, --by-branch` — Target resolution
302
303### `gw merge [branch] [OPTIONS]`
304Merge feature branch into base branch.
305- `-i, --interactive` — Interactive rebase
306- `--dry-run` — Show what would happen
307- `--push` — Push to remote after merge
308- `--ai-merge` — Use AI to resolve merge conflicts
309- `-w, --worktree` — Resolve as worktree name
310
311### `gw sync [branch] [OPTIONS]`
312Sync worktree with base branch (rebase).
313- `--all` — Sync all worktrees
314- `--fetch-only` — Only fetch without rebasing
315- `--ai-merge` — Use AI to resolve conflicts
316- `-w, --worktree` / `-b, --by-branch` — Target resolution
317
318### `gw change-base <new-base> [branch] [OPTIONS]`
319Change base branch for a worktree.
320- `--dry-run` — Show what would happen
321- `-i, --interactive` — Interactive rebase
322- `-w, --worktree` / `-b, --by-branch` — Target resolution
323
324### `gw diff <branch1> <branch2> [OPTIONS]`
325Compare two branches.
326- `-s, --summary` — Show statistics only
327- `-f, --files` — Show changed files only
328
329## Maintenance
330
331### `gw clean [OPTIONS]`
332Batch cleanup of worktrees.
333- `--merged` — Delete worktrees for branches already merged to base
334- `--older-than <DURATION>` — Delete worktrees older than duration (e.g., `7d`, `2w`, `1m`)
335- `-i, --interactive` — Interactive selection
336- `--dry-run` — Preview without deleting
337
338### `gw doctor`
339Run health check: git version, worktree accessibility, uncommitted changes, behind-base detection, merge conflicts, Claude Code integration.
340
341### `gw upgrade`
342Check for updates and install latest version from GitHub Releases.
343
344### `gw tree`
345Display worktree hierarchy as a visual tree.
346
347### `gw stats`
348Show worktree statistics (count, age, size).
349
350## Backup & Stash
351
352### `gw backup create [branch] [--all]`
353Create git bundle backup of worktree(s).
354
355### `gw backup list [branch] [--all]`
356List available backups.
357
358### `gw backup restore <branch> [--path <PATH>] [--id <ID>]`
359Restore worktree from backup.
360
361### `gw stash save [message]`
362Save changes to worktree-aware stash.
363
364### `gw stash list`
365List stashes organized by worktree/branch.
366
367### `gw stash apply <target-branch> [-s <stash-ref>]`
368Apply stash to a different worktree.
369
370## Configuration
371
372### `gw config show`
373Show current configuration.
374
375### `gw config list`
376List all configuration keys with descriptions.
377
378### `gw config get <KEY>`
379Get a config value. Keys use dot notation (see Key Config Keys section below).
380
381### `gw config set <KEY> <VALUE>`
382Set a config value. Key-specific valid values:
383- `ai_tool.command` — Preset name (`claude`, `claude-yolo`, `claude-remote`, `claude-yolo-remote`, `codex`, `codex-yolo`, `no-op`) or any command name
384- `launch.method` — Any terminal launch method name or alias (see Terminal Launch Methods)
385- `update.auto_check` — `true` or `false`
386
387### `gw config use-preset <NAME>`
388Use a predefined AI tool preset: `claude`, `claude-yolo`, `claude-remote`, `claude-yolo-remote`, `codex`, `codex-yolo`, `no-op`.
389
390### `gw config list-presets`
391List available presets.
392
393### `gw config reset`
394Reset configuration to defaults.
395
396## Hooks
397
398### `gw hook add <EVENT> <COMMAND> [--id <ID>] [-d <DESC>]`
399Add a lifecycle hook.
400
401### `gw hook remove <EVENT> <HOOK_ID>`
402Remove a hook.
403
404### `gw hook list [EVENT]`
405List hooks.
406
407### `gw hook enable/disable <EVENT> <HOOK_ID>`
408Toggle hook on/off.
409
410### `gw hook run <EVENT> [--dry-run]`
411Manually run hooks for an event.
412
413**Available events:** `worktree.pre_create`, `worktree.post_create`, `worktree.pre_delete`, `worktree.post_delete`, `merge.pre`, `merge.post`, `pr.pre`, `pr.post`, `resume.pre`, `resume.post`, `sync.pre`, `sync.post`
414
415## Export / Import
416
417### `gw export [-o <FILE>]`
418Export worktree configuration to JSON.
419
420### `gw import <FILE> [--apply]`
421Import configuration (preview by default, `--apply` to apply).
422
423## Global Mode
424
425Add `-g` or `--global` to any command to operate across all registered repositories.
426
427### `gw -g list`
428List worktrees across all registered repos.
429
430### `gw scan [--dir <DIR>]`
431Scan for and register git repositories.
432
433### `gw prune`
434Clean up stale registry entries.
435
436## Shell Integration
437
438### `gw shell-setup`
439Interactive setup for shell integration (gw-cd function).
440
441### `gw-cd [branch]`
442Shell function to navigate to worktree by branch name. Supports:
443- `gw-cd` — interactive selector
444- `gw-cd feature-x` — direct navigation
445- `gw-cd -g feature-x` — global (across repos)
446- `gw-cd repo:branch` — repo-scoped navigation
447
448## Terminal Launch Methods
449
450Used with `-T` flag on `gw new` and `gw resume`. Supports `method:session-name` for tmux/zellij (e.g., `tmux:mywork`, `z:task1`).
451
452| Method | Alias | Description |
453|--------|-------|-------------|
454| `foreground` | `fg` | Block in current terminal |
455| `detach` | `d` | Fully detached process |
456| `iterm-window` | `i-w` | iTerm2 new window |
457| `iterm-tab` | `i-t` | iTerm2 new tab |
458| `iterm-pane-h` | `i-p-h` | iTerm2 horizontal pane |
459| `iterm-pane-v` | `i-p-v` | iTerm2 vertical pane |
460| `tmux` | `t` | tmux new session |
461| `tmux-window` | `t-w` | tmux new window |
462| `tmux-pane-h` | `t-p-h` | tmux horizontal pane |
463| `tmux-pane-v` | `t-p-v` | tmux vertical pane |
464| `zellij` | `z` | Zellij new session |
465| `zellij-tab` | `z-t` | Zellij new tab |
466| `zellij-pane-h` | `z-p-h` | Zellij horizontal pane |
467| `zellij-pane-v` | `z-p-v` | Zellij vertical pane |
468| `wezterm-window` | `w-w` | WezTerm new window |
469| `wezterm-tab` | `w-t` | WezTerm new tab |
470| `wezterm-tab-bg` | `w-t-b` | WezTerm new tab (background, no focus steal) |
471| `wezterm-pane-h` | `w-p-h` | WezTerm horizontal pane |
472| `wezterm-pane-v` | `w-p-v` | WezTerm vertical pane |
473
474## Key Config Keys
475
476| Key | Description | Default |
477|-----|-------------|---------|
478| `ai_tool.command` | AI tool name or preset | `claude` |
479| `ai_tool.args` | Additional arguments | `[]` |
480| `launch.method` | Default terminal method | `foreground` |
481| `launch.tmux_session_prefix` | tmux session prefix | `gw` |
482| `launch.wezterm_ready_timeout` | WezTerm ready timeout (secs) | `5.0` |
483| `update.auto_check` | Auto-check for updates | `true` |
484
485## Helper Commands (for scripting and completion)
486
487These hidden commands output newline-separated values, useful for scripting:
488- `gw _config-keys` — List all config key names
489- `gw _term-values` — List all valid `--term` values (canonical + aliases)
490- `gw _preset-names` — List all AI tool preset names
491- `gw _hook-events` — List all valid hook event names
492- `gw _path --list-branches [-g]` — List worktree branch names
493"#
494}