Software consultancy

The problems that do not
have an obvious answer.

A small consultancy for web applications, AI systems, and data platforms. We take a few engagements at a time, and we hand back code your own engineers can own.

39+
Systems shipped
4
Engineering domains
Decades
Combined infrastructure experience
0
Vendor lock-in. You own the code

Services

Three practices, one team.

We take engagements end to end: the architecture, the build, the tests, and the handover. Usually two at a time, so each one gets the attention the problem actually needs.

Web Applications

Product-grade web applications, from the first prototype to the system that carries real traffic.

We design the data model, build the API and the interface, and put the whole thing behind tests and CI. You get a codebase your own engineers can read, extend, and own.

A request, end to end
  1. 01Client
    • React / Astro
    • Typed API client
    • Optimistic UI
  2. 02Edge
    • CDN + cache rules
    • TLS, redirects
    • Rate limiting
  3. 03API
    • Go / Gin handlers
    • Validation layer
    • Background jobs
  4. 04Data
    • Postgres
    • Versioned migrations
    • Read replicas

Across every layer

  • OAuth 2.0, JWT, RBAC
  • Tests and CI on each PR
  • Structured logs and traces
  • Migrations that roll back
  • Full-stack product development
  • API design and integration
  • Frontend architecture and design systems
  • Authentication, billing, and multi-tenancy
  • Performance and accessibility work
  • Legacy rewrites and incremental migration

AI Systems

Applied AI that survives contact with production: evaluated, observable, and costed.

Most AI projects stall between the demo and the deployment. We focus on the part that decides the outcome: retrieval quality, evaluation harnesses, guardrails, latency, and unit cost.

A retrieval and generation path, plus the loop that keeps it honest
  1. 01Query
    • Rewrite and expand
    • Embed
  2. 02Retrieve
    • Vector + keyword
    • Top-k over your data
    • Metadata filters
  3. 03Rerank
    • Cross-encoder
    • Drop low-signal chunks
  4. 04Generate
    • Model call
    • Tool and function use
    • Structured output
  5. 05Guard
    • Schema validation
    • Policy checks
    • Fallback path

The evaluation loop

  • Golden set per capability
  • Faithfulness and relevance scoring
  • Regression gate in CI
  • Cost and p95 latency per route
  • Retrieval-augmented generation over your own data
  • Agent and tool-use workflows
  • Evaluation harnesses and regression suites
  • Prompt and model selection under a cost budget
  • Fine-tuning and model routing
  • Monitoring, tracing, and guardrails

Data Engineering

Pipelines and warehouses that stay correct as the volume and the schema move.

We build the ingestion, transformation, and storage layer that everything else depends on, then make it testable so a schema change fails loudly in CI instead of quietly in a dashboard.

From source of truth to something you can query
  1. 01Sources
    • Postgres CDC
    • Event streams
    • Third-party APIs
  2. 02Ingest
    • Kafka topics
    • Schema registry
    • Dead-letter queue
  3. 03Transform
    • dbt staging models
    • Marts by domain
    • Incremental builds
  4. 04Serve
    • Warehouse tables
    • BI and notebooks
    • Reverse ETL

What keeps it correct

  • Freshness thresholds per table
  • dbt tests that fail the build
  • Column-level lineage
  • Backfills that are replayable
  • Batch and streaming pipelines
  • Warehouse and lakehouse modelling
  • dbt transformations and data tests
  • Change data capture and event ingestion
  • Orchestration and backfill strategy
  • Data quality monitoring and lineage

The name

WAL: write ahead, then apply.

A write-ahead log records the change before it touches the data, so the system can always recover. We work the same way: the intent is written down first, the change comes second, and the record survives us.

01 / LOG

Intent before change

The architecture is written down before any code is committed, including the options we rejected.

02 / APPLY

Small, reversible commits

Every change arrives as a pull request with tests and CI, so nothing lands that cannot be backed out.

03 / RECOVER

Replayable by your team

Documentation and a runbook ship with the code. If we vanish, the log is enough to keep going.

Work

What we have built.

Roughly 39 systems across tenancy, storage internals, platform engineering, and applied AI. Most started as a problem we hit and could not buy a good answer to.

Tenancy & identity

Multi-tenant data & identity

Systems that know whose data this is

