GuardRAG
A published RAG engine with guardrails that run in code
Stack
Frontend
- TypeScript
- Typed public API
- Browser client without credentials
- ESM + CJS builds
- Zero runtime dependencies
Backend & Data
- Node 18+, Deno, Bun and edge runtimes
- OpenAI, Gemini and OpenAI-compatible providers
- Pluggable vector stores behind one interface, in-memory by default
- Dense, keyword and hybrid retrieval
- Reciprocal-rank fusion
Problem
Most RAG code is welded to one provider, one vector store and one framework, with safety living in a prompt string anyone can talk past. I wanted a retrieval engine you could drop into any runtime, point at any provider, and trust to refuse a bad question before it reached the model.
What I built
- A framework-agnostic RAG pipeline published as a package — zero runtime dependencies, ESM and CJS, typed, running on Node 18+, Deno, Bun, edge runtimes and browsers.
- A provider layer covering OpenAI, Gemini and any OpenAI-compatible endpoint, so a local model and a hosted one are the same call.
- A store layer built on a single VectorStore interface, so a backing store is an adapter rather than a rewrite.
- Three retrieval modes: dense, keyword scoring that needs no API key at all, and hybrid with reciprocal-rank fusion.
- A guardrail set: content safety, prompt-injection defence, PII redaction, rate limiting, and a grounding gate that refuses off-topic questions before a model call is spent.
Technical decisions & trade-offs
- Guardrails execute as code, not prompt text. A grounding gate that returns a blocked result is a control-flow decision, not a request the model can be argued out of.
- Constructing a provider or store with an API key inside a browser throws, with no override flag. A convenience escape hatch eventually becomes someone else’s production leak.
- Zero runtime dependencies and nothing but fetch, so the SDK runs anywhere JavaScript does and the supply-chain surface stays at the standard library.
- Retrieval, providers and stores each sit behind an interface, so swapping strategy is a new file rather than a fork.
- Citations are structural: passages are numbered and the answer has to reference them, so an uncited claim is visible rather than plausible.
Challenges solved
- Making one pipeline behave identically across four provider shapes and four store backends without leaking provider-specific concepts into the public API.
- Getting keyword retrieval to work with no API key, so the package is usable — and testable — before anyone signs up for anything.
Outcome
Published under MIT. The guardrail and key-custody patterns are the same ones I hold production systems to; packaging them made the practice reusable instead of retold.