Isolated git worktrees · Split terminal panes · Monaco editor · One unified workspace
Split panes, tab groups, and worktree isolation — all in one window
You're working on a feature branch. A critical bug comes in. You git stash, switch branches, fix the bug, switch back, git stash pop... and pray nothing broke. Sound familiar?
Canopy eliminates context switching entirely. Each branch gets its own isolated worktree with independent terminal sessions, file trees, and editor tabs. Switch between branches like switching browser tabs — zero stashing, zero conflicts, zero lost state.
Organize your projects into collapsible folders for a cleaner sidebar. Projects can live at the root level or be grouped inside folders — your choice.
- Create folders from the "+" dropdown menu in the sidebar header
- Drag-and-drop projects into and out of folders
- Reorder folders and loose projects freely
- Customizable folder and project colors via inline color picker (16-color palette)
- Right-click context menu to rename or remove folders
- Removing a folder keeps the projects — they just become loose again
Each branch runs in a completely isolated git worktree. No stashing, no conflicts, no lost work. Your main branch and feature branch coexist side by side with independent file systems, terminal sessions, and editor state.
- Create, list, and remove worktrees from the sidebar
- Each worktree tracks its own branch, split layout, tabs, and file tree
- Instant switching — click a worktree to switch context immediately
Split your workspace horizontally or vertically with Cmd+D / Cmd+Shift+D. Nest splits arbitrarily deep. Drag dividers to resize with visual feedback. The recursive binary split-tree architecture handles any layout you can dream up.
- Horizontal and vertical splits with arbitrary nesting
- Draggable dividers with glow effect on hover
- Proportional ratio tracking for smooth resizing
Each pane contains a tab group with terminals and file editors. Organize your workflow naturally — tests in one pane, server in another, editor in the third.
- Terminal tabs and editor tabs in the same group
- Drag-and-drop to reorder tabs within a group or move between groups
- Tab renaming (double-click or right-click context menu)
- Dirty state indicator (
*) for unsaved editor tabs - Add tab dropdown (+) to create new terminal or file tabs
Built-in VS Code-powered editor for quick file edits without leaving Canopy.
- Syntax highlighting for 20+ languages (TypeScript, JavaScript, Python, Go, Rust, SQL, YAML, and more)
- Bracket pair colorization, word wrap, line numbers
- Save with
Cmd+S - Automatic language detection from file extension
- Theme synced with app theme (dark/light)
Canopy understands your shell's command lifecycle through OSC 133 escape sequences, with intelligent fallback for shells without integration.
- Zsh, Bash, and Fish shell support with automatic bootstrap
- Command state detection — idle, busy (executing), or done (with exit code)
- Dual-layer prompt detection: OSC 133 sequences + ANSI pattern matching fallback
- Activity-based idle detection (4-second silence timeout) compatible with interactive programs like
node,python, and Claude Code
Never miss a finished command again. When a terminal is in the background and a command completes, Canopy notifies you.
- Visual indicator in the sidebar (colored dot: idle / busy / done)
- Procedurally generated notification sounds (Ding, Chime, Bell, Pop)
- Configurable sound type and volume in settings
- Sound can be toggled on/off
A full file browser and git changes panel in the right sidebar.
- All Files tab: directory tree with expand/collapse, sorted folders-first
- Changes tab: git status with color-coded indicators (added, modified, deleted, renamed, untracked)
- Staged vs unstaged distinction
- Filter dropdown (All / Uncommitted)
- Change count badge
- Checks tab: placeholder for future CI/linting integration
- Inline create, rename, and delete files/folders
- Double-click to open files in the Monaco editor
- Right-click context menu for all operations
Drop files directly into the terminal to insert their shell-escaped paths. Supports multi-file drop with space-separated paths and visual feedback during drag.
Terminal sessions survive worktree switches. Switch to another branch, come back, and your terminal is exactly where you left it — with full scrollback replay (up to 100KB buffer).
All workspace state is auto-saved to ~/.canopy/config.json with debounced writes (1.5s), including:
- Projects, folders, and worktrees
- Sidebar ordering (folders and loose projects)
- Split layouts per worktree
- Active worktree selection
- Theme preference
- Terminal and notification settings
A carefully crafted theme system with dark and light modes.
- Dark theme: deep navy surfaces (
#111125) with warm amber accents (#ffb300) - Light theme: warm beige (
#faf7f2) with orange accents - System mode: follows OS appearance preference
- 16-color project palette — click the color indicator on any project or folder to pick a new color
- 8-level tonal hierarchy for depth — boundaries defined through tonal shifts, not harsh borders
- Consistent theming across terminal (xterm.js) and editor (Monaco)
- Node.js 18+ and npm
- Git 2.15+ (worktree support)
- macOS or Linux (Windows support planned)
- Linux only:
build-essentialandpython3(for native module compilation)
# Clone the repository
git clone https://github.com/guikfouri/canopy.git
cd canopy
# Install dependencies
npm install
# Start in development mode
npm run dev# Build the app
npm run build
# Package for current platform
npm run pack
# Package for a specific platform
npm run pack:mac # .dmg / .zip
npm run pack:linux # .AppImage / .debFrom .AppImage:
chmod +x Canopy-*.AppImage
./Canopy-*.AppImageFrom .deb (Debian/Ubuntu):
sudo dpkg -i canopy_*_amd64.debNote: On Linux, you may need to install build dependencies before
npm install:sudo apt install build-essential python3
Click the + button in the sidebar header. Choose New Project to point at a git repo, or New Folder to create an organizational group. Drag projects into folders to keep related repos together.
For each branch you want to work on, create a worktree. Canopy runs git worktree add under the hood, creating an isolated copy of your repo at .claude/worktrees/{name}.
Each worktree has its own:
- Terminal sessions (PTY processes)
- Split pane layout
- File explorer tree
- Editor tabs
- Git status tracking
Click a worktree in the sidebar to switch. Your terminal sessions persist in the background — no process killed, no state lost.
┌─────────────────────────────────────────────────────────┐
│ Electron Main Process │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Terminal │ │ Worktree │ │ Config │ │
│ │ Manager │ │ Manager │ │ Store │ │
│ │ (node-pty) │ │ (git cli) │ │ (JSON fs) │ │
│ └──────┬───────┘ └──────┬───────┘ └───────┬───────┘ │
│ │ │ │ │
│ └────────────┬────┴───────────────────┘ │
│ │ IPC Channels │
├──────────────────────┼──────────────────────────────────-┤
│ │ │
│ Electron Renderer │
│ ┌───────────────────┴────────────────────────────────┐ │
│ │ React App │ │
│ │ ┌─────────┐ ┌────────────────┐ ┌─────────────┐ │ │
│ │ │ Sidebar │ │ MainArea │ │ File │ │ │
│ │ │ Projects │ │ ┌────────────┐ │ │ Explorer │ │ │
│ │ │ Worktree │ │ │SplitContain│ │ │ Changes │ │ │
│ │ │ List │ │ │ ┌──┐ ┌──┐│ │ │ Panel │ │ │
│ │ │ │ │ │ │T1│ │T2││ │ │ │ │ │
│ │ │ │ │ │ └──┘ └──┘│ │ │ │ │ │
│ │ │ │ │ └────────────┘ │ │ │ │ │
│ │ └─────────┘ └────────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ Zustand Stores: worktree-store │ terminal-store │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Layer | Technology |
|---|---|
| Framework | Electron 40 |
| Frontend | React 19, TypeScript 5.9 |
| Terminal | xterm.js 6 + WebGL renderer |
| Editor | Monaco Editor (VS Code engine) |
| Styling | Tailwind CSS 4.1 |
| State | Zustand 5 |
| PTY | @lydell/node-pty |
| Build | electron-vite, electron-builder |
Pane layouts use a recursive binary tree structure. Each node is either a TabGroup (leaf with tabs) or a Split (internal node with direction, ratio, and two children). All tree operations are immutable — returning new references for clean React reconciliation.
type SplitNode = TabGroupNode | SplitNodeInternal
interface SplitNodeInternal {
type: 'split'
direction: 'horizontal' | 'vertical'
ratio: number // 0.0 - 1.0
children: [SplitNode, SplitNode]
}Renderer and main process communicate through typed IPC channels. The renderer is the source of truth for UI state. The main process manages system resources (PTY processes, git operations, filesystem access).
| Domain | Operations |
|---|---|
| Terminal | Create, attach, input, resize, destroy, output, exit, command-state |
| Worktree | Create, list, remove |
| Git | Get branch, list branches, checkout, status |
| Config | Load, save |
| Filesystem | Read dir, read/write file, create dir, rename, delete, stat, watch |
| Dialog | Open directory, save file |
All workspace state (projects, worktrees, layouts, active selections) is serialized to ~/.canopy/config.json with debounced auto-save (1.5s after last change).
| Shortcut | Action |
|---|---|
Cmd/Ctrl+D |
Split pane horizontally |
Cmd/Ctrl+Shift+D |
Split pane vertically |
Cmd/Ctrl+T |
New terminal tab |
Cmd/Ctrl+W |
Close active tab |
Cmd/Ctrl+S |
Save file (in editor) |
Double-click tab |
Rename tab |
Esc |
Close dialogs |
Access settings from the gear icon in the sidebar bottom.
| Setting | Options |
|---|---|
| Theme | System (follows OS), Dark, Light |
| Font Size | 1–32pt (default 13) |
| Scrollback | Lines to keep in buffer (default 10,000) |
| Sound | On/Off toggle |
| Sound Type | Ding, Chime, Bell, Pop |
| Volume | 0–100% slider |
src/
├── main/ # Electron main process
│ ├── index.ts # App entry, window creation
│ ├── ipc-handlers.ts # IPC bridge
│ ├── terminal-manager.ts # PTY lifecycle
│ ├── worktree-manager.ts # Git worktree operations
│ └── config-store.ts # Persistent config
├── preload/ # Secure IPC bridge
│ └── api/ # Typed API surfaces
├── renderer/ # React UI
│ ├── components/
│ │ ├── layout/ # App shell, sidebar, top bar
│ │ ├── terminal/ # Terminal panes, tabs, splits
│ │ ├── workspace/ # Worktree management
│ │ └── file-explorer/ # File browser, git changes
│ ├── stores/ # Zustand state stores
│ └── lib/ # Utilities, constants, split-tree ops
└── shared/ # Types & IPC channel constants
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
npm run dev # Start dev server with hot reload
npm run build # Production build
npm run typecheck # TypeScript validation
npm run rebuild # Rebuild native modules (node-pty)
npm run preview # Preview production build- Multi-project support
- Project folders for sidebar organization
- Git worktree creation & management
- Split pane terminal layout
- Tab groups with terminals & editors
- Drag-and-drop tab reordering & cross-group moves
- Monaco editor integration (20+ languages)
- File explorer with git status & changes panel
- OSC 133 shell integration (zsh, bash, fish)
- Command state detection (idle/busy/done)
- Background command notifications with sound
- Drag-and-drop file path insertion into terminal
- Dark & light themes with system mode
- Session persistence across worktree switches
- Scrollback buffer replay (100KB)
- Color picker for projects and folders (16-color palette)
- Config auto-save & restore
- Settings panel (theme, font, scrollback, notifications)
- Linux support (.AppImage, .deb)
- Windows support
- Integrated search across worktrees
- Custom keybinding configuration
- Plugin system
- Collaborative sessions
- AI-assisted terminal (command suggestions)
A canopy is the uppermost layer of a forest — where branches spread out and coexist without conflict. Just like git worktrees let your branches coexist independently, Canopy gives each branch its own space to grow.
MIT — use it, fork it, build on it.
Built with 🌿 by developers, for developers