feat(claude): sync Claude Code session title to HAPI web UI#394
feat(claude): sync Claude Code session title to HAPI web UI#394koenzhao wants to merge 1 commit intotiann:mainfrom
Conversation
Intercept `custom-title` events from Claude Code's JSONL session files and update HAPI session metadata.name, so /rename in Claude Code automatically reflects in the HAPI web UI. - Add onTitleChange callback to session scanner - Detect custom-title events in readSessionLog before schema validation - Apply latest title on session startup from JSONL history - Emit title changes during live scanning (within 3s poll interval)
There was a problem hiding this comment.
Findings
- [Major] Pending-session title events can overwrite the active session title.
findSessionFiles()still scanspendingSessionsduring Claude session rollover, andparseSessionFile()now forwards everycustom-titleit sees. A late rename written to the previous JSONL file can therefore replacemetadata.namefor the new active Claude session. Evidencecli/src/claude/utils/sessionScanner.ts:104,cli/src/claude/utils/sessionScanner.ts:123.
Summary
Review mode: initial
1 finding. Static review only. Residual risk: the new title-sync path has no regression coverage for startup hydration or session rollover in cli/src/claude/utils/sessionScanner.test.ts:41.
Testing
Not run (automation; bun is not installed in this runner).
HAPI Bot
| } | ||
| const { events, totalLines } = await readSessionLog(filePath, cursor); | ||
| const { events, titleChanges, totalLines } = await readSessionLog(filePath, cursor); | ||
| for (const title of titleChanges) { |
There was a problem hiding this comment.
[MAJOR] This applies custom-title updates from every scanned file, not just the current Claude session. During /clear or resume, findSessionFiles() still includes pendingSessions, so a late rename in the previous JSONL file can overwrite metadata.name for the new active session.
Suggested fix:
const { events, titleChanges, totalLines } = await readSessionLog(filePath, cursor)
if (sessionId === this.currentSessionId) {
for (const title of titleChanges) {
logger.debug(`[SESSION_SCANNER] Title change: ${title}`)
this.onTitleChange?.(title)
}
}|
Clean and focused change. The title sync from Claude Code's JSONL log is a nice addition. One issue: pending session title events can overwrite the active session title.
Suggested fix: only fire |
Summary
custom-titleevents from Claude Code's JSONL session files and update HAPI sessionmetadata.name/renamein Claude Code, the title automatically syncs to the HAPI web UI within ~3 secondsMotivation
Currently, HAPI relies on its own
mcp__hapi__change_titleMCP tool (via system prompt injection) to set session titles. This means Claude Code's native/renamecommand has no effect on the HAPI web UI — they are two separate naming systems.This PR makes Claude Code the single source of truth for session titles by reading
custom-titleevents directly from the JSONL files.Changes
cli/src/claude/utils/sessionScanner.ts— AddedonTitleChangecallback;readSessionLognow detectscustom-titleevents before Zod schema validation and returns them separatelycli/src/claude/claudeLocalLauncher.ts— WiresonTitleChangetosession.client.updateMetadatato setmetadata.nameTest plan
hapi claude, verify session appears in web UI/rename my-sessionin Claude Code, verify title updates in web UI within ~3s