Skip to content
Agents tracked: 440 Downloads (7d): 202M down 19.5% GitHub stars: 10.4M Releases (7d): 607 Agent status: 1 with issuesSince last limit reset: Claude 28d · Codex 0d Updated Oct 21, 2026

Starter kit for a PDF tool

A recipe for a PDF toolbox that runs on your machine, so files never go to an online converter: compress, merge, split, rotate, stamp and protect, each result checked against the original. For Claude Code, Cursor, Codex or Copilot, with exact versions, licenses and the traps a test build ran into.

New to kits? Read how to use a kit.

How the kit fits together

Your agent reads the brief, builds with these parts and checks its own work before you ship. Click a part to see why it was picked.

File for your agent

AGENTS.md

The plan your agent follows, a step at a time, with a check that must pass before the next step. It also holds the stack with exact versions, the licenses and the known traps.

File for your agent

first-prompt.txt

The first message you paste into your agent. It points the agent at AGENTS.md and tells it to stop after step 1 and report.

File for your agent

.mcp.json

The MCP servers the brief lists, set up for Claude Code. The kit builder writes the same setup for Cursor, Codex or Copilot.

File for your agent

CREDITS.md

The license record of every third-party file. The brief tells the agent to add a row for every file it brings in.

You bring this

Your coding agent

The kit works with any of these. Pick yours in the kit builder and the setup files change to match.

Library knowledge

Context7

4.3.0MIT

pikepdf changes its API between major versions, and models mix it up with PyPDF2 and PyMuPDF.

By Upstash · In 1,266 of 29,413 sampled repos · v4.3.0 on npm · Agent can use it through MCP

Tool and asset data

AgentGid

If the agent needs another library or font, it asks AgentGid for one that fits your license constraints.

By AgentGid · Agent can use it through MCP

Runtime

Python 3.12

official source

One Python version has to satisfy every package below.

Nothing to install

PDF engine

pikepdf

10.17.0MPL-2.0

Opens, changes and saves the files. It has to keep what each page shows while it rewrites the structure underneath. Built on qpdf: repairs damaged files on open, rewrites streams losslessly, and gives direct access to images for recompression.

v10.17.0 · MPL-2.0 · Installs from a package registry

2 other candidates also fit.

Merging

pypdf

6.20.1BSD-3-Clause

Joining files has to keep bookmarks and form fields. Of the two permissive libraries, only pypdf's PdfWriter.append kept both in our check.

In 60 of 1,546 Python agent projects (3.9%) · #12 of 99 in files, images and media · v6.20.1 (pypi registry) · BSD-3-Clause · Installs from a package registry

Image recompression

Pillow

12.3.0MIT-CMU

Scans and photos are most of a PDF's size. Pillow scales them to the resolution they are shown at and writes JPEG.

In 230 of 1,546 Python agent projects (14.9%) · #2 of 80 in files, images and media · v12.3.0, July 1, 2026 · MIT-CMU · Installs from a package registry

Stamps and test files

ReportLab

5.0.1BSD-3-Clause

Watermarks and page numbers are drawn as a one-page PDF and laid over each page; the same library makes the test PDFs.

v5.0.1 · BSD-3-Clause · Installs from a package registry

Stamp font · from Google Fonts

Inter

OFL-1.1

ReportLab's built-in fonts have no Cyrillic: a Russian watermark comes out as black boxes. A TTF file with Latin and Cyrillic fixes that.

SIL OFL 1.1 (most), Apache-2.0 (some), Ubuntu Font License 1.0 · Commercial use OK · No credit needed · Free · 856 KB · variable font · Agent can fetch it through an API

Page rendering

pypdfium2

5.14.0Apache-2.0 or BSD-3-Clause

Draws pages to images, so a check can compare each page before and after a command, and the web page can show previews.

v5.14.0 · Apache-2.0 or BSD-3-Clause (PDFium) · Installs from a package registry

Strongest compression

Ghostscript

AGPL-3.0 or Artifex commercial licenseoptional, offofficial source

