Skip to main content

CopyTree

Bundle a worktree into a structured context snapshot (from the toolbar, a worktree card, a file row, or an agent) with per-project history and re-runnable recents.

Updated
Reviewed

What CopyTree Does

CopyTree walks a worktree, applies your filters and budgets, and produces one structured bundle of the file tree plus file contents. Paste it into an agent, hand an agent the file it was written to, or inject it straight into a terminal. It saves you copying files one at a time or describing your project structure in prose, and it gives the agent something it can read in a single pass.

CopyTree is worktree-scoped. Every route below resolves to a worktree, which is why the file browser drops Copy context on a plain workspace folder that has no worktree behind it.

Note
CopyTree is also a standalone command-line tool, and Daintree embeds it as a library rather than shelling out to it. Nothing on this page needs it installed — but if you want the same bundles in a bare terminal, a CI job, or an editor that is not Daintree, CopyTree CLI covers installing and using it.

Three Ways to Copy

The toolbar button

The Copy context button in the toolbar opens a dropdown rather than copying immediately. It holds two things:

  • Copy full context: the old one-click behavior, now one click deeper.
  • The five most recent copies for this project, each showing its name and a "N files · size · age" line. Selecting one re-runs it.

Shift-Command-C Control-Shift-C Control-Shift-C skips the dropdown and copies the full context for the active worktree directly.

Copy the full context, or re-run a recent copy

The worktree card

  1. Click the button on a worktree card, or right-click the card.
  2. Hover Copy Context.
  3. Choose Full Context or Modified Files Only.

Full Context copies everything that survives your filters, the right choice when you start a session, ask an architectural question, or onboard an agent to a project. Modified Files Only restricts the bundle to git-tracked files with staged or unstaged changes, on top of whatever else your project settings apply. Use it for iterative work, when the agent already holds the broader picture.

Note
Untracked files (ones you have never run git add on) are not in a Modified Files Only bundle. Stage them first if you want them included.

From an agent

The in-app Daintree Assistant and any external MCP client reach CopyTree through three tools, at three different tool tiers:

ToolTierWhat it does
copyTree.generateWorkbenchWrites the bundle to a temporary file and returns its path.
copyTree.injectToTerminalActionStreams the bundle straight into a terminal. Target an idle one: this types a potentially enormous payload into a live pane.
copyTree.generateAndCopyFileSystemBundles to a file and puts it on the system clipboard, replacing what you had copied. macOS and Linux copy the file; Windows copies its path.

A bundle is never returned inline. copyTree.generate hands back a file handle because these bundles routinely run to tens of megabytes; the caller can opt into a bounded head of the content alongside the path, with a flag saying whether that head was truncated. Temporary bundles are pruned by age, so an agent should read the file promptly.

Named copies

Assistant and MCP callers can pass a name with the run. That name becomes the label on the history row, so an agent's "auth module context" sits in the same recents list as your own copies, labeled the way it described itself rather than as another anonymous entry. Names are capped at 120 characters; a run with no name gets one derived from its options.

How a Finished Copy Is Confirmed

Every route confirms the same way: a short-lived notice pinned to the toolbar's Copy context button, reading a title and a one-line summary: file count, size, and format. That includes copies you never clicked for, like an agent bundling context in the background.

The notice falls back to a toast when the button can't carry it: the button is unmounted or has overflowed out of the toolbar, the window is in the background, or the recents dropdown is open on the same anchor and the two surfaces would stack. The notice is mirrored into a live region, so assistive technology gets it either way.

The wording follows the destination, because the verb has to be true: clipboard copies read "Copied … to clipboard", terminal injections "Injected … into terminal", and temporary-file bundles "Bundled … into a temporary file". A failure reads Copy context failed: … with the reason.

Tip
Read the file count and size as a token-budget check before you send the bundle anywhere. If it looks too big, the fix is usually a scoped copy rather than a tighter global filter.

Scoped Copies

Copy context appears on file and folder rows in the file browser, the diff sidebar, and the worktree card's changed-file list. It bundles just that path.

A scoped copy passes the row's literal path rather than a pattern, and scoping restricts traversal rather than adding a filter: your project's ignore rules and excludes still apply inside the scope, so the result is exactly the subset a whole-worktree copy would have produced for that path. Nothing outside the scope can be pulled in.

That default is deliberate, but it has a cost: name a folder your .gitignore prunes and you get an empty bundle. Rather than leave you to guess, an empty scoped copy explains itself: "Every file in this folder is excluded by an ignore rule" when that accounts for all of it, and a neutral wording when the causes are mixed.

Agent and MCP callers have a narrow escape hatch for exactly that case. scopeIgnoresIgnoreFiles lifts only the rules blocking entry into each scoped path, and only from .gitignore and .copytreeignore. Unrelated rules in those same files, negations, ignore files at or below the selection, project excludes, .git, the git filters and every budget all still apply. It requires scopePaths and is rejected without it.

Filtering and Pattern Semantics

