DOCS / AGENT PLUGINS
Live workspace status
This is the reference behind the status discs: which hook event produces which state, why “waiting” means the agent needs you, and why “done” waits for background sub-agents to finish. Useful when a status looks wrong and you want to know what Birch was told.
Status reporting requires the birch-status plugin; how the discs fit into the wider AI feature set is covered in AI in Birch.
How status reaches Birch
Section titled “How status reaches Birch”Each hook pipes its JSON payload to birch agent-event, which relays it to a running Birch app over a local named pipe (see CLI utility commands). The payload’s working directory is matched to the registered worktree it lives in, so the right workspace row lights up no matter where the agent runs — including sessions you started outside Birch, from any terminal or editor. An event whose directory doesn’t belong to a worktree Birch tracks is ignored.
Event reference — Claude Code
Section titled “Event reference — Claude Code”| Claude Code hook | birch agent-event | Workspace state |
|---|---|---|
SessionStart | --event started | Ready — muted dot, “Ready for your input” |
UserPromptSubmit | --event working | Working — spinner |
PreToolUse / PostToolUse | --event working | Working — spinner |
Notification (needs input / permission) | --event waiting | Waiting — amber alert + desktop notification + Inbox row with sound |
SubagentStart / SubagentStop | --event subagent-started / subagent-stopped | (bookkeeping only — no visible change) |
Stop (turn finished) | --event idle | Done ✓ — unless background sub-agents are still running |
SessionEnd | --event ended | Done ✓ — session over |
The PreToolUse / PostToolUse hooks are what clear the waiting state: after you answer a permission prompt or an in-turn question, the agent resumes work without a new prompt, so its next tool call is what flips the indicator back to working.
When several sessions run in one worktree, the row shows the most urgent one: Waiting outranks Working, which outranks Done — and Ready ranks below Done, so a second tab idling at its prompt can’t hide a finished turn’s checkmark.
Codex differences
Section titled “Codex differences”The Codex plugin wires the same lifecycle, but its hook set swaps some of Claude Code’s entries rather than adding to them:
- There is no
Notificationhook —PermissionRequest→--event waitingreplaces it: Codex is asking for a permission. - Its only
PreToolUsehook is the one matching therequest_user_inputtool →--event waiting— Codex is asking you a question. There is no genericPreToolUse→ working entry; working is signalled byUserPromptSubmitandPostToolUseonly.
A following PostToolUse flips the state back to working after you respond. Every Codex hook command carries --agent codex, so Birch knows the source regardless of payload shape, and each hook has a 3-second timeout (Claude Code’s hooks use 5 seconds).
Ready is not working
Section titled “Ready is not working”SessionStart produces a distinct fourth state: ready. It means the session is up and listening — nothing more. For a resumed or reopened workspace it is the only event that arrives until you type, so Birch shows a muted “Ready for your input” dot rather than a spinner that would never stop. Ready never triggers a notification, an Inbox row, or a sound — but the agent process is real, so a ready workspace still counts as active when Birch warns you about closing the app.
Interrupting a turn
Section titled “Interrupting a turn”Pressing Esc or Ctrl+C to stop an agent mid-turn — or to dismiss a permission prompt or question — puts the workspace back to Ready, instead of leaving the spinner (or the amber bell and its Inbox row) up until your next prompt. An interrupted turn is not a finished one, so it gets no checkmark, sound, toast, or Inbox row. How Birch learns about it depends on the agent:
- Claude Code and Codex run no hook when you interrupt them. Instead, Birch notices a lone Esc or Ctrl+C typed into the agent’s Birch terminal tab and, while that session is working or waiting, reads the agent’s own log for up to about two seconds: Claude Code’s transcript must end in its “[Request interrupted by user” note, Codex’s session log in an aborted turn. Only then does the status change — if the log says nothing, or a hook has already moved the session on, it stays as it was.
- OpenCode reports the interrupt itself: version 0.3.0 of its status plugin marks the turn as interrupted. An older copy reports an Esc as a finished turn, with a checkmark and a beep — Birch offers the plugin update once at startup, and Settings → Status integrations has an Update button.
Birch only sees the key in its own terminal tabs: an agent running in an external terminal keeps its status until its next hook. Both log formats are undocumented, so if a future Claude Code or Codex changes them you get the old behavior — the spinner stays until your next prompt — never a false Ready.
Waiting means the agent needs you
Section titled “Waiting means the agent needs you”Waiting is the one state that actively interrupts: the amber indicator on the workspace row and rail, a desktop notification (gated on the desktop-notification toggle in Settings → General), an Inbox row with a sound, and a spot on the dashboard’s needs-attention list. Nothing else fires those — a workspace being opened, a turn finishing, or a sub-agent completing never beeps.
Done waits for background sub-agents
Section titled “Done waits for background sub-agents”When the main agent dispatches background sub-agents, it stops while they run — so the Stop hook fires mid-task. To avoid flashing a premature “done ✓” (and ringing the completion sound), Birch reads the background-task list Claude Code sends with every Stop:
- Only sub-agent and workflow tasks that are still running or pending count. A background shell task — a dev server you left running — never keeps the workspace out of “done”.
- A
Stopreporting sub-agents still running is shown as working, not done. Only the finalStop, once every sub-agent has finished, marks the turn complete. - Older Claude Code versions whose
Stoppayload lacks that list fall back to per-sessionSubagentStart/SubagentStopcounting: a suppressed “done” is remembered and promoted once the pending set empties — never a spinner stuck forever. - A sub-agent finishing on its own never notifies or beeps.
Fail-safe by design
Section titled “Fail-safe by design”The hooks are built so that Birch can never disturb your agent:
- Every hook carries an explicit timeout — 5 seconds for Claude Code, 3 seconds for Codex. The agent CLI waits for hooks to exit before continuing (Claude Code’s own default hook timeout is 10 minutes), so the explicit cap is what keeps a misbehaving relay from ever stalling a session.
birch agent-eventcaps its pipe call at 500 ms, always exits 0, and never touches Birch’s database — it has nothing slow to do.- If Birch is not running, the command exits silently in well under a second. A missing or closed Birch is a no-op for the agent.
Stale-status cleanup
Section titled “Stale-status cleanup”SessionEnd only fires on a clean quit — a crashed or killed agent, or a closed terminal tab, would otherwise strand a spinner or an amber alert forever. So when the last terminal tab of a workspace exits, Birch retires that workspace’s live indicator and its Inbox row. A finished turn keeps its checkmark.
Two related behaviors:
- Entering a workspace acknowledges a finished turn’s indicator — a live agent keeps its status.
- An agent you launched in an external terminal for the same worktree loses its indicator when the workspace’s embedded tabs close; it reappears on the agent’s next hook event.