Chronos/DBWaitlist

Build

Vectors and search

pgvector columns and HNSW indexes, Postgres full-text search, and ranked text search over a table.

SoonThese pages describe Chronos Cloud, which opens from the waitlist. Running Chronos yourself? Self-host docs

Vectors (pgvector)

Bring your own embeddings. Chronos speaks pgvector: vector(n) columns, the distance operators, and HNSW indexes, so code written for pgvector (LangChain, LlamaIndex, Mem0, your own) runs as it is. CREATE EXTENSION vector is accepted; it’s built in.

SQL
create table docs (id bigint primary key, tenant int, body text, embedding vector(1536));create index on docs using hnsw (embedding vector_cosine_ops);select id, body, embedding <=> $1 as distancefrom docs where tenant = $2order by embedding <=> $1limit 5;
OperatorDistanceIndex opclass
<=>cosinevector_cosine_ops
<->Euclidean (L2)vector_l2_ops
<#>negative inner productvector_ip_ops

Every vector in a column has the column’s dimensions; a vector of another length is 22000. Normalize embeddings if you want cosine and inner product to agree.

Indexes and recall

  • Small tables, or narrow filters, are compared exactly: every candidate, full precision.
  • Larger ones scan 1-bit codes of every vector on the free cores, then rescore the best at full precision: on 76,000 real 1,536-dimension embeddings that finds 99.98% of the true top 10 in about 0.6 ms.
  • Past that, the HNSW graph is used once it has tested itself (99% or better of the scan’s top 10 on its own vectors); a weaker graph waits until the scan would cost more. Recall comes first.
  • SET hnsw.ef_search = 200 widens the graph’s beam for more recall at some speed.
  • Graphs build in the background the first time they’re needed; no query waits for one.

With filters

Filter in SQL as usual: where tenant = $2 is applied first, so a filter keeping a few thousand rows is searched exactly. Index the columns you filter on (create index on docs (tenant)).

Full-text search

Postgres’s full-text search works as in Postgres: its parser, stop words and Snowball stemmer for english and simple, checked word for word against Postgres.

SQL
create index on docs using gin (to_tsvector('english', body));select id, ts_rank(to_tsvector('english', body), q) as rankfrom docs, websearch_to_tsquery('english', 'refund "late delivery" -test') qwhere to_tsvector('english', body) @@ qorder by rank desc limit 10;

to_tsvector, to_tsquery, plainto_tsquery, phraseto_tsquery, websearch_to_tsquery, @@, ts_rank, setweight, and tsvector columns work. The index’s expression must match the query’s, config included. Not yet: ts_headline, ts_rank_cd.

Ranked search: search()

Chronos also keeps its own text index per table: BM25 over every text field, with typo tolerance (a word one edit away matches at half weight). Use it as a table in FROM:

SQL
select d.title, s.scorefrom search('docs', 'billing eror', 10) s       -- the typo still finds "error"join docs d on d.id::text = s.idorder by s.score desc;

It returns id, score and row (jsonb), best first, on the session’s world. Words under 4 letters and over 32 aren’t corrected, and exact spellings always rank first.

Fuzzy matching

pg_trgm, fuzzystrmatch and unaccent are built in: similarity, %, word_similarity, the trigram distances, levenshtein, soundex, metaphone, unaccent. A gin or gist index with gin_trgm_ops serves %, LIKE and ILIKE.

SQL
create index on customers using gin (name gin_trgm_ops);select name from customers where name % 'jon smyth' order by similarity(name, 'jon smyth') desc limit 5;

Search in worlds

A world sees its own changes in search the moment they’re written. Indexes are shared between worlds, so a fork searches about as fast as main: an agent can re-embed a table in a world and compare results before merging.

From an agent

The find tool

MCP’s find takes where (exact filters), text (BM25), and vector with vector_field (dot product), and fuses text and vector rankings when both are given. Most agents use the sql tool with the pgvector queries above instead.

Vectors and search · Chronos