Navi 🧭

A floating macOS monitor for Claude Code sessions
See what every Claude Code session is doing across all your terminals — at a glance, from one floating window.
Installation
/plugin marketplace add Affirm/navi
/plugin install navi@navi
Hooks are registered automatically. Navi builds and launches itself the first time an event fires.
What You Get
| Feature | Description |
|---|
| Session status | Working (green), Idle (blue), needs attention (orange) at a glance |
| Inline permissions | Approve or deny tool permissions without switching terminals |
| Session discovery | Auto-detects running sessions by scanning ~/.claude/sessions/ |
| Jump to terminal | One-click focus the correct terminal tab for any session |
| Auto-dismiss | Stale permission cards clean up when approved in the terminal |
| Menu bar icon | Toggle the window; icon signals pending permissions |
| Per-event sounds | Configurable alerts for permission, completion, notification events |
| Multi-session | Monitor many concurrent Claude Code sessions side-by-side |
| Sub-agent tree | Nested Task tool agents shown as a live tree under their parent session |
| Context size bar | Mini colored progress bar on each session showing current input token usage |
| Context window alerts | Sticky info card when a session crosses configurable warning/critical thresholds, recommending /compact |
| Session row badges | Optional per-session badges for working folder, git branch/status, permission mode, model, context size, and open PR (each independently toggleable in Settings, all default off) |
Requirements
- macOS (tested on macOS 15+)
- Xcode Command Line Tools (
xcode-select --install)
- Python 3 (ships with macOS)
- Claude Code
Settings
Click the gear icon to open settings. The General tab covers auto-launch, sounds (per-event, any macOS system sound), display (font scale), and stable features like the menu bar icon, session names, permission details, and session row badges. The Experimental tab holds newer features: sub-agents, context size bar, and context window alerts with configurable warning/critical thresholds.
Manual Setup
If you'd rather not use the plugin system:
git clone https://github.com/Affirm/navi.git
cd navi
bash build.sh # Downloads + verifies the published Navi.app release
open Navi.app
Then register the hooks from hooks/hooks.json in your ~/.claude/settings.json, replacing ${CLAUDE_PLUGIN_ROOT} with the absolute path to this directory.
How It Works
Claude Code session
│
├── PreToolUse ────────→ pretooluse.sh ────────→ captures tool_use_id ──→ /tmp/navi/pretooluse/
├── PermissionRequest ─→ hook.sh → parse_event.py → event JSON ─────────→ /tmp/navi/events/
├── PostToolUse ───────→ hook.sh → parse_event.py → resolve signal ─────→ /tmp/navi/events/
├── Stop ──────────────→ hook.sh → parse_event.py → event JSON ─────────→ /tmp/navi/events/
├── StopFailure ───────→ hook.sh → parse_event.py → event JSON ─────────→ /tmp/navi/events/
├── Notification ──────→ hook.sh → parse_event.py → event JSON ─────────→ /tmp/navi/events/
└── PostToolUseFailure → hook.sh → parse_event.py → resolve signal ─────→ /tmp/navi/events/
~/.claude/sessions/*.json ──→ Navi session discovery (PID liveness + TTY lookup)
External producers ────────→ drop info event JSON ────────────────────────→ /tmp/navi/events/
Navi.app
├── polls /tmp/navi/events/ (instant via kqueue watcher + fallback timer)
├── discovers sessions from ~/.claude/sessions/
├── tracks Working/Idle/Dead status per session
├── EnrichmentService polls transcripts → git status, model, mode, context tokens
│ └─ context window alert ──────────────────────────────────────────→ injected directly
└── displays events in SwiftUI floating window + menu bar popover
│
User clicks Approve/Deny
│
writes response to /tmp/navi/responses/<event-id>
│
hook.sh reads response, returns decision to Claude Code
For permission requests, hook.sh writes an event file and polls for a response file. When you click Approve/Deny, Navi writes the response, the hook picks it up and returns the decision to Claude Code. If no response comes within 120 seconds, it falls back to the terminal prompt.