Skip to main content

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

  1. Detect — per-page text-layer analysis (pagepilot.detect)
  2. OCR — optional, via OCRmyPDF + Tesseract for scanned PDFs (pagepilot.ocr)
  3. 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)
  4. Tree — node walk / validation / pruning; typed TreeNode view (pagepilot.tree, pagepilot.models)
  5. Summaries — bottom-up, gentle concurrency (pagepilot.summarize)
  6. Library — corpus-level document selection for multi-doc chat (pagepilot.library)
  7. Retrieval — one-shot page pick from the tree, history-aware (pagepilot.retrieve)
  8. Chat — cited answers (page + document), OpenAI-shaped output, streaming surface (pagepilot.chat)
  9. Chunk/export — hierarchy-aware chunks + JSON / CSV / Markdown / tree serializers (pagepilot.chunk, pagepilot.export)
  10. Assess — zero-LLM index health reports (pagepilot.assess)
  11. 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)

Source distribution for pagepilot 0.3.0
File Size Uploaded Provenance
pagepilot-0.3.0.tar.gz 41.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pagepilot 0.3.0
File Interpreter ABI Platform
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.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page