Skip to content

feat: add pii-bouncer skill#170

Draft
joethreepwood wants to merge 3 commits into
mainfrom
pii-bouncer-skill
Draft

feat: add pii-bouncer skill#170
joethreepwood wants to merge 3 commits into
mainfrom
pii-bouncer-skill

Conversation

@joethreepwood

Copy link
Copy Markdown

Summary

The context-mill skill ("cartridge") for the wizard's PII Bouncer program — companion to PostHog/wizard#510. The wizard side is pure engine; this is the packaged-English methodology it loads at runtime.

pii-bouncer is a docs-only remediation skill that hardens a frontend against PII leaking into session replay and autocapture:

  • adds the ph-no-capture class to sensitive elements (the replay-masking mechanism — distinct from the data-ph-no-capture autocapture attribute)
  • tightens session_recording mask config: adds maskTextSelector for sensitive text (not masked by default) and confirms maskAllInputs isn't disabled (it defaults to true, so inputs are already masked — the skill doesn't restate that)
  • writes posthog-pii-bouncer-report.md (elements masked + why, init changes, reviewed-but-skipped, manual follow-ups)

Design

  • type: docs-only, single variant id: all → skill id pii-bouncer (matches the wizard's skillId).
  • shared_docs pulls in session-replay/privacy.md + libraries/js/config.md, bundled as references/ so the agent uses the authoritative option names and defaults instead of guessing.
  • Emits the [ABORT] signals the wizard routes verbatim: no-posthog-js, no-init-call, no-frontend-templates.
  • Conservative heuristic (type / autocomplete / name·id / label / placeholder / rendered text); bias toward masking. Idempotent — a second run is a no-op.

This is complementary to the new warlock PII rules: warlock stops PII being sent as event properties; this skill stops PII being recorded in the DOM.

Test plan

  • pnpm build produces dist/skills/pii-bouncer.zip containing SKILL.md + references/{privacy,config}.md
  • pii-bouncer appears in skill-menu.json
  • pnpm dev serves it at http://localhost:8765; the wizard (localMcp) resolves + downloads it
  • Manual e2e (reviewer): run the wizard's pii-bouncer against a workbench app and confirm the masking edits + report

🤖 Generated with Claude Code

The instructions for the wizard's PII Bouncer program (PostHog/wizard#510).
A docs-only remediation skill that hardens a frontend against PII leaking
into session replay and autocapture:

- adds the `ph-no-capture` class to sensitive elements
- tightens session_recording mask config (maskTextSelector; confirms
  maskAllInputs is not disabled — it defaults to true)
- writes posthog-pii-bouncer-report.md

shared_docs inlines the authoritative privacy + js/config docs as
references/ so the agent uses real option names, not guesses. Emits the
[ABORT] signals the wizard program routes (no-posthog-js / no-init-call /
no-frontend-templates).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci basic-integration
  • /wizard-ci error-tracking-upload-source-maps
  • /wizard-ci misc
  • /wizard-ci revenue

Test an individual app:

  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
Show more apps
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci error-tracking-upload-source-maps/android
  • /wizard-ci error-tracking-upload-source-maps/flutter
  • /wizard-ci error-tracking-upload-source-maps/ios
  • /wizard-ci error-tracking-upload-source-maps/next
  • /wizard-ci error-tracking-upload-source-maps/next-no-posthog
  • /wizard-ci error-tracking-upload-source-maps/node-raw
  • /wizard-ci error-tracking-upload-source-maps/node-rollup
  • /wizard-ci error-tracking-upload-source-maps/node-rollup-typescript-plugin
  • /wizard-ci error-tracking-upload-source-maps/node-webpack
  • /wizard-ci error-tracking-upload-source-maps/nuxt-3-6
  • /wizard-ci error-tracking-upload-source-maps/nuxt-4-3
  • /wizard-ci error-tracking-upload-source-maps/react-native
  • /wizard-ci error-tracking-upload-source-maps/react-vite
  • /wizard-ci error-tracking-upload-source-maps/rust
  • /wizard-ci misc/quack-quack
  • /wizard-ci revenue/stripe

Results will be posted here when complete.

@edwinyjlim

edwinyjlim commented Jun 5, 2026

Copy link
Copy Markdown
Member

@joethreepwood this is a perfectly constructed context mill skill 👏

i don't even have to read it. you can tell just by the shape and how you're stitching posthog docs as a reference with your skill instructions

@sarahxsanders sarahxsanders left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one thing that could potentially be breaking for React projects, then you're good for ✅

Comment on lines +56 to +57
emit `[ABORT] no-posthog-js`. Find the `posthog.init(...)` call; if there
is none, emit `[ABORT] no-init-call`. Enumerate frontend templates

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for this sentence: Find the posthog.init(...)call; if there is none, emit[ABORT] no-init-call.

React projects may not have a literal posthog.init(...) call to find, so in this case, it would hit the abort on a valid React project. I'd also have it detect <PostHogProvider> and write masking config into its options={...} prop instead. Same outcome, framework-correct

claude should be able to fix this easily ^^^

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fd9c087. Step 1 now looks for either a posthog.init(...) call or a <PostHogProvider>, and only emits [ABORT] no-init-call if neither exists. Step 4 writes the masking config into whichever it found — the session_recording options on init, or the options={{…}} prop on the provider. (Also broadened the wizard's abort copy to match: PostHog/wizard#510.)

|---|---|
| `type` | `password`, `email`, `tel` |
| `autocomplete` | `current-password`, `new-password`, `cc-number`, `cc-csc`, `cc-exp`, `email`, `tel`, `one-time-code`, `ssn` |
| `name` / `id` | matches `/pass(word)?\|pwd\|card\|cc[-_]?(num\|number)\|cvv\|cvc\|csc\|ssn\|sin\|nin\|pin\|dob\|birth\|tax\|passport\|iban\|account[-_]?(num\|number)/i` |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the alternatives in this regex have no word boundaries so it matches anywhere inside another word. for example passenger matches pass, spinner matches pin, etc. could get messy with bury sensitive stuff and add to token waste

if you wrap each alternative in \b...\b it should help:

/\b(pass(word)?|pwd|card|cc[-_]?(num|number)|cvv|cvc|csc|ssn|sin|nin|pin|dob|birth|tax|passport|iban|account[-_]?(num|number))\b/i for example

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — word-bounded in fd9c087: /\b(pass(word)?|pwd|card|cc[-_]?(num|number)|cvv|cvc|csc|ssn|sin|nin|pin|dob|birth|tax|passport|iban|account[-_]?(num|number))\b/i, with a note that it's bounded so pass doesn't match passenger, pin doesn't match spinner, etc.

joethreepwood and others added 2 commits June 8, 2026 11:56
Review feedback (PostHog/wizard#510): the [ABORT] signals are a contract
with the wizard, but neither side named the other's file. Adds a breadcrumb
to the consuming side (src/lib/programs/pii-bouncer/abort-cases.ts); the
wizard side now points back here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review feedback (PostHog/wizard#510 skill):

- React projects often have no literal posthog.init(...) — config goes
  through <PostHogProvider options={{…}}>. The skill now detects either,
  writes masking into whichever it finds, and only aborts (no-init-call)
  when neither exists. Avoids a false abort on valid React apps.

- Word-bound the name/id heuristic so `pass` no longer matches `passenger`,
  `pin` no longer matches `spinner`, etc. — less over-masking, less noise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@joethreepwood

Copy link
Copy Markdown
Author

Thanks @sarahxsanders — both points addressed in fd9c087:

  • React <PostHogProvider> — step 1 now treats either a posthog.init(...) call or a <PostHogProvider> as a valid init site, and only emits [ABORT] no-init-call when neither exists (no more false abort on valid React apps). Step 4 writes the masking into whichever it found — session_recording on init, or the options={{…}} prop on the provider. The wizard's abort copy was broadened to match (feat: PII Bouncer program (engine) + robust PII scanner rules wizard#510).
  • Word-bounded the name/id regex/\b(pass(word)?|pwd|card|…)\b/i, so pass no longer matches passenger, pin no longer matches spinner, etc.

Also added a reciprocal breadcrumb back to the wizard's abort-cases.ts so the [ABORT] contract is explicit on both sides (e7c5bfa).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants