Not a list of technologies. The reasoning behind each one, and what it costs us when we're wrong.
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.
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-driven · CQRS · Domain 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.
Go · gRPC · PostgreSQL · Redis
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.js · React · TypeScript · Tailwind
Mobile
One codebase for iOS and Android, native where it counts.
React Native with Expo, against the same API contract the web uses; it's what Mesh and Spenzo ship on. Flutter where it suits the client's team better. We drop to native modules only for the things that have to be native: biometrics, secure storage, background sync.
React Native · Expo · Flutter
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.
GCP · Terraform · Kubernetes
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.
Docker · GitHub Actions · Prometheus · Grafana
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.
Python · RAG · Evals · Vector 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.
PostgreSQL · Kafka · dbt
How an engagement runs.
Discover
Understand the domain and, more importantly, the failure you're trying to avoid.
Design the guarantee
Settle ordering, consistency, durability, and privacy before a line of feature code.
Build inside it
Ship the smallest thing that's true, constrained by the invariants we chose.
Harden
Evaluation suites, load, and deliberate failure injection until it holds.
Operate & hand over
SLOs, runbooks, and on-call — so the team that owns it can run it.
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.
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
- React Native · Mobile
- Flutter · Mobile
- Python · AI / data
- PostgreSQL · System of record
- Redis · Cache / presence
- Kubernetes · Orchestration
- Docker · Packaging
- Terraform · Infrastructure
- GCP · Cloud
- gRPC · Transport
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.
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.
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.
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.
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.