A product that serves one customer per database is simple. One that serves ten thousand is a different system. Tenancy has two halves: a data plane that decides which shard holds a customer’s rows, and a control plane that knows who the customer is, what they may do, and what they owe. Most teams build neither, so tenant state ends up scattered across an auth provider, a billing dashboard, and a spreadsheet.

  • Postgres wire protocol
  • Sharding
  • Cross-shard transactions
  • Multi-tenancy
  • RBAC
  • OAuth 2.0
  • JWT
  • Stripe billing
  • Go

Tenant-aware Postgres proxy

Unreleased

A wire-protocol proxy that clients connect to as if it were Postgres. It reads tenant identity out of the query, routes to the shard that owns those rows, fans out and merges when the key is absent, and coordinates commit across shards with best-effort rollback. Wire adapters stay separate from the routing core, so other databases can plug in later.

System of record for organisations

Current

One service that owns the whole organisation lifecycle, covering orgs, their users, authorisation, and billing, so tenant state stops living in three vendor dashboards. Merchants configure policy centrally and enforce it inside their own backend.

OAuth integration broker

Configure an external provider once, then fetch a valid token for it over a plain REST call from any application, indefinitely. It removes per-project OAuth flows, refresh logic, and secret storage from every downstream service.

Standalone authorisation layer

Permissions extracted into a library so access rules stop being re-implemented, slightly differently, in every service that needs them.

Token and session auth service

Shared user management built because rewriting it per project stopped being defensible: session tokens, JWT, and OAuth first, with a path through directory protocols, MFA, and time-bounded access.

Multi-tenant SaaS foundation

A production-grade Go starting point that stitches the full stack together without a heavyweight framework: JWT auth, role-based access control, Stripe billing across plan tiers with webhook handling, account-isolated projects, migrations, and a generated client SDK.

Backend-agnostic persistence layer

Define a Go struct, call save or find, and the adapter maps it onto Postgres, MySQL, SQLite, MongoDB, or ClickHouse. It trades SQL expressiveness for reaching persistence fast.

Self-hostable form platform

An open-source alternative to the dominant form SaaS: Postgres, OAuth sign-in, and a Docker Compose stack that comes up from a single env file.

Storage internals

Database & storage internals

The layer below the query

When a database becomes the bottleneck, the fix usually sits below the query layer, in the replication path, the snapshot mechanism, the lock granularity, or the cache in front of it. We have built these pieces from scratch rather than configured them, in Go and in Rust, because that is what it takes to reason about them under load.

  • Raft
  • WAL
  • Change data capture
  • Copy-on-write snapshots
  • Redis internals
  • SQLite internals
  • Hash table design
  • Lock striping
  • Go
  • Rust

Logical replication on Raft

Consensus and log replication implemented from first principles, built to close the gap between understanding Raft and actually shipping it. A coordinator drives independently runnable managers for WAL generation, log replication, and leader election, exercised against a three-node cluster in the test suite.

Copy-on-write point-in-time snapshots

Snapshot semantics for an in-memory store with zero additional memory cost until data is mutated and minimal impact on read latency. A snapshot buffer layers over shard threads, with simultaneous snapshot instances and cross-shard restore, and no dependence on an OS-level fork.

Change data capture for live migration

Move a collection between clusters with negligible downtime: bulk-copy what exists, record the start timestamp, then tail the oplog from that point until lag closes. A self-contained path off a managed migration service and its lock-in.

Redis-compatible engine with live queries

An in-memory database in Go that extends Redis commands with query subscriptions. Clients subscribe to a SQL-like query and receive a push when the result changes, rather than polling. Drop-in compatible with existing Redis tooling.

SQLite reimplementation in Rust

Work inside a from-scratch Rust rewrite of SQLite: storage engine territory, in a systems language with a different set of guarantees to Go.

Dragonfly-style dash tables

A Go implementation of the hash table design behind Dragonfly, written to understand its memory layout and probe behaviour rather than to read about them.

HTTP caching reverse proxy

Sits between the edge and the application server with a per-request in-memory response cache, invalidation APIs, and per-route skip rules for endpoints that must always reach the backend. It cuts backend load with no application-level change.

Concurrency and memory primitives

