Skip to content

`cass search` misses sessions you know happened

Source: Troubleshooting reference

Symptom: history you remember from Codex or Cursor never surfaces, even on exact phrases, while Claude Code sessions from the same week come back fine.

Root cause: cass ingest is append-only per conversation. Once a conversation is in the canonical DB it is never re-read, so every parser improvement since it was first indexed only reaches new sessions. Old ones keep whatever subset the parser of the day extracted. cass index --full does not fix this — it forces a full scan and a lexical rebuild, then logs skipping historical salvage because canonical database is already populated.

Confirm — compare the DB against a fresh parse of the same files:

Terminal window
sqlite3 -readonly ~/.cass/agent_search.db \
"select a.name, count(m.id) from messages m
join conversations c on c.id=m.conversation_id
join agents a on a.id=c.agent_id group by 1 order by 2 desc;"
wc -l < ~/.codex/sessions/2026/*/*/rollout-*.jsonl # rough upper bound per file

Measured 2026-08-01: codex held 15,037 messages where the same 88 rollouts parse to 85,488 today, and cursor 3,384 vs 6,949 — 82% and 51% of that history unsearchable.

Fix, one connector at a time. Every step matters:

Terminal window
# 0. verify each source file still exists — forget is only safe if it can come back
sqlite3 -readonly ~/.cass/agent_search.db \
"select c.source_path from conversations c join agents a on a.id=c.agent_id
where a.name='codex';" | while read -r p; do [ -f "$p" ] || echo "MISSING: $p"; done
# 1. back up via sqlite, NOT cp — a plain copy can tear a live WAL
sqlite3 ~/.cass/agent_search.db ".backup '$HOME/.cass/agent_search.db.bak'"
# 2. drop the stale rows (dry-run first: omit --apply)
cass forget --source-glob "$HOME/.codex/sessions/**" --apply
# 3. reset the connector watermark — --full still honours it, and rollouts dated
# months ago never beat a watermark stamped today, so the scan finds nothing
sqlite3 ~/.cass/agent_search.db \
"update meta set value='0' where key='last_scan_ts:connector:codex';"
# 4. re-ingest, then clean up after a cass bug: forget leaks tail-state rows keyed
# by the deleted conversation_id, and that column is a plain rowid — SQLite
# reuses freed ids, so a future conversation would inherit a stale
# "ingested through idx N" marker and be silently truncated
cass index --full
sqlite3 ~/.cass/agent_search.db \
"delete from conversation_tail_state
where conversation_id not in (select id from conversations);"
# 5. rebuild vectors in bounded batches; repeat until the backlog is empty
bash ~/dotfiles/install/memory.sh semantic

Skipping step 3 is the usual failure — the run exits 0, having ingested nothing.