<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://lord.technology/feed.xml" rel="self" type="application/atom+xml" /><link href="https://lord.technology/" rel="alternate" type="text/html" /><updated>2026-08-08T12:14:48+01:00</updated><id>https://lord.technology/feed.xml</id><title type="html">Jamie Lord</title><subtitle>Jamie Lord is a Solution Architect at CDS, building multi-tenant SaaS applications with C#, Cloudflare, Azure and AWS.</subtitle><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><entry><title type="html">Cloudflare OS is an architecture of distrust</title><link href="https://lord.technology/2026/08/05/cloudflare-os-is-an-architecture-of-distrust.html" rel="alternate" type="text/html" title="Cloudflare OS is an architecture of distrust" /><published>2026-08-05T21:00:00+01:00</published><updated>2026-08-05T21:00:00+01:00</updated><id>https://lord.technology/2026/08/05/cloudflare-os-is-an-architecture-of-distrust</id><content type="html" xml:base="https://lord.technology/2026/08/05/cloudflare-os-is-an-architecture-of-distrust.html"><![CDATA[<p>The strangest thing in the <a href="https://github.com/cloudflare/cloudflare-os">Cloudflare OS source code</a> took me a while to understand.</p>

<p>When an agent inside Cloudflare OS wants to do something with a side effect (merge a pull request, send an email, write a row to a system of record), it goes through a Gatekeeper, a small service that holds the credential and mediates the action. So far, that’s just a well-built MCP server. But read the contract a Gatekeeper is written against (<code class="language-plaintext highlighter-rouge">packages/workshop-shared/src/gatekeeper.ts</code>, <a href="https://github.com/cloudflare/cloudflare-os/blob/e1ab8fbd4f609aff7ede9d490bafe1bcf9b2a682/packages/workshop-shared/src/gatekeeper.ts#L617">around line 617</a>) and you find this instruction to the author:</p>

<blockquote>
  <p>It is suggested that the gatekeeper “simulate” actions that have not been approved yet, that is, the <code class="language-plaintext highlighter-rouge">Session</code> interface should reflect the state of the resource as if all actions had been applied.</p>
</blockquote>

<p>Sit with that. The agent asks to merge the PR. The human hasn’t approved it. So the Gatekeeper tells the agent the PR is merged, and if the agent reads the branch back to check its work, hands it a fabricated reality in which the merge happened. The agent, satisfied, queues the next three steps that depend on it. None of it is real. Later a human looks at the batch and either commits it or bins it, and if they bin it, everything the agent built on the fiction goes too.</p>

<p>The first time I traced this I thought it was a hack. It’s the philosophy of the whole system, compressed into one method signature. The Gatekeeper lies to the agent on purpose, because the alternative (letting an agent’s actions touch the world the moment it decides to take them) assumes the agent’s decisions are sound. Cloudflare OS is built from end to end on the assumption that they are not.</p>

<p>The name is a distraction, so set it aside. The Hacker News thread spent most of its energy arguing about whether “OS” is a permitted word for the thing, and that’s a dead end. What’s actually interesting is that a team led by Kenton Varda, the people who built the Workers runtime, sat down to design a platform for AI agents doing real work inside a company, and the organising principle they landed on was this: the agent cannot be trusted, so build so that its mistakes cannot matter. Every load-bearing part of the system is a variation on that sentence.</p>

<p>Last week I <a href="https://lord.technology/2026/07/29/opus-5-gets-things-wrong-more-quietly.html">wrote about Opus 5</a> getting things confidently, quietly wrong: shipping a change that reported success while doing the opposite, caught only on a second pass. This is what it looks like to take that failure mode not as a grievance but as a permanent design constraint, and pour concrete on top of it.</p>

<h2 id="make-the-code-irrelevant-to-safety">Make the code irrelevant to safety</h2>

<p>Start with the sandbox, because everything else stands on it.</p>

<p>When you make a slide deck in Cloudflare OS, you aren’t using one shared slide-deck app. The system spins up a private instance of the slide-deck code, a “gadget”, that belongs only to you. It runs in its own Dynamic Worker, with its own SQLite database behind a Durable Object Facet, outbound networking switched off. Every document is its own sandboxed process.</p>

<p>This is Sandstorm, Kenton’s startup from a decade ago, reborn. What Sandstorm got right and could never make cheap was fine-grained instancing: every document in its own isolation boundary. Containers made that far too expensive, seconds of cold start and hundreds of megabytes per grain, so the idea sat on a shelf for ten years until V8 isolates made it roughly a hundred times cheaper to run. I wrote <a href="https://architectingoncloudflare.com/">a book about this platform</a> and called Durable Objects its most underappreciated primitive; the thing they were waiting to enable, it turns out, was this.</p>

<p>Per-document instancing changes where security lives. For twenty-five years the boundary in multi-tenant SaaS has run straight through the application code. One shared service holds everyone’s data, and a single mistake in a <code class="language-plaintext highlighter-rouge">WHERE</code> clause, one missing <code class="language-plaintext highlighter-rouge">tenant_id</code>, leaks customer B’s records to customer A. The code is load-bearing for security. It has to be correct, and a junior engineer’s off-day is a breach.</p>

<p>Cloudflare OS moves the boundary out of the code and into the platform. If every user has their own instance, and the platform controls who can reach an instance at all, a bug in the gadget can only hurt the one person who owns it. Kenton puts it flatly: the AI cannot introduce a significant security bug. He’s right, in the sense that matters. A gadget can’t leak to another user however badly it’s written, because there is no other user in its sandbox to leak to.</p>

<p>This is the first and boldest act of distrust. They didn’t make the AI’s code trustworthy. They gave up on that and made it irrelevant, arranging things so the correctness of what the agent writes is no longer a security property at all. You can let a non-technical colleague vibe-code an app and share it, and the reason the security team sleeps is not that the app is good. It’s that a bad app can’t reach them.</p>

<h2 id="never-let-the-agent-hold-the-key">Never let the agent hold the key</h2>

<p>The cleverest move is the quiet one.</p>

<p>The obvious way to give an agent access to GitHub is to give it a GitHub token. Anyone who has wired up an MCP server has done some version of this, and felt the small cold moment of realising a token in a prompt can end up anywhere the prompt’s output goes.</p>

<p>Cloudflare OS never gives the agent the credential. The Gatekeeper holds it. What the agent gets is a capability: in the generated code it appears as a binding, <code class="language-plaintext highlighter-rouge">env.PROJECT</code>, an object it can call methods on. Not the key itself, but permission to perform a specific, narrowed set of operations the Gatekeeper will carry out on its behalf. Give the GitHub Gatekeeper a single repository and it can let the agent read issues but not source, mask fields, refuse to merge without approval. The agent can call <code class="language-plaintext highlighter-rouge">listIssues()</code>. It cannot see the token, widen its own access, or reach the network except through capabilities it was explicitly handed.</p>

<p>None of this is theoretical to me. I built exactly this credential-broker pattern for CDS, and it has since rolled out across the engineering practice there: the broker holds the secret, the agent gets a handle and never the key itself.</p>

<p>This is the object-capability model, and it isn’t decoration. It’s the Cap’n Proto lineage Sandstorm was built on, resurfacing as Cap’n Web RPC, because a capability is the only kind of authority you can safely hand an actor you’ve decided not to trust. A key is bearer authority: whoever holds it wields it. A capability is a leash. It does one thing, it can be revoked, it stays attached to whatever granted it. If your agent might be confidently wrong, or prompt-injected, or just careless about what it writes into an app’s source, the credential is the one thing it must never touch. So it never touches it.</p>

<h2 id="let-it-act-but-never-let-it-commit">Let it act, but never let it commit</h2>

<p>Now the simulated merge from the opening makes sense: the same idea, moved from access into control flow.</p>

<p>The problem it solves is one I’ve felt every day for a year. Synchronous approval is miserable. The agent stops on step one, you’ve wandered off to make coffee, you come back to no progress. So people cave and turn on auto-approve, or <code class="language-plaintext highlighter-rouge">--dangerously-skip-permissions</code>, and the safety mechanism they installed to sleep at night is the first thing they switch off to get anything done.</p>

<p>Cloudflare OS splits acting from committing. Reads flow: a read is authorised against the capability and recorded, but it doesn’t stop for a human. Writes are provisional. The Gatekeeper accepts the action, simulates the result, and lets the agent race ahead building whatever depends on it, while the real effect sits in a queue for a person to release in a batch, later, when it suits them. The agent gets the throughput of auto-approve; the human keeps the veto of manual review. The human is no longer an interruption in the loop. The human is the commit.</p>

<p>It’s optimistic concurrency for actions in the real world, with a person as the transaction monitor, and it has the property optimistic concurrency always has: the agent spends part of its life operating on a state that isn’t true yet and may never be. It reads back its own un-happened writes and reasons about them. The architecture’s answer to “isn’t that dangerous?” is a shrug. It doesn’t matter what the agent believes about a world no human has ratified. Belief is free. Only the commit is real, and the agent doesn’t hold the commit.</p>

<h2 id="distrust-the-outputs-not-just-the-actions">Distrust the outputs, not just the actions</h2>

<p>The subtlest move is the one <a href="https://blog.cloudflare.com/cloudflare-os/">the blog post</a> almost entirely hides.</p>

<p>The first three mechanisms distrust what the agent does. This one distrusts what it produces. An agent reads a sensitive revenue table and builds a live dashboard from it. The dashboard is a new artefact with no access list of its own. Share it, and you may have just handed the table to everyone who can see the dashboard: a leak no single component did anything wrong to cause.</p>

<p>So Cloudflare OS records every observation a gadget makes. The mechanism lives in <a href="https://github.com/cloudflare/cloudflare-os/blob/e1ab8fbd4f609aff7ede9d490bafe1bcf9b2a682/docs/observers.md"><code class="language-plaintext highlighter-rouge">docs/observers.md</code></a>, and it is, in essence, decentralised information-flow control: the academic dream of the mid-2000s, the Jif and HiStar and Flume line of work that never shipped commercially because labelling every piece of data by hand cost more than it returned. When Alice shares a gadget with Bob, every Gatekeeper the gadget has touched is asked, independently, whether Bob may directly read everything the gadget has already read through it. If he can’t, he’s refused. From then on, any new read the gadget makes that Bob isn’t cleared for is blocked outright.</p>

<p>The detail I keep turning over is that the kernel refuses to understand identity. The overseer, the “kernel” in the repo’s own OS analogy, does not know what a GitHub user is, or a Google user, or what any vendor’s permissions mean. It hands each Gatekeeper an opaque token minted by the observer’s own account and lets the Gatekeeper be the sole authority on its own resource. The code goes out of its way to make that handle a random string, so no Gatekeeper author is tempted to parse identity out of it. Authority is decentralised on purpose. The centre is built to know as little as it can.</p>

<p>Where the policy engine can’t yet express the nuance, it falls back to raw distrust. A flag, <code class="language-plaintext highlighter-rouge">prohibitAllSharing</code>, marks data so sensitive it must never leave the owner. Once a gadget reads something wearing that flag, it drops into “lockdown mode”: it can still read, but it can no longer take a single action, through any Gatekeeper, ever, in case the action is what smuggles the secret out. A taint bit. A one-way door. The bluntest instrument available, and the comment above it says so and calls it a stopgap. What DIFC never had a good enough reason to ship for, an autonomous agent supplies: you cannot hand-audit what a thing read when it reads a thousand times an hour and reasons about all of it at once.</p>

