pdfcraft · git:20261026.76415fe · 2026-10-26 · sha256 815baf323928dcd8

pdfcraft git:20261026.76415feA

Immutable. This exact content never changes and is served at /api/v1/blob/815baf323928dcd8.

---
name: pdfcraft
description: PdfCraft is the ArtCraft PDF workbench, a clean-room Acrobat Pro reimplementation for macOS, Windows, Linux, FreeBSD and the web. Use this skill whenever the user mentions PdfCraft or pdfcraft-cli, asks what it can do, which file formats or shortcuts it supports, or asks to read, render, search, organize, combine, split, rotate, annotate, fill, calculate, sign, redact, OCR, compare, print, protect, layer, measure or convert a PDF; when preparing assets or inputs for it; when driving it headlessly through the CLI, the MCP server or the UI control channel; or when verifying, repairing or troubleshooting its output — even if the app is not named (for example "merge these PDFs", "make this scan searchable", "fix this form's calculation order", "redact this contract", "convert this PDF to Word").
---

Audit basis: this checkout is tag `v0.14.0`, commit `5a78b223871add8e3883856205cc653d741e0e94`. The installed `/Applications/PdfCraft.app` reports version `0.14.0` (bundle id `ai.storyteller.pdfcraft`, minimum macOS 11.0), its `PdfCraftBuildCommit` is the same full commit, and `/Applications/PdfCraft.app/Contents/MacOS/PdfCraft --version` prints `pdfcraft 0.14.0`, so the bundle matches this source. **Verify against your installed version** if the ArtCraft Launcher has auto-updated since. Deep detail: `references/automation-tools.md` lists all 179 automation tools at this tag.

## Overview

PdfCraft is an open-source, pure-Rust PDF reader and editor ("The PDF workbench; an open-source, modern PDF reader and editor", `README.md`), built clean-room with Adobe Acrobat Pro as the documented parity target (`docs/target-app-parity.md`; Acrobat DC continuous track 26.002.21931). It is **alpha** (README "What's next": 57% of its tracked Acrobat features, 94% of core essentials, ~55% ready for everyday work) and runs on macOS, Windows, Linux and FreeBSD plus a WebAssembly shell (`apps/pdfcraft-web`, `docs/architecture.md`). Source: GitHub storytold/pdfcraft.

The PDF object graph is the document model: there is no separate project file, so the `.pdf` **is** the project (`docs/architecture.md` §Data model and editing). Pages are drawn by the vendored `hayro` 0.7.x family while PdfCraft's own renderer is built (`docs/gaps.md` gap 2; `vendor/README.md`), so rendering is good but not Acrobat-measured. This tag (v0.14.0, 2026-10-25) is mostly a hardening release after v0.13.0: decode budgets and other bounds against hostile files, plus attachment add/delete, bookmark colour/style, pasting added content, per-reply comment status, accessibility table summary/scope, custom document properties, print paper/duplex fixes and macOS file-association recovery.

## Capabilities (verified)

Unless a bullet says **partial**, the path is wired into the UI and/or the CLI at this tag. If your installed version differs, run `/Applications/PdfCraft.app/Contents/MacOS/PdfCraft --version` and `pdfcraft-cli tools` before trusting flags or tool names. Tool names live in `crates/automation/src/tools.rs`; command ids in `crates/engine/src/commands.rs`; UI panels and dialogs are under `crates/ui-egui/src`.

### Automation surface at a glance

| Surface | Count at v0.14.0 | Change vs the v0.12.0 skill |
|---|---|---|
| Automation tools (`crates/automation/src/tools.rs:120`) | **179** | +4: `attachment_add`, `attachment_delete`, `bookmark_set_style`, `content_copy`; none removed |
| Command registry (`crates/engine/src/commands.rs:165`) | **205** | +1: `edit.attach`; none removed |
| Tools mapped to a command (`ToolDef::command`) | **71** | +1 (the rest of the 205 commands are UI-only) |
| CLI subcommands (`apps/pdfcraft-cli/src/main.rs:57`) | **14 documented**, plus internal `check-one` | unchanged; 25 `--flag` names, unchanged |
| UI control methods (`crates/ui-egui/src/control.rs:282`) | **17** | unchanged |
| Interface languages (`crates/ui-egui/src/i18n/mod.rs:162`) | **34** (English + 33 catalogs) | unchanged |
| All tools catalogue (`crates/engine/src/catalog.rs:562`) | 150 items, 24 groups, 5 categories; 26 items + 5 groups badged planned | `Attach file` left the planned list (M12) |
| MCP tools | the same **179**, or 17 entries under `--compact` (15 core + `tool_search` + `tool_call`) | same +4 tools |
| MCP resources (`crates/automation/src/mcp.rs`) | 4 URI templates + 2 list resources | unchanged; 16 MiB request-line cap added |
| Convertible input extensions (`CONVERTIBLE`, `crates/create/src/lib.rs:516`) | **12** (png, jpg, jpeg, tif, tiff, gif, bmp, jp2, j2k, jpx, txt, text) | unchanged |
| Office export targets (`OfficeFormat::from_extension`, `crates/engine/src/compare.rs:156`) | **4** kinds / 5 extensions (docx, pptx, html, htm, rtf) | unchanged |
| Form-data extensions (`crates/xfdf/src/lib.rs:52`) | **8** (xfdf, fdf, xml, xdp, csv, txt, tab, tsv) → 6 formats | unchanged |
| Page-image export formats | **3** (png, jpeg, tiff; `pdfcraft-cli render` also writes `.pam`) | unchanged |

`pdfcraft-cli tools` is the live capability contract; the full name/title/hint table is in `references/automation-tools.md`. Every tool has a JSON Schema, read-only (48) or destructive (25) hints and an optional registry command id. Repo docs lag badly: `docs/architecture.md` §4, `docs/ui-parity.md` and `docs/target-app-parity.md` still say "141 automation tools" and "184 registered commands".

