Skip to content
Engineering

Not a list of technologies. The reasoning behind each one, and what it costs us when we're wrong.

The order we work in

Guarantees first. Features inside them.

Most systems fail because nobody chose what they must never do. Ordering, consistency, durability, privacy: these get assumed rather than decided, and assumptions do not survive load. So we settle them first.

Only then do we design the product — inside the constraints those guarantees create. It looks slower on day one. It is faster over the life of the system, because the rewrite that usually comes never does.

A stack of platform layers with glowing edges
Disciplines

Eight things we do, and how we do them.

Architecture

Decide the guarantees before the diagram.

We start from the invariants a system must never violate: ordering, consistency, durability. The structure is derived from those. Boundaries follow data ownership, not org charts, so a service can be understood without reading the ones around it.

Event-drivenCQRSDomain boundaries

Backend

Go services that stay simple under load.

Statically-compiled Go behind gRPC, with Postgres as the system of record and Redis where latency demands it. Handlers stay thin, domain logic stays testable, and anything slow moves to a queue rather than a bigger machine.

GogRPCPostgreSQLRedis

Frontend

Server-first React that ships less JavaScript.

Next.js App Router with React Server Components by default. Client components are the exception, reached for only where interaction demands them, which keeps the hydration cost proportional to what's actually interactive.

Next.jsReactTypeScriptTailwind

Mobile

One Flutter codebase, native where it counts.

Flutter for iOS and Android against the same API contract the web uses. We drop to platform channels only for the things that have to be native: biometrics, secure storage, background sync.

FlutterDart

Cloud & infrastructure

Every environment is a Terraform plan.

GCP, described entirely in Terraform. There is no console-clicked resource anywhere in production, which means an environment can be rebuilt from an empty project and a git checkout.

GCPTerraformKubernetes

DevOps

Deploys are boring on purpose.

Trunk-based development, containers built once and promoted through environments, progressive rollout with automatic rollback on SLO burn. The engineer who wrote it is the one who ships it.

DockerGitHub ActionsPrometheusGrafana

AI

Models narrate. Code computes.

Retrieval over your own data, deterministic aggregation before inference, and evaluation suites that gate every prompt change. If a model states a number, that number was calculated in code first. The model is never the source of truth.

PythonRAGEvalsVector search

Data

Schema is a contract, migrations are code.

Normalised Postgres with explicit, reversible migrations that run in CI before they run anywhere else. Analytics reads from replicas, so a slow dashboard query can never take the product down with it.

PostgreSQLKafkadbt
Process

How an engagement runs.

01

Discover

Understand the domain and, more importantly, the failure you're trying to avoid.

02

Design the guarantee

Settle ordering, consistency, durability, and privacy before a line of feature code.

03

Build inside it

Ship the smallest thing that's true, constrained by the invariants we chose.

04

Harden

Evaluation suites, load, and deliberate failure injection until it holds.

05

Operate & hand over

SLOs, runbooks, and on-call — so the team that owns it can run it.

Principles

What we won't compromise on.

The guarantee comes first

We decide what a system must never do before deciding what it should. The rest is derived from that.

Boring infrastructure wins

We choose tools for operational calm, not the changelog. Reproducible, observable, and hard to surprise.

Evals gate the merge

A prompt or model change ships only when the evaluation suite says it's at least as good as what's live.

Own what you ship

The engineer who designs a system builds it, ships it, and carries the pager for it. No walls to throw things over.

Write the decision down

What we chose, what we rejected, and what would change our minds. Six months later it's the only thing that still works.

Design for the tired engineer

A system that needs a hero at 3am is broken. We build for the version of ourselves that's out of sleep and patience.

Technology

The stack we bet on.

Every tool here is one we run in production and can support at 3am. Chosen for operational boredom, not for the changelog.

  • Go · Services
  • TypeScript · Web
  • Next.js · Frontend
  • Flutter · Mobile
  • Python · AI / data
  • PostgreSQL · System of record
  • Redis · Cache / presence
  • Kubernetes · Orchestration
  • Docker · Packaging
  • Terraform · Infrastructure
  • GCP · Cloud
  • gRPC · Transport
Engineering philosophy

Four rules we don't bend.

Every team says they care about quality. These are the specific calls we make when caring about it costs something.

01

Correctness is a feature.

A system that is fast and wrong is just wrong sooner. We pick the guarantee first (ordering, consistency, durability) and then make it fast inside that constraint.

02

Boring infrastructure, ambitious products.

Postgres, Go, containers, Terraform. We spend our novelty budget on the product surface, not on the parts that page someone at 3am.

03

AI that reasons over facts, not vibes.

Models narrate; they don't compute. Every number an AI feature reports is derived deterministically before the model ever sees it, and every claim traces back to its source.

04

Own the thing you ship.

The engineer who builds a service runs it. That closes the loop between the design decision and the pager, which is the only thing that reliably produces good design decisions.

Have a system that needs to hold up?

Bring us the hard part. We'd rather work on the thing that scares you than the thing that's easy.