Ghostscript rewrites the whole file and often wins on scans, but it is AGPL and a separate program.

AGPL-3.0 or Artifex commercial license · Installs from a package registry

AGPL license (AGPL-3.0 or Artifex commercial license): if people use your project over a network, for example as a web service, you must offer them its source code. That holds for non-commercial services too.

When the agent is done

9 checks

  • python -m pdftool make-fixtures writes the test PDFs into tests/fixtures/: a 3-page text file with known text, a photo file with 300-dpi images, a file with a form field, a file with bookmarks, a rotated page and a password-protected file.
  • merge joins files in the given order and keeps bookmarks and form fields (a test reads both back with pypdf).
  • split writes one file per range (1-3,5,7-), pages keeps, deletes or reorders pages (3,1,2), rotate turns chosen pages by 90, 180 or 270 degrees relative to their current rotation.
  • compress on the photo file at the default 150 dpi makes it at least 60% smaller; page count, page sizes and the extracted text are unchanged, and each page rendered before and after differs by less than 8 on average (0 to 255 scale).
  • compress never hands back a bigger file: when the result is not smaller, it copies the input byte for byte to <name>-compress.pdf and says so.
  • stamp writes a diagonal watermark or page numbers in Latin and Cyrillic; extracting the text of a stamped page gives the stamp back letter for letter, and a stamped rotated page shows the stamp upright.
  • protect sets a password, unlock removes it with the right password, and a wrong password ends with a clear message and exit code 2.
  • Every result passes pikepdf.Pdf.open(out, password=...).check_pdf_syntax() == [] (the password only for encrypted results), and no command ever writes over its input file.
  • Tests pass with python -m pytest.
After the agent

Left to you

  • Open one compressed file of your own in your usual viewer and printer before relying on the default quality: 150 dpi suits screens and office printers, not print shops.
Files for your agentAgent tools (MCP)CodeArt, sound and contentChecksOptional, off by default

What you get

The result

A Python command line tool with one command per job: info, merge, split, pages (keep, delete, reorder), rotate, compress, stamp (watermark or page numbers) and protect/unlock. Every command writes a new file and checks it against the original.

7 files
Ready for your agent
  • AGENTS.md: the plan, with a check after every step
  • first-prompt.txt, install.txt, .mcp.json
  • CREDITS.md, CLAUDE.md, kit.json
10 parts
Every part is free or has a free tier
  • Toolbox: MPL-2.0, BSD-3-Clause, MIT-CMU, OFL-1.1, Apache-2.0 or BSD-3-Clause
  • Agent tools: MIT
1 of 1 asset sources allow commercial use with no credit needed. Plus 1 optional part, off by default.
9 / 9
Checks met in the last test build
  • Build 2, Oct 12, 2026
  • 9 things in the brief reported, 1 serious
  • Findings went back into recipe v0.3
The brief counts it as done when these 9 checks pass
  • python -m pdftool make-fixtures writes the test PDFs into tests/fixtures/: a 3-page text file with known text, a photo file with 300-dpi images, a file with a form field, a file with bookmarks, a rotated page and a password-protected file.
  • merge joins files in the given order and keeps bookmarks and form fields (a test reads both back with pypdf).
  • split writes one file per range (1-3,5,7-), pages keeps, deletes or reorders pages (3,1,2), rotate turns chosen pages by 90, 180 or 270 degrees relative to their current rotation.
  • compress on the photo file at the default 150 dpi makes it at least 60% smaller; page count, page sizes and the extracted text are unchanged, and each page rendered before and after differs by less than 8 on average (0 to 255 scale).
  • compress never hands back a bigger file: when the result is not smaller, it copies the input byte for byte to <name>-compress.pdf and says so.
  • stamp writes a diagonal watermark or page numbers in Latin and Cyrillic; extracting the text of a stamped page gives the stamp back letter for letter, and a stamped rotated page shows the stamp upright.
  • protect sets a password, unlock removes it with the right password, and a wrong password ends with a clear message and exit code 2.
  • Every result passes pikepdf.Pdf.open(out, password=...).check_pdf_syntax() == [] (the password only for encrypted results), and no command ever writes over its input file.
  • Tests pass with python -m pytest.

