Fresh Thoughts

View all →

Software engineering used to be a translation problem.

You had an idea, and you spent your day fighting syntax to express it. The "how" was the work: how to walk a tree, how to align a flexbox, how to handle an N+1 query.

Now, syntax is cheap. If you want a function, you get it. If you want a service, it’s there in seconds. But when you collapse the cost of one constraint, the bottleneck doesn't vanish—it just moves to the next hardest thing.

The new bottleneck is verification.

Reading code is fundamentally harder than writing it. When you type every character yourself, you build a mental map of every edge case and every "why." You aren't just writing code; you're building the history of the logic in your head.

When an AI generates it, you’re just a witness. You get a block of code that looks correct, passes the happy-path tests, and hides its flaws behind perfect indentation. You have the what, but you’ve lost the why.

Asking for a "CRUD endpoint" is easy. Proving it handles permissions, retries, and partial failures is the real work. The machine has no intent. It doesn't care if the system works; it just knows what the next token should probably be.

The keyboard was never the bottleneck. The bottleneck is our ability to hold a complex system in our heads—and know exactly when the generated lines are failing us.

Bytes & Drafts

How TLA+ Can Help Build Reliable AI Agentic Systems

4 minute read Published: 2026-03-24

When we move from building chatbots to building agents—systems that can call tools and perform actions—we move from the domain of language modeling into the domain of stateful systems.

In a simple chat interface, a model's mistake is usually a semantic one: it gives a wrong answer or hallucinates a fact. But when an agent has the authority to issue a refund, move a file, or trigger a deployment, a mistake can become an operational failure.

Often, these failures are not caused by the model's reasoning, but by how we have designed the system around it.

Why on earth do we need TLA+?

19 minute read Published: 2025-11-16

Every few years the industry collectively rediscovers the same uncomfortable fact: you can have good engineers, solid testing, careful code reviews, and still ship a distributed system that behaves in ways nobody expected.

Software is when hardware changes, Part 2: When the clock disappears

22 minute read Published: 2025-11-10

If you have ever chased a bug where a system froze every few hours, only to wake up the moment you attached a debugger, you already know that time is rarely as simple as a counter that increments once a millisecond. Timers fire slightly early or slightly late, interrupts sneak in between instructions, peripherals run from their own oscillators, and distributed nodes see each other through links with variable delay. From the outside everything looks nicely clocked. Inside, every part of the stack negotiates its own idea of now.

DSPy: Keeping pipeline promises intact

7 minute read Published: 2025-10-08

Language-model pipelines began life as collections of personal tricks. We shipped features only after someone produced the right paragraph of instructions, and that paragraph lived in a notebook or a mind. The knowledge was fragile, undocumented, and always under revision.

We learned this the hard way building a classifier that stubbornly hovered around 50% accuracy for days. After countless attempts and growing frustration, we discovered two innocuous words in our prompt were poisoning the results. Remove them, and accuracy jumped to 70% overnight. The "fix" lived in one person's head, and we had no process for finding it again.