Skip to content
View as .md

Thread search

Full-text search over prior thread history in one house. Use it: arbe search "token revocation" --house <id> [-n 20] [--json], POST /api/threads/search, JS client.searchThreads(query, houseId), or the bot tool search_threads. A hit is a thread id and name, the thread’s last-updated time, a rank, an opaque offset range, and a match-centered snippet (matched words wrapped in « ») — enough to decide relevance without a second lookup. Snippets are empty for chunks indexed before they stored source text; backfill by replay restores them.

Indexing is a projection of the stream, not a second source of truth: every searchable append fires a throttled, best-effort catch-up (packages/core/thread-recency.ts) that replays new stream batches into thread_search_chunks via a watermarked, idempotent RPC (packages/core/search-index.ts). Chunks are bounded at 500 entries / 100KB and store their source text for snippet extraction. The whole index can be dropped and rebuilt by replay (packages/core/scripts/backfill-thread-search-index.ts).

Querying is websearch_to_tsquery against a simple (unstemmed, so revokeApiKey stays findable) tsvector, ranked by ts_rank plus a flat boost when the thread title matches, with only the best chunk per thread returned and a ts_headline snippet extracted from the chunk’s stored source text (packages/core/thread-search.ts). Consequences: no kind or author filter, because a chunk blends entries; a phrase spanning a chunk boundary may not match; archived threads surface deliberately.

Surfaces: apps/cli/src/commands/search.ts, apps/www/src/routes/api/threads/search/+server.ts (membership guard on top of RLS), packages/core/dispatch/thread-search-tools.ts. SQL lives in migrations 20260823210000_thread_search_chunks.sql (table, catch_up_thread_search_chunk), 20260824001000_thread_search_read.sql (search_thread_chunks), 20260830130000_thread_search_headlines.sql (stored chunk source text, thread name/date/snippet hits, title boost), and 20260830131500_thread_search_title_only_matches.sql (title-only matches pass the gate). The DB contract is proved by packages/supabase/tests/verify-thread-search-headlines.sql.

See threads for what is being indexed, streams for the append it projects from, and the CLI, HTTP API, and SDK for search operations.