Notes on .NET, XAF, and building things
Twenty years of XPO, application frameworks, and lately a lot of applied AI. 319 articles and counting.
Browse by topic
All topics →Latest articles
View all →
NPU vs CPU, Same Model, Same Machine: I Tried to Benchmark It, and the Result Surprised Me
The plan was clean: run the same model on the same machine on the NPU and on the CPU, and show the speedup. I got a result — it just wasn't the one I planned. The NPU is real and reachable, Foundry Local loads QNN models onto the Hexagon, but the shipping NPU build errors on the very first attention layer of every prompt, in a layer type every modern small model shares. This is what NPU LLM inference on Windows-on-ARM actually looks like right now. Part 3 of 3.

The Cheapest 3× Speedup: Stop Sending Your Local Model Verbose JSON
Before I moved my local automation brain onto the NPU, I found a speedup that cost nothing and needed no new hardware: I was feeding the model twice the tokens it needed. On a CPU, prefill is the whole cost, and prefill scales with tokens sent. Swapping verbose JSON candidates for a terse line format cut the prompt 63% and prefill 65% — 2.7× fewer tokens, 2.9× faster — with no accuracy trade-off. Part 2 of 3.

Running Local AI Models on the NPU of a Snapdragon Surface — with Foundry Local
I have a Copilot+ Surface with a 45-TOPS Hexagon NPU that had never run a single inference. This is the note I wish I'd had: how to actually put a language model on that NPU with Microsoft's Foundry Local, why prefill-heavy automation workloads are exactly what an NPU is built to eat, and the session-0 gotcha that wastes an afternoon when you drive the machine headless over SSH. Part 1 of 3.

Voice Activity Detection: The Cheap Gate That Makes Your Speech Pipeline Fast
Most of the audio in a real recording is silence, and if you send that silence to a speech-to-text model you pay full price to transcribe nothing. Voice activity detection is the cheap gate you put in front of the expensive stuff: a tiny model that tells you, 32 milliseconds at a time, whether the current slice of audio is speech. This is what it is, why it belongs in front of every ASR pipeline, and a small working C# example built on Silero VAD and ONNX Runtime — including the one undocumented detail that makes everyone think the model is broken.

Agent Resources: You'd Never Hire a Person the Way You Hire an Agent
Before we hire anyone at my company we write a profile — the exact role, the skills it needs, what it is and isn't responsible for — and then we spend that person's first week inducting them into the office: here are the systems, here's how we do this, here's who owns what. We do neither of those things for agents. We buy one magical all-in-one agent, hand it a god-prompt, and expect it to figure out the whole business at runtime — which it dutifully tries to do, burning a fortune in tokens re-deriving on every single request the context nobody ever gave it once. This is the case for Agent Resources: writing the profile and running the induction for your non-human hires, the same way you already do for the human ones.
More topics
All topics →
The Curb Cut for AI Agents: The Metadata Layer Accessibility Is Missing
Around 2001 I set up a blind neighbor's first computer with a screen reader, and watched him read the news on his own for the first time in decades. The interface he navigated with Tab and patience is the same one I now point AI agents at — the accessibility tree, a curb cut built for screen readers that turns out to be the cleanest way for an agent to operate an app too. But both hit the same wall: the tree says a control is a grid named Invoices and stops there. It won't say the grid can be filtered, where the filter lives, or how to work it without the dropdown collapsing on you. This is about the thin metadata layer that fixes that — for agents and for humans at once — and a small DevExtreme experiment where it filtered a real invoice grid to Pending on the first try.

From Chess to Xbox: The Rating System Behind the Match
There's a story that gets repeated in game-dev threads: Xbox Live uses the Elo equation to calculate experience points. Almost every word of it is wrong. Elo isn't an XP system, Xbox's Gamerscore doesn't use Elo, and the skill system Xbox does use for matchmaking isn't Elo either — it's TrueSkill, which Microsoft Research built precisely because Elo couldn't do what a console needed. This is the real journey, from a physicist scoring chess games in 1960 to the algorithm deciding who you get matched against — where every weakness in Elo turns out to be something TrueSkill was designed to fix.

I Gave Uno Platform a Linux Accessibility Backend in an Afternoon
Two posts ago I argued that agents should read the desktop's accessibility tree instead of guessing pixels. Then I tested which .NET frameworks actually expose that tree on Linux, and found Avalonia does and Uno doesn't — a Uno app is invisible to a screen reader (and to an AT-SPI-first agent) on Linux. So the obvious question: could I add it myself? It turns out yes, in an afternoon, because the hard part already exists inside Uno. Here's the build log — what AT-SPI actually wants, the ~350 lines that give it to Uno, the one gotcha that cost me a rebuild, and an honest accounting of what's done and what isn't.

Stop Guessing Pixels: AT-SPI-First Grounding for Desktop Agents
Last post was about OmniParser — reading a screen from pixels, detecting boxes, captioning icons. It's clever, and it's still guessing: a vision model infers where the button probably is, and every so often it clicks four pixels off and hits the wrong thing. On Linux there's a way that doesn't guess. Every GTK and Qt app already publishes a structured description of its own UI — the accessibility tree that screen readers use — with exact boxes, real names, and live states. AT-SPI-first grounding reads that instead of the pixels. Here's the flow, why it's pixel-perfect where it works, and why you still keep the vision model around as a fallback.

How an AI Agent Reads Your Screen: Microsoft's OmniParser v2
When an AI agent clicks a button in an app, how did it know the button was there? Not from the DOM — there often isn't one. It got a screenshot, a flat grid of pixels, and something had to turn that into 'here are the clickable things and what they do.' For a large part of the field, that something is Microsoft's OmniParser v2 — and the surprise is that it isn't an LLM at all. It's two small vision models: a YOLOv8 that finds the boxes and a Florence-2 that reads the icons. Here's how it works, why it turns any LLM into a computer-use agent, and the licensing footnote nobody mentions.