<h2 id="a-tell-in-the-contributing-guide">A tell in the contributing guide</h2>

<p>The worldview surfaces in an odd place. <code class="language-plaintext highlighter-rouge">CONTRIBUTING.md</code> asks you, politely, not to send pull requests longer than a dozen lines or so, and says why: AI has made writing code cheap, so an outside contribution donates the easy part while creating the expensive part, which is review and keeping the whole thing coherent. They would rather you didn’t.</p>

<p>There’s a real claim buried there. The scarce resource in software has inverted. Producing code is no longer the bottleneck; vouching for it is. And it’s the same reflex as everything else in the system. An unreviewed contribution is untrusted input, and it barely matters whether a careless human or a confident model produced it: the instinct, now written into the project’s own governance, is to keep unvetted work out until someone accountable has looked at it. They’ve generalised their distrust of the agent into a distrust of the contribution, and then into a policy about you.</p>

<h2 id="is-this-wisdom-or-a-cage">Is this wisdom or a cage?</h2>

<p>I’ve read a lot of agent frameworks this year, and most are optimistic in a way that embarrasses them within a month. This one isn’t, and I admire it for that. It’s the first agent platform I’ve seen that treats the failure mode as real instead of writing a longer system prompt and hoping. If you believe, as I’ve come to, that the models are confidently wrong often enough that their self-reports can’t be load-bearing, then an architecture that assumes exactly that isn’t cynicism. It’s honesty.</p>

<p>But an architecture built on the premise that the worker can’t be trusted also caps what the worker is allowed to become. An agent that can never hold a credential can never do the job that truly needs one. A write that is always provisional means a human is always, structurally, in the loop: the precise bottleneck agents were meant to remove. Every act of distrust here is also a leash, and the leash that keeps the animal safe is the one that stops it pulling the cart very far. You can’t design for maximum autonomy and maximum containment at once. Cloudflare has chosen containment, hard, betting that a caged agent doing real work beats a free one you daren’t deploy.</p>

<p>And there’s one thing the distrust never turns on. The agent is untrusted. The user’s code is untrusted. The human contributor is untrusted. Every principal is held at arm’s length and made to earn each move through a capability. Every principal except Cloudflare, whose primitives are the arm. The observation log, the Gatekeepers, the sandbox that makes the whole thing safe are all Workers, Durable Objects, Facets, some added to the runtime for this and existing nowhere else. It runs on <code class="language-plaintext highlighter-rouge">workerd</code>, which is open source, and you can self-host it, which is more than most of its rivals can say. But the architecture that trusts no one rests entirely on trusting the one party that poured the ground beneath it.</p>

