feat(core): add search({ excludeSession }) and derive missing session titles - #17
Open
Cyb3rN8 wants to merge 1 commit into
Open
feat(core): add search({ excludeSession }) and derive missing session titles#17Cyb3rN8 wants to merge 1 commit into
Cyb3rN8 wants to merge 1 commit into
Conversation
… titles
Two things make a first-pass retrieval noisier than it needs to be.
Self-hits: searching history from inside a session almost always returns that
session's own prompt, because the query terms were taken from it. A script can
filter the rows afterwards, but `limit` has already been spent on them, so real
evidence from other sessions falls off the end. `excludeSession` accepts one ID
or an array and filters in SQL, before `limit` applies.
Missing titles: `overview()` and `sessions()` are advertised as a navigation
map, but on a current index most rows come back with `title: null`. Both upstream
sources are usually absent now — recent Claude Code versions rarely write an
`ai-title` transcript row, and `history.jsonl` entries no longer carry a `title`
field at all (they are prompt history: display/pastedContents/timestamp/project/
sessionId). On the index I checked, 792 of 821 Claude sessions had no title, so
`overview({ limit: 6 })` is six unlabelled IDs.
`overview()`, `sessions()`, and `search()` now fall back to the first 80
characters of the opening user message, skipping `<command-…>` envelopes so the
label is the task rather than the slash command's name. Sessions with no user
text still return null rather than an invented title. This is computed in the
query layer, so it also covers sessions that were indexed before this change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8 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.
Fixes the two behavioural items from #16. Documentation-only items from that issue are not included here.
search(text, { excludeSession })Searching history from inside a session reliably hits that session's own prompt, because the query terms came from it. Filtering afterwards in the query script does not recover the loss:
limitis applied in SQL, so the self-hits have already displaced evidence from other sessions.excludeSessionaccepts one session ID or an array and filters beforelimit.Derived session titles
overview()andsessions()are advertised as a navigation map, but on a current index most rows come back withtitle: null— 792 of 821 Claude sessions on the index I measured. Both title sources are usually absent now:ai-titletranscript rows have become rare (most recent one in a 264-transcript project directory: 2026-07-21), andhistory.jsonlentries no longer carry atitlefield at all, so thehistoryTitlespath inproviders/claude.tscannot populate. Neither is an indexing failure — every title that exists is picked up.overview(),sessions(), andsearch()now fall back to the first 80 characters of the opening user message, skipping<command-…>envelopes so the label describes the task instead of naming the slash command. A session with no user text keepstitle: nullrather than getting an invented one.Implemented as a SQL expression in the query layer (
titleExpr()), for two reasons: it covers sessions indexed before this change without a rebuild, and it leavessessions.titlemeaning "a title the transcript actually provided". The tradeoff is that a derived title is not distinguishable from a stored one in the returned row — the docs call it a navigation label. Happy to switch to a separate field, or to compute it at index time, if you would rather have the provenance explicit.Notes
skill-docchanges are limited to what documents the new behaviour: thesearch()opts list, anExclude Yourselfentry in the Retrieval Contract, thesessions()note about derived titles, and theapi-reference.mdrows. The broader documentation suggestions stay in First-pass retrieval wastes most of its budget: untitled sessions, self-hits, and known-empty memory recall #16.tests/query.test.mjs(SQL-level exclusion including thelimit: 1case, and the title fallback including the command-envelope skip and the null case). On this machinenpm testgoes from 207 passing to 209 with an unchanged set of 12 failures — all in the app/session suites, which need Electron deps that are not installed here.main, so this may touchapi-reference.mdnear feat(core): index failed tool results for retrieval #15. Say the word if you want it rebased onto either of the open branches instead.