I build the platforms other engineers build on. Payments first, then AI.
What I do
Twenty-plus years of shipping, seven of them inside one enterprise platform
Most of my work is infrastructure with an internal user base: the layer a product team injects and stops thinking about. I like the part where nothing exists yet and the shape of the thing is still an argument. I also spend a lot of time in rooms with executives, product managers and customers, which is why I care whether the abstraction survives contact with a real business. The newer work is in Python: multi-agent orchestration on Google's ADK, a coordinator that decomposes a request and delegates to specialist sub-agents, and agents wired to MCP tool servers.
LLM platform architecture
Multi-tenant SaaS
Payments integration
Distributed systems
Multi-agent orchestration
API design
PHP
TypeScript
React
Python
BigQuery
GCP
Google ADK
MCP
Platforms
Architecture only. No employer code, no client names, no internal identifiers.
A provider-agnostic AI platform
In production
One gateway. Every product team's model calls run through it, and none of them name a vendor.
Problem
Model calls were going to spread across a large monolith, each with its own client, its own error handling, and no way to answer "what is this costing us, and for which tenant?"
Design
A single injectable service behind a narrow provider interface. Callers pass a model variation such as "normal" or "pro" rather than a vendor model name, so no calling code anywhere names a vendor. Requests persist per tenant with input and output token counts, giving cost attribution and full history for free.
Result
Customer summaries, AI-generated preferences across two generations, message generation with brand-guideline enforcement, and the dashboard generator below all ship on the same foundation. Every rollout is gated per tenant.
Callers pass "normal" or "pro", never a model name, so the second vendor is a config change rather than a migration.
Every customer wants a slightly different view of their own data, and each one was a ticket: someone writes the warehouse SQL, someone lays out a screen, someone ships a release. That does not scale past the first handful.
Design
A generation job turns a plain-language request into a spec: warehouse queries, computed fields, and the UI components bound to them. The spec is data rather than code, so the same definition can be validated, repaired, versioned, localized, and rendered on web and mobile.
Result
A dashboard that used to be a release cycle is now a generation job, with a human approving each one before it goes live. Built with a second backend engineer: I designed the generation, validation and repair pipeline, and wrote most of the renderer.
the generation, validation and repair pipelinerepair loopstops and asks a person
Drafts that start closer to how you actually write, and get closer over time.
Problem
A generated customer message is only useful if it sounds like the person sending it. A draft that reads like nobody gets rewritten from scratch, which is slower than not having it. On top of that, every brand has rules about tone, banned words, signatures and whether emoji are allowed, and those rules differ by channel.
Design
Prompt assembly is layered and ordered: who the message is for, then the sender, then the location, then the brand rules, then the channel. Above that sit personas at three levels of specificity, with the most specific winning. Every layer is separately gated, so any of it can be switched off for one tenant without disturbing the rest.
Result
Drafts that land closer to the sender's own voice, with brand rules enforced per channel underneath. Mine since the first version, and still mine: I have maintained and extended it through every generation it has had.
The loop only works because the vocabulary is pinned: a free-form analysis would drift until the personas stopped meaning anything.
Card-present terminals, gift cards, and online, behind one interface.
Problem
Multiple payment providers, physical terminals in retail stores, and real money. Every failure mode is a customer standing at a counter.
Design
A provider-abstraction layer with connectors for each processor, per-tenant transaction logging, metrics, and provider health checks, so adding a processor does not touch the transaction flow.
Result
Still in production years later. Other engineers took it over and built well past what I left them, which is the outcome you want from an abstraction: new processors plug in without touching the transaction flow, and it stopped needing me.
The agent pipeline is the point. The game is what I pointed it at.
A real-time session manager for a tabletop role-playing game, built solo, to find out what one engineer plus a serious agent pipeline could actually ship. Nineteen custom automation skills plan, implement, review and ship the work; the app is the proof they hold up over five months and 1,300 commits rather than one impressive afternoon.
Nineteen skills that plan, implement, review and ship
In daily use, on a live codebase
Agents fan out across tickets in parallel git worktrees. Every gate that could merge something is deterministic, and every write to a shared system stops for a person.
Knowing when not to
Every gate that can let code through is deterministic, never a model's opinion: typecheck, lint, import-cycle and dead-code checks, 168 Playwright specs sharded in parallel, visual regression, performance budgets, supply-chain audit. A model proposes; only a test merges. Anything that writes to a shared system stops at a person first.
Measuring it
A reopen check flags any issue closed and then reopened inside seven days, the signature of a fix that satisfied the ticket but missed the intent. Building it taught me more than running it did: a separate audit found fourteen partial fixes on closed issues that the metric could never see, because the convention files those as new issues. A measure blind to its own target class reads green forever.
The app underneath
Real-time state synchronization across a table of players, live maps with fog of war, character and combat management, an image pipeline and a component library. React and TypeScript on Node and MySQL, 18 CI workflows, nightly deploys to self-hosted infrastructure.
The worktree isolation is what makes the fan-out safe: concurrent agents never share a checkout, so one run cannot corrupt another.
to add screenshots, an architecture diagram, and a short walkthrough video.
Developer tooling
Nobody asked for this. I built it because the same twenty minutes kept disappearing at the start and end of every ticket.
Twelve tools, from ticket to published documentation
In daily use by me and by teammates
Each one removes a specific twenty minutes I was spending by hand. None of them decide anything on their own.
What it does
Takes a ticket from untouched to merged and documented: open it with the right branch, worktree and context already loaded; review the merge request; write and publish its description; triage reviewer comments into a work plan; keep track of what is in flight across projects.
Documentation that shows the thing
The documentation tool does not just write prose. It generates the diagrams and it drives the product to capture its own screenshots, on the web app and on the iOS app, walking the real interaction and embedding the result. The merge-request descriptions use the same capture path, so a reviewer sees the change rather than a paragraph claiming it happened.
Beyond me
Pieces of it have been packaged up and handed to other developers on the team.
Claude CodePythonPlaywrightiOS simulator captureJira RESTGitLab APIConfluence API
Open source
Workflow skills for a self-hosted repo
Ready to publish
The Darkwatch toolchain, genericized so anyone can adapt it.
What
File and triage issues, open a pull request with a test plan and watch CI, verify QA tickets against a live app with Playwright, fan parallel agents out across tickets in git worktrees, and drive exploratory playthroughs that end in a written report. Each one documents honestly how portable it is, because most of this shape of tooling is quietly welded to one repo.
Status
placeholder Repository link lands here.
Contact
Currently open to staff-level work
I am most useful where something does not exist yet and someone has to decide what shape it should be. Remote, or Greater Toronto Area.