Client-side Retrieval-Augmented Generation in the browser. transformers.js embeddings in the browser. Zero server. Three lines of code. (C++23 → WebAssembly coming in v0.2)
Load tRAGar as an ES module. No build step required — serve from any static host or use the CDN URL from GitHub Pages.
// Via GitHub Pages CDN
import { TRAGar } from 'https://charly-vibes.github.io/tRAGar/dist/js/tragar.js';
Or serve the file yourself. The bundle has a single peer dependency
(@xenova/transformers) that it loads on first use via dynamic import.
Three calls: create, ingest, query.
import { TRAGar } from 'https://charly-vibes.github.io/tRAGar/dist/js/tragar.js';
// 1. Create an instance (model loads on first ingest)
const rag = await TRAGar.create({
store: TRAGar.stores.memory(),
embedder: TRAGar.embedders.transformers(),
});
// 2. Ingest a document (chunk → embed → store)
await rag.ingest({ source: 'readme', text: yourMarkdownText });
// 3. Query the corpus
const hits = await rag.query('what is tRAGar?');
hits.forEach(h => console.log(h.score, h.text));
// Always close when done
await rag.close();
TRAGar.create(config) returns a TRAGarInstance —
a handle to one corpus (namespace). All operations (ingest,
query, stats, close) go through it.
Call close() when done to release file handles.
ingest({ source, text, meta? }) chunks the text into paragraphs,
embeds each chunk, and writes to the store.
source is a stable identifier (a path or URL) used to attribute hits.
meta is stored with each chunk and reserved for future filtering — it
is not yet surfaced on query results.
query(text, { k? }) returns the top-k chunks ranked by
cosine similarity. Use queryStream() for an async iterator
that yields hits in descending score order.
Each instance operates on its own namespace (default: "default").
Create multiple instances with different namespace values to keep
corpora isolated.
Choose where vectors and chunks are persisted.
| Store | Description | Persists across reloads? |
|---|---|---|
TRAGar.stores.memory() |
In-memory only. Fast, ephemeral. Good for testing and single-session use. | No |
TRAGar.stores.opfs() |
Origin Private File System (IndexedDB fallback). Chunks survive page reloads.
Emits a StoreFallback warning when IndexedDB is used. |
Yes |
// Persistent — chunks survive page reloads
const rag = await TRAGar.create({
store: TRAGar.stores.opfs(),
embedder: TRAGar.embedders.transformers(),
namespace: 'my-corpus',
onWarn: (code, msg) => console.warn(code, msg),
});
Embedders convert text chunks into float32 vectors. The embedder is loaded
lazily on the first ingest() call.
| Embedder | Description | Default model |
|---|---|---|
TRAGar.embedders.transformers() |
Lazy-loads a transformers.js model. No network call until first ingest. Model is cached in the browser after the first download. | Xenova/all-MiniLM-L6-v2 (dim 384, ~23 MB) |
TRAGar.embedders.custom(fn, dim) |
Bring your own embedder. Good for testing or swapping models. | — |
// Custom model
const rag = await TRAGar.create({
store: TRAGar.stores.memory(),
embedder: TRAGar.embedders.transformers(
'Xenova/all-MiniLM-L12-v2',
384
),
});
// Custom embedder function
const myEmbedder = TRAGar.embedders.custom(
async (batch) => batch.map(() => new Float32Array(128)),
128,
'my-test-embedder',
);
queryStream() returns an async iterator that yields hits in descending
score order. Break early without consuming all results.
for await (const hit of rag.queryStream('search term', { k: 5 })) {
console.log(`[${hit.score.toFixed(3)}] ${hit.text.slice(0, 80)}`);
if (hit.score < 0.3) break; // stop when relevance drops
}
All errors reject with a TRAGarError that has a typed code property.
import { TRAGar, TRAGarError } from './tragar.js';
try {
await rag.ingest(doc);
} catch (err) {
if (err instanceof TRAGarError) {
console.error(err.code, err.message); // e.g. "EmbedderLoadFailed"
}
}
| Code | When |
|---|---|
InstanceClosed | Method called after close() |
InvalidConfig | Bad namespace, unsupported config option |
EmbedderLoadFailed | transformers.js model or module failed to load |
SchemaTooNew | Persisted schema version exceeds library support |
SchemaTooOld | Persisted schema has no migration path |
NamespaceLocked | Another tab holds the namespace lock |