AI and data systems that survive contact with production.

Anyone can call a model. The engineering is in everything around it: moving messy real-world data into a usable shape, keeping the answer correct when a provider fails, holding a latency budget, and knowing what a model should never be trusted to decide. This page covers the constraints I have built against and the decisions that came out of them.

Three things I do well.

Applied AI

Putting language and vision models into products where the output has to be correct, fast, and affordable at volume.

  • Retrieval grounded in live production data
  • Model-agnostic architecture and failover
  • Structured extraction and classification
  • Governed decisioning with human limits

Data transformation

Turning unstructured and inconsistent sources into structured, queryable, trustworthy assets.

  • Ingestion, normalisation, deduplication
  • Entity resolution and relationship mapping
  • Knowledge graphs at six-figure scale
  • Document and vision-based extraction

Systems architecture

Designing platforms that keep running unattended, degrade predictably, and cost what they should.

  • Distributed services and scheduled workers
  • Multi-tenant isolation and access control
  • Cost and quota engineering
  • Observability and graceful degradation

The work.

Three systems, and the constraint that shaped each one.

Rippli

Production Financial Intelligence

A platform that maps how a single news event ripples across global markets, combining entity extraction, relationship mapping, and sentiment over a continuously updated financial knowledge graph. Live at rippli.ai.

  • Unstructured news into a queryable graph. The core of the system is a data transformation problem, not a prompting problem. Raw articles are normalised, deduplicated, resolved to known entities, and written into a graph where companies, people, sectors, and roles are connected. The model is one stage in that pipeline, not the product.
  • Migrated extraction from self-hosted models to an LLM without breaking consumers. Entity extraction and sentiment previously ran on locally hosted transformer models. I moved them onto a hosted LLM while preserving the original interfaces and data structures, so every downstream consumer kept working through the migration.
  • Parallelised inference to hold a hard latency budget. Sequential per-article analysis exceeded the pipeline's timeout. Restructuring the batch to run concurrently cut extraction time by roughly two thirds and brought the stage back inside budget.
  • Retrieval grounded in the production database. Before the model sees a query, a context service assembles company profiles, known relationships, historical mentions, key people, and financial metrics from the warehouse. The context budget is measured rather than open-ended, which keeps both cost and accuracy under control.
  • Progressive enhancement. A fast pass returns a usable answer immediately; a deeper enrichment pass upgrades the result in place when it completes. Each response carries its own analysis tier and confidence score.
  • Vendor independence by design. Multiple model providers sit behind a single interface, selected by configuration. If a provider degrades, changes pricing, or is unavailable, switching is a configuration change rather than a rewrite, and a missing provider degrades the feature instead of taking the service down.
Python Flask PostgreSQL Neo4j Redis Celery Next.js React Docker

Impact OS

Production Behavioural Systems

The operating system behind Cycle28's economic transformation programmes. It converts effort into verified income by encoding an entire 90-day programme in software: missions instead of task lists, behavioural currencies that cannot be faked, and one non-negotiable outcome, which is real income earned from a trained skill and verified by an outside party before day 90. It is not a learning platform, a task tracker, or a motivational app.

  • Humans teach, systems enforce. Programme rules execute in code rather than being administered by staff: mission sequencing, progression gates, support disbursement, and escalation all run unattended. That is what makes the programme repeatable across cohorts instead of dependent on whoever is running it.
  • Everything is a mission, never a to-do list. Each unit of work carries context for why it matters, a required real-world action, a difficulty level, a reward, and an explicit consequence for skipping it. At least one mission is always active, and none of them are optional.
  • Failure is classified, not punished. Inaction is the only unacceptable state. The system separates market rejection from non-response, declined offers, missed deadlines, avoidance, and burnout, then responds differently to each: crediting exposure, triggering a pricing intervention, or opening a welfare check.
  • Behavioural currencies that resist gaming. Consistency decays with inactivity. Capability accrues only through executed work. Courage is earned through real outreach and rejection, never for planning. The final currency is issued once, on externally verified income, and closes the loop.
  • Selection reads readiness, not polish. Intake deliberately discounts English fluency, presentation, and prior experience, because those select for access and confidence rather than for who will act once their blockers are removed.
  • Explicit limits on what the model may decide. AI classifies failure, personalises missions, tunes difficulty, and flags disengagement. It is expressly forbidden from overriding rules, granting exceptions, or determining who graduates. Verified income is the only proof of outcome.
TypeScript NestJS Prisma PostgreSQL Next.js Rules engine Event-driven

Content Engine

Production Multi-Tenant Automation

A multi-workspace publishing platform where each workspace is a separate property with its own audience, voice, sources, and content store, and nothing crosses a workspace boundary.

  • The cheapest inference is the call you never make. Candidate topics are gathered from public signals and filtered by deterministic scoring before any model is invoked. The expensive stage only ever sees material already judged worth paying for.
  • Quality gate with automated remediation. Generated drafts are evaluated against a house standard and returned for revision when they fail. Anything that still fails is held for human review rather than published. The pipeline degrades to a queue, never to poor output.
  • Provider-agnostic by construction. Hosted and self-hosted models are interchangeable behind one interface, and each workspace can pin its own choice or inherit the platform default.
  • Tenant isolation as a first-class concern. Per workspace configuration, hashed and rotatable credentials, signed delivery webhooks, and scheduled autonomous runs per property.
Node.js Next.js Prisma PostgreSQL Docker

Also shipping with AI

Data infrastructure

The ingestion and extraction layer feeding the graph above: resilient collection from primary sources, document parsing, and vision-based extraction for scanned filings that plain text parsing cannot read.

Dirra

Learning and mastery platform using generative models for content generation and assessment.

OfferAlert

Fixed-income opportunity discovery, applying document understanding to prospectuses and regulatory filings.

What production actually taught me.

Latency is a budget, not a hope

Decide the ceiling first, then let it dictate the architecture: what batches, what runs concurrently, and what happens only after you have already returned something useful.

Cost is a design constraint

Filter before you spend. Batch what is asynchronous. Self host where volume justifies it. Most AI cost problems are architecture problems wearing a billing disguise.

Every model call will fail eventually

Rate limits, timeouts, malformed output, changed response shapes. Fallbacks, timeout ceilings, defensive parsing, and fail-soft returns are the difference between a degraded feature and a dead pipeline.

The data work is most of the work

Retrieval from a source you already trust beats a longer prompt and a larger model. Normalisation, deduplication, and entity resolution decide the ceiling on quality long before the model does.

Schema is the contract

When one extraction path replaces another it should return an identical shape. Downstream code should not know which path produced the data. That is what makes an AI component replaceable rather than load bearing.

Decide what the model may never decide

Write the limits down before you ship. A system that can explain what its model is not allowed to do is a system you can defend to a regulator, a partner, or the person it just rejected.

Delivery & Advisory

The systems above are the credential. If your firm has sold a client an AI or data build and needs it delivered — architecture, build, and production operation — that is the work I take on. Advisory and a second opinion from someone who has already paid for the mistakes, likewise.