Engineering
How we build, and what we build with.
The sequence an engagement follows, the stack by layer, the architecture principles behind the systems we have built, and the checks this site passes before every release.
How we build
A sequence, not a slogan.
Six stages, in order. Each one ends with something you can hold us to.
Discover
The business, users, constraints and goals, written down and signed off.
Architect
The architecture, the system boundaries, and the latency and cost budgets.
Engineer
Reliable software and infrastructure, with a demo every cycle.
Integrate
Systems, services, data and automation connected and documented.
Deploy
CI/CD, containerised deployments and a runbook.
Scale
Performance, reliability and capability improved against the success measures.
In practice
How a project actually runs.
The same six stages, as the three phases a project runs in.
Discovery and plan
We agree on users, success metrics, constraints and risks, then produce a technical approach and milestone plan so everyone knows what “done” means and when.
Stages
- Discover
- Architect
Build in iterations
Working software every cycle, with demos, an open backlog, and early integration of auth, data and deployments — so problems surface when they are cheap to fix.
Stages
- Engineer
- Integrate
Launch and operate
Release with monitoring, runbooks and a sensible cutover. We support stabilisation after go-live and hand the system over properly.
Stages
- Deploy
- Scale
Technical depth
The stack, by layer.
Only what our repositories and shipped work show.
- Product
- React
- Next.js
- React Native
- Backend
- Node.js
- NestJS
- Django
- GraphQL
- REST
- gRPC
- Socket.IO
- Data
- PostgreSQL
- Redis
- pgvector
- WatermelonDB
- SQLite
- AI
- Claude
- GPT-4.1
- Embeddings and retrieval
- Agents
- Infrastructure
- Docker
- Docker Swarm
- GitHub Actions
- Vercel
Architecture principles
Principles we can point to.
Each comes from a system we have built, and links to where it is written up.
Route before you pay for a model
The restaurant search classifies every query with ordinary code before any paid inference runs. Only the lane that needs a model calls one, so most traffic never reaches a model.
Written up in
Give the model the narrowest job
In the AI lane the model reads a sentence and returns structured intent, nothing more. Claude Haiku does that job, not a frontier model; retrieval and ranking stay in Postgres and in our code.
Written up in
Cache repeat demand
Search results live in Redis under a key built from the tenant, the query, the location, the filters and the lane, so a popular query is computed once and two tenants never share a result.
Written up in
Enforce tenancy in the database
Tenant isolation is a Postgres row-level security policy, not a WHERE clause someone can forget. It fails closed: a query with no tenant set returns no rows.
Written up in
Let one failure stay one failure
In WarmChats each inbound message is an event, and qualification, reply generation and calendar writes are separate consumers, so a failure in one does not silently drop a lead.
Written up in
Keep the till selling offline
In the restaurant point of sale we built, every order is written locally together with its outbox row in one transaction, and a background worker syncs it when the network allows.
Written up in
Make retries harmless
The server upserts each synced order on its terminal and the id the till generated, so a batch sent twice still records one order.
Written up in
Label every figure
Every number we publish says whether it was measured on a running system (shipped) or is a target, and a budget is never rounded up into a result.
Written up in
Verify before release
Checked before every push.
This site is held to the same discipline. Before every push it runs through a black-box test suite that loads each public page in a real browser, at phone, tablet and desktop widths, and fails the release on any of these:
- A figure without its shipped or target label — in the text, in the page's metadata or in its structured data.
- A page without exactly one h1, or with a heading level skipped.
- A keyboard stop with no visible focus, or one hidden under the sticky header.
- Text below AA contrast against what is actually behind it.
- Content that is invisible with JavaScript off, or still hidden after a reading-speed scroll.
- Sideways scrolling or cut-off content at any width it tests.
- A template, placeholder or generated face, or a named person on the team section, which shows a headcount only.
- A project card that does not say who built it, or a screenshot that does not load.
- Structured data that disagrees with the page it describes.
- Anything still moving when reduced motion is requested.
- A piece of inventoried content missing from its page.
Some of it is refused earlier, by the build: content that fails its schema — an unlabelled figure, a named team roster, a Lab capability without its honesty line — stops the build and names the file.
Have a complex problem?
Let's turn it into an engineered system.