A Claude Code hook that updates your terminal tab title with the current session state, so you can tell at a glance which session is thinking, waiting on you, or done.
🔵 claude-hooks ← thinking / running tools
🔴 claude-hooks ← waiting for permission
🟢 claude-hooks ← done / idle
Running multiple Claude Code sessions in different tabs (or worktrees) means you constantly tab around to check which one needs your attention. clostty pushes that state into the tab title via OSC 2 escape sequences, so the terminal does it for you.
| Icon | Event(s) | Meaning |
|---|---|---|
| ◆ | SessionStart |
Session starting |
| 🔵 | UserPromptSubmit, PostToolUse |
Thinking / processing |
| ⚡ | PreToolUse Bash / BashOutput |
Running shell command |
| ◉ | PreToolUse Read / Glob / Grep / LS |
Reading or searching |
| ✎ | PreToolUse Edit / Write / MultiEdit |
Editing files |
| ⊜ | PreToolUse Task |
Spawning subagent |
| ◈ | PreToolUse WebFetch / WebSearch |
Web |
| ⚙ | PreToolUse (other) |
Other tool |
| 🔴 | PermissionRequest |
Waiting for your approval |
| 🟢 | Stop, SubagentStop, idle |
Finished |
clostty picks the tab name in this order:
- The session's
customTitlefrom the transcript JSONL (set by/rename) - The current git branch
- The basename of the working directory
cargo install --path .
clostty installclostty install writes the hook entries into ~/.claude/settings.json, pointing to wherever the binary lives (std::env::current_exe()). It registers handlers for: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PermissionRequest, PermissionDenied, Notification, Stop. Existing clostty entries are removed and re-added; other hooks in settings.json are preserved.
You'll also want to disable Claude Code's own terminal title management so it doesn't fight with clostty:
export CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1(Add this to your shell config.)
clostty uninstallRemoves any hook entries pointing at clostty.
clostty hook reads a single JSON object from stdin and writes the new title to /dev/tty. It expects fields from Claude Code's hook input schema:
hook_event_name— required, dispatches the icontool_name— used forPreToolUseto pick a tool-specific iconnotification_type— used forNotification(onlyidle_promptproduces output)transcript_path— read for the most recentcustom-titlelinecwd— used for git branch lookup and basename fallback
Unknown events and missing fields are silently ignored. Failure to open /dev/tty (e.g., when invoked outside a terminal) is also silent — no error, no exit code.
cargo test