docs-agent template, then customize the retrieval hook and
document sources.
Terminal
How RAG works
Veryfront splits a RAG app into three flows:- Ingestion: Upload or read documents, extract text, split text into chunks, and store those chunks.
- Search: Embed the user’s query and compare it with stored chunk embeddings.
- Generation: Add the best matching chunks to the AG-UI request before the agent responds.
docs-agent template wires these flows with ragStore(),
createUploadHandler(), useUploadsRegistry(), and createAgUiHandler().
Create the store
In your project root, create a shared RAG store:store.ts
ragStore() stores chunks and vectors in data/index.json.
When Veryfront Cloud bootstrap is present, it uses the Veryfront Cloud RAG
backend automatically.
Set contentDir: "knowledge" to index knowledge/ instead of content/.
Add upload routes
Create upload routes that share the same store:lib/upload-auth.ts
app/api/uploads/route.ts
POST ingests a file, GET lists ingested documents, and DELETE removes a
document. For local-only prototypes, pass
auth: { type: "none", allowUnauthenticated: true } to explicitly allow
unauthenticated upload routes.
The auth policy is required and fails closed. An authorize callback must
return the literal value true to permit a request; false or an accidental
missing return denies it with 401. Return a Response when the route needs a
custom denial or authentication-challenge response. Calling
createUploadHandler(store) without an explicit auth policy now fails when the
handler is created.
The handler bounds each source file to 10 MiB, the complete multipart body to
the file limit plus 64 KiB, and extracted UTF-8 text to 5 MiB by default. Set
maxFileSize, maxBodySize, or maxExtractedTextBytes only when your
deployment has a different, still-bounded budget. Invalid configuration fails
when the handler is created. Request cancellation is propagated through
multipart reading, extraction, and RAG ingestion.
GET /api/uploads?limit=25&offset=0 returns only upload-origin documents,
newest first:
maxListItems (100 by
default, at most 1,000). useUploadsRegistry() follows hasMore pages and
publishes the new server snapshot only after every bounded page validates.
DELETE accepts an id route parameter or query parameter and refuses to
delete documents that did not originate from the upload route. In Cloud mode,
a 502 means the RAG entry was removed but source blob cleanup is incomplete;
retry the same deletion safely.
Understand ingestion
Upload ingestion does three things:- Extracts text: Text, Markdown, and MDX are read directly. CSV files are
converted into row text with headers. PDF, DOCX, XLS, XLSX, PPTX, HTML, RTF,
EPUB, JSON, and XML use the
DocumentExtractorextension backed by@veryfront/ext-document-kreuzberg. - Chunks and embeds: Text is split with
chunkOptionsbefore embedding. Defaults aremaxChars: 2000,overlap: 200, andseparators: ["\n\n", "\n", " ", ""]. - Stores data: Cloud mode stores the original uploaded file as a source file
blob under
.veryfront/rag/uploads/. Local mode stores only the RAG index indata/index.json.
store.ingest(). Local mode fills embeddings on first search. Cloud
mode chunks and embeds during ingestion. When extraction behavior changes or an
uploaded document needs reprocessing, call
store.refreshDocument(id, text, meta) to keep the document ID while replacing
its chunks and embeddings.
Add bundled content ingestion
Use a separate ingestion route for files that ship with the app:app/api/ingest/route.ts
content/ change:
Terminal
indexContentDir() reads files from
contentDir and skips files that are already tracked by source. Uploaded
documents do not need this call because the upload route ingests them directly.
Add retrieval to the agent route
UsebeforeStream to retrieve context before the agent runs:
app/api/ag-ui/route.ts
Add the chat UI
Use the app-modeChat component with useUploadsRegistry() and
AttachmentsPanel:
app/page.tsx
docs-agent template includes a fuller upload panel. Use this smaller
example when you want the minimum wiring. Upload documents through the panel:
the RAG ingestion route returns document metadata, not the runtime-fetchable
url required by Chat.uploadApi. Composer attachments use a separate
createChatUploadHandler route when you want them stored durably.
Use Veryfront Cloud mode
Set Veryfront Cloud bootstrap variables before starting the app:Terminal
ragStore()uses the Veryfront Cloud RAG backend.- Generation uses Veryfront Cloud model routing.
- Embeddings use Veryfront Cloud embedding routing.
veryfront-cloud/openai/...andveryfront-cloud/google/...models route through AI Gateway.
veryfront-cloud/openai/text-embedding-3-small. Set
VERYFRONT_DEFAULT_EMBEDDING_MODEL to provider/model, such as
google/text-embedding-004; Cloud bootstrap routes it as
veryfront-cloud/google/text-embedding-004:
Terminal
Use raw Cloud APIs
Use raw Cloud APIs when you are building outside a Veryfront app or need direct control over indexing. The manual flow is:- Create or list RAG document records.
- Split source content into chunks.
- Generate vectors through AI Gateway or another embedding provider.
- Store vectors with the embeddings endpoint.
- Search with a query vector.
ragStore() unless you need that lower-level control.
Verify it worked
Runveryfront dev, open the app, and check these behaviors:
- Upload a document. The upload route returns success and the document appears in the upload list.
- Index bundled files with
/api/ingestafter changing files incontent/. - Ask a question that depends on the document. The response cites the document title.
- Ask an unrelated question. The response says the retrieved context does not contain a clear answer.
- In cloud mode, confirm API requests use
VERYFRONT_API_TOKENand the target project slug.
Next
- Build a chat UI: Add or customize the chat surface
- Providers: Configure model and embedding routing
- CLI knowledge ingestion: Turn files into project knowledge
Related
- veryfront/embedding: RAG store and upload helpers
- veryfront/agent: AG-UI route helpers
- veryfront/chat: Chat components and hooks