Left to you, because no check can do it: Open one compressed file of your own in your usual viewer and printer before relying on the default quality: 150 dpi suits screens and office printers, not print shops.

The parts and why each was picked

Defaults for commercial use, free parts and Claude Code. Change them.

Toolbox

Runtime
Python 3.12 official source

One Python version has to satisfy every package below.

Nothing to install

PDF engine
pikepdf 10.17.0

Opens, changes and saves the files. It has to keep what each page shows while it rewrites the structure underneath. Built on qpdf: repairs damaged files on open, rewrites streams losslessly, and gives direct access to images for recompression.

v10.17.0 · MPL-2.0 · Installs from a package registry

Also fits: pypdf, PyMuPDF.

Merging
pypdf 6.20.1

Joining files has to keep bookmarks and form fields. Of the two permissive libraries, only pypdf's PdfWriter.append kept both in our check.

In 60 of 1,546 Python agent projects (3.9%) · #12 of 99 in files, images and media · v6.20.1 (pypi registry) · BSD-3-Clause · Installs from a package registry

Image recompression
Pillow 12.3.0

Scans and photos are most of a PDF's size. Pillow scales them to the resolution they are shown at and writes JPEG.

In 230 of 1,546 Python agent projects (14.9%) · #2 of 80 in files, images and media · v12.3.0, July 1, 2026 · MIT-CMU · Installs from a package registry

Stamps and test files
ReportLab 5.0.1

Watermarks and page numbers are drawn as a one-page PDF and laid over each page; the same library makes the test PDFs.

v5.0.1 · BSD-3-Clause · Installs from a package registry

Stamp font

ReportLab's built-in fonts have no Cyrillic: a Russian watermark comes out as black boxes. A TTF file with Latin and Cyrillic fixes that.

SIL OFL 1.1 (most), Apache-2.0 (some), Ubuntu Font License 1.0 · Commercial use OK · No credit needed · Free · 856 KB · variable font · Agent can fetch it through an API

Page rendering
pypdfium2 5.14.0

Draws pages to images, so a check can compare each page before and after a command, and the web page can show previews.

v5.14.0 · Apache-2.0 or BSD-3-Clause (PDFium) · Installs from a package registry

Strongest compressionoptional, off
Ghostscript official source

Ghostscript rewrites the whole file and often wins on scans, but it is AGPL and a separate program.

AGPL-3.0 or Artifex commercial license · Installs from a package registry

AGPL license (AGPL-3.0 or Artifex commercial license): if people use your project over a network, for example as a web service, you must offer them its source code. That holds for non-commercial services too.

Installed along with them: pytest 9.1.1.

For your agent

Library knowledge
Context7 4.3.0

pikepdf changes its API between major versions, and models mix it up with PyPDF2 and PyMuPDF.

By Upstash · In 1,266 of 29,413 sampled repos · v4.3.0 on npm · Agent can use it through MCP

Tool and asset data

If the agent needs another library or font, it asks AgentGid for one that fits your license constraints.

By AgentGid · Agent can use it through MCP

Licenses of the assets

SourceUsed forTermsLicense page
Google FontsInter Stamp font Commercial use OK; No credit needed; Can ship inside your build, with conditions SIL OFL 1.1 (most), Apache-2.0 (some), Ubuntu Font License 1.0read Oct 10, 2026

License terms as the sources state them, read on the dates shown. The kit's CREDITS.md starts with these rows and the brief tells the agent to add one for every file it brings in. This is a record, not legal advice.

The plan your agent follows

