The knowledge ingestion pipeline
How an uploaded document becomes searchable: stages, status values, and failure handling.
When a document is uploaded, whether to the operator Global Library or to an organization's Policy
Hub, it runs through a multi-stage pipeline that ends with embedded, searchable chunks. The pipeline
lives in @repo/ingestion, is driven by @repo/jobs, and is stored in the ingestionJob and
kbChunk tables.
Upload and registration
- The client requests a presigned upload URL and uploads the file directly to object storage.
- The server registers a
knowledgeDoc(statuspending) recording the storage key, MIME type, size, scope, and category. - An
ingestionJobis created in thequeuedstage and processing begins.
Stages
The job's stage column is the state machine. The happy path runs through:
kbChunk and committed.indexed.There are also two terminal failure stages:
- failed: processing exhausted its retries.
- dead_letter: an unrecoverable condition, such as the document being deleted mid-flight or its metadata being invalid.
The document's own status is a simpler view of this. It reads pending while in flight, indexed
on success, and failed once the job gives up.
Supported file types
| Type | MIME | Extraction |
|---|---|---|
application/pdf | Text extraction | |
| Word | …wordprocessingml.document | Raw text extraction |
| Excel | …spreadsheetml.sheet, application/vnd.ms-excel | Sheets converted to text, one per sheet |
An unsupported MIME type fails the parse stage with a clear error instead of producing empty content.
Embedding
Embeddings are generated through @repo/ai, which resolves a provider and model. By default this is
OpenRouter with a 1536-dimension model. In development only, you can use a local Ollama model by
setting EMBEDDING_PROVIDER=ollama while NODE_ENV is not production.
Chunks are embedded in batches with bounded concurrency. Safety guards cap the chunk count and total
bytes per document so one oversized upload can't run away. The embedding run is recorded in
aiUsageLog for cost tracking. The produced vector dimension is checked against the configured
dimension; a mismatch fails the job rather than corrupting the index.
Failure handling and retries
When a stage throws, the worker:
- Increments
attemptsand recordslastError. - If
attemptsis belowmaxAttempts(default 5), schedules a retry with exponential back-off and jitter, capped at roughly 15 minutes, vianextRunAt. Failures early in the pipeline retry fromqueued; failures during embedding or indexing retry fromembedding. - Once retries are exhausted, moves the job to
failed, or todead_letterfor unrecoverable conditions, and sets the document's status tofailed.
Some conditions skip retries and dead-letter immediately, for example a missing document, a missing storage key, or an embedding-dimension mismatch.
Health and observability
The pipeline exposes a health summary used by the operator Ingestion Health panel and the GP Knowledge settings:
| Metric | Meaning |
|---|---|
pending | Documents waiting to be indexed. |
processing | Jobs in an active stage. |
indexed | Documents fully indexed and searchable. |
failed | Documents whose ingestion gave up. |
An operator can retry failed jobs from the Command Center. See ingestion troubleshooting.
Replacing a document, in either the Policy Hub or the Global Library, is latest-wins: the previous version is marked superseded and dropped from retrieval, and the new file is re-ingested through the same pipeline.