Read PDFs locally — classify text-based vs scanned, convert to markdown, extract positioned text and tables, and report which pages still need OCR.
Published as experimental by its release pipeline. It installs and resolves like any other worker, but its interface may change without notice.
- macOS: arm64 · x64
- Linux: arm64 · armv7 · x64
- Windows: arm64 · x64 · x86
exact versions are immutable; binary and bundle artifacts are digest-pinned.
skill doc
The pdf worker parses PDF documents on the machine. A PDF is not text: reading
one with a file-reading function returns binary noise and spends the context on
it, so every PDF goes through pdf::* instead. Parsing is local, needs no
credential, and sends nothing anywhere.
Its first job is a routing decision. pdf::classify samples the document's
content streams and answers whether the pages hold real characters or are
photographs of pages, plus which individual pages cannot be read without a
vision model and why. That verdict decides whether the rest of the work is
worth doing at all, and it is what separates "this document is empty" from
"this document is a scan".
Its second job is reading. Text-based documents convert to markdown that keeps the shape of the original, because headings, lists and tables are recovered from font sizes and page geometry rather than from any structure the file promises. Underneath that sit the positions themselves, for callers that need to know where text is and not only what it says.
This worker is called on demand. It registers no harness hook and injects nothing into any prompt, so a conversation that never touches a document never pays for it. Reach for it when one appears.
When to Use
- A conversation names a PDF path or hands one over: call
pdf::classifybefore anything else. Never read a PDF with a file-reading function; it returns binary noise and spends the context on it. - Read a document:
pdf::to-markdown, narrowed withpageswhen it is long. - Search or embed a document rather than read it:
pdf::extract-text. - Decide whether a document is worth sending to a vision model, and which of
its pages:
pdf::classify, then readpages_needing_ocrandocr_reasons. - A vision model located a region and you want the real characters rather than
its transcription:
pdf::extract-regions. - Reason about layout, headings by size, or where a value sits on the page:
pdf::extract-items.
Boundaries
- Nothing here rasterizes a page, so nothing here can OCR. Scanned and
image-based documents are classified and routed, never read. Image content
is reported as a placeholder with a real box and no pixels.
document::ocris where routed pages go when thedocumentworker is installed: it renders them and reads them with a vision model, so it costs money per page. Hand it thepages_needing_ocrthis worker named rather than the whole file. suspected_garbled_textinocr_reasonsmeans the text layer decodes to nonsense. Do not trust the extraction, whateverdocument_typesays.- Responses are capped.
truncated: truewith a much largertotal_charsmeans you hold a fragment and must not answer from it. Narrow withpagesrather than raising the cap: conversion cost scales with the document, so a page filter is faster as well as smaller.max_chars: 0lifts the cap and belongs in a pipeline moving a document to storage, not in a call whose result lands in the conversation. - Encrypted documents take a
passwordonpdf::classifyandpdf::to-markdownonly. The other three cannot decrypt and say so. - Page numbers are 1-indexed everywhere, in requests and responses.
- Coordinates differ by function and every response states which it used:
pdf::extract-itemsreports PDF points from the bottom left,pdf::extract-regionstakes boxes in PDF points from the top left. Assuming the wrong one returns text from the wrong end of the page with no error.
Functions
pdf::classify— the routing call. Document type, confidence, page count, the 1-indexed pages needing OCR, and a machine-readable reason per page.pdf::to-markdown— markdown with headings, lists, links and tables recovered; optional page filter, per-page output, and a fidelity or compact profile.pdf::extract-text— plain text, no structure recovery. Cheaper than markdown when the result will be searched or embedded.pdf::extract-items— every positioned run of characters with its box, font, size, and recovered bold, italic, underline and strikeout.pdf::extract-regions— the text, or a markdown table, inside given boxes on given pages.