Resume Agents and History
How Daintree resumes a closed agent conversation: what writes a journal record, the 20-second trash window, what a record holds, every surface you can resume from, session ids, bookmarks, and retention.
Resuming a closed agent conversation
Closing an agent panel does not throw the conversation away. Daintree journals a resume record on close whenever it captured a resumable session id for that agent, and those records are browsable and searchable, so a session you closed days ago can be picked up where it left off. Agents that expose no id, and closes where none was captured, leave nothing to resume from.
What writes a record
Records are written on every close path, not just the obvious one:
- An agent panel's trash window expiring, or being removed early
- A kill requested from the app, gracefully or not
- App shutdown
- Closing a project, removing a project, or removing a scratch
- Reclaiming a background project's memory
- Bookmark-and-close
All of them funnel through one writer keyed on the terminal and its launch generation, so overlapping paths (a quit racing a trash expiry, say) produce exactly one record rather than duplicates. The main process is the journal's only writer.
The 20-second trash window
Closing an agent panel doesn't kill it immediately. The panel moves into the sidebar trash bin and starts a 20-second countdown, which gives you three outcomes:
- Restore: bring it back exactly as it was, still running. No session record is written, because nothing closed.
- Remove now: kill the agent immediately and write the record at once.
- Let it expire: after 20 seconds the PTY is killed and the record is written.
While the panel is still counting down, no record exists yet: the panel itself is the thing to restore.
What a record holds
Each record carries enough to relaunch the agent into the same conversation, and deliberately nothing more. It holds the session id, the agent, the model if the agent reported one, the worktree and project it belongs to, the working directory and branch it was captured on, the original launch flags, the panel title, and a timestamp. It stores no transcript, no prompt text, and no environment values.
Panel titles are cleaned before they're stored: shell binary names, absolute paths and prompt-style strings are filtered out, so a row reads as a task rather than as a fragment of someone's PS1.
Where to resume from
Four surfaces read the same journal:
- The resume session launcher: Command-K, then Command-R Control-K, then Control-R Control-K, then Control-R , or Resume Session… from the command palette. This is the browse-and-search surface: a search field placeholded Search closed sessions…, a Load more pager for the full journal, and live refresh as new records land. Its empty state reads No closed sessions yet.
- The toolbar: a Resume session button, visible by default.
- The panel palette: Command-N Control-N Control-N carries a short shelf of the five most recent sessions, for the common case where the one you want is the one you just closed.
- The empty grid: when a worktree has no panels open, the launcher offers the most recent resumable session inline, with a +N more link into the full launcher.
Every row reads Resume: <title> when a meaningful title was captured, or Resume <agent> otherwise, with a second line giving the model, agent, location and how long ago it was closed. Rows whose worktree no longer exists are greyed out with a Worktree removed badge and can't be launched: resume is directory-scoped, so relaunching into a directory that isn't there would not resume anything.
Selecting a row launches a new agent panel with the right resume flag and the original launch arguments. You get a fresh panel that continues the same conversation.
Reopen Last Closed
Shift-Command-T Control-Shift-T Control-Shift-T reopens the most recently trashed terminal while its 20-second window is still open. Once that window has lapsed there is nothing in the trash to restore, so it falls back to the journal and resumes the most recent record for the active worktree, scoped that way so the resumed session launches into the directory it was recorded in. If a live panel is already holding that session id, Daintree focuses it instead of spawning a second one, because two panels talking to one transcript is not a state either agent handles well.
Session ids, and why some sessions survive a crash
Resume depends on a session id, and there are two ways Daintree gets one.
For most agents the id is read from the agent's output at teardown: Daintree sends the agent's quit signal and watches for the id in what it prints on the way out. That works for a clean close and only for a clean close.
Claude's id is assigned at launch instead. Daintree mints an id and passes it in on the command line, so the id is known before the agent has produced a single byte. Teardown recognizes this and short-circuits: it kills the process without writing anything into the PTY, because there is nothing left to scrape. The consequence is the point: a session whose id was assigned at launch survives a crash, a force quit, or a SIGKILL, none of which run a teardown.
Which agents do which, and the resume flag each one uses, is per-agent. See Agent States and Agents rather than assuming a shared mechanism.
Bookmarks
A session can be bookmarked with a label, which pins it: bookmarked records are exempt from both the per-worktree cap and the retention window, and deleting the bookmark is the only thing that removes one. Bookmark-and-close captures a live pane's session as a bookmark and then closes the pane, which is the shape of "park this and come back to it": the conversation is preserved, the running process is not.
Retention and clearing
Records live in agent-session-history.json in the app data directory. Daintree keeps up to 50 records per worktree, newest first, and prunes by age on the next write. The retention window is configurable in Settings > Privacy & Data > Session history: 7 days, 30 days (default), 90 days, or Keep forever. A journal file that fails to parse is quarantined to a .corrupted.<timestamp> file rather than truncated, so a bad write can be recovered from rather than silently discarded.
There are two ways to clear history, and they differ in scope:
- One worktree: Clear Session History in the worktree card's context menu. Confirm-gated, and it deletes only that worktree's records.
- Everything on this machine: Clear session history in Settings > Privacy & Data, confirmed by a Clear all session history? dialog. This crosses every project.
Neither touches open sessions, and neither removes bookmarks.
Resumable sessions over MCP
The journal is exposed to automation as List Resumable Sessions, so an agent can find a conversation to hand back to. It refuses to list unscoped: called with no worktree or project, and from a context where neither resolves, it throws rather than returning an empty list: an empty result is indistinguishable from a valid scope with nothing in it, and would read as "nothing to resume". Bookmark tools sit alongside it. See the MCP server for the tool surface and its tiers.