A bird's-eye view of your git workspaces
Canopy is a CLI/TUI tool that manages isolated workspaces for your development work. It creates dedicated directories for each workspace, containing git worktrees for all relevant repositories, while keeping canonical clones centralized.
- The Metaphor
- Features
- Installation
- Quick Start
- Documentation
- Command Reference
- Configuration
- License
Think of Canopy as your vantage point above the forest. Just as a canopy provides a bird's-eye view of the trees and branches below, this tool gives you an elevated perspective to see and organize all your git workspaces and branches. The TUI provides a literal canopy-level dashboard where you can survey your entire development landscape—multiple repositories (trees), their branches, and the workspaces where you tend them.
- Isolated Workspaces — Dedicated directories for each task (e.g.,
~/workspaces/PROJ-123) - Git Worktrees — Automatic worktree creation for multiple repos on the same branch
- Centralized Storage — Canonical repos cloned once and reused across all workspaces
- Interactive TUI — Terminal UI for managing workspaces at a glance
- Lifecycle Hooks — Run custom commands on workspace creation and closure
- Pattern Matching — Auto-assign repos to workspaces based on ID patterns
go install github.com/alexisbeaulieu97/canopy/cmd/canopy@latestgit clone https://github.com/alexisbeaulieu97/canopy.git
cd canopy
make installThis embeds version, commit hash, and build date into the binary.
# Initialize configuration
canopy init
# Add repositories you work with
canopy repo add https://github.com/myorg/backend.git
canopy repo add https://github.com/myorg/frontend.git
# Create a workspace
canopy workspace new PROJ-123 --repos backend,frontend
# Start working
cd ~/workspaces/PROJ-123See the Quick Start Guide for a complete walkthrough.
| Guide | Description |
|---|---|
| Quick Start | Get up and running in 5 minutes |
| Usage Guide | Complete workflow and examples |
| Configuration | All configuration options |
| Hooks | Automate with lifecycle hooks |
| Error Codes | Error codes for scripting |
| Architecture | Technical architecture overview |
| Command | Description |
|---|---|
canopy workspace new <ID> |
Create a new workspace |
canopy workspace list |
List active workspaces |
canopy workspace view <ID> |
View workspace details |
canopy workspace path <ID> |
Print workspace path |
canopy workspace close [ID] |
Close a workspace (or bulk close with patterns) |
canopy workspace reopen <ID> |
Restore an archived workspace |
canopy workspace rename <OLD> <NEW> |
Rename a workspace |
canopy workspace branch [ID] <BRANCH> |
Switch branch for all repos (or bulk switch with patterns) |
canopy workspace sync [ID] |
Pull updates for all repositories (or bulk sync with patterns) |
canopy workspace git <ID> <git-args...> |
Run git command across all repos |
canopy workspace export <ID> |
Export workspace definition |
canopy workspace import <file> |
Import workspace from file |
canopy workspace repo add <ID> <REPO> |
Add a repository to workspace |
canopy workspace repo remove <ID> <REPO> |
Remove a repository from workspace |
Flags for workspace new:
--repos— Comma-separated list of repositories--branch— Custom branch name (defaults to ID)--print-path— Print the created workspace path--no-hooks— Skip post_create hooks--hooks-only— Run post_create hooks without creating workspace
Flags for workspace list:
--status— Show git status for each repository--timeout— Timeout for status check per workspace (default: 5s)--closed— List closed workspaces--json— Output in JSON format
Flags for workspace close:
--keep— Keep metadata for later restoration--delete— Delete without keeping metadata--force— Force close even with uncommitted changes--dry-run— Preview what would be deleted--no-hooks— Skip pre_close hooks--hooks-only— Run pre_close hooks without closing workspace--pattern— Close workspaces matching a regex pattern--all— Close all workspaces (equivalent to--pattern ".*")
Flags for workspace sync:
--timeout— Timeout for each repository sync (default: 60s)--json— Output in JSON format--pattern— Sync workspaces matching a regex pattern--all— Sync all workspaces (equivalent to--pattern ".*")
Flags for workspace branch:
--create— Create branch if it doesn't exist--pattern— Switch branches for workspaces matching a regex pattern--all— Switch branches for all workspaces (equivalent to--pattern ".*")
| Command | Description |
|---|---|
canopy repo list |
List cloned repositories |
canopy repo add <URL> |
Clone and register a repository |
canopy repo remove <NAME> |
Remove a repository |
canopy repo sync <NAME> |
Fetch updates from remote |
canopy repo path <NAME> |
Print canonical repository path |
Use short aliases for repositories:
| Command | Description |
|---|---|
canopy repo register <alias> <url> |
Register an alias |
canopy repo unregister <alias> |
Remove an alias |
canopy repo list-registry |
List all registered aliases |
canopy repo show <alias> |
Show registry entry details |
canopy tui| Key | Action |
|---|---|
Enter |
View workspace details |
Space |
Toggle workspace selection |
a |
Select all visible workspaces |
A |
Deselect all workspaces |
o |
Open workspace in editor |
s |
Sync selected workspaces |
p |
Push selected workspaces |
c |
Close selected workspaces |
t |
Toggle stale filter |
/ |
Search workspaces |
q |
Quit |
See Configuration to customize keybindings.
| Command | Description |
|---|---|
canopy init |
Initialize configuration |
canopy status |
Show status of current workspace |
canopy check |
Validate configuration |
canopy version |
Print version information |
Version output example:
canopy version v1.0.0
commit: abc1234
built: 2025-01-15T10:30:00Z
go: go1.21.0
Use canopy version --json for machine-readable output or canopy --version for a short version string.
Configuration is stored in ~/.canopy/config.yaml:
projects_root: ~/projects
workspaces_root: ~/workspaces
closed_root: ~/.canopy/closed
workspace_close_default: delete # default; set to "archive" to keep metadata
defaults:
workspace_patterns:
- pattern: "^PROJ-"
repos: ["backend", "frontend"]
templates:
backend:
description: "Backend workspace defaults"
repos: ["backend", "common"]
default_branch: "main"
frontend:
description: "Frontend workspace defaults"
repos: ["frontend", "ui-kit", "design-system"]
setup_commands:
- "npm install"See Configuration Reference for all options.
Use templates to create common workspace layouts quickly:
canopy workspace new PROJ-123 --template backend
canopy workspace new PROJ-456 --template frontend --repos extra-libWorkspace creation fails with "unknown repository"
The repository must be cloned or registered first:
# Clone the repository
canopy repo add https://github.com/myorg/repo.git
# Or register an alias
canopy repo register repo https://github.com/myorg/repo.gitGit operations timeout
Configure retry settings in ~/.canopy/config.yaml:
git:
retry:
max_attempts: 5
initial_delay: "2s"
max_delay: "60s""Repository has uncommitted changes" error
Either commit/stash changes or use --force:
canopy workspace close PROJ-123 --forceConfiguration validation errors
Run canopy check to validate your configuration:
canopy checkFor machine-readable error handling, see the Error Codes Reference.