Rekalldocs
Getting Started

Quickstart

Run a multi-hop, reasoning-grade search over your own documents — with the trace and the latency — in under a minute. CLI, TypeScript, or Python.

Three steps: set up, ingest, search. Pick your surface — the language switcher below persists across the whole site.

Closed beta — request access

Rekall is a closed API: the SKIM engine runs server-side and every surface reaches it with an API key. Request access to get a key (generous evaluation usage, no card). The steps below assume REKALL_API_KEY is set; the CLI client picks it up after rekall login.

1 · Set up

Download the CLI client from the Downloads page in your dashboard, put it on your PATH, and log in:

rekall login          # browser auth → saves your key to ~/.rekall/config
rekall --version
# rekall 0.2.0 · client → api.rekall.sh
npm i rekall-search
# or: bun add rekall-search · pnpm add rekall-search · yarn add rekall-search

Zero-dependency, pure fetch. Works in Node 18+, Bun, Deno, and edge runtimes.

pip install rekall-search
# or: uv add rekall-search

Sync-first (calls are ~4 ms — async matters less than for LLM RAG). AsyncRekall is available for async apps.

2 · Ingest a folder

Whole files, no chunking. Documents are queryable the moment ingest returns — there is no index build step to wait on.

rekall ingest ./docs --store demo
Output
✓ 287 documents ingested · queryable now  (4.1 s, 70 docs/s)

rekall ingest walks folders and globs, auto-detects PDF/MD/HTML/DOCX/TXT, and creates the store if it doesn't exist. Per-doc failures print at the end without aborting the batch (--strict to abort).

ingest.ts
import { Rekall } from "rekall-search";

const rekall = new Rekall();                    // reads REKALL_API_KEY / REKALL_BASE_URL
const store = await rekall.store("demo");       // get-or-create by name

await store.ingest([
  { id: "supplier_a", text: supplierText, metadata: { team: "procurement" } },
  { id: "policy_2026", text: policyText },
]);

// Big local corpus? Extraction parity with the CLI:
await store.ingestFiles("./docs/**/*.{pdf,md,txt}");
ingest.py
from rekall import Rekall

rekall = Rekall()                       # reads REKALL_API_KEY / REKALL_BASE_URL
store = rekall.store("demo")            # get-or-create

store.ingest([
    {"id": "supplier_a", "text": supplier_text, "metadata": {"team": "procurement"}},
    {"id": "policy_2026", "text": policy_text},
])

# Big local corpus? Extraction parity with the CLI:
store.ingest_files("docs/", glob="**/*.pdf")

3 · Ask something that needs reasoning

The query below can't 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
Output
● 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 hops

Add --json to emit the SearchResult verbatim for scripts; -i opens an interactive REPL for repeated queries.

search.ts
const result = await store.search(
  "which supplier contract conflicts with the 2026 policy?",
  { maxResults: 5, trace: true },
);

result.passages.forEach((p) => console.log(p.docId, p.score, p.hop));
console.log(result.confidence, result.hopsUsed, result.latencyMs);
console.log(result.trace); // [{ hop, docId, why }]
Output
supplier_a 0.92 1
policy_2026 0.81 2
0.87 2 4.2
[
  { hop: 1, docId: 'supplier_a', why: 'matches query' },
  { hop: 2, docId: 'policy_2026', why: 'conflict found, given hop 1' }
]
search.py
result = store.search(
    "which supplier contract conflicts with the 2026 policy?",
    max_results=5, trace=True,
)

for p in result.passages:
    print(p.doc_id, p.score, p.hop, p.text[:60])

print(result.confidence, result.hops_used, result.latency_ms)
print(result.trace)  # [TraceStep(hop, doc_id, why), ...]
Output
supplier_a 0.92 1 …Supplier A payment terms are net-90 as amended in §4.2…
policy_2026 0.81 2 …all supplier payment terms must not exceed net-60…
0.87 2 4.2
[TraceStep(hop=1, doc_id='supplier_a', why='matches query'),
 TraceStep(hop=2, doc_id='policy_2026', why='conflict found, given hop 1')]

What just happened

  • Rekall ran a multi-hop reasoning loop, not a single lookup — hop 1 matched the query, hop 2 found the conflicting clause given hop 1.
  • It stopped early (2 of a possible 4 hops) because the learned sufficiency head decided it had enough — you never tell it how many hops a question needs.
  • Every result carries confidence, hops_used, and latency_ms; the trace explains why each document was chosen.

Next steps

On this page