Claude Agent Skills for PDF extraction: SKILL.md, walked through
Direct answer: A Claude Agent Skill is a directory with a SKILL.md file — YAML frontmatter (name, description) plus Markdown instructions — that Claude Code, claude.ai, or the Claude API load automatically when the description matches what you’re asking for. It’s a different mechanism from an MCP server: Skills are filesystem-based and read on demand with bash; MCP is a live tool-call connection. Below is what the format actually requires, and a working Skill that wraps pdfmux’s CLI for PDF extraction in Claude Code — install it at ~/.claude/skills/pdfmux-extraction/SKILL.md and Claude uses it the next time you mention a PDF.
What a Skill actually is
Skills exist because prompts don’t compound. Every conversation, you re-explain the same workflow, the same edge cases, the same “don’t forget to check X” — or you don’t, and Claude re-derives it, sometimes wrong. A Skill packages that knowledge once, as files on disk, and Claude loads it only when it’s relevant.
The mechanism is filesystem-based, not injected into every prompt. Anthropic’s Agent Skills documentation describes three loading levels:
- Level 1 — metadata, always loaded. Just the
nameanddescriptionfrom the frontmatter, roughly 100 tokens per skill. This is what sits in context at all times, for every skill you have installed. - Level 2 — instructions, loaded when triggered. When your request matches a skill’s description, Claude reads the full
SKILL.mdbody withbash— under 5,000 tokens by convention. - Level 3 — resources, loaded as needed. Bundled reference files and scripts stay on disk until Claude actually opens one. A script’s code never enters context at all; only its stdout does, when Claude runs it.
That’s why you can have dozens of skills installed with no context penalty — until one actually fires, it costs about 100 tokens.
The frontmatter rules
Every SKILL.md needs YAML frontmatter with two required fields:
---
name: pdfmux-extraction
description: Extract text, tables, and structured fields from PDF files using pdfmux. Use when the user mentions a PDF, needs data pulled from a document, or asks to convert a PDF to markdown, JSON, or CSV.
---
name is capped at 64 characters, lowercase letters/numbers/hyphens only, and can’t contain the words “anthropic” or “claude” — which is why a PDF skill built around Claude tooling still needs a neutral name like pdf-extraction or pdfmux-extraction, not something with “claude” in it.
description is capped at 1024 characters and does double duty: it’s both the marketing copy and the trigger condition. Claude matches your request against it to decide whether to load the skill at all, so it has to state what the skill does and when to reach for it — “Extract data from PDFs” alone under-specifies the trigger; adding “Use when the user mentions a PDF…” gives Claude the matching signal it needs.
Where it lives, and what changes per surface
Claude Code Skills are pure filesystem — no upload step:
~/.claude/skills/pdfmux-extraction/SKILL.md # personal, every project
.claude/skills/pdfmux-extraction/SKILL.md # project-only, checked into the repo
That’s a meaningfully different model from claude.ai and the API. On claude.ai, custom Skills are uploaded as zip files per-user through Settings and don’t sync to teammates. On the API, Skills are uploaded through the /v1/skills endpoint and run inside a sandboxed, network-isolated code-execution container with no runtime package installation — so a Skill that shells out to pip install works fine in Claude Code (full network access, same as any program on your machine) and fails outright through the API. If you’re building a Skill meant to run in more than one surface, that constraint decides what the Skill is allowed to assume about its environment.
A working pdfmux Skill
Here’s a complete Skill for Claude Code that wraps pdfmux’s CLI — the same tool that also ships an MCP server for direct tool-call access. The Skill version is for a different situation: you want Claude to reach for pdfmux as part of a broader filesystem workflow (batch-processing a folder, chaining it into a script) without wiring up an MCP connection first.
~/.claude/skills/pdfmux-extraction/SKILL.md:
---
name: pdfmux-extraction
description: Extract text, tables, and structured fields from PDF files using pdfmux (pip install pdfmux). Use when the user shares a PDF, asks to convert a PDF to markdown/JSON/CSV, or needs structured data (invoices, contracts, forms) pulled from a document.
---
# pdfmux extraction
pdfmux is a local, CPU-only PDF extractor with per-page confidence scoring — no API
keys, no uploads. Install once with `pip install pdfmux` if the `pdfmux` command
isn't found.
## Quick start
Convert a single PDF to markdown:
```bash
pdfmux convert document.pdf
```
Convert to JSON for programmatic use:
```bash
pdfmux convert document.pdf --format json
```
## Structured field extraction
For invoices, receipts, or contracts, use a saved profile instead of raw conversion —
see [PROFILES.md](PROFILES.md) for the full profile list and field schemas.
```bash
pdfmux convert invoice.pdf --format json --profile invoice
```
## Batch processing a directory
```bash
pdfmux batch ./documents/ --profile invoice --output ./extracted/
```
## Checking extraction quality
Every result includes per-page confidence. Before trusting an extraction for anything
downstream, check for low-confidence or dropped pages:
```bash
pdfmux verify --source document.pdf --extracted extracted/document.json
```
This reports PASS / REVIEW / FAIL per page. Treat REVIEW or FAIL pages as
unverified — tell the user which pages need a manual check rather than presenting
the full extraction as reliable.
## Large documents
For documents over ~50 pages, prefer streaming so partial results are available
immediately: `pdfmux convert document.pdf --stream`. See
[STREAMING.md](STREAMING.md) for handling the NDJSON output.
Bundle PROFILES.md and STREAMING.md alongside it for the detail Claude only needs when a task actually calls for it — that’s Level 3 in practice. A user asking to convert one clean PDF never triggers either file; a user asking to batch-process a folder of invoices triggers PROFILES.md and nothing else.
Why the split matters in practice
The MCP server and the Skill aren’t competing options; they solve different problems. MCP gives any spec-compliant agent (Claude Code, Cursor, Claude Desktop) a live, always-available tool interface — good when you want extraction wired into every session without Claude needing to decide anything. A Skill is conditional and filesystem-native: good when the behavior you want is “run this multi-step CLI workflow, check the output, handle the edge cases the way our team has learned to” — the kind of procedural knowledge that’s awkward to express as a fixed tool signature but natural as instructions plus a couple of reference files.
If you already run pdfmux’s MCP server, adding the Skill isn’t redundant — the Skill is where you encode the judgment calls (which profile to use, what to do with a REVIEW-flagged page, when to switch to streaming) that an MCP tool call alone doesn’t carry.
Security, briefly
Anthropic’s own guidance is blunt about this: only install Skills from a source you trust, because a Skill’s instructions can direct Claude to run arbitrary bash commands and shell scripts. A Skill that shells out to a CLI you already have installed and audited, like the one above, is a reasonable case for a custom Skill. A Skill you downloaded from an unfamiliar repository that also happens to shell out to arbitrary commands is exactly the case their warning is about; read the whole SKILL.md and every bundled script before installing it.
FAQ
What’s the difference between a Claude Agent Skill and an MCP server? An MCP server exposes tools over a protocol connection that any MCP-compliant agent can call — it’s always running and always listed. A Skill is a directory with a SKILL.md file that Claude reads from the filesystem with bash, only when the skill’s description matches the current request. pdfmux ships both: an MCP server for tool-call access, and a Skill you can build yourself that wraps the CLI for filesystem-driven workflows.
Where do I put a custom Skill in Claude Code?
Personal skills go in ~/.claude/skills/{skill-name}/SKILL.md; project skills go in .claude/skills/{skill-name}/SKILL.md inside the repo. Claude Code discovers and loads them automatically — no registration step.
Does a Skill’s name have any restrictions?
Yes. The name field is capped at 64 characters, must contain only lowercase letters, numbers, and hyphens, and can’t include the words “anthropic” or “claude” — so a skill wrapping Claude-adjacent tooling needs a name like pdf-extraction or pdfmux-extraction, not claude-pdf-skill.
Frequently asked questions
What's the difference between a Claude Agent Skill and an MCP server?
An MCP server exposes tools over a protocol connection that any MCP-compliant agent can call — it's always running and always listed. A Skill is a directory with a SKILL.md file that Claude reads from the filesystem with bash, only when the skill's description matches the current request. pdfmux ships both: an MCP server for tool-call access, and (as shown below) a Skill you can build yourself that wraps the CLI for filesystem-driven workflows.
Where do I put a custom Skill in Claude Code?
Personal skills go in ~/.claude/skills/{skill-name}/SKILL.md; project skills go in .claude/skills/{skill-name}/SKILL.md inside the repo. Claude Code discovers and loads them automatically — no registration step.
Does a Skill's name have any restrictions?
Yes. The name field is capped at 64 characters, must contain only lowercase letters, numbers, and hyphens, and can't include the words "anthropic" or "claude" — so a skill wrapping Claude-adjacent tooling needs a name like pdf-extraction or pdfmux-extraction, not claude-pdf-skill.