feat: auto-name claude sessions with haiku titler#5
Merged
Conversation
Adds `server/services/session-titler.js` and `server/services/title-prompt.js`. The titler watches `~/.claude/projects/**/*.jsonl`, waits for 60s of idle per file, reads the first two non-system user messages, and asks Haiku for a 3-5 word title stored in the existing `session_names.custom_name` column. On boot it backfills any JSONL that has no custom name. Writes trigger the existing projects watcher via a blank-line append, so the sidebar updates live without touching server/index.js beyond a future single import line. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- server/index.js: single-line import of session-titler service so it self-starts at boot (matches the "no other edits" rule for churn files). - server/database/db.js: applyCustomSessionNames now marks Claude sessions without a custom_name with pendingTitle=true so the UI can flag them. - server/services/session-titler.js: prefer @anthropic-ai/sdk directly when an ANTHROPIC_API_KEY is available (env or settings.json); fall back to the Claude Agent SDK's query() for OAuth-only environments. - SidebarSessionItem.tsx: render the session name with the `.shimmer` Midnight utility class while pendingTitle is true; aria-busy for SR. - types/app.ts: add optional pendingTitle?: boolean to ProjectSession. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When both the direct Anthropic SDK and the Claude Agent SDK fail to produce a result (no key, offline, rate limited, ...), treat the title as unresolved and leave `pendingTitle=true` so the next boot or network recovery picks the session back up. Previously we wrote 'Untitled' which poisoned the cache. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
17 tasks
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.
Summary
~/.claude/projects/**/*.jsonl, waits 60 s of idle per file, asks Haiku for a 3-5 word title, stores in the existingsession_names.custom_namecolumn..shimmerMidnight utility on the title whilependingTitleis true (aria-busy for screen readers).Changes
server/services/session-titler.js— new worker: chokidar watcher + serial queue + debounced Haiku call. Prefers the direct@anthropic-ai/sdkwhen anANTHROPIC_API_KEYis available (env or~/.claude/settings.json), falls back to@anthropic-ai/claude-agent-sdk'squery()for OAuth-only boots. If both paths fail, skips saving so pending state resumes later.server/services/title-prompt.js— prompt template (adapted from open-webui) plusextractFirstUserTextsandnormalizeTitlehelpers that mirror the system-message filter inprojects.js.server/index.js— singleimport './services/session-titler.js';line, self-starts on import. No other edits.server/database/db.js—applyCustomSessionNamesnow tags Claude sessions withpendingTitle(true when no custom row, false when resolved).src/components/sidebar/view/subcomponents/SidebarSessionItem.tsx— adds the shimmer class +aria-busywhensession.pendingTitle === true(mobile + desktop paths).src/types/app.ts— addpendingTitle?: booleantoProjectSession.Acceptance criteria (phase-3 brief)
server/projects.jsorSidebarProjectItem.tsx; single import line inserver/index.jsnpm run buildsucceeds.shimmerutility comes frommidnight.cssTest results
npm run build— pass (client + server)npm run typecheck— passnpm run lint— pass on changed files (pre-existing warnings only)normalizeTitle/extractFirstUserTexts— all assertions passstop()daac4fb)🤖 Generated with Claude Code