Recipes
Save multi-panel workspace presets as recipes. Launch terminals, AI agents, and dev servers in one click — globally, per-project, or shared with your team via git.
What Are Recipes?
Recipes are saved workspace presets that launch multiple panels at once. Each recipe defines a combination of terminals, AI agent sessions, and dev server panels, complete with commands, starting prompts, and environment variables. You can spin up your preferred layout in one click, and every panel runs in the active worktree's directory so agents and terminals always start in the right branch.
A single recipe can open up to 10 panels in any combination. You can launch recipes from the RecipeRunner (the empty state when no panels are open), from the new worktree dialog, or broadcast them to multiple worktrees at once via Bulk Operations.
Recipe Scopes
Recipes exist in three tiers that control where they are available and how they are stored.
| Tier | Scope | Storage | Shared via Git |
|---|---|---|---|
| Global | All projects, machine-wide | App-level config | No |
| Team | Current project, shared with team | .canopy/recipes/{name}.json | Yes |
| Project | Current project, local only | Machine-local store | No |
Team recipes are not created directly. Instead, you promote a Global or Project recipe to Team status using Save to Repo in the Recipe Manager. This writes the recipe
to .canopy/recipes/ where it can be committed and shared via git.
Team recipes take priority over project-local recipes. If a team recipe and a project recipe share the same name, only the team version is shown. New project recipes default to in-repo storage, so they are ready to be committed and shared from the start.
The Recipe Manager
The Recipe Manager is a dedicated dialog for managing all your recipes across all three tiers. Open it from the action palette (Cmd+Shift+P and search for "Recipe Manager").
The dialog shows three labelled sections: Global Recipes, Team Recipes (visible when .canopy/recipes/ contains recipe files), and Project Recipes.
Each section header has a "New" button for creating recipes in that tier.
Per-Recipe Actions
Hover over any recipe row to reveal action buttons:
| Action | Notes |
|---|---|
| Edit | Opens the recipe editor. Available for all recipe types. |
| Save to Repo | Promotes a global or project recipe to a team recipe. Not shown for recipes already in the repo. |
| Export to Clipboard | Copies the recipe as JSON. Shows a checkmark for two seconds to confirm. |
| Export to File | Opens a save dialog to write a .json file. |
| Delete | Removes the recipe. |
Creating Recipes
Click New Global Recipe or New Project Recipe in the relevant section header. You can also right-click any worktree card and select Save Layout as Recipe to capture all currently active panels, including their agent types, commands, and prompts.
Importing Recipes
The Project Recipes section footer has two import buttons: Import from Clipboard (opens a
dialog with a text area and scope selector) and Import from File (opens a file picker for .json files). Import validation checks for required fields and drops any invalid panel definitions
rather than rejecting the whole recipe. The import only fails if no valid panels remain after validation.
The Recipe Editor
The recipe editor opens when you create or edit a recipe. It has recipe-level settings at the top and panel definitions below.
Recipe-Level Fields
- Recipe Name — required, auto-focused when the editor opens
- Scope — Global or Project. On edit, this is read-only since scope cannot change after creation
- Show in Empty State — pins the recipe to the Pinned section of the RecipeRunner
- Auto-assign Issue — controls whether the linked GitHub issue is auto-assigned to you when creating a worktree with this recipe. Options: "Always assign to me" (default), "Ask before assigning", "Never assign". See GitHub Integration for issue linking setup
Panel Definitions
Each recipe contains one to ten panels. The available fields depend on the panel type:
| Panel Type | Fields | Exit Behavior |
|---|---|---|
| Terminal | Title (optional), Command (optional) | Send to Trash (default), Keep for Review, Remove Completely |
| Agent (Claude, Gemini, Codex, OpenCode) | Title, Initial Prompt (optional, supports variables) | Keep for Review (default), Send to Trash, Remove Completely |
| Dev Preview | Title, Dev Command (auto-detects from package.json) | Send to Trash (default), Keep for Review, Remove Completely |
Every panel also supports optional environment variables and a custom title for the tab label. All panels run in the active worktree's directory.
Variables in Prompts
Initial prompts on agent panels support variable replacement using {{double_curly}} syntax. Variables are resolved at run time from the worktree's context and
are case-insensitive.
| Variable | Resolves To | Example |
|---|---|---|
{{issue_number}} | GitHub issue number linked to the worktree | #123 |
{{pr_number}} | Pull request number linked to the branch | #456 |
{{number}} | Issue number if set, otherwise PR number | #123 |
{{worktree_path}} | Absolute path to the worktree directory | /home/user/project |
{{branch_name}} | Git branch name | feature/issue-42 |
If a variable's context is missing (no issue linked, for example), it resolves to an empty string. Unknown
variable names are left unchanged. When both an issue and PR are linked, {{number}} prefers the issue number.
Team Recipes
Team recipes are stored in .canopy/recipes/ inside the repository and committed to git, making them
available to everyone working on the project. Each recipe is saved as an individual JSON file, which keeps git
diffs clean and minimizes merge conflicts.
Canopy auto-loads any .canopy/recipes/*.json files when a project is opened. New team members get
access to shared recipes automatically after pulling. Save to Repo writes directly to .canopy/recipes/ and does not require the "Store settings in repository" toggle to be enabled first.
Saving a Recipe to the Repo
- Open the Recipe Manager (Cmd+Shift+P and search for "Recipe Manager")
- Hover over a Global or Project recipe and click Save to Repo
- Confirm in the dialog. The recipe is written to
.canopy/recipes/{recipe-name}.json - Choose Delete Original to remove the local copy, or Keep Both to keep it alongside the team version
Environment Variable Handling
When saving a recipe to the repo, Canopy blanks all environment variable values while preserving the keys. This prevents secrets from being committed to git. The keys remain as a signal to teammates about which environment variables need to be filled in locally.
Committing Team Recipes
Canopy writes the recipe file but does not commit it automatically. You need to stage and commit the file yourself.
git add .canopy/recipes/ && git commit to share it with your
team. Canopy auto-loads any .canopy/recipes/*.json files when a project is opened.Export and Import
Exporting Recipes
Recipes can be exported in two ways from the Recipe Manager:
- Export to Clipboard copies the recipe as JSON (without the internal project ID). A checkmark appears for two seconds to confirm the copy.
- Export to File opens a save dialog to write a
.jsonfile to disk.
Importing Recipes
The Project Recipes section of the Recipe Manager has two import options:
- Import from Clipboard opens a dialog with a text area for pasting JSON and a scope selector to choose Global or Project.
- Import from File opens a file picker for
.jsonfiles.
During import, Canopy validates the recipe structure, sanitises control characters from commands and prompts, and drops any panels with invalid types. The import only fails if no valid panels remain after validation.
RecipeRunner (Empty State)
When a worktree has no active panels, the content area shows the RecipeRunner. This is the primary surface for discovering and launching recipes.
Grid Mode and List Mode
With six or fewer recipes, the RecipeRunner uses a grid layout (two columns for one to two recipes, three columns for three to six). When you have more than six recipes, it switches to a compact list mode with a search box that auto-focuses for quick filtering.
In list mode, recipes are grouped into three sections:
- Pinned — recipes with "Show in Empty State" enabled
- Recent — the five most recently used recipes, ranked by frequency and recency
- All — remaining recipes in alphabetical order
Search uses fuzzy matching on recipe names, weighted 70% by name relevance and 30% by usage frequency with a seven-day decay.
Keyboard Shortcuts
| Key | Action |
|---|---|
| ↑ / ↓ | Navigate between recipes |
| Enter | Run the focused recipe |
| Escape | Clear search |
| Cmd+E | Edit the focused recipe |
| Cmd+N | Open the create recipe dialog |
Context Menu
Right-click any recipe card or row to access: Run, Edit, Duplicate, Pin to Empty State (or Unpin), and Delete.
Zero-Recipe State
When no recipes exist yet, the RecipeRunner shows a brief description of what recipes do and a Create new recipe button to get started.
Example Recipes
| Recipe Name | Panels |
|---|---|
| Full Stack Dev | Claude Code + npm run dev terminal + Dev Preview |
| Code Review | Claude Code (prompt: "Review the latest changes") + Gemini CLI (prompt: "Check for security issues") |
| Test & Watch | npm run test:watch terminal + Dev Preview |
| Quick Fix | Claude Code (prompt: "Fix the failing tests") |