I build the tooling a 679+ site agency runs on.
88 headless Next.js sites and more than 500 WordPress builds, for multi-location practices with real traffic, real lead flow and no tolerance for downtime. I also build the internal tooling the agency uses to produce them.
01
Internal tooling
Designed and built a WordPress/Elementor plugin, now live in production across the agency, that generates client sites from Word documents and an SEO spreadsheet. A REST API, a resumable batch engine with per-page rollback, site-wide restore points, backup-before-write on every page, WP-CLI commands, and a permissions-gated admin interface. It takes a 20-page site from 12 to 16 designer-hours down to 1 to 2. A companion plugin cut the image work to 10 to 20 minutes, so a full client build went from 2 to 4 days to roughly half a day including QA.
It ships with an end-to-end test suite built in Playwright, running against a real WordPress install rather than a mock. The tests cover the permission boundary, REST authentication and nonce enforcement on every route that can write, and the blast radius of the destructive operations, proven against a canary page rather than assumed.
02
Headless front end
Build, fix and maintain the agency’s headless WordPress front end: a Next.js, React and TypeScript application consuming WPGraphQL through Apollo, serving 88 production client sites. Traced and fixed a defect that was rendering the blog archive’s SEO metadata on every individual post, which meant every article across 68 sites was canonicalizing to a single URL. Nothing in the CMS looked wrong and nothing threw an error. It was only visible by reading what the server actually returned to the browser.
03
Design systems
Own the design system behind a landing-page generator: a canonical section order and a set of reusable modules that hold 24 generated pages, across four practices, two templates and three variants, structurally identical to one another. Wrote the verifier that enforces it. It checks the rendered HTML rather than the source, so a guarantee that did not survive rendering cannot pass, and it covers section order, mandatory modules, semantics, element ids and color contrast.
04
Open source
wp-e2e-kit is a Playwright library for testing the parts of a WordPress plugin that fail quietly: the capability gate, REST authentication, and how far a destructive operation actually reaches. Most plugin tests drive the happy path, which is worth having but is not where the expensive failures live.
Three of its assertions exist because tests I wrote passed while proving nothing. A route registered for POST answers a GET with 404, so checking for any status above 400 reports a security boundary is holding when the request never reached a permission callback. WordPress validates required arguments before it runs the permission callback, so an empty request body returns 400 without ever consulting authentication. And a suite made entirely of refusals still passes if you delete the plugin, which is why the library forces you to prove an authorized call succeeds.
didntrun is the same idea as a service rather than a library. Jobs check in on a schedule and it alerts when one stops, because a cron job that dies does not send an error, it sends nothing, and nothing looks exactly like success. I built it after losing eighteen days of backups to a job that had quietly stopped while every monitor stayed green. It runs on AWS: FastAPI in a container on Lambda behind API Gateway, PostgreSQL on RDS in a private subnet, and EventBridge running the sweeper every minute.
Then the same failure happened to the service itself. The Lambda runtime installs its own root log handler during initialization, which makes a later basicConfig call a silent no-op, so it ran correctly for several minutes with every alert going nowhere. Alembic’s logs were arriving the whole time, which is what gave it away. The write-up is in the repository, because that failure is the entire argument for the project.
orrery is a real-time multiplayer physics arena in Java that you can play right now (source), and it is here for the opposite reason to the rest of this section. Nothing about it fails quietly. It is the case where I wanted a number instead of an argument: two teams fight over a captured star in zero gravity, the server is authoritative on a fixed 60Hz tick, and the browser predicts its own player forward and corrects itself when the truth arrives, so the controls answer on the frame you press them rather than after a round trip.
The physics is written twice, once in Java for the server and once in JavaScript for the browser. A drift check runs both for six hundred ticks and fails the build if they disagree by a single bit, because a prediction built on two simulations that are nearly the same is a prediction that is wrong later instead of now. Prediction error is measured by a headless client that plays a real match against a live server, and it reads 0.000000 units.
It took four wrong answers to get there and all four are in the repository. An input queue and a tick clock are two clocks, and letting them race cost a quarter of a body of permanent error. A client that only simulated the ticks it had inputs for drifted whenever a packet was late. A measurement that compared the client’s present against the server’s past reported the lead as an error. And lag compensation, which is the textbook answer, made this particular client worse and was taken out, because this one extrapolates rather than rendering in the past. The reasoning stayed in the file so the next person does not add it back.
sentinel exists because a client site I maintain was compromised and nothing said a word about it. The attacker created administrator accounts and dropped a webshell in a folder named to look like a security plugin. Both are loud, obvious events. Nobody was listening for them, and it surfaced weeks later through a traffic spike on search terms that had nothing to do with the business.
It is one must-use file that reports the moment an account becomes an administrator, a plugin folder appears on disk, or core files stop matching the checksums WordPress publishes. It has no settings screen, no REST route and no admin page, because monitoring added to a site that may already be hostile should not widen the thing it is watching. The plugin the attacker used was marked inactive the whole time and still answered on a direct URL, so deactivation was never the boundary anyone assumed it was.
The part I care about is the silence. A daily heartbeat goes out whether or not anything happened, so deleting the plugin is itself detectable: a site that reports every day and then stops is telling you something. Two things were only found by testing rather than reasoning. WordPress fires set_role before user_register, so creating an administrator raised two alerts for one action until the hook order was read rather than assumed. And WordPress implements non-blocking HTTP as open-socket-and-walk-away, which is the wrong trade for an alert that fires twice a year, so delivery is now confirmed and the outcome recorded.
These installs get cloned to spin up new sites, and a clone inherits the label configured for the site it came from. Every alert therefore carries the live domain read at runtime, not the configured name, and flags itself when the two disagree. An alert titled with the wrong client is worse than no alert at all.
wp-e2e-kit
Playwright helpers for WordPress capability gates, REST auth, and destructive blast radius.
quietfail-action
Runs quietfail in GitHub Actions, so the rules fire in CI instead of on request.
orrery
Multiplayer physics arena in Java. Authoritative tick, client prediction measured at zero error. Play it.
sentinel
WordPress intrusion alerting in one must-use file. Heartbeat makes deleting it detectable.
05
Selected client work
Infinity Dental↗
ASAP Dental Care↗
Seville Dental Aesthetics↗
Progressive Dental Marketing↗
Smile Rescue↗
Smiles of Naples↗ 06
Stack
WordPress: plugin and theme development, hooks and filters, WP-CLI, must-use plugins, REST API, block themes and the Site Editor, WooCommerce, Elementor, Beaver Builder, Oxygen, migrations and launches, managed hosting (Kinsta, Cloudways, Sevalla)
Front end: Next.js, React, TypeScript, WPGraphQL and Apollo, Tailwind, HTML5, CSS3/Sass, Three.js and WebGL
Languages: PHP, JavaScript, TypeScript, Python, Java, Ruby, C#, SQL · Node/Express, FastAPI, Rails, Laravel, Angular
Back end: REST APIs, WebSockets, an authoritative server on a fixed tick with client prediction (Java 21, Javalin, Gradle)
Cloud & infrastructure: AWS (Lambda, API Gateway, RDS PostgreSQL, EventBridge, IAM), Terraform, Docker, Fly.io, GitHub Actions CI, PostgreSQL, MySQL and MariaDB, DNS, domain management, email/MX and deliverability, Git
Testing: Playwright, Vitest, JUnit, end-to-end suites against real environments: a real WordPress, a real Postgres, a real browser
Incident response: the person called when a site is down, mail stops arriving, a form quietly stops sending, or a launch goes wrong. Crashed sites, DNS and MX, authentication and sender reputation, plugin and theme conflicts traced to the cause rather than the symptom. Under time pressure, routinely outside business hours, with no separate operations team behind me
Security: found and remediated a compromised client site: a webshell hidden in a plugin-shaped folder, rogue administrator accounts, doorway pages serving search traffic. Wrote the must-use plugin now watching for the next one, which alerts on new and promoted admins, files appearing on disk, core files drifting from the WordPress.org checksums, and a daily heartbeat whose absence is itself the alert. HMAC signed webhooks. Capability and nonce enforcement proven by tests rather than assumed
Also build in: Webflow, Wix, Duda, DNN/DotNetNuke
Analytics & compliance: Google Analytics 4, Google Tag Manager, HighLevel (CRM), technical SEO, ADA/WCAG remediation
07
Contact
I’d love to hear from you.




