Writing
34 posts · oldest Feb 2025
- Six hundred lines or it does not shipA 2,313-line orchestrator with a 1,073-line function is maintainable by a human with an IDE and unmaintainable by an agent. The refactor whose acceptance criterion was an agent behaviour, the CI guard that enforced it — and the fact that the guard is red as I write this.agentsarchitecturerefactoring10 min
- I built a time machine, then deleted half of itA retrospective on the deletions. Four timeline verbs, parallel variants in git worktrees, a record mode and four branch families — two cleanup specs removed almost all of it, including, awkwardly, the feature whose existence justified the first round.gitproductarchitecture10 min
- Driving the Agent SDK: permissions, hooks and capsA stage is one query() call. The five options that define what an autonomous agent is allowed to do, the four hooks that make an unattended run watchable, and an honest account of what bypassPermissions actually means.agentsaiarchitecture8 min
- One authority, three counters: deriving state from git refsNaming a source of truth is the easy half. The hard half is naming the moment every other view gets rebuilt from it — and the run where a UI, a state file and a git history gave three different answers to "how much of this is built".agentsdebuggingarchitecture9 min
- Git as the databaseEvery stage commits, the run is reconstructable from refs alone, and the app owns exactly two branch families. Why an autonomous builder should store its work in the versioning system its users already have — and what that choice costs at review time.gitarchitectureagents9 min
- Your test suite bills by the tokenTwenty minutes and real dollars to verify a two-line UI change. A pluggable agent backend, a mock that refuses to improvise, and checkpoint replay took it to sixty seconds and zero — plus an honest account of what the mock does not buy you.agentstestingarchitecture9 min
- Structured handoffs, and what the model is still allowed to decideWhen one agent hands work to the next, prose is the wire protocol — and a catastrophically bad one. The manifest that made feature selection cost zero tokens, and the line between what a schema pins down and what genuinely needs judgement.agentsaiarchitecture8 min
- Nine stages, nine amnesiacs: context isolation as an architectureDex never lets a session get long enough to rot. Every stage is a brand new agent with an empty context window, state travels through the filesystem, and the unit of everything — execution, resume, storage, the UI — is the stage. Including what that costs.agentsaiarchitecture9 min
- Three pillars, and what each one is missingDex is not a new idea. It is three existing ideas — a bash loop, a spec workflow, and an SDK — each of which is most of an autonomous coding system and none of which is all of it. The interesting part is the shape of the holes.agentsaiarchitecture9 min
- Five months, two repos, one lesson: the model was the easy partA retrospective on OpenOperator. What I would keep, what I would redo, and why a commit called "remove hardcoded API keys" landing a year late is the most honest thing in the history.agentsinfraretrospective6 min
- Benchmarking AI agents: node pools, job queues, and cost per stepFive workload classes with five different scaling shapes, a bounded queue that fans tests into Kubernetes Jobs, and the reason your autoscaler makes terrible decisions about 30 GB virtual machines.kubernetesterraformazureobservability7 min
- One proxy pod per VM does not scaleA design that is obviously right at n=1 and obviously wrong at n=20, with no warning in between. The commit that deleted it is the best one in the repository.kubernetestraefikarchitectureinfra6 min
- Streaming helm upgrade to a browserProvisioning a VM takes three minutes. A spinner is not an acceptable answer. An async generator, a path-keyed WebSocket relay, and one design decision I would not repeat.kubernetespythonfastapiarchitecture7 min
- Forty minutes to ninety seconds: VolumeSnapshots as golden images for VMsOne Helm chart, two completely different storage topologies behind a single boolean. Plus the two bugs it cost — a StatefulSet naming convention and a substring match that matched too much.kubernetesazurehelminfra7 min
- Decoding Microsoft Bond: reading an app’s own telemetry through mitmproxyGround truth from an application with no test hooks. mitmproxy local mode against a single process, a hand-written Bond Compact Binary decoder, and the one-line AKS bug that killed a day.mitmproxyreverse-engineeringtestingpython8 min
- Shipping a 6 GB ISO to every pod (and then deleting the storage key)An initContainer that pulls once, one PVC projected into eleven mount points via subPath, and a three-month migration from a storage key to workload identity.kubernetesazuresecurityinfra7 min
- Nested virtualisation on AKS: yes, you can run KVM in a podhostPath /dev/kvm, privileged: true, and the Deployment→StatefulSet migration. Plus the annotation that stops the autoscaler evicting a forty-minute Windows install.kubernetesazureqemuinfra7 min
- MCP for mouse and keyboard: a desktop as a tool serverSix tools, one resource, and a design decision I still think is underrated — the screenshot is not a tool, it is a resource. Plus the reason we composite a cursor into every capture.mcpagentspython7 min
- "It looked like it worked": grading a non-deterministic agentThe least trustworthy signal in the system is the agent reporting success. Here is the evaluator we built instead — and the four-word commit that forced a whole second repository into existence.agentstestingevaluation7 min
- Tasks as config, not codeA JSON scenario format with lifecycle hooks, so an agent test starts from the same desktop every time — and so the person writing the test does not have to be the person who wrote the agent.agentstestingarchitecture7 min
- Four agents in four weeks: from AutoGen to a hand-rolled plan-and-solve loopThe old_agents/ directory still holds all the corpses. What each generation got wrong, and why most of a computer-use agent is not acting — it is checking whether the last action worked.agentsaiarchitecture8 min
- The bootstrap from hell: provisioning a Windows guest you cannot SSH intoNo SSH, no cloud-init, no config management. Just a .bat file, an SMB share the hypervisor provides, and one Task Scheduler flag that decides whether your screenshots are black.windowsdockerinfraautomation9 min
- Reading the screen: OmniParser as a serviceTurning a screenshot into a numbered list of clickable things — YOLOv8 for detection, Florence-2 for captions, OCR for text. And why it had to be a server, not a library.aiagentspython6 min
- We tried every vision model we could get our hands onMagma, Llama 3.2 Vision, Gemma 3, Phi-4, GPT-4o, Claude — including feeding a screen recording instead of stills. What actually moved the needle was not the model.aiagentsmodels5 min
- You cannot debug an agent from logsThe day we put noVNC in front of the guest, our mean time to diagnosis dropped by an order of magnitude. Failures in computer use are visual.agentsdebugginginfra4 min
- QEMU in Docker: a real Windows 11 VM as a containerIt is not Windows in a container. It is QEMU in a container with a Windows ISO and an unattended answer file — and the difference is three lines of compose.yml.dockerqemuwindowsinfra7 min
- The API is the screenWhy we built an agent that uses Microsoft Teams the way a person does — and why the model turned out to be the easy part.agentsaiinfra7 min