Allow hooks to set the terminal tab title

Resolved 💬 3 comments Opened May 6, 2026 by tommygents Closed May 6, 2026

Problem

Users running multiple concurrent Claude Code sessions (one per project, for
example) want to visually distinguish their terminal tabs by user-chosen
context — a Johnny Decimal project code, branch name, ticket ID, etc.

Claude Code's built-in title-setting auto-generates a topic summary from
conversation content, which works well much of the time but doesn't surface
context the user has explicitly attached to a session.

The existing CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 env var provides an
escape hatch to disable the built-in title-setting, but no replacement
mechanism. I tried wiring hooks (UserPromptSubmit, Stop, Notification,
SessionStart) that emit OSC 0 escape sequences directly. They fail for two
reasons:

  1. Hook subprocesses on Windows have no inherited console attached to

the parent terminal pane. \.\CONOUT$ opens succeed but write to a
detached console (verified empirically — writes return ok:true, no
visible effect, no cross-tab interference).

  1. ESC bytes in assistant output AND hook stdout are stripped by Claude

Code's display layer. This is correct defensive sanitization (otherwise
prompt injection could rewrite terminal state) — but it leaves no path
for a hook to emit OSC.

Proposal

Add a hook output field, e.g. {"setTerminalTitle": "<string>"}, that
Claude Code's privileged renderer translates into an OSC 0 sequence
emitted from the trusted path. Available on hook events where titles
are likely to change: UserPromptSubmit, Stop, Notification, SessionStart.

Example UserPromptSubmit hook output:

{
  "additionalContext": "...",
  "setTerminalTitle": "[14.10] working: way authoring"
}

The user retains full control over title content via their hook script;
Claude Code provides only the trusted emit path. Could optionally
auto-prepend or suppress when the built-in title-setter is also active,
or simply require CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 as a precondition
to take effect.

Workarounds

Currently no clean path. Out-of-band approaches that work mechanically:

  • PowerShell + AttachConsole(parent_pid) + SetConsoleTitle() — adds

~1-2s startup latency per hook fire.

  • Per-pane watcher daemon polling a side-channel file — heavyweight

multi-process architecture for a one-line feature.

Both are excessive for what could be a single hook-output field.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