PDF Skill
When To Use
- Read or review PDF content where layout and visuals matter.
- Create PDFs programmatically with reliable formatting.
- Fill and validate interactive PDF forms.
- Validate final rendering before delivery.
Workflow
- Prefer visual review: render PDF pages to PNGs and inspect them.
- Use
pdftoppmfrom the bundled runtime or system Poppler when available. - If unavailable, install Poppler or ask the user to review the output locally.
- Use
- Use
reportlabto generate PDFs when creating new documents. - Use
pdfplumberorpypdffor text extraction and quick checks; do not rely on text extraction for layout fidelity. - After each meaningful update, re-render pages and verify alignment, spacing, and legibility.
Fill And Validate AcroForms
Visual review alone is not a correctness check for a fillable PDF. A page /Widget annotation can render a value from its appearance stream while the canonical /AcroForm/Fields tree is missing or contains a stale value.
- Keep the result interactive by default; set
flatten=Trueonly when the user explicitly requests a completed, static form. Preserve the source PDF, and do not flatten a signed PDF without an explicit workflow decision. - Inspect both representations before filling: enumerate fields from
reader.get_fields()and/Widgetannotations from every page's/Annots, following/Parentand/Kids. If a widget and a canonical field have the same name but are distinct objects with no/Parentrelationship, do not callreattach_fields()blindly: it can create a second top-level field with the same name. Report the ambiguity or produce a static result. - Recover genuinely orphaned widgets, fill all pages, and write the result with
pypdf:
pythonfrom pypdf import PdfReader, PdfWriter from pypdf.generic import NameObject reader = PdfReader(input_pdf) writer = PdfWriter() writer.clone_document_from_reader(reader) # Restores widgets that are missing from /AcroForm/Fields. writer.reattach_fields() fields = writer.get_fields() or {} missing = set(expected_values) - set(fields) if missing: raise ValueError(f"Form fields not found after repair: {sorted(missing)}") values_to_write = dict(expected_values) if flatten: # Paint every existing value before removing every widget. values_to_write = { name: field.get("/V", "/Off" if field.get("/FT") == "/Btn" else "") for name, field in fields.items() } values_to_write.update(expected_values) writer.update_page_form_field_values( None, values_to_write, auto_regenerate=False, flatten=flatten ) if flatten: # pypdf's flatten=True paints appearances but does not remove widgets. writer.remove_annotations(subtypes="/Widget") writer.root_object.pop(NameObject("/AcroForm"), None) with open(output_pdf, "wb") as stream: writer.write(stream)
- Reopen the written PDF before delivery. For an interactive result, require every expected field to be present in
get_fields()with the expected/V, enumerate page widgets again, and confirm their effective/V(the widget value or inherited/Parentvalue) agrees. Confirm each updated widget has a non-empty/AP/Nappearance and render the final pages to catch stale or clipped appearances. Do not rely on/NeedAppearancesor a successful PNG render as proof that logical field data was updated. - For a flattened result, require zero
/Widgetannotations and no remaining/AcroFormfield tree after reopening, then render the final pages. Keep an editable copy when the user may need to revise the form.
Temp And Output Conventions
- Use
tmp/pdfs/for intermediate files; delete them when done. - Write final artifacts under
output/pdf/when working in this repo. - Keep filenames stable and descriptive.
Dependencies
Prefer the Codex bundled workspace/runtime dependencies when available. The primary runtime is expected to include:
- Python packages:
reportlab,pdfplumber,pypdf - Rendering tools:
pdftoppmandpdfinfofrom Poppler
If a dependency is missing, install only what is needed.
Python packages:
bashuv pip install reportlab pdfplumber pypdf
If uv is unavailable:
bashpython3 -m pip install reportlab pdfplumber pypdf
System tools for rendering:
bash# macOS (Homebrew) brew install poppler # Ubuntu/Debian sudo apt-get install -y poppler-utils
If installation is not possible in this environment, tell the user which dependency is missing and how to install it locally.
Environment
No required environment variables.
Rendering Command
bashpdftoppm -png "$INPUT_PDF" "$OUTPUT_PREFIX"
Quality Expectations
- Maintain polished visual design: consistent typography, spacing, margins, and section hierarchy.
- Avoid rendering issues: clipped text, overlapping elements, broken tables, black squares, or unreadable glyphs.
- Charts, tables, and images must be sharp, aligned, and clearly labeled.
- Use ASCII hyphens only. Avoid U+2011 and other Unicode dashes.
- Citations and references must be human-readable; never leave tool tokens or placeholder strings.
Final Checks
- Do not deliver until the latest PNG inspection shows zero visual or formatting defects.
- Confirm headers, footers, page numbering, and section transitions look polished.
- Keep intermediate files organized or remove them after final approval.
Final response citations
Place :codex-file-citation{...} inline in prose, not in a trailing list. Use purpose="source" for Q&A/no-op and purpose="output" for create/edit.
- [HARD REQUIREMENT] Create/edit: cite each final PDF exactly once with a plain output citation. Summarize representative changes; do not cite every page or add a separate filename, path, or Markdown link. Example:
Created :codex-file-citation{path="/abs/path/report.pdf" purpose="output"}, with the completed analysis and appendix. - Q&A/no-op: do not edit or re-export. Inspect the complete relevant pages, preserve material headings, table/figure labels, footnotes, sources, and sample sizes, and cite each source PDF once with a plain source citation.
PDF citations currently support only plain file citations. Do not add artifact_kind, page_number, or other locators. Never cite rendered PNGs, scratch files, builders, or QA intermediates unless asked.


