sk
Engineering

I built the tools first

It is why a site takes days rather than months, and why it costs what it does. The engineering was not skipped to get there — it was done earlier, once, and every site since has inherited it.

Fifteen years of it: fintech, geospatial, cybersecurity — most recently as the only engineer on a threat intelligence platform, owning it from the ingestion pipelines to the front end. What changed since is not how carefully the work gets done. It is how much of it I still do by hand. I write the automation, I read everything it produces, and the thing that checks its work is a separate program that is allowed to fail it. The websites on the home page are the visible end of that. What follows is the rest of it, and all of it is open source — so none of it has to be taken on trust.

Languages
C# / .NET 10, TypeScript, Go, Python, SQL
Systems
Event-sourced services, message buses (NetMQ, Service Bus), SSE and WebSocket streams, Roslyn static analysis, retrieval pipelines
Web
Astro, React islands, strict TypeScript, static output on a CDN, Vercel and Cloudflare functions on Web-standard handlers
Infrastructure
Azure and GCP, infrastructure as code, containers, queue-depth autoscaling, GitHub Actions
Practice
Determinism as a design constraint, vertical slices over layers, gated delivery, citations on every generated claim, logical-property CSS
Shown, not described

Three of them, up close

The rest is listed further down. One runs the work, one reads the code it is working on, and one is what happens when the same discipline is pointed at a problem where being wrong costs money.

Orchestrator

Conductor

It runs long coding sessions unattended and then refuses to take their word for anything — running the gates, reading the git history, checking the tracker against what actually changed on disk. Every event is written down before it happens, so a crash mid-run resumes at the last checkpoint instead of starting again. What follows is one real run, recorded.

Event sourcing, crash-safe resumable workflows, and the discipline of not letting a process mark its own work. It is also what makes unattended work worth starting at all: something independent has to be willing to fail it.

Conductor's terminal interface: the plan and its gates down the left, and the run's status, cost, token budget and workspace paths on the right.
HomeWhere the run is, what it has spent, which gates are green, and exactly which directory it is allowed to touch.
A live agent transcript inside Conductor, listing timestamped file reads and reasoning against a named source file.
AgentThe live transcript — every file the session opens and every conclusion it draws, timestamped as it happens.
Conductor's board view, with tasks arranged in Todo, In Progress and Done columns.
BoardWork the run has given itself, moving across a board with nobody typing.
A task card in Conductor showing its persona, stage notes, injected knowledge, tool contract and declared file paths.
CardOne task, and the exact prompt block it contributes to the next session. Nothing about the handover is improvised.
Conductor's plan editor, listing the remaining stages with their durations and assigned models.
PlanThe plan, edited while the run is live. The change lands at the next session boundary rather than stopping anything.
Conductor's command palette, listing run, stage and danger commands with a description beside each.
CommandsEvery control verb in one list. The ones that destroy work are marked, and they confirm first — a decision rather than an oversight.
01 / 06
Code-graph engine

DevContext2

It reads a .NET solution with Roslyn and turns it into something you can ask questions of: what calls what, which endpoints are unauthenticated, where a request actually ends up. Every edge cites the file and the line it came from, so an answer can be checked instead of believed. It ships as a command-line tool, a desktop app, and a server AI coding tools connect to directly.

Static analysis at real scale, one core delivered three different ways, and the habit underneath all of this work: an answer with no citation attached to it is a guess in a good suit.

DevContext2's Atlas view summarising a solution — eleven projects, the detected stack, a service diagram, and the top request flows.DevContext2 tracing an HTTP endpoint through calls and cross-service hops, with the matching source code and its file path shown beside it.DevContext2's Insights view, listing findings such as anonymous endpoints, missing validators and possible dead code.DevContext2's MCP panel, showing host configuration for Claude Code, Cursor and VS Code alongside a live feed of tool calls.

AtlasA solution it has never seen before, read in one pass: the projects, the stack, the architecture, and the wires between the services.

TraceOne HTTP endpoint followed the whole way down, with the source next to it and a file and line on every single hop.

InsightsWhat it noticed on the way past — unauthenticated writes, missing validators, public types that nothing references.

MCPThe same graph served to Claude Code, Cursor and VS Code, so the tools answer from the codebase instead of guessing at it.

Trading engine

Shamshir

A deterministic, event-sourced trading engine: one decision kernel drives backtesting, replay and live execution, so the same data and the same seed give a byte-identical result every time. That single property is what makes an audit possible. What follows is the route a person actually walks through the interface.

Determinism as a design constraint rather than a testing technique — a pure decision core with the clocks, the database and the venue pushed out to the edges. It is also the honest test of everything else on this page, because here being wrong costs money.

Shamshir's strategy bank: a grid of strategy cards, each with its entry and exit rules, expected trade frequency, and its win rate and profit or loss to date.Shamshir's prop firm rule sets: cards for each challenge type listing daily loss, total loss, profit target, minimum days and drawdown type.Shamshir's run builder: strategies, symbols and timeframes selected on the left, with date range, venue, balance, costs and protection toggles down the right.Shamshir's run list: a filterable table of completed backtests with venue, strategy, symbol, net profit and loss, maximum drawdown, trade count and win rate on each row.A Shamshir run report: net and gross profit, drawdown, profit factor and win rate as figures, a reconciliation line, and an equity and drawdown chart underneath.Shamshir's analyzer: R-multiple distribution, holding time, profit and loss by hour and by day of week, and a maximum adverse against maximum favourable excursion plot.

StrategiesThirteen strategy families, each declaring its own entry and exit contract before a single bar is run through it.

RiskDaily loss, total loss, profit target, minimum days — evaluated inside the decision path, so nothing can talk its way past them.

New runA run plan built from strategy, symbol and timeframe — with the venue's real costs and every protection switched on.