Striped locks across 1024 slots with FNV-32a key hashing, benchmarked against a single global mutex under contention. Plus a memory pool, and a ring buffer that flushes batches on message count, rollover, or time since the last flush.

Measurements, published

Benchmarks run and written up rather than assumed: protobuf against JSON across four compressors and eleven payload shapes, goroutine spawn cost against pre-allocated worker pools, interface dispatch against direct calls, and copy-by-value against pointer semantics.

Platform & runtimes

Platform & distributed runtimes

Getting workloads to run, on time, in order

Most teams do not need Kubernetes. They need a repeatable way to put a container on a machine, give it a database, and find out when it dies. Once the workloads run, something still has to schedule them, move events between them, and hold the pipeline together when a stage fails. That machinery is where delivery speed is actually won or lost.

  • Docker
  • Terraform
  • Kubernetes
  • kubebuilder
  • Kafka
  • Prometheus / Grafana
  • WebSockets
  • WebRTC
  • AWS
  • DigitalOcean
  • Go

Self-hosted mini-PaaS

Current

Register SSH-reachable nodes, define an app, and deploy Docker containers to it, with no Kubernetes required. It provisions managed Postgres, Redis, Kafka, and Prometheus with Grafana, injects the connection details into linked services automatically, redeploys on a container-registry webhook, streams logs live, and runs a background health reconciliation loop.

Infrastructure as code across two clouds

Current

Terraform modules for AWS and DigitalOcean: VPCs and networking, instances, object storage, managed Kubernetes, and a Kafka node, with deployable manifests kept separate from the reusable modules.

Kubernetes operator

A custom resource and its controller on kubebuilder, covering both the standard reconciler pattern and external event sourcing, where events from outside the cluster enter the reconcile loop through a channel-based source.

Function executor and adaptive worker pool

A small function-as-a-service runtime, and a worker pool that sizes itself against the arriving work instead of spawning a goroutine per task.

Scheduler with a real data model

Current

Schedules hold triggers; triggers fire jobs built from templates with conditional logic and connector integrations. Absolute dates, relative offsets, and recurring intervals, expressed in a scheduling DSL that supports genuine pipelining. A structured replacement for a drawer full of crontabs.

Kafka pipeline DSL

Declare a source topic, a transformation, and a destination topic or external system, then chain the stages. Streaming pipeline logic in Go, for teams that want it without the JVM footprint of Kafka Streams or ksqlDB.

Event-driven workflow engine

Private

Composable stage definitions over Kafka with reliable delivery semantics, for pipelines where a dropped or duplicated event is a correctness problem rather than a metric.

Low-latency market data ingestion

A broker WebSocket client with binary protocol decoding behind a callback-handler interface, benchmarked for latency across 100k ticks. On top of it, an order management system covering placement, modification, and lifecycle tracking, and a tick-processing engine that runs rule-based strategies.

Global market aggregation

Current

Every major index, sector, and currency-adjusted return in one view, with valuation and macro overlays and capital-flow tracking, so the question of where the next unit of capital should go is answerable at a glance instead of out of a filing.

WebRTC selective forwarding unit

A minimal SFU handling multiple simultaneous producers and consumers, with the full signalling lifecycle: RTP capability negotiation, transport creation, and the producer and consumer handshakes. Conferencing infrastructure without a managed service.

API framework and load tooling

A Gin-based framework that exposes Go structs as CRUD endpoints with Rails-style lifecycle hooks around save and action, plus a config-driven parallel HTTP load driver that exercises an API without bespoke client code.

AI & agents

Applied AI & agentic systems

Agents that survive contact with production

Agents are easy to demo and hard to run. The engineering sits in the plumbing around the model: routing events in from the systems people already use, keeping sessions coherent across turns, deciding what runs locally so the bill stays near zero, and making the output reproducible enough to trust twice.

  • LLM agent orchestration
  • Tool and CLI integration
  • Session management
  • Local inference
  • Whisper
  • Remotion
  • ffmpeg
  • Go
  • Python

Agent orchestrator across messaging providers

Current

Bridges Telegram and Linear into a coding agent running locally. It fans incoming events from every configured provider into a single channel, invokes the agent per message, streams results back in chunks, and holds session IDs so multi-turn conversations stay coherent. Project bindings hot-reload from config every few seconds, with no restart.

Agent development environment

Current

