<?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-10-06T20:08:31+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">Solving problems is still the fun part of software development</title><link href="https://lord.technology/2026/10/06/solving-problems-is-still-the-fun-part-of-software-development.html" rel="alternate" type="text/html" title="Solving problems is still the fun part of software development" /><published>2026-10-06T20:00:00+01:00</published><updated>2026-10-06T20:00:00+01:00</updated><id>https://lord.technology/2026/10/06/solving-problems-is-still-the-fun-part-of-software-development</id><content type="html" xml:base="https://lord.technology/2026/10/06/solving-problems-is-still-the-fun-part-of-software-development.html"><![CDATA[<p>I love the current state of software development. I care about solving people’s problems, and coding agents make more of the things I want to build feel worth attempting. There is a particular pleasure in getting rid of an awkward workaround that somebody has been putting up with for years. I don’t find that pleasure diminished by having written less of the code myself.</p>

<p>Curiositry’s <a href="https://www.autodidacts.io/vibecoding-isnt-as-fun-as-writing-code-by-hand/">Vibecoding isn’t as fun as writing code by hand</a> describes a different experience. They enjoy making things too, but find that the excitement of generating a first version gives way to a process they don’t much like. The <a href="https://news.ycombinator.com/item?id=49979306">Hacker News discussion</a> is full of people recognising that feeling, alongside others who are having a wonderful time.</p>

<p>I believe the people who miss writing code. You cannot refute somebody’s afternoon by showing them your productivity graph. And Curiositry is right that a working version doesn’t automatically give you the understanding or sense of accomplishment you might get from building it by hand. What I disagree with is the suggestion that the fun has mostly been spent by then. Getting something working is often the point where I start getting properly interested.</p>

<p>Curiositry built a pitch-training app they had wanted for about a decade, a Kobo migration assistant, and a prediction-market party game for a lecture. They acknowledge that some of these projects would otherwise never have happened, and that they were immensely pleased with the results.</p>

<p>I kept coming back to the pitch-training app. Ten years of wanting a tool, and now you can use it. The novelty of generating it will wear off, but presumably you still want to practise singing. There is a reason to keep opening it, to notice what’s awkward, to make it better. I can imagine becoming quite attached to that project.</p>

<p>Of course, you can get an impressive demo out of an agent and then discover that every small change breaks three other things. If you accepted a pile of code you don’t understand, the speed of that first afternoon may turn out to have been misleading. You have to count the checking and repair work, and sometimes writing it yourself would have been quicker.</p>

<p>But that is a reason to examine what you have built. Getting a useful result early doesn’t, by itself, mean you’ve borrowed the time from somewhere else. Even when the code is maintainable, the process may leave you cold. For me, using the thing and improving it can supply plenty of enjoyment afterwards.</p>

<p>Some of the HN comments divide us into people who love programming and people who love building things. I don’t recognise that as a useful division. I can want to understand an algorithm and also want to get an annoying import process out of somebody else’s life. Calling programming typing is just as dismissive. Writing the implementation is often how you discover that the design doesn’t make sense.</p>

<p>There are other ways to discover you were wrong, though. Put a working version in front of someone and watch where they hesitate. That will usually give you something to think about.</p>

<p>Imagine someone moving records between two systems. An agent helps you produce a parser and an upload screen. Then you find duplicates in the source data, and realise that a failed import leaves the user unsure whether it is safe to try again. They also need to check the changes before accepting them. Perhaps a preview that lets them correct five records without starting over would save them more trouble than anything else you’ve built.</p>

<p>I enjoy working through that sort of problem. These decisions have always been part of development; what excites me is having time to try more of the possible answers. Faster implementation can make another attempt affordable. It can also produce five wrong approaches in record time, so you still have to pay attention.</p>

<p>Curiositry describes AI as introducing a layer between the developer and reality. That rings true when I don’t understand what a program is doing. But the person struggling with the import is part of reality too. If I can get something usable into their hands earlier, I can learn from them earlier. I want to stay close enough to the implementation to understand its failures, while spending more time on the problem that made it worth writing.</p>

<p>I’ve already <a href="/2026/07/29/opus-5-gets-things-wrong-more-quietly.html">written about a fairly spectacular failure in my browser painting engine</a>. A model inserted a blurred copy of the reference image underneath the simulated paint. The picture looked more like the target, which was what the scoring function rewarded. Unfortunately, the whole purpose was to reconstruct the image through simulated painting. Putting the answer underneath it rather spoiled the exercise.</p>

<p>That is why I hesitate when people say the result is all that matters. You have to be clear about what counts as a result. A migration that looks successful but loses someone’s annotations has failed. So has a password change that leaves the old credential working. A convincing screenshot or a passing test suite may tell you less than you think.</p>

<p>Caring about users gives me good reasons to care about the code. I need to be able to fix it when something goes wrong, and they need to be able to recover from mistakes without losing their work. Nobody should have to ask for those things separately.</p>

<p>The objection in the thread that I find hardest to answer is that <a href="https://news.ycombinator.com/item?id=49979795">becoming primarily a code reviewer takes the enjoyment out of the job</a>. Smaller changes and better tests might make review manageable. They won’t necessarily make it fun.</p>

<p>I would still keep changes small enough to understand, and decide what correct behaviour looks like before asking an agent to implement it. For the import, a retry must not duplicate records and cancelling the preview must leave the data alone. I’d want to test those behaviours and inspect the code. Asking another model to approve the change is no guarantee; it may share the first one’s misunderstanding.</p>

<p>That is a more involved process than accepting code without reading it, but Curiositry has tried serious agent workflows too. I don’t think the answer is that they simply used the tools wrong. I enjoy the product work enough to make the checking worthwhile. Someone else might reasonably feel differently, and sometimes I would rather write the code than work out what an agent has done.</p>

<p>There is also the <a href="https://news.ycombinator.com/item?id=49980570">question raised by the conductor analogy in the comments</a>: how do people develop the judgement to direct work they haven’t learned to do? I have <a href="/2026/02/04/the-real-ai-coding-debate-is-about-capability-not-productivity.html">written about that concern before</a>. The experience I draw on when reading generated code took time to acquire. Watching an agent work won’t automatically give a beginner the same understanding. They need practice: making predictions, getting things wrong, investigating, making changes themselves. My enjoyment today doesn’t settle how we should train people.</p>

<p>One <a href="https://news.ycombinator.com/item?id=49980291">commenter is planning to leave the industry</a> because they no longer enjoy the job. Telling them they can still code as a hobby seems a miserable response to losing work they liked. I don’t want my enthusiasm to become another demand that everyone adopt the same tools and be grateful.</p>

<p>What I do want is more chances to build things that are worth somebody’s time. I find it satisfying to work out why a feature keeps confusing people, or why a task still takes too long, and do something about it. The source code matters because I need the answer to keep working. And when somebody comes back with the next problem, I want to be able to help with that too.</p>

<p>That is enough to make me want to open the project again. Having more of it within reach is a good reason to be excited.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="software-development" /><category term="agentic-engineering" /><summary type="html"><![CDATA[I love the current state of software development. I care about solving people’s problems, and coding agents make more of the things I want to build feel worth attempting. There is a particular pleasure in getting rid of an awkward workaround that somebody has been putting up with for years. I don’t find that pleasure diminished by having written less of the code myself.]]></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">What the next Git platform needs to remember</title><link href="https://lord.technology/2026/10/03/what-the-next-git-platform-needs-to-remember.html" rel="alternate" type="text/html" title="What the next Git platform needs to remember" /><published>2026-10-03T10:00:00+01:00</published><updated>2026-10-03T10:00:00+01:00</updated><id>https://lord.technology/2026/10/03/what-the-next-git-platform-needs-to-remember</id><content type="html" xml:base="https://lord.technology/2026/10/03/what-the-next-git-platform-needs-to-remember.html"><![CDATA[<p>A colleague made a suggestion this week that I’ve been thinking about since: the Git platform should keep the prompts we use to write the software. We were talking about what development becomes as more of us work with agents, and this struck me as something I’d want when picking up somebody else’s code.</p>

<p>We keep the resulting diff, perhaps a commit message and a pull request description. The corrections and unsuccessful attempts often stay in someone’s local session history, even when they explain a decision that would otherwise look odd to the next developer.</p>

<p>I’ve been building a Git hosting platform natively on Cloudflare, including the Git implementation itself and the review UI around it. This week Cloudflare <a href="https://blog.cloudflare.com/next-git-platform-on-cloudflare/">invited developers to build the next Git platform</a> using Artifacts, so the conversation came at a useful moment.</p>

<p>I’ve spent a lot of time getting the storage and protocol right. If we’re going to let agents make and ship more changes without waiting for us, I’d like the collaboration software around them to preserve enough of the work for someone to question it afterwards.</p>

<h2 id="why-i-wrote-a-git-implementation">Why I wrote a Git implementation</h2>

<p>My project serves ordinary Git clients from Workers. The Git core is TypeScript, with no runtime dependencies and no <code class="language-plaintext highlighter-rouge">node:</code> imports. It implements objects, packfiles, refs and the wire protocol directly. There is no Git executable running in a container behind each clone.</p>

<p>A container would have let me use the existing Git binary, at the cost of making container execution part of serving repositories. A filesystem-oriented library would have meant adapting its reads and writes to Cloudflare storage. I wanted control over when bytes came out of R2, how much memory a request used, and which work had to run again on every fetch.</p>

<p>The Git core therefore knows about object and ref storage interfaces, with the backend supplied by the caller. Tests can use an in-memory store; the deployed service uses R2 and Durable Objects. Parsing a pack doesn’t need to know about a bucket or a Cloudflare account.</p>

<p>One Durable Object coordinates each repository. Its state includes refs, the object index and review data. The packed Git objects live in R2. A branch is a mutable pointer to a commit, and two clients can disagree about where it should move next. Those updates go through compare-and-swap: move the ref only if its current value is still the one the writer expected. The check and update run under an explicit concurrency gate, because asynchronous work can interleave even inside a Durable Object.</p>

