PDF Toolkit
XiaomiMiMo/MiMo-Code
Reads, transforms, composes and fills PDFs with Python scripts for extraction, merging, watermarking, encryption, OCR and form filling.
Picks the right library for generating a new PDF, filling an existing PDF form, or extracting text and tables, defaulting to Node where possible.
$ npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install pipeshub-ai/pipeshub-ai pdf --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/pipeshub-ai/pipeshub-ai.git skills-src && mkdir -p .claude/skills && cp -r skills-src/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf .claude/skills/pdf && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "pdf" agent skill from https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf into .claude/skills/pdf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pdf", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdfType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install pipeshub-ai/pipeshub-ai pdf --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pipeshub-ai/pipeshub-ai.git skills-src && mkdir -p .agents/skills && cp -r skills-src/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf .agents/skills/pdf && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "pdf" agent skill from https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf into .agents/skills/pdf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pdf", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install pipeshub-ai/pipeshub-ai pdf --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pipeshub-ai/pipeshub-ai.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf .cursor/skills/pdf && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "pdf" agent skill from https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf into .cursor/skills/pdf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pdf", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/pipeshub-ai/pipeshub-ai.git --path backend/python/app/agents/agent_loop/skills/builtin_packs/pdf--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install pipeshub-ai/pipeshub-ai pdf --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pipeshub-ai/pipeshub-ai.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf .gemini/skills/pdf && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "pdf" agent skill from https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf into .gemini/skills/pdf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pdf", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install pipeshub-ai/pipeshub-ai pdfInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/pipeshub-ai/pipeshub-ai.git skills-src && mkdir -p .github/skills && cp -r skills-src/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf .github/skills/pdf && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "pdf" agent skill from https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf into .github/skills/pdf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pdf", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install pipeshub-ai/pipeshub-ai pdf --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/pipeshub-ai/pipeshub-ai.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf .opencode/skills/pdf && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "pdf" agent skill from https://github.com/pipeshub-ai/pipeshub-ai/tree/main/backend/python/app/agents/agent_loop/skills/builtin_packs/pdf into .opencode/skills/pdf/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pdf", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
pdfPicks the right library for generating a new PDF, filling an existing PDF form, or extracting text and tables, defaulting to Node where possible.
This skill is a decision table for PDF work: generate a new PDF from scratch with a TypeScript library by default, or a Python reporting library when a report needs several pages of tabular data and automatic pagination beats hand-rolled page breaks; fill an existing form with a TypeScript or Python library; and extract text or tables from an existing PDF in Python, since there's no solid Node option for extraction.
Because the default generation library has no built-in table primitive, it walks through drawing tabular content manually - fixed per-column x-offsets, a page-break check before every row, and computing each row's height from the tallest wrapped cell rather than using a fixed height, which otherwise causes overlapping rows. It also covers setting an explicit page size rather than relying on a locale-dependent default.
It explicitly excludes converting an existing Word, PowerPoint or Excel file to PDF, since that needs LibreOffice and is handled by a separate skill; the libraries it calls for are already installed or allowlisted in its environment.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit a883af6. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript and python).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
PDF Generation, Forms and Extraction loads about 2.9k tokens when it runs. Until then it costs about 89 tokens; SKILL.md has 766 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from pipeshub-ai/pipeshub-ai at commit a883af6, republished under its Apache-2.0 licence (© pipeshub-ai). 766 words, ~2,894 tokens.
.claude/skills/pdf/SKILL.md (or your agent's skills folder).| Task | Default (Node) | Fallback (Python) |
|---|---|---|
| Generate a new PDF from scratch | pdfkit — write a TypeScript program (packages: ["pdfkit"]) and run it via your coding tool; pre-installed in the standard sandbox image | reportlab's platypus — reach for this for a report with several full pages of tabular data, where platypus.Table's built-in pagination beats hand-rolling page breaks in pdfkit (see below) |
| Fill in an existing PDF form (AcroForm) | pdf-lib — TypeScript program (packages: ["pdf-lib"], pre-installed); form.getTextField(name).setText(value) | pypdf (PdfWriter.update_page_form_field_values) |
| Extract text from an existing PDF | — (no good Node equivalent) | pdfplumber (also gets tables) or pypdf (faster, text-only) |
| Extract tables from an existing PDF | — (no good Node equivalent) | pdfplumber (page.extract_tables()) |
All of the above are already installed/allowlisted — no extra setup either way. Default to pdfkit/pdf-lib in TypeScript for generation and form-filling per this environment's Node-first policy for office-document creation; extraction has no solid Node option here, so stays Python.
pdfkit is a low-level, stream-based PDF library — it does not have reportlab.platypus's automatic page-flow layout for tables, so you place text yourself and check the vertical position before every element:
import PDFDocument from "pdfkit";
import fs from "fs";
const doc = new PDFDocument({ size: "A4", margins: { top: 50, bottom: 50, left: 50, right: 50 } });
doc.pipe(fs.createWriteStream("report.pdf"));
doc.fontSize(18).text("Invoice", { align: "center" });
doc.moveDown();
// doc.text() without an explicit x/y auto-wraps and flows below the previous
// element, including inserting new pages for long paragraphs — only switch
// to explicit x/y positioning (below) for tabular/columnar layout.
doc.fontSize(11).text("Body text wraps and paginates automatically here.");
doc.end();size explicitly ("A4" or "LETTER") rather than relying on the default, since it may not match the user's locale expectation.doc.text() alone handles wrapping and page breaks. Only tabular/columnar content needs the manual pattern below.pdfkit has no built-in table primitive — draw it with fixed per-column x offsets and a manual page-break check before each row:const startX = 50;
const colWidths = { desc: 260, qty: 60, total: 90 };
let y = doc.y;
for (const item of items) {
if (y > doc.page.height - doc.page.margins.bottom - 20) {
doc.addPage();
y = doc.page.margins.top;
}
doc.text(item.desc, startX, y, { width: colWidths.desc });
doc.text(String(item.qty), startX + colWidths.desc, y, { width: colWidths.qty, align: "right" });
doc.text(item.total.toFixed(2), startX + colWidths.desc + colWidths.qty, y, { width: colWidths.total, align: "right" });
// Compute row height from the tallest cell; fixed values cause overlapping when a cell wraps.
const rowHeight = Math.max(
doc.heightOfString(item.desc, { width: colWidths.desc }),
doc.heightOfString(String(item.qty), { width: colWidths.qty }),
doc.heightOfString(item.total.toFixed(2), { width: colWidths.total }),
) + 4; // 4pt bottom padding
y += rowHeight;
}doc.heightOfString(text, { width }) across all cells in the row and use the maximum. A fixed row height causes rows to overlap whenever any cell wraps to a second line.reportlab.platypus.Table (Python) instead when the table is long enough that hand-rolling pagination is more work than it's worth — it paginates a table across pages automatically given column widths and a TableStyle.Tables with many columns (ticket lists, dashboards, audit logs) overflow if you use portrait orientation or eyeball column widths. Follow this checklist:
const doc = new PDFDocument({ size: "A4", layout: "landscape", margins: { top: 40, bottom: 40, left: 40, right: 40 } });const pageWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
// Give variable-length columns (e.g. "Summary") a proportionally larger share
const fixedColWidth = 70; // narrow cols: status, priority, type, etc.
const fixedCols = 6;
const flexColWidth = pageWidth - fixedCols * fixedColWidth; // remainder for "Summary"function truncate(original: string, font: string, size: number, maxWidth: number): string {
let text = original;
while (doc.widthOfString(text, { font, size }) > maxWidth && text.length > 0) {
text = text.slice(0, -1);
}
return text.length < original.length ? text + "…" : text;
}{ width: colWidth, ellipsis: true } in the .text() call (pdfkit supports this natively).{ width: colWidth } and compute row height with doc.heightOfString(cellText, { width: colWidth }) across all cells in the row, then use the tallest.reportlab.platypus.Table handles both pagination and cell wrapping automatically when you give it explicit colWidths that sum to the available page width:
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from reportlab.lib.enums import TA_LEFT
pagesize = landscape(A4)
doc = SimpleDocTemplate("report.pdf", pagesize=pagesize,
topMargin=15*mm, bottomMargin=15*mm,
leftMargin=15*mm, rightMargin=15*mm)
available_width = pagesize[0] - 30*mm # left + right margins
# Assign proportional widths — flex column gets remainder
fixed = {"key": 45*mm, "type": 30*mm, "status": 30*mm,
"priority": 28*mm, "due": 28*mm, "sprint": 35*mm}
flex_width = available_width - sum(fixed.values()) # "Summary" gets the rest
col_widths = [fixed["key"], flex_width, fixed["type"], fixed["status"],
fixed["priority"], fixed["due"], fixed["sprint"]]
# Every cell must be a Paragraph — plain strings in Table cells do NOT wrap
styles = getSampleStyleSheet()
cell_style = ParagraphStyle("Cell", parent=styles["Normal"], fontSize=8, leading=10,
splitLongWords=True, wordWrap="CJK")
header_style = ParagraphStyle("Header", parent=cell_style, fontSize=9,
textColor=colors.white, fontName="Helvetica-Bold")
def P(text, style=cell_style):
return Paragraph(str(text) if text is not None else "—", style)
table_data = [[P(h, header_style) for h in ["Key", "Summary", "Type", "Status", "Priority", "Due", "Sprint"]]]
for ticket in tickets:
table_data.append([
P(ticket["key"]),
P(ticket["summary"]),
P(ticket["type"]),
P(ticket["status"]),
P(ticket["priority"]),
P(ticket.get("due", "—")),
P(ticket.get("sprint", "—")),
])
table = Table(table_data, colWidths=col_widths, repeatRows=1)
table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#2c3e50")),
# TEXTCOLOR/FONTNAME/FONTSIZE for header are now carried by header_style Paragraph
("FONTSIZE", (0, 1), (-1, -1), 8),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.Color(0.95, 0.95, 0.95)]),
("GRID", (0, 0), (-1, -1), 0.4, colors.grey),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 4),
("RIGHTPADDING", (0, 0), (-1, -1), 4),
]))
doc.build([table])Key points:
landscape(A4) — always use landscape for 6+ column tables.colWidths must sum to available_width — if they exceed it, the table overflows the page; if they're omitted, reportlab auto-sizes but often overflows.Paragraph(..., style) — including headers and short cells. Plain strings inside a Table cell never wrap; they clip or overflow regardless of colWidths. This is the #1 cause of reportlab table overflow. Use a helper P(text, style=cell_style) to keep the data-building code readable. Add splitLongWords=True, wordWrap="CJK" to cell_style so URLs and other long unbreakable tokens are force-split rather than overflowing.repeatRows=1 — repeats the header row on every page when the table spans multiple pages.import { PDFDocument } from "pdf-lib";
import fs from "fs";
const pdfDoc = await PDFDocument.load(fs.readFileSync("form.pdf"));
const form = pdfDoc.getForm();
for (const field of form.getFields()) console.log(field.getName(), field.constructor.name); // discover field names/types first
form.getTextField("first_name").setText("Jane");
fs.writeFileSync("filled.pdf", await pdfDoc.save());Field names are exactly what the form's original author named them (often generic like Text1) — always call form.getFields() first rather than guessing. pdf-lib is also the right tool for merging/splitting existing PDFs (PDFDocument.copyPages) if that comes up alongside form-filling.
pdfplumber: page.extract_text() for reading order-preserving text, page.extract_tables() for tabular data — the better default for anything that might contain a table, since pypdf's text extraction does not attempt to reconstruct table structure.pypdf: faster and sufficient when you only need plain text and know the source has no tables (e.g. extracting a paragraph from a text-heavy report).page.extract_text() for an empty/near-empty result and tell the user OCR would be needed (not available in this environment) rather than returning an empty string silently..docx/.pptx/.xlsx to PDF requires a rendering engine (LibreOffice) not installed in the sandbox yet.© pipeshub-ai, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in backend/python/app/agents/agent_loop/skills/builtin_packs/pdf of pipeshub-ai/pipeshub-ai.
Open the folder on GitHubat commit a883af6
PDF Generation, Forms and Extraction next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| PDF Generation, Forms and Extraction this skillpipeshub-ai/pipeshub-ai | 3.8k | — | ~2.9k | Automated safety check: Pass | Apache-2.0 | |
| PDF ToolkitXiaomiMiMo/MiMo-Code | 14k | — | ~1.7k | Automated safety check: Pass | Apache-2.0 | |
| React PDFtrailofbits/skills-curated | 513 | — | ~3.1k | Automated safety check: Notes | CC-BY-SA-4.0 | |
| PDF Processinganthropics/skills | 180k | 48 repos | ~2k | Automated safety check: Pass | Proprietary | |
| PDF Processing with PythonHKUDS/DeepTutor | 41k | — | ~2.7k | Automated safety check: Pass | Apache-2.0 | |
| PDF ToolkitTokenRhythm/opensquilla | 7.1k | — | ~1.9k | Automated safety check: Pass | Apache-2.0 |
XiaomiMiMo/MiMo-Code
Reads, transforms, composes and fills PDFs with Python scripts for extraction, merging, watermarking, encryption, OCR and form filling.
trailofbits/skills-curated
Generates PDF documents using the React-PDF library (@react-pdf/renderer) with TypeScript and JSX.
anthropics/skills
Handles everyday PDF jobs in Python and on the command line: extract text and tables, merge, split, rotate, watermark, fill forms, encrypt and OCR.
HKUDS/DeepTutor
Reads, extracts from, creates, merges, splits, watermarks, encrypts and fills PDF files with pdfplumber, pypdf and reportlab inside a Python sandbox.
TokenRhythm/opensquilla
Deterministic PDF operations through bundled scripts: extract text and tables, merge files or page ranges, split by range, fill form fields and build PDFs from data.
agentscope-ai/QwenPaw
Handles PDF tasks with Python libraries and command-line tools: extract text and tables, merge, split, rotate, create, fill forms and more.
pipeshub-ai/pipeshub-ai
Creates and edits .xlsx workbooks with real Excel formulas rather than hardcoded computed values, defaulting to exceljs in TypeScript with a static formula-safety check.
pipeshub-ai/pipeshub-ai
Unpacks a .docx or .pptx into pretty-printed XML, lets you make small targeted edits, and repacks it into a file Office will open.
pipeshub-ai/pipeshub-ai
Creates new PowerPoint decks with pptxgenjs in TypeScript, reads existing decks with python-pptx, and applies a design-quality checklist so every slide has real visual hierarchy.
pipeshub-ai/pipeshub-ai
Loads, cleans, aggregates and joins tabular data with pandas under a verification rule: every number reported must be one that the code actually printed.
pipeshub-ai/pipeshub-ai
Picks the right chart type for a data question and applies readability rules like axis labels, colorblind palettes and legend restraint.
pipeshub-ai/pipeshub-ai
Routes a Word document request to the right approach: a TypeScript library for new files, XML editing for existing ones, and plain reading only.
Works with
Categories
Picks the right library for generating a new PDF, filling an existing PDF form, or extracting text and tables, defaulting to Node where possible. This skill is a decision table for PDF work: generate a new PDF from scratch with a TypeScript library by default, or a Python reporting library when a report needs several pages of tabular data and automatic pagination beats hand-rolled page breaks; fill an existing form with a TypeScript or Python library; and extract text or tables from an existing PDF in Python, since there's no solid Node option for extraction.
PDF Generation, Forms and Extraction fits situations like: generating a new PDF report or invoice from scratch; filling in the fields of an existing PDF form; extracting text or tables out of an existing PDF.
Run `npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a claude-code`. Or copy the skill folder (backend/python/app/agents/agent_loop/skills/builtin_packs/pdf in pipeshub-ai/pipeshub-ai) into .claude/skills/pdf in your project. Claude Code loads it when a task matches its description.
Run `npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a codex`. Or copy the skill folder (backend/python/app/agents/agent_loop/skills/builtin_packs/pdf in pipeshub-ai/pipeshub-ai) into .agents/skills/pdf in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add pipeshub-ai/pipeshub-ai --skill pdf -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/pdf, .gemini/skills/pdf, .github/skills/pdf and .opencode/skills/pdf in your project.
SKILL.md names no scripts, command-line tools or credentials: PDF Generation, Forms and Extraction is instructions for the agent only. Our summary lists: A TypeScript or Python PDF library such as pdf-lib or pypdf.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
PDF Generation, Forms and Extraction is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.9k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with PDF Generation, Forms and Extraction: PDF Toolkit (XiaomiMiMo/MiMo-Code, 14k stars), React PDF (trailofbits/skills-curated, 513 stars), PDF Processing (anthropics/skills, 180k stars) and PDF Processing with Python (HKUDS/DeepTutor, 41k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
pipeshub-ai (a GitHub organization) maintains it in pipeshub-ai/pipeshub-ai, which has 3,821 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 9, 2026.
Source: pipeshub-ai/pipeshub-ai on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.