The context layer
that shows its work.
Hand RedHop your documents and a question. It pulls just the sections that matter, hands them to your LLM, and explains every decision — with citations back to the source.
import redhop
doc = redhop.Document.from_file("contract.pdf")
ctx = doc.context("What is the governing law?")
ctx.text() # prompt, ready for any LLM
ctx.citations # sources, cited to the page
ctx.report # what it kept, and whyconst { Document } = require("redhop");
const doc = Document.fromFile("contract.pdf");
const ctx = doc.context("What is the governing law?");
ctx.text; // prompt, ready for any LLM
ctx.citations; // sources, cited to the page
ctx.report; // what it kept, and whyuse redhop::read_file;
let mut doc = read_file("contract.pdf")?;
let ctx = doc.context("What is the governing law?")?;
ctx.text(); // prompt, ready for any LLM
ctx.citations; // sources, cited to the page
ctx.report; // what it kept, and whyA short, fixed pipeline
you bring the documents · RedHop owns chunking, retrieval, allocationno services to run · nothing to wire · a whole PDF parsed, chunked & indexed in a millisecond or two
Three calls do the work
load → ask → read · each returns a plain object you hand to any LLMPoint at a file or folder
doc = Document.from_file("contract.pdf") A whole PDF is parsed, chunked and indexed in a millisecond or two.
from_folder handles a directory the same way.
Send a question
ctx = doc.context("…governing law?") Retrieval, token-budgeting and the assembly decision all happen in-process. No service to call.
Use the result
ctx.text() # prompt
ctx.citations # sources
ctx.report # decision One context object carries the prompt, the per-chunk citations, and the Decision Report.
What a query matches on
start lexical · climb only when the words don't line upBM25 matches words. For keyword-dense documents — contracts, specs, API references, logs — the words in the question are usually the words in the answer, so it needs no model at all. When a query shares no vocabulary with its answer, you climb a tier.
A pure-synonym query is exactly when you reach past lexical. RedHop tells you which tier found the hit — on the Decision Report.
RedHop holds the whole corpus in memory and scores it directly — no ANN index, no vector database. That's a scoped choice, not a claim that vectors are obsolete: at millions of chunks, an ANN-scale stack is the right tool. RedHop is the focused context layer for a corpus that fits in memory.
It shows its work
every answer ships a Decision Report — what was kept, dropped, and why{
"kept": 3, "dropped": 41, "budget": "1024 tok",
"chunks": [
{ "id": 17, "score": 8.41, "cite": "p.12 §14.2",
"why": "kept · top BM25 · 'governing law'" },
{ "id": 9, "score": 5.02, "cite": "p.12 §14.1",
"why": "kept · adjacent · bridge passage" }
],
"dropped_sample": [{ "id": 31,
"why": "over budget after gold kept" }]
}The same report drives evaluation — no LLM judge, the same engine as runtime, milliseconds per query. So you can see why a chunk made the cut, and measure when a change helps.
Tune retrieval, measure the lift
numbers are workload-shaped · measured on the same report · check yoursA reproducible, audited workflow — not a retrieval-engine win: the same Stripper applied to LlamaIndex lifts it to 94%. Every rewrite stage lands on the Decision Report as an audit trail.
RedHop vs LangChain vs LlamaIndex
same contract.pdf, same answer — count what you stand upimport redhop
from openai import OpenAI
q = "What is the governing law?"
ctx = redhop.Document.from_file("contract.pdf").context(q)
# parsed, chunked, retrieved, token-budgeted — internally
OpenAI().chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"{ctx.text()}\n\nQ: {q}"}],
)stand up: nothing parse · chunk · retrieve · token-budget all internal — and every call hands back a Decision Report.
- PyMuPDF loader
- text splitter (
chunk_size/overlap) - embedding model
- FAISS vector store
- a retriever
- prompt + retrieval chain
six wired pieces · embeddings cost a call per chunk
- PyMuPDF reader
- sentence splitter
- vector index
- query engine
cleaner than LangChain — still an embed-and-index pipeline you own and pay for
Same answer, without an index to build, embed, or persist. The full head-to-head covers retrieval quality too — and where a dense-first stack wins.
Where RedHop fits
honest positioning · the wins are measured and workload-shaped- You want three small calls (
load → ask → read) instead of a framework - You need a Decision Report and per-rewrite audit trail — regulated or debugging-heavy contexts
- You're doing multi-hop reasoning where the bridge passage matters
- Your corpus fits in memory
- Your team ships in Python, Node or Rust and wants one engine, defaults and reports in each
- You have millions of chunks and need ANN-scale search infrastructure
- Your queries share almost no vocabulary with your documents — a dense-first vector stack fits better
- You want a broad connector and agent ecosystem rather than a focused context layer
- You want a managed or hosted offering — RedHop is library-only
Apples-to-apples with the same bge-small. On MuSiQue LangChain still leads narrowly (39% vs 34%). CUAD reaches 90.7% with the Stripper + Vocabulary recipe, but the same Stripper lifts LlamaIndex to 94% — a reproducible, audited workflow, not a retrieval-engine win. RedHop's hybrid tier is currently 2–5× slower than the competitors' hybrid, a known open item. We have not measured against dense-only services at scale. Full head-to-head →
Grounded, cited answers — and a report that says exactly what the engine kept, and why.