PDF (Anthropic, official)
## what it does
tl;dr: one of the four document skills Anthropic ships under anthropics/skills (with docx, pptx, xlsx) — SKILL.md stays routing-only and the heavy lifting lives in forms.md (form filling) and reference.md (advanced features). Stack is fixed: pypdf + pdfplumber + reportlab + qpdf + pdftotext, with pytesseract + pdf2image for OCR.
What it actually does
Per the frontmatter, the skill activates for any .pdf mention: read, extract text/tables, merge, split, rotate, watermark, create, fill forms, encrypt/decrypt, extract images, OCR scanned PDFs. The skill is a thin routing layer — it tells Claude which of the pinned libraries to reach for; it does not run on its own.
Tool routing
| Task | Tool |
|---|---|
| merge / split / rotate / metadata | pypdf (PdfWriter, PdfReader) |
| extract text with layout | pdfplumber |
| extract tables | pdfplumber → pandas.DataFrame |
| create new PDFs | reportlab (canvas or Platypus) |
| command-line merge / split / rotate | qpdf |
| OCR scanned PDFs | pytesseract + pdf2image |
| fill PDF forms | pdf-lib or pypdf (see forms.md) |
| extract images | pdfimages (poppler-utils) |
| command-line text extract | pdftotext -layout |
Quick start (read a pdf)
from pypdf import PdfReader
reader = PdfReader("document.pdf")
print(f"Pages: {len(reader.pages)}")
text = ""
for page in reader.pages:
text += page.extract_text()
Forms path (forms.md)
The deep guide sits at forms.md (lowercase on disk, even though SKILL.md references it as FORMS.md — that’s a misnomer in the prose). The guide splits into two paths: fillable fields vs. non-fillable annotations. Eight helper scripts under skills/pdf/scripts/:
check_fillable_fields.py— does the PDF even have fillable fields?extract_form_field_info.py— dump field IDs, page, rect, typeextract_form_structure.py— extract labels/lines/checkboxes for non-fillable forms (Approach A)convert_pdf_to_images.py— page-by-page rasterizationfill_fillable_fields.py— write the answers into a fillable PDFfill_pdf_form_with_annotations.py— overlay text/boxes on non-fillable forms (structure coords preferred, visual fallback)check_bounding_boxes.py— pre-flight validator for fields.jsoncreate_validation_image.py— render the overlays as PNG to eyeball coordinate accuracy
The forms.md guide picks Approach A (structure coordinates) over Approach B (visual estimation with ImageMagick zoom crops) by default — fall back to B only when extract_form_structure.py returns empty labels. Hybrid mode (A for some fields, B for missed elements) is the common case for scanned PDFs with odd graphics.
Reference path (reference.md)
reference.md collects what the routing SKILL.md deliberately omits:
- pypdfium2 (Python) — fast render + image extraction; the PyMuPDF alternative Anthropic recommends for Chromium-style rendering
- pdf-lib (JavaScript) — load, create, merge/split PDFs in Node; what Anthropic picks when the skill is called from JS not Python
- pdfjs-dist (JavaScript) — Mozilla’s PDF.js for browser-side rendering and text-with-coordinates
- poppler-utils advanced —
pdftotext -bbox-layoutfor text with bounding boxes,pdftoppmfor high-res page rasters,pdfimages -j -pfor embedded images with metadata - qpdf advanced — split-pages, page-range extraction, encryption with permissions, linearization, repair (
--check/--fix-qdf) - pdfplumber advanced — text with per-character coords, bbox-bounded extraction, custom table-detection settings
- reportlab advanced —
PlatypusTable+TableStyle, professional reports - batch processing with
logging, error isolation, chunked streaming for large PDFs - license summary at the end (
pypdfBSD,pdfplumberMIT,pypdfium2Apache/BSD,reportlabBSD,poppler-utilsGPL-2,qpdfApache,pdf-libMIT,pdfjs-distApache)
Gotchas
- Unicode subscripts/superscripts render as black boxes in
reportlab. The built-in fonts don’t include those glyphs. Use<sub>/<super>XML tags inParagraphobjects, not₀₁₂/⁰¹². TheSKILL.mdrepeats this — it’s the most common silent bug. forms.mdis its own doc. Read it before touching fillable fields. The scripts live inskills/pdf/scripts/and expect to be run from that directory; pass the PDF as a relative path.SKILL.mdcalls themFORMS.md/REFERENCE.md(uppercase) — actual filenames on disk are lowercase. Older tutorials quoting the prose verbatim will misdirect you.- License is Proprietary.
LICENSE.txtrestricts redistribution, derivative works, and extraction outside Anthropic’s services. You use the skill; you don’t fork it. - OCR is heavy.
pytesseract+pdf2imageneed both Python packages and thetesseractsystem binary. Don’t reach for it unless the PDF is scanned;pdfplumberhandles born-digital text faster. - Validate bounding boxes before filling.
check_bounding_boxes.pycatches intersecting entries (which produce overlapping text on the rendered PDF) and entries too small for the chosen font size. Run it every time, not just when something looks wrong. - Plugins ship from a marketplace, not a clone.
/plugin marketplace add anthropics/skillsthenBrowse and install plugins → anthropic-agent-skills → document-skills. Directgit clonelands you outside the Anthropic plugin contract.
Install
# Claude Code (marketplace)
/plugin install document-skills@anthropic-agent-skills
# Or register the whole repo as a marketplace
/plugin marketplace add anthropics/skills
On Claude.ai, the document skills are pre-built for paid plans. On the API, attach via the container.skills parameter:
{
"model": "claude-opus-5",
"max_tokens": 4096,
"container": {
"skills": [
{ "type": "anthropic", "skill_id": "pdf", "version": "latest" }
]
},
"messages": [
{ "role": "user", "content": "Extract the tables from /mnt/invoice.pdf" }
],
"tools": [
{ "type": "code_execution_20250825", "name": "code_execution" }
]
}
Skills require code_execution_20250825; pinned to the Claude API ID claude-opus-5 in the example. Use the Files API to pull the result back when Claude writes a new PDF.
Related
- frontend-design (Anthropic, UI Skills) — same Anthropic skills shelf
- UI Skills catalog (Anthropic) — the broader Anthropic UI skills surface
- Anthropic Claude — what Anthropic publishes — cross-shelf context
## compatibility
## embed this badge
