Worktree Cards
The anatomy of a worktree card in the sidebar: lifecycle chips, row status signals, badges, the quick state filter, collapsed states, search and filters, and per-card recovery actions.
Worktree Cards
This page documents how a worktree card is constructed in the sidebar: the lifecycle chip and row status signals, badge salience, the quick state filter, collapsed states, search and filters, and the per-card recovery actions. For creating, switching, and deleting worktrees, see Worktrees.
Each worktree shows as a card in the sidebar. A card carries:
- Branch name with a badge for the main worktree (it moves to the secondary row when an issue is linked)
- Mood indicator (stable / active / stale / error)
- GitHub issue title as the card headline when linked, plus PR badges for PR state
- Git status: modified file count, insertions, and deletions
- Last commit message summary
- Terminal list: every panel in this worktree with its type and state
- Quick actions: launch agents, run recipes, open in editor
Local git state on worktree cards (commits, branch switches, and file changes) stays current through file-system event watching, not polling. Daintree watches git-internal files and the working directory for changes, so the sidebar reflects new commits and branch switches within roughly 300 milliseconds. While an agent is writing files steadily, updates arrive within one to two seconds. A 30-second polling fallback kicks in if the OS-level watcher isn't available, which mostly happens on Linux when the inotify watch limit is exceeded.
On Linux, sidebar updates lagging by around 30 seconds usually mean the inotify watch limit is exhausted. Check Daintree's log file (Settings > Troubleshooting > Open Log File) for a watcher initialization warning. Raise the limit with sudo sysctl -w fs.inotify.max_user_watches=524288. To make it permanent, add fs.inotify.max_user_watches=524288 to /etc/sysctl.d/99-inotify.conf and run sudo sysctl --system.
Double-click anywhere on the card header to collapse the card. A collapsed card takes less vertical space in the sidebar while still showing key status. Double-click again to expand.
Lifecycle Stage Chip
A small triangular chip in the top-left corner of a worktree card tells you the next action that worktree needs. The chip is color-coded and only appears when there's something to act on.
| Color | State | Meaning |
|---|---|---|
| Amber | Waiting | An agent in this worktree is waiting for your input. |
| Green | Complete | The worktree has a linked issue, an open PR, no uncommitted changes, and no active agents. It is ready for review. |
| Purple | Cleanup | The PR has been merged. This worktree has served its purpose and the branch can be deleted. |
When several conditions apply at once, the chip shows the highest-priority state. The order is cleanup, then complete, then waiting. A merged PR always wins, because its action, delete the worktree, is the most definitive thing you can do.
The chip only shows on secondary worktrees. The main worktree never gets one. It's also absent while git data is still loading for a worktree.
Once a worktree reaches the "complete" state (green chip), open the Review Hub from its context menu to stage, review, and push the changes.
Inline cleanup trash icon
When a card carries a purple cleanup chip, the row toolbar adds a trash-icon button next to the three-dot menu. One click opens the standard delete dialog. The icon stays muted red until you hover, so it reads as available without crowding the rest of the toolbar. You don't have to open the three-dot menu to find Delete on a merged worktree.
Row Status Signals
To the right of the branch name, a worktree row carries a set of small signals. Each one is independent and updates or degrades on its own, so a stale freshness pill never hides a fresh commit chip next to it.
| Signal | What it shows |
|---|---|
| Git state indicator | Inline label for any in-progress Git operation: rebasing, merging, cherry-picking, reverting, bisecting, or applying mailbox. Tone is amber for in-progress and red for a conflict you need to resolve. |
| Commit chip | A small activity dot followed by the relative time of the last commit, for example "2m". The dot fades from accent green to idle as time passes. Hover for the full tooltip with author, commit message subject, and absolute timestamp. |
| Upstream sync badge | ↑N / ↓N ahead and behind counts against the configured upstream remote. When the upstream and the base branch diverge from each other, a second set of counts appears against the base branch, so you see both pictures at once. |
| Git status freshness pill | A quiet indicator of how recently Daintree last refreshed the working tree status. Hidden when the data is under 30 seconds old. Between 30 seconds and one minute, a dim relative-time pill. Between one and five minutes, the pill brightens to a warning tone. Past five minutes, it becomes a clickable Refresh button. |
The author avatar is deliberately left off the row. A row of identical "you" avatars adds noise and no information. The hover tooltip on the commit chip surfaces the author when you actually need it.
Badge Salience and the Collapsed Alarm Pill
A worktree row can carry several status signals at once: a failing CI run, an auth failure on the upstream remote, an "agent waiting" chip, a behind-upstream count, and more. To keep the row from turning into a wall of badges, Daintree applies salience tiers so the most important signal renders first, on the left, and lower-tier signals follow it.
The alarm tier table:
| Tier | Signal | Tone |
|---|---|---|
| 3 (highest) | CI failed | Red |
| 2 | Auth failed (couldn't fetch from upstream) | Amber |
| 1 | Behind upstream | Amber |
| 0 | No alarm | n/a |
Transient, neutral, or pending CI states stay quiet. They never enter the alarm set, so a long push session doesn't flicker the row between tiers as checks queue and finish. Detached HEAD is deliberately not an alarm either: the git state indicator already labels that case in the title row, and there's nothing actionable to surface as a colored pill.
The collapsed alarm pill
When a card is collapsed and at least one alarm-tier signal is active, the badge row collapses into a single colored pill in the card header. The pill takes the color of the highest active tier and carries that tier's label, for example "CI failed" in red or "Behind" in amber. Expand the card to get the full row of individual badges back.
Quick State Filter
The quick state filter bar sits above the worktree list and filters by agent state. In v0.12 the layout moved from text+count pills to icon and count chips, which keeps the bar legible in a narrow sidebar.
There are four segments: All, Working, Waiting, Finished. "All" keeps its text label. The other three are icon plus count only.
- Working uses a green spinner icon. When the count is above zero, the icon turns slowly, with the rotation gated by
prefers-reduced-motion. The animation is a glance signal that work is in flight. It doesn't change polling cadence. - Waiting uses an amber hollow circle.
- Finished uses a blue hollow circle. Finished worktree cards in the list pick up the same blue tone for their status label, and a completed agent's avatar reads as a slate-toned check circle, so completion is easy to spot without reading text.
The active chip carries a subtle inset bottom rule in neutral text color, not the accent color. Clicking an active chip resets to All. Each chip's accessible name carries the noun and the count together ("Working, 3 worktrees"), so screen readers don't lose meaning when the text label drops.
"Finished" vs "Completed". The filter bar uses Finished as the worktree-level label for green-chip (complete) and purple-chip (cleanup) worktrees. Completed is a separate concept: an individual agent session that has finished a turn. The two labels coexist on the same page, and on the same card. The filter bar shows the worktree-level Finished count; the collapsed card indicators show the session-level Completed count.
Disjunctive chip counts
Each chip's count shows what the list would show if only that chip were active, not the count within the current filtered set. With All selected and "Waiting (2)" on the bar, clicking Waiting reliably shows two worktrees. Clicking Working then Waiting won't give you a count that depends on which one you clicked first.
The trailing arm-matching button
An Arm matching button sits at the right edge of the bar in a separate trailing slot, split from the chips by a thin left border. One click arms every eligible agent in the currently filtered set and opens the Fleet Arming Ribbon, ready for an Accept, Interrupt, or broadcast. The label tracks the current state:
- Arm all N terminals: no filter active, no terminals armed yet.
- Arm N matching terminals: filter active, no terminals armed yet.
- Arm N more terminals / Arm N more matching terminals: some terminals already armed; this adds the rest.
When nothing is eligible, the button stays in place but goes disabled with one of: No arm-eligible terminals, All terminals are armed, No arm-eligible terminals match the filter, or All matching terminals are armed. The button never disappears, so its spot in the bar stays predictable.
PR and Issue Badge Freshness
PR and issue badges on a worktree card come from cached GitHub responses. The badge's icon tells you how much to trust the data right now, without opening the panel or reading a tooltip.
| Glyph | Meaning |
|---|---|
| None | Fresh: the cached value is recent and a refresh isn't queued. |
| Clock | Stale: the cached value is older than the freshness threshold. A refresh is in flight or queued. |
| CloudOff | Disconnected: Daintree hit a GitHub rate limit, opened the circuit breaker after repeated failures, or paused PR detection. The badge keeps showing the last known value; the glyph tells you not to treat it as live. |
The badge tooltip shows the relative timestamp ("Updated 4 minutes ago"), and in the disconnected state, the reason and a retry hint ("Rate-limited; retrying at 15:42"). With no GitHub token configured, the badge grayscales and the tooltip reads "Configure GitHub token to see PR details".
Collapsed Cards
Collapsing a worktree card hides the full card body: git status, last commit, terminal list, quick actions. What stays in the header row is the branch name and a set of compact session state indicators.
The indicators show the count of agent sessions in each non-idle state, with small colored icons:
| State | Icon | Color | Animated |
|---|---|---|---|
| Working | Spinning circle | Orange | Yes |
| Directing | Interacting circle | Blue | No |
| Waiting | Hollow circle | Grey (amber when prompting) | No |
| Running | Play icon | Blue | No |
| Completed | Checkmark circle | Green | No |
Each indicator is an icon followed by a count, for example a spinning circle and "2" for two working sessions. Hovering the indicator group shows a tooltip with the full summary, such as "3 sessions: 2 working, 1 waiting". The collapsed view never shows idle sessions.
When every session is idle, or there are no active sessions, no indicators appear and the collapsed card shows just the branch name. For full definitions of each session state, see AI Agents.
Focused Sub-Line
Below the branch name, an expanded card reveals a thin sub-line of context when the card has focus, from mouse hover or keyboard focus. The sub-line is hidden by default. It expands with a short height transition and fades in over about 30 milliseconds, then collapses again when focus leaves. The animation respects prefers-reduced-motion.
The sub-line carries up to three dot-separated segments, in this order:
- Changed file count, when the worktree has uncommitted changes ("3 files" or "1 file").
- Last activity time, as a live relative timestamp.
- Status label, the same short label the card header uses (waiting, working, complete, and so on).
The sub-line stays out of the way until you're looking at the card, then surfaces just enough context for a quick triage call without expanding the card body.
Primary Worktree Card
The main worktree card, usually your main, master, or develop branch, uses a two-row header that gives you a project-level overview at a glance.
The top row shows the project name, not the branch name, a sprout icon, a collapse button, and the actions menu. The second row, visible when expanded, shows the branch label, an upstream sync indicator, and an aggregate summary of all secondary worktrees.
Upstream sync
When your main branch is ahead of or behind the upstream remote, the second row shows commit counts: ↑N in green for commits ahead and ↓N in amber for commits behind. Hover for the full text, for example "3 commits ahead, 1 commit behind upstream".
Aggregate summary
When the project has secondary worktrees, the second row also carries a compact summary: a branch icon with the total worktree count, then colored state counts for working and waiting worktrees. The finished count only appears once there are no working or waiting worktrees. That keeps finished worktrees from drowning out active work that still needs attention.
Card body
When expanded, the primary worktree card body shows two summary rows:
- Worktree and agent counts with the same aggregate breakdown as the header (worktree count, working, waiting, finished)
- GitHub health pulse with CI status, open PR count, and open issue count. This row only appears when GitHub health data is available, which needs a configured GitHub token. See Code Forge for token setup.
Search and Filters
A search bar at the top of the worktree sidebar finds worktrees by name or branch. It searches with a 200ms debounce, so the list filters as you type without flickering on every keystroke. The debounce also drops late results, so a slow GitHub-backed filter can't overwrite a faster local one. The list won't flip back to old results after you type quickly.
The search box, filter popover, and results list follow the ARIA combobox pattern from the W3C Authoring Practices Guide, so screen readers announce filter changes and result counts as you go.
Press Escape to clear the search text and any active filters in one action. If the search is already clear, Escape again blurs the input. The X button at the right edge of the search bar clears both text and filters too.
Advanced filter popover
The filter icon button inside the search bar opens a popover with detailed filter and sort options. When any non-search filter is active, a small green dot badge appears on the filter icon.
| Category | Options |
|---|---|
| Sort by | Date created, Recently updated, Alphabetical, Custom order |
| Group by type | Toggle on/off (groups worktrees by branch type prefix) |
| Status | Active, Dirty (uncommitted changes), Stale, Idle |
| Branch Type | Feature, Bugfix, Refactor, Chore, Docs, Test, Release, CI, Deps, Perf, Style, WIP, Main, Detached, Other |
| GitHub | Has Issue, Has PR, PR Open, PR Merged, PR Closed |
| Sessions | Has Terminals, Working, Running, Waiting, Completed |
| Activity | Last 15 min, 1 h, 24 h, 7 days |
The "Custom order" sort option is hidden while "Group by type" is enabled. A "Clear all filters" button appears at the bottom of the popover when any filter is active.
The chip counts inside each filter category use the same disjunctive logic as the quick state filter bar: each count shows what the list would show if only that chip were active, not the count within the current filtered set. The number you see is the number you get if you click.
Visual Hierarchy
With many worktrees open, Daintree dims idle and stale cards so active work stays visually prominent. The muting drops the visual weight of cards that don't need your attention right now.
A card is muted when it's idle or stale, has no waiting agents, isn't the currently selected worktree, and isn't being hovered or focused. Muted cards use a dimmer text color for branch names and other labels.
One exception matters: a card with a waiting agent is never muted, even if the worktree is otherwise idle or stale. Waiting needs your attention, so those cards always render at full weight. The currently selected card, and any card you hover, are also never muted.
Lifecycle Failure Recovery
The setup lifecycle script can fail, on a missing dependency, a wrong path, or a network blip. In v0.12, failures surface in the card footer rather than in a transient toast you can miss after a context switch. The failed worktree holds its error state until you act on it.
The failure footer reads Setup didn't finish. Re-run when you're ready. in subdued copy, with two controls on the right:
- Retry setup: re-runs the failed lifecycle phase from scratch. The button label changes to "Retrying…" while the run is in flight, then disappears on success. The retry targets the card's own worktree, not the focused one, so you can retry from any context.
- Show details: a disclosure that expands to show the captured error and standard output combined in a scrollable monospaced block. Daintree keeps the last 8192 bytes of output, the same buffer used for remote compute timeouts.
The failure footer survives card collapse and persists across app restarts, so a half-set-up worktree never quietly disappears.
Restarting a Session
Restarting an agent session uses a two-click armed pattern. It guards against accidental scrollback loss without putting a modal in your way.
- Open the panel three-dot menu and click Restart Session. The item arms: its background tints amber, and the label changes to Confirm Restart (3s) with a countdown ticking 3 → 2 → 1.
- Click again within the three-second window to restart. The menu stays open between the two clicks, so you don't have to chase a moving target.
If you don't click the second time, the item disarms on its own and the label returns to Restart Session. The arm state also resets if you switch panels, or if restart eligibility changes mid-countdown. The accessible name on the armed item reads "Armed — click again to confirm restart. N seconds remaining", so screen-reader users get the same signal as the visual countdown.
Sessions Submenu
The worktree card's three-dot menu has a Sessions submenu that fans one action across every session in the worktree. Each item shows the eligible count in parentheses and disables when that count is zero.
| Item | What it does |
|---|---|
| Dock All | Move every grid-resident session in this worktree into the dock. |
| Maximize All | Restore every docked session back to the panel grid. |
| Close All | Close every active session. Terminal output ends and the sessions are gone. |
| Terminate All | Send SIGTERM to every agent process. Use this when Close All would wait too long. |
| Reset All Renderers | Force-reload the xterm renderer for every terminal in this worktree. Handy after a GPU driver hiccup or a font-loading glitch. |
| Select All Terminals | Arm every agent terminal in this worktree (opens the Fleet Arming Ribbon). |
| Select Waiting Agents | Arm only sessions currently in the waiting state. |
| Select Working Agents | Arm only sessions currently in the working state. |
WSL Git Banner
On Windows, when a worktree lives inside a WSL distribution, Daintree checks whether git can be routed through the WSL interop layer. The result drives a banner on the worktree card. Both variants describe themselves in plain language, and the buttons are explicit, so you can opt in or close them out.
The WSL git banner does not appear on macOS. Daintree always runs git natively.
Eligible distribution
When the WSL distribution has git installed and Daintree can reach it, the banner title reads Speed up git on this WSL worktree. The body explains the speed-up:
This worktree lives in WSL ({distro}). Routing git through wsl git avoids the Windows–Linux filesystem boundary and can make status polling 5–10× faster. Two buttons sit at the bottom: Enable WSL git, which switches this worktree to WSL-native git, and Not now, which dismisses the banner. You can flip the setting back from the worktree's settings at any time.
Ineligible distribution
When git isn't available through the WSL distribution, because the distro is stopped, it isn't the default distro, or git isn't installed inside it, the banner title reads Git runs via Windows:
This worktree is in {distro}, which isn't the default WSL distro. Git can't be routed through this distro automatically — it will run from Windows and may be slower than usual.
A single Got it button dismisses the banner. Nothing else happens. This variant is informational, so you know why git feels slow on this worktree.
The WSL git banner does not appear on Linux. Daintree always runs git natively.