Grounded document intelligence

Answers your auditor can check, line by line.

FactSpectra is retrieval-augmented generation (RAG) with the failure mode removed. It reads your documents and answers questions about them — but every assertion carries a quote, and every quote is checked against the source in code before you see it. When the documents don't contain the answer, it says so instead of inventing one.

Demo runs against the public NIST Cybersecurity Framework 2.0. Ask for access.


The system

What it is, in one picture.

A user asks; the API layer starts a run; the pipeline researches, drafts, verifies every quote in code, criticises what survives, and stops for a human before anything is published. Indexing happens offline, locally, and never on the request path.

User UI API Agentic layer Data layer

See the full architecture → — every layer, the offline ingest path, and the one outbound dependency.

The problem

“Cites its sources” is a request. It isn’t a guarantee.

Ask any competent model to answer from a document and cite its sources and it will do exactly that — including, sometimes, for a sentence that isn't in the document. The citation looks identical either way. A page number, a quotation mark, a confident tone.

That is survivable when the output is a summary. It is not survivable when a human has to sign the output and an auditor may read it later: a regulatory filing, a due-diligence memo, a customer security questionnaire. In those documents a plausible wrong answer is worse than no answer, because someone acts on it.

The distinction that matters

Asking a model to quote its source is a request it can decline silently. Checking the quote against the source in software is a fact. FactSpectra does the second one, and discards anything that fails.

The mechanism

The model proposes. Deterministic code disposes.

Every claim arrives with the exact text it came from and the chunk it was attributed to. Before anything reaches a human, that quote is matched character-for-character against the stored source. A quote that doesn't resolve isn't a weaker claim — it is discarded, and if nothing survives, the answer becomes unsupported.

Research Draft Verify Critic Human sign-off Report

Green is deterministic code, not a model. Red is where a person signs.

The check costs microseconds, needs no second model call, and cannot be talked out of its answer. See the full pipeline →

From a real run

What it looks like when it works.

A question the corpus cannot answer — deliberately adjacent to material that is in there, which is exactly the setup that produces a confident wrong answer:

“What is our organization's incident response SLA, in hours?” The model ran four searches and retrieved 12 relevant-looking passages.
“The passages describe NIST CSF 2.0 outcomes for incident management, response, and recovery, but contain no information about any organization-specific incident response service-level agreement or timeframe in hours.” Verdict: unsupported. Zero claims made.

Retrieval succeeded. Twelve plausible passages were sitting right there. The system declined anyway — which is the behaviour you are actually buying.

Two different failures, two different checks.

Quote isn’t in the source

Caught by deterministic verification. A substring match against the stored document text. No model involved, so nothing to persuade.

Software

Quote is real but doesn’t support the claim

Caught by a separate critic pass. In one run it flagged a quote truncated mid-sentence at “and those that focus” — genuine text, but it never established what the claim said it did.

Model

Collapsing these into one “fact-checking” step would replace a guarantee with a probability. They stay separate.

Built for the place the documents actually live.

Runs in your environment

One Docker Compose file, one database. Deploy it inside your VPC and your documents never leave your account.

Local embeddings by default

Documents are indexed by a model running in your container, not sent to a third-party embedding API.

Every run is auditable

Searches run, passages retrieved, quotes rejected, who approved it and when — retrievable as a record, not a log line.

Built on

No proprietary black box underneath.

Everything here is inspectable, and deliberately boring where boring works. The interesting part is the verification discipline, not an exotic stack.

LayerWhat we useWhy
OrchestrationLangGraph A checkpointed state machine, so a run can pause for a human and resume hours later in another process.
ReasoningClaude (Anthropic) Structured outputs, so claims and quotes arrive as data rather than prose to be parsed.
RetrievalHybrid RAG — pgvector + Postgres full-text, fused by RRF Vectors catch the paraphrase; keyword search catches the exact control identifier. Neither alone is enough.
EmbeddingsONNX, in your container Indexing a confidential document does not transmit it to a third party.
StoragePostgreSQL 17 + pgvector Vectors, keyword index, checkpoints and audit records in one database your team already knows.
APIFastAPI, containerised One Compose file. Runs on a laptop or inside your VPC unchanged.