Install
openclaw skills install pdf-fillerExtract and fill PDF AcroForm fields with a multi-backend fallback chain. Reads field schemas (text inputs, checkboxes, radio buttons, dropdowns, multi-line text) from any AcroForm PDF and fills them using user-provided JSON values. Tries pypdf, pdfrw, PyMuPDF, and pdftk in order so it works on PDFs that defeat any single library. Use when the user wants to inspect, populate, batch-fill, or programmatically complete PDF forms, or asks about extracting form field names from a PDF, filling out a PDF, generating a filled PDF, or AcroForm processing.
openclaw skills install pdf-fillerOperate on PDF AcroForms: list every field with its type and current value, then fill the PDF with values supplied as JSON. The skill calls a small Python package (oc-pdf-filler) that wraps a fallback chain of PDF libraries, so a single recalcitrant PDF doesn't block the workflow.
Many agent hosts run inside a sandbox that only allows reads/writes inside a specific workspace folder. Files written outside that folder show up as "Unavailable / Outside allowed folders" and the user can't download them.
The CLI enforces this for you:
OC_PDF_FILLER_WORKSPACE, OPENCLAW_WORKSPACE, CLAWHUB_WORKSPACE,
AGENT_WORKSPACE, SKILL_WORKSPACE, WORKSPACE.--output that points outside the workspace, the CLI
rewrites it to the same basename inside the workspace (and prints a warning to
stderr).--workspace DIR.In practice: pass relative paths (e.g. -o form_done.pdf), or omit --output
entirely. The default is <input-stem>_done.pdf inside the workspace.
Trigger this skill when the user:
The skill scripts call the oc-pdf-filler Python package. Install it first:
pip install "oc-pdf-filler[all]"
# or, if working from the source repo: pip install -e ".[all]"
The [all] extra pulls in pdfrw and PyMuPDF for the full fallback chain. Install pdftk from your package manager for the last-resort backend (optional, but useful for stubborn PDFs).
Verify which backends are active:
python scripts/list_backends.py
Always extract first so you know the exact field names and types before constructing the JSON values file. Use a workspace-relative path for the output (the CLI confines it to the workspace automatically).
python scripts/extract.py /path/to/form.pdf --output schema.json --include-values
Each entry in the resulting JSON has:
name: the AcroForm field name (use this verbatim as the key when filling)type: one of text, checkbox, radio, choice, signature, pushbutton, unknownoptions: for radios and checkboxes, the accepted export values; for choices, the dropdown optionsvalue: current value if the form is partially filled (only when --include-values is set)max_length, multiline, required, read_only: hints for validationSee references/FIELD_TYPES.md for the value contract per field type.
The fill input is a flat JSON object { "FieldName": value }. Example:
{
"Name Verantwortlicher": "ACME GmbH",
"Postleitzahl Verantwortlicher": "10115",
"Beschäftigte": true,
"Verarbeitungstyp": "Automatisiert"
}
A starter template is included at assets/values.example.json.
LLMs tend to omit fields they're unsure about, which silently leaves checkboxes unchecked in the output PDF. Don't do that. For every field in the schema:
type: checkbox): set true or false. If the user didn't mention it, default to false rather than omitting the key.type: radio): set the exact export string from options. If the user didn't pick one, leave it out only if it's truly optional; otherwise ask the user or pick the most plausible value.If you are unsure for a checkbox, choose false, not omission. The CLI's unset_checkboxes and unset_radios summary fields tell you which fields were left out so you can self-correct on the next pass. As safety nets you can pass:
--default-unset-checkboxes off to force every untouched checkbox to false in one go.--default-unset-radios first to pick the first available option for every untouched radio group.Omit --output to get the recommended default <input-stem>_done.pdf inside the workspace, or pass a workspace-relative filename. Absolute paths outside the workspace are automatically rewritten into it (the host's sandbox would reject them otherwise).
# preferred: keep the original name with _done suffix, in the workspace
python scripts/fill.py /path/to/form.pdf values.json
# or pass an explicit relative path
python scripts/fill.py /path/to/form.pdf values.json --output form_done.pdf
By default the orchestrator uses --backend auto, walking the chain pypdf -> pdfrw -> PyMuPDF -> pdftk and stopping at the first backend that fills every field.
Useful flags:
--backend pymupdf -- force a specific backend (e.g. when the auto winner produces a PDF that doesn't render correctly in your viewer)--best-effort -- chain backends so partial fills accumulate (use when no single backend handles every field)--flatten -- bake values into the PDF so they can't be edited (best support: PyMuPDF, pdftk)--strict -- exit non-zero if any requested field is missing or unfillableThe script prints a JSON summary including winning_backend, workspace, output_path (absolute path of the resulting PDF, always inside the workspace), filled, missing, failed, unset_checkboxes, unset_radios, and per-attempt details. If filling fails, see references/BACKENDS.md for backend-specific troubleshooting tips.
Send the file back automatically as soon as the fill succeeds. Do not wait for the user to ask. Users on chat platforms (Telegram, Slack, Discord, Teams, the ClawHub web client, etc.) expect the finished PDF to arrive in the conversation as an attachment immediately after you announce success.
Procedure:
output_path from the fill summary. It is guaranteed to be inside the workspace, so the host can attach it.sendDocument, Slack files.upload, the agent runtime's own attach_file / send_file tool, or simply emit it as a workspace artifact. Do not ask the user "do you want me to send it?"; just send it.Never write the PDF outside the workspace (e.g. /tmp, /var, your home directory). Sandboxed hosts will mark it as "Unavailable / Outside allowed folders".
python scripts/extract.py form.pdf -o schema.json
# ... agent inspects schema.json, builds values.json based on user input ...
python scripts/fill.py form.pdf values.json
# writes <workspace>/form_done.pdf
After filling, re-run extract.py --include-values form_done.pdf and confirm the values stuck before delivering the PDF to the user.
extract.py output.options), not a boolean.type: signature) are reported but not auto-filled.--flatten.