The reasoning trace
Why did it find that? Walk a real multi-hop query hop by hop — the trace is the proof that Rekall reasons, and explainability vector search structurally cannot offer.
The trace is the product. It's not debug output — it's the receipt that shows Rekall
followed a chain of reasoning to its answer. Turn it on with return_trace: true
(--trace on the CLI); it costs almost nothing.
A real multi-hop query
Over the demo corpus (contracts + policies), ask a question that cannot be answered by similarity — it requires reading one document, then finding the conflicting clause in another:
rekall search "which supplier contract conflicts with the 2026 policy?" \
--store demo --trace● 2 passages · 2 hops · confidence 0.87 · 4.2 ms
1. supplier_a.pdf score 0.92 hop 1
"…Supplier A payment terms are net-90 as amended in §4.2…"
2. policy_2026.md score 0.81 hop 2
"…all supplier payment terms must not exceed net-60…"
reasoning trace
hop 1 → supplier_a.pdf (matches query)
hop 2 → policy_2026.md (conflict found, given hop 1)
✓ sufficient — stopped after 2 of 4 max hopsconst r = await store.search(
"which supplier contract conflicts with the 2026 policy?",
{ trace: true },
);
console.log(r.trace);[
{ hop: 1, docId: 'supplier_a', why: 'matches query' },
{ hop: 2, docId: 'policy_2026', why: 'conflict found, given hop 1' }
]r = store.search(
"which supplier contract conflicts with the 2026 policy?",
trace=True,
)
print(r.trace)[TraceStep(hop=1, doc_id='supplier_a', why='matches query'),
TraceStep(hop=2, doc_id='policy_2026', why='conflict found, given hop 1')]Hop by hop
Hop 1 — address the query
The engine encodes the query into the store's address space and reads the most relevant
passage: supplier_a.pdf — "Supplier A payment terms are net-90…". The why is
"matches query": this passage looks like the question. A vector search would also find
this. The interesting part is what happens next.
Absorb
A small controller absorbs what hop 1 read. The engine now "knows" that Supplier A's terms are net-90 — this fact becomes part of the query state for the next hop.
Hop 2 — re-address, given what it knows
The engine re-addresses the store conditioned on hop 1. It retrieves
policy_2026.md — "all supplier payment terms must not exceed net-60" — with the
why "conflict found, given hop 1".
This is the key move: policy_2026.md shares no keywords with the original query
("which supplier contract conflicts…"). Similarity search cannot reach it. Rekall reaches
it because the reasoning state — net-90 terms that need checking against policy — points
there.
Sufficiency stop
A learned sufficiency head decides it has enough to answer and stops after 2 of a
possible 4 hops. You never told it a contradiction takes two hops — it decided. That's
what hops_used: 2 and confidence: 0.87 report.
The trace schema
Each TraceStep has three fields:
Prop
Type
Adaptive effort — a longer chain
Not every question takes two hops. Evidence-aggregation questions fan out across more documents, and the engine spends more hops before its sufficiency head is satisfied:
rekall search "what evidence supports ending the legacy billing contract?" \
--store demo --trace● 4 passages · 4 hops · confidence 0.79 · 8.1 ms
reasoning trace
hop 1 → billing_legacy.pdf (matches query)
hop 2 → incident_2025.md (outage evidence, given hop 1)
hop 3 → sla_addendum.pdf (breached SLA terms, given hop 2)
hop 4 → finance_review.md (cost overrun, aggregates prior hops)
✓ sufficient — stopped after 4 of 4 max hopsconst r = await store.search(
"what evidence supports ending the legacy billing contract?",
{ trace: true },
);
console.log(r.hopsUsed, r.confidence); // 4 0.79
console.log(r.trace);The same engine, same defaults — it simply worked harder because the question demanded it.
hops_used is your window into that.
Why vector search can't do this
A vector database does one lookup: it returns the passages most similar to your query
embedding. It has no notion of "given what I just read, what matters next," so it cannot
produce a policy_2026.md that shares no words with the query — and it has nothing to put
in a why. The trace is a structural consequence of reasoning at retrieval time, which is
exactly what similarity search lacks.
Turn it on everywhere
return_trace is near-zero cost. Enable it in production for explainability and audit — a
reviewer, an auditor, or a user can see why each document was retrieved.
Next steps
Search
Query a store with SKIM's reasoning loop — writing good queries, tuning max_hops and max_results, metadata filters, reading traces, and branching on confidence.
Self-hosting (Enterprise)
Run the SKIM engine inside your own network — a licensed single binary plus a versioned model artifact. Cloud Run, Kubernetes, or VMs. The exact same API as the managed cloud.