Launch and Share Recipes
Using a recipe once it exists: launching from the empty-canvas launcher, running one across several worktrees at once, sharing recipes with a team through the repository, and exporting or importing them.
The Empty-Canvas Launcher
When a worktree has no open panels, the canvas is not blank — it is a launcher. Recipes are its first section, not the whole of it. Five sections stack down the column, each arriving 30 ms after the one above it so the surface reads as a sequence rather than a wall:
- Recipes — the recipe runner described below, shown once the project's recipes have loaded.
- Resume — a single line for the most recent resumable agent session, with a +N more entry into the searchable resume list when there is deeper history. It renders nothing at all when there is nothing to resume, so a genuine first run stays quiet. See Session Management.
- Quick actions — a chip per agent you keep on the toolbar, plus New terminal and Browse files, each showing its live keybinding, over a wider Search agents & panels… button that opens the panel palette.
- Project Pulse — the activity strip, when it is enabled. See Project Pulse.
- Tips — a rotating hint, shown only once you have launched an agent at least once.
Switching projects re-enters nothing, since the sections were already mounted, so Daintree replays the entry
animation by hand on a project switch. The whole sequence is suppressed under prefers-reduced-motion, Daintree's own reduce-animations toggle, and performance mode.
Grid Mode and List Mode
With six or fewer recipes, the recipe section uses a grid layout: two columns for one to two recipes, three columns for three to six. Past six recipes, it switches to a compact list mode with a search box that auto-focuses for quick filtering. Every card and row prints its scope label, and a shadowed one is dimmed with its Overridden by Team badge.
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 runs 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, wrapping through the create button |
| Enter | Run the focused recipe |
| Escape | Clear search |
| Command-E Control-E Control-E | Edit the focused recipe |
Where that edit chord is Ctrl+E — Windows and Linux — it is deliberately not captured while the search box has focus, because there it already means "move to end of line".
Status Banners
When you launch a recipe, the runner can show a banner at the top of the grid reporting what happened. There are two.
The spawn-failure banner, an error banner, appears when one or more panels fail to start. It reads like "Started 2 of 3 terminals. 1 failed: Dev server." and offers a Retry failed action. Retry re-runs only the panels that failed. The panels that already started keep running, untouched.
The unresolved-variables banner, a warning banner, appears when a prompt variable couldn't be resolved, for example when no issue is linked. It reads
"Missing context for {{issue_number}}" and explains that "These variables stayed
empty in the launched commands." The check covers the agent panel's initial prompt.
Stale banners clear themselves on the next run, or when you switch worktrees.
Context Menu
Right-click a recipe card or row for Run, Edit, Duplicate, Pin to Empty State (or Unpin), and Delete.
Before You Have Any Recipes
With no recipes saved, the section falls back to a create prompt — but it uses what it knows about the project
first. If Daintree has detected run commands, up to two of them appear as suggestion pills, name on the left and
command on the right, filtered to the ones that look like a dev, start, serve, test or build script. Clicking one runs it in a terminal. Only when nothing is detected
does the line "Launch agents, dev servers, and terminals together with one click" stand alone. Either way, a Create your first recipe… button sits below.
The cap of two is deliberate: the empty state should be an obvious next click, not a catalog.
Launching Across Worktrees
Terminal spawning is rate limited — six per second, per project — so a burst of new PTYs cannot swamp the host. A recipe fanout would pay that toll once per terminal, which is why a recipe run does not queue as individual spawns.
Instead, every terminal in one recipe run shares a single spawn admission batch: one slot is claimed for the whole burst, and each terminal is admitted against it. Bulk worktree creation extends the same batch across worktrees, so creating worktrees for a list of issues and running the same recipe on each one cold-spawns as one bounded operation rather than one worktree at a time.
The batch is bounded, not unlimited. A batch admits at most 30 PTYs, and bulk creation chunks the work into as many batches as it needs rather than raising that ceiling. Each batch expires after 30 seconds, so a run that dies partway through cannot hold an admission slot open. Dev preview panels don't count against it — they aren't PTYs.
Two other caps apply to a single run. A recipe can define at most 10 panels, and a run dispatched by an agent through the MCP surface is capped at three terminals, so one approved tool call can't open a full ten-panel workspace. Anything past a cap comes back as a reported failure, not a silent drop. To drive the agents once they are running, see Fleet.
Team Recipes
Team recipes live in .daintree/recipes/ inside the repository and are committed to git, so everyone
working on the project has them. Each recipe is saved as its own JSON file. That keeps git diffs clean and
minimizes merge conflicts.
Daintree auto-loads any .daintree/recipes/*.json files when a project opens. New team members get the
shared recipes after pulling, with no extra step. Save to repo writes straight to .daintree/recipes/ and does not need the "Store settings in repository" toggle enabled first.
Saving a Recipe to the Repo
- Open the Recipe Manager (Shift-Command-P Control-Shift-P Control-Shift-P and search for "Recipe Manager")
- Hover over a Global or Project recipe and click Save to repo
- Confirm in the dialog. Daintree writes the recipe to
.daintree/recipes/{recipe-name}.json - Choose Delete original to drop the local copy, or Keep both to keep it alongside the team version
Environment Variable Handling
When you save a recipe to the repo, Daintree blanks every environment variable value and keeps the keys. That keeps secrets out of git. The keys stay behind as a signal to teammates about which environment variables they need to fill in locally.
Your local values are not lost. Daintree keeps a machine-local mirror of each in-repo recipe holding the values you filled in, and reconciles the two whenever the repository copy changes, so a pull that rewrites the shared file does not blank your environment or reset the recipe's usage history.
Committing Team Recipes
Daintree writes the recipe file. It does not commit it. You stage and commit the file yourself.
git add .daintree/recipes/ && git commit to share it with your
team. Daintree auto-loads any .daintree/recipes/*.json files when a project is opened.How recipe files are written
Every recipe write — a create, an edit, a delete, and the reconciliation pass that folds the repository's files back into your local store — goes through a single queue per project, one turn at a time. Each turn reads the state the previous turn left on disk. That closes the window where a reconcile and an edit could read the same snapshot and one of them silently win.
Reconciliation also refuses to guess. If .daintree/recipes/ is missing entirely — you checked out a
commit that predates it — or if the directory could only be read in part, Daintree cannot tell a recipe a teammate
deleted from one that simply doesn't exist on this branch. In that case it makes no filesystem changes at
all and defers until the directory is readable again, so your local-only environment values and usage
metadata survive a branch switch.
When a teammate edits the same recipe
If an in-repo recipe's file changed on disk between the moment Daintree loaded it and the moment you save — a git pull, a branch switch, a stash pop — the write is refused rather than applied. Your edit is rolled back in the UI and a dialog titled Recipe '<name>' changed on disk asks how to reconcile:
- Reload from disk discards your in-flight edit and refreshes to match the file. This is the safer choice and the one the dialog leads with.
- Overwrite recipe re-applies your edit on top, replacing the newer file content.
- Dismissing the dialog leaves the rolled-back state in place, so you can look at the file and retry.
A related case is a filename collision: two recipes whose names reduce to the same file name. Only one can own the file. The other stays project-local rather than being dropped, and the collision is reported so you can rename one, instead of being logged where nobody would see it.
Export and Import
Exporting Recipes
The Recipe Manager exports recipes two ways:
- Export to clipboard copies the recipe as JSON, without the internal project id or the shadowing marker. The button reads "Exported" for two seconds to confirm.
- 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 for Global or Project.
- Import from file opens a file picker for
.jsonfiles.
On import, Daintree validates the recipe structure, rejects control characters in commands, arguments, dev commands and environment values, and drops any panel with an unknown type. The import only fails if no valid panels remain after validation.