<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Kellerstein</title><description>Notes on AI agents, platform engineering, and running things on hardware I own.</description><link>https://blog.kellerstein.org/</link><item><title>Hello, world</title><link>https://blog.kellerstein.org/blog/hello-world/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/hello-world/</guid><description>Placeholder post — the blog is live, real articles land here next.</description><pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate></item><item><title>Formatting reference</title><link>https://blog.kellerstein.org/blog/formatting-reference/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/formatting-reference/</guid><description>Example post exercising every Markdown element the theme styles.</description><pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate></item><item><title>Drag a div, get a diff</title><link>https://blog.kellerstein.org/blog/drag-a-div-get-a-diff/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/drag-a-div-get-a-diff/</guid><description>VEX turns browser gestures into source-code changes. Three hard problems hide in that sentence — here is what each one taught me.</description><pubDate>Tue, 14 Jul 2026 08:29:44 GMT</pubDate></item><item><title>It works from the terminal</title><link>https://blog.kellerstein.org/blog/it-works-from-the-terminal/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/it-works-from-the-terminal/</guid><description>The app ran perfectly when I launched it from a shell and failed with ENOENT when a user double-clicked it. A GUI app does not have your PATH, and the only thing that knows your PATH is your shell.</description><pubDate>Sun, 21 Jun 2026 13:12:32 GMT</pubDate></item><item><title>Six hundred lines or it does not ship</title><link>https://blog.kellerstein.org/blog/six-hundred-lines-or-it-does-not-ship/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/six-hundred-lines-or-it-does-not-ship/</guid><description>A 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.</description><pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate></item><item><title>I built a time machine, then deleted half of it</title><link>https://blog.kellerstein.org/blog/i-built-a-time-machine-then-deleted-half-of-it/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/i-built-a-time-machine-then-deleted-half-of-it/</guid><description>Four timeline verbs, parallel variants in git worktrees, a record mode and five branch families. Two cleanup specs removed almost all of it — including, awkwardly, the feature whose existence justified the first round of deletions.</description><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate></item><item><title>Three counters, three answers</title><link>https://blog.kellerstein.org/blog/three-counters-three-answers/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/three-counters-three-answers/</guid><description>One Stop click produced a UI, a state file and a git history that disagreed with each other three different ways. None of them was wrong. The reconciliation point that should have caught it was a line in a spec that said &quot;details TBD in implementation&quot;.</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate></item><item><title>Your test suite bills by the token</title><link>https://blog.kellerstein.org/blog/your-test-suite-bills-by-the-token/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/your-test-suite-bills-by-the-token/</guid><description>Twenty 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.</description><pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate></item><item><title>Nine stages, nine amnesiacs</title><link>https://blog.kellerstein.org/blog/nine-stages-nine-amnesiacs/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/nine-stages-nine-amnesiacs/</guid><description>Dex builds a project unattended by making sure no agent ever remembers anything. State travels through the filesystem instead — which works beautifully for artifacts and catastrophically for decisions.</description><pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate></item><item><title>The agent spawned an agent and I could not see it</title><link>https://blog.kellerstein.org/blog/the-agent-spawned-an-agent-and-i-could-not-see-it/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/the-agent-spawned-an-agent-and-i-could-not-see-it/</guid><description>A subagent is a black box that spends your money. Making it inspectable took no new instrumentation at all — the events were already firing, into nothing.</description><pubDate>Tue, 14 Apr 2026 23:45:19 GMT</pubDate></item><item><title>Six polling loops and a spinning fan</title><link>https://blog.kellerstein.org/blog/six-polling-loops-and-a-spinning-fan/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/six-polling-loops-and-a-spinning-fan/</guid><description>VEX was idle and my laptop was audible. The fix was not &quot;poll slower&quot; — it was noticing that a UI which asks &quot;anything new?&quot; sixty times a minute is a UI with no idea what happened.</description><pubDate>Tue, 07 Apr 2026 17:11:56 GMT</pubDate></item><item><title>The field that was never populated</title><link>https://blog.kellerstein.org/blog/the-field-that-was-never-populated/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/the-field-that-was-never-populated/</guid><description>Continuing a conversation with an agent that already finished turned out to be one line of SDK config and three days of admitting my data model thought agents were disposable.</description><pubDate>Sun, 05 Apr 2026 19:56:25 GMT</pubDate></item><item><title>Five months, two repos, one lesson: the model was the easy part</title><link>https://blog.kellerstein.org/blog/the-model-was-the-easy-part/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/the-model-was-the-easy-part/</guid><description>A retrospective on OpenOperator. What I would keep, what I would redo, and why a commit called &quot;remove hardcoded API keys&quot; landing a year late is the most honest thing in the history.</description><pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate></item><item><title>Benchmarking AI agents: node pools, job queues, and cost per step</title><link>https://blog.kellerstein.org/blog/benchmarking-ai-agents-at-scale/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/benchmarking-ai-agents-at-scale/</guid><description>Five 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.</description><pubDate>Wed, 04 Jun 2025 00:00:00 GMT</pubDate></item><item><title>One proxy pod per VM does not scale</title><link>https://blog.kellerstein.org/blog/one-proxy-pod-per-vm/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/one-proxy-pod-per-vm/</guid><description>A 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.</description><pubDate>Thu, 01 May 2025 00:00:00 GMT</pubDate></item><item><title>Streaming helm upgrade to a browser</title><link>https://blog.kellerstein.org/blog/streaming-helm-to-a-browser/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/streaming-helm-to-a-browser/</guid><description>Provisioning 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.</description><pubDate>Wed, 30 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Forty minutes to ninety seconds: VolumeSnapshots as golden images for VMs</title><link>https://blog.kellerstein.org/blog/volumesnapshots-as-golden-images/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/volumesnapshots-as-golden-images/</guid><description>One 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.</description><pubDate>Tue, 22 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Decoding Microsoft Bond: reading an app’s own telemetry through mitmproxy</title><link>https://blog.kellerstein.org/blog/reading-teams-telemetry-microsoft-bond/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/reading-teams-telemetry-microsoft-bond/</guid><description>Ground 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.</description><pubDate>Sun, 20 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Shipping a 6 GB ISO to every pod (and then deleting the storage key)</title><link>https://blog.kellerstein.org/blog/shipping-a-6gb-iso-to-every-pod/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/shipping-a-6gb-iso-to-every-pod/</guid><description>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.</description><pubDate>Wed, 16 Apr 2025 00:00:00 GMT</pubDate></item><item><title>Nested virtualisation on AKS: yes, you can run KVM in a pod</title><link>https://blog.kellerstein.org/blog/kvm-in-a-kubernetes-pod/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/kvm-in-a-kubernetes-pod/</guid><description>hostPath /dev/kvm, privileged: true, and the Deployment→StatefulSet migration. Plus the annotation that stops the autoscaler evicting a forty-minute Windows install.</description><pubDate>Tue, 08 Apr 2025 00:00:00 GMT</pubDate></item><item><title>MCP for mouse and keyboard: a desktop as a tool server</title><link>https://blog.kellerstein.org/blog/mcp-for-mouse-and-keyboard/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/mcp-for-mouse-and-keyboard/</guid><description>Six 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.</description><pubDate>Fri, 28 Mar 2025 00:00:00 GMT</pubDate></item><item><title>&quot;It looked like it worked&quot;: grading a non-deterministic agent</title><link>https://blog.kellerstein.org/blog/it-looked-like-it-worked/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/it-looked-like-it-worked/</guid><description>The 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.</description><pubDate>Wed, 26 Mar 2025 00:00:00 GMT</pubDate></item><item><title>Tasks as config, not code</title><link>https://blog.kellerstein.org/blog/tasks-as-config-not-code/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/tasks-as-config-not-code/</guid><description>A 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.</description><pubDate>Tue, 25 Mar 2025 00:00:00 GMT</pubDate></item><item><title>Four agents in four weeks: from AutoGen to a hand-rolled plan-and-solve loop</title><link>https://blog.kellerstein.org/blog/four-agents-in-four-weeks/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/four-agents-in-four-weeks/</guid><description>The 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.</description><pubDate>Sun, 23 Mar 2025 00:00:00 GMT</pubDate></item><item><title>The bootstrap from hell: provisioning a Windows guest you cannot SSH into</title><link>https://blog.kellerstein.org/blog/bootstrapping-a-windows-guest/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/bootstrapping-a-windows-guest/</guid><description>No 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.</description><pubDate>Fri, 21 Mar 2025 00:00:00 GMT</pubDate></item><item><title>Reading the screen: OmniParser as a service</title><link>https://blog.kellerstein.org/blog/omniparser-as-a-service/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/omniparser-as-a-service/</guid><description>Turning 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.</description><pubDate>Mon, 17 Mar 2025 00:00:00 GMT</pubDate></item><item><title>We tried every vision model we could get our hands on</title><link>https://blog.kellerstein.org/blog/every-vision-model-we-could-get/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/every-vision-model-we-could-get/</guid><description>Magma, 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.</description><pubDate>Fri, 07 Mar 2025 00:00:00 GMT</pubDate></item><item><title>You cannot debug an agent from logs</title><link>https://blog.kellerstein.org/blog/watching-the-robot-work/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/watching-the-robot-work/</guid><description>The 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.</description><pubDate>Tue, 04 Mar 2025 00:00:00 GMT</pubDate></item><item><title>QEMU in Docker: a real Windows 11 VM as a container</title><link>https://blog.kellerstein.org/blog/qemu-in-docker-a-real-windows-vm/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/qemu-in-docker-a-real-windows-vm/</guid><description>It 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.</description><pubDate>Mon, 24 Feb 2025 00:00:00 GMT</pubDate></item><item><title>The API is the screen</title><link>https://blog.kellerstein.org/blog/the-api-is-the-screen/</link><guid isPermaLink="true">https://blog.kellerstein.org/blog/the-api-is-the-screen/</guid><description>Why we built an agent that uses Microsoft Teams the way a person does — and why the model turned out to be the easy part.</description><pubDate>Sat, 22 Feb 2025 00:00:00 GMT</pubDate></item></channel></rss>