CLI Reference
The canopy CLI provides worktree management and AI tool integration from the terminal.
Table of contents
- Installation
- Shell integration
- Commands
- Launch Claude Code
- AI Tool Hooks
- Claude Code hooks
- Cursor hooks
- Environment variables
- Worktree locations
- Troubleshooting
Installation
The CLI is bundled with Git Canopy. To install:
- Open Git Canopy
- Go to Git Canopy > Settings in the menu bar (not the project settings in the sidebar)
- Click Install CLI
This installs the canopy command to /usr/local/bin/canopy.
Shell integration
Add ~/.canopy/bin to your PATH by adding this to your shell config:
# For zsh (add to ~/.zshrc)
eval "$(canopy shell-init zsh)"
# For bash (add to ~/.bashrc)
eval "$(canopy shell-init bash)"
# For fish (add to ~/.config/fish/config.fish)
canopy shell-init fish | source
Commands
canopy add
Create a new worktree. Idempotent - returns existing path if the branch already has a worktree.
# Create worktree with auto-generated branch name
canopy add
# Create worktree for specific branch
canopy add feature-login
# Create from a specific base branch
canopy add feature-login --base develop
canopy list
List all worktrees in the current repository.
canopy list
canopy ls # alias
# Output as JSON
canopy list --json
# Include commit hashes
canopy list --verbose
canopy status
Show the status of the current worktree.
canopy status
# Output as JSON
canopy status --json
canopy reload
Trigger a reload of local state in the Git Canopy GUI (fast, no network).
canopy reload
# Specify repository path
canopy reload --path /path/to/repo
canopy fetch
Fetch from remote and fully refresh the Git Canopy GUI.
canopy fetch
# Specify repository path
canopy fetch --path /path/to/repo
Launch Claude Code
The easiest way to use Git Canopy with Claude Code is the run command:
canopy claude run
This creates a new worktree for an isolated coding session, then launches Claude Code inside it. Any arguments after run are passed to Claude:
canopy claude run --resume # Resume previous session
canopy claude run -p "fix the bug" # Start with a prompt
If you’re already in a Git Canopy worktree, it launches Claude directly without creating a new one.
Branch naming
Branches start with a generated name like claude-a1b2c3d4. After your first prompt, Git Canopy automatically renames the branch based on what you asked for:
claude-a1b2c3d4 → fix-auth-bug-a1b2c3
This makes it easy to identify sessions later.
AI Tool Hooks
Git Canopy can automatically create worktrees when you start coding sessions with Claude Code or Cursor. This keeps each AI conversation isolated on its own branch.
How it works
- You start a conversation in Claude Code or Cursor
- When the AI makes its first file edit, the hook creates a new worktree
- The AI is instructed to
cdinto the new worktree - All subsequent edits happen in the isolated worktree
This prevents AI tools from accidentally modifying your main branch or mixing changes from different conversations.
Installing hooks
Install hooks for both Claude Code and Cursor:
# Install in current project only
canopy hooks install
# Install globally (all projects)
canopy hooks install --global
# Install for specific tool only
canopy hooks install --claude
canopy hooks install --cursor
Check hook status
canopy hooks status
This shows whether hooks are installed and where.
Claude Code hooks
The Claude Code integration uses the PreToolUse hook to intercept file edits before they happen.
Hook commands
canopy claude pre-tool # PreToolUse hook - creates worktree on first edit
canopy claude stop # Stop hook - marks session as completed
Behavior
When Claude Code calls Write, Edit, or Bash tools:
- First edit from main repo: Creates a new worktree, blocks the edit, and instructs Claude to
cdto the worktree first - First edit from existing worktree: Tracks the session against that worktree without creating a new one
- Subsequent edits: Updates session activity tracking
Configuration file
Hooks are configured in .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|Bash",
"hooks": [
{
"type": "command",
"command": "canopy claude pre-tool"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "canopy claude stop"
}
]
}
]
}
}
Cursor hooks
The Cursor integration uses the afterFileEdit hook to create worktrees after the first edit.
Hook commands
canopy cursor after-edit # afterFileEdit hook - creates worktree on first edit
canopy cursor stop # Stop hook - marks session as completed
Behavior
When Cursor edits a file:
- First edit from main repo: Creates a new worktree and instructs Cursor to
cdto it - First edit from existing worktree: Tracks the session against that worktree
- Subsequent edits: Updates session activity and file count
Configuration file
Hooks are configured in .cursor/hooks.json:
{
"version": 1,
"hooks": {
"afterFileEdit": [
{
"command": "canopy cursor after-edit"
}
],
"stop": [
{
"command": "canopy cursor stop"
}
]
}
}
Environment variables
These environment variables control hook behavior:
| Variable | Effect |
|---|---|
CANOPY_SKIP_WORKTREE | Skip worktree creation entirely. Sessions are still tracked, but no new worktrees are created. |
CANOPY_FORCE_NEW_WORKTREE | Always create a new worktree, even when already in one. |
Examples
Skip worktree creation for a session:
CANOPY_SKIP_WORKTREE=1 claude
Force a new worktree even when in an existing one:
CANOPY_FORCE_NEW_WORKTREE=1 claude
Default behavior
Without either variable set:
| Starting location | Result |
|---|---|
| Main repository | Creates new worktree |
| Existing worktree | Uses existing worktree (no new one created) |
Worktree locations
Worktrees created by hooks are placed in:
~/.canopy/worktrees/<repo-name>/<branch-name>/
For example, a Claude Code session in the git-canopy repo might create:
~/.canopy/worktrees/git-canopy/claude-a1b2c3d4/
Troubleshooting
Hooks not firing
- Check hooks are installed:
canopy hooks status - Verify the config file exists (
.claude/settings.jsonor.cursor/hooks.json) - Check the
canopycommand is in your PATH
Worktree not created
Check the logs at ~/.canopy/logs/hooks.log for errors.
Common issues:
- Not in a git repository
- Branch name conflicts
- Disk space issues
Session not tracked
Ensure the AI tool is passing the required context (session ID, working directory) to the hook via stdin.