The selection surface an agent sees is wider than the project settings screen, and the shapes are not interchangeable:

OptionBehavior
filter / includePathsTwo spellings of one selection set, unioned when both are given. Worktree-relative exact file paths or globs.
excludePatterns to drop. Installed as an ignore layer, so it prunes before the include patterns are consulted.
alwaysForce-include. The blunt instrument: it beats ignore files, project and config excludes, your own exclude, the git filters, and the per-file size gate.
scopePathsLiteral file or directory paths to walk. Restricts traversal; the include patterns can only narrow within it.
modified / changedOnly files with uncommitted changes, or only files changed since a named base branch.

What always does not override is worth knowing before you reach for it: .git, CopyTree's internal 10 MB per-file memory ceiling, and the file-count, total-size and character budgets, which still drop force-included files. A broad always pattern can pull in node_modules, and a ../ pattern reaches outside the worktree entirely. When you only need past an ignore rule, prefer a scoped copy.

CopyTree reads and honors your project's .gitignore and .copytreeignore alongside the excludes configured in project settings.

Limits and Budgets

These are enforced, not advisory: a file that survives every filter is still dropped when a budget bites, force-included or not.

SettingDefaultEffect
Max context size (bytes)100 MBTotal size across all files.
Max file size (bytes)Up to 10 MBSkip any single file larger than this. CopyTree's own 10 MB ceiling applies regardless.
Character budgetNo truncationTotal characters of file content across the bundle.
File priority strategyAll files, in path orderWhat to keep when a budget drops files: Include all files or Recently modified first.

A result reports which budget bit first and how many files it dropped, so a truncated bundle is legible rather than silently short. There is also a case where the budget is exceeded without any truncation at all: when the first file alone is over the total-size limit, it is kept anyway rather than producing an empty bundle.

Output Formats

Six formats are available, chosen per run by the caller: xml (the default), json, markdown, tree, ndjson, and sarif. XML suits AI consumption, Markdown reads well to a human, and tree gives the structure alone with no file contents, a cheap way to orient an agent before it reads into specific files.

Format is not a project setting. Manual copies use the default; agents and MCP clients name a format on the call.

Testing Your Configuration

Test config in Project Settings → Context runs a dry pass against a real worktree with your current (including unsaved) settings, and reports:

  • How many files would be included, at what total size, with a rough token estimate.
  • How many were excluded, and the reasons that account for most of them.
  • The file list itself, with per-file sizes, so you can see what actually made the cut.
  • A truncation warning naming the budget that bit, if one did.

Sizes are an estimate: the dry run plans the character budget from file sizes without reading content, and says so when a character budget is set.

The Test config result in Project Settings → Context
Tip
Run this before your first full copy on a large project. It is a quick check that your filters catch the right files at a sane size, and it is much faster than discovering the problem in an agent's context window.

Per-Project Configuration

CopyTree settings are per-project, so each repository gets its own excludes and budgets. Configure them in Project Settings → Context (see Project Settings). The tab holds the excluded paths, the always-include and always-exclude glob lists, all four size and priority settings above, and the Test config panel.

Options supplied on a call take precedence over the project's settings, field by field: an agent that names its own exclude replaces yours for that call rather than adding to it. When a call names no excludes, the project's excluded paths and its always-exclude patterns are combined and used together.

Copy History

Every completed run is recorded in a per-project history: 20 records kept, about five surfaced in the dropdown. It is genuinely per-project: the file lives beside that project's own settings, and its updates are pushed only to views bound to that project.

Each record stores the caller's options before project settings were folded in. That is what makes a re-run useful rather than a fossil: replaying a record dispatches its original options through the normal path, so current project settings and excludes apply. A record that froze the merged result would replay a configuration you had since changed.

Runs are also tagged with the surface that asked for them (toolbar, shortcut, worktree card, file browser, MCP, terminal, or workflow), because the same options mean different things coming from a folder menu and from an agent.

Recents replay against the active worktree, not the worktree stored on the record. The record's worktree is whichever one ran it last, and it may since have been removed.

Multi-Window Behavior

CopyTree resolves the worktree and the project settings from the view that made the request, not from whichever project the app most recently focused. A call from a backgrounded window therefore reaches its own project rather than failing or picking up a sibling project's exclusions. The same resolution is captured before any asynchronous work starts, so a view that gets evicted mid-request can't silently drop its project's settings from the bundle.

Recent Changes Worth Knowing

The underlying CopyTree library is pinned at 0.17. Two upgrades changed observable behavior:

  • Budgets are real. The max file size, total size, file count and character budgets are applied rather than being advisory, and the context listing comes from CopyTree itself. Configurations tuned before this may now produce smaller bundles than you remember, which is the budget working, not a regression.
  • Configuration reliability. The Test configuration panel reports a true excluded-file count, the preview populates its file list and respects cleared and unsaved settings, a malformed copyTreeSettings block no longer corrupts generation, gitignored entries no longer leak through in very large directories, and context-injection progress and cancel controls are wired up.