This is a submission for the Sanity Challenge, Path One: Ship an Agent That Queries Real Content
What I Built
Research Dossier is a multi-agent research analyst built with LangGraph.
Instead of asking one model to answer a research question from its own knowledge, the system routes the question through four stages:
Research → Analysis → Writing → Review
The research stage is grounded in a Sanity Knowledge Base, queried directly via GROQ. Sanity Context wasn't yet enabled on my org during the build window, so the research agent's tool talks to Sanity's Content API directly rather than through the managed Context/MCP layer. The tool is isolated behind a single function, so swapping it for the Sanity Context MCP endpoint later is a contained change, not a rewrite of the agent's reasoning logic.
The interesting problem I wanted to solve is not simply finding information. It is handling situations where the sources themselves disagree.
When conflicting claims are found, Research Dossier does not silently merge them into one confident answer. It preserves the disagreement, shows the sources behind the claims, and marks the final report:
CONTESTED
The Problem
My Knowledge Base contains multiple pieces of evidence about LangGraph checkpoint deserialization.
One source is the LangGraph documentation itself, which implies checkpointing "just works" safely out of the box. Another is the official security advisory for CVE-2026-28277, which documents unsafe msgpack deserialization by default and describes strict-mode and allowlist-based hardening. A third source is a second advisory database's framing of the same CVE, which tempers the risk with essential context — it's classified as a defense-in-depth issue requiring an attacker to already have privileged write access, not a standalone remote exploit. A fourth is a community checkpointer implementation, which raises the separate question of whether that hardening even reliably extends to third-party backends.
The system keeps all of these claims and their provenance distinct, rather than flattening them into one answer.
That matters because a normal keyword search can find all of these pieces of information without preserving the relationships between them.
Research Dossier treats disagreement as structured information instead of noise.
Demo
Live app: https://multi-agent-research-analyst.vercel.app/
Try one of the built-in example questions, or ask:
Does LangGraph handle checkpoint deserialization safely by default?
Watch the case log as the system progresses through Research → Analysis → Writing → Review, with each step's output expandable if you want to see the full reasoning. Once a draft is ready, it enters a human-approval step — you can review or edit it before the case is closed and the final dossier is rendered. The report preserves the conflicting evidence and distinguishes stronger sources from lower-trust material instead of flattening everything into one conclusion, and stamps the report CONTESTED when sources disagreed.
You can also browse the raw Knowledge Base directly at /sources — every claim, its source, and what it contradicts, without needing to ask a question first.
Why Keyword Search Isn't Enough
A keyword search can return documentation, security advisories, and community discussions that mention checkpoint serialization.
The problem is that matching text does not tell the agent how those pieces of information relate to each other.
Research Dossier retrieves structured claims together with:
- their sources,
- source trust information,
- and relationships between claims.
That lets the analysis stage reason about disagreement rather than simply presenting a list of matching passages.
The result can be explicitly marked CONTESTED when the evidence remains in conflict.
How I Used Sanity
I modeled the Knowledge Base around three core document types:
topicsourceclaim
The key relationship is:
claim
└── contradicts → claim
This makes disagreement machine-readable. Instead of asking an LLM to infer whether two unrelated passages appear to disagree, the content model explicitly represents that relationship.
A claim also references its source, allowing the research pipeline to retain provenance while moving from retrieval to analysis to writing and review.
Retrieval Layer
The research agent's tool queries the Knowledge Base directly via GROQ, expanding topic, source, and contradicts[]->source in a single request:
LangGraph
│
▼
Research Agent
│
▼
GROQ query (@sanity/client)
│
▼
Sanity Knowledge Base
This retrieval layer is deliberately isolated behind a single tool function — swapping it for the Sanity Context MCP endpoint is a contained change, not a rewrite of the agent's reasoning logic.
Architecture
User Question
│
▼
┌──────────────┐
│ Research │
│ Agent │
└──────┬───────┘
│
▼
┌────────────────────┐
│ GROQ Query Layer │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ Sanity Knowledge │
│ Base │
│ │
│ claims + sources + │
│ contradictions │
└─────────┬──────────┘
│
▼
┌──────────────┐
│ Analysis │
└──────┬───────┘
▼
┌──────────────┐
│ Writing │
└──────┬───────┘
▼
┌──────────────┐
│ Review │
└──────┬───────┘
│
APPROVED / REVISE
│
▼
Human Approval / Edit
│
▼
Final Report
What Each Agent Does
Research
The research agent is responsible for retrieval. It queries the Sanity Knowledge Base directly via GROQ and is explicitly instructed not to rely on general knowledge alone. When contradictory evidence is retrieved, it keeps both sides and their sources.
Analysis
The analysis agent compares the retrieved claims. It considers source provenance, trust level, and recency, and distinguishes well-supported evidence from weaker or single-source claims.
Writing
The writing agent converts the analysis into a source-linked report. It is instructed not to introduce factual claims that were not present in the research findings.
Review
The review agent acts as a hallucination gate. It checks the draft against the original research findings. Unsupported claims trigger a revision pass instead of being silently accepted. The workflow allows bounded revision before producing the final report — which then goes to a human approval step before being marked closed.
Why Sanity?
The project could have been built as a conventional search application. That would miss the important part of the problem.
The Knowledge Base stores claims, sources, and relationships between claims. In particular, the contradicts relationship makes disagreement part of the data model.
That structure changes what the agent can do. It is not simply retrieving text that matches a query. It is retrieving structured knowledge that can be compared, traced back to sources, and carried through a multi-agent reasoning and review pipeline.
Example Sources
The checkpoint-deserialization investigation uses sources with different levels of authority, including:
- LangGraph checkpoint documentation
- LangGraph security advisory — CVE-2026-28277
- A second advisory database's framing of the same CVE, with mitigating context
- A community checkpointer implementation, stored in the Knowledge Base
The agent preserves those provenance differences rather than treating every retrieved claim as equally authoritative.
Sanity Project Details
Project ID: 4kagnnrl
Code
https://github.com/pratikdevelop/multi-agent-research-analyst
The repository contains the LangGraph agent, Sanity schemas, and the Next.js interface.
What I Wanted to Demonstrate
The interesting part of this project isn't simply that multiple agents can call a CMS.
It is that structured content can make disagreement explicit.
Instead of forcing conflicting evidence into one confident answer, the Knowledge Base preserves the claims and their relationships, the analysis stage compares them, the review stage checks that the final report remains grounded in the retrieved evidence, and a human gets the final say before the case closes.
Research Dossier doesn't try to make disagreement disappear. It makes disagreement visible.
Top comments (4)
it very useful
Its a very useful
Some comments may only be visible to logged-in visitors. Sign in to view all comments.