Hi – my name's Tom and I like making things.
Receive updates on my latest games, experiments and thoughts.
Unsubscribe anytime. Privacy notice.
"Everyone wants AI to do their laundry and not their art. Well, in the world of software engineering the equivalevnt of laundry is… GDPR compliance. So voilà, let's write an AI skill to do my proverbial laundry."
But before that, let's recognise something: Vibe coding is an amazing ability that is enabling builders around the world to create whatever they want without formal coding backgrounds. But are they ticking all the boxes before publishing their work online?
If a builder isn't careful, they could create a website and publish it without complying with European privacy law. You know those little cookie banners you see online? Those are because of GDPR – which stands for General Data Protection Regulation.
Personally I've had this website for a while and it's had different iterations. But recently I've been trying to be more consistent with my blogging, so I decided I wanted to add some analytics to see how that was going (spoiler alert: my traffic is up with 76.5% new users since I started posting regularly. With the more navel gazing-esque articles appearing to be the most popular).
But thinking about analytics on my own site meant I needed to think about the privacy regulations around a feature like that. This thought-process led directly to the idea for a GDPR AI skill inside my personal library of Antigravity skills.
Along the way, I learned how others are exploring this space, where privacy actually breaks across a modern web stack, and how combining deterministic scripts with agent reasoning turns a legal text and requirements into an actionable engineering check.
For anyone who hasn't had the pleasure: GDPR is short for "the General Data Protection Regulation". Introduced by the EU in 2018. is built on a simple premise – your personal data belongs to you, not the companies that collect it. Even something as small as an IP address or a tracking cookie counts as personal data. Crucially, the law follows where the visitor is, not where the developer lives: if someone in Paris opens your website, GDPR applies to you even if you coded it on a beach in Hawaii.
When I moved from Australia to France seven years ago, one of the first things that surprised me on the everyday internet was the sheer wall of GDPR pop-ups on every single website.
Historically, in much of the tech world the default mindset was to collect first, ask questions later. People would drop Google Analytics into their site and call it a day. Over time, different countries and governments have implemented various privacy laws. GDPR being one of the most famous.
So suddenly those harmless-looking engineering defaults weren't just bad hygiene – they became real legal risks.
Under the EU's GDPR (and the ePrivacy Directive), privacy isn't a legal disclaimer you merely slap in a footer at the end of a project. It's an architectural constraint.
A quick summary:
is_deleted = true.Regulation is complicated, dense, and written by lawyers rather than engineers. Nobody wants to read 99 pages of regulation before shipping a weekend prototype.
Which is why so many people still make mistakes in this space.
And worse: if you ask an AI model to build your app without specific guidance, the model might happily reproduce some of the industry's bad habits. Why wouldn't it? If it's trained on websites that have made the mistakes themselves.
Before diving in, I had a look around to see how other developers were tackling privacy and GDPR in the age of coding agents. Unsurprisingly, there are people are actively experimenting in this space – and the existing tools fall into a few interesting buckets:
Privacy-Data-Protection-Skills (which bundles 280+ structured skills across GDPR, CCPA, the EU AI Act, and LGPD) and Claude-Skills-Governance-Risk-and-Compliance focus on giving agents deep regulatory reference knowledge so they don't hallucinate article numbers when drafting DPIAs, privacy notices, or audit checklists.compliance-scanners and regional setups like deutsches-recht-mit-claude, which pairs a skill with an MCP server connected directly to Germany's federal law portal (rechtsinformationen.bund.de).I wanted to try something more mechanical: a hybrid engineering skill that pairs deterministic local scripts (a fast Python static codebase scanner and a headless Playwright browser inspector) with parallel agent reasoning – and actually clicks buttons on localhost to see if the app behaves itself.
As soon as you try to map GDPR articles to actual engineering checks, you realise why neither a pure regex linter nor a pure LLM prompt is enough on its own.
Regulatory compliance lives at the intersection of UI design, runtime browser behaviour, database architecture, backend data flows, and plain-English legal text.
Think about what a real privacy audit actually requires:
/privacy page to check whether those companies/brands are actually disclosed to the user.DELETE /api/user endpoint through server calls to database models.So in my gdpr-auditor skill, I structured the workflow into four phases combining deterministic scripts, reference data, and parallel subagents:
scan_gdpr_codebase.py)inspect_frontend_runtime.mjs)gdpr_compliance_report.md)Instead of guessing, the skill categorises every finding into one of four explicit dispositions: CRITICAL_VIOLATION, ARCHITECTURAL_RISK, NEEDS_LEGAL_REVIEW, or COMPLIANT, complete with clickable file-and-line links and the exact GDPR or ePrivacy article it maps to.
Building the skill and its scanner scripts forced me to break technical compliance down into four distinct pillars across the stack. Each one had gotchas that are remarkably easy to miss when you're heads-down building a product.
You cannot audit frontend privacy just by reading React or Vue files in a code editor. Too much happens dynamically at runtime via tag managers, third-party scripts, and CSS imports.
In Phase 1, the Python scanner (scan_gdpr_codebase.py) first separates consumer_facing routes from internal /admin routes, checks forms for pre-ticked consent boxes, and flags sensitive tokens or PII written to localStorage.
Then in Phase 2, the Node runtime inspector (inspect_frontend_runtime.mjs) spins up headless Playwright against the live URL and tests three distinct runtime states:
document.cookie, localStorage, and sessionStorage against a curated database (known_tracker_domains.json) of 20+ tracking domains and cookie prefixes (_ga, _fbp, ph_, mp_, _hj). Under the ePrivacy laws, any non-essential tracker firing here is an immediate critical violation.fonts.googleapis.com on page load, the visitor's browser automatically transmits their IP address to Google's servers without prior consent. Certain German courts have explicitly ruled this unlawful under GDPR. The fix takes two minutes – self-host the .woff2 files – but if you don't live in Europe, you'd almost never think to check for it.<button> while "Reject" is demoted to an inline <a> link.Moving down to the database layer opened up a completely different set of headaches.
First, scan_gdpr_codebase.py inventories schema files (like sql or other database formats) and separates Standard PII (email, phone, ip_address, geolocation) from something called Article 9 Special Category Data (health, biometric, genetic, religion, political_opinion, sexual_orientation, ethnicity) – which requires explicit consent and field-level encryption – fun stuff!
Secondly, it checks access isolation. In the era of Backend-as-a-Service tools like Firebase, it is super easy for a vibe-coded app to ship with a table missing basic PostgreSQL security rules or with a Firestore rule set like allow read: if request.auth != null – which politely allows any logged-in user to read the personal documents of every other user in the database.
Lastly, there's what we'll call the Soft-Delete Trap.
Engineers can be lazy so it's always tempting to just do soft deletes. This is when a user deletes their account and the programmer decides to just change a setting like deleted_at = NOW() or is_deleted = true to keep things simpler. Nothing breaks! Your billing history tables don't suddenly have opharns.
Except under GDPR Article 17 (Right to Erasure), if a user deletes their account and you keep their plaintext email, full_name, phone_number, or ip_address sitting in that row forever, you haven't deleted their data. It's obvious but a lazy developer might take this approach.
Creating the skill made me formalise what a compliant deletion cascade actually looks like: either hard-deleting the row with ON DELETE CASCADE, or – if you genuinely need to retain transaction records for tax laws – running an irreversible anonymisation pass that scrubs the PII columns.
Even if your database is locked down and your cookie banner is spotless, backend servers leak personal data like a sieve in two places: logs and third-party API payloads.
When we're debugging an auth flow or a webhook, logging object data to the web console is a handy shortcut. But suddenly, plaintext emails, IP addresses, and headers are sitting in a third-party logging sink that can be visible to other parties.
And in 2026, there is a brand-new egress vector that didn't exist when GDPR was written in 2016: LLM prompts.
It is extraordinarily easy to grab a full User row from some databases and pass the whole object into a prompt template, when the model only needed two non-identifying fields to do its job. Teaching the skill to trace outbound SDK calls and check for data minimisation before the data leaves the server was a valuable check for the whole flow.
Finally, there is the problem of drift.
A company writes a Privacy Policy on day one. Over the next three months, they swap one developer product API for another, add a new analytics tracker, and a new billing provider.
Over time the code iterates but the developer forgets to update the privacy policy.
To catch this automatically, scan_gdpr_codebase.py scans the repository for 20 common developer products and immediately cross-checks every discovered vendor against the actual text of the repository's /privacy and /cookies files – flagging any undisclosed vendors/integrations before a user or regulator notices the gap.
Of course, once the skill was working, there was an obvious next test: my own site.
So I asked Antigravity to run gdpr-auditor against the repository for tomgreenaway.com.
Now, this site is about as simple as web architecture gets: a static site built from Markdown files and some EJS templates.
To my relief, a few things were already compliant – mostly from earlier minimalism habits:
NunitoSans.ttf) and syntax highlighter (highlight.js) were already self-hosted in /resources/ rather than pulled from Google Fonts or a third-party CDN.build.js were already using youtube-nocookie.com (Privacy-Enhanced Mode).And yet the skill still immediately discovered some mistakes:
highlight.js, articles with Mermaid flowcharts were still pulling mermaid.min.js directly from cdn.jsdelivr.net – leaking visitor IP addresses to a third-party CDN on load.public/_headers was missing global Referrer-Policy and Permissions-Policy headers.I don't think anyone is a fan of cookie pop-ups. (I believe John Gruber calls intrusive modal overlays "Dick-Overs"? Vulgar but sentiment is on point honestly.) The absolute last thing I wanted to do to fix my analytics violation was bolt an obnoxious pop-up banner onto the front of my personal website.
So instead of using Google Analytics and adding a banner, I went with Cloudflare Web Analytics – which is cookieless, doesn't fingerprint visitors, and means I get lightweight traffic stats while avoiding pop-up banners altogether.
For the rest, it took less than five minutes to:
pages/privacy.md) disclosing Cloudflare and EmailOctopus, and link it directly underneath the newsletter form.mermaid.min.js into public/resources/ so diagrams render 100% first-party with zero CDN requests.Referrer-Policy: strict-origin-when-cross-origin, X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN, and a strict Permissions-Policy to public/_headers.Nobody wakes up on a Saturday morning excited to audit the privacy of their website – we want to build cool things, test ideas, and ship them to people around the world.
Historically, complicated regulations meant one of two things for small builders: either you ignored them and hoped for the best, or you got bogged down in compliance anxiety and delayed your launch.
But once you take the time to distil a complex domain – whether it's GDPR, accessibility, or security hardening – into a structured skill with deterministic helper scripts, that knowledge becomes portable and repeatable.
It isn't a replacement for a lawyer when you're scaling a company. Nothing in a markdown file or a Python script is legal advice. And to be clear, if you use my AI skill you do so at your own risk – I don't indemnify you at all.
But as an extra engineering guardrail? In a world where anyone can ship software globally in an afternoon, having an automated collaborator that understands the local legal rules – and happily folds the proverbial laundry for you – makes the web a little safer, a little more private, and a lot less stressful to build for.
What other laundry do you need taken care of for you?
Article published on: 25 Oct, 2026