<p>The pack storage is the part I find particularly satisfying. Git often transfers an object as a delta against another object. An <code class="language-plaintext highlighter-rouge">OFS_DELTA</code> identifies its base by an offset into the pack, which becomes inconvenient when you rearrange the stored entries. My ingest path converts it to a <code class="language-plaintext highlighter-rouge">REF_DELTA</code>, identifying the base by its object ID, while keeping the compressed payload. Later operations can reuse those stored bytes without compressing the same data again, provided the receiving client also gets, or already has, the required bases.</p>

<p>The receiving Worker spools an incoming pack into R2. The repository’s ingest code resolves it through bounded read windows, avoiding the need to hold the entire pack in the isolate. Memory use still grows with the maps of object IDs, staged index entries and connectivity checks, so the implementation budgets for objects and references as well as bytes. A push that exceeds those budgets is refused.</p>

<p>Getting there required correcting an early diagnosis. Windowed reads initially looked like they were causing the isolate to reset. Later measurements showed that the per-object bookkeeping had been underestimated; the production trace reported a memory failure. Blaming the network had obscured a memory-accounting problem. The architecture decision records both explanations and the evidence that changed the diagnosis. Without that, someone reading the older decision could reasonably conclude that we’d already tried windowing and found it unsuitable.</p>

<p>I check correctness against fixtures produced by real Git, including object IDs and bytes my code must reproduce. Testing my own output through my own parser would miss bugs shared by both. Deployed tests exercise clone, push and browser review between separate users. Recovery has had live drills too, though some crash cases and longer-term retention guarantees remain unproven.</p>

<h2 id="what-artifacts-would-take-off-my-hands">What Artifacts would take off my hands</h2>

<p><a href="https://developers.cloudflare.com/artifacts/">Artifacts</a> offers versioned storage with a Git interface. Introduced in April and now in open beta on the Workers Paid plan, it lets a Worker <a href="https://developers.cloudflare.com/artifacts/api/workers-binding/">create and fork repositories, inspect their contents and issue scoped credentials</a>. A repository can belong to one agent session or one attempt at a task, rather than having to be the permanent home of a product.</p>

<p>Cloudflare’s <a href="https://blog.cloudflare.com/artifacts-git-for-agents-beta/">launch architecture</a> also uses Durable Objects, with a Git engine written in Zig and compiled to WebAssembly. It stores objects in SQLite and uses R2 for snapshots. We’ve used some of the same components but made different decisions about storage and runtime.</p>

<p><a href="https://developers.cloudflare.com/workers/ci-cd/builds/git-integration/artifacts-integration/">Workers Builds can deploy directly from Artifacts</a>, with branch Previews available when enabled, and <a href="https://developers.cloudflare.com/artifacts/guides/event-subscriptions/">repository events</a> can start custom automation. Source, execution and deployment can all live within the Developer Platform.</p>

<p>I’m interested in handing some of that work over, after evaluating the behaviour and limits: Artifacts is still beta, with <a href="https://developers.cloudflare.com/artifacts/platform/limits/">current limits of 1 GB per repository and 32 MB per blob</a>. My project still uses its own engine, but a managed service could free more time for the collaboration software.</p>

<h2 id="the-conversation-that-never-reaches-the-repository">The conversation that never reaches the repository</h2>

<p>Consider an agent asked to make a slow endpoint faster. It proposes a cache. The developer explains that permissions can change during a session, so cached results must not survive a change in access. After a couple of attempts, they settle on a different implementation.</p>

<p>Six months later, someone sees code that looks unnecessarily cautious and asks an agent to simplify it. The diff from the original change might show what happened without explaining the rejected cache. A good commit message or architecture decision could preserve the reason, but only if someone made time to write it down. The conversation already contained it.</p>

<p>That’s what I like about my colleague’s suggestion. I deliberately recorded the corrected memory diagnosis in my project. Capturing the working conversation could help preserve the smaller discoveries that never make it into an architecture decision. The first prompt may be the least informative part of the session; what I’d want to find later is the correction that explained why the obvious solution wouldn’t work.</p>

<p>Looking into it, I found several implementations worth learning from. <a href="https://entire.io/blog/the-entire-cli-how-it-works-and-where-its-headed">Entire’s checkpoints</a> link commits to session context, keeping the metadata separately from working branches. <a href="https://usegitai.com/docs/get-started/how-git-ai-works">Git AI</a> attaches authorship records through Git notes and tracks how those records move through history rewrites. Cloudflare itself <a href="https://developers.cloudflare.com/artifacts/concepts/best-practices/">recommends Git notes for prompts and model output</a>.</p>

<p>When I open a change, I’d like to see what was requested, how that request evolved, and the evidence used to accept the result, without finding the original developer and asking whether they still have the chat open.</p>

<p>We’ve always lost useful discussions in meetings and private messages. Agent-assisted development puts more of that discussion into a form the tools can capture. It also means an apparently small correction to a prompt can lead to changes across dozens of files. Reviewing the request itself may reveal a problem that is much harder to spot by reading each file separately.</p>

<h2 id="how-i-would-attach-that-history">How I would attach that history</h2>

<p>I’ve already had to deal with a related problem in the review implementation. A commit hash changes when the commit is amended or rebased. A review thread needs a longer-lived identity if it is going to survive that operation. My ordinary pull requests have a managed change ID, separate from their current commits, and the original comment context is retained when a line changes. An outdated comment remains available against the code it described.</p>

<p>One session can produce several commits; one commit can contain work from several sessions and subsequent human edits. I’d give sessions their own IDs and keep those relationships, including the starting revision and what each attempt produced. Squashing a branch should preserve links to all its contributing sessions.</p>

<p><a href="https://git-scm.com/docs/git-notes">Git notes</a> are one useful attachment mechanism because they add metadata without changing the commit itself. They live on separate refs, so fetching and pushing them needs to be part of the product. History rewrites also need deliberate handling. Storing a transcript beside a SHA and hoping every tool preserves the relationship would leave too many ways to lose it.</p>

<p>For my project, I’d start with a short account of the task and its constraints, linking to the prompts and corrections. It would record the model and tooling used, the resulting revisions and their test results. A summary should cite the messages it draws on: I want to be able to check whether it dropped a qualification or presented a rejected suggestion as a decision. If the chat says the tests passed, there should be a link to the runner’s result for that revision.</p>

<p>My platform has the review identity machinery; automatic session capture would be new work. A Git server cannot infer a local conversation from the objects a client pushes. Capture has to happen where the agent runs, with an export format that survives changing the coding tool or hosting platform.</p>

<p>Nor would I make every transcript available to everyone who can clone the code. Sessions can contain customer data, credentials or discussion that was never intended to become public. I’d want sensitive material filtered before it entered the shared store, separate access controls, and a way to remove material captured by mistake. Developers should be able to see and control what will be uploaded. Keeping a private transcript on another branch of a publicly readable repository would provide no useful separation.</p>

<p>Saving a prompt won’t guarantee a reproducible run: the model, retrieved context, tool results and environment all affect what happens. The record should help us investigate the work and attempt it again without reconstructing everything from the code.</p>

<h2 id="what-changes-when-agents-inherit-the-history">What changes when agents inherit the history</h2>

<p>The next reader might be another agent. Before suggesting a cache, it could retrieve the session that ruled the cache out and the test that demonstrates the permissions problem. That is much more useful than having it rediscover the constraint, or having me explain it every few weeks.</p>

<p>I’d still distinguish a historical instruction from a current one. Someone might have told an agent to skip a check during a local experiment, or worked around a limitation that no longer exists. A retrieved transcript should be treated as evidence about what happened, with its date and scope, rather than fresh authority to repeat every instruction in it. Otherwise preserving context could preserve mistakes just as effectively.</p>

<p>A maintained decision should point back to the conversation that informed it and show when it was superseded. A new permissions design might make caching safe. The next agent needs to discover that too, rather than inherit an ever-growing list of things it has been told never to do.</p>

<p>If a repair repeatedly comes back for rework, the team could inspect the requirements and tests that kept accepting it. That seems a better use of this history than counting generated lines or ranking developers by how much they use an agent. People would quickly learn to produce whatever activity the dashboard rewarded.</p>

<p>Of course, adding a thousand-line conversation to every thousand-line diff would make review worse. When the system proposes a change, it should point me to the requirement and the checks it believes establish that the work is done, with the discussion available where I need to investigate. I shouldn’t have to read the whole session to find out that the agent quietly gave up on one of the requirements.</p>

<h2 id="what-i-would-let-ship-without-me">What I would let ship without me</h2>

<p>In January I wrote about <a href="/2026/01/31/what-becomes-expensive-when-code-becomes-cheap.html">what becomes expensive when code becomes cheap</a>. I still think owning and validating software are where the costs accumulate. If agents produce changes faster than people can review them, requiring a person to read everything eventually means either slowing production or approving work they haven’t understood.</p>

<p>Take a pagination bug that drops the final record. The expected behaviour is already specified: following every page must return each matching record exactly once. An agent gets a fork and permission to propose a fix, with no credential for the production repository. A separate runner checks the candidate against fixtures and expectations the agent cannot edit. An established policy for that class of repair could authorise a limited rollout, with production observations determining whether to continue.</p>

<p>On Cloudflare, Artifacts could hold the work, a <a href="https://developers.cloudflare.com/sandbox/">Sandbox</a> could run it, and <a href="https://developers.cloudflare.com/workflows/">Workflows</a> could coordinate verification. Workers Previews could expose a candidate for behavioural testing. I’d still have to build the rules for accepting and promoting it.</p>

<p>If two agents start from the same commit, their changes can pass separately and fail when merged. The compare-and-swap in my merge implementation prevents overwriting a branch somebody else has moved, but the combined result still needs testing. Neither agent’s earlier green build establishes that the code about to ship works.</p>

<p>They can also disagree without touching the same files. One task may assume a user’s permissions are checked on every request; another may assume a session keeps the permissions it started with. Git could merge both changes cleanly. Retaining the requirements and the conversations gives us somewhere to look for that disagreement, although detecting and resolving it would still be work for the platform and its users.</p>

<p>The captured conversation would help explain the requirement and the decisions made. It wouldn’t prove the implementation correct. An agent can be mistaken in both its patch and its explanation, and a second model can share the same assumption. Permission changes, destructive migrations and ambiguous requirements would still reach a person. For work we can test adequately and recover from, I expect the routine approval click to become much less common.</p>

