Skip to main content

The Engineer

Software engineering work: selected projects, stack, and role on each.

I'm a software engineer at Epic Web Studios, building AI-native tooling, audit platforms, and the automation an agency runs on day to day. Nine of those projects are below, with the stack and my role on each. The charts and commit counts cover the eight that live in git; the ninth is a Shopify theme, which has no repository to count.

Projects

Selected Work

Engineering projects with stack, role, and commit history.

1,627 commits over 16 consecutive months, every one of them active.

Spread across 165 days on which something was committed, out of 441 calendar days. The span is not the effort. 1,627 of the 1,822 commits in these repositories are mine, and only 1 of the 8 projects had another contributor at all.

Columns are commits that month. Each mark below the axis is one project I committed to that month : a single project through Feb 2026, then never fewer than 3 at once, peaking at 6 in Jun 2026. The busiest month was Jul 2025 at 283 commits. The final month runs only to 16 September 2026, when these figures were collected.

Show the monthly figures
MonthCommitsProjects worked on
41
2831
1741
1011
621
191
501
871
331
1825
1555
434
2506
1226
535
(to 16 Sep)93
Total1,627

1,627 commits across 8 projects, Jun 2025 to Sep 2026.

Each bar spans a project’s first to last commit on its default branch. Bar length is elapsed time, not effort, so the commit count is given separately on every row.

  1. SSA Tool: AI-Powered SEO Analysis Platform995 commits, 14 months
  2. Claude Chat: Desktop Client for Claude Code79 commits, 5 months
  3. claude-code-index12 commits, 6 months
  4. Epic Agent: White-Label RAG Chatbot Platform370 of 565 commits, 6 months
  5. winscp-mcp4 commits, 4 days
  6. Claude Code Automation Suite57 commits, 5 months
  7. InMotion Watcher: Server Security Infrastructure15 commits, 6 weeks
  8. EWS Dev Tools: Hosted Diagnostics MCP Server95 commits, 3 months

878 source files across the 8 projects tracked in git, in 8 languages.

TypeScript and Python are 64% of it, but not in the same way: TypeScript is concentrated in 2 of 8 projects, while Python reaches 6. Counted by file, not by byte or line, after excluding 426 vendored and generated files, a checked-in browser driver and a folder of test output would otherwise dominate the totals.

  1. TypeScript296 files, 2 of 8
  2. Python265 files, 6 of 8
  3. HTML84 files, 5 of 8
  4. SQL79 files, 3 of 8
  5. Shell72 files, 4 of 8
  6. JavaScript55 files, 4 of 8
  7. PowerShell16 files, 3 of 8
  8. CSS11 files, 4 of 8

Bar length is tracked source files, scaled to 300. Markdown is excluded . There are 274 Markdown files across 7 of the 8 repositories, which says something about the documentation but is not what any of this is built with.

