Status Detection
How fleet knows what every session is doing.
fleet uses Claude Code hooks as its primary status source, with a structural pane-scrape fallback. The result: real-time status without polling.
The states
| Icon | State | Meaning |
|---|---|---|
| ● | running | Claude is processing |
| ◐ | waiting | A prompt needs your input |
| ● | finished | Claude completed; awaiting next prompt |
| ○ | idle | At the prompt, no activity |
| ✕ | error | Session died |
| ○ | starting | Spawning |
How hooks work
On first launch, fleet writes entries into ~/.claude/settings.json that point Claude Code's hooks at fleet hook-handler. Each hook writes a JSON status file to ~/.config/fleet/hooks/<session_id>.json.
The handler reads FLEET_INSTANCE_ID from the environment to know which session it belongs to.
Hooks fleet listens to
UserPromptSubmit— captures the prompt text (for auto-naming)Notification/Stop/SubagentStop— driverunning/waiting/finishedtransitionsSessionStart— captures Claude'ssession_idso we canclaude --resumeit on restart
A background HookWatcher goroutine reads the status files and feeds the session model.
Pane fallback
Hooks don't fire for sub-agents in agent-team mode, so fleet also does a structural pane capture:
- Menu prompts:
❯ 1.+2.+Esc to cancelon the visible pane - Team box:
│+Waiting for team leadat line start (box-drawing characters)
Pane detection uses structural checks (not text patterns) to avoid false positives from code or scrollback. Spinner characters on "waiting for" lines are skipped to dodge the animated team-box spinner.
Key invariants
- Hooks are authoritative.
hook=runningis never overridden towaitingby the pane scraper. - Stale waiting hook: if the pane shows the idle prompt, fleet downgrades to
finished(and preservesidleif you've already acknowledged it — prevents oscillation). - All blocking I/O (tmux, git, gh) runs in a background worker; the Bubble Tea
Update()loop is never blocked.
Debugging
Status detection logs to ~/.config/fleet/debug.log (via slog). Press ! in the TUI to open the bug-report dialog, which captures the last 100 lines.