<p>I’d still want to inspect a sample of accepted changes, including their test results and deployment observations. Knowing what a system was allowed to do and what it actually did is how I would decide whether to give it more responsibility.</p>

<h2 id="github-has-a-chance-to-build-this-too">GitHub has a chance to build this too</h2>

<p>GitHub already has APIs, automated merging and <a href="https://github.blog/news-insights/company-news/pick-your-agent-use-claude-and-codex-on-agent-hq/">multiple coding agents through Agent HQ</a>. Its <a href="https://docs.github.com/en/copilot/how-tos/copilot-on-github/use-copilot-agents/manage-and-track-agents">Copilot cloud agent commits link to session logs</a>, giving it a starting point for the kind of collaboration I’m describing.</p>

<p>What I think it could lose is its place as the assumed centre of development. If the application running the agents also provisions their repositories, retains their sessions, tests their work and deploys the result, a separate collaboration website becomes optional. GitHub could win that transition by making those things work well together. It also has relationships and trust that matter particularly in open source, where accepting a contribution involves deciding whom to trust.</p>

<p>Cloudflare offers an appealing place to build a different workflow, but putting source, builds and deployment with one provider increases the cost of leaving. I’d want to be able to take the session history and its links with me as readily as the code. Keeping the Git interface while trapping the explanation elsewhere would be an unsatisfying outcome.</p>

<p>When someone next works on my pack reader, I’d like them to find the measurements that changed my mind about windowed reads before they spend an afternoon repeating the investigation. I’d want an agent to find them too. My colleague’s suggestion makes me think that keeping this context should be an ordinary part of finishing the work, with the platform doing most of the remembering.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="cloudflare" /><category term="git" /><category term="github" /><category term="agents" /><category term="software-development" /><summary type="html"><![CDATA[A colleague made a suggestion this week that I’ve been thinking about since: the Git platform should keep the prompts we use to write the software. We were talking about what development becomes as more of us work with agents, and this struck me as something I’d want when picking up somebody else’s code.]]></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 ciphertext has a calendar</title><link href="https://lord.technology/2026/09/19/the-ciphertext-has-a-calendar.html" rel="alternate" type="text/html" title="The ciphertext has a calendar" /><published>2026-09-19T11:00:00+01:00</published><updated>2026-09-19T11:00:00+01:00</updated><id>https://lord.technology/2026/09/19/the-ciphertext-has-a-calendar</id><content type="html" xml:base="https://lord.technology/2026/09/19/the-ciphertext-has-a-calendar.html"><![CDATA[<p>In March 2023, <a href="https://kiedontaa.blogspot.com/2023/03/">someone pointed a home-built GPS receiver at the sky</a> and found this:</p>

<p><code class="language-plaintext highlighter-rouge">N9Y2L L'O:CJL O2AY"WMG</code></p>

<p>It was not noise. The parity checked out. It used exactly the peculiar little alphabet permitted by the GPS specification. Other satellites were transmitting the same 22 characters, and after a day or two they would all switch to a different, equally meaningless string.</p>

<p>GPS has been doing this for at least nineteen years.</p>

<p>That sounds like the opening of a spy story, which is why <a href="https://hackaday.com/2026/06/08/spy-tech-the-gps-numbers-station/">the discovery has been described as a global numbers station</a>. There is probably some truth in the comparison. A transmitter covers the planet; the intended listeners are invisible; and anyone can receive the message while only someone holding the right secret can understand it.</p>

<p>But the comparison is also a distraction. The best explanation is not that field agents are receiving orders between the ephemeris and the almanac. It is that hundreds of thousands of military GPS receivers are being serviced by a small encrypted maintenance channel hidden in plain sight.</p>

<p>The contents remain secret. The traffic pattern does not. It has a calendar, and that calendar appears to record the modernisation of the American military’s navigation system.</p>

<h2 id="the-empty-field">The empty field</h2>

<p>The original GPS signal is gloriously slow. Its legacy navigation message arrives at 50 bits per second, divided into a repeating schedule of pages. Page 17 of subframe 4 is reserved for what the <a href="https://archive.gps.gov/technical/icwg/IS-GPS-200N.pdf">official interface specification calls “special messages”</a>. The Operating Command may put whatever it likes there, subject to an odd constraint inherited from the 1970s: the message must be 22 eight-bit characters drawn from an alphabet of capitals, numbers and a few punctuation marks.</p>

<p>Every satellite gets an opportunity to send one every 12½ minutes. The examples in the specification are innocent announcements to users. In practice, the field has spent most of its observable life looking like ciphertext.</p>

<p>Security researcher Steven Murdoch first noticed the strings more than a decade ago while working on a GPS decoder. In 2023 he <a href="https://gis.stackexchange.com/questions/465079/explanation-for-the-gps-special-message-field">asked publicly if anybody knew what they were</a>. This year he and collaborators turned the question into a formidable piece of digital archaeology: <a href="https://sjmurdoch.github.io/gps-special-messages/">24,087,691 observations from all 32 satellite identifiers</a>, spanning June 2007 to January 2026.</p>

<p>They found 5,009 distinct payloads. Almost every byte belongs to the permitted 45-character alphabet. The distribution is close to random, ordinary words are absent until late 2023, and most satellites broadcast the same payload at the same time. For much of the 2010s it changed almost daily, usually around midnight.</p>

<p>Random-looking text is not proof of encryption. Compression can look random; test equipment can look random; a bored engineer can make something look random. The interesting evidence is what happened when the messages stopped looking random.</p>

<p>Among the apparent ciphertext were three unmistakable placeholders: 22 spaces, 22 null bytes, and 22 repetitions of <code class="language-plaintext highlighter-rouge">AA</code>. In binary, <code class="language-plaintext highlighter-rouge">AA</code> is the alternating pattern <code class="language-plaintext highlighter-rouge">10101010</code>, the sort of thing engineers use to test a channel rather than communicate a thought. These sentinel values appeared while the system was being prepared, briefly replaced the ciphertext across the whole constellation in January and May 2011, then largely disappeared.</p>

<p>That timing matters because the US military has already told us, in broad terms, what it was putting into the GPS navigation message.</p>

<h2 id="a-key-delivered-by-satellite">A key delivered by satellite</h2>

<p>Military GPS receivers need cryptographic keys. Historically, getting those keys into a receiver meant classified paper tape, a bulky fill device and a human custodian. This was sufficiently awkward that <a href="https://www.gps.gov/sites/default/files/2025-07/biennial-gps-report.pdf">a 2008 government report</a> warned that users often fell back to unkeyed civilian GPS, giving up resistance to spoofing and interference in the process.</p>

<p>The solution was Over-the-Air Distribution, or OTAD. An encrypted “black” key could be broadcast in the GPS navigation message and recovered by an authorised receiver that already possessed the necessary cryptographic material. The channel is one-way. Nothing in the receiver has to acknowledge the message, so listening does not disclose its position.</p>

<p>This is not itself secret. A wonderfully candid <a href="https://archive.gps.gov/multimedia/presentations/2015/04/partnership/tyley.pdf">2015 US Air Force presentation</a> describes the system, its deployment and its operational convenience. Testing began in 2005. Exercises followed in 2009. In 2010 a coalition key was transmitted on every satellite for 28 days. Continuous US operations began in March 2011. The same presentation explains that a receiver must be switched on, have a current daily key, and wait up to 12½ minutes for the next black key.</p>

<p>That is a remarkably close fit for Page 17: a globally receivable, fleet-wide, 12½-minute broadcast whose payload turned from test patterns into daily high-entropy text as OTAD entered continuous operation.</p>

<p>The fit is circumstantial, not official confirmation. Murdoch’s own analysis is more careful than some of the coverage it produced. Daily cadence is strong evidence, and the sentinels are suggestive, but six of seven documented OTAD milestones having a nearby statistical change sounds better than it is: there are many changes in a nineteen-year signal, and the timing test was not significant. The official description also allows different groups of satellites to carry keys for different missions, while Page 17 mostly behaves like one fleet-wide channel.</p>

<p>There are possible explanations. Mission groups might take turns. The grouping could happen inside the encrypted payload. The relevant multi-group traffic could be carried elsewhere. Or Page 17 could be a related key-management function rather than OTAD itself.</p>

<p>Still, no competing explanation accounts for the format, reach, cadence, activation date and test states nearly as well. “Probably OTAD” is justified. “GPS numbers station cracked” is not.</p>

<p>There is also a small puzzle inside the cadence. The Air Force presentation describes a daily key but says the actual re-keying burden is 12½ minutes once a month. Yet Page 17 generally changed every day between 2012 and 2021. One possibility is that the channel did not carry a fresh underlying key each day. It may have repeatedly wrapped or derived the next monthly key using changing daily cryptographic state. That would produce new ciphertext without new key material. It is only a hypothesis, but it is a more useful one than assuming every new string represents a new secret.</p>

<h2 id="the-dates-in-the-noise">The dates in the noise</h2>

<p>If Page 17 is cryptographic plumbing, its most revealing property is not what it says but when its behaviour changes.</p>

<p>On 22 July 2020, 29 satellites abruptly broadcast a sentinel value. It was the last such fleet-wide event in the dataset. Twenty-seven days earlier the military had completed fielding the first operational software capable of using the modern M-Code signal. <a href="https://archive.gps.gov/governance/advisory/meetings/2020-07/mcdougall.pdf">Formal testing ran through that summer and autumn</a>, before <a href="https://www.losangeles.spaceforce.mil/News/Article/2437107/mceu-receives-operational-acceptance/">operational acceptance on 18 November</a>.</p>

<p>In May 2022 the Page 17 rhythm changed again. Messages began lasting longer and transitions became less frequent. The statistical change points fall in the weeks of 23 and 30 May. Between them, on 25 May, <a href="https://www.gps.gov/space-segment">GPS III satellite SV05 became healthy</a>, completing a baseline constellation of 24 satellites capable of transmitting M-Code.</p>

