[ OPERATIONS · OPERATOR UTILITY ]
/sign-pdf
Add Faris's handwritten-style signature + date (+ city) to one or more PDF documents at the correct field locations.
ACME Agency, <id> and you@example.com mark values that are per-agency — your install fills them with YOUR clients and accounts. If a section references a helper script you don't have yet, it ships with that workflow's install./sign-pdf
Adds Faris's handwritten signature, date, and (optional) city to one or more PDFs at the correct field locations. Output goes to a sibling _signed/ folder with _signed.pdf suffix on each filename.
Trigger
- "sign these PDFs"
- "add my signature to <file>"
- "potpiši ove dokumente"
- User pastes/attaches German tax forms, declarations, contracts, etc.
Defaults
| Field | Default |
|---|---|
| Name | Faris Biogradlic |
| Date | today's date (DD.MM.YYYY) |
| Place | Hamburg |
| Font | PatrickHand-Regular.ttf (clean handwriting, reliable letter spacing) |
| Ink color | dark blue [0.05, 0.10, 0.55] |
| Signature size | 24pt |
| Date/place size | 11pt Helvetica |
If the user wants Caveat (more cursive/loopy) say so explicitly: --font Caveat-Regular.ttf. Do not use the variable-axis Caveat.ttf — its glyph metrics break and you get visible gaps inside words like "Biogradlic" → "Bio gr adl ic".
Workflow
1. Identify which documents need signing
Before signing, classify each PDF:
- Sign: tax returns, declarations, contracts, offers/Angebote, balance sheets requiring Unterschrift der Geschäftsführung, lease agreements, Vollmachten, etc.
- DO NOT sign — flag to user:
- Invoices received from a third party (e.g. tax advisor's invoice to you)
- Electronic-submission pACME Agencyws (
E-Bilanz-Vorschau, ELSTER-Vorschau) — those go through ERiC authenticated by the advisor's software - Bank statements, receipts, info letters
If the user said "all of them" but some clearly don't need signing, tell them which two and why before processing — let them confirm. Don't silently sign everything.
2. Discover signature label positions
For every PDF that will be signed, run:
node .claude/skills/sign-pdf/scripts/find_sig_positions.mjs "<absolute-path-to.pdf>"
This outputs JSON listing every match for keywords like Unterschrift, Datum, Ort, Datum, Datum, eigenhändige Unterschrift, Best regards — with {page, text, x, y} coordinates. Coordinates use pdf-lib's bottom-left origin.
3. Decide placement (the rule)
German tax forms put the label BELOW the entry field. So if you find a label at y=440, you write the signature at roughly y=420 (~20pt above the label, inside the cell).
Common patterns:
| Layout | Where to write | |
|---|---|---|
Unterschrift heading + `Ort \ | Datum row + entry row + Unterschrift` row + entry row + disclaimer | Place inside each entry row (~20pt above each label) |
Single horizontal line above Datum, Unterschrift label | Date on left, name on right, both ~5-10pt above the label baseline | |
Letter sign-off (Best regards / [Company]) with no signature line | Place handwritten name BELOW the closing block, optionally with "City, Date" line above | |
Combined Datum, eigenhändige Unterschrift field | Date (Helvetica) + name (handwriting) on same line, ~30pt above the label |
For each placement object you output:
{
"page": 6,
"name_xy": [274, 252], // signature (handwriting font)
"date_xy": [82, 256], // standalone date (Helvetica)
// OR for single-cell place+date fields:
"<id>": [85, 100],
// OR for separate cells:
"place_xy": [95, 420]
}
4. Build a config and run the signer
Write a config to .tmp/sign-job-<timestamp>.json:
{
"name": "Faris Biogradlic",
"date": "29.04.2026",
"place": "Hamburg",
"font": "PatrickHand-Regular.ttf",
"outDir": "C:/Users/faris/Downloads/_signed",
"files": [
{
"in": "C:/Users/faris/Downloads/Foo.pdf",
"placements": [
{ "page": 6, "<id>": [72, 258], "name_xy": [274, 252] }
]
}
]
}
Then run:
node .claude/skills/sign-pdf/scripts/sign_pdf.mjs .tmp/sign-job-<ts>.json
Outputs each file as <original>_signed.pdf in outDir.
5. Report back
- List the signed file paths.
- Flag any PDFs you skipped (with the reason).
- Tell the user to open one and verify placement before sending — coordinates are derived but font baselines can sit slightly differently than expected. Offer to nudge if anything's off (specify direction: up/down/left/right by N points).
Dependencies
Already installed in repo node_modules: pdf-lib, @pdf-lib/fontkit, pdfjs-dist. If missing:
npm install --no-save pdf-lib @pdf-lib/fontkit pdfjs-dist
Bundled fonts in .claude/skills/sign-pdf/fonts/:
PatrickHand-Regular.ttf(default — print-style handwriting, reliable metrics)Caveat-Regular.ttf(cursive — use only if user requests)
Common gotchas
- Variable fonts break letter spacing. Use the static
*-Regular.ttffiles only. - Subsetting can drop kerning. The signer passes
{ subset: false }when embedding. Don't change that. - First-pass coordinates may need a small nudge. Always tell the user to spot-check before sending. Save the working config to
.tmp/so re-runs are cheap. - Don't add a signature to invoices you received or electronic-submission pACME Agencyws — flag them and skip.
- Date format: German tax forms expect
DD.MM.YYYY. Default to that unless told otherwise.
Reference: the original 8-document run
Live config used for the 2024 Iqramal Solution UG Jahresabschluss + Steuererklärungen package: see examples/<id>.json. Reuse those placements as a template for next year's filing.