A maintained library of agent skills and workflows: review, planning, release, and repository conventions encoded once, so an agent applies them consistently instead of being briefed from scratch each session.

Time-synced video generation pipeline

Any technical video in, animated overlays out. ffmpeg extracts the audio, a local Whisper model transcribes it with timestamps, a model detects technical scenes and writes the slides, Remotion renders them with spring animations and line-by-line code reveals, and ffmpeg composes the result. Keeping speech-to-text local holds API cost near zero.

Coaching application from gameplay analysis

Private

Analyses recorded play, tracks progress across sessions, and generates personalised drills and feedback rather than a single post-hoc score.

Local inference experiments

Running open models on local hardware to establish where a hosted API earns its latency and cost, and where it does not.

Also shipped

Smaller things

Tools and products that did not need a section of their own.

Interview preparation platform

Merges the five best-known problem lists into roughly 326 unique problems, reorganised by 20 solution patterns instead of by data structure.

Mobile-first consumer app

A lightweight product built around a clean, product-oriented architecture rather than a framework default.

Team and organisation management

People, projects, and responsibilities held in one shared workspace instead of three disconnected tools.

Python dependency extractor

Give it a file and an object name; it traces every transitive dependency and copies the closure into a mirrored source tree with the import hierarchy intact.

Go struct reflection utility

Normalises an arbitrary struct into a name and an attribute map, with optional snake_case keys, for schema-less serialisation and structured logging.

REST layer over CSV files

Post a set of paths and key-value filters, get matching rows back. Makes flat data queryable without standing up a database.

Approach

How we work.

Short feedback loops, working software early, and no black boxes. You see the repository from day one.

  1. Read the log

    Scope

    We start with the problem, not the technology. One or two calls to understand the constraints, the deadline, and what success means.

  2. Write ahead

    Design

    We write the architecture down before we write code: the data model, the interfaces, the trade-offs we chose and the ones we rejected.

  3. Apply

    Build

    Weekly increments you can run yourself. Every change arrives through a pull request, with tests and CI attached.

  4. Durability

    Harden

    Load, failure modes, observability, and cost. This is the step most projects skip, and the one that decides whether the system holds.

  5. Recovery

    Hand over

    Documentation, a runbook, and time with your engineers. The goal is that you do not need us afterwards.

Tests come with the code

Not a phase at the end. A change without a test is not finished.

You own the codebase

Your repository, your accounts, your infrastructure. No lock-in to us.

We say when we are wrong

If an approach is not working, you hear it early, not at the deadline.

About

Built by people who have run this at scale.

The core team has spent its career on systems where correctness and scale were not optional, previously at:

  • Amazon
  • Broadcom
  • Stripe
  • Google
  • VMware
  • Rippling

Databases, payments infrastructure, virtualisation, and platform engineering. The kind of work where an outage has a postmortem and a schema change has a migration plan.

Why Write Ahead

A write-ahead log records the change before it is applied, so the system can always recover its state. It is also the reason our engagements leave documentation behind. If the only record of a decision is in someone's head, the system is one resignation away from being unmaintainable.

Fit

We are not right for every project.

Being honest about that early saves everyone a quarter.

Where we earn our keep

  • The system works until it does not, and nobody can say why
  • A rewrite has to happen without downtime or a frozen roadmap
  • An AI feature demos well and falls over in production
  • Data is correct in one place and wrong in three others
  • The architecture decision is expensive to reverse
  • Your team is strong but short of a specific kind of depth

Where someone else is a better call

  • A well-specified app on a standard stack, where plenty of good teams will do excellent work for less
  • Staffing a seat for a year against a backlog someone else owns
  • Work that needs to start next week at full speed
  • A build where the requirements are still moving weekly

None of the second column is a lesser kind of work. It is simply work where our particular experience adds cost rather than value, and we would rather say so than bill for it.

Contact

Tell us what you are building.

Email is the fastest route. A paragraph is enough to start. We read every enquiry ourselves, and we answer either way.

Append to the log

  • What the product or system does today
  • The specific problem you want solved
  • Your timeline and any fixed dates
  • The stack you already run on
  • Who we would be working with on your side
  • Whether you need a team or a specific skill

We answer every genuine enquiry, including the ones we turn down. If we are not the right team, we will say so and suggest who might be.