Skip to content

Data Flow

When Claude Code fires an event, the hook system writes status to the filesystem:

Claude Code Event
Hook Script (notify.sh)
├── Reads stdin JSON for event metadata
│ (teammate_name, team_name, session_id, hook_event_name)
├── Determines target file: ~/.claude-sessions/<tmux_session>.json
├── Routes based on teammate presence:
│ ├── No teammate → Update main session status
│ └── Has teammate → Update team.agents[] entry
└── Writes JSON atomically
{
"tmux_session": "my-session",
"status": "working",
"message": "Implementing login feature",
"cwd": "/home/user/projects/app",
"timestamp": 1738972800,
"metrics": {
"started": 1738970000,
"tools": {"Read": 5, "Write": 3, "Bash": 2},
"recent_tools": ["Read", "Write", "Bash"]
},
"team": {
"name": "my-project",
"agents": [
{"name": "researcher", "status": "working", "timestamp": 1738972800}
]
}
}

The TUI runs multiple concurrent polling loops:

Timer tick
Read ~/.claude-sessions/*.json
Parse each JSON file → []session.Info
Cross-reference with `tmux list-sessions`
├── Remove entries with no matching tmux session
SortSessions()
├── Priority statuses first (waiting, permission)
├── Priority teammates next (agents needing attention)
└── Then by timestamp (most recent first)
Send sessionsMsg to Update
Re-render view
Session list updated / Timer tick
For each session with a CWD:
├── Check cache (5s TTL, 10s max age)
│ ├── Cache hit → skip
│ └── Cache miss ▼
Run git commands in CWD
├── git branch --show-current
├── git status --porcelain
├── git rev-list --count @{upstream}..HEAD
└── git log -1 --format="%h %s"
Send gitInfoMsg to Update
Session CWD
Convert to Claude project path
/home/user/project → -home-user-project
Find most recent .jsonl in ~/.claude/projects/<path>/
Parse JSONL for assistant messages with usage data
Aggregate: input_tokens + cache_read + cache_creation → total input
output_tokens → total output
Timer tick / Manual refresh
Discover .navi.yaml files
For each project config:
├── Check cache (configurable TTL)
│ ├── Cache hit → skip
│ └── Cache miss ▼
Execute provider script with args
Parse JSON output → ProviderResult
Send to Update → render task panel

The Bubble Tea Update function processes messages in priority order:

  1. Dialog mode — Route to dialog-specific handler
  2. Task panel focus — Route to task panel handler
  3. Preview focus — Route to preview handler
  4. Search mode — Route to search handler
  5. Main keybindings — Handle navigation, actions, toggles
  6. Async messages — Process polling results, command outputs