HybridDB 0.8.0 — one identity across the store
Chroma vectors are now keyed by the logical primary key, killing a whole bug class at the root: the TEXT-PK journal wedge and the repeated rowid→pk mapping bugs.
Release notes, HybridDB 0.8.0 (2026-09-03). This is also the first post in the “what shipped” series — every release gets one of these, tied to the changelog.
The change
Chroma vectors are now keyed by the logical primary key (str(pk)), not the physical rowid — one identity shared across SQLite, the DuckDB mirror, and Chroma:
- Per-collection identity marker (
hybriddb:identity: pk|rowid) in Chroma collection metadata. - New collections are pk-keyed from creation; pre-0.8 collections keep rowid keys until migrated — upgrading changes nothing until you opt in.
migrate_vector_identity(table=None)re-keys legacy collections by copying embeddings (never recomputed — asserted bit-identical) and deleting orphan rowid-keyed vectors; idempotent, covers all longtext collections, default rowid-alias tables are no-ops.
Why it matters
This deletes at the root a bug class we’d been chasing across three releases:
- The TEXT-PK journal wedge —
DuplicateIDErroron delete+reinsert (TEXT-PK tables reuse rowids, so delete-then-reinsert produced duplicate Chroma ids and permanently wedged the journal) - The repeated rowid→pk mapping bugs (0.5.4/0.5.5, and the CoreMem variants that inherited them)
- Read paths unified on pks: FTS keyword ids, vector ids, and row fetches all use the pk;
reconcileis scheme-aware
There’s a regression test for the delete+reinsert scenario, and the migration is copy-only — embeddings are never recomputed, so re-keying can’t silently change your semantics.
What came with it
0.7.0 (last month) shipped metadata pre-filtering — where= pushes scalar-column filters into the Chroma scan before the vector query — and made DuckDB mirrors lazy (tables you never query with olap cost nothing). Operator-form filters are now enforced in keyword mode too, and versioned-table rollback got the batched-path treatment (~20× removal-heavy, ~37× update-heavy at 100k rows). Full detail: the changelog.
Using it
pip install hybriddb -U
db = HybridDB("./data") # new collections: pk-keyed automatically
db.migrate_vector_identity() # legacy collections: opt in, idempotent
db.verify_chain("memories") # versioned tables unchanged
Docs: API reference · Concepts. Benchmarks and methodology: the stack post.