Skip to main content

Agent States

The six agent states Daintree tracks, the four reasons an agent can be waiting, how detection works from PTY output, and every surface that reads them.

Reviewed

Why States Exist

Delegating to several agents at once only works if you can tell, without reading any of them, which ones need you. That is the whole job of agent state: Daintree watches each agent's terminal output and reduces it to one of six values, plus a reason when the agent is stuck. Everything that ranks, filters, badges, or notifies in Daintree reads that one signal.

Nothing here is configured. State detection runs for every agent panel, including plugin-contributed agents, from the moment it launches.

The Six States

StateLabelMeaning
IdleidleThe agent's prompt is up and nothing is in flight. This is where a session starts and where it returns after a watchdog gives up on a stale wait.
WorkingworkingThe agent is doing something — streaming a response, running a tool, executing a shell command. Daintree does not split these; from outside the CLI they are the same fact.
WaitingwaitingThe agent has settled and is blocked on you. The waiting reason says what kind of block it is.
DirectingdirectingYou are actively typing into that agent's terminal. It is a renderer-side state — it exists so a panel you are mid-sentence in does not sit in the "needs attention" list you are already attending to.
CompleteddoneThe agent finished a task, detected from its own completion output.
ExitedexitedThe agent process ended — cleanly, by your kill, or by crashing.
Note
There is no "Running" state. Earlier builds had one, as a pre-state-machine signal about the shell process, and older docs still list it. It was folded into working: any stored running value is read as working, and nothing produces it any more.

How states move

The transitions are deliberately narrow, so a noisy terminal cannot walk an agent into a state it was never in:

  • idle goes to working (on launch, output, or your input) or to exited.
  • working goes to waiting (silence, once the agent has settled), completed (a completion pattern), or exited.
  • waiting goes back to working (output or input), to completed, to exited, or — if a watchdog decides the wait is stale and no child process is alive — back to idle.
  • completed goes to working, waiting, or exited.
  • exited is terminal for that agent run. It returns to idle only when a new agent session starts in the same panel.

A user kill is the one hard reset: it returns the panel to idle from any state.

The Four Waiting Reasons

"Waiting" alone does not tell you what it costs to unblock. A permission dialog is a keystroke; a rate limit is a different afternoon. So a waiting agent also carries a reason:

ReasonBadgeWhat it means
approvalApprovalA permission or approval selector is on screen — a tool approval, a y/n confirmation, a trust dialog. A specific choice is required, not free text.
errorErrorThe agent settled after a blocking error: an auth failure, a rate limit, a network error, a failed command. Typing at it may not unblock it.
questionQuestionThe agent asked a free-form question. Read it before answering — this is the one that most rewards actually looking.
promptAn empty input prompt is visible and nothing more specific was detected. It may just mean "ready for the next instruction".

Only the first three earn a specific label. prompt is the classifier's fallback — it means no positive evidence was found — so every surface renders it as plain "waiting for input" rather than claiming a certainty the classifier does not have.

The same vocabulary is used everywhere, so one agent reads as one signal:

  • The panel header chip carries the badge next to the state.
  • The waiting popover in the layout lists every waiting agent, each with its reason and how long it has been waiting.
  • Fleet pane badges and Pilot rows show it alongside the agent and branch.
  • OS notifications use the sentence form — "Claude is waiting for approval", "Codex asked a question", "Grok is blocked by an error". A grouped notification only names a reason when every agent in the group shares it; a mixed group falls back to the generic wording rather than overclaiming for any member.

When several agents wait at once they are ordered by how much a second of your attention buys: approval first (one keystroke unblocks it), then error (hard-blocked and burning wall clock), then question, then a bare prompt. Within a reason, the longest wait comes first.

How Detection Works

Two questions are answered separately: which agent is this, and what is it doing.

Which agent

An agent panel's runtime identity is resolved from the executable's image path in the process tree, not from its window title or its argv. That is a deliberate correction: agent CLIs rewrite both, so title-and-argv heuristics confidently reported the wrong agent. The detector also folds in evidence from commands you type into the shell, applies hysteresis before committing a change, and holds the last committed identity when its signals disagree — which is why the chrome does not flicker during a launch or an exit.

What it is doing

State comes from the PTY stream itself: output volume and temperature, per-agent output patterns for prompts, completions and approval dialogs, redraw structure for full-screen TUIs, and your own keystrokes. A settle window separates "the agent paused mid-thought" from "the agent is done and waiting", and the waiting reason is classified from the last dozen visible lines — wide enough to catch an approval dialog, whose question sits above its selector rows.

Where output goes silent but work continues — a compile, a test suite — process-tree CPU acts as a bounded backstop: it holds the current state rather than dropping to idle early. It never creates activity on its own, and it expires, so a genuinely wedged process cannot be held in "working" forever by a busy child.

Note
Why a state can lag. Detection is inference over a byte stream, not a callback from the agent. Transitions are debounced on purpose — a half-second of silence is not a completed task, and a spinner frame is not a new state — so a state can trail reality by a second or two, and an agent idling for a long time is polled at a slower cadence until it makes a sound. The state chip's tooltip reports the trigger that caused the last change (input, output, heuristic, AI classification, timeout, exit, activity, or title) along with a confidence score when the trigger is not a certain one, so you can see what the reading is based on.