Show the language figures
LanguageSource filesProjects using it
TypeScript2962 of 8
Python2656 of 8
HTML845 of 8
SQL793 of 8
Shell724 of 8
JavaScript554 of 8
PowerShell163 of 8
CSS114 of 8
Total878
  • SSA Tool: AI-Powered SEO Analysis Platform

    Multi-user web platform that crawls a site's sitemap, captures full-page screenshots, performs deep technical-SEO extraction (meta, headings, links, schema, Core Web Vitals), and generates AI-authored findings tuned for AI search engines. Includes authentication with isolated per-user dashboards, an admin console, background job processing with live progress, a domain scoring system across eight SEO categories, and professional PDF report generation. Runs as internal tooling at Epic Web Studios, where the team reaches it both through the web interface and as an MCP server.

    Sole author

    Python, Playwright, OpenAI API, MySQL, SQLite

    995 commits

    to

  • Epic Agent: White-Label RAG Chatbot Platform

    Multi-tenant platform that deploys branded AI chatbots on client websites, answering visitor questions from the client's own content. Architected the full crawl-embed-classify-retrieve-generate pipeline: a Playwright BFS crawler that renders JS-heavy pages to clean markdown, structure-aware 512-token chunking with local embeddings, a combined safety-and-intent classifier in a single model call, cosine-similarity retrieval with a live web-fetch fallback for low-confidence queries, and grounded generation with source citations. Dockerized with CI/CD deploys.

    Primary author

    TypeScript, Node 22, PostgreSQL, pgvector, Claude API, Playwright

    370 of 565 commits

    to

  • EWS Dev Tools: Hosted Diagnostics MCP Server

    Team-hosted MCP server giving the whole dev team a shared client-site operations toolbelt: tech-stack fingerprinting, HTTP inspection, SSL and DNS checks, blacklist and email-deliverability lookups, WAF testing from an alternate egress IP, credential-aware database query and dump, pre/post-launch audits, and internal-linking analysis. Auto-discovers site credentials by domain via the hosting control panel rather than requiring manual configuration.

    Sole author

    Python, Model Context Protocol

    95 commits

    to

  • Hot Cut Calculator: Made-to-Order Pricing on Shopify

    Custom Shopify build for The Ribbon Factory, a sixth-generation American ribbon manufacturer, replacing a legacy quoting page with a made-to-order pricing tool. Hot cutting is a thermal cut that fuses the ribbon end so it cannot fray; it is billed per piece on top of the ribbon, and whole rolls have to be cut end to end. So the calculator turns a job spec (cut style, length, piece count) into the rolls to buy, the pieces the customer will actually receive, and the tiered per-piece fee, recomputed on every keystroke, with a per-style waste model, per-style length limits, and a width parser that accepts 7/8 and 1 1/2 as readily as 1.5. It adds two paired cart lines, the ribbon rolls and a cutting-fee variant, so the price comes from Shopify's own catalogue and is never sent by the browser, then guards the pair with a Liquid classifier that stops either line being orphaned or quantity-edited. A second mode prices cutting for ribbon the customer ships in, estimating the yield first so nobody can order more pieces than their yardage produces. The build also includes a Shopify Function, JavaScript compiled to WebAssembly, running on Shopify's own purchase.product-discount.run target, that sums yardage across the whole cart and applies one volume tier to the ribbon lines while excluding the cutting fee. 3,381 lines across eight new files, with four edits to the stock Dawn theme's 410.

    Sole author

    Shopify Liquid, JavaScript, Shopify Functions (WebAssembly), GraphQL, Dawn 15.4.1

  • Claude Code Automation Suite

    A complete workflow-automation layer for the team's AI coding environment: 40 reusable skills covering technical-SEO audit passes, accessibility testing, malware scanning, DNS management, deploy pipelines, PDF generation, and client reporting; plus 8 specialized review subagents (security/performance validation, accessibility auditing, debugging, deliverable QA, cross-model second-opinion review) with a model-routing strategy that matches task risk to model tier to control cost.

    Author

    Markdown, Python, Bash

    57 commits

    to

  • Claude Chat: Desktop Client for Claude Code

    Electron desktop wrapper around the Claude Code CLI adding image paste, voice readback, a session-status overlay, and a full GUI. Debugged and fixed terminal-rendering defects at the ConPTY and WebGL layers, tracing scrollback corruption to row churn from an auto-growing input and gutter artifacts to a transparency setting in the WebGL renderer.

    Sole author

    JavaScript, Electron, xterm.js

    79 commits

    to

  • claude-code-index

    Local MCP server providing semantic code search over per-project vector databases, with incremental reindexing.

    Author

    Python

    12 commits

    to

  • winscp-mcp

    MCP server exposing FTP/SFTP site management for AI-assisted deployment workflows.

    Author

    Python

    4 commits

  • InMotion Watcher: Server Security Infrastructure

    Defensive monitoring and automated-response system for the agency's shared cPanel server. Detects suspicious FTP and SSH activity, deterministically blocks offending IPs, quarantines recently modified files by the suspect account, rotates credentials, and dispatches alerts, with an investigation workflow for triaging each incident and distinguishing true positives from allowlisted staff activity.

    Sole author

    Bash, systemd

    15 commits

    to

