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.
Tools + Contract Requirements
Immediately before the first create/edit authoring command, run mark_artifact_operation_started.mjs successfully exactly once using the command below. Do not run it for read-only work. For edits, replace create with edit; adjust the expected count and output format to match the requested outputs.
node container_tools/mark_artifact_operation_started.mjs --operation-kind create --expected-output-count 1 --output-format pdf
Workflow
- Prefer visual review: render PDF pages to PNGs and inspect them.
- Use
pdftoppm from the bundled runtime or system Poppler when available.
- If unavailable, install Poppler and use it to review the output.
- Use
reportlab to generate PDFs when creating new documents.
- Use
pdfplumber or pypdf for 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=True only 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 /Widget annotations from every page's /Annots, following /Parent and /Kids. If a widget and a canonical field have the same name but are distinct objects with no /Parent relationship, do not call reattach_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:
from 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 /Parent value) agrees. Confirm each updated widget has a non-empty /AP /N appearance and render the final pages to catch stale or clipped appearances. Do not rely on /NeedAppearances or a successful PNG render as proof that logical field data was updated.
- For a flattened result, require zero
/Widget annotations and no remaining /AcroForm field 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:
pdftoppm and pdfinfo from Poppler
If a dependency is missing, install only what is needed.
Python packages:
uv pip install reportlab pdfplumber pypdf
If uv is unavailable:
python3 -m pip install reportlab pdfplumber pypdf
System tools for rendering:
# 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
pdftoppm -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.
1---2name: pdf3description: Read, create, inspect, render, and verify PDF files where visual layout matters, including fillable AcroForms. Use Poppler rendering plus Python tools such as reportlab, pdfplumber, and pypdf for generation and extraction.4---56# PDF Skill78## When To Use910- Read or review PDF content where layout and visuals matter.11- Create PDFs programmatically with reliable formatting.12- Fill and validate interactive PDF forms.13- Validate final rendering before delivery.1415## Tools + Contract Requirements1617Immediately before the first create/edit authoring command, run `mark_artifact_operation_started.mjs` successfully exactly once using the command below. Do not run it for read-only work. For edits, replace `create` with `edit`; adjust the expected count and output format to match the requested outputs.1819```bash20node container_tools/mark_artifact_operation_started.mjs --operation-kind create --expected-output-count 1 --output-format pdf21```2223## Workflow24251. Prefer visual review: render PDF pages to PNGs and inspect them.26 - Use `pdftoppm` from the bundled runtime or system Poppler when available.27 - If unavailable, install Poppler and use it to review the output.282. Use `reportlab` to generate PDFs when creating new documents.293. Use `pdfplumber` or `pypdf` for text extraction and quick checks; do not rely on text extraction for layout fidelity.304. After each meaningful update, re-render pages and verify alignment, spacing, and legibility.3132## Fill And Validate AcroForms3334Visual 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.35361. Keep the result interactive by default; set `flatten=True` only 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.372. Inspect both representations before filling: enumerate fields from `reader.get_fields()` and `/Widget` annotations from every page's `/Annots`, following `/Parent` and `/Kids`. If a widget and a canonical field have the same name but are distinct objects with no `/Parent` relationship, do not call `reattach_fields()` blindly: it can create a second top-level field with the same name. Report the ambiguity or produce a static result.383. Recover genuinely orphaned widgets, fill all pages, and write the result with `pypdf`:3940```python41from pypdf import PdfReader, PdfWriter42from pypdf.generic import NameObject4344reader = PdfReader(input_pdf)45writer = PdfWriter()46writer.clone_document_from_reader(reader)4748# Restores widgets that are missing from /AcroForm/Fields.49writer.reattach_fields()50fields = writer.get_fields() or {}51missing = set(expected_values) - set(fields)52if missing:53 raise ValueError(f"Form fields not found after repair: {sorted(missing)}")5455values_to_write = dict(expected_values)56if flatten:57 # Paint every existing value before removing every widget.58 values_to_write = {59 name: field.get("/V", "/Off" if field.get("/FT") == "/Btn" else "")60 for name, field in fields.items()61 }62 values_to_write.update(expected_values)6364writer.update_page_form_field_values(65 None, values_to_write, auto_regenerate=False, flatten=flatten66)6768if flatten:69 # pypdf's flatten=True paints appearances but does not remove widgets.70 writer.remove_annotations(subtypes="/Widget")71 writer.root_object.pop(NameObject("/AcroForm"), None)7273with open(output_pdf, "wb") as stream:74 writer.write(stream)75```76774. 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 `/Parent` value) agrees. Confirm each updated widget has a non-empty `/AP` `/N` appearance and render the final pages to catch stale or clipped appearances. Do not rely on `/NeedAppearances` or a successful PNG render as proof that logical field data was updated.785. For a flattened result, require zero `/Widget` annotations and no remaining `/AcroForm` field tree after reopening, then render the final pages. Keep an editable copy when the user may need to revise the form.7980## Temp And Output Conventions8182- Use `tmp/pdfs/` for intermediate files; delete them when done.83- Write final artifacts under `output/pdf/` when working in this repo.84- Keep filenames stable and descriptive.8586## Dependencies8788Prefer the Codex bundled workspace/runtime dependencies when available. The primary runtime is expected to include:8990- Python packages: `reportlab`, `pdfplumber`, `pypdf`91- Rendering tools: `pdftoppm` and `pdfinfo` from Poppler9293If a dependency is missing, install only what is needed.9495Python packages:9697```bash98uv pip install reportlab pdfplumber pypdf99```100101If `uv` is unavailable:102103```bash104python3 -m pip install reportlab pdfplumber pypdf105```106107System tools for rendering:108109```bash110# macOS (Homebrew)111brew install poppler112113# Ubuntu/Debian114sudo apt-get install -y poppler-utils115```116117If installation is not possible in this environment, tell the user which dependency is missing and how to install it locally.118119## Environment120121No required environment variables.122123## Rendering Command124125```bash126pdftoppm -png "$INPUT_PDF" "$OUTPUT_PREFIX"127```128129## Quality Expectations130131- Maintain polished visual design: consistent typography, spacing, margins, and section hierarchy.132- Avoid rendering issues: clipped text, overlapping elements, broken tables, black squares, or unreadable glyphs.133- Charts, tables, and images must be sharp, aligned, and clearly labeled.134- Use ASCII hyphens only. Avoid U+2011 and other Unicode dashes.135- Citations and references must be human-readable; never leave tool tokens or placeholder strings.136137## Final Checks138139- Do not deliver until the latest PNG inspection shows zero visual or formatting defects.140- Confirm headers, footers, page numbering, and section transitions look polished.141- Keep intermediate files organized or remove them after final approval.142143## Final response citations144145Place `: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.146147- [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.`148- 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.149150PDF 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.