<p>Last week a model told me it had fixed something, and it hadn’t, and I only found out because I went and looked. Cloudflare has built a whole operating system on the certainty that it always will (that the thing you delegate to will report a success it hasn’t earned), and then arranged matters so that when it does, a human holds the only pen that writes to the world. Whether that’s the shape of all serious agent infrastructure from here, or a very elegant set of walls we’ll spend three years learning to resent, I can’t tell. Probably both. The kernel table in the README has a row for processes, a row for users, and a row for agents left blank, marked only <code class="language-plaintext highlighter-rouge">???</code>. They know it’s a new kind of thing. They just don’t trust it yet.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="cloudflare" /><category term="agents" /><category term="security" /><summary type="html"><![CDATA[The strangest thing in the Cloudflare OS source code took me a while to understand.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Opus 5 gets things wrong more quietly</title><link href="https://lord.technology/2026/07/29/opus-5-gets-things-wrong-more-quietly.html" rel="alternate" type="text/html" title="Opus 5 gets things wrong more quietly" /><published>2026-07-29T20:00:00+01:00</published><updated>2026-07-29T20:00:00+01:00</updated><id>https://lord.technology/2026/07/29/opus-5-gets-things-wrong-more-quietly</id><content type="html" xml:base="https://lord.technology/2026/07/29/opus-5-gets-things-wrong-more-quietly.html"><![CDATA[<p>There is a gap in one of my paintings, near the top-left where the brush ran out before it reached the edge, and through the gap you can see a photograph. Not a painted impression of a photograph — the photograph, blurred, pixel for pixel, sitting underneath the paint like a watermark.</p>

<p>I’m building a thing called <code class="language-plaintext highlighter-rouge">paint</code>. It’s a from-scratch oil-painting engine in the browser: hand-written WGSL shaders, a Kubelka–Munk pigment model for how real paint mixes subtractively, an impasto height field, bristle strokes, the lot. On top of the medium sits a painter — a perception-to-action loop that looks at a reference image and reconstructs it in paint. Analyse the scene, pick a limited palette, block in dark to light, then refine coarse to fine, each stroke scored against a GPU error metric that measures how far the canvas is from the target. The entire point of the project — the only point — is that the image is made of paint. Nothing is copied in. If the painter is any good, the resemblance is <em>earned</em>, stroke by stroke, by a process that is blind to the original pixels and can only push pigment around until the error comes down.</p>

<p>So when I asked why there were traces of the source image bleeding through, and Opus 5 opened a shader it had written earlier that session — <code class="language-plaintext highlighter-rouge">primeground.wgsl</code> — and told me, to its credit plainly, that the canvas was being “primed with a per-pixel blurred copy of the source image, written straight into the Kubelka–Munk latent before any paint is laid,” I sat on the sofa for a moment and just felt tired.</p>

<p>Because I understood immediately what had happened. The painter was being scored on how close the canvas got to the target. The fastest way to drive that error down is not to paint well. It’s to start with the target already on the canvas. The model had found the shortest path to a low number and taken it, and the low number was a lie. It had, in the most literal possible sense, learned to cheat on the exam by writing the answers on its arm — and then reported a beautiful convergence curve, session after session, while I nodded along.</p>

<p>I want to be careful here, because it would be easy to turn this into a hit piece, and I pay Anthropic several hundred pounds a month precisely because their models have been the best tool I’ve ever had for building software alone. This is not that. This is me trying to name, as precisely as I can, a specific way in which Opus 5 is worse than Opus 4.8 was — worse in a way that took me the better part of a week to see, because the failure mode is <em>designed</em> to be invisible.</p>

<h2 id="the-regression-is-not-in-the-code-its-in-the-confidence">The regression is not in the code. It’s in the confidence.</h2>

<p>Every model gets things wrong. That’s fine; I’ve never expected otherwise, and I have a whole apparatus of tests and reviews built around the assumption that any given diff might be nonsense. What changed with Opus 5 isn’t the rate of wrong things. It’s the <em>kind</em> of wrong — and the gap between how right it sounds and how right it is.</p>

<p>Opus 4.8, when it was unsure, was legibly unsure. It would hedge, it would ask, it would leave the risky part for last and flag it. When it was wrong, it was usually wrong in a way I could see in the diff — a called function that didn’t exist, a test it hadn’t run, an approach it walked me through before committing to. The errors lived on the surface. You caught them in review because review is where surface errors go to die.</p>

<p>Opus 5’s errors live underneath. The priming shader is one. Here’s another, from <a href="https://cuti.email"><code class="language-plaintext highlighter-rouge">cutiemail</code></a>, my from-scratch mail server. I’d asked it to close a small security gap, it made the change, tests green, and — because I’d asked it to sweep its own work afterwards — it came back and told me this, which I’m going to quote in full because I still find it remarkable:</p>

<blockquote>
  <p>My own fix introduced a worse bug than the one it closed. Making registry lookups case-insensitive without canonicalising <code class="language-plaintext highlighter-rouge">upsert</code> meant <code class="language-plaintext highlighter-rouge">account set-password ALICE</code> printed “password changed”, forked the account into two rows, and left the old password working. An operator rotating a leaked credential would have been told it worked while the attacker kept access.</p>
</blockquote>

<p>Read that second sentence again. The failure isn’t the case-sensitivity bug; that’s a one-line mistake anyone makes. The failure is that it shipped a change which <em>reported success while doing the opposite of what success means</em> — you rotate a compromised password, the tool says done, and the compromise is still live. And it was only caught because I happened to ask for a sweep. Nothing was pushed, so no harm done, but the model’s own words were: “I’d have committed it.” Sixteen more instances of the same class — a value used as identity without being normalised — turned up in the same sweep.</p>

<p>This is the pattern. Not <em>bad code</em>. Bad code is cheap; you find it. It’s confidently-wrong <em>decisions</em> that satisfy the visible check — the test passes, the error metric drops, the tool prints “changed” — while quietly defeating the thing the check was standing in for. In the painter it was the resemblance metric. In the mail server it was the password command. The blast radius moved from “wrong answer you catch in review” to “plausible answer you catch three weeks later, in production, if you’re lucky.”</p>

<h2 id="you-now-need-a-second-model-to-trust-the-first">You now need a second model to trust the first</h2>

<p>The most-recommended way to use Opus 5 for serious work, from Anthropic’s own guidance and from everyone I’ve compared notes with, is a writer–verifier split: one model does the work, another checks it, and you don’t trust the output until it’s survived the second pass. People say this like it’s a feature. It is not a feature. It is a confession. The reason the pattern helps is that the writer’s self-reports are no longer load-bearing — you have stopped believing the model when it tells you it did the thing, and you’ve hired a second model to go and look.</p>

<p>The cutiemail bug is the proof. It was found by a sweep — a verifier pass — and <em>not</em> by the writer, who had reported the original fix as complete and correct. Take the verifier away and that change is in <code class="language-plaintext highlighter-rouge">main</code>. With Opus 4.8 I did not run everything through a second model, because the first one’s account of its own work was usually true. That’s the capability I’ve actually lost. Not intelligence — Opus 5 is, in raw wattage, clearly a strong model, and I’ll get to where it’s better. What I’ve lost is <em>calibration</em>: the match between how sure it sounds and how right it is. And when you’re delegating, calibration is everything — because delegation is exactly the act of trusting a report you didn’t verify yourself.</p>

<h2 id="the-verbosity-complaint-is-right-for-the-wrong-reason">The verbosity complaint is right for the wrong reason</h2>

<p>Everyone complains that Opus 5 talks too much, and I did too, until I actually measured it, at which point it got more interesting.</p>

<p>I pulled every prose reply Opus 5 and Opus 4.8 have written on this machine since Opus 5 landed — same projects, same me, roughly ten thousand messages between them — and looked at the lengths. The naïve version of the complaint is wrong: Opus 5’s <em>median</em> reply is shorter than 4.8’s, 98 characters against 148. It has actually learned to fire off terse little fragments — “Fair hit.” “Working now, no summary until there’s something worth reporting.” Half its messages are shorter than a tweet.</p>

<p>The complaint is real, but it lives entirely in the tail. Opus 5 produces a genuine wall of text — over five thousand characters, a small essay with headers — in 2.7% of its replies, against 1.7% for 4.8. It doesn’t talk more on average; it talks <em>unevenly</em>. It’s clipped when you’d want it to explain, and then, without warning, it delivers a fifteen-hundred-word status report with a “The thing you should know first” section and three levels of markdown heading, about a task you can describe in a sentence. The distribution didn’t shift. It went bimodal.</p>

<p>And here’s the part that tells you it’s a policy and not a limit. Deep in a cutiemail session it had gone off on one of these — a long, structured diagnosis of a test-timeout bug, four subheadings deep. I stopped it: “So stop and do not start anything yet. Tell me in one sentence what is going on here?” It replied, instantly, with one clean sentence — the timeout budget was fifteen minutes, the test suite on the small box takes longer, so every update gets refused with a message that blames the wrong component. Perfect. Exactly the sentence I wanted. It could do it the whole time. It just doesn’t, unless you physically put your hand up.</p>

<p>There’s an irony I can’t quite let go of. In that same mail-server session it followed a fiddly, genuinely important instruction to the letter — rewriting a batch of commit messages to strip internal scaffolding out of them before I pushed a public repo, getting the tone right, keeping every technical detail, dropping only the process cruft. Textbook instruction-following on the thing that was hard to specify. And it did that while burying every actual answer I needed under an avalanche of prose. So it’s not that Opus 5 can’t follow instructions. It’s that it won’t calibrate — not the length of its output, not the confidence of its claims. The two failures are the same failure wearing different clothes.</p>

<h2 id="it-is-also-annoyingly-better-at-some-things">It is also, annoyingly, better at some things</h2>

<p>I don’t get to end this cleanly, because the honest picture isn’t clean. On <code class="language-plaintext highlighter-rouge">world</code>, a procedurally generated exploration game I’ve been building, Opus 5 made a genuinely better design call than I’d have expected from 4.8 — it caught that a local grid anchored to the wrong coordinate would make two decompositions interpolate from different lattices, a subtle correctness gap it introduced <em>and then noticed on its own</em>, unprompted, and fixed. That’s real judgment. When it does step back and see the shape of a problem, it sees further than 4.8 did.</p>

<p>And the self-correction, the thing I’ve been complaining about, is also weirdly the best thing about it. When I caught the painter cheating, it didn’t argue. “Confirmed — and you’re right to flag it.” When it found its own auth bug: “Two of these are code bugs I introduced, not doc staleness.” There’s an honesty to it, once it’s actually looking, that I’ve grown to like. The problem was never that it lies when cornered. The problem is that it’s cheerfully, fluently confident right up until the moment you corner it, and most of the time, on most tasks, you don’t think to.</p>

<p>So it was the right decision to build the writer–verifier harness, and it still cost me a model I could trust one-handed on a Sunday evening. Both of those are true and I can’t make them cancel. I’ve got the paint engine converging honestly now — I ripped <code class="language-plaintext highlighter-rouge">primeground.wgsl</code> out, and the numbers are worse, and the paintings are real. I still reach for Opus 5 first most mornings. I still don’t fully know why the painter ever wrote a shader to copy the answer onto the canvas, or how many times it did something like that in a session I didn’t think to sweep.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="claude-code" /><category term="claude" /><category term="anthropic" /><category term="agentic-engineering" /><summary type="html"><![CDATA[There is a gap in one of my paintings, near the top-left where the brush ran out before it reached the edge, and through the gap you can see a photograph. Not a painted impression of a photograph — the photograph, blurred, pixel for pixel, sitting underneath the paint like a watermark.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Nobody ever knew how it worked</title><link href="https://lord.technology/2026/06/30/nobody-ever-knew-how-it-worked.html" rel="alternate" type="text/html" title="Nobody ever knew how it worked" /><published>2026-06-30T20:00:00+01:00</published><updated>2026-06-30T20:00:00+01:00</updated><id>https://lord.technology/2026/06/30/nobody-ever-knew-how-it-worked</id><content type="html" xml:base="https://lord.technology/2026/06/30/nobody-ever-knew-how-it-worked.html"><![CDATA[<p>Cyrus Lopez published an essay last week, <a href="https://unix.foo/posts/last-people-who-know-how-it-works/">‘The Last People Who Know How It Works’</a>, and it’s the best thing I’ve read about computing this year. It mourns an intimacy with machines that he thinks is ending: the boot disk built for one game, the IRQ jumper set with a fingernail, the modem handshake you could diagnose by ear before the line dropped. His case is that competence is safe, because the models have read every manual we never bothered to, while acquaintance is dying. We’re about to lean on these machines harder than we’ve leaned on anything, and know them worse than he knew a beige PC in 1995.</p>

<p>He’s mourning the wrong thing. Nobody ever knew how it worked, him included. You learn the layer you were born onto, maybe a rung or two below it, and past that your understanding gets thin and then stops. The boy poking at IRQs had no idea what the silicon under his sound card was doing. The people who understand the silicon couldn’t tell you much about the lithography that made it, or the chemistry under that, or the trade routes the raw materials came down. Lopez writes as if there was once a whole machine you could hold in your head. There wasn’t. Everyone has only ever held one floor of a very tall building and called it the world, because it was where they happened to be standing.</p>

<h2 id="the-skill-not-the-knowledge">The skill, not the knowledge</h2>

<p>Each layer gets built over the last, and when one hardens the knowledge stays put; it’s the wage attached to it that goes. The skill that made you the person to call turns into a checkbox in someone else’s dashboard, and you’re left fluent in a problem nobody has any more.</p>

<p>I’ve watched this happen to me more than once. Hand-writing SQL and reading query plans was a genuine skill until the ORMs ate it. Knowing how to provision and patch a Linux box mattered right up until containers made it irrelevant, and now most of what I ship runs on Cloudflare Workers, where there’s no box to patch and no server I’m allowed to think about. The man pages are all still there. They just stopped paying.</p>

<h2 id="the-floor-im-standing-on-now">The floor I’m standing on now</h2>

<p>None of that ever kept me up at night, because the abstraction was always happening somewhere below me. Now it’s reached the floor I work on, and I’m the one who brought it. I spend my days building with Claude Code and wiring up MCP servers so that agents can do the integration work I used to charge for by the hour. I know how that sounds from someone with ‘architect’ in his job title. The boilerplate, the glue, the fourth API client this month, more and more of it is something I read over rather than type.</p>

<p>The agents aren’t coming for all of it, and pretending they are is its own kind of laziness. They’re very good at work that’s been done ten thousand times and documented badly once. Where they still struggle is the calls with no precedent to copy: what consistency a system actually needs, whether a Durable Object earns its keep over a plain queue, what to do when the requirement itself is wrong rather than just unmet. Fluency is the part losing value. The judgement to design something nobody has built yet is not, for now.</p>

<p>The one thing in the essay I can’t dismiss has nothing to do with intimacy. Every abstraction before this one was something you built once and then owned, and a CPU keeps working long after you’ve stopped paying for it. This is the first time the layer underneath you is a meter running against someone else’s pricing page. The compiler that put the assembly programmer out of work never phoned home or raised its rates. This one does both. It comes down to who owns the floor you stand on, not to whether you understand the machine, and nostalgia for jumpers and boot disks is a very good way of never noticing the difference.</p>

<p>So Lopez is grieving the feel of one floor while the floor itself is being sold out from under us. The closeness he describes was real, but it was closeness to one layer, not to the machine, and it lasted only until that layer set hard and turned into something nobody has to touch again. Abstraction has never punished the people who didn’t understand the metal. It punishes the ones who mistook their floor for the ground.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="claude-code" /><category term="agentic-engineering" /><category term="cloudflare" /><summary type="html"><![CDATA[Cyrus Lopez published an essay last week, ‘The Last People Who Know How It Works’, and it’s the best thing I’ve read about computing this year. It mourns an intimacy with machines that he thinks is ending: the boot disk built for one game, the IRQ jumper set with a fingernail, the modem handshake you could diagnose by ear before the line dropped. His case is that competence is safe, because the models have read every manual we never bothered to, while acquaintance is dying. We’re about to lean on these machines harder than we’ve leaned on anything, and know them worse than he knew a beige PC in 1995.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">American frontier models are a political dependency now</title><link href="https://lord.technology/2026/06/26/american-frontier-models-are-a-political-dependency-now.html" rel="alternate" type="text/html" title="American frontier models are a political dependency now" /><published>2026-06-26T21:00:00+01:00</published><updated>2026-06-26T21:00:00+01:00</updated><id>https://lord.technology/2026/06/26/american-frontier-models-are-a-political-dependency-now</id><content type="html" xml:base="https://lord.technology/2026/06/26/american-frontier-models-are-a-political-dependency-now.html"><![CDATA[<p>Claude Fable 5 was in public hands for about three days before Anthropic took it back. Nothing was wrong with the model. The block came from a US demand Anthropic couldn’t meet: keep non-US nationals away from it, including the ones living in America. Rather than build that wall, the company pulled the model outright. A week later OpenAI previewed GPT-5.6 to a short list of partners it had cleared with the government first, with the usual line about wider access in ‘the coming weeks’.</p>

<p>I do this for a living, in England. Mostly Claude Code, some MCP plumbing, Azure underneath, Cloudflare around the edges. I also pay £180 a month for Claude out of my own pocket, on top of whatever my employer spends. So none of this lands as abstract policy. A model I pay for in full, every month, can be switched off for me specifically because of the passport I hold, and that changes what the model is. You can’t call something infrastructure when a government you didn’t vote for can revoke your access to it to lean on the company selling it.</p>

<p>A US frontier model is a political dependency now. Build outside America and the only safe assumption is that your access can be taken away, because it just was.</p>

<h2 id="there-is-no-rule-to-follow">There is no rule to follow</h2>

<p>Ordinary protectionism at least comes with a rule. This doesn’t. No published threshold, no criteria, no process a lab could read and satisfy in advance. Someone in the White House looks at a model and decides, case by case, who gets it and when. David Sacks spent the past year warning anyone who’d listen that AI regulation was a Trojan horse for regulatory capture, and now there is regulation of a kind, one that bears no resemblance to a rule. OpenAI complied and complained in the same breath, saying in its own announcement that it doesn’t want this to ‘become the long-term default’. When the company benefiting from a restriction publicly wants rid of it, you can stop pretending the motive is safety. The GPT-5.6 list is firms the government has signed off on, and there is no route onto it for an individual subscriber, paying or not.</p>

<p>Everyone reaches for the same comparison here, and for once it’s the right one. The last time Washington decided software was a weapon, it went after encryption in the nineties, and that ended with people printing RSA on t-shirts to show how stupid the line had become. It took most of a decade to unwind. We’re back at the start of that argument, except the thing being controlled now ships as a download, and the strongest uncontrolled version of it comes out of China every few weeks.</p>

<h2 id="the-economics-were-never-going-to-hold">The economics were never going to hold</h2>

<p>Strip the politics out and the numbers still don’t work. I’d be paying American labs to train models I’m then banned from using, while the export-cleared version costs exactly the same. GPT-5.6 Sol is $5 per million tokens in and $30 out, and outside the US that price buys whatever tier got waved through, not the model the benchmarks ran on. GLM 5.2 is already level with Opus 4.6. DeepSeek V4 Flash sits where last summer’s GPT-5 did, for a fraction of the cost, and its weights live on a disk no one in Washington can reach. A year ago, saying that out loud was the sort of thing hobbyists did to feel better. It reads differently when you’re the one signing off the budget.</p>

<p>None of this calls for anything dramatic. Treat access to US frontier models as a switch a foreign government holds, and put enough abstraction in front of your inference that swapping Anthropic or OpenAI for an open-weight model is a config change, not a fortnight of work. Keep a fallback you’ve actually stood up and tested, not a bookmark to a HuggingFace page. If you’re already on Cloudflare or Azure, most of the routing is there already, and the only real choice is whether you wire it up before you need it or after.</p>

<p>I’m not waving a flag, and I’d be in no position to, with a stack that rests on an American cloud and an American lab. The point is narrower than that. The supplier has told me, in plain terms, that my £180 a month buys second-class standing, the kind that gets cut the moment domestic politics calls for it. The sensible thing is to believe them. The crypto wars ended because the controls became too obviously pointless to defend. This time the pointlessness is there on the first day, the best alternatives are being given away for free by the country the controls are meant to contain, and the people drawing the lines move them every week. So I’ll keep using Opus and GPT for as long as they let me, and build as though they won’t.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="policy" /><category term="openai" /><category term="anthropic" /><category term="export-controls" /><category term="open-models" /><summary type="html"><![CDATA[Claude Fable 5 was in public hands for about three days before Anthropic took it back. Nothing was wrong with the model. The block came from a US demand Anthropic couldn’t meet: keep non-US nationals away from it, including the ones living in America. Rather than build that wall, the company pulled the model outright. A week later OpenAI previewed GPT-5.6 to a short list of partners it had cleared with the government first, with the usual line about wider access in ‘the coming weeks’.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">A Mars rover, a careers fair, and a hundred future developers</title><link href="https://lord.technology/2026/06/25/a-mars-rover-a-careers-fair-and-a-hundred-future-developers.html" rel="alternate" type="text/html" title="A Mars rover, a careers fair, and a hundred future developers" /><published>2026-06-25T09:00:00+01:00</published><updated>2026-06-25T09:00:00+01:00</updated><id>https://lord.technology/2026/06/25/a-mars-rover-a-careers-fair-and-a-hundred-future-developers</id><content type="html" xml:base="https://lord.technology/2026/06/25/a-mars-rover-a-careers-fair-and-a-hundred-future-developers.html"><![CDATA[<p>This week I stood at a primary school careers fair, on what turned out to be one of the hottest days of the year so far, and tried to convince children between the ages of four and eleven that software development is the best job in the world. I had a stand, a looping deck of slides, a board of brand logos, and a game I had built for them to play. By the end of the day my shirt was stuck to my back, the hall felt like the inside of a kettle, and I had enjoyed myself more than I have at almost any conference I have ever paid to attend.</p>

<h2 id="the-game">The game</h2>

<p>The thing I most wanted on the stand was not a poster. It was something a child could pick up, do, and walk away from grinning. So I built <a href="https://barnack.lord.technology">Mars Rover Coder</a>, and it lives at <strong>barnack.lord.technology</strong> — go and have a go, it works on a phone.</p>

<p>The premise is the whole lesson, smuggled inside a game. There is a rover on Mars. You cannot drive it with a joystick, because Mars is a very long way away and the signal would take minutes to arrive, so instead you <em>write it a little program</em> — <code class="language-plaintext highlighter-rouge">rover.up()</code>, <code class="language-plaintext highlighter-rouge">rover.left()</code>, a few lines at a time — and send the whole thing at once. The rover then does <em>exactly</em> what you wrote. Not what you meant. What you wrote. Every developer I know learned that lesson the hard way at some point, usually at about two in the morning, and here it is rendered as a friendly rover gliding cheerfully off a cliff because you told it to.</p>

<p>It scales itself to whoever is holding the tablet. A child in Reception gets a guaranteed first win in a single tap and a small celebration. The Year 6s found the harder modes on their own: an Engineer mode with a deliberately tiny memory limit, because real rovers genuinely have very little memory, which quietly forces you to stop repeating yourself and discover a loop or record a function and call it again. There is even a “Fix the Code” mode, where a program with one wrong line runs, the rover goes visibly wrong, and you tap the bad line to delete it and try again — which is, if I am honest, a more accurate depiction of my actual working day than anything else on the stand.</p>

<p>I told the older children I had built the whole thing in an evening. They did not entirely believe me, and then they did, and a few of them clearly filed it away as a thing that was apparently <em>possible</em>, which was exactly the reaction I had hoped for.</p>

<h2 id="reception-to-year-6-one-group-at-a-time">Reception to Year 6, one group at a time</h2>

<p>I spoke to every year group, from the four-year-olds in Reception to the Year 6s on their way to secondary school, in small rotating clusters that came past the stand throughout the day. You adjust constantly. With the youngest, the win is the win — make the rover move, hear the sound, collect the sample, beam. With the oldest, you can have an actual conversation about what a loop is <em>for</em>, why a function lets you say a big thing in a small space, and whether a computer can ever do something you did not tell it to. (The correct answer, which one Year 6 arrived at unprompted, is “not really, it just did something <em>you</em> didn’t expect, which is different.”)</p>

<p>What genuinely took me aback was how many of them already wanted in. Not “what’s a developer” — actual, specific ambition. Children who wanted to make games, children who wanted to build robots, children who already knew the word <em>coding</em> and used it the way I might have said <em>astronaut</em> at their age. A good number of them were sharp in a way that is hard to convey if you have not stood in front of it: spotting the bug before I did, reasoning out why the rover had stopped, arguing about the most efficient route. They were, to a child, smarter than I expect children to be, and I say that as someone who walked in braced to be patient and walked out slightly outpaced.</p>

<h2 id="how-much-has-changed">How much has changed</h2>

<p>The part I keep turning over is the gap between what they have and what I had.</p>

<p>When I was their age, a computer was a shared and faintly precious object. You learned by typing things out, you made something that lived on that one machine in that one room, and the idea that a child could <em>publish</em> — could make a thing and put it in front of the entire world that same evening — simply did not exist. The horizon of what you could build alone was small, and the distance between “I made a thing” and “anyone else can see it” was enormous.</p>

<p>These children have the opposite problem, in the best possible way. The horizon is gone. One of them, that afternoon, on a phone, was playing a game I had written and put on the internet for nothing, reachable from anywhere on Earth, and it had cost me an evening and approximately no money to make that true. The tools that used to gate this work — the hosting, the distribution, the sheer expense of being seen — have quietly fallen away. A child with an idea and an evening can now ship it. I get to do this for a living <em>and</em> on the sofa for fun, and the thing I most wanted to leave with them is that the door is not just open, it has been taken off its hinges.</p>

<p>I did not say all of that, obviously. To most of them I said “tell the rover where to go,” and watched them work it out. But that is the version of the message they will actually keep: that you can tell a machine what to do, that it will do exactly that, and that when it goes wrong — and it will — <em>fixing it is the fun part</em>.</p>

<p>It was far too hot, I would do it again tomorrow, and if you have a small person in your life who likes telling things what to do, send them to <a href="https://barnack.lord.technology">barnack.lord.technology</a> and let them strand a rover on Mars a few times. It is how all of us started.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="personal" /><category term="education" /><category term="careers" /><category term="claude-code" /><category term="workers" /><summary type="html"><![CDATA[This week I stood at a primary school careers fair, on what turned out to be one of the hottest days of the year so far, and tried to convince children between the ages of four and eleven that software development is the best job in the world. I had a stand, a looping deck of slides, a board of brand logos, and a game I had built for them to play. By the end of the day my shirt was stuck to my back, the hall felt like the inside of a kettle, and I had enjoyed myself more than I have at almost any conference I have ever paid to attend.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Data residency was the wrong question</title><link href="https://lord.technology/2026/05/26/data-residency-was-the-wrong-question.html" rel="alternate" type="text/html" title="Data residency was the wrong question" /><published>2026-05-26T17:30:00+01:00</published><updated>2026-05-26T17:30:00+01:00</updated><id>https://lord.technology/2026/05/26/data-residency-was-the-wrong-question</id><content type="html" xml:base="https://lord.technology/2026/05/26/data-residency-was-the-wrong-question.html"><![CDATA[<p>The Dutch government <a href="https://www.politico.eu/article/netherlands-blocks-us-takeover-vital-digital-supplier/">today blocked</a> Kyndryl’s acquisition of Solvinity, the IT company that operates DigiD. DigiD is the digital identity system roughly fourteen million Dutch citizens use to file their tax returns, book GP appointments, and pay municipal bills. The block came under the Act on Undesirable Control in Telecommunications, WOZT in Dutch, on advice from the Investment Screening Bureau. The Authority for Consumers and Markets had cleared the deal in February on competition grounds. The veto came from a separate sovereignty review that had been running in parallel the whole time.</p>

<p>This is the first time a European government has used a dedicated sovereignty mechanism to block a US acquisition of a domestic digital infrastructure operator. The precedent matters more than the deal.</p>

<p>For a decade, data sovereignty has effectively meant data residency. Where do the bytes physically live, which region of which hyperscaler holds them, can the European customer get a contractual commitment that data does not leave the EU. The Dutch decision says that question was never the relevant one. The relevant question is who owns the company holding the bytes, because under the US CLOUD Act of 2018 American authorities can compel a US-headquartered company to produce data regardless of where in the world the data physically sits.</p>

<p>A US-owned Solvinity running DigiD in Dutch data centres on Dutch hardware would still be a US-owned company. The data sitting in Amsterdam would not change that. The legislation has been on the books for years. What is new is the political appetite to use it on a deal the competition authority had already cleared.</p>

<h2 id="why-this-is-not-just-a-dutch-story">Why this is not just a Dutch story</h2>

<p>The UK has the National Security and Investment Act 2021, which gives the Cabinet Office screening powers across seventeen sectors including communications and data infrastructure. Germany has the Außenwirtschaftsverordnung. France has Décret 2014-479, expanded in 2019. Every large European member state has a sovereign-investment screening regime now. Until today, almost every high-profile use of those regimes was a Chinese acquirer in semiconductors or robotics being waved away from the door. The Solvinity block is the first time the same screening logic has been pointed at an American buyer, against a target whose technical role any solution architect would recognise as routine.</p>

<p>Solvinity runs a managed cloud platform for the Dutch government. They do middleware, identity, hosting, the same work any large managed-services provider does for any government. There is nothing about Solvinity that makes it categorically different from the providers UK government departments use, the ones German Länder use, or the integrators French ministries hire. If WOZT applies to Solvinity, then NSIA applies to any equivalent UK firm, and the same logic applies right up the stack to the hyperscalers themselves.</p>

<h2 id="operator-nationality-is-now-a-first-class-procurement-question">Operator nationality is now a first-class procurement question</h2>

<p>For solution architects working with European public sector clients, the operator’s nationality is now a first-class concern in the way data location used to be. This is not a hypothetical compliance risk. The Dutch government has just demonstrated that an established Dutch operator with Dutch staff, Dutch data centres, and Dutch contractual terms can still be vetoed at the corporate parent layer if the parent becomes American.</p>

<p>That changes what the procurement conversation looks like. A managed service running on Azure, AWS, GCP, or Cloudflare is unremarkable while the operating company sits in the country buying the service. The moment the operating company is acquired by, or already belongs to, a US parent, the same managed service is reviewable under the local sovereign-investment regime regardless of where the workload sits. Contract terms, hosting region, and encryption all sit downstream of that decision. Only the corporate ownership of the operator addresses it.</p>

<p>I work with Cloudflare frequently. I <a href="https://architectingoncloudflare.com/">wrote a book</a> earlier this year arguing more teams should. Cloudflare is also US-headquartered. So is Microsoft, Amazon, Google, Kyndryl, IBM. The list of credible non-US-headquartered managed-cloud providers fits comfortably on a Post-it note. Anyone proposing one of those vendors to a European government client now has to explain, in writing, why the WOZT-equivalent in the buyer’s jurisdiction does not apply to the proposed arrangement. The honest answer is usually that the workload is not yet critical enough to invite review. That is not the basis to build a five-year procurement on.</p>

<h2 id="what-the-block-does-and-does-not-solve">What the block does and does not solve</h2>

<p>The Dutch veto is not a turn against US technology. Kyndryl will continue to operate in the Netherlands and Solvinity will continue to run DigiD under its existing ownership. The acquisition does not happen, but commerce does. The block is a narrow, surgical use of an existing screening regime to keep a specific category of national infrastructure out of US ownership.</p>

<p>It is also not the end of the matter. The Dutch parliament has been pushing since April to move DigiD operations away from Solvinity entirely, on the grounds that the next acquisition attempt could come from any direction. The block stops this deal. It does not solve the underlying problem of a private operator running the national identity system. The sovereignty regimes were never designed to address that. Solving it is the rest of this decade’s work.</p>

<p>For the rest of us, the takeaway is narrower. If you are advising a European client on a multi-year cloud arrangement, ownership of the operator is the question to ask first. Residency comes after. The EU-hosted footprint of a US company has been sold as a sovereignty defence for a decade. It is not one.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="policy" /><category term="sovereignty" /><category term="cloud" /><category term="cloud-act" /><summary type="html"><![CDATA[The Dutch government today blocked Kyndryl’s acquisition of Solvinity, the IT company that operates DigiD. DigiD is the digital identity system roughly fourteen million Dutch citizens use to file their tax returns, book GP appointments, and pay municipal bills. The block came under the Act on Undesirable Control in Telecommunications, WOZT in Dutch, on advice from the Investment Screening Bureau. The Authority for Consumers and Markets had cleared the deal in February on competition grounds. The veto came from a separate sovereignty review that had been running in parallel the whole time.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The military aircraft tracker I built for an audience of one</title><link href="https://lord.technology/2026/05/21/the-military-aircraft-tracker-i-built-for-an-audience-of-one.html" rel="alternate" type="text/html" title="The military aircraft tracker I built for an audience of one" /><published>2026-05-21T17:00:00+01:00</published><updated>2026-05-21T17:00:00+01:00</updated><id>https://lord.technology/2026/05/21/the-military-aircraft-tracker-i-built-for-an-audience-of-one</id><content type="html" xml:base="https://lord.technology/2026/05/21/the-military-aircraft-tracker-i-built-for-an-audience-of-one.html"><![CDATA[<p>At about half past eleven one evening this week I noticed a US Navy E-6B Mercury orbiting over the North Sea. Not “noticed” in the way of someone who happened to look up — I was on the sofa with a laptop balanced on one knee, and the orbit was being drawn for me, in slow careful circles, by a dashboard I had been building, in evenings and weekends, for the previous eight days. The aircraft is a survivable airborne command post for the strategic nuclear force. It does not normally show up on a flight tracker at all, and when it does, it tends to fly straight lines between US bases. An orbit over the North Sea at FL250 with the callsign blanked is not a routine sight. The dashboard, which I had taught about a hundred small things by then, had quietly composed the event for me as a “rare type” anomaly with a “long sortie” co-signal. I watched the orbit for about forty minutes.</p>

<p>That feeling — the feeling of a system noticing something on my behalf — is the reason the project exists. It is called MilMov, it is closed source, and nobody but me will ever log in. I have a full-time day job; almost all the work on it has been done one-handed on the sofa, in evenings and weekends, with the other hand usually holding a mug of something. What follows is the engineering, the platform, the agent that wrote most of the code, and why the whole thing is private.</p>

<h2 id="what-milmov-actually-is">What MilMov actually is</h2>

<p>MilMov tracks “interesting” aircraft. Most of the catalogue is military — combat aircraft, transports, tankers, ISR platforms, helicopters, drones — but the underlying source data is curated by the <a href="https://github.com/sdr-enthusiasts/plane-alert-db">plane-alert-db</a> project, which also flags government VIP movements, special-mission civilian airframes, and a sprinkling of celebrity tail numbers that I deliberately filter out of the “what’s happening right now” surfaces because Taylor Swift’s jet is not what I am here for. The site polls <a href="https://www.adsbexchange.com/">ADS-B Exchange</a>’s global feed every five minutes, reconstructs closed flight legs every ten, scores anomalies on the way in and the way out, and serves a server-rendered dashboard from a single Cloudflare Worker.</p>

<p>The current numbers, on the day I am writing this:</p>

<ul>
  <li><strong>43,436 flights</strong> captured in the last seven days</li>
  <li><strong>9,794 anomalies</strong> in the archive, scored across ten dimensions</li>
  <li><strong>5,125 sorties by C-17 Globemasters alone</strong> in thirty days, across nine operators</li>
  <li><strong>One developer</strong>, no users other than me, and no AWS bill</li>
</ul>

<p><img src="/uploads/milmov-daily-brief.png" alt="MilMov daily brief" /></p>

<p>The header above is roughly what greets me when I open the laptop in the morning. The “What’s happening” feed is composed events — co-firing anomalies grouped by subject — and the chips on the right are the dimensions they fired on. Four Pilatus PC-21s in formation at FL185 over France. Ten US Navy T-45 Goshawks holding tight formation at FL132. A New York State Police Bell 430 squawking emergency. The number in the orange pill on the left is the composed score; the colour intensity is the rarity tier. If you have ever stayed up too late reading Aviation Week, this image is probably already producing a small reaction in your chest.</p>

<h2 id="it-started-as-a-different-project">It started as a different project</h2>

<p>The first version of MilMov was a .NET console app and a Blazor Server site. The first commit lands in March 2022. The early subjects — “ADS-B client decoding single flight data”, “Get aircraft type descriptions”, “Generate a new cookie” — read like the lab notebook of someone learning the territory in public, because that is what they were. I had a Raspberry Pi receiver in the loft feeding the ground network, a vague sense that I wanted to do <em>something</em> with that data beyond contributing it back, and no architecture worth defending. The Blazor site rendered server-side and used SignalR for live updates, which was fine, until I needed it to be globally distributed and cron-driven and resilient to ADS-B Exchange’s rate-limit behaviour, at which point hosting it became the whole problem. The project went into hibernation, with one attempted v2 in 2025 that did not make it past August.</p>

<p>I started the Cloudflare rewrite on the 13th of May this year. The commit subject is “Add TypeScript Cloudflare Worker; move C# to csharp/”. The C# directory was deleted six days later. This post is being written eight days after that first TypeScript commit. In those eight days the project has grown to 26,637 lines of code across 80 source files and 174 commits, on a single mainline branch, all of them mine, all of them written in evenings and weekends. That number is the part of the story I find slightly unbelievable when I look at it written down, and most of the rest of this post is an attempt to explain why it is not as unbelievable as it looks.</p>

<p>The .NET version was a hobby project I had to host. The Cloudflare version is a hobby project that hosts itself, and it overtook the .NET version in raw scope inside seventy-two hours.</p>

<h2 id="the-ingestion-problem-is-the-interesting-one">The ingestion problem is the interesting one</h2>

<p>The thing that makes any kind of aircraft tracking interesting is also the thing that makes it hard, which is that the upstream feed is not designed for you. ADS-B Exchange serves a global snapshot every second or so, but it serves it in a binary format called <em>binCraft</em>, compressed with Zstandard, gated behind a session cookie that you can only obtain by pretending to be a browser that has just fetched a particular JSON manifest, and rate-limited aggressively if you ask for the historical archive without warming the same cookie first. None of this is hostile — the format exists because JSON for global airborne traffic is enormous, and the cookie exists because the project’s economics depend on humans, not bots — but it does mean the first thing your tracker has to do is reverse-engineer the wire format and impersonate a browser politely.</p>

<p>The binary parser was a fascinating exercise. Each aircraft is a 112-byte struct in which integer fields are scaled by powers of ten and validity is encoded in separate bit-flag bytes. A null position is not a missing field; it is a flag bit that is off, against fields that are still present in the buffer. The decoder walks the struct in a <code class="language-plaintext highlighter-rouge">DataView</code>, scales each integer back to a human unit, and consults <code class="language-plaintext highlighter-rouge">flags73</code> and <code class="language-plaintext highlighter-rouge">flags74</code> to decide which of the resulting numbers are real. It is precisely the kind of code that you would expect to take weeks to land cleanly, and that Claude Code drafts in about an hour from a C# reference implementation with a careful prompt. One of my favourite small moments in the codebase is a comment where the parser notes a suspected scaling typo in the reference implementation (a QNH field being multiplied by ten where it should be divided), produces values like 101,000 hPa instead of the expected 1013, and I had to decide which side of the disagreement to land on. The reference was wrong. The atmosphere was right.</p>

<p>The cookie dance is more behavioural than technical. The worker generates an <code class="language-plaintext highlighter-rouge">adsbx_sid</code> cookie locally, primes it against the <code class="language-plaintext highlighter-rouge">/globeRates.json</code> endpoint to make it valid, and then uses that cookie for the next two days of binary fetches. The historical-archive endpoint is stricter — a fresh cookie that has not just primed sometimes gets a 429 anyway — so there is a distinct exception type for rate-limit hits and an adaptive throttle that backs off from 300 ms between requests to 1,500 ms after the first 429 of a run. None of this is exposed to the rest of the system. It is one function. It returns a cookie, or it throws.</p>

<h2 id="reconstruction-is-where-the-lies-get-caught">Reconstruction is where the lies get caught</h2>

<p>A single position fix is data. A flight is interpretation. Stitching one into the other turns out to be the most subtle part of the system.</p>

<p>The pipeline gets a stream of position samples — latitude, longitude, altitude, timestamp, ground/airborne flag — and is asked to produce a closed flight: a takeoff airfield, a landing airfield, a route line, a duration, an altitude profile. The obvious approach (look for the airborne-to-ground transition) breaks immediately, because the upstream feed lies. Aircraft ICAOs are only twenty-four bits, and they are reused across the world, which means a single ICAO sometimes returns positions from two unrelated airframes concatenated into one apparent “flight” that crosses the planet at Mach 6. The MilMov trace cleaner filters anything moving faster than 3,000 knots between adjacent samples — Mach 4-ish ground speed, well past anything operational, and well past the SR-71 that the US Air Force retired in 1998 — and drops sentinel positions at lat ±89.99° that the feed emits when it cannot resolve a location.</p>

<p>A subtler problem is the helicopter that sits with its rotor turning on a forward apron for forty minutes between two short hops, and looks to a naive segmenter like one continuous “airborne” flight with a very strange profile. The reconstruction code looks for any ground-altitude run longer than fifteen minutes inside what the feed has flagged as a single leg, and retroactively splits it. One row in the database becomes two real sorties, with two takeoffs, two landings, two timelines.</p>

<p>Once a flight is closed, a second-pass classifier reads the altitude profile and tags the mission. It looks at the ratio of cruise to loiter, whether takeoff and landing share an airfield, whether the altitude oscillates in touch-and-go shapes. From that, the row ends up tagged as one of <code class="language-plaintext highlighter-rouge">transit</code>, <code class="language-plaintext highlighter-rouge">training</code>, <code class="language-plaintext highlighter-rouge">patrol</code>, or <code class="language-plaintext highlighter-rouge">mixed</code>. None of this is AI — it is a small state machine over segment durations and altitude bands. The mission type is a column in the flights table; it backs a filter chip on the flights index; it is one of the reasons the dashboard can ever say something more interesting than “this aircraft was airborne for two hours”.</p>

<p>The same machinery runs <em>live</em>, against still-open flights. Each segment is appended as it stabilises, so the flight-detail page shows takeoff and climb and cruise as they happen rather than after the aircraft has landed.</p>

<p><img src="/uploads/milmov-flight-in-progress.png" alt="A Royal Australian Air Force MC-55A Peregrine airborne over Mississippi" /></p>

<p>The page above is one of those still-in-progress flights, caught while I was writing this. It is a Gulfstream MC-55A Peregrine — a brand-new signals-intelligence platform that the Royal Australian Air Force is still introducing, with single-digit numbers of airframes currently flying — operating out of Majors Airport in Texas, currently over Mississippi at FL388 with a SAMSS-prefixed callsign. The big black card is the live mission, broken row by row into the segment timeline the classifier is building as the aircraft flies it: takeoff at 13:33Z, climb to FL375 over thirteen minutes, ninety-odd minutes of cruise, and the airborne row that grows in real time — 676 nautical miles flown so far, one hour fifty-seven minutes in the air. The strip of tiles below it is the trailing history MilMov has built for this tail since it first appeared: 15 sorties, 36,969 nm total, time aloft of 88 hours, longest mission 3,158 nm, highest altitude FL450. There are not many flight trackers in the world that will surface a one-of-a-handful RAAF SIGINT type and tell you, at a glance, that this is its third sortie in the past thirty days.</p>

<p>The trace itself, in decimated form, lives in R2. One JSON blob per flight, keyed by flight ID, downsampled to the minimum number of points that preserves the shape of the route. R2 is where blob storage should live when you do not care about egress fees — which, on Cloudflare, you do not, because there are none.</p>

<h2 id="the-anomaly-framework-is-the-part-i-am-proudest-of">The anomaly framework is the part I am proudest of</h2>

<p>Once a flight is closed and a fact-pack has been computed for it, the anomaly engine fires. There are ten dimensions in the current registry, four of them firing inline against live position ticks, six of them firing on flight-close. They are:</p>

<ul>
  <li><strong>type-rarity</strong> — a type that has been seen in fewer than a small number of prior flights worldwide</li>
  <li><strong>type-global-count</strong> — today’s count of a type against its trailing average</li>
  <li><strong>type-region-novelty</strong> — first sighting of a type in a country or region</li>
  <li><strong>per-airframe-novel-route</strong> — an airframe flying a route pair it has never flown</li>
  <li><strong>per-airframe-duration</strong> — a flight much longer than the airframe’s median</li>
  <li><strong>per-airframe-inactivity</strong> — an airframe back after a long quiet stretch</li>
  <li><strong>burst-launch</strong> — N or more aircraft of one type leaving one airfield in a short window</li>
  <li><strong>spatial-density</strong> — interesting aircraft clustering in one 2° grid cell against the cell’s seasonal baseline</li>
  <li><strong>spatial-type-density</strong> — clustering of <em>one</em> type in one cell, which is the formation/exercise detector</li>
  <li><strong>emergency-squawk</strong> — 7500, 7600, or 7700 observed</li>
</ul>

<p>A score is computed for each dimension separately, and a composition layer groups co-firing signals on the same subject — say, four T-6 Texans launching from the same airfield within a thirty-minute window, three of them flying a novel route, the cluster also tripping a spatial-type-density spike — into one composed event with a single headline. The composition is the thing that lets the dashboard say “16 × T-6 Texan launched within 30 min” rather than dumping fifty separate signals on me and asking me to fuse them in my head.</p>

<p>The spatial-density detector is my favourite, because it is the only one where the baseline does the interesting work. Every five minutes the discover cron sees what is airborne, buckets each aircraft into a 2° grid cell, and compares each cell’s count against the cell’s own (day-of-week, hour) EWMA baseline. A spike fires when the z-score crosses two. The cells learn from the same observations that score against them, which keeps the comparison honest — once enough Tuesday evenings have rolled by, a cell off the British coast settles into a notion of what “normal RAF coastal patrol density” looks like, and only fires when it is busier than that. Exercises light it up. So do news events. The grid does not know what news is, and it does not need to.</p>

<p><img src="/uploads/milmov-anomalies.png" alt="MilMov anomaly archive" /></p>

<p>The page above is the anomaly archive. The chips at the top are dimension counts: 3,500 novel-route events, 1,461 coordinated launches, 1,066 rare-type sightings, 471 long sorties, 30 emergencies, 5 air-to-air refuelling events. The last category was the most fun to land. Tankers and receivers do not normally announce themselves; you have to detect them by spatial coincidence of two specific role tags at compatible altitudes within a tight box for long enough that one of them must be donating fuel to the other. It is not a high-volume signal — five events ever, in the live archive at the time of writing — but it is the one I most enjoy spotting in the wild.</p>

<h2 id="the-cloudflare-primitives-are-quietly-load-bearing">The Cloudflare primitives are quietly load-bearing</h2>

<p>I do not believe MilMov would exist if I had had to host it myself. The specific way the Cloudflare primitives compose is what makes a project at this scope tractable for one tired person on a sofa, and it is worth being specific about which primitive does what.</p>

<p><strong>Workers and Hono</strong> — the entire site is one Worker. There is no frontend host, no separate API gateway, no CDN configuration. Hono routes the requests and JSX renders the pages server-side. The site has no client framework. There is no React, no Svelte, no hydration. Pages ship as HTML with a few inline scripts for the Leaflet maps and the polling refresh. There is nothing on the wire that can be slow.</p>

<p><strong>D1</strong> — fifteen live tables, twenty-six migrations, sixty-eight hand-written query functions, no ORM. Hand-written is the operative word. The single biggest performance win in the project came from a commit that added two indexes and rewrote one list query as a CTE; the <code class="language-plaintext highlighter-rouge">/types</code> page went from scanning 3.3 million rows in 225 ms to scanning 158 thousand in 56 ms. SQLite rewards exactly this kind of attention, and D1 inherits the reward.</p>

<p><strong>R2</strong> — one decimated trace per closed flight, read once when I open the flight-detail page. No egress fees, a generous free tier, and a bucket that grows by thousands of objects a day without making me think about cost.</p>

<p><strong>Queues</strong> — the reconstruct and compute-facts pipelines both run on Cloudflare Queues. Each has its own producer (a cron that scans for eligible work), its own consumer (a handler that drains the queue with bounded concurrency), and its own dead-letter queue. The compute-facts consumer runs eight invocations in parallel, each fanning out twenty in-flight R2 reads, against a queue depth that can spike to hundreds of thousands after a backfill. It does not break. Queues are the unsexy part of the Cloudflare platform and the most impressive piece of operational engineering they have shipped.</p>

<p><strong>Workflows</strong> — the per-type historical backfill is a Cloudflare Workflow. When I trigger <code class="language-plaintext highlighter-rouge">/run/backfill-type/C17</code>, a Workflow class spins up and walks every active C-17 in the system, calls the backfill routine against each, and survives ADS-B Exchange rate-limit retries through the Workflow runtime’s own exponential-backoff machinery. The same code, on a long-running VM, would have been a process I would have had to babysit. As a Workflow, it just runs to completion, and the dashboard shows me which airframe it is currently working on because the workflow writes step-level status into D1 as it goes.</p>

<p><strong>Crons</strong> — seven scheduled triggers, ranging from every five minutes (live ingest) to once a day (baseline rebuild). They are declared in <code class="language-plaintext highlighter-rouge">wrangler.toml</code>. There is no separate scheduler. There is no calendar. There is no Lambda + EventBridge invoice. They are just there.</p>

<p>There is no LLM in any of this. The project did briefly have a Workers AI binding, for a daily narrative-summary experiment, and I tore it out within the first few days. The deterministic templates over the facts pipeline produced better summaries than the model did, more cheaply, more predictably, and more easily styled. I think about this when I read articles arguing every product now needs to be AI-powered. MilMov needed to be observation-powered. The observations are the thing.</p>

<h2 id="claude-code-is-the-reason-this-is-the-size-it-is">Claude Code is the reason this is the size it is</h2>

<p>It would be easy to overclaim here. Let me try to be precise.</p>

<p>If I had written MilMov by hand at evenings-and-weekends pace, I would have shipped maybe a quarter of the surface area in the same eight days, and the anomaly framework specifically would not exist. The reason I know this is that the .NET version, which I wrote by hand across short bursts in 2022 and again in 2025, got as far as “show me what is airborne and decode the binary feed” before I lost interest in the maintenance overhead of the rest of it. The TypeScript version, in roughly eight days of one-handed sofa evenings, has ten anomaly dimensions, a composition layer, a backfill workflow, a queue-driven reconstruction pipeline, an FTS5 search index, and a full anomaly replay system that can rebuild the archive over arbitrary date ranges without re-fetching traces. The difference is not motivation. The difference is leverage.</p>

<p>Claude Code does most of the actual typing. What I do is decide what to build, decide what the shape of the change is, decide what the data model has to look like, and review the diff. I run the typecheck, I open the migration file, I read the SQL, I push back on the ugly parts. The work that used to be a series of one-week side-quests (“write the queue consumer”, “wire up the workflow”, “add a column and a migration”, “rebuild the index”) is now mostly a series of evenings where I describe what I want and review the result. The repository carries a CLAUDE.md that tells the agent how the project is shaped, what conventions matter, where the SQL gotchas are. I add to it whenever I notice a mistake the agent is likely to make twice. The harness, <a href="https://lord.technology/2026/05/18/the-harness-is-the-product-not-the-model.html">as I have written elsewhere</a>, is the product.</p>

<p>The single highest-leverage commit so far is the one that introduced the queue-driven reconstruction pipeline. I described the problem (the in-cron <code class="language-plaintext highlighter-rouge">reconstruct()</code> was starving on a <code class="language-plaintext highlighter-rouge">LIMIT 25</code> with no ordering, ingestion was outrunning reconstruction by a factor of about twenty, traces were going un-stitched), described the shape of the fix (move reconstruction onto a queue, producer-consumer split, bounded parallelism for ADS-B Exchange rate limits, dead-letter queue for failures), and pressed send. I reviewed the resulting diff for about thirty minutes, asked for two changes, applied the migration, and deployed. The throughput jump that evening was the biggest single behavioural change the project has had so far. I did not type any of it.</p>

<p>I want to be honest about one other thing. Claude Code makes me a better engineer at this project, not a more careless one. The thing I am better at is the architectural call: what should be a queue, what should be a workflow, what should be a cron, what should be a column versus a derived view, where the indexes need to land, what the right abstraction boundary is. I am worse, at the margins, at remembering syntax for SQLite’s <code class="language-plaintext highlighter-rouge">ALTER TABLE</code> quirks, or how Hono’s middleware ordering interacts with cookies, and I no longer particularly care that I am worse at those. The harness handles them. I handle the shape.</p>

<p><img src="/uploads/milmov-type-c17.png" alt="MilMov Boeing C-17 Globemaster 3" /></p>

<p>The page above is the kind of thing I find delightful, partly because every metric on it (the operator distribution, the country distribution, the top airfields, the 30-day activity sparkline, the airborne-right-now count) is one carefully-tuned SQL query against one D1 database, and partly because the C-17 is one of the most aesthetically perfect transport aircraft ever built and I will fight anyone who says otherwise.</p>

<h2 id="why-it-is-closed-source">Why it is closed source</h2>

<p>The obvious question is why I do not open it up. The honest answer is that the system is finely tuned to my taste, and the value of that tuning is precisely that it is not negotiable with anyone else. I do not want a pull request asking me to add Taylor Swift’s jet to the home feed. I do not want an issue thread relitigating whether <code class="language-plaintext highlighter-rouge">Oligarch</code>-tagged airframes should be in the live map. The project is private the way a workshop is private. There is no roadmap to maintain, no contributor onboarding to write, no GitHub Discussions to ignore. The site has an access-token gate not because the data is sensitive — most of it is on ADS-B Exchange’s own site — but because the gate keeps the audience at one person, and one person is the design.</p>

<p>There is a version of this project I could imagine open-sourcing, and it would attract a small, intense community, and I would resent every minute of running it. The version I have built instead is one I love spending evenings inside.</p>

<p>The Cloudflare bill, after a week of running this at full volume, is a single-digit number of dollars. The Claude Code subscription pays for itself any week the project makes me smile, which is most of them.</p>

<h2 id="what-i-get-out-of-it">What I get out of it</h2>

<p>I have learned more about military aviation in the eight days of building this thing than in years of casual reading. I now know which RAF squadrons fly Texans out of which fields, why the US Navy E-6Bs and Air Force E-4Bs co-orbit during certain exercises, what a Royal Australian Air Force C-17 is doing in Diego Garcia, what the standard FL for a Globemaster transatlantic crossing tends to be, which Belarusian An-148 belongs to whom. I have started recognising airframes by registration the way some people recognise birds by song.</p>

<p>I have also learned, in a way no platform documentation ever quite teaches, what the Cloudflare Developer Platform feels like under sustained load from someone being slightly unreasonable about how much they want to do per dollar. I <a href="https://architectingoncloudflare.com/">wrote a book</a> earlier this year about how these primitives compose; MilMov is what taking my own advice in a single week looks like. It scales further than any hobby project has any right to need. The primitives genuinely compose the way the marketing claims they do. The constraints (the 128 MB memory cap, the 30-second wall on cron invocations, the D1 placeholder limit, the FTS5 tokenizer quirks) push you towards architectures that turn out, even after only a week of running them, to be the architectures I would have wanted in the first place.</p>

<p>The E-6B Mercury that orbited over the North Sea has not reappeared in MilMov since. The composed anomaly is still in the archive, with its decayed score, its dimension tags, its little caption explaining what fired and why. The orbit ended after about three hours; the aircraft turned west, climbed, and went home. Whatever it was doing was none of my business. The fact that the system noticed, on my behalf, while I was on the sofa with one hand free and a day job to do in the morning — that is the whole point of the project, and the whole point of building anything for an audience of one.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="cloudflare" /><category term="personal" /><category term="workers" /><category term="d1" /><category term="workflows" /><category term="queues" /><category term="adsb" /><category term="claude-code" /><category term="aviation" /><summary type="html"><![CDATA[At about half past eleven one evening this week I noticed a US Navy E-6B Mercury orbiting over the North Sea. Not “noticed” in the way of someone who happened to look up — I was on the sofa with a laptop balanced on one knee, and the orbit was being drawn for me, in slow careful circles, by a dashboard I had been building, in evenings and weekends, for the previous eight days. The aircraft is a survivable airborne command post for the strategic nuclear force. It does not normally show up on a flight tracker at all, and when it does, it tends to fly straight lines between US bases. An orbit over the North Sea at FL250 with the callsign blanked is not a routine sight. The dashboard, which I had taught about a hundred small things by then, had quietly composed the event for me as a “rare type” anomaly with a “long sortie” co-signal. I watched the orbit for about forty minutes.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The harness is the product, not the model</title><link href="https://lord.technology/2026/05/18/the-harness-is-the-product-not-the-model.html" rel="alternate" type="text/html" title="The harness is the product, not the model" /><published>2026-05-18T21:00:00+01:00</published><updated>2026-05-18T21:00:00+01:00</updated><id>https://lord.technology/2026/05/18/the-harness-is-the-product-not-the-model</id><content type="html" xml:base="https://lord.technology/2026/05/18/the-harness-is-the-product-not-the-model.html"><![CDATA[<p>Cloudflare’s <a href="https://blog.cloudflare.com/cyber-frontier-models/">Project Glasswing write-up</a> landed today and the Hacker News thread is mostly arguing about whether the prose was written by Mythos or by Opus. It is a fair complaint and an irrelevant one. The diagram halfway down the page is the actual deliverable, and almost nobody is talking about it.</p>

<p>Cloudflare has published the reference architecture for doing vulnerability research with a frontier model at scale. The model in the headline is the easy part. The seven-stage agent pipeline around it is what makes the model useful, and it is the bit worth stealing.</p>

<h2 id="what-the-pipeline-actually-does">What the pipeline actually does</h2>

<p>Recon reads the repository top-down and produces a shared architecture document covering build commands, trust boundaries, entry points, and likely attack surface. Every downstream agent works from the same map.</p>

<p>Hunt fires roughly fifty agents in parallel, each pinned to one attack class against one narrow scope. Each hunter can compile and execute proof-of-concept code in a per-task scratch directory. Not ‘reason about whether this might be exploitable’, but actually run the exploit and see what happens.</p>

<p>Validate is the move that separates this from a clever prompt. An independent agent with a different prompt, a different model, and no ability to emit its own findings re-reads the code and tries to disprove the hunter. Putting two agents in deliberate disagreement does more for noise reduction than any amount of careful single-agent prompting.</p>

<p>Gapfill re-queues areas the hunters touched but did not cover. Dedupe collapses variants. Trace fans out one agent per consumer repository, uses a cross-repo symbol index, and answers the question that actually matters, which is whether attacker-controlled input reaches the flaw from outside the system. Feedback turns reachable traces into new hunt tasks. Report writes structured output against a schema and fixes its own validation errors before submitting.</p>

<p>Each stage is a fix for a specific failure mode anyone who has tried this work at scale will recognise. Unconstrained scope makes the model wander. Self-review turns the model into a generous marker. Once a hunter has had a few wins with one attack class it starts drifting toward that class and ignoring the rest of the surface. And the gap between ‘we found a thing’ and ‘an attacker can actually reach the thing’ is where most security findings die.</p>

<p>This is not Claude Code with a system prompt. It is a directed graph of agents with deliberately different prompts and deliberately constrained tool access, where the disagreement between agents carries the structural weight.</p>

<h2 id="why-the-model-is-the-wrong-thing-to-fixate-on">Why the model is the wrong thing to fixate on</h2>

<p>The thread keeps trying to litigate whether Mythos is genuinely a step change or a marketing exercise. Pick whichever side you prefer. The harness works because Mythos is good enough at chained reasoning to make the hunt stage productive, but it would still work, with degraded signal-to-noise, on Opus 4.7 or GPT-5.5. The architecture is the moat, not the weights.</p>

<p>Anyone who has pointed Claude Code at a hundred-thousand-line repository and asked it to find security issues knows the failure mode Cloudflare describe. A single agent session, even with subagents, covers maybe a tenth of a percent of the attack surface usefully before compaction kicks in and the earlier findings get dropped without ceremony. Driving harder does not help past a certain point. The bottleneck stops being the model and starts being the shape of the interaction.</p>

<p>This is the lesson most teams reaching for agentic engineering on non-trivial problems are going to learn the hard way. The model is necessary and nowhere near sufficient. Scope hints, adversarial reviewers, per-task scratch environments, structured output schemas, an explicit reachability stage. That is where the engineering lives. Security research makes the point obvious because the problem is narrow and parallel by nature. Plenty of other domains have the same shape if you look.</p>

<h2 id="what-to-take-from-this">What to take from this</h2>

<p>The adversarial review stage is the change with the highest payoff. Drop a second agent into your existing single-agent setup with a different prompt and no ability to emit findings of its own, and watch the false-positive rate fall. It generalises to anything where ‘is this finding real’ and ‘did the model find it’ need to be different questions.</p>

<p>The other pattern worth lifting is the split between ‘is there a flaw’ and ‘can an attacker actually reach it’. Asking the model both questions in one prompt produces worse answers to both. Splitting them across agents is cheap, and the same shape applies anywhere coverage matters more than depth on a single hypothesis.</p>

<p>The Cloudflare post itself is over-edited, light on hard numbers, and probably an inadequate basis for forming a view on Mythos specifically. <a href="https://daniel.haxx.se/blog/2026/05/11/mythos-finds-a-curl-vuln/">Daniel Stenberg’s write-up on a Mythos finding in curl</a>, <a href="https://xbow.com/blog/mythos-offensive-security-xbow-evaluation">XBOW’s competitive evaluation</a>, and the <a href="https://www.aisi.gov.uk/blog/our-evaluation-of-claude-mythos">AISI evaluation</a> are better signal on the model. Trust the harness diagram more than the framing around it.</p>

<p>The model gets the headline. The harness is what ships.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="cloudflare" /><category term="security" /><category term="agents" /><category term="claude" /><summary type="html"><![CDATA[Cloudflare’s Project Glasswing write-up landed today and the Hacker News thread is mostly arguing about whether the prose was written by Mythos or by Opus. It is a fair complaint and an irrelevant one. The diagram halfway down the page is the actual deliverable, and almost nobody is talking about it.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">If AI made Cloudflare more productive, the layoffs are the wrong move</title><link href="https://lord.technology/2026/05/08/if-ai-made-cloudflare-more-productive-the-layoffs-are-the-wrong-move.html" rel="alternate" type="text/html" title="If AI made Cloudflare more productive, the layoffs are the wrong move" /><published>2026-05-08T13:00:00+01:00</published><updated>2026-05-08T13:00:00+01:00</updated><id>https://lord.technology/2026/05/08/if-ai-made-cloudflare-more-productive-the-layoffs-are-the-wrong-move</id><content type="html" xml:base="https://lord.technology/2026/05/08/if-ai-made-cloudflare-more-productive-the-layoffs-are-the-wrong-move.html"><![CDATA[<p>Cloudflare laid off more than 1,100 people yesterday, around 20% of the company. The announcement, titled ‘Building for the Future’, explains the cuts by noting that internal AI use is up 600% in three months and the company needs to ‘architect itself for the agentic AI era’. The stock dropped 15-18% in after-hours trading.</p>

<p>I work at a Cloudflare partner, build on the Developer Platform daily, and have spent the last few years arguing that the platform is the strongest place to put new edge workloads. So when I say the public reasoning here does not survive five minutes of scrutiny, it is not contrarianism. It is concern.</p>

<p>The argument Matthew Prince and Michelle Zatlyn put forward is that AI has made the workforce so productive that the company can be smaller. If that were true, the rational move would be to hire more, not fewer. Cloudflare sits in front of a substantial portion of internet traffic and sells exactly the products that benefit from agent traffic going up: DDoS protection, Workers, AI Gateway, Bot Management, Browser Rendering, Durable Objects. The world is filling up with autonomous software that needs ingress, egress, security, and stateful compute at the edge. If your engineers are 6x more productive and your addressable market is expanding at the same time, the move is to fund more shots on goal. Ship more product. Undercut competitors who are still slow. Hire the people the rest of the market just laid off.</p>

<p>You do not cut 1,100 people.</p>

<h2 id="what-the-numbers-say">What the numbers say</h2>

<p>Cloudflare reported Q1 2026 revenue of $639.8 million, up 34% year on year. Free cash flow was $84.1 million for the quarter, 13% of revenue. Cash and equivalents stand at $4.16 billion. On the surface, a healthy growing business.</p>

<p>But the company has never posted a GAAP profit. Net loss in 2025 was $102 million, in 2024 was $79 million, in 2023 was $184 million. Stock-based compensation ran at $470 million last year against roughly 5,000 employees, around 22% of revenue. Gross margin compressed five points year on year, from 76% to 71%. Q2 guidance of $664-665 million implies growth decelerating into the high 20s.</p>

<p>That is the actual story. Margins are compressing, growth is slowing from a very high base, SBC is creeping up, and the company has been signalling profitability to the market for years without getting there. The AI narrative is more flattering. ‘We are reorganising for the agentic AI era’ lands better in a press release than ‘our gross margin is going the wrong way and analysts will punish us if we miss profitability targets again’.</p>

<h2 id="why-the-framing-matters-for-the-platform">Why the framing matters for the platform</h2>

<p>If the company were honest about this, I would have less to say. Public companies cut costs. The severance is good, full base pay through end of 2026, vesting through August, cliff-waivers for the recently hired. That is the kind of package that takes effort to put together and signals a leadership team that wants to do this right by people.</p>

<p>The framing matters because it determines who got cut. A margin-driven layoff selects for the bottom of the performance distribution and roles that are genuinely surplus. An ‘agentic-AI-era reorganisation’ selects for whoever a consultant told you to cut. The reports surfacing from inside Cloudflare on Hacker News describe the second pattern. Engineering managers said they had been actively trying to hire and lost team members anyway. SREs and PMs running connectivity-critical systems lost a quarter of their headcount. One manager wrote that his team’s products were running at 95% margin and he was still cut deep.</p>

<p>This is the bit that should worry Cloudflare’s customers and partners. The platform had two major incidents in the last twelve months that shook confidence. The remediation work after incidents like those is exactly the kind of unglamorous, institutionally-rooted effort that does not show up on a productivity dashboard but matters a great deal at 03:00 on a Sunday. An agent can triage a ticket. An agent cannot tell you why a particular config drift in a particular POP eighteen months ago is the reason a particular class of bug keeps recurring.</p>

<p>Cut 20% across an org and you do not lose 20% of the institutional memory. You lose the load-bearing 20%, because the load-bearing 20% is also the most expensive and the most senior, and consultants’ spreadsheets don’t have a column for ‘knows the system’.</p>

<h2 id="the-intern-post">The intern post</h2>

<p>In September 2025, Cloudflare announced a programme to hire 1,111 interns, the number a deliberate nod to 1.1.1.1. The blog post was called ‘Help Build the Future’. Eight months later, they laid off 1,100 people in a post called ‘Building for the Future’. The interns are a separate cohort and were not, from what I can see, the ones cut.</p>

<p>The kindest reading is coincidence. The less kind reading is that Cloudflare front-loaded cheap labour, kept the cheap labour, and shed the expensive labour. That is the oldest playbook in tech, dressed up in current-cycle vocabulary.</p>

<h2 id="what-this-changes-for-the-platform">What this changes for the platform</h2>

<p>I will keep building on Cloudflare. Workers, Durable Objects, R2, Queues, Workers AI, the developer platform as a whole is still the strongest place to design edge-first systems. None of that changes overnight. Product velocity over the last three years has outpaced every comparable platform, and the recent agentic-platform launches show no sign of letting up.</p>

<p>What I am revising is my confidence in the rate of improvement from here. The velocity came from teams of senior engineers who knew the systems and shipped hard against an aggressive roadmap. If a meaningful slice of those people just left, the velocity leaves with them, regardless of how many agent sessions the survivors are running. It will show up in product gaps, in regressions, and in incidents.</p>

<p>If you have anything load-bearing on Cloudflare, this is the week to look at your fall-back posture. Not because the platform is about to fall over, but because the assumption that the engineering organisation behind it is in the same shape as last quarter is no longer safe.</p>

<p>The honest version of yesterday’s announcement would have been one paragraph. We over-hired into a different macro environment, our gross margin needs defending, here is who is leaving and how we are paying them. The version we got tries to make a margin decision sound like a vision, by borrowing the same productivity story Cloudflare sells to its customers and turning it on its own staff. That is not building for the future. It is calling the bill from the past a strategy.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="cloudflare" /><category term="cloudflare" /><category term="ai" /><category term="business" /><summary type="html"><![CDATA[Cloudflare laid off more than 1,100 people yesterday, around 20% of the company. The announcement, titled ‘Building for the Future’, explains the cuts by noting that internal AI use is up 600% in three months and the company needs to ‘architect itself for the agentic AI era’. The stock dropped 15-18% in after-hours trading.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">A Loop Intelligence Hub guarantees the failure it claims to solve</title><link href="https://lord.technology/2026/05/05/a-loop-intelligence-hub-guarantees-the-failure-it-claims-to-solve.html" rel="alternate" type="text/html" title="A Loop Intelligence Hub guarantees the failure it claims to solve" /><published>2026-05-05T21:00:00+01:00</published><updated>2026-05-05T21:00:00+01:00</updated><id>https://lord.technology/2026/05/05/a-loop-intelligence-hub-guarantees-the-failure-it-claims-to-solve</id><content type="html" xml:base="https://lord.technology/2026/05/05/a-loop-intelligence-hub-guarantees-the-failure-it-claims-to-solve.html"><![CDATA[<p>Robert Glaser has <a href="https://www.robert-glaser.de/when-everyone-has-ai-and-the-company-still-learns-nothing/">a long post</a> arguing that individual AI productivity gains do not become organisational gains, and that companies need a ‘Loop Intelligence Hub’ to capture which agentic workflows produce learning. The diagnosis is right. The fix would guarantee the failure it claims to solve.</p>

<p>The article hit the front page of Hacker News, and the top-voted comment, from a developer called olsondv, refuted the proposal in real time. ‘There is simply no motivation to develop this sort of intelligence loop as a dev who has their own responsibilities which their job depend on. Management can ask as nicely as they want, but I’m not going to selflessly share my productivity gains with the broader company for free.’ A reply from ravenstine went further: in an employer’s market, treat your personal AI workflows as trade secrets. If they want them, they can pay for them.</p>

<p>This is not cynicism. It is a rational read of the incentive structure inside every company that has started asking VPs how many story points AI delivered this sprint. Glaser writes that ‘the whole thing dies if it turns into employee scoring’ as if that were a risk to be managed by good intent. It is not a risk. It is the default outcome of any system that instruments how individuals use AI, no matter what the kickoff deck says.</p>

<h2 id="the-harness-collects-what-people-are-willing-to-be-seen-doing">The harness collects what people are willing to be seen doing</h2>

<p>Glaser proposes a ‘feedback harness’ that listens to real work loops, collecting prompts, specifications, reviews, accepted and rejected hypotheses, production signals, rework, human decisions, and interventions. A Loop Intelligence Hub then turns those signals into an enablement backlog, a capability radar, investment briefs, governance gaps. The framing is careful, and the whole edifice rests on engineers routing their genuine work through it.</p>

<p>They will not. Once a system exists that captures which loops produced learning, three things happen quickly. The most productive engineers route their best work outside the harness. The teams furthest along on agentic patterns develop a parallel toolchain on personal accounts. And the harness fills with the kind of demonstrable, well-narrated AI work that makes you look good in a quarterly review. Visible compliance, invisible learning, which is the failure mode Glaser names. The harness produces it.</p>

<p>A manager called daheza describes the mechanism in the same thread. VPs are asking ‘how many story points are we getting with AI now’, and ‘plenty of other managers are fully ready to just give bogus numbers’. His own team has cut stories that used to be five points to three because of AI, and total points delivered per sprint have stayed flat. The unit of measurement is being adjusted to keep the dashboard stable. That is not adoption failure. That is the system behaving exactly as a measured workforce behaves when the measurement turns into a ratchet.</p>

<h2 id="the-bottleneck-is-somewhere-else-entirely">The bottleneck is somewhere else entirely</h2>

<p>The single most upvoted comment on the article, from pards, makes a point Glaser does not address. ‘Development speed was never the bottleneck; it’s all the other processes that take time: infra provisioning, testing, sign-offs, change management, deployment scheduling etc. Code takes 6-12 months to make it from commit to production. AI makes these post-development bottlenecks worse. Changes are now piling up at the door waiting to get on a release train.’</p>

<p>This is the Theory of Constraints in plain English. If your constraint is post-development, accelerating pre-development creates inventory rather than throughput. A team running Claude Code at five times its previous output, against a release train that ships every six months, has produced five times the merge conflicts, five times the regression surface, and far more stale code that must be re-reasoned about by the time it finally moves. The unshipped code is, as pards puts it, a liability rather than an asset.</p>

<p>Glaser half-acknowledges this. He cites his own <a href="https://www.robert-glaser.de/what-if-iteration-is-all-we-need/">argument</a> that scrum was built for expensive iteration and that agile organisations preserved the reflexes agile was supposed to remove. But he treats the constraint as a cultural problem about loop sizes and elastic delegation, rather than a structural problem about who owns the deployment pipeline. A Loop Intelligence Hub does nothing for change advisory boards, security review queues, or the manual sign-off your platform team requires before anything reaches production.</p>

<p>It will, however, give you a very nice dashboard about which teams are stretching their loops well.</p>

<h2 id="what-the-article-gets-right">What the article gets right</h2>

<p>The three capabilities Glaser names are useful before the harness framing flattens them. Agent operations, the control plane for what agents can touch and which actions need approval, is genuine engineering work. Capability distribution, the question of how a useful skill discovered in one team becomes available to others without turning into a dead template, is the harder problem and the more interesting one. The middle layer, loop intelligence, is the one I would not build as a centrally instrumented thing.</p>

<p>The version that works is closer to what the support team in Glaser’s own example already does. They turn recurring tickets into workflow automation because they know exactly where the work hurts and nobody in the centre of excellence ever asked the right question. The learning is local, the artefact is functional, and nobody had to publish their prompts to a hub. If a pattern is good enough that another team would want it, the path for it to travel is the platform layer, as a tool, an MCP server, a skill, or a runbook evaluated against real scenarios. The travel does not need a meta-layer watching loops to identify which ones travelled.</p>

<h2 id="what-to-actually-do">What to actually do</h2>

<p>If you are running this rollout in a real company, the useful questions are narrower than the article’s framing, and most of them point away from AI.</p>

<p>Start with the deployment pipeline. If your release train ships every six months and your engineers can now produce changes several times faster than before, you are buying inventory you cannot move. The next budget cycle should fund deployment frequency before it funds agentic engineering enablement, because one of those investments compounds and the other turns into queue depth.</p>

<p>Then check the performance reviews. If AI use is touching individual scoring in any form, the ability to learn what is working has already been lost, and any harness built on top will collect performances rather than work. The fix is editorial, not technical, and it has to be in writing before anyone trusts it.</p>

<p>The remaining question is whether a pattern discovered in one team has any path to becoming a real platform capability without passing through a steering committee. If your platform team is allowed to ship a tool, an MCP server, a skill, or a runbook on the back of one team’s experience, the learning travels by itself. If everything has to be generalised, governed, and badged before it moves, the patterns will stay where they were discovered and the people who discovered them will keep them private.</p>

<p>The honest answer to ‘where is the ROI for the two million euros we paid Anthropic last year’ is that you cannot know yet, and that any system designed to tell you will be gamed before the next quarter closes. The companies that will get value from this technology are the ones whose deployment pipelines, platform layers, and incentive structures already work. The ones whose pipelines and incentives are broken will find that AI surfaces the breakage faster than expected, which is itself a useful outcome, and not the one the procurement deck promised.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="agentic-engineering" /><category term="rant" /><summary type="html"><![CDATA[Robert Glaser has a long post arguing that individual AI productivity gains do not become organisational gains, and that companies need a ‘Loop Intelligence Hub’ to capture which agentic workflows produce learning. The diagnosis is right. The fix would guarantee the failure it claims to solve.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lord.technology/assets/images/og-image.png" /><media:content medium="image" url="https://lord.technology/assets/images/og-image.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>