Recipe: FAQ bot with hot reload of source

Build a Q&A chatbot that ingests Markdown files and reloads answers live when you edit the source — no rebuild, no restart.

What you'll build

A single-page chatbot backed by a local Markdown knowledge base. Edit any .md file, hit save, and the bot picks up the change instantly via a file-watch loop. Answers stay grounded — no hallucination.

Stack

  • Next.js 14 App Router (server + client)
  • OpenAI chat completions (gpt-4o-mini)
  • chokidar for file watching
  • In-memory vector store (no Pinecone / Weaviate)
  • Tailwind CSS

Architecture

pages/
  api/chat/route.ts    ← POST handler, RAG pipeline
  page.tsx             ← chat UI
lib/
  store.ts             ← in-memory doc store + watcher
  embed.ts             ← embedding helper
data/
  faq/                 ← your .md files live here

Step 1 — In-memory store with hot reload

On server start, glob data/faq/*.md, chunk each file by ## headings, embed with text-embedding-3-small, and store in a Map<string, Chunk[]>. A chokidar watcher re-indexes changed files on the fly.

Step 2 — RAG route handler

POST /api/chat accepts{ question: string }, embeds the question, runs cosine similarity against the store, picks the top 3 chunks, and sends them as context to the LLM with a strict system prompt: “Answer only from the provided context. If unsure, say you don't know.”

Step 3 — Chat UI

A minimal client component with a text input and message list. Messages stream via fetch +ReadableStream for token-by-token rendering. No websockets needed.

Why hot reload matters

Traditional RAG pipelines require a re-index step on every content change. With chokidar and an in-memory store, your bot stays in sync with your docs automatically. Edit a Markdown file, save, and the next question uses the updated content — zero friction for non-technical content editors.

Pro tip: Keep the store in a module-level variable so it survives HMR across route handler invocations. Use aglobalThisguard to avoid re-init on every hot reload in dev.