Incident response

When something is on fire

Two unrelated intrusions three weeks apart, on different servers, with different attackers. Plus the audit where I found my own monitoring had been quietly broken for months.

Shared-host intrusion

A seven-day active intrusion on a shared host carrying 302 client accounts, contained with no data lost on any account.

May 2026

Led the response

I did not find this one. The host’s daily malware scanner flagged it and the hosting provider’s staff confirmed it; I led the remediation with them over the following week. The compromise reached root, which meant the response had to assume every credential on the box was already in someone else’s hands and act on that assumption rather than hunt for proof of it.

They were not after the data. The payload hijacked visitor clicks and pushed them out to online casino affiliates, so every compromised site was quietly monetising its own audience for someone else. That shapes the response: the damage is to the client’s traffic and reputation rather than to their records, and it is invisible from the admin side.

Two moments decided the outcome. A full-access root API token was created while the incident was still open, and was revoked with the session that made it still live. And a second sweep, run because the first pass had a blind spot I could name, turned up two obfuscated backdoors the first cleanup had walked straight past. Nothing was deleted. Every artifact was quarantined and preserved, because a cleanup that destroys its own evidence cannot be audited afterwards.

client accounts on the affected host
302
of active intrusion, contained
7 days
cPanel passwords rotated in one proactive sweep
296
accounts’ CMS files reverted after a hijacked sync
90+
upload directories hardened; 1,106 others deliberately left alone
611
previously compromised accounts re-verified two weeks later, all clean
22
What went wrong

Five sites dropped during the password sweep, my own change:, a database host-entry mismatch, diagnosed and restored in about ten minutes. The attack caused no outage; I did. Ten minutes on five sites bought 296 rotated credentials in a single pass, and 302 accounts that kept their data.

Ransomware recovery

An 11.2 GB database recovered in full, a rebuilt site verified in production four days after encryption, and no ransom paid.

eriereader.com

May 2026

Led the recovery and the rebuild

Files across the site were encrypted overnight on 1 May 2026, with a ransom note dropped into every directory on the way through. The database survived and came back whole by a separate route. Everything else had to be rebuilt.

Before choosing how to recover, I measured the encryption itself rather than reaching for a tool and hoping. Those measurements established that the weakness this family is normally broken on was not present, and predicted that the public decryption tool would not even recognise the format, which it then didn’t. I deliberately did not approach the operator.

The rebuild started the next day and shipped faster than the site it replaced: cold-visitor weight roughly halved and warm-cache response time fell from about 400 ms to about 80 ms. The security fixes the old codebase needed were made during the rebuild rather than written down for later.

database recovered in full
11.2 GB
ransom paid
None
from encryption to a verified production site
4 days
commits on the rebuild
251

Auditing my own monitoring

Nine monitoring components were running, exiting clean, logging success, and structurally incapable of ever firing. I found them by auditing my own work.

September 2026

Self-initiated

Months after the intrusion I went back and asked whether the detectors I had left behind could still detect anything. Nine of them could not. Each ran on schedule, returned success and wrote its log line, and none of them was capable of raising an alarm. One was the watcher that watches the other watchers, and it had already sent two genuine alerts into a delivery path that reached nobody.

A detector that cannot fire looks exactly like a quiet one. So every repair carried a control that has to fail: the fix is not accepted until something deliberately trips it and the alarm arrives. They were then proven in production the following morning rather than asserted.

components running, reporting success, structurally unable to fire
9
genuine alerts the watcher-of-watchers had already sent into a dead path
2

The monitoring left behind after the first incident was last confirmed running in September 2026, with no indication of compromise.

Random Dad Jokes

301 dad jokes. 243 of them recovered from my own Android app by unpacking its APK; the rest written to fill the categories I never got round to.

Random Dad Jokes

Gathering Dads Now…