Session Management
How sessions are tracked, matched, and managed throughout their lifecycle.
Session State Machine#
Every session progresses through a set of statuses driven by hook events:
SessionStart → idle (Robot idles at coffee lounge)
UserPromptSubmit → prompting (Robot walks to desk)
PreToolUse → working (Robot sits, charging effect)
PostToolUse → working (Stays working)
[timer expires] → approval (Visor flashes yellow)
PermissionRequest → approval (Direct signal, more reliable)
Stop → waiting (Robot goes to gym)
[2 min idle] → idle (Back to coffee lounge)
SessionEnd → ended (Offline animation)
Status Details#
| Status | Animation | 3D Behavior | |--------|-----------|-------------| | idle | Gentle bob | Seeks coffee lounge workstation | | prompting | Head tilt | Walks to desk in assigned room | | working | Charge effect, typing arms | Sits at desk, tool-specific animations | | waiting | Slow bounce | Seeks gym workstation | | approval | Visor flash, arm shake | Freezes in place | | input | Purple visor pulse | Freezes, arm raised | | ended | Dim, head drooped | Stays in last position |
Approval Detection#
Two mechanisms detect when an agent needs user approval:
Timeout Heuristic#
When PreToolUse fires, a category-based timer starts:
| Category | Tools | Timeout | |----------|-------|---------| | fast | Read, Write, Edit, Grep, Glob | 3 seconds | | userInput | AskUserQuestion, EnterPlanMode | 3 seconds | | medium | WebFetch, WebSearch | 15 seconds | | slow | Bash, Task | 8 seconds |
If PostToolUse doesn't arrive before the timeout, the session transitions to approval (or input for userInput tools).
For slow tools, a hasChildProcesses check runs first — if the process still has children, the command is still running and isn't waiting for approval.
PermissionRequest Signal#
At medium+ hook density, the PermissionRequest hook event fires when Claude actually asks for approval. This immediately overrides the timeout heuristic and is more reliable.
Session Matching#
When a hook event arrives with an unknown session_id, the matcher links it to the correct terminal session using a 5-priority fallback:
| Priority | Strategy | When Used |
|----------|----------|-----------|
| 0 | Pending resume + terminal ID | Session resume after disconnect |
| 1 | AGENT_MANAGER_TERMINAL_ID env var | SSH terminal with injected env |
| 2 | Working directory match | Claude starts in same dir as terminal |
| 3 | Path scan of connecting sessions | Multiple sessions, pick matching dir |
| 4 | PID parent check | Check if Claude is child of PTY |
If no match is found, a display-only card is created showing the detected source (VS Code, iTerm, Warp, etc.).
Team & Subagent Tracking#
When Claude spawns agent teams, the dashboard tracks parent-child relationships:
- Direct linking:
CLAUDE_CODE_PARENT_SESSION_IDenv var provides instant linkage - Path-based detection:
SubagentStarton parent + newSessionStartwithin 10 seconds from matching directory - Visual: Animated connection beams between parent and child robots
- Cleanup: Team is deleted 15 seconds after all members end
Session Resume#
When you resume a Claude session (claude --resume or claude --continue):
- A
pendingResumeentry is registered - The new
SessionStartevent is matched to the pending entry - The session is re-keyed: old data moves to
previousSessionshistory - Previous prompt history is accessible as collapsible sections in the detail panel
- Terminal reconnects automatically
Labels & Organization#
Sessions can be labeled for organization:
| Label | Behavior | |-------|----------| | ONEOFF | Completion alarm + shake effect | | HEAVY | Auto-pinned, urgentAlarm + electric frame on completion | | IMPORTANT | Auto-pinned, fanfare + liquid frame on completion | | Custom | Configurable per-label sound, movement, and frame effects |
Labels persist across session resume and are stored in both the server and IndexedDB.