Run the CLI
Index a folder and ask a question — no browser, no server.
The CLI is the fastest way to prove the pipeline works. Take a folder, build a temporary brain, ask one question, print the answer with citations, delete the brain on the way out.
Run it
bun run cli examples/sample-brain "Why does LocalLens use QWEN3_1_7B_INST_Q4?"A successful run looks like this:
LocalLens uses QWEN3_1_7B_INST_Q4 because it offers a strong balance of answer
quality and local resource use [1]. A 600M fallback is wired in for slimmer
machines [2].
Sources:
- locallens.md#0
- qvac-notes.md#1The first run pauses for several seconds while the chat and embedding models load. Subsequent runs are much faster — the weights are cached.
What happens under the hood
src/cli.ts is intentionally short. Read it once and you've got the
whole workflow:
const app = new LocalLensApp();
let brain: Brain | undefined;
try {
brain = await app.createBrainFromFolder({
name: folderPath.split(/[\\/]/).filter(Boolean).at(-1) ?? "cli-brain",
folderPath,
});
const result = await app.askBrain(brain.id, question);
console.log(`\n${result.answer}\n`);
if (result.citations.length > 0) {
console.log("Sources:");
for (const citation of result.citations) {
console.log(`- ${citation.relativePath}#${citation.chunkIndex}`);
}
}
} finally {
if (brain) await app.deleteBrain(brain.id).catch(() => undefined);
await app.close();
}Three things to call out:
- The brain is deleted in
finally. The CLI is one-shot. It leaves no JSON entry behind. The browser path keeps brains around. That's the real difference between the two entry points. await app.close()matters. It tears QVAC down. Skip it and the model process can stick around in the background.- The brain name comes from the folder name. Just enough to keep the JSON store readable while the brain briefly exists.
Asking multiple questions
The CLI reindexes every time. If you want to fire several questions at the same folder, use the browser app. It keeps brains around between requests.
Errors you might see
Folder not found— the path you passed isn't a directory. Check spelling and that you're in the repo root.Choose a folder with supported text files— the folder exists but nothing inside it qualifies. Supported extensions live insrc/files.ts. Binary files and files over 2 MB are skipped.- A long pause followed by a model error — the 1.7B model failed to load. The gateway falls back to 600M automatically. If that also fails, you probably need more memory.