The client’s documents, turned into something the system can quote
Every engagement arrives with material: a brief pack, an audit, a vendor's API note, the notes from kick-off. Uploading them is what makes the difference between a generic Statement of Work and one about this project.
| Source | Type | Chunks | State |
|---|---|---|---|
| Client brief.docx | DOCX | 38 | Indexed |
| Existing platform audit.pdf | 126 | Indexed | |
| API limits — vendor note.md | Markdown | 12 | Indexed |
| Kick-off transcript.txt | Text | — | Processing |
What this gets you
Before the mechanics, the outcome: documents that reference what the client actually sent, and answers you can check.
Specific documents
Deliverables quote the client's own constraints instead of describing a generic project of that shape.
Checkable answers
The assistant names the sources behind an answer, so a claim can be verified rather than trusted.
Nothing re-read
Material uploaded once is available to every deliverable, and to everyone in the workspace.
Upload to grounded output
Seven steps, each of which leaves something you can inspect in the interface.
- 01Upload
PDF, DOCX, text, markdown
- 02Extract
Text pulled from the file
- 03Chunk
Split into overlapping windows
- 04Embed
Each window becomes a vector
- 05Store
Kept with its workspace and project
- 06Retrieve
Nearest passages for this run
- 07Ground
Fed to the model under a budget
- RESULTAnswers with sources
The assistant cites the documents it drew on, so a claim can be checked rather than trusted.
What can be uploaded
Text is extracted on arrival. A file that cannot be read — a scanned PDF with no text layer, a corrupt document — is still stored, with the reason recorded on it and a notification, rather than disappearing quietly into a failed queue.
Web research, when enabled for a run, is treated the same way: results are stored as sources in the project and indexed like an upload, so they are retrievable afterwards rather than being a one-off context injection.
How a passage is chosen
- Chunking
- Documents are split into overlapping windows, so a sentence spanning a boundary is not lost to both sides.
- Embedding
- Each window becomes a vector, stored in PostgreSQL with pgvector alongside the project.
- Similarity
- A generation or question is embedded and matched against the nearest windows by cosine distance.
- Budget
- Retrieved passages compete with the brief and dependencies for one shared context allowance.
- Reindexing
- Re-run extraction and embedding when a source is replaced or the chunking changes.
One client’s material cannot reach another’s document
Chunks carry their workspace, and the similarity search filters on it in the query itself. That is structural rather than conventional: the retrieval function requires a workspace argument, so a caller who forgets one fails to compile rather than quietly searching everything.
The same boundary applies to the assistant, to generation and to search. A project in another workspace is not simply invisible — it answers as though it does not exist.
Access is membership, never row ownership: a colleague in the same workspace reaches its projects, and a resource in another workspace answers 404 rather than 403 — a 403 would confirm it exists.
What happens when indexing fails
Retrieval is an enhancement. The rule throughout the product is that an enhancement degrades and says why, rather than taking the work down with it.
Embeddings unavailable
Retrieval returns nothing rather than falling back to an unscoped search across other workspaces.
A document fails
It is still stored, with the reason on the row and a notification, so it can be fixed and reindexed.
Nothing indexed yet
Generation still runs, grounded in the brief and dependencies, and the studio says plainly that sources are missing.
Upload one engagement’s documents and ask it something
The assistant with citations is the quickest way to see whether retrieval is finding what you would have found.