PagePilot
Standalone, provider-agnostic PDF page-indexing SDK. Layout heuristics build a nested tree index of a document; retrieval and citation-answer chat run on an injected LLM callable — PagePilot never imports a provider SDK, so it works with any model/tool (OpenAI, Gemini, Groq, Copilot, LiteLLM, …).
Vectorless, reasoning-based retrieval: the LLM navigates a table-of-contents tree the way a human reader would, then answers with exact page (and document) citations. No vector DB, no chunking required — but chunks with section paths are a first-class export for hybrid/vector pipelines.
Install
pip install pagepilot # from PyPI (0.3.0+)
# or, for development:
python -m venv .venv && .\.venv\Scripts\activate
pip install -e ".[dev]"
Quick start
from pagepilot import PagePilotClient
from pagepilot.llm import ChatCompletion
def llm(messages, *, model=None, max_tokens=None):
return my_provider.chat(messages, model=model, max_tokens=max_tokens)
client = PagePilotClient(ChatCompletion(llm, chat_model="your/model"),
summary_concurrency=1) # gentle by default
entry = client.submit_document("report.pdf") # llm-free structure, or:
# entry = client.submit_document("report.pdf", mode="skip-summaries") # never calls the LLM
doc_id = entry["doc"]["id"]
# OpenAI-shaped answer dict + cited result
answer = client.chat("What was the 2023 margin?", doc_id=doc_id)
print(answer["choices"][0]["message"]["content"])
# Typed Answer with page + document sources
typed = client.answer([{"role": "user", "content": "…"}], doc_id=doc_id)
print(typed.content, [c for c in typed.citations])
Multi-turn conversations are context-aware: page and document selection receive the earlier turns, so follow-ups ("…and the second part?") resolve correctly.
Multi-document chat
ids = [client.submit_document(d)["doc"]["id"] for d in ("a.pdf", "b.pdf")]
answer = client.chat("Compare the risk factors across these filings.",
doc_id=ids)
print([f"{s.doc_name} p.{s.page}" for s in client.answer([], doc_id=ids).sources])
The client picks relevant documents by reasoning over the library index, then retrieves pages per document and cites the correct source document.
Change detection
r1 = client.submit_document("report.pdf") # {"status": "ingested"}
r2 = client.submit_document("report.pdf") # {"status": "unchanged"} (same sha256)
r3 = client.submit_document("report.pdf", force=True) # re-index
Chunks & export (for vector pipelines)
from pagepilot import chunk_document
chunks = chunk_document(client.raw_tree(doc_id), source=doc_id)
for c in chunks[:3]:
print(c.section_path, c.page, c.content[:60])
print(client.export(doc_id, fmt="json")) # json | csv | markdown | tree
Index health (zero LLM calls)
from pagepilot import assess_library
for r in assess_library(client.storage_path):
print(r["name"], r["coverage"], r["problems"])
Or via CLI: python scripts/assess_index.py --storage <store> (exit code 1 on
failures — CI-safe).
What it does
- Detect — per-page text-layer analysis (
pagepilot.detect) - OCR — optional, via OCRmyPDF + Tesseract for scanned PDFs
(
pagepilot.ocr) - Layout extract — pure heuristics (no LLM): columns, body-font stats,
header/footer stripping, TOC recognition, heading candidates, doc title,
embedded-PDF-bookmark merge, graceful degradation to coarse page groups
(
pagepilot.layout) - Tree — node walk / validation / pruning; typed
TreeNodeview (pagepilot.tree,pagepilot.models) - Summaries — bottom-up, gentle concurrency (
pagepilot.summarize) - Library — corpus-level document selection for multi-doc chat
(
pagepilot.library) - Retrieval — one-shot page pick from the tree, history-aware
(
pagepilot.retrieve) - Chat — cited answers (page + document), OpenAI-shaped output, streaming
surface (
pagepilot.chat) - Chunk/export — hierarchy-aware chunks + JSON / CSV / Markdown / tree
serializers (
pagepilot.chunk,pagepilot.export) - Assess — zero-LLM index health reports (
pagepilot.assess) - Storage — JSON per-doc dirs under a user storage root
(
pagepilot.storage)
Examples
python examples/quickstart.py path/to/report.pdf other.pdf
python examples/export_chunks.py report.pdf out/
python examples/index_health.py path/to/report.pdf
python -m pagepilot.demo path/to.pdf # deterministic fake-LLM demo
Examples run against an injected fake LLM — no keys, no network.
Design notes
- No provider coupling — the LLM seam (
llm.py) is the only network-ward interface; providers own their retry/quota/header logic. - Cheap ingest — structure extraction is entirely heuristic; summaries are
the only per-ingest LLM cost, or zero with
mode="skip-summaries". - Honest degradation — documents that defeat heuristics fall back to page groups, never fabricated subsection structure.
- Traceable answers — every statement carries
[document p.page]citation from the actually-read pages.
Development
python -m venv .venv
.\.venv\Scripts\activate # Windows PowerShell
python -m pip install -e ".[dev]"
python -m pytest -q
License
MIT — see LICENSE.
Metadata
Release files for pagepilot 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pagepilot-0.3.0.tar.gz | 41.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pagepilot-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 78.4 kB
Release files / pagepilot-0.3.0.tar.gz
| Download URL | pagepilot-0.3.0.tar.gz |
|---|---|
| Size | 41.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
601e68eaeecb73eb2e4ab8fbcd9848de3d6db15ed75b93f43a0777166b4a0c5a
|
|
BLAKE2b-256 checksum How to use checksums |
163a48c451d38996012f44a4f8f560e941ae9fd80278268a8d150f7340b5988c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.1
|
Release files / pagepilot-0.3.0-py3-none-any.whl
| Download URL | pagepilot-0.3.0-py3-none-any.whl |
|---|---|
| Size | 37.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
478a8439962e272b71c93d10729e060f1df833cbc4690d7b77a089a875d47353
|
|
BLAKE2b-256 checksum How to use checksums |
2b4885047da9494a4ac3ebf027faa262c20e36a06f67da35653b767762a1c683
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.1
|
Security for pagepilot 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.