Request trace
Two flow diagrams — one through the CLI, one through the browser.
The clearest way to see how the eight files interact is to trace a single question through both entry points.
CLI question trace
CLI question
→ cli.ts (parse argv, instantiate LocalLensApp)
→ locallens.ts (createBrainFromFolder)
→ files.ts (discoverTextDocuments)
→ rag.ts (chunkDocuments → ragChunk)
→ qvac.ts (ingestChunks → ragIngest)
→ store.ts (saveBrain, saveChunks)
→ locallens.ts (askBrain)
→ qvac.ts (search → ragSearch)
→ rag.ts (buildGroundedHistory)
→ qvac.ts (answer → completion stream)
→ locallens.ts (assemble ChatAnswer)
→ cli.ts (print answer + sources, deleteBrain, close)Two things to notice:
- The trace fans out from
locallens.tsinto the gateways and comes back. Every internal-to-internal call routes through the workflow class. domain.tsdoesn't appear in the trace. That's by design. Types don't participate in the runtime — they only constrain it.
Browser question trace
Browser question
→ ui/app.js (event handler, fetch POST /api/brains/:id/chat)
→ server.ts (route match, JSON parse)
→ locallens.ts (askBrain)
→ qvac.ts (search)
→ rag.ts (buildGroundedHistory)
→ qvac.ts (answer)
→ locallens.ts (assemble ChatAnswer)
→ server.ts (JSON serialize, write response)
→ ui/app.js (render markdown, append to chat thread)The browser trace is the CLI trace plus an HTTP hop on each end.
Once the request reaches locallens.ts, the path is identical to
the CLI path.
Why this shape matters
Three properties fall out of one workflow class with thin entry points:
- One place to add a feature.
LocalLensApp.askBrainis the single answer-the-question method. The CLI and the browser both benefit the moment you add to it. - Stable error surface. Errors flow up through
LocalLensApp, reachcli.tsorserver.tsasAppErroror genericError, and get formatted by one helper at the edge. - Easy to test.
LocalLensAppcan be unit-tested without spinning up a server or shell. The store swaps out for a temp-directory variant; the QVAC gateway can be stubbed.
Where it would break
If a feature needed a different workflow on the browser path
than on the CLI path, the symmetry would crack. The right move
then is to add a new method on LocalLensApp (or a new helper
that consumes it), not to push logic into server.ts. Keep the
entry points thin.