Changing regulated platforms
Retire systems, move data and rotate credentials without losing the records or the audit trail.
Writing
Architecture, delivery and lessons learned, from ingesting the Twitter firehose for trading firms to building white-label banking platforms and practising agentic engineering.
Start here
A few routes through the writing, selected by problem rather than publication date.
Retire systems, move data and rotate credentials without losing the records or the audit trail.
Make payment timing, prices and discounts explicit contracts rather than scattered configuration.
Agree the contract, challenge the tests and keep the author separate from the reviewer.
Count migration effort and opportunity cost, then fix the bottleneck that matters.
Archive
I once sold a WorkSite mobility product to Interwoven. Looking back, the interesting part was not the handset UI but the server-side integration, queuing and extension points that made mobile workflows dependable.
Before AirTag, we built a prototype child-tracking system around Bluetooth tokens, an iPhone app, shopping centre receivers, and a Rails backend. Looking back, the strongest lesson was that platform rules, hardware economics, and privacy constraints mattered more than the code.
Rereading my final-year project from the mid-1990s, I was struck by how little the core lessons have changed. The stack is obsolete, but the habits still look right: understand users, iterate, separate concerns, write things down, and design for change.
FHIR has no ClaimBatch resource, and NCPDP batch files don't care about REST. How we composed Task, List, Claim, ClaimResponse, ExplanationOfBenefit and PaymentReconciliation into a claims lifecycle with at-least-once delivery that's safe to retry.
Token pruning, native REST tools that skip the model, a three-tier agent budget, and the small terminal extensions (vi mode, statusline, notify, theme) that make a Pi workflow comfortable all day.
The six natural-language skills, the fleet of phase and review agents, and the MCP servers that sit behind my Pi workflow, from the morning briefing to commit and pull request.
How a Pi extension runs a full agentic SDLC through hooks the agent never sees: shift-left gates by phase, TDD with isolated test authoring, a dangerous-command gate, plan mode and git worktrees.
Independent review agents, decision packets built for thirty seconds, and a plain list of what ACCORD has cut or only half built. How to keep an agent harness honest about its own limits.
Why ACCORD pushes decisions left: tests written from the spec alone, an adversarial review before any production code exists, and three layers of protection that keep most checks off your attention.
A seed job, a build artifact, five services across three package managers and an AWS emulator, all brought up in dependency order and wired to each other by one command. How we built a thin orchestration layer from a YAML registry, a pure-JS resolver and Tilt, and the things we deliberately didn't build.
Four years on from my Babylon-era setup: agent skills in Pi, tmux and Neovim as the whole IDE, Gmail in the editor, dotfiles that build a machine in one command, a PARA notes repo as a second brain, and the same session from desk, iPad or iPhone over Tailscale and mosh.
A replacement workflow engine would have cut the licence bill by more than 90%. The honest business case said the question wasn't cost at all. How to write a platform-migration case that counts engineering time, opportunity cost and operational maturity honestly.
Entering a market that requires patient data to stay in-country doesn't have to mean cloning your whole platform. Split it into data cells and processing hubs, then hunt down the places data quietly comes to rest.
Most agent setups optimise for capability. I optimised for attention, and built ACCORD, a Pi extension that turns a free-text request into a verifiable contract before anyone writes code.
When one feature means five coordinated PRs and a shared dev environment, a new runtime platform won't save you. A monorepo, a one-command local stack, contract tests and preview environments will, whether the humans or the AI agents are writing the code.
Every promotion modelled as a new Stripe price multiplies into hundreds of IDs that drift. Here's the standard we adopted: prices are list prices, every adjustment is a coupon, and plans are versioned documents, not dashboard clicks.
Conditional create on top of an eventually consistent search index will create duplicates under load. A small, strongly consistent write barrier fixes it, and the hard part is choosing the uniqueness key, not the lock.
A rotation playbook for third-party credentials across environments and regions: overlapping validity, dual-running webhook secrets, a boring checklist, and the audit trail you need before an incident, not after.
A requirement to 'pause' a care programme turned out to be four independent behaviours. Model it as a time-bounded hold with declarative effects rather than a lifecycle status, and one mechanism covers every kind of delay.
A per-signature SaaS bill that grows with every prescription. Designing an in-house Advanced Electronic Signature pipeline to replace it: the cryptography is the easy part; the migration design is what makes it safe.
Eleven extensions, six skills, eighteen agents and a token budget: how I rebuilt my whole working day inside a terminal-first coding agent, from morning briefing to verified pull request.
We wanted a Heroku-like developer experience without leaving AWS or re-platforming our data. A requirements-first evaluation of managed runtimes found two gaps every vendor shared, and a few questions worth asking before any pilot.
Five skills, thirteen single-purpose agents and a spec that travels with the code: how I structured AI-assisted delivery so every session starts fresh and every change is verified against written acceptance criteria.
Adding pods made things worse. Before you switch on a Horizontal Pod Autoscaler, you need admission control, bulkheads and fan-out budgets. Otherwise more replicas just means more retries hitting the same bottleneck.
Two payments RFCs from the same week: a stacking policy for employer coverage, coupons and referral credits, and a design for several payment accounts in one deployment. Both are cheaper to decide before marketing and partnerships need them.
A TV advert means a traffic spike you can't schedule precisely, because catch-up viewing exists. Our plan: config-only scaling first, fix the one call every request makes, then add application-level protection with a go/no-go gate two weeks out.
A payment service that knows about referral credits, employer coverage, promotions and shipping has to change for every new business idea. Push business rules out into resolvers that produce line items, and the core never changes again.
B2B health programmes live or die on two files: who is eligible (in) and what happened (out). Design both as versioned contracts with clear keys, and you get easier onboarding, easier reporting and fewer awkward client calls.
Isolating business operations from each other is a good instinct, until every operation carries its own client for the same third-party API and its own reading of the same data. Share contracts and integration clients; keep behaviour isolated.
In chronic care, the normal latency of an interaction is days or weeks. Model those interactions as tasks, not synchronous flows, and you can control demand, set honest expectations and survive a cohort-sized spike.
When two businesses sharing one Stripe account need to separate, the question isn't how to move customers. It's which customers to move. Move the smaller, quieter population and leave the growing one alone.
Switching off a platform is easy; keeping its patient records accessible for regulators, lawyers and GDPR requests for another decade is not. How we chose a single final resting place and built a simple, repeatable export.
When a regional business is divested, the shared services it depends on have to move too. A practical checklist for relocating a multi-tenant service and its data: stand up, copy, prune, re-point, verify.
A reusable request → fulfil pattern for products and services, with payment treated as just another eligibility gate. It works the same for direct-to-consumer and employer-funded customers.
How a four-line change, AES decryption and Ruby's Global VM Lock turned into a P1 incident, and what it taught us about understanding the runtime beneath our code.
Time-blocking, batching context switches, and a modal, terminal-first setup on an iPad Pro: how a Principal Engineer protects focus while bouncing between teams.
Six weeks of trying to code from an iPhone 6 Plus with a monitor and Bluetooth keyboard: what worked, where the device fell short, and why I moved on to a cellular iPad Air 2.
Why I moved my primary coding environment to a cloud VPS in 2014: Vim, tmux and mosh over SSH, Dropbox as a safety net, and what it meant for working on poor connections at customer sites.
What FSWire offered financial firms in 2013: a multi-stage funnel filter that turns hundreds of millions of daily tweets into a structured, relevant stream, and the case for buying that capability rather than building it.
Reflections on analysing hundreds of millions of tweets a day for financial insight, and why a hypothesis-first approach to big data can't scale when there aren't enough data scientists to ask the questions.
Announcing a 1.0 beta API that exposed FSWire's real-time social analytics (sentiment, volume and trending for US and UK securities and FX pairs) as JSON, free for personal use.
Why predicting stock prices from social sentiment alone was naive, and how FSWire moved from raw sentiment to curating context-sensitive content, event detection and a Social Strength Indicator.
Why the links inside social posts turned out to be rich signals: expanding shortened URIs, who shared them and when, and how that fed junk filtering, relevance and authority models for financial content.
How the FSWire stack was put together in 2013: Rails on Heroku for the dashboard, and an analytics backend built on RabbitMQ, Redis, Postgres, MongoDB and MapReduce, consuming around 1 TB of Twitter data a day.