Local-first RAG web app that runs entirely in the browser, including embeddings, retrieval, local storage, and on-device model access once weights are cached.
@browser-ai/* packages for browser-native text, embedding, transcription, and model warmup flowsXenova/all-MiniLM-L6-v2 via @browser-ai/transformers-jsai, @ai-sdk/react)pg_trgm trigram searchInstall dependencies once from the repo root:
pnpm install
Start the app:
pnpm dev
Default URL: http://localhost:3000
pnpm dev — start the local dev server on port 3000pnpm build — create the production client buildpnpm serve — preview the production build locallypnpm test — run Vitest suitespnpm typecheck — run tsc --noEmitpnpm lint — run Biome lintingpnpm format — run Biome formattingpnpm check — run Biome checkspnpm db:generate — generate Drizzle migration outputAll document processing, embedding, storage, and retrieval run in the browser. After model weights are downloaded, the app is designed to continue working offline.
The production output is a static Vite build under dist/. Serve that directory from any static host that rewrites unknown application routes such as /chat and /documents to the app entry document so TanStack Router can handle navigation in the browser.
WebPDFLoader + RecursiveCharacterTextSplitterMarkdownTextSplitterchunkSize: 1000, chunkOverlap: 150Xenova/all-MiniLM-L6-v2 with 384 dimensionschunk_embeddingspg_trgmmixedbread-ai/mxbai-rerank-xsmall-v1More implementation detail lives in:
docs/chunking-impl.mddocs/embedding-impl.mddocs/retrieval-impl.mdUseful snippet to run in the browser DevTools console to delete the OPFS data used by PGlite:
(async () => {
const root = await navigator.storage.getDirectory();
try {
await root.removeEntry("local-rag", { recursive: true });
console.log("Database deleted successfully.");
} catch (e) {
console.log("Could not delete 'local-rag' directly. Deleting all OPFS entries...");
for await (const [name] of root.entries()) {
await root.removeEntry(name, { recursive: true });
console.log(`Deleted: ${name}`);
}
console.log("All OPFS data cleared.");
}
})();
If the OPFS directory name ever changes in src/workers/db.worker.ts or src/workers/blob.worker.ts, update the snippet to match.
283 commits
TypeScript
99.1%
Local-first RAG web app that runs entirely in the browser, including embeddings, retrieval, local storage, and on-device model access once weights are cached.
@browser-ai/* packages for browser-native text, embedding, transcription, and model warmup flowsXenova/all-MiniLM-L6-v2 via @browser-ai/transformers-jsai, @ai-sdk/react)pg_trgm trigram searchInstall dependencies once from the repo root:
pnpm install
Start the app:
pnpm dev
Default URL: http://localhost:3000
pnpm dev — start the local dev server on port 3000pnpm build — create the production client buildpnpm serve — preview the production build locallypnpm test — run Vitest suitespnpm typecheck — run tsc --noEmitpnpm lint — run Biome lintingpnpm format — run Biome formattingpnpm check — run Biome checkspnpm db:generate — generate Drizzle migration outputAll document processing, embedding, storage, and retrieval run in the browser. After model weights are downloaded, the app is designed to continue working offline.
The production output is a static Vite build under dist/. Serve that directory from any static host that rewrites unknown application routes such as /chat and /documents to the app entry document so TanStack Router can handle navigation in the browser.
WebPDFLoader + RecursiveCharacterTextSplitterMarkdownTextSplitterchunkSize: 1000, chunkOverlap: 150Xenova/all-MiniLM-L6-v2 with 384 dimensionschunk_embeddingspg_trgmmixedbread-ai/mxbai-rerank-xsmall-v1More implementation detail lives in:
docs/chunking-impl.mddocs/embedding-impl.mddocs/retrieval-impl.mdUseful snippet to run in the browser DevTools console to delete the OPFS data used by PGlite:
(async () => {
const root = await navigator.storage.getDirectory();
try {
await root.removeEntry("local-rag", { recursive: true });
console.log("Database deleted successfully.");
} catch (e) {
console.log("Could not delete 'local-rag' directly. Deleting all OPFS entries...");
for await (const [name] of root.entries()) {
await root.removeEntry(name, { recursive: true });
console.log(`Deleted: ${name}`);
}
console.log("All OPFS data cleared.");
}
})();
If the OPFS directory name ever changes in src/workers/db.worker.ts or src/workers/blob.worker.ts, update the snippet to match.
283 commits
TypeScript
99.1%