[BUG] Session title permanently blank after /clear — UserPromptSubmit workaround defeated by unchanged-title no-op (follow-on to #67389)

Open 💬 1 comment Opened Jun 15, 2026 by syd3n

Summary

After /clear, the session title bar goes blank and never returns — not on the next prompt, and not after a full claude -c resume — even though a UserPromptSubmit hook emits the correct sessionTitle. The title can only be restored by emitting a different value, which proves the apply path is being short-circuited by the unchanged-title no-op while /clear leaves the cached title (and on-disk customTitle) intact.

This is the follow-on to #67389 (SessionStart clear discards sessionTitle). #67389 documents that the UserPromptSubmit path is "the workaround" for /clear — but in 2.1.x that workaround does not actually work, for the reasons below.

Environment

  • CLI: 2.1.177 (also observed on 2.1.173)
  • OS: macOS (darwin 25.5.0)
  • Area: hooks / session title

Minimal repro

  1. Add a UserPromptSubmit hook that always sets a fixed title:

``jsonc
// ~/.claude/settings.json
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"sessionTitle\":\"MyTitle\"}}'" }]}]
``

  1. Start a session, submit a prompt → title bar shows MyTitle. ✅
  2. Run /clear → title bar goes blank (expected per #67389; clear-source emit is discarded).
  3. Submit another prompt → the hook emits MyTitle again, but the title bar stays blank. ❌
  4. /exit, then claude -c to resume → title bar still blank, despite customTitle: "MyTitle" being present on the first line of the session .jsonl. ❌
  5. Temporarily change the hook to emit a different value (e.g. MyTitle X) and submit a prompt → title bar renders MyTitle X. ✅ → confirms the apply path works and the only blocker in step 4 is the equal-value no-op.

Expected

After /clear, the first UserPromptSubmit that emits a sessionTitle should re-render the title bar (and/or claude -c should rehydrate the title bar from the persisted customTitle).

Actual

The title bar is permanently blank for the life of the conversation once /clear is used, unless the hook emits a value that differs from the previously-applied title.

Root cause (from the bundled build; minified names are build-specific)

Three interacting behaviors:

  1. clear-source discard (#67389): ... = source === "startup" || source === "resume" ? title : void 0 — the SessionStart emit on /clear is dropped.
  2. Unchanged-title no-op, with a stale cache across /clear: the apply/cache paths early-return when the sanitized emit equals the current cached title:

``js
let _ = sanitize(incoming); if (!_) return;
let cur = currentTitle(); // resolves to the cached title / customTitle
if (_ === (cur && sanitize(cur))) return; // no-op
// ... "Hook sessionTitle applied (N chars)" / "... cached (N chars)"
`
/clear blanks the **rendered** title but does **not** reset this cached "current" title. So re-emitting the same (correct) title from UserPromptSubmit` matches the cache and no-ops → the bar stays blank.

  1. Resume doesn't rehydrate the bar from customTitle: claude -c resumes the session (whose first .jsonl record still has customTitle: "MyTitle") but does not render the bar from it, and resume isn't honored by the SessionStart path for hooks either.

Net: there is no value a hook can emit that both (a) differs from the cache (to pass the no-op) and (b) is visually identical to the intended title — so no clean hook workaround exists. A zero-width-suffix trick renders once, then becomes the cache and re-sticks on the next /clear.

Suggested fix (any one breaks the deadlock)

  • On /clear, reset the cached "current" title (and ideally re-render the bar from customTitle), so a subsequent equal-value emit applies; or
  • Have claude -c rehydrate the title bar from the persisted customTitle; or
  • Honor sessionTitle for SessionStart source clear (the #67389 ask), which would make the bar correct immediately without relying on the no-op'd re-emit.

Evidence

Verified empirically with a hook that logs its input + decision: post-/clear UserPromptSubmit received session_title: "<derived>" and emitted "<derived>", yet the bar stayed blank; emitting "<derived> __TEST" rendered immediately. customTitle on disk remained "<derived>" throughout. Inspected the 2.1.177 binary for the source-filter and no-op branches quoted above.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