The agent works one step at a time and does not start a step until the previous one meets its "Done when" lines. The full instructions, with code, are in AGENTS.md.

  1. Scaffold · done when:
    • python -m pdftool --help lists the commands and python -m pytest runs.
    • The kit files listed under "Before you start" are still there.
  2. Test files and checks · done when:
    • The fixtures open in pypdfium2 and the checks pass when a file is compared with itself.
  3. Pages: split, select, reorder, rotate · done when:
    • Tests cover ranges, reordering, deleting and rotating, and the extracted text of each output page matches the source page it came from.
  4. Merge · done when:
    • A test merges the bookmark file and the form file and reads back the bookmarks of the bookmark file and the field fullname with its value.
  5. Compress · done when:
    • The photo fixture shrinks by at least 60% at 150 dpi and passes every check; the text fixture never grows.
  6. Stamp · done when:
    • Text extracted from a stamped page contains the stamp letter for letter, in Latin and Cyrillic, and the rotated fixture shows the stamp upright and full size when rendered, with the page number at the bottom of the page as displayed.
  7. Protect and unlock · done when:
    • A test protects the text fixture, fails to open it without a password, unlocks it with the right one and gets the same text back.
  8. Verify · done when:
    • Every line under Definition of done is true, and anything that could not be verified is named in PROGRESS.md.

Known traps

What test builds and the official docs showed going wrong with these parts. Each one is in the brief, so the agent reads it before it gets there.

  • pikepdf's pages.extend() from another file drops interactive form fields (it warns with PageCopyWarning); Pdf.add_pages_from() keeps the fields but not the bookmarks. pypdf's PdfWriter.append() kept both. measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • Keep a source Pdf open until the file you copy its pages into is saved. If the source is closed or garbage-collected first, its pages become destroyed objects and the save fails. measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • In pikepdf 10.17 page.images prints a DeprecationWarning; page.get_images() replaces it and also finds images nested inside form XObjects. measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • There is no Pdf.check(): the syntax check is pdf.check_pdf_syntax(), which returns a list of problems (empty when the file is fine). measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • After replacing an image's data with JPEG you must also set Width, Height, ColorSpace and BitsPerComponent and delete DecodeParms; otherwise the old values describe new data and viewers draw garbage. pikepdf docs and our check
  • ReportLab's built-in fonts (Helvetica and the rest) have no Cyrillic: "Черновик" comes out as eight black boxes. Register a TTF font with Cyrillic, such as Inter[opsz,wght].ttf. measured with reportlab 5.0.1, Oct 12, 2026
  • pypdf reads AES-encrypted PDFs (the AES-256 files protect makes) only with the extra package cryptography; without it, decrypt() raises "DependencyError: cryptography>=3.1 is required for AES algorithm". measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • pikepdf.Encryption(...) without allow= uses pikepdf.Permissions(), whose modify_assembly is False: the file forbids inserting, deleting and rotating pages. measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • add_overlay on a page with /Rotate 90 keeps the stamp upright but fits it into the page's box as stored, which is landscape when the page shows portrait: a portrait-sized stamp is scaled to 70.7% and centred. Draw the stamp at the displayed size and pass rect=Rectangle(page.mediabox). ReportLab's setPageRotation(90) swaps the stamp page's box too, so text drawn at portrait coordinates falls off it. measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026
  • A PDF that has only an owner password (restrictions, no password to open) opens in pikepdf without any password, and a plain save writes it without the restrictions. measured with pikepdf 10.17.0, pypdf 6.20.1 and reportlab 5.0.1, Oct 12, 2026

Checks on this kit

  • Note pikepdf 10.17.0 requires Python 3.11 or newer; the kit uses 3.12. Source

What happened when an agent built from it

The recipe was given to a fresh coding agent in a clean sandbox, twice. The agent got only the kit files. It had to build the project and write down everything in the brief that was wrong, missing or unclear.

Build 1 · brief v0.1 · Oct 12, 2026

9 of 9
lines of the definition of done met
8
things in the brief reported as wrong, missing or unclear
2
serious: would have shipped a wrong result

Files the tool protected could not be split or merged again, because pikepdf's default permissions forbid page assembly. On a rotated page the stamp shrank to about 70% and page numbers landed mid-page.

Build 2 · brief v0.2 · Oct 12, 2026

9 of 9
lines of the definition of done met
9
things in the brief reported as wrong, missing or unclear
1
serious: would have shipped a security hole