Behaviors worth knowing

  • A crashed agent CLI reports as exited, not as a wait that never ends. Before this, a CLI that died mid-turn left its panel stuck on "waiting" — indistinguishable from an agent politely asking a question, and the worst possible lie for a triage list to tell.
  • Scrolling does not flip state to working. Wheeling through a mouse-reporting TUI sends input sequences to the process, which used to read as activity. Scrolling back through what an agent wrote is not the agent working, and no longer registers as it.
  • Directing clears itself. It is held by a short debounce while you type, released on Enter or Esc, and swept by a wall-clock guard so a backgrounded window cannot strand a panel in it.

The quiet Cue

"Working" is not one condition. An agent that has been working for forty minutes and printing steadily is healthy; an agent that has been working for forty minutes and silent for the last twelve is probably wedged. Both render identically as "working", which is exactly the case where a fleet view stops being useful.

So a working run that has produced no output for over ten minutes picks up a quiet 12m cue on its Pilot row, counting from the later of its last output and its entry into the current working stint. Anchoring on the stint rather than on output alone matters: a run resumed after waiting quietly for twenty minutes would otherwise be stamped "quiet 20m" before it had a chance to make a sound.

The cue is absent for a healthy busy agent. It appearing is the signal; it is never merely unknown.

Park and Snooze

State is what the agent is doing. Park and snooze are what you have decided about it, and they change how state is read without changing the state itself.

Park shelves a run you have already triaged. It drops into a quiet Parked band, stops counting as demand everywhere — group counts, chips, filters — and carries a note in your own words so the row explains itself when you come back to it. A park can be gated on another terminal: it releases itself, with a notification, the next time that terminal goes from busy to ready. Otherwise it holds until you lift it. The agent underneath keeps doing whatever it was doing.

Snooze defers a run that is not ready to be triaged yet: 15 minutes, 30 minutes, 6 hours, or unlimited. It withdraws the run's demand on you and nothing else — a snoozed working agent still counts as running, a snoozed completed agent is still completed. Any typed input clears it, which is why "unlimited" is a ceiling rather than "forever": most snoozes end because you came back and answered the agent. Snoozes are wall-clock, so a machine that sleeps through the window wakes with the snooze already over.

The two are separate because they end differently: a park ends on a gate or by hand, a snooze ends on a clock or on your keystrokes. Both are documented in full, with the demand bands and filters they feed, at Pilot.

Where States Surface

SurfaceWhat it uses state for
Panel header chipPer-panel icon and color, the waiting-reason badge, the activity headline, elapsed time, the change trigger and confidence, and session cost where the agent reports it.
Worktree cardsA state badge per card, showing the highest-priority state among that worktree's agents — working, then directing, waiting, completed, exited, idle.
Sidebar filtersThe quick filter bar segments worktrees into working, waiting, and finished; the full filter popover adds "has terminals", completed, and exited as separate session filters with live counts.
Waiting popoverEvery waiting agent across the window, reason-ranked, with jump-to and kill actions.
FleetPane state badges, including the waiting-reason badge, and the counts that say how much of the fleet wants something.
PilotCross-project demand bands, the Parked segment, project group chips, and the quiet cue.
NotificationsWaiting and completion notifications and their sounds, plus the title bar and dock badge counts, which clear when you focus the window.
Quit and powerOnly working agents trigger the quit confirmation and keep the system from suspending. Waiting and directing agents are paused, not in flight.
Memory managementWorking, waiting, and directing agents are protected from renderer eviction and project hibernation, so a background project cannot be reclaimed out from under a live run.

From state to demand band

Fleet and Pilot do not show raw states. They fold state, waiting reason, and your own park and snooze decisions into one band, so a row's label, its tone, and its sort order can never disagree:

  • Parked and Snoozed beat everything, including a blocked run. Parking is you saying "this does not need me until further notice"; an attention model that second-guesses that the moment something looks urgent is one you would have to keep re-checking.
  • Blocked — waiting with the error reason.
  • Waiting — waiting for any other reason.
  • Ready for review — completed and not yet acknowledged. Once the workspace's completion watermark has passed it, it becomes Finished and stops asking for anything.
  • Working (or Directing) — a live run, hued but making no demand.
  • Idle, or Exited for a run whose process has ended.

Blocked, Waiting, and Ready for review are the three demand bands. A fleet with none of them is a quiet fleet, and that is what the counts and chips report.

Keyboard navigation reads state too: there are bindings to jump to the next waiting agent in the current project, the next waiting agent anywhere, and the next working agent, so a fleet is navigable without touching the sidebar. See Keyboard Shortcuts.

Plugin-Contributed Agents

An agent registered by a plugin takes part in all of this. Output-volume detection works from the launch hint alone, so a plugin agent gets working, waiting, and completed states with no extra declaration. A plugin can also declare output patterns for its agent, which sharpen prompt and completion detection to the same standard as a built-in. Detection stays passive observation of the terminal stream — Daintree never modifies an agent's own configuration to get a better reading out of it.