Cited clinical search in Postgres
The current core fuses Postgres full-text ranking with a deterministic development vector signal and returns source citations under practice/resource/purpose policy. It does not ship BM25, production semantic embeddings, reranking, or patient/consent filters yet; those are the target contract below.
You search the meaning, not the schema
“Find when this kid’s anxiety started spiking around school” is a clinical question, not a FHIR query. The current core indexes dedicated search_doc rows and cites each hit back to its canonical FHIR source record. Searching app-native projections is a target design, not the current implementation.
Current retrieval core
Postgres full-text relevance + a deterministic development vector, fused with reciprocal-rank fusion and cited to the source.
Dedicated search documents
Current search reads search_doc, with every hit linked back to its canonical resource. Clean app-projection search is target work.
Policy at retrieval
Current: practice/resource/purpose scope before retrieval. Target: patient assignment, consent, and minimum-necessary filtering per hit.
Cited to the source
Every result points back to the record it came from. No floating snippets, no “trust me” answers.
One Postgres. Vectors next to the data.
bonfireDB keeps vector signals in pgvector inside the same Postgres that holds the canonical record. The current signal is a deterministic development embedder; production clinical embeddings and reranking are not shipped yet.
Current: pgvector + deterministic development signal. Target: in-boundary semantic models.
const hits = await clinical.search.hybrid({ patientId, query: "worsening anxiety around school stress", citations: true }) // target contract: hits ABAC-scoped to this caller, // ranked by keyword + vector relevance, // each carrying a citation to its source record hits.map(h => ({ view: h.source.view, // notesByPatient | timeline | ... score: h.score, cite: h.source.recordId, // the record this came from snippet: h.snippet }))
The permission check is the query, not the prompt
Putting “only show records this clinician can see” in the system prompt is a hope, not a control. bonfireDB applies ABAC at retrieval — the search itself never returns a row the caller isn’t entitled to. The model only ever sees what it’s already allowed to see.
Search-then-filter-in-prompt
Index returns everything, the prompt is told to “be careful,” and one jailbreak or a sloppy chain leaks another patient’s record into the context window.
Filter-at-retrieval (target)
The target checks patient assignment, consent, purpose, and minimum necessary before a hit leaves Postgres. Current retrieval is practice/resource/purpose scoped.
The closest shipping thing is Google’s — and it’s sunsetting
Credit where it’s due: Google Agent Search for healthcare already ships FHIR-native semantic search today, and it’s a serious managed offering. The catch is that Google has announced its end of life for 2027-05-15 — so building your retrieval layer on it means building on a clock. bonfireDB makes a different bet: keep hybrid search in the same Postgres you already run, so retrieval isn’t a separate managed service that can be deprecated out from under you.
Agent Search for healthcare
FHIR-native semantic search, managed by Google — genuinely the closest shipping competitor. Announced end of life 2027-05-15. Re-verify the date and migration path against Google’s current docs before you commit.
bonfireDB
Current core: pgvector colocated with the canonical record, practice-scoped retrieval, cited hits, and a deterministic development vector. Production semantic embeddings and patient/consent scope are target work.
Target: a sidecar projection with explicit freshness
Search documents are a separate write path in the current core. The target unifies governed commits, projections, and async semantic indexing behind one receipt so callers can distinguish committed, pending, and fresh state.
Write commits
The target governed writer commits canonical FHIR and operational projections atomically.
Index lane picks it up
The async index lane embeds the new content into pgvector beside the data — heavy work, off the write path.
Freshness is reported
The write’s freshness object marks indexes.semanticSearch as pending → fresh, so you always know what’s searchable.
Every write tells you what’s searchable
No guessing whether the index caught up. The freshness lifecycle distinguishes what’s committed and queryable now from what’s still being indexed.
{
status: "committed",
views: {
notesByPatient: "fresh",
timeline: "fresh"
},
indexes: {
semanticSearch: "pending",
agentContext: "pending"
}
}
The same clean retrieval your agents run on
Search is one retrieval primitive underneath the AI layer. Current tools read cited search_doc hits; future agent tools can combine them with clean app projections and structured packets for exact Observations, medications, counts, or dates.
Agent context tools
Planned agent tools expose hybrid search and structured evidence packets as scoped, cited reads.
Agent context tools →App-native primitives
Target: search over the same typed projections the app reads, while preserving canonical citations.
App-native primitives →Fresh on commit
The freshness lifecycle that tells you what’s indexed and what’s pending.
Fresh on commit →Clinical authorization & audit
Current retrieval is practice/resource/purpose scoped; patient/consent policy and complete read-audit coverage are target work.
Clinical authorization →You build the app. Bonfire is the clinical data layer underneath.
Cited search documents in Postgres today; production semantics, patient/consent policy, clean-view retrieval, and unified freshness next.
Frequently asked questions
Do I need a separate vector DB for clinical notes?
No separate vector database is required: the current core stores its development vector signal in pgvector beside the canonical record. Production semantic embeddings and reranking are still target work.
How does bonfireDB do clinical RAG without leaking other patients' records?
Current search is practice/resource/purpose scoped before retrieval. Patient assignment, consent, and minimum-necessary filtering per hit are required target work before production use over real PHI.
Is this keyword search or vector search?
The current core fuses Postgres full-text relevance with a deterministic development vector signal and cites every hit. Production semantic embeddings, reranking, and BM25 are not shipped claims.
Does hybrid search run over raw FHIR® JSON?
The current core reads dedicated search_doc rows and cites canonical FHIR source records. Search over app-native projections is part of the target contract, not the current implementation.
How does the index stay fresh after I save a note?
Search documents currently have a separate write path. The target unified governed writer updates canonical FHIR and required projections atomically, then reports semantic indexing as pending until fresh.