OCR-powered document agent · Python

Ask your documents.
Get the answer and the line it came from.

Inklight reads PDFs, scans and photos on your own CPU, works out what you asked for, and runs a short, bounded plan: search, extract, filter, calculate, compare. Every answer cites its page and position. Anything uncertain is flagged.

$pip install inklight
43 ms per PDF pageEvery wrong value flagged0 API keys needed
$ inklight ask ./invoices "Find all invoices above $5,000"
2 of 3 documents match total > 5000
invoice_acme.pdf · 5,616.00 · verified (5,200 + 416)
initech_scan.png · 7,930.00 · ⚠ subtotal + tax ≠ total
evidence: invoice_acme.pdf p.1 · OCR 1.00 · 129 ms
How it works

A real agent with a short leash.

Your words become a typed plan. Plans never come from document text, so an instruction hidden inside a PDF can't change what the agent does.

READ

Indra OCR

Uses a PDF's own text layer first and OCRs only where needed. Keeps layout blocks, reading order, boxes and per-line confidence.

PLAN

Typed steps

Intent, fields and conditions are parsed into a plan of allow-listed tools. There is no shell and no code execution.

ACT

Bounded run

Step limits, time budgets, retries and cancellation. Arithmetic is done in exact decimals, not by a model.

VERIFY

Evidence check

Tells you how it read your request and anything it could not apply. Citations are matched against the stored text, totals are cross-checked, and currencies are never mixed.

Replace the manual pass

Ask the way you would ask a colleague.

You sayInklight doesTools
“Create a CSV of vendor, date, tax and total”Typed extraction with page provenance, then a CSV (with your permission)extract → write
“Contracts that expire within 90 days”Reads expiry dates and filters by the date windowextract → filter
“Compare these reports”Field and line diffs, plus changed figures such as 6% → 17%compare
“Flag inconsistent customer names”Groups spelling variants, checks arithmetic and datesextract → inconsistencies
“Find the paragraph about termination”Returns the exact block, highlighted on the pagesearch → cite
“Watch this folder”Indexes new files once their copy finishes and runs your request on each batchinklight watch
Measured, not promised

Fast on a laptop CPU.

43 ms
per digital PDF page (median)
98 ms
per noisy scanned page (median)
96.7%
of 240 fields across 3 invoice layouts; all 8 misses flagged
446 MB
peak memory, offline rules mode

Measured with the bundled bench/run.py on a 16-thread AMD laptop CPU (Windows, Python 3.13) over 40 generated invoices in three layouts (20 digital, 20 rotated and noisy scans) and 8 mixed documents. These are generated test documents, not unseen real-world ones, and they are easier than handwriting or complex tables. Run the suite on your own hardware.

Small-model intelligence

Under 200M parameters each, used where they're strong.

We measured a 135M model as the planner on 40 requests. It picked the right task 27.5% of the time, so it doesn't plan. Rules plan the work. Small models point at evidence and rank passages, and code does the maths.

Rule planner (in-distribution set)100%
SmolLM2-135M as zero-shot planner27.5%
66M
Reader

Extractive question answering. It can only copy a span from your document, so it can't invent a fact.

33M
Embedder

Finds "expiration date" when you asked about the "contract end", fused with BM25 search.

135M
Writer (optional)

Rephrases an answer it was given. Any wording with a number or name missing from the evidence is discarded.

0
Rules mode

No models at all, fully deterministic, and still useful for every task above.

Built for untrusted documents

Local first. Safe by construction.

Prompt injection is data

"Ignore previous instructions" inside a PDF is detected, reported, and has no effect on the plan.

Writes need permission

One tool can write, only into your output folder, never overwriting, and only after --out, --yes or your confirmation.

Nothing leaves the machine

No API key and no telemetry. A stronger remote model is opt-in, https-only, and its quotes are verified against your document.

Two minutes to first answer

CLI, Python, or the local workspace.

Python 3.11+ on Windows, Linux or macOS. Indra's OCR models (~76 MB) download on first use. inklight models pull adds the small models (~100 MB). After that, everything runs offline.

# the shell
pip install inklight
inklight process ./documents/
inklight ask ./documents/ "Find all invoices above $5,000"
inklight serve        # http://127.0.0.1:8765

# Python
from inklight import DocumentAgent
agent = DocumentAgent()
result = agent.ask("Extract the invoice number, date, and total",
                   files=["invoice.pdf"])
print(result.answer, result.sources[0].cite())

Licensing, before you use it commercially

Inklight's code is Apache-2.0. It reads documents with Indra OCR by Datalab. Indra's model weights are downloaded under a modified OpenRAIL-M license: free for research, personal use, and organisations under $20M revenue and funding, with restrictions on commercial use that competes with Datalab. For commercial deployments, get a license from Datalab or plug in another OCR engine.