No retries. The brief did not say to keep the encryption of an encrypted input, so a plain save would have written split or stamped copies without a password; the test agent kept it on its own. Also fixed: page reordering inside a copy of the source (keeps form fields), fixture permissions, password variables, and how to measure an image's drawn size.

Result of the last build. A command-line PDF tool with merge, split, reorder, rotate, compress, stamp, protect and unlock; 85 tests pass, also in a fresh clone set up from the README alone. A 29.4 MB photo PDF compressed to 298 KB at 150 dpi with the text and page sizes unchanged. Its findings went back into the recipe, which is now at v0.3. That version has not been built again as a whole.

Checked again on Oct 19, 2026. AgentGid checks every recipe each week, without a model: 6 pinned packages all still exist on their registries, 2 of them have a newer release than the tested pin; the pip lines resolve together; 19 links in the brief: all open. npm lines are checked pin by pin, not installed.

Not checked by anyone yet

  • A PDF of the person's own, and how compressed files print
  • The web page and the Ghostscript engine
  • macOS and Windows

The kit files

Put them in an empty project folder, open your coding agent there and paste the first prompt (Claude Code first asks you to approve the MCP servers in .mcp.json). These are the files for Claude Code with the default answers; the kit builder writes them for Cursor, Codex, Copilot or another agent, and for other choices. Full guide: how to use a kit.

FileWhat it isSize
AGENTS.mdThe brief: what to build, stack and versions, licenses, plan with checks, known traps249 lines
CREDITS.mdThe license record of every third-party file23 lines
first-prompt.txtYour first message to the agent8 lines
install.txtInstall commands with exact versions4 lines
CLAUDE.mdOne line that imports AGENTS.md for Claude Code1 lines
.mcp.jsonThe MCP servers the brief lists, for Claude Code15 lines
kit.jsonThe kit as data: parts, versions, checks196 lines

Download all (.zip)

first-prompt.txt the agent stops after each step and reports
Read AGENTS.md from top to bottom before you do anything else. The kit files it lists are already in this folder.

Then do step 1 of the plan and stop. Report back with:
1. the commands you ran,
2. what each "Done when" check showed (a screenshot or the output),
3. anything in AGENTS.md that turned out to be wrong, missing or out of date.

Do not start step 2 until I reply.
Or let it run the whole plan
Read AGENTS.md from top to bottom before you do anything else. The kit files it lists are already in this folder.

Then work through the plan in order. After each step, run its "Done when" checks yourself and write one line in PROGRESS.md: the step, what you checked, and the result.
You may install the packages and download the files that AGENTS.md lists without asking. Stop and ask me only for what its "Before you start" section says needs a person.
When a check fails, fix the cause and run it again. If it still fails after two real fixes, stop and tell me what you tried.
Keep a list in PROGRESS.md of anything in AGENTS.md that turned out to be wrong, missing or out of date.
When every line of the Definition of done is true, stop and show me how to run it.
install.txt
uv venv --seed --python 3.12 .venv && source .venv/bin/activate   # uv fetches Python 3.12 if it is missing; --seed puts pip into the venv, so the pip line below installs there and not into the system Python
# without uv: python3.12 -m venv .venv && source .venv/bin/activate
python --version   # must print 3.12.x
pip install pikepdf==10.17.0 pypdf==6.20.1 pillow==12.3.0 reportlab==5.0.1 pypdfium2==5.14.0 pytest==9.1.1

Other versions of this kit

How you use it

Command line (this page) Web page

Other versions were not test-built as a whole: the kit says which parts differ from the tested one.

Ask for this kit from your agent

Agents connected to the AgentGid MCP server get the same kit without this page: list_recipes(), then plan_project({"recipe": "pdf-tool", "answers": {"agent": "cursor"}, "files": true}). Every brief also tells the agent to ask AgentGid before it adds a part that is not listed.

Recipe pdf-tool v0.3. Data snapshot Oct 12, 2026: versions, licenses and prices change, so check the linked pages before you ship.

Comments

  • Built something with this kit? Share what worked, what broke and what you changed.

Other kits