
promptShield
Offline document anonymizer for the AI era
Visit Website
July 9, 2026
The hard parts of shipping a real offline desktop app (license validation + a local PII engine)
Building promptShield taught me "just make it offline" is a trap.
Offline license validation isn't crypto — it's clocks. Fail closed against abuse, but fail gracefully when a laptop wakes on flaky Wi-Fi. A 4-hour local token TTL was silently logging users out every morning.
And a local PII engine means shipping ML to machines you don't control: CPUs with no AVX2 crash on import, and deleting a loaded NER model on Windows throws sharing-violation errors.
Offline is the whole product. It's also the hard part.
About
Professionals shouldn't have to choose between AI and privacy. promptShield anonymizes documents before any AI sees them.

1 Comment
The part I underestimated most: the detection engine isn't one model, it's three layers that constantly disagree, and the real work is in reconciling them.
Regex is high-precision but dumb - it nails SSNs, emails, IBANs, phone numbers, but has zero context.
NER (I run spaCy / BERT / GLiNER depending on the language) is the opposite: it catches names, orgs and addresses regex never could, but it drifts - the same name can come back with slightly different boundaries on two different pages.
LLM (optional, a local GGUF model) catches the subtle context-dependent stuff the other two miss, but it's slow and can't be the default.
So the hard part isn't running them - it's the merge. Three layers produce overlapping, conflicting spans over the same text, at different confidence levels, with different boundaries. You have to dedupe them, decide who wins on overlap, then unify types (if something is a PERSON on page 1 it must stay a PERSON on page 9), propagate a name detected once across every page it appears on, and then run a noise filter to kill the false positives NER loves to invent — all without dropping a real hit.
Getting "high recall" is easy with three layers firing. Getting high recall and a clean, non-noisy output is the entire ballgame.
How do others handle merge conflicts between a precise-but-context-blind matcher and a fuzzy-but-smart model? Confidence-weighted, or hard precedence rules?