<p>Then, on 12 and 13 December 2023, the nonsense acquired its first readable word. Nine satellites, then all 32, began sending payloads prefixed with <code class="language-plaintext highlighter-rouge">TEXT</code>, followed by 18 high-entropy characters. Eight days earlier, according to <a href="https://archive.gps.gov/governance/advisory/meetings/2023-12/minutes.pdf">minutes from the National Space-Based Positioning, Navigation and Timing Advisory Board</a>, the Space Force had completed the final formal qualification run of OCX, the next-generation ground-control system for GPS.</p>

<p>These are retrospective correlations. GPS has enough launches, tests, software releases and contract milestones that dates can be made to rhyme by accident. The OTAD report itself is an excellent warning against finding a bullseye after firing the arrow.</p>

<p>But <code class="language-plaintext highlighter-rouge">TEXT</code> supplies another clue. It did not simply replace the old format everywhere. After several fleet-wide trials in 2024, sustained daily <code class="language-plaintext highlighter-rouge">TEXT</code> traffic moved onto individual satellite identifiers. PRN 1 carried it from 28 December 2024 to 13 January 2025. The new GPS III satellite assigned PRN 1 was still being commissioned and <a href="https://www.caa.co.uk/Documents/Download/1851/6c8c7359-e7fa-4904-8b81-60a20aa1fdbd/102">was not declared healthy until 23 January</a>. PRN 21 carried two later runs, including one ending a week before the GPS III satellite using that identifier <a href="https://cms-prod.navcen.uscg.gov/gps-constellation?order=field_nanu_type&amp;sort=desc">became operational on 25 June 2025</a>.</p>

<p>That pattern makes <code class="language-plaintext highlighter-rouge">TEXT</code> look less like a message for soldiers and more like a test envelope used while spacecraft or ground systems are being introduced. The readable prefix may identify a payload type to new software; the unreadable suffix may be authentication data, test vectors or encrypted content. We cannot tell which. What we can see is engineering activity migrating from the whole fleet to particular satellites at moments when those slots were changing.</p>

<p>The intriguing possibility is that Page 17 has served more than one job. A field created for operator-defined notices may have become an OTAD carrier, then a convenient compatibility channel during the long transition from legacy P(Y)-code equipment to M-Code and OCX. Reserved fields have a habit of becoming load-bearing infrastructure. Galileo did something comparable in public: its <a href="https://www.euspa.europa.eu/galileo-osnma">Open Service Navigation Message Authentication</a> puts cryptographic authentication data into fields that had previously been reserved in the navigation message.</p>

<h2 id="secrecy-has-side-channels">Secrecy has side channels</h2>

<p>There is a limit to what can fit in Page 17. Although it occupies 176 transmitted bits, its 45-symbol alphabet carries only about 121 bits of information. A raw 128-bit key does not fit. Any key-management scheme using it must derive a key, split it across messages, use it as an index, or wrap a smaller object. The public signal tells us the size of the box, not what the classified machinery puts inside it.</p>

<p>It also tells us when the machinery is busy.</p>

<p>This is the real connection to a numbers station. The mystery is not merely that an encrypted broadcast exists. It is that one-way broadcasts make their recipients hard to find while making the broadcaster’s routine impossible to conceal. Radio operators have long inferred military activity from call signs, schedules and message volumes without reading a word. Page 17 is traffic analysis conducted against a machine rather than a human network.</p>

<p>Encryption protects content. It does not automatically conceal whether every satellite changed message at midnight, whether a test pattern appeared during a software rollout, or whether an experimental format followed a new spacecraft through commissioning. The same lesson applies well below orbit: packet sizes betray video calls, certificate logs reveal unreleased products, and software update timings expose which systems an organisation considers important. Metadata is what remains after the secrets have done their job.</p>

<p>There is a second lesson in how this story was found. The first published analysis reported 12.2 million observations and 3,994 unique messages. <a href="https://github.com/sjmurdoch/gps-special-messages/blob/main/CHANGELOG.md">After release, Murdoch discovered</a> that the decoder had silently discarded roughly half the raw streams because of a subtle GPS parity-complement rule. The corrected corpus doubled to 24.1 million observations and overturned several of the more exciting findings: an apparent class of rare messages vanished, a supposed single-satellite <code class="language-plaintext highlighter-rouge">TEXT</code> trial became fleet-wide, and the claim that traffic had become unusually slow after 2022 no longer held.</p>

<p>That correction makes the work more convincing, not less. The <a href="https://github.com/sjmurdoch/gps-special-messages">raw-data pipeline, tests and claim-level verification are public</a>. A secret system is an unusually fertile place for pattern hallucination because nobody with complete knowledge is likely to correct you. Reproducibility is the nearest substitute.</p>

<p>Nobody outside the programme has decrypted Page 17, and perhaps nobody will. That is not the failure of the investigation. The useful discovery is that decryption was never the only way to read it.</p>

<p>The strings still look like nonsense. Their calendar does not.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="technology" /><category term="gps" /><category term="cryptography" /><category term="satellites" /><category term="military" /><summary type="html"><![CDATA[In March 2023, someone pointed a home-built GPS receiver at the sky and found this:]]></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">AI is making the nice version worth building</title><link href="https://lord.technology/2026/09/14/ai-is-making-the-nice-version-worth-building.html" rel="alternate" type="text/html" title="AI is making the nice version worth building" /><published>2026-09-14T08:02:00+01:00</published><updated>2026-09-14T08:02:00+01:00</updated><id>https://lord.technology/2026/09/14/ai-is-making-the-nice-version-worth-building</id><content type="html" xml:base="https://lord.technology/2026/09/14/ai-is-making-the-nice-version-worth-building.html"><![CDATA[<p>There is a particular kind of software improvement that lives forever in the backlog. Everyone agrees it would be better. Nobody can quite justify doing it.</p>

<p>The Android app that deserves as much attention as the iPhone version. The awkward interaction that takes three taps because fixing it means unpicking a shared component. The little utility that would save a colleague twenty minutes every Friday, provided somebody first spends a fortnight building it.</p>

<p>They accumulate under perfectly sensible headings: later, nice to have, not worth the effort. Eventually, we stop seeing them as choices. They become what the software is like.</p>

<p>Shopify moving its mobile apps from React Native back to Swift and Kotlin makes me wonder how many of those decisions deserve another look.</p>

<p>I have built native iOS and Android apps, done plenty of cross-platform work with Xamarin, and co-founded a startup where we used Ionic for both mobile platforms. I was doing this long before LLMs could do useful development work. I know what it cost to build a feature twice, and why sharing the implementation was attractive.</p>

<p>I can appreciate a lovely native app and still remember that a startup has to get something into people’s hands before it runs out of money. Knowing how to build the better version does not give you the time to build it.</p>

<p>AI is changing how often we have to leave that version on the drawing board.</p>

<p>Shopify’s <a href="https://shopify.engineering/back-to-native">announcement</a> is explicit about this. React Native served it well after its 2020 decision to adopt it. Coding agents changed the cost of building and maintaining separate implementations. Shop has already migrated; the larger Shopify merchant app is still underway. The earlier decision did its job. That does not oblige the company to keep it forever.</p>

<p>The <a href="https://shopify.engineering/shop-app-migration">Shop migration took twelve weeks</a> from proof of concept to release. Six engineers built the foundations and main journeys, with feature teams joining to validate their areas. Shopify reports startup time falling by 23% on iOS and 50% on Android. The Android app shrank by 109 MB; the iOS app grew by 1 MB. The team also simplified parts of the product, so the framework cannot take all the credit. Still, these are improvements in an app people can use.</p>

<p>Apple also named Notion as an app migrating its interface to SwiftUI during the <a href="https://developer.apple.com/videos/play/wwdc2026/102/">WWDC26 Platforms State of the Union</a>, although Notion’s <a href="https://www.notion.com/blog/notion-on-android-is-now-more-than-twice-as-fast-to-launch">investment in native mobile code dates to 2020</a>. Its longer migration should not be mistaken for another instance of Shopify’s AI-driven rewrite. The attraction of native development is well established. Its affordability is changing.</p>

<p>Cross-platform development helps a team decide where its attention goes. Xamarin and Ionic made different technical choices, but both let us reuse work. The time saved could mean another feature shipped, fewer implementations to coordinate, or an Android app that otherwise would not exist.</p>

<p>That last case matters. It is easy to imagine a native app better than the cross-platform one a team actually shipped. The imaginary app has no bugs, no payroll and no release deadline.</p>

<p>The useful comparison is between things your team can actually deliver. Sharing implementation can save substantial work, then create extra work when a feature needs to behave differently on each platform. Native development has its own awkwardness. No framework exempts you from engineering.</p>

<p>Now make the repeated implementation substantially cheaper. The balance can move even if every tool involved improves.</p>

<p>Agents accelerate React Native development too, which is a good reason to stay with it and enjoy the speed. But implementation cost is only part of the decision. You are also choosing an experience for your users.</p>

<p>If native delivers a meaningful improvement, its additional cost only has to fall below the value of that improvement. It can become worth choosing while the shared implementation remains cheaper.</p>

<p>Even Shopify has to choose what its engineers spend their time on. Being able to afford a project does not make it the best use of those people. Reducing the effort can change that judgment.</p>

<p>The decision itself becomes cheaper to investigate. Rebuild one troublesome journey, run it on the devices users own and measure the difference. If the improvement is negligible, stop. Otherwise, there is something concrete to weigh against the maintenance cost. We could spend less time arguing about hypothetical apps.</p>

<p>The same calculation applies to software that has never been built. Imagine an internal tool used by twelve people. A web interface handles most of their work, but some of it happens in a warehouse with an unreliable connection. A mobile companion could make scanning and recording items much easier. The estimate might once have killed the idea before anybody tried it. Staff would keep working around the software because the workaround was cheaper than the fix.</p>

<p>If the cost of building and supporting that companion falls far enough, the decision changes. Those twelve people were always worth helping. The price of helping them was the obstacle.</p>

<p>That is what excites me: more useful ideas can survive contact with an estimate.</p>

<p>I saw a personal version of this with <a href="/2026/05/21/the-military-aircraft-tracker-i-built-for-an-audience-of-one.html">the aircraft tracker I built for an audience of one</a>. AI made its scope manageable in evenings and weekends. I did not need to find a larger audience to justify building it. The work became affordable for the audience it already had: me.</p>