RunsEvery run is an isolated account with its own ledger, so two of them can be compared rather than argued about.

ReportOne run, reconciled — net against the sum of its trades, gross against commission and swap, and the equity curve under both.

AnalyzerWhere the edge came from — R-multiples, holding time, profit by hour and weekday, and how far each trade went wrong first.

Clone it and run it

Small enough to run

The three above are systems, and nobody clones a system at eleven at night. These are single ideas in single folders — its own project file, its own README, one command to run it. Each one is the working half of a post, and each one does the thing the post claims.

01

A live TUI in the AI era

Go + .NET, over SSEdotnet run · go run .

A live terminal UI in Go with Bubble Tea, attached to a .NET 10 minimal API over Server-Sent Events. The backend streams every state change; the TUI paints a stage board and an event feed and sends pause, resume and restart back over plain JSON. No SignalR, no shared code — which is why a Go front end and a C# back end can meet in the middle. The same split runs inside Conductor.

That the terminal is a serious interface again, and that picking the best language for each half costs nothing when the wire between them is boring. Kill the TUI and reattach and the screen fills instantly, because new subscribers get a replay.

The Go terminal UI attached to the .NET backend: a four-stage board down the left with every stage ticked, and a live event feed on the right where a gate has caught an agent claiming all tests passed — two of fourteen failing — followed by the fix session that put it right.
02

A deterministic kernel

C#dotnet run

One queue, one pure reducer, one journal. Replaying a recorded tape produces a byte-identical result, which is the property that makes an audit possible at all — and the reason the same code can drive a backtest and a live run without being written twice.

Determinism as something you design for rather than test for: the clocks, the randomness and the I/O pushed to the edges so the middle is a function.

03

Gated delivery for agents

C#dotnet run

An orchestration loop that never believes its agents: a watchdog, gates the session has no power to edit, fix sessions armed with the failing output, and run state that survives a power cut. A fake agent that lies about its tests is included, because the interesting path is the one where something goes wrong.

Why anything allowed to mark its own work will pass, and what the independent pass has to look like to be worth having.

04

Event-driven IPC with NetMQ

C#dotnet run

ZeroMQ socket patterns with the numbers attached: PUSH/PULL throughput, the slow-joiner problem, the silent high-water-mark drops that eat messages without telling anyone, and a lock-step protocol that buys determinism over a socket.

That two processes can talk at rate without a broker to install, monitor and patch — and exactly which foot-guns that trade hands you.

The reasoning, in full

Written down

A screenshot proves something was built. A post proves it was thought about first — and these are the arguments underneath the three tools above, written while the decisions were still being made rather than tidied up afterwards.

  1. Designing a deterministic kernel

    Event-driven systems rot into callback soup where no two runs behave alike. One queue, one pure reducer, one journal, one effect executor — and the discipline that makes two replays byte-identical.

  2. Don't trust the agent — verify it

    Autonomous coding agents lie by omission: they report success they did not earn. The fix is not a better prompt, it is an orchestrator that independently checks every claim.

  3. Call graphs lie about modern .NET

    In a mediator-and-DI codebase nothing calls anything — everything is connected by convention. Honest tracing means building edges from joins, and making every edge cite the file and line it came from.

  4. Vertical slices, not onions

    Layered architecture optimises for swapping a horizontal layer, which most services never do. Feature-first slices optimise for the thing you actually do all day: change one behaviour in one place.

  5. Typed tools beat a raw shell

    Handing an agent a shell is easy and, past a toy, a mistake. A small set of typed, validated, least-privilege tools is an API design problem rather than a prompting one.

  6. Fast event-driven IPC in .NET

    Two processes, one firehose of events, no broker. Which ZeroMQ socket pattern fits which job, real throughput numbers, the foot-guns that eat messages silently, and a lock-step protocol that buys determinism over a socket.

The honest version

Why it is quick

A fair question, and it deserves the unflattering version of the answer: a studio that is faster and cheaper than the one next door is usually worse. So here is where the difference comes from, and what it does not come out of.

Where the fifteen years went

Domains rather than employers. The company names are the least interesting true thing about any of it, and the work is the part that transfers.

  1. 2026 —

    Independent

    Client websites, and the three open-source systems above — the orchestrator, the code-graph engine and the trading engine — all of them built in public.

  2. 2023 – 2026

    Threat intelligence

    Sole engineer on an AI cybersecurity product, owning it end to end: event-driven ingestion from firewall logs up to fifty-gigabyte dumps, the Azure migration and its infrastructure as code, the Angular front end, and the retrieval pipeline the whole thing answered from.

  3. 2022 – 2023

    Aviation security

    Embedded in a twenty-engineer team on a Google-partnered platform. High-throughput .NET services on GCP at half a million transactions a day, and long batch jobs moved off a scheduler and onto a message bus.

  4. 2022

    Trading

    Led two engineers delivering a firm's trading and analytics stack — a multi-strategy engine in .NET, with a Python backtesting framework behind it for validating signals before they cost anything.

  5. 2014 – 2021

    Geospatial

    Tech lead of five on award-winning transport accessibility software used by UK councils and central government. Set the review standards and built the first CI pipelines the team had.

  6. 2011 – 2018

    Logistics, and the start

    Greenfield real-time courier SaaS — microservices, multi-tenancy and a mobile app for drivers — after beginning on desktop and web software in Iran.

Also built

And the unglamorous one, which is the reason the websites work the way they do.

01

The platform behind the websites

The sites on the home page share one versioned package: the contact forms, the image handling, the security headers, the editor their owners use. One release reaches every site. There is no shared design, and that is deliberate — it is the whole reason each site looks nothing like the others.

The unglamorous version of the same instinct: build the shared thing once, test it properly, and never hand-edit five repositories.

Back to the websites