fix(claude): preserve native titles and add a remote fallback#1080
Open
techotaku39 wants to merge 2 commits into
Open
fix(claude): preserve native titles and add a remote fallback#1080techotaku39 wants to merge 2 commits into
techotaku39 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Findings
- [Major] Fallback titles can leak into the chat timeline and overwrite a real title — the new fallback path calls
sendClaudeSessionMessage, which emits a normalmessagebefore updating metadata. Web currently normalizessummaryoutputs into visibleagent-eventblocks (web/src/chat/normalizeAgent.ts:455,web/src/chat/reducerTimeline.ts:840), so nativeai-title/first-message fallback titles become transcript events instead of metadata-only updates. The title guard is also evaluated beforeApiSessionClient.updateMetadata()enters its async lock/ack path (cli/src/api/apiSession.ts:907), so a concurrentchange_titlewrite that has not acked yet can still be overwritten by the fallback. Evidence:cli/src/claude/utils/sessionTitleFallback.ts:23,cli/src/claude/claudeLocalLauncher.ts:25.
Suggested fix:Then route bothexport function applySessionTitleFallback( client: Pick<ApiSessionClient, 'updateMetadata'>, message: string ): boolean { const title = createSessionTitleFallback(message) if (!title) return false client.updateMetadata((metadata) => { if (metadata.name?.trim() || metadata.summary?.text.trim()) return metadata return { ...metadata, summary: { text: title, updatedAt: Date.now() } } }) return true }
ai-titleand nativesummaryfallback handling through that metadata-only helper instead ofsendClaudeSessionMessage().
Questions
- None.
Summary
- Review mode: initial
- One Major issue found: the title fallback uses the chat-message path, so it can create visible title events and race with explicit title writes. Residual risk: I did not run the test suite because this review must not execute PR code.
Testing
- Not run (automation)
HAPI Bot
There was a problem hiding this comment.
Findings
- No issues found at >=80% confidence in the added/modified lines.
Questions
- None.
Summary
- Review mode: follow-up after new commits
- Previous Major finding appears addressed: title fallback now writes through
updateMetadata()and the guard runs inside the metadata updater. Residual risk: I did not execute PR code/tests, so runtime verification depends on CI and the contributor's reported targeted tests.
Testing
- Not run (automation)
HAPI Bot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Title
Summary
ai-titlemetadata for local interactive sessionssummaryevents as a fallback without overriding an existing titlechange_titletoolProblem
Claude sessions could remain named after their working directory in HAPI even after the first task completed.
The two Claude launch paths fail differently:
{"type":"ai-title","aiTitle":"..."}, but HAPI's transcript schema and scanner did not recognize those records.ai-titlerecords, and the model does not always follow HAPI's prompt to callchange_title.As a result, local sessions could discard an available native title, while remote sessions had no deterministic fallback at all.
Changes
Local Claude sessions
ai-titlerecords inRawJSONLinesSchemaai-titlerecords stable scanner keysai-titlemetadata into HAPI's existing summary-title updatesummaryrecordsRemote Claude sessions
metadata.namenormetadata.summary, normalize that message and store it as a fallback title/clear,/compact, and/plancommand handlingPrecedence
The change does not replace:
metadata.namemetadata.summary, including a successfulchange_titlecallThis also closes the race where a title tool call succeeds during the first turn: the remote fallback checks the latest local metadata before writing.
Scope
This PR restores native AI-generated titles where Claude Code provides them and prevents untitled remote sessions from staying on the directory fallback.
It intentionally does not add periodic topic detection, automatic retitling after later turns, or extra model calls. Those behaviors have separate cost, lifecycle, and configuration considerations.
Testing
bun typecheckbun run test:clibun run test:webbun run test:sharedclaudeRemote.test.tsclaudeRemoteLauncher.test.tsclaudeLocalLauncher.test.tstypes.test.tssessionScanner.test.tssessionTitleFallback.test.tsai-titleformat verified from local Claude Code sessionsbun run test:hubcurrently reports 487 passing tests and 7 unrelated Windows failures in the existing Cursor ACP verification/migration tests. This PR does not modify Hub or Cursor code.