PORTAL / LIBRARY / sign-pdf

[ OPERATIONS · OPERATOR UTILITY ]

/sign-pdf

Add Faris's handwritten-style signature + date (+ city) to one or more PDF documents at the correct field locations.

Download the skill file (.md)

Placeholders like 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

Defaults

FieldDefault
NameFaris Biogradlic
Datetoday's date (DD.MM.YYYY)
PlaceHamburg
FontPatrickHand-Regular.ttf (clean handwriting, reliable letter spacing)
Ink colordark blue [0.05, 0.10, 0.55]
Signature size24pt
Date/place size11pt 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:

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:

LayoutWhere to write
Unterschrift heading + `Ort \Datum row + entry row + Unterschrift` row + entry row + disclaimerPlace inside each entry row (~20pt above each label)
Single horizontal line above Datum, Unterschrift labelDate on left, name on right, both ~5-10pt above the label baseline
Letter sign-off (Best regards / [Company]) with no signature linePlace handwritten name BELOW the closing block, optionally with "City, Date" line above
Combined Datum, eigenhändige Unterschrift fieldDate (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

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/:

Common gotchas

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.