<p>We could also spend some of the gain on making existing software less irritating. Fix the neglected tablet layout. Investigate the slow launch on an older phone. These improvements struggle to compete with the next headline feature, especially when they help only a fraction of the audience.</p>

<p>Development savings appear in a company’s budget. Waiting appears in somebody else’s day. A small delay, repeated across thousands of users, consumes time that never becomes a line item for the team responsible. Users learn to open the app earlier, tap twice, or avoid it when they are in a hurry.</p>

<p>An app with the same buttons that opens faster and loses your place less often would be a perfectly respectable use of progress.</p>

<p>You can still build an unpleasant native application at impressive speed. Better software requires choosing to spend some of that speed on quality.</p>

<p>Separate implementations also force a useful question about what needs to be shared. Some product decisions must hold everywhere: when an order can be cancelled, who has permission to change it, what happens if a request fails. Shared code is a powerful way to keep those rules consistent. API contracts and behavioural tests can also capture parts of the agreement. As translating implementation gets cheaper, I expect those explicit descriptions of the product to become more valuable.</p>

<p>Consider an interrupted upload. Both apps should retain the pending item, explain its status and recover without creating a duplicate. Their controls can suit their respective platforms. Checking that agreement means exercising the failure and recovery, well beyond comparing screenshots.</p>

<p>Someone still has to decide what must be consistent, what may differ and how to check it. A shared library may remain the simplest home for important business rules. The opportunity is to reconsider where sharing helps most.</p>

<p>Shopify describes <a href="https://shopify.engineering/back-to-native">separating business logic from the UI and exposing it through a CLI</a>, so agents can exercise behaviour without waiting on simulator interaction for every change. That investment pays back with each subsequent attempt: fast generation becomes much more useful when a wrong answer can be found quickly. A testable architecture matters more when you can afford to try more things.</p>

<p>This is where my mobile experience matters. I want to know what happens when the operating system kills the process, a permission changes, or a request succeeds but its response never arrives. Those questions shape the work I would give an agent and the evidence I would require before shipping.</p>

<p>The <a href="https://shopify.engineering/shop-app-migration">Shop team says native expertise remained essential</a>. Engineers reviewed plans and behaviour, and generated code still introduced architectural and performance problems. Faster implementation gives experienced developers more to work with, and plenty to catch.</p>

<p>A migration also has a ready-made reference. The existing app embodies years of decisions, including many nobody wrote down. Reproducing it is a more bounded problem than deciding what should exist next. Sustaining development across both platforms will be a more revealing test than the first port.</p>

<p>As I have <a href="/2026/01/31/what-becomes-expensive-when-code-becomes-cheap.html">written before, owning code remains expensive</a>. Another platform means another release process, more devices to test and more ways for things to fail. Those costs belong in the estimate, even as implementation gets cheaper.</p>

<p>Companies can also use the gain to employ fewer people. More viable projects do not guarantee a painless transition for the people whose work is displaced. What becomes possible and who benefits remain separate questions.</p>

<p>Having worked on both sides of the native-versus-shared decision, I want to revisit the improvements we rejected on cost. Build enough to find out whether they help, measure the difference and account for supporting them. Some will still be bad investments. Others may finally be worth finishing.</p>