### Reading, navigation and text
- Tiled CPU rendering with single, continuous, two-up and two-page layouts, rotation, full screen, Read mode, light/dark/system themes and per-tab history (`crates/ui-egui/src/canvas.rs`; `crates/ui-egui/src/lib.rs` `set_option`). Optional gapless page display: `view.page_gaps` (command), `--page-gaps on|off`, `ui.set key=page-gaps`, and an independent 50–150% thumbnail slider (`docs/page-display.md`).
- Reading-order text extraction (columns, RTL runs, vertical CJK), find-as-you-type, next/previous match, text selection and permission-aware copy (`crates/render`; `crates/ui-egui/src/canvas.rs`). `pdfcraft-cli text` refuses text from a document that forbids copying unless the owner password is supplied.
- Bookmarks (nested, searchable, with colour and bold/italic), page thumbnails, the document's own page labels, transitions/display times, word/character counts, layers, attachments, reading colours and the document's initial view (`doc_info` now reports "the destination it opens at"; `bookmark_list`, `text_word_count`, `view_reading_colors`, `doc_initial_view`).
- **New:** reopening a file can restore the page, zoom and page display it was last shown with (Acrobat's Preferences ▸ Documents option, on by default, 100 files, desktop only: `crates/ui-egui/src/last_view.rs`).
- PDF 1.0–2.0 (2.0 features preserved but not used), repair of damaged files with the repairs reported (`crates/cos`; `docs/file-format-parity.md`). Whole-file operation: no lazy disk read yet (`docs/gaps.md` gap 13).

### Page organization, combine, split, create
- Rotate, reverse, delete, move, duplicate (with `at`), replace, extract, insert blank/file pages, crop/boxes, page labels, transitions (`page_*` tools; `crates/organize`). Page copy/cut/paste exist only as commands (`page.copy`, `page.cut`, `page.paste`) with no headless tool.
- Combine with one bookmark per file, carrying links, named destinations, form fields, layer defaults, attachments and nested bookmarks; per-file page ranges, passwords and grouping; field-name collisions resolve by rename or merge (`doc_combine`; `crates/organize/src/import.rs`). Split by page count, before pages, top-level bookmarks or maximum size into `<name>-partK.pdf` (`doc_split`).
- Create PDFs from blank pages, images (PNG/JPEG/TIFF including multi-page and BigTIFF, GIF, BMP, JPEG 2000) and `.txt`/`.text` — 12 extensions (`CONVERTIBLE`, `crates/create/src/lib.rs:516`); `doc_create_multiple` mixes PDFs, images and text. **Partial** for text: WinAnsi (Western European) only; other characters are refused (`doc_create` description).
- Compare two documents: text diff plus optional visual-region diff, side-by-side when both are open, PDF report, or differences added as comments (`doc_compare`, `doc_compare_report`, `doc_compare_mark`; `crates/engine/src/compare.rs`). The Compare panel shows Text / Visual filters. **Partial:** no filters for images, annotations, formatting or background, no page ranges, no scanned-document support (`docs/gaps.md` gap 21).
- Action Wizard: list built-in actions/steps and run an action or a custom step list over many files (`action_list`, `action_run`; `crates/engine/src/actions.rs`). No action creation UI.

### Comments, bookmarks, forms, layers, attachments
- 19 markup kinds: note, highlight, underline, strikeout, squiggly, replace, rectangle, oval, line, arrow, ink, text box, stamp (static/dynamic/custom), polygon, cloud, polyline, callout, caret, attachment; replies, review status, locking and summarization (`comment_*`; `crates/annot`); flattening is `doc_flatten`.
- **New:** comment threads are resolved through each reply's `/IRT` reference, not a shared `/NM` name; a status or checkmark belongs to the annotation it was set on, and `comment_list` reports each reply's own status/checkmark (`crates/render/src/inspect.rs:574` `thread_tops`; `crates/automation/src/comments.rs`). `comment_*` tools now **refuse an `id` that several comments share** and ask for `page` + `index`; `comment_list` reports the displayed rectangle (`shown_rect`), which is right on rotated pages.
- **New:** `stamp_custom` fits a picture into `rect` as well as placing it at `at`, and keeps a source PDF page's content as a vector form XObject; `comment_add` accepts the extended note icons (the standard names plus Check, Circle, Cross, CrossHairs, Star, RightArrow, UpArrow).
- **New:** `bookmark_set_style` colours a bookmark's title and makes it bold/italic (`/C`, `/F`); `bookmark_list` reports both. New bookmarks can target a place on the page (`bookmark_add` `top`/`left`), and `bookmark_from_structure` builds them from tagged headings.
- AcroForm listing, filling with regenerated appearances, field creation (text/date/checkbox/radio/combo/list/button/image/signature), properties, tab order, calculations and field JavaScript, automatic detection, data import/export (`crates/forms`, `crates/xfa`, `crates/js`; `form_*`). **New:** a dotted field name such as `MASTER.first` creates or moves a field under parent fields.
- Form calculation order: `form_calculation_order` reads calculated fields in order with each formula's `reads` and `issues` (`runs_too_early`, `cycle`, `not_in_order`) and can set, move or `fix` the order, then recalculates (`crates/forms/src/calc_order.rs`). Text-field tables: `form_add_field_table` divides a rectangle into 1–100 rows × 1–50 columns with per-column name patterns (`crates/forms/src/table.rs`).
- **New:** document-level attachments can be added and deleted headlessly (`attachment_add` → command `edit.attach`, `attachment_delete`; `crates/organize/src/attachments.rs`). Still **no tool extracts an attachment**.
- Layers: `layer_set` shows/hides an optional-content group by name or position; it is a view setting — `page_render` draws with it, the file never changes (`crates/automation/src/layers.rs`). Fill & Sign without prepared fields: typed text, checks/crosses/dots/lines, dates, typed or image signatures/initials, photo-of-signature scanning (`fill_sign_add`; `crates/ui-egui/src/fill_sign.rs`).
- Links, JavaScript, XFA: `link_*` lists/opens/adds/edits/deletes links and creates them from URLs; `js_run`, `js_document_scripts`, `js_set_document_script` and `form_set_script` run/edit document and field JavaScript; `xfa_to_static` converts an XFA form to a static form; `doc_flatten` bakes appearances in. **New:** when XFA layout is active, document-level "PDF container" scripts are skipped from `js_run` (they stay reachable via `js_document_scripts`), and `js_run` reports the document-level scripts that failed while the rest still ran (`crates/engine/src/js.rs`).

### Protect, redact, sanitize, standards
- Standard security handler R2–R6: RC4-40/128, AES-128/256, user/owner passwords with SASLprep, permissions, re-encryption on save (`crates/crypt`; `doc_protect`, `doc_unprotect`). No certificate (public-key) encryption.
- Redaction by rectangle, text find, word list, pattern (phone/email/credit-card/SSN/date) or whole pages, with FOIA/Privacy Act overlay codes; applying removes text, images, vectors, comments and form fields under the marks and runs a verification pass (`crates/redact/src/lib.rs:679`; `redact_mark`, `redact_apply`). **New:** labelled Italian geographic numbers such as Tel. +39 0426/123456 match the phone pattern (`crates/redact/src/patterns.rs`).
- Faux-redaction audit finds text still extractable under painted boxes and unapplied marks; paint-order and colour-aware, fails closed on unreadable content, CLI exits non-zero on findings (`doc_audit_redactions`; `pdfcraft-cli audit`; `crates/audit/src/lib.rs`). **New:** it honours the copy permission (withheld text is not reported) and has a work/report budget, so a hostile file errors instead of hanging.
- Remove hidden information / Sanitize, with categories listed first (`doc_hidden_info`, `doc_remove_hidden`).
- `standards_remove_id` removes PDF/A (`pdfaid:`) or PDF/X (`GTS_PDFX…`) identification from XMP and document info; it fails if nothing of that kind is declared and does not repair the document (`crates/organize/src/lib.rs`).
- Printing obeys document permissions: the Print command needs `Needs::Printing` and the engine's `print_pdf` returns `NotPermitted` when printing is forbidden; low-quality-only printing rasterizes at ≤150 dpi (`crates/engine/src/lib.rs:4747`; `print.dialog` in `crates/engine/src/commands.rs`).

### Signatures
- Sign with `.p12`/`.pfx` digital IDs, macOS Keychain identities or the Windows certificate store; PAdES B-B, SHA-256 (SHA-384 for P-384 keys); certification signatures with no-changes/form-fill/comments levels; visible signatures with image, typed text or drawn strokes; self-signed ID creation; trust list incl. `.p7b`/`.p7c` bundles; validation including changes made after signing (`crates/sign`; `sign_document`, `sign_id_create`, `sign_keychain_ids`, `sign_windows_ids`, `sign_list`, `sign_trust`).
- Validation checks embedded RFC 3161 timestamp tokens (token signature, imprint, TSA certificate validity/EKU, coverage of the signature value) and offline CRL/OCSP evidence with a DSS for PAdES B-LT (`crates/sign/src/pdf.rs`, `crates/sign/src/timestamp.rs`, `crates/sign/src/revocation.rs`, `crates/sign/src/dss.rs`). **Partial:** no timestamp-server setting and no online fetching; `sign_with_timestamp`/`timestamp_document` take a caller-supplied `TimestampAuthority` and are engine-only (`crates/engine/src/lib.rs:5318`). No PKCS #11/smart cards on macOS/Linux, no OS trust store, no EU Trusted Lists (`docs/gaps.md` gap 10).

### OCR, print, export, optimize, accessibility, measuring, editing
- OCR adds an invisible searchable text layer over a page image; batch recognition, camera-photo straightening and "recognise pictures on pages that already have text" (`ocr_recognize`, `ocr_recognize_files`, `page_enhance_camera`). **Partial:** English/unaccented Latin only (`crates/ocr/src/lib.rs:27`); models must be installed (`ocr_status`, `PDFCRAFT_MODELS`); recognised text is withheld when copying is forbidden. **New:** two batch inputs that would write the same output are refused before anything is read.
- Print with Acrobat-style options — ranges (labels allowed, `subset` even/odd by page number), odd/even, reverse, fit/actual/shrink/custom, multiple/cut-stack, booklet, poster, comments/forms, 21 paper presets including US #10 envelope, copies, duplex, grayscale, CUPS driver options — "print as image" at 72–600 dpi, or write a print-ready PDF (`doc_print`, `printers`, `printer_options`, `print_readiness`; `PAPERS` in `crates/print/src/lib.rs:295`). **New:** the chosen paper is sent to the spooler as its `media` option instead of the queue default, and a booklet sets two-sided itself (`crates/automation/src/printing.rs`). `print_readiness` is verification only (image resolution, boxes/bleed, output intents, unembedded fonts, PDF/A-2b structure), not PDF/X.
- Export pages as PNG/JPEG/TIFF (default 150 dpi), all embedded images, reading-order text, Word `.docx`, PowerPoint `.pptx`, HTML or RTF (`doc_export_images`, `doc_export_all_images`, `doc_export_text`, `doc_export_office`; `OfficeFormat::from_extension` at `crates/engine/src/compare.rs:156`). **Partial** for Office (basic/lossy, no layout fidelity). **New:** images exported keep soft-mask Decode opacity ranges; Word table cells use the grid columns they span and covered table slots keep their text in Word/HTML/RTF/PPTX. `doc_export_all_images` writes JPEGs unchanged, everything else as PNG with alpha, and lists JPEG 2000/JBIG2/CCITT/Separation images it cannot decode under `skipped`.
- Reduce File Size and the PDF Optimizer (downsample/compress, discard options) plus a space audit (`crates/optimize`; `doc_reduce`, `doc_optimize`, `doc_audit_space`). **New:** `doc_optimize` adds `compatibility` (`retain`/1.4–2.0), `object_streams` and `lzw_to_flate`; signed documents are refused.
- PDF/A-2b and PDF/A-3b verification and conversion; **partial** (structural rules only, CMYK documents get no output intent) (`crates/preflight/src/lib.rs:31`; `pdfa_verify`, `pdfa_convert`). There is no PDF/UA or PDF/X verification: the CLI `info` and the Standards panel only read what a file *declares*.
- Accessibility Checker with 32 rules in 7 categories, HTML report, review records, alt text, tag property/sibling-order edits and text-only auto-tagging (`crates/a11y/src/lib.rs`; `accessibility_*`). **New:** Table tags expose a `summary` attribute and TH tags a `scope` (Row/Column/Both), readable in `accessibility_tags` and settable with `accessibility_set_tag_property`. **Partial:** no reading-order or table-structure editor, no Read Out Loud.
- Calibrated 2D distance/perimeter/area measurements with CSV export and snapping to endpoints/midpoints/intersections/paths; `measure_scale` accepts a ratio (1 mm = 50 mm for a 1:50 plan), `units_per_point` or two calibration points (`measure_*`; `crates/measure`).
- Edit existing text in place (paragraph or line, rewrapping, formatting incl. underline/line spacing/horizontal scale/character spacing), move 1–1000 mixed objects on a page as one undo step, edit images, edit added text/images/links, and import an openly licensed TTF/OTF to complete a source subset (`crates/edit`; `text_edit`, `text_edit_layout`, `text_paragraphs`, `text_lines`, `object_list`, `object_move`, `image_edit`, `content_update`, `text_font_import`). Paragraph numbers from `text_paragraphs` stay meaningful across edits; a merged paragraph is refused and named in `stale_paragraphs` (`docs/editing-existing-text.md`).
- **New:** Copy Image / Copy Image in Original Format on a page picture (context menu; `crates/engine/src/copy_image.rs`, `crates/ui-egui/src/canvas.rs`) — UI only, no tool.
- Headers/footers with Bates numbering, watermarks (text or image) and backgrounds, with `shrink` and font choice (`doc_header_footer`, `doc_watermark`, `doc_background`, `doc_remove_marks`).
- Document properties: title/author/subject/keywords plus **new** arbitrary custom properties through `doc_set_info` (listed under `custom`; Document Properties ▸ Custom), with XMP counterparts kept in step (`docs/pdf-spec-parity.md` §14.3).

### Platform, interface and packaging
- Native macOS/Windows/Linux/FreeBSD app plus a WebAssembly shell; no account, telemetry or cloud processing (`README.md`).
- 34 selectable interface languages (English + 33 catalogs); Chinese interface text can still show missing-glyph boxes in releases (no embedded Hans face), Arabic layout is not mirrored, and no help is translated (`docs/gaps.md` gaps 5, 14; `docs/localization.md`). Treat translations as UI polish, not a data path; a missing entry falls back to English instead of failing (`cargo xtask i18n-report`).
- The macOS `.app` contains only the GUI: its Contents/MacOS folder holds `PdfCraft`, not `pdfcraft-cli`. The CLI is a separate signed/notarized release asset, `pdfcraft-cli-<version>-macos-universal.zip` (`README.md` §Downloads).
- Web build **partial**: browser print dialog instead of the spooler (`crates/ui-egui/src/web_print.rs`), no crash-recovery store (`crates/ui-egui/src/recovery.rs`), no control-channel transport (native only; `ui.open` errors on the web), and only a subset of fonts embedded (BIZ UDPGothic Regular plus Arab/Telu/Hebr/Thai/Deva faces) (`crates/fonts/build.rs`).
- **New (v0.13.0):** after a successful open/save, macOS re-queues an existing per-file PdfCraft binding when LaunchServices had redirected it (quarantine), never removing quarantine or changing type-wide defaults (`crates/ui-egui/src/macos_association.rs`).
- Robustness at this tag: one shared decode budget per page walk (`crates/cos/src/budget.rs`: 256 MiB and 50 000 form entries per page), 16 MiB MCP request lines, bounded audit, bounded Office-export form depth (50) and count (50 000/page, `truncated_pages`).

## Known limitations and not-implemented

The repo's ranked shortfall list is `docs/gaps.md`; read it before promising anything. These are the ones that change what an agent can safely assign.

- **Rendering is borrowed and fidelity is unmeasured against Acrobat.** Pages come from vendored `hayro` 0.7.1 with many local patches; the replacement renderer and font engine are incomplete (`docs/gaps.md` gaps 2, 12; `vendor/README.md`). README claims about kerning, colour emoji, blend modes and script coverage are **claimed but unverified** here.
- **Existing-text editing is improved but not general.** Latin text with an embeddable matching face works, including subset completion; rotated text, CJK/RTL editing, lists, superscript/subscript, structure-tag retention and arrange/align remain missing or fragile (`docs/gaps.md` gap 3; `docs/editing-existing-text.md`). Paragraph numbers are positional, not stable IDs, across save/reopen.
- **Office import is absent; Office export is lossy.** No Create PDF from Word, Excel, PowerPoint, HTML, web page, PostScript or EPS; Word export flows text/tables and may lose layout; no `.xlsx`, `.doc`, SVG, EPS, PostScript or XML-spreadsheet export (`CONVERTIBLE` at `crates/create/src/lib.rs:516`; `crates/engine/src/compare.rs:156`; `docs/gaps.md` gap 8).
- **`doc_create` text is WinAnsi only**; other characters are refused. `page_add_text` adds WinAnsi text, or Arabic/Hebrew/Thai when the build has those craft-fonts faces; `text_edit` can also use Japanese fallback faces and refuses text no available face can show.
- **OCR reads only unaccented Latin (`en`).** No accents, Cyrillic, Greek, CJK, Arabic, Hebrew or Indic recognition; no editable-text OCR output (`crates/ocr/src/lib.rs:27`; `docs/gaps.md` gap 7).
- **No Preflight; PDF/A only 2b/3b and partial.** No PDF/X or PDF/UA verification, PDF/A-1/4, PDF/E or PDF/VT; CMYK documents get no output intent (`docs/gaps.md` gap 9). `standards_remove_id` only strips a standard's identification.
- **Signatures:** no PKCS #11/smart cards on macOS/Linux, no timestamp-server setting, no online OCSP/CRL fetching (LTV only with caller-supplied evidence), no OS trust store, no signing in the browser (`docs/gaps.md` gap 10). Engine-only TSA APIs are unreachable from CLI/UI.
- **Attachments are one-way:** `attachment_add`/`attachment_delete` exist, `doc_info` lists them, the Attachments panel opens/saves them, but no tool extracts an attachment's bytes.
- **`content_copy` is the only paste path and it is headless-only:** desktop keys/menus were not wired at this tag (`ROADMAP.md`, 2026-10-23), and it copies *added* content only, never page objects or annotations.
- **Forms:** wider Acrobat JavaScript object model incomplete; document actions, form submission, barcode fields and rich-text values missing; XFA flattening incomplete (`docs/gaps.md` gap 15). `form_calculation_order` can report a `cycle` but **cannot fix it**. Text-field tables are capped at 100 × 50, and a cell under 4 pt or a duplicate/period-containing name refuses the whole table.
- **Compare** has Text/Visual filters but no image/annotation/formatting/header-footer filters, no page ranges and no scanned-document support (`docs/gaps.md` gap 21).
- **No scanners** (TWAIN/WIA/ICA/SANE), **no GPU page rasterization**, **no pen pressure**, **no Read Out Loud** (`docs/gaps.md` gap 20). Touch/pen pointer handling was reworked (`crates/ui-egui/src/page_pointer.rs`) but pen pressure is still absent.
- **Preferences are sparse** (interface language, documents/view incl. restore-last-view, identity, Fill & Sign, JavaScript); print-production tools (output preview, separations, ink manager, printer marks, colour conversion) are absent (`docs/gaps.md` gaps 18–19).
- **Performance:** the whole file is held in memory; viewing holds one copy, editing lets go of the old working file but saving still peaks higher; file-backed lazy input is blocked on the renderer (`docs/gaps.md` gap 13). Hostile files are bounded, not fast.
- **UI precision:** moving selected objects across pages, rulers/grids/guides, multiple windows and split view are missing (`docs/gaps.md` gap 16).
- **No AI/cloud features**; a local/opt-in provider is planned (`docs/gaps.md` gap 23).
- **Other PDF gaps:** no certificate encryption, no linearized/Fast-Web-View save, no portfolio view, no `.xdp` opened as a document, no Acrobat `.sequ` action files; JPEG 2000/JBIG2/CCITT/Separation images cannot be exported as images (`docs/file-format-parity.md`; `docs/gaps.md` gap 17; `doc_export_all_images`).
- **Copy- and print-protected documents:** extraction, copy, `content_copy`, compare and OCR text output honour permissions; printing is refused or capped at 150 dpi. Supply the owner password where the caller legitimately has it; never bypass.
- **View-only settings do not save:** page gaps, layer visibility and reading colours change the view and `page_render`, not the file (`docs/page-display.md`; `crates/automation/src/layers.rs`). Page gaps has no JSON tool at this tag: `command_run id=view.page_gaps` fails with "has no headless tool" (`crates/automation/src/conventions.rs:15`); use the app/control channel (`ui.set key=page-gaps`) or `--page-gaps`.
- **The All tools catalogue is a plan, not a promise, in both directions:** it lists entries with a milestone badge that do not exist yet, and whole groups are badged planned (Edit a PDF M7, Protect a PDF M8, Use print production M11, Add search index M12, Use JavaScript M6) although several items inside them work (`crates/engine/src/catalog.rs`).
- **Repo docs lag the code at this tag:** `docs/architecture.md`, `docs/ui-parity.md`, `docs/target-app-parity.md` still say 141 automation tools / 184 commands (real: 179 / 205); `docs/gaps.md` gap 14 still lists Hindi/Indonesian/Korean catalogs as missing although they exist; gap 18 still lists "print as image" as missing although `doc_print.as_image` works; `docs/roadmap.md` M13 says 123 tools. Trust the code and `pdfcraft-cli tools`.

## How to operate

### Launch (macOS)
- App: `/Applications/PdfCraft.app` (bundle id `ai.storyteller.pdfcraft`, minimum macOS 11.0). Binary: `/Applications/PdfCraft.app/Contents/MacOS/PdfCraft`.
- `open -a PdfCraft` or `open -a PdfCraft FILE.pdf`; pass flags with `open -a PdfCraft --args --control ~/.pdfcraft-control.json`.
- `/Applications/PdfCraft.app/Contents/MacOS/PdfCraft --version` prints `pdfcraft 0.14.0` and `-h`/`--help` prints usage, both without opening a window. `pdfcraft-cli --version` prints its own version.
- Launch parsing (`apps/pdfcraft/src/main.rs:61`): explicit flags are `--version`, `-h`/`--help`, `--control FILE`, `--create-images [images…]`, `--new-window`; **every other `--key value` is a view/preference key** handed to `set_option` (`crates/ui-egui/src/lib.rs:2885`, 46 keys). Unknown keys fail with a message and are logged.
- View keys: `--page N`, `--zoom 150`, `--layout single|continuous|two-up|two-page`, `--continuous on|off`, `--page-gaps on|off`, `--default-page-gaps on|off`, `--cover on|off`, `--rotate 0|90|180|270`, `--select <ranges>`, `--find <text>`, `--comment PAGE:INDEX`, `--layer "Name=on|off"`, `--grid-zoom 50..300`, `--thumbnail-zoom 50..150`, `--organize on|off`, `--fields on|off`, `--always-default-view on|off`.
- Panels/mode/tools: `--panel comments|bookmarks|pages|fields|layers|attachments|signatures|accessibility|tags|search|compare|none`, `--mode all|read|edit|convert|sign`, `--default-mode …`, `--tool <catalogue id>`, `--quick <quick tool>`, `--tools full|expanded|collapsed`, `--tools-side left|right`, `--left open|closed`, `--home on`, `--palette <query>`, `--combine-view grid|list`, `--combine-zoom 60..200`, and `--dialog properties|security|fonts|custom|advanced|space-audit|shortcuts|split|protect|page-boxes|header-footer|watermark|background|export-image|word-count|export-text|export-all-images|accessibility-options|recognize-text|js-console|document-js|preferences|compare-files|action-wizard|pdfa|signature|optimize|sign|certify|number-pages|none`.
- Preferences: `--theme light|dark|system`, `--language auto|<code>`, `--author <name>`, `--date-format …`, `--date-language …`, `--ui-scale …`, `--system-title-bar true|false`, `--flatten-fill-sign true|false`, `--secured-notice true|false`, `--notice on|off`, `--comment-tool-pinned true|false`, `--hide-empty-highlight-hover true|false`. Keys are taken verbatim, so `scroll_speed`/`animation_effects` keep their underscores.
- One window, several documents as tabs; by default the All tools/mode rail is on the left and an inspector panel docks on the right; panels can be floated, tab-stacked or split (`crates/ui-egui/src/docking.rs`). Window size/position is restored. On Windows and Linux/BSD a launch that only names files hands them to the running instance as tabs; on macOS Finder opens do the same through Apple events; `--new-window` starts an independent window (`apps/pdfcraft/src/single_instance.rs`; `apps/pdfcraft/src/apple_events.rs`).

### Headless CLI (not installed with the app)
`pdfcraft-cli` is a separate signed/notarized asset: `pdfcraft-cli-<version>-macos-universal.zip`. Put it on `PATH` (or `cargo install --path apps/pdfcraft-cli --locked`, `docs/mcp.md`). Use the same release as the app where possible; the control protocol is internal and may change between versions.

Documented subcommands: `info`, `render`, `text`, `edit`, `combine`, `extract`, `split`, `check`, `audit`, `batch`, `tools`, `run`, `ui`, `mcp`; the internal `check-one` worker is spawned by `check` (`apps/pdfcraft-cli/src/main.rs:110`).

```sh
pdfcraft-cli info report.pdf          # + declared pdfa/pdfua, output_intents, xfa
pdfcraft-cli text paper.pdf --page 3
pdfcraft-cli render paper.pdf --page 1 --dpi 144 --out p1.png    # .png/.jpg/.tif/.pam
pdfcraft-cli edit in.pdf --rotate 1,2:90 --delete 5 --title "Q3" --out out.pdf
pdfcraft-cli combine a.pdf b.pdf --out combined.pdf
pdfcraft-cli extract report.pdf --pages 1,3,5-8 --out highlights.pdf
pdfcraft-cli split report.pdf --every 10 --out-dir parts/
pdfcraft-cli batch scans --recursive --steps ocr,optimize --out-dir out --root .
pdfcraft-cli tools | jq '.[].name'
pdfcraft-cli run text_find doc=1 query=invoice
pdfcraft-cli run --script steps.json --root ./work --report
pdfcraft-cli audit maybe-redacted.pdf      # exits non-zero on findings
```

A script is a JSON array of `{"tool": "...", "args": {...}}` steps; one session keeps document ids stable (`doc_open` → 1). With `--root DIR` every read/write path, including a step's `"out"`, must resolve inside DIR. `--report` prints one JSON document with per-step status/result. An argument that is not UTF-8 is a usage error (never a panic).

### MCP (opt-in, stdio, no port)
Add `{"command":"pdfcraft-cli","args":["mcp","--root","work/pdfs"]}` to the agent's MCP config (`docs/mcp.md`; `crates/automation/src/mcp.rs`). `--compact` makes `tools/list` return 15 core tools plus `tool_search` and `tool_call` (17 entries; the README says "about ten", the code says 15); `tools/call` still accepts any of the 179 names. For least privilege use `--automation-read-root` and `--automation-write-root` instead of one broad `--root`; a root left out grants none of its access, and another UNC share/device namespace is refused by name before resolution. Resources: `pdfcraft://document`, `pdfcraft://commands` and the templates `pdfcraft://doc/{doc}/info`, `…/text`, `…/page/{page}/text`, `…/page/{page}/image{?dpi}`. Request lines over 16 MiB get a JSON-RPC error instead of memory growth; a panic in any method becomes an error reply.

### UI control channel (opt-in)
Start the app with `--control ~/.pdfcraft-control.json`, then use `pdfcraft-cli ui --control ~/.pdfcraft-control.json …`:
`inspect query=…`, `click label="Organize pages"`, `key key=K modifiers='["command"]'`, `command id=comment.square`, `drag from='[400,300]' to='[600,420]'`, `screenshot --out window.png`, `quit`.
The file holds the loopback port and a random token; the CLI authenticates first and refuses a symlink, a non-regular file, and on Unix a file owned by or readable/writable by another user (`apps/pdfcraft-cli/src/main.rs` `read_control_file`). The app accepts 8 unauthenticated connections at a time, each with 10 s to authenticate, and times out a blocked write after 30 s (`crates/ui-egui/src/control.rs` `Limits`). The 17 methods are `ui.state`, `ui.commands`, `ui.command`, `ui.set`, `ui.open`, `ui.inspect`, `ui.click`, `ui.focus`, `ui.resize`, `ui.quit`, `ui.drag`, `ui.move`, `ui.type`, `ui.key`, `ui.screenshot`, `ui.dock`, `ui.dock.reset` (`crates/ui-egui/src/control.rs:282`). `ui.state.active` reports `page`, `zoom_percent`, `layout`, `continuous`, `page_gaps`, `organize`, `grid_zoom`, `thumbnail_zoom`, `selected_pages`, `page_errors`, `viewport` and `pages_on_screen` rectangles for aiming clicks. `ui.dock` takes `{operation, panel}` with `open|close|activate|float(rect)|move(target, zone)|moveFloating(rect)|resizeSplit(path,size)|setStackOpen(open)|resizeStack(height)`. `ui.quit` asks the normal Save/Don't save/Cancel prompt and never discards silently.

### Document model, save and export
- The PDF is the document; there is no sidecar project file. Converted images/text are new unsaved PDFs (`crates/ui-egui/src/files.rs`; `crates/ui-egui/src/create_ui.rs`).
- Edits stay in memory as undo steps; autosave writes a recovery snapshot every 60 s and offers recovery after a crash (`AUTOSAVE_SECS`, `crates/ui-egui/src/recovery.rs:28`). Encrypted documents stay encrypted on disk.
- Save (`⌘S`) writes an **incremental update appended to the same file**, preserving the original bytes and prior signatures; Save As (or any new path) is a full rewrite; writes are atomic through a staging file (`crates/cos/src/writer.rs:199`; `crates/platform/src/staging.rs:126`). `doc_save` `full: true` forces the rewrite; `flatten_fill_sign: true` bakes Fill & Sign marks first and removes those annotations.
- A full rewrite happens where it must: redaction, PDF/A conversion, password change, sanitize, Save As with garbage collection, or print imposition; signed documents are protected from optimizer rewrites.
- Export formats are chosen by extension: images `.png/.jpg/.tif`; Office `.docx/.pptx/.html/.htm/.rtf`; form/comment data `.xfdf/.fdf/.xml/.xdp/.csv/.txt` (also `.tab`/`.tsv` on import, `crates/xfdf/src/lib.rs:52`); text `.txt`; a print job goes to a printer name or a PDF path (`crates/engine/src/compare.rs:156`; `doc_print`). Page-image export defaults to 150 dpi; JPEG/TIFF are flattened onto white.

### Panels and keyboard (verified in the command registry)
Panels: comments, bookmarks, pages, fields, layers, attachments, signatures, accessibility, tags, search, compare (`crates/ui-egui/src/lib.rs` `set_option` "panel").

`⌘K` command palette · `⌘F` find / `⇧⌘F` advanced search · `⌘G` / `⇧⌘G` next/previous match · `⌘Z` / `⇧⌘Z` undo/redo · `⌘S` / `⇧⌘S` save / save as · `⌘O` open · `⌘W` close / `⇧⌘W` close all · `⌘P` print · `⌘D` document properties · `⌘J` JavaScript console · `⌘B` add bookmark · `⌘,` preferences · `⌘L` full screen · `⌃⌘H` Read mode · `⌘3` fit visible · `⌃Tab` / `⌃⇧Tab` next/previous tab · `⌘[` / `⌘]` previous/next view · `⇧⌘N` go to page (`crates/engine/src/commands.rs:165`; `crates/ui-egui/src/canvas.rs`). On Windows/Linux the command modifier is Ctrl; labels follow the interface language, machine ids never change. With a comment selected, arrow keys nudge it one screen pixel (⌘/Ctrl or Shift = ten).

## Working with an AI agent

**Legitimate work.**
- Prefer the headless tool table over GUI automation. `pdfcraft-cli tools` (or MCP `tools/list`) is the capability contract for the installed version; `command_list` maps UI commands to tools, and 134 of 205 commands have no tool — check before you promise one.
- Prepare inputs: images (PNG/JPEG/TIFF/GIF/BMP/JP2/J2K/JPX) and `.txt` for `doc_create`; XFDF/FDF/XML/XDP/CSV/tab-delimited text for `doc_import_data`; FDF/XFDF or filled PDFs for `form_merge_data`; `.p12`/`.pfx`, a Keychain/Windows-store identity, or a `.p7b`/`.p7c`/`.cer`/`.crt`/`.pem`/`.der` trust bundle for signing/trust; openly licensed TTF/OTF for `text_font_import`; document-level attachment files for `attachment_add`.
- Use the v0.14.0 additions deliberately:
  - `attachment_add`/`attachment_delete` for document-level attachments; there is still no read-back tool — use the Attachments panel or an external tool.
  - `bookmark_set_style` after `bookmark_list` verifies colour/style; it never changes targets.
  - `content_copy` to duplicate an added text box/image into another open document; pass `to_doc`/`to_page`/`at` explicitly, and remember the desktop keys are not wired.
  - `comment_list` returns per-reply `status`/`checkmark`; when an `id` is shared by several comments, pass `page` + `index` (`comment_*` refuse a shared id).
  - `doc_set_info` with a non-standard key creates a custom document property (no spaces/delimiters/`/`/`#`, ≤127 bytes); empty value removes it.
- Inspect and repair: `doc_info` exposes warnings, repairs and the initial destination; `doc_inspect` summarizes open documents; `doc_revisions` + `doc_open_revision` show what each incremental save appended; `pdfcraft-cli info` tells you which PDF/A or PDF/UA level a file *claims* (not whether it complies).
- Verify with independent observations: `page_render`/`render_preview` for pixels, `text_extract` for text, `doc_audit_redactions` after redaction, `pdfa_verify` after PDF/A conversion, `print_readiness` before printing, and external `qpdf`, `pdftotext`, `pdftoppm`, `pdfsig` or a real viewer where installed. The repo itself uses hayro, qpdf and poppler as oracles (`README.md` §How it's built).
- For UI work, launch with `--control`, use `ui.inspect` to get the accessibility tree, click by unique label or widget id, then `ui.screenshot` to confirm. `ui.state.active.pages_on_screen` gives page rectangles; never reuse coordinates from an older launch.

**Must not.**
- Do not drive the GUI blind or assume a deterministic layout across launches; use the control channel and `inspect`.
- Do not assume Office/HTML/PostScript import, `.xlsx` export, SVG/EPS/PS/JP2 export, PDF/X or PDF/UA verification, or OCR in any language but English.
- Do not rewrite signed documents destructively; incremental save keeps signatures valid, but any full rewrite invalidates certification. Keep the original bytes.
- Do not use `doc_create` for non-WinAnsi text; it will refuse. Use `page_add_text`/`text_edit` with an embeddable face for other scripts.
- Do not expect a tool to extract an attachment, to copy page objects with `content_copy`, or to persist `layer_set`/page gaps in the PDF.
- Do not expect a timestamp server or PKCS #11 token in the CLI/UI; signing is PAdES B-B, and timestamp validation only covers tokens already in the file.
- Do not use `form_calculation_order fix=true` to repair a formula `cycle`, or `standards_remove_id` as a compliance fix. Both report their limits.
- Do not put the control file in a shared folder or assume the MCP server/control channel is on; both are opt-in and loopback/stdio only.
- Do not assume `pdfcraft-cli` exists on a machine with only the macOS app installed.

## Verification protocol

Alpha-software discipline for every session:
1. **Throwaway round-trip first.** In a scratch folder, open → edit → `doc_save` to a *new* path → reopen with `pdfcraft-cli info`/`text` and in Preview/Acrobat or `qpdf --check`. Reopening only in PdfCraft proves little about other readers.
2. **Never trust a silent export.** Re-render exported images, re-read exported text, and open `.docx/.pptx` in Word/PowerPoint or LibreOffice before declaring success; Office export is known lossy — compare against page images.
3. **Redaction is not done until audited.** Run `pdfcraft-cli audit` (or `doc_audit_redactions`) on the saved file; the internal pass in `redact_apply` is a gate, not a substitute. The audit fails closed on unreadable content and withholds covered text when copying is forbidden, so a "clean" run on a hostile file is an error, not a pass.
4. **Signatures:** after signing, use `sign_list` (and `pdfsig`/OpenSSL if available) on the saved file; check "changes after signing", the revision the signature covers, and any embedded timestamp's trust. `sign_document` produces PAdES B-B with no timestamp at all.
5. **Print and view settings:** before a print job, check `print_readiness` and the document's permissions; a printing-forbidden document fails and a low-quality-only document rasterizes at ≤150 dpi. Page gaps, layer visibility, reading colours and restore-last-view are view state — verify them with `page_render`, not by expecting the file to change.
6. **Backups and versions.** Keep the original PDF before any full rewrite. Check `/Applications/PdfCraft.app/Contents/MacOS/PdfCraft --version` and `pdfcraft-cli --version` before trusting this skill's flags or tools; update apps only between projects.
7. **Hostile or huge files.** Use `pdfcraft-cli check` (a separate child process per file) when a file misbehaves. Bounds are explicit (page decode budget, 16 MiB MCP lines, audit budget, Office-export form limits) — hitting one is a documented refusal, not corruption. Read the app's `logs/pdfcraft.log` under the user's Application Support/PdfCraft folder for internal errors.

## Sources & evidence

- Repo: https://github.com/storytold/pdfcraft · tag `v0.14.0` · inspected commit `5a78b223871add8e3883856205cc653d741e0e94` ("Release 0.14.0", 2026-10-25); date of inspection 2026-10-26. The checkout is a shallow worktree pinned to the release tag; it was not modified or built.
- Installed app: `/Applications/PdfCraft.app` 0.14.0, bundle id `ai.storyteller.pdfcraft`, minimum macOS 11.0, `PdfCraftBuildCommit = 5a78b223871add8e3883856205cc653d741e0e94`; binary `--version` → `pdfcraft 0.14.0`. The macOS bundle contains only `PdfCraft`, not `pdfcraft-cli`.
- Counts were machine-derived from code at this tag and diffed against the published v0.12.0 files (`crates/automation/src/tools.rs`, `crates/engine/src/commands.rs`, `crates/engine/src/catalog.rs`, `crates/ui-egui/src/control.rs`, `crates/ui-egui/src/i18n/mod.rs`, `apps/pdfcraft-cli/src/main.rs`): tools 175 → 179, commands 204 → 205, control methods 17 → 17, languages 34 → 34, CLI unchanged.
- Key files read: `README.md`, `ROADMAP.md`, `Cargo.toml`, `vendor/README.md`, `docs/gaps.md`, `docs/target-app-parity.md`, `docs/architecture.md`, `docs/mcp.md`, `docs/ui-parity.md`, `docs/file-format-parity.md`, `docs/page-display.md`, `docs/localization.md`, `docs/localization-parity.md`, `docs/pdf-spec-parity.md`, `docs/cli-batch.md`, `docs/editing-existing-text.md`, `docs/word-count.md`, `docs/hardware-parity.md`, `docs/roadmap.md`, `apps/pdfcraft/src/main.rs`, `apps/pdfcraft/src/single_instance.rs`, `apps/pdfcraft/src/apple_events.rs`, `apps/pdfcraft-cli/src/main.rs`, `crates/automation/src/tools.rs`, `crates/automation/src/lib.rs`, `crates/automation/src/mcp.rs`, `crates/automation/src/file_access.rs`, `crates/automation/src/comments.rs`, `crates/automation/src/printing.rs`, `crates/automation/src/content.rs`, `crates/automation/src/layers.rs`, `crates/automation/src/a11y.rs`, `crates/engine/src/commands.rs`, `crates/engine/src/catalog.rs`, `crates/engine/src/compare.rs`, `crates/engine/src/lib.rs`, `crates/engine/src/js.rs`, `crates/engine/src/copy_image.rs`, `crates/engine/src/actions.rs`, `crates/ui-egui/src/lib.rs`, `crates/ui-egui/src/control.rs`, `crates/ui-egui/src/canvas.rs`, `crates/ui-egui/src/docking.rs`, `crates/ui-egui/src/recovery.rs`, `crates/ui-egui/src/last_view.rs`, `crates/ui-egui/src/all_tools_ui.rs`, `crates/ui-egui/src/macos_association.rs`, `crates/ui-egui/src/page_pointer.rs`, `crates/ui-egui/src/web_print.rs`, `crates/ui-egui/src/compare_ui.rs`, `crates/ui-egui/src/calc_order_ui.rs`, `crates/ui-egui/src/field_table_ui.rs`, `crates/ui-egui/src/format_text_ui.rs`, `crates/ui-egui/src/standards_ui.rs`, `crates/ui-egui/src/i18n/mod.rs`, the sources of `crates/create`, `crates/crypt`, `crates/redact`, `crates/audit`, `crates/preflight`, `crates/ocr`, `crates/a11y`, `crates/xfdf`, `crates/measure`, `crates/edit`, `crates/organize`, `crates/sign`, `crates/forms`, `crates/print`, `crates/fonts` and `crates/cos`, `apps/pdfcraft-web`, `/Applications/PdfCraft.app/Contents/Info.plist`.
- Shared libraries consulted: `storytold/craft-libs` (`craft-ui`, `craft-quit`, `craft-print`, `craft-docpath` revs pinned in `Cargo.toml`).
- Companion files: `evidence.md` (claim → evidence → tier table) and `references/automation-tools.md` (all 179 tool names, titles, hints and command mappings).