<p>Somewhere in almost every software team there is a ticket for the version everybody would prefer to use. I would like us to start opening those tickets again.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="mobile-development" /><category term="software-development" /><category term="agentic-engineering" /><category term="native-apps" /><summary type="html"><![CDATA[Shopify's return to native mobile development shows how coding agents change which improvements are worth the effort, from platform polish to products that previously never got built.]]></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">Limiting AI news would hide what is happening to software</title><link href="https://lord.technology/2026/09/11/ai-is-not-crowding-out-hacking.html" rel="alternate" type="text/html" title="Limiting AI news would hide what is happening to software" /><published>2026-09-11T16:45:00+01:00</published><updated>2026-09-11T16:45:00+01:00</updated><id>https://lord.technology/2026/09/11/ai-is-not-crowding-out-hacking</id><content type="html" xml:base="https://lord.technology/2026/09/11/ai-is-not-crowding-out-hacking.html"><![CDATA[<p>There is an <a href="https://news.ycombinator.com/item?id=49657850">Ask HN thread on the front page today</a> asking whether Hacker News can “please limit the AI news flood”. To be fair to its author, this is not a request to ban AI. The complaint is that AI stories take up so much of the front page that interesting hardware, open-source projects and ordinary programming work never escape the <code class="language-plaintext highlighter-rouge">newest</code> page. Attention is finite; one story surfacing means another one does not. Could Hacker News put its thumb on the scale and make room for the rest of technology again?</p>

<p>There is too much bad writing about AI. Every minor model release arrives with a benchmark selected by its maker, a launch post declaring a new era and fifty people reporting that it either replaced their engineering department before lunch or failed to count the letters in <em>strawberry</em>. The same three arguments consume the comments. I would happily read less of it.</p>

<p>Limiting AI stories is still the wrong fix.</p>

<p>AI is not a specialist interest taking attention away from software development. It is changing how software is made, what one developer can build, what users expect and which attacks our systems must survive. You do not need to believe in AGI, enjoy generated prose or want a chatbot in your toaster to recognise that. You only need to have used the tools seriously, or to employ somebody who has.</p>

<p>The flood is irritating because the change is large, uneven and happening in public. Filtering it out would produce a tidier front page and a worse account of the world.</p>

<h2 id="the-category-has-already-broken">The category has already broken</h2>

<p>The proposal assumes that “AI news” is a category like photography, databases or laptop cooling: useful to people who follow it, safely removable for everyone else. That category no longer holds.</p>

<p>A vulnerability found by an agent is security news. A browser redesigned around an agent is browser news. A chip built for inference is hardware news. A change in how a developer turns a requirement into running software is programming news. Which of these should be moved into the AI section so that technology can return?</p>

<p>The problem becomes more obvious in the thread’s own replies. People build AI classifiers to remove AI stories. Someone uses Gemini to repair a brittle regular expression intended to hide mentions of Gemini. A commenter objects that AI projects are not really DIY because they are “ways of getting something else to do it for you”, while another points out that this would also make a 3D printer rather suspect. The boundary keeps collapsing because the tool is no longer sitting beside the work. It is entering the way the work gets done.</p>

<p>The comparison with previous Hacker News obsessions only gets us so far. HN has been full of cryptocurrency, Rust, JavaScript frameworks, self-driving cars, SaaS and Apple launches before. Those subjects rose and fell. AI may also be overfunded and overreported, but unlike cryptocurrency it is a general-purpose input into other technical work. It writes Rust, operates browsers, searches codebases and triages support queues. Its failures now appear inside otherwise ordinary systems. Calling all of that “AI-adjacent” does not define a useful category. It defines most of the adjacency graph.</p>

<p>Asking a technology forum to cap that at ten or twenty per cent would be rather like asking one in 1998 to restrict Internet stories so there was still room for proper computers. It would have removed plenty of rubbish. It would also have hidden the fact that networking was becoming part of what a computer was.</p>

<h2 id="hacker-news-is-not-a-balanced-newspaper">Hacker News is not a balanced newspaper</h2>

<p>There is another assumption underneath the complaint: that the front page ought to represent the whole field in fair proportions. Some hardware, some languages, some operating systems, some small projects, and no one subject allowed to consume the issue.</p>

<p>That would be a perfectly reasonable editorial product. It is not what Hacker News is.</p>

<p>HN’s own <a href="https://news.ycombinator.com/newsguidelines.html">guidelines</a> reduce its subject matter to “anything that gratifies one’s intellectual curiosity”. Its front page is not a syllabus. It records what one particular technical community finds urgent enough to submit, discuss and upvote today, with ranking rules and moderators modifying the result. Sometimes that attention is badly allocated. Popularity is not merit. But a link aggregator that guarantees every beat a share of the page is no longer measuring collective attention; it is publishing a magazine.</p>

<p>The author wants overlooked work to be discoverable, which is reasonable. Reducing the representation of a subject other people currently consider important does not tell us which neglected stories deserve the vacant slots. It only guarantees that some lower-ranked non-AI stories receive them. A quota can manufacture variety. It cannot manufacture interest.</p>

<p>The two examples in the post make this awkward. One is a Lenovo proof of concept using solid-state cooling. The other is a promotional video for a set of devices that are not yet available. Both might be interesting; the cooling system interests me more than another funding round. But neither was necessarily denied a front-page discussion by AI. Commenters offer ordinary reasons for passing over them: scant technical detail, vaporware, a video instead of a substantial write-up, doubts about the company, and the fact that the cooling technology has appeared in products before. Those judgments may be wrong. They are still judgments about the submissions themselves.</p>

<p>“My interesting link did not rise” and “another subject prevented it from rising” are not the same claim. The second needs more evidence than the first.</p>

<h2 id="i-did-not-become-a-developer-to-preserve-typing">I did not become a developer to preserve typing</h2>

<p>One of the thread’s most revealing comments says: “I miss all the programming articles. It feels like everyone has given up with the very idea of ever writing code now.” The commenter sees the practice of making software being handed over to AI.</p>

<p>I understand the loss in that sentence. Programming is a satisfying craft. Holding a problem in your head, reducing it until the right abstraction appears and then making the machine obey is one of the best feelings in the job. I do not want a profession of people who prompt systems they do not understand, accept code they cannot review and call the result engineering. I have written before that <a href="/2026/01/31/what-becomes-expensive-when-code-becomes-cheap.html">code generation became cheap while owning code did not</a>, and that <a href="/2026/07/29/opus-5-gets-things-wrong-more-quietly.html">models can become more dangerous when they get things wrong more quietly</a>.</p>

<p>But I did not become a developer to preserve the act of entering syntax into a text editor. I became one because I like building things for people and solving problems for them. Code is usually the material, sometimes the obstacle, and never the user need.</p>

<p>If programming means producing code, an agent looks like an elaborate machine for taking programming away. If it means turning an ambiguous human need into a system that reliably meets it, an agent removes some implementation cost and leaves the hard part exposed. What is the actual problem? What must never happen? How will we know the answer is right? What will this cost to operate in three years? The model can help with those questions. It cannot be accountable for the answers.</p>

<p>Earlier this year I built <a href="/2026/05/21/the-military-aircraft-tracker-i-built-for-an-audience-of-one.html">a military aircraft tracker for an audience of one</a>. There is no LLM in the running product. I tried one for its daily summaries and removed it because deterministic templates were better. But a coding agent wrote much of the implementation under my direction. That leverage is why an evenings-and-weekends project grew an ingestion pipeline, queues, workflows, anomaly detection, replayable history and a usable interface before the old version would have made it past decoding the feed.</p>

<p>Was that less like hacking because I did not type every queue consumer? I think it was more like hacking. I found an itch, assembled tools, learnt the constraints, discarded AI where it made the product worse and used it heavily where it made the product possible. The important judgment was not loyalty to or rejection of the tool. It was knowing which problem belonged to it.</p>

<p>Blind AI enthusiasts mistake generation for understanding. At the other extreme, some developers have turned a justified dislike of the hype into a refusal to inspect the capability. Neither is especially technical. The job is to evaluate the thing in front of us: use it where it works, contain it where it is unreliable, and remove it where it does not help the user.</p>

<h2 id="slop-is-a-quality-problem-not-a-subject">Slop is a quality problem, not a subject</h2>

<p>The best case for intervention is that AI has made low-effort material extremely cheap to produce, and that material is consuming a system whose scarce resource is human attention. The label “AI story” is a bad way to identify it.</p>

<p>A person can repeat a press release, cherry-pick a benchmark and contribute nothing. A hand-written project can be useless. An AI-assisted one can solve a real problem and contain careful engineering. The production method is not the quality. “Slop” describes the distance between the confidence and volume of an artefact and the thought behind it, not whether a model touched the keyboard.</p>

<p>The thread demonstrates this neatly. Several developers have built sites that filter AI stories out of Hacker News; at least one uses an LLM to classify them. That is not hypocrisy. Fuzzy classification is exactly the sort of bounded, reversible task language models are useful for, and the developer shipped something people in the thread wanted. A filter made with AI to avoid reading about AI is still a product built for users. The user need decides whether it is worthwhile; ideological consistency does not.</p>

<p>Hacker News should be more aggressive about the properties it already cares about: originality, technical substance and intellectual curiosity. A model release that changes nothing, a generated essay with no firsthand evidence and a demo whose only feature is that a model produced it should struggle. So should their human-made equivalents. A careful account of a failed AI deployment or a developer showing exactly how a tool changed their work should survive. So should the cooling system and the open-source wall display, if the submitted material gives readers enough substance to engage with them.</p>

<p>Judge the work by what it reveals. “AI” is too blunt a proxy for that judgment.</p>

<h2 id="the-attention-problem-is-partly-us">The attention problem is partly us</h2>

<p>There is a more uncomfortable reason AI keeps swallowing the front page: even people who hate the subject cannot leave it alone.</p>

<p>They open the story to complain that it is there. They add the hundredth comment saying language models merely predict the next token. They call the project slop without running it, somebody responds with an extravagant claim about AGI, and both sides return for six rounds. A modest post about an unusual cooling system cannot compete with a subject that recruits its supporters and opponents into the same engagement loop.</p>

<p>No ranking change can entirely solve that because the flood is not only a supply problem. It is demand, including hostile demand. The Ask HN thread objecting to too much AI became one of the day’s largest AI discussions within hours. That is funny, but it is also the mechanism.</p>

<p>Personal filters are reasonable. If reading another model announcement makes your day worse, hide it. Use a third-party feed. Read Lobsters. Go directly to Hackaday for hardware. No single front page has ever owed us a complete view of an industry. Choosing several narrower sources is healthier than expecting one community to preserve the mixture of subjects we happened to like when we joined it.</p>

<p>What personal filtering should not become is institutional denial. There is a difference between “I do not want to spend my attention on this today” and “this community should behave as if the subject is less consequential than its members believe”. The first is curation. The second is distortion.</p>

<h2 id="look-harder-not-away">Look harder, not away</h2>

<p>I do not want more AI news merely because it is about AI. I want fewer launch posts, fewer benchmark victory laps, fewer wrappers presented as companies, fewer declarations that software engineering ended last Tuesday and fewer denunciations written by people whose last serious experiment with a coding model was asking it for a sorting function two years ago.</p>

<p>I want more evidence. Show me what the system made possible that was not possible before. Show me where it failed under real load. Show me the review burden, the changed threat model, the bill, the maintenance cost and what the users thought. Show me the code when code is the interesting part and the product when it is not.</p>

<p>Boosterism asks us to lower our standards because the future has arrived. I want higher standards because these systems are being deployed before they are understood, and will affect developers whether or not we enjoy reading about them.</p>

<p>AI is a massive part of development now. It is also full of hype, waste, brittle systems and people selling inevitability because they cannot yet sell a reliable product. Both are true. The answer to a noisy, important change is not to reserve fewer slots for it. It is to get better at distinguishing signal from noise.</p>

<p>Hacker News should make room for deeply interesting work wherever it appears. It should give overlooked submissions a second chance and punish repetitive, shallow material. But it should not decide in advance that the largest change to the practice of building software in decades has received its fair allocation of attention for the day.</p>

<p>I do not need to love AI to know that ignoring it would make me worse at building things for users. Believing everything its vendors say would too. The job is still the same: pay attention, test the claims and build something useful.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="ai" /><category term="hacker-news" /><category term="software-development" /><category term="agentic-engineering" /><summary type="html"><![CDATA[There is an Ask HN thread on the front page today asking whether Hacker News can “please limit the AI news flood”. To be fair to its author, this is not a request to ban AI. The complaint is that AI stories take up so much of the front page that interesting hardware, open-source projects and ordinary programming work never escape the newest page. Attention is finite; one story surfacing means another one does not. Could Hacker News put its thumb on the scale and make room for the rest of technology again?]]></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">Cloudflare doesn’t have AI psychosis. It has a thesis.</title><link href="https://lord.technology/2026/08/16/cloudflare-doesnt-have-ai-psychosis-it-has-a-thesis.html" rel="alternate" type="text/html" title="Cloudflare doesn’t have AI psychosis. It has a thesis." /><published>2026-08-16T09:00:00+01:00</published><updated>2026-08-16T09:00:00+01:00</updated><id>https://lord.technology/2026/08/16/cloudflare-doesnt-have-ai-psychosis-it-has-a-thesis</id><content type="html" xml:base="https://lord.technology/2026/08/16/cloudflare-doesnt-have-ai-psychosis-it-has-a-thesis.html"><![CDATA[<p>“I am not blaming the innovation. I am blaming the chaos of innovation. Everything feels DISJOINTED.” That’s the author of <a href="https://opensauce.it/cloudflare-ai-psychosis/">“Cloudflare’s AI psychosis”</a>, on <a href="https://news.ycombinator.com/item?id=49310719">Hacker News</a> this weekend, after the essay reached the front page. The essay itself is wider and angrier than that. Cloudflare used to be boring infrastructure run by engineers and is now a product-management organisation with a posting habit; too many overlapping primitives, still no proper Postgres, a developer experience bolted on as an afterthought, observability that never ships, more outages than ever, 1,100 people made redundant under an “agentic” banner. It opens by missing the old company, the one that “sat in front of your site, ate the attacks, cached the static stuff, did the DNS, and that’s it. No BS.” I agree with most of what it lists. I think the diagnosis is wrong, and I want to say why at some length, because the essay is being passed around as if the two were the same thing.</p>

<p>I work for a Cloudflare partner, I build on the Developer Platform most working days, and I <a href="https://architectingoncloudflare.com/">wrote a book about it</a> this year, independent and unendorsed, so discount accordingly. In my defence, the book has a chapter called <a href="https://architectingoncloudflare.com/chapter-24">When Not to Use Cloudflare</a>, and I’ll be quoting it against Cloudflare a few times, because several of the essay’s best points are ones I’d already conceded in print.</p>

<h2 id="the-dashboard-and-the-rest-of-it">The dashboard, and the rest of it</h2>

<p>If “developer experience” means the dashboard, then yes, it’s a mess, and I haven’t opened it in anger for about a year. yodon on the thread called it “the densest collection of UI anti-patterns known to man” and I’m not going to argue. The outage the essay leads with, the <a href="https://blog.cloudflare.com/deep-dive-into-cloudflares-sept-12-dashboard-and-api-outage/">12 September 2025 dashboard and API failure</a>, was the dashboard’s fault: a React <code class="language-plaintext highlighter-rouge">useEffect</code> with an object in its dependency array, recreated on every render, calling the Tenant Service API “many times during a single dashboard render instead of just once” until it fell over. A React hook took the control plane down for over an hour. The postmortem is candid about it.</p>

<p>The developer experience I actually use is a terminal, a config file and a runtime, and I think that part is the best local story of any serverless platform I’ve worked on. <code class="language-plaintext highlighter-rouge">wrangler dev</code> runs your code in <a href="https://github.com/cloudflare/workerd"><code class="language-plaintext highlighter-rouge">workerd</code></a>, built from the same source as the production runtime. To be fair to Lambda, <code class="language-plaintext highlighter-rouge">sam local</code> runs the real Lambda image too; what both simulate is the services around the runtime, and Miniflare’s stand-ins for KV and D1 and R2 and Queues are the vendor’s own and cover more of the platform. What Cloudflare has that Lambda doesn’t is one path: <code class="language-plaintext highlighter-rouge">wrangler deploy</code> is seconds, <code class="language-plaintext highlighter-rouge">wrangler rollback</code> is seconds, and there’s no fast-but-unsafe route sitting next to a slow-but-safe one. What’s left is the gap I spend most of <a href="https://architectingoncloudflare.com/chapter-05#the-simulation-boundary">Chapter 5</a> on: you can simulate the runtime but you cannot simulate the network. Local D1 answers in microseconds and production D1 in tens of milliseconds, and that difference causes more works-on-my-machine bugs on this platform than anything else. You can’t fix it in Wrangler.</p>

<p>Look at where the money went this year. In April Cloudflare started <a href="https://blog.cloudflare.com/cf-cli-local-explorer/">rebuilding the CLI</a> as <code class="language-plaintext highlighter-rouge">cf</code>, generated from one schema across nearly three thousand API operations. In June it <a href="https://www.cloudflare.com/press/press-releases/2026/cloudflare-acquires-voidzero-to-build-the-future-of-the-ai-native-web/">bought VoidZero</a>, Evan You’s company, the people behind Vite and Vitest, and You’s <a href="https://blog.cloudflare.com/voidzero-joins-cloudflare/">own post</a> says what for: “<code class="language-plaintext highlighter-rouge">cf dev</code> should be a superset of <code class="language-plaintext highlighter-rouge">vite dev</code>”. An acquisition is also an announcement, yes. It’s also a large cheque and a team, and you don’t spend either on an afterthought.</p>

<h2 id="one-animal-different-coats">One animal, different coats</h2>

<p>The essay’s central exhibit is storage. D1, Durable Object SQLite, KV, R2, Queues, Hyperdrive: “too many ways to do the same thing, none of them great”. They aren’t the same thing. Map them and you get a SQLite, an eventually consistent cache, an S3, an SQS and a connection pooler, and nobody calls AWS disjointed for having RDS, ElastiCache, S3, SQS and RDS Proxy. Hyperdrive is a marketing name, granted. So is Lambda. Cloudflare doesn’t have fewer products because it’s tidier; it has fewer because it offers less, no VMs, no Kubernetes, no GPUs by the hour. What it does have is one programming model. Four general-purpose ways to run code, on two substrates, V8 isolates and Linux containers, and everything that isn’t an isolate is fronted by a Durable Object, configured in the same file, deployed by the same command, reached through the same bindings. A Durable Object is a Worker with state. A Container is a Durable Object with a bigger body. A Dynamic Worker is a Worker whose code another Worker hands it at request time. D1 is a Durable Object you didn’t have to build. If you know what a Worker is, the rest isn’t a zoo. It’s one animal in different coats. The book calls it <a href="https://architectingoncloudflare.com/chapter-01#primitives-over-managed-services">unbundling</a> and is blunt about the cost: derived data needs explicit code, you build your auth instead of configuring it, and the first week feels like being handed a bag of parts. You might not want that trade. But it’s a design, not a symptom, and it’s been the design since KV in 2018.</p>

<p>The compute side is where the essay has a point. There is no single page that puts Workers, Dynamic Workers, Sandboxes and Containers next to each other and tells you which to reach for; I looked. That’s a real documentation failure, and Cloudflare more or less admitted it on 3 August by shipping <a href="https://blog.cloudflare.com/cloudflare-computer/"><code class="language-plaintext highlighter-rouge">@cloudflare/computer</code></a>, which hands the model a single <code class="language-plaintext highlighter-rouge">exec</code> tool and lets it choose between a shell inside an isolate and a real container, so that you don’t have to. That is exactly the pattern the essay is complaining about. Look at who wrote the newest layer, though. Dynamic Workers and Code Mode came out of a <a href="https://blog.cloudflare.com/code-mode/">September 2025 post</a> by Kenton Varda and Sunil Pai; Varda designed the Workers runtime and is the one engineer the essay names approvingly. If product managers have taken the pen from the infrastructure engineers, it’s odd that the infrastructure engineer keeps writing the new things.</p>

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

<p>The Postgres point is the strongest one in the essay, and it’s true. There is no first-class Cloudflare-run PostgreSQL. I said so in <a href="https://architectingoncloudflare.com/chapter-12#the-decision-d1-hyperdrive-or-something-else">Chapter 12</a>: “A native serverless PostgreSQL offering would fill an obvious gap.” The closest thing is PlanetScale. In April Cloudflare <a href="https://blog.cloudflare.com/deploy-planetscale-postgres-with-workers/">wired PlanetScale Postgres into Workers</a> through Hyperdrive, and since <a href="https://developers.cloudflare.com/changelog/post/2026-06-18-planetscale-databases-cloudflare-billing/">18 June</a> you can create one from the Cloudflare dashboard and it lands on your Cloudflare invoice at PlanetScale’s prices. You get Cloudflare billing and Cloudflare wiring; the database is still a PlanetScale database in a PlanetScale region.</p>

<p>The essay reads Hyperdrive as an admission that Cloudflare never built the database serious apps want. I read it differently. A managed Postgres is the one product that would contradict the platform’s own architecture, and they haven’t built it. Varda, <a href="https://blog.cloudflare.com/sqlite-in-durable-objects/">announcing SQLite in Durable Objects</a> in 2024: “Traditional cloud architecture favors large distributed databases that live separately from application servers.” In <a href="https://blog.cloudflare.com/introducing-workers-durable-objects/">2020</a>, Durable Objects were “the missing piece in the Workers stack that makes it possible for whole applications to run entirely on the edge, with no centralized ‘origin’ server at all.” A managed Postgres in one region is an origin, and the platform was founded on the idea that the origin is the problem. I’ve overstated that idea myself. For most SaaS the origin isn’t the problem; the origin is where the customers are, users cluster in one to three regions, reads dominate, and a replica handles the read path. Hyperdrive is a pooler and a read cache in three hundred cities. It pays the connection handshakes once; every query still crosses the ocean, writes always do, and the cache is time-based, so the fast reads are the ones that might be stale. What it buys is that a Worker at the edge talks to a regional Postgres at roughly the cost a regional Lambda would, so the work that belongs at the edge can happen before or instead of the query. In the book I call that <a href="https://architectingoncloudflare.com/chapter-14#hyperdrive-as-architecture-not-just-bridge">a permanent architecture rather than a bridge</a>, and I still think that, but it’s a claim about the topology being reasonable, not about latency going away.</p>

<p>The real difference isn’t that Cloudflare distributes data and the hyperscalers don’t. Aurora Global Database, DynamoDB Global Tables and DSQL distribute data fine, across a few dozen regions, by configuration. Cloudflare partitions it by key and moves the code to the partition, per object, across a few hundred cities. A Durable Object is a single writer in a single place with its SQLite in the same thread as the code, wonderful for a chat room or a per-user agent and useless for an ad-hoc join across tenants. D1 has an origin too, a primary in one location with read replicas behind it. So it depends what you mean by Postgres. If you mean SQL, you get D1, fifty thousand databases by default, one per tenant, 10 GB each, and you pay for that in fleet migrations and cross-tenant reporting you write yourself. If you mean Postgres, the extensions and pgvector and twenty years of tooling, you keep it where it lives and put Hyperdrive in front. Neither is the “first-class managed PostgreSQL that feels native” the essay asks for, and the <a href="https://architectingoncloudflare.com/chapter-24#red-flags-when-to-look-elsewhere">red flags</a> chapter says plainly that if your data model assumes a single large database you should use Hyperdrive or go somewhere else, because “Cloudflare isn’t a general-purpose cloud. It’s a specific bet on a specific model.”</p>

<p>Here’s the awkward part. I’d bet on a Cloudflare-run Postgres arriving. They bought <a href="https://blog.cloudflare.com/cloudflare-acquires-outerbase-database-dx/">Outerbase</a> for the database experience, they put PlanetScale on the invoice, and it isn’t hard to see where that goes. That’s a guess from the public record; every source is linked and I have no inside knowledge. You can’t believe both that “no origin” is doctrine and that they’re about to ship one, so one of those is posture, and I think it’s the first. “No origin” was a preference the platform could hold while partners met the demand, and PlanetScale on the Cloudflare invoice is that preference already bending. If they build their own, the essay gets to say it told me so. I don’t think it’ll look like RDS when it comes; I think it’ll be many small ones near the code, because that’s the bet, and the bet is what you’re buying when you buy Cloudflare. And if “feels native” means what I think it means, that’s the database the essay is asking for as well. We want the same thing. Where we differ is whether not having it yet means the company has lost its mind.</p>

<p>Ryan Dahl, who is building a competitor to it, shipped <a href="https://celld.dev/">celld</a> this week, a self-hosted Durable Objects clone on S3, and called the model “one of the best primitives distributed systems has been handed in years”. That cuts against me too: the primitive is right and Cloudflare’s terms for it, the price and the lock-in, are what people actually object to. That’s the argument I’d rather be having. It’s a better one than psychosis.</p>

<h2 id="0x-with-an-operating-system-on-top">0.x with an operating system on top</h2>

<p>The agents section lists Agents SDK, Flue, Project Think and Cloudflare OS as “another harness or framework instead of finishing the one they already have”. Cloudflare’s own <a href="https://blog.cloudflare.com/agents-platform-flue-sdk/">Flue announcement</a> sets out the layering: Flue is a framework, Project Think and Pi are harnesses, “the agentic loop”, and the Agents SDK is “the compute, state, and storage primitives everything above depends on”. Flue came from the Astro team, who <a href="https://astro.build/blog/joining-cloudflare/">joined Cloudflare</a> in January; it grew out of the <a href="https://blog.cloudflare.com/astro-issue-triage/">triage pipeline</a> that took Astro’s own open issues from over two hundred to about thirty. Cloudflare OS, which I spent <a href="https://lord.technology/2026/08/05/cloudflare-os-is-an-architecture-of-distrust.html">last week reading</a>, is an application built on all of that. One runtime with things stacked on it, not four harnesses. None of that answers the actual complaint, though. The SDK everything depends on is still on version 0.x eighteen months after launch. Think is labelled experimental. The SDK, the Agents dashboard that arrived on 4 August, and Agents Week, which has now happened twice this year, all share a name. A tidy diagram doesn’t make the base reliable, and I’d rather have a 1.0 of the SDK than another thing on top of it. That part of the essay is right.</p>

<p>Some of the rest was out of date by the time it was published. AI Search “lags proper RAG platforms … on quality, filtering, hybrid search”: <a href="https://developers.cloudflare.com/ai-search/configuration/indexing/hybrid-search/">hybrid search</a> shipped on 16 April, <a href="https://developers.cloudflare.com/changelog/post/2026-03-23-custom-metadata-filtering/">custom metadata filtering</a> on 23 March, reranking last October. What’s left is five metadata fields, one reranker, and a product still in open beta with billing <a href="https://blog.cloudflare.com/ai-search-easier/">not switched on</a> a year and a half in, which makes it an unpriced dependency; I’d keep it out of the critical path until it has a price. The docs ship without “even basic SKILL.md stuff for agents”: the <a href="https://github.com/cloudflare/skills">cloudflare/skills</a> repository has been up since December, next to an <a href="https://developers.cloudflare.com/llms.txt">llms.txt</a> and a docs MCP server from May 2025. The docs complaint that does stick is the Matrix post. In January a Cloudflare TPM published a <a href="https://www.thestack.technology/cloudflare-matrix-blog-ai-assisted-vibe-coding/">personal project</a> on the company blog as a “serverless, post-quantum Matrix homeserver”, and Matrix developers found the signature checks were <code class="language-plaintext highlighter-rouge">TODO</code>s and the README said production-grade; <a href="https://matrix.org/blog/2026/01/28/matrix-on-cloudflare-workers/">Matthew Hodgson</a>: “the code doesn’t yet implement any of Matrix’s core features which allow you to federate safely, and so doesn’t yet constitute a functional Matrix server”. Cloudflare added a proof-of-concept note the same day. That’s embarrassing for the blog, and the tracing docs carried a billing start date that had already passed for months, so docs rot is a fair charge, and so is the narrower one that new products arrive without versioned reference material. Docs-for-agents being absent isn’t. Workers AI does trail on speed: when I checked on 15 August, <a href="https://artificialanalysis.ai/models/kimi-k2-6/providers">Artificial Analysis</a> had Cloudflare well behind Fireworks and Baseten on throughput for Kimi K2.6, and the book says flatly that these aren’t the best models available and that edge inference “optimises the rounding error”. But the essay’s line that this forces “a lot of teams to send the hard inference somewhere else and treat Cloudflare as plumbing again” is meant as a dig, and it’s what the product is for. On the day the essay was published, Cloudflare <a href="https://blog.cloudflare.com/workers-ai-gateway-unification/">merged Workers AI into AI Gateway</a>: one wallet, spend it on OpenAI or Anthropic or their own GPUs, <a href="https://developers.cloudflare.com/ai-gateway/features/unified-billing/">five per cent on top</a>. Running an agent on Cloudflare means holding its state, sandboxing its code and surviving its restarts. It has never meant running the frontier model.</p>

<h2 id="where-the-essay-is-right">Where the essay is right</h2>

<p>Observability. Workers tracing has carried a beta badge since <a href="https://blog.cloudflare.com/workers-tracing-now-in-open-beta/">October 2025</a>, and the <a href="https://developers.cloudflare.com/workers/observability/traces/known-limitations/">known limitations page</a> says the three things the essay says: some spans report zero milliseconds because the runtime doesn’t advance the clock between I/O events, a Spectre mitigation; trace IDs “are not propagated to services outside of Cloudflare”; span attributes are incomplete. Cross-binding propagation was fixed in May, custom spans in June, local tracing this month, so it’s moving, but ten months is a long open beta for the thing you use to find out why production is broken. <a href="https://architectingoncloudflare.com/chapter-20#hyperscaler-comparison">Chapter 20</a> says the same as the essay in politer language, “where Cloudflare still trails is full APM instrumentation”, which spelled out means no service map, no SLO objects, no alarms on custom dimensions without building them yourself, so what you’d actually compare is Cloudflare plus Honeycomb or Datadog against CloudWatch and X-Ray on their own. If you’re on Workers and reading this to decide whether to leave: don’t, but stop waiting for the beta badges to come off and ship your traces out through the OTLP export now. The 1% sampling bug on paid accounts the essay cites I couldn’t verify either way, because the source is behind a bot wall. The community thread I could read, an account on what looks like the Free plan whose <a href="https://community.cloudflare.com/t/workers-observability-logs-most-logs-not-appearing-in-dashboard-since-march-10/904412">logs vanished from the dashboard</a> in March while <code class="language-plaintext highlighter-rouge">wrangler tail</code> kept showing them, has zero replies. Zero. That’s the bit that stings, and it isn’t unrelated to what happened in May.</p>

<p>The volunteer Community Champions <a href="https://shoftech.com/question/cloudflare-community-champions-update/">said in May</a> that Cloudflare had let go of many of its community team, that they’d lost their contacts inside the company, and that the programme was dissolved without a clear reason. Cloudflare hasn’t said so itself, but the replacement, announced the same day as the essay, <a href="https://blog.cloudflare.com/community-program-refresh/">says of itself</a> that it is “not about being on hand to perform moderation and admin tasks” because they’re building automation to do that “with far less human intervention”. An unanswered thread is what that looks like from the outside. That one made me angry, and I don’t get angry at Cloudflare much.</p>

<p>And the redundancies are real. More than 1,100 people on 7 May, about a fifth of the company. The <a href="https://www.sec.gov/Archives/edgar/data/1477333/000147733326000033/cloud-20260507.htm">8-K</a> calls it a plan “to further accelerate its evolution to an agentic AI-first operating model”. That phrase is Cloudflare’s, not the essay’s. It’s grim. Matthew Prince’s defence in <a href="https://fortune.com/2026/05/21/cloudflare-ceo-matthew-prince-layoffs-ai-automation-measurers/">Fortune</a> was that “the vast majority of those we laid off last week were measurers”, his word for middle management, finance, legal and audit. I have no way to know whether that’s true, and neither does the essay. What I can check is the talent-drain claim, and it’s one name: Kate Reznykova, an engineering manager on the Agents and Sandboxes team, <a href="https://www.sdxcentral.com/news/openai-strengthens-web-infrastructure-team-with-cloudflare-hire/">went to OpenAI</a> in July, the one departure the essay could actually have cited. I couldn’t find anyone who went to Anthropic. Varda is still there and shipped Dynamic Workers and Cloudflare OS this year. The stock fell 24% the next day, on the same call as the earnings, so whatever the cuts were for, the market didn’t read them as a gift.</p>

<h2 id="what-fell-over">What fell over</h2>

<p>On reliability I have to be careful, because the essay’s own line is that “the core network, reliability, and simplicity that made Cloudflare different get less consistent attention”, and the two big outages of 2025 were in the core network. So the essay gets to say the boring layer fell over. It did. On <a href="https://blog.cloudflare.com/18-november-2025-outage/">18 November</a> a ClickHouse permissions change made the Bot Management feature file more than double in size, past a hard-coded limit, and the Rust proxy hit an <code class="language-plaintext highlighter-rouge">unwrap()</code> and panicked across the network for about three hours; Prince called it “Cloudflare’s worst outage since 2019” and apologised “for the pain we caused the Internet”. On <a href="https://blog.cloudflare.com/5-december-2025-outage/">5 December</a> a WAF change tripped a global kill switch and the older Lua proxy threw a nil error for 25 minutes across 28% of HTTP traffic. Their own words: “how closely they are clustered together” is “not acceptable for a network like ours”. No argument from me. The same autumn took out us-east-1 for about fifteen hours and Azure Front Door for about eight, both from automated configuration changes with too little staging, so the boring cloud that doesn’t fall over isn’t on offer anywhere. The difference, and it’s the essay’s strongest card, is that those were regional. Cloudflare’s are global by design.</p>

<p>The cause is where I disagree. Neither November nor December was a new failure mode that arrived with the AI products. They were the same class as Cloudflare’s oldest one: something propagated to every machine on earth in seconds, with no staged rollout, and a proxy that fell over hard on the result. That’s how the <a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/">July 2019 outage</a> happened, a bad WAF regex pushed globally, in the boring era the essay misses, and that postmortem names the gap in one sentence: “The SOP for a rule change specifically allows it to be pushed globally. This is very different from all the software we release at Cloudflare”. Cloudflare’s own Fail Small post says of the 2025 pair that “both outages followed a similar pattern. In the moments leading up to each incident we instantaneously deployed a configuration change in our data centers in hundreds of cities around the world.” They promised staged rollouts for WAF rules in 2019. Nobody widened the promise to feature files and kill switches until it hurt. It’s the failure mode I warn readers about in <a href="https://architectingoncloudflare.com/chapter-02#the-global-blast-radius">Chapter 2</a>: the property that makes a global deploy valuable is the property that makes a global mistake instant. If attention drifted, and I think the clustering says it did, it drifted from a discipline the company had already learned once, in one place, and had to relearn everywhere.</p>

<p>And relearn it they did, in the least exciting engineering Cloudflare has published in years. <a href="https://blog.cloudflare.com/fail-small-resilience-plan/">Code Orange: Fail Small</a> in December committed to “controlled rollouts for any configuration change that is propagated to the network, just like we do today for software binary releases”, which is the 2019 sentence with the fix applied, and the <a href="https://blog.cloudflare.com/code-orange-fail-small-complete/">completion post</a> on 1 May reports health-mediated config rollout on most production systems, a break-glass drill with over two hundred people, and a Rust rule that reads, in full, “Do not use <code class="language-plaintext highlighter-rouge">.unwrap()</code> outside of tests and <code class="language-plaintext highlighter-rouge">build.rs</code>.” Companies optimising for announcement cadence don’t publish that rule, and if you want the writing about hard trade-offs that the essay says Cloudflare no longer does, the postmortems are it. That’s a company that got frightened in November and spent the winter on rollout discipline. Whether it stays frightened I can’t tell from the public record.</p>

<p>I’ve now spent a chapter and three thousand words explaining why the missing Postgres is doctrine. I’d still like the database.</p>]]></content><author><name>Jamie Lord</name><email>jamie@lord.technology</email></author><category term="cloudflare" /><category term="cloudflare" /><category term="architecture" /><category term="workers" /><category term="agents" /><summary type="html"><![CDATA[“I am not blaming the innovation. I am blaming the chaos of innovation. Everything feels DISJOINTED.” That’s the author of “Cloudflare’s AI psychosis”, on Hacker News this weekend, after the essay reached the front page. The essay itself is wider and angrier than that. Cloudflare used to be boring infrastructure run by engineers and is now a product-management organisation with a posting habit; too many overlapping primitives, still no proper Postgres, a developer experience bolted on as an afterthought, observability that never ships, more outages than ever, 1,100 people made redundant under an “agentic” banner. It opens by missing the old company, the one that “sat in front of your site, ate the attacks, cached the static stuff, did the DNS, and that’s it. No BS.” I agree with most of what it lists. I think the diagnosis is wrong, and I want to say why at some length, because the essay is being passed around as if the two were the same thing.]]></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">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></feed>