Phil Booth

Existing by coincidence, programming deliberately

Very niche software, part 2

Hot on the heels of my Bluesky client for an audience of one, I’ve now shipped a coding harness for an audience of one too. This post is about Opair, the coding harness that no-one asked for but I built anyway.

“Jesus wept, not another coding harness” I can hear you thinking. It’s true there’s a lot of them about but as far as I know, none have chosen to make the same tradeoffs I’ve made in Opair. Where most coding harnesses seek to maximise autonomy for the agent, Opair takes the opposite stance:

The obvious benefit here is safety. The agent has no way to accidentally nuke stuff with rm -rf or git reset. It can’t read secrets from git-ignored env files, unless the user explicitly approves it (Deepseek I’m looking at you here). These are genuine wins and they give me the confidence to run Opair directly on my own machine, not inside a sandbox.

But security was not the only motivation for writing Opair, or even the primary one. The main reason I opted to build such a heavily restricted agent was to force it to collaborate with the human at the keyboard. I don’t want to read a massive diff at the end of an implementation push; I want to be involved in it all the way through. Opair is my attempt to make the human/agent relationship more like pair programming and less like code review.

Pair programming with agents is a topic I’ve written about before and plot twist, I started building Opair about a week after writing Agentic coding and mental models on this blog. I had no idea I was about to create my own harness when I wrote that, but it’s interesting to see many of the themes were quite well formed, even then. The core problem is that most other harnesses are made by companies who are in the business of selling you tokens. They’re incentivised for the agent to disappear on long loops of investigation or trial-and-error implementation. Forcing other harnesses to work how I wanted felt like a constant battle, so Opair was my experiment to see what a purpose-built agentic pair programming harness might look like. It turns out to be both interesting and useful in my opinion.

This brings us to perhaps the biggest point of difference from those other harnesses. Opair has two modes, driver and navigator:

Navigator mode works best with Opair running in a visible window or tab, while you make changes in your regular editor. I’ve found it quite compelling. After spelunking deeply into nested rabbit holes, sometimes it’s difficult to page in earlier context while unwinding your mental stack. Navigator mode is great for helping here. It spots things you’ve forgotten about or left unfinished. This is exactly what I want from AI-assisted development, to augment my own skills instead of replacing them.

Granted, navigator mode can also be a bit annoying at times. The agent talks too much in this role because, as we know, LLMs are the ultimate paperclip token factory. If you ask it to ignore part of the code because you’re still iterating, the agent will often ignore your comment and proceed to critique everything you told it not to. There are improvements I can make to how the navigator loop is implemented, so the agent acts more reasonably there. I’m also interested in how it works with a text-to-speech integration, so Opair speaks in your ear while your eyeballs stay glued to the code.

The hardest challenge turned out to be getting the UI to work reliably without glitching on scrollback. Initially I was seduced by Bubbletea’s promise of a clean model with “three simple methods”. No shade thrown at Bubbletea here, I’m sure it’s glorious when you actually know what you’re doing. But my ham-fisted efforts resulted in a long-winded “god” model that was hard to understand and numerous rendering bugs that I was incapable of fixing. Eventually I tore it out and replaced it with some hand-rolled UI abstractions, composed around the idea of “areas” that dock to an edge of the screen and own their internal rendering logic. When a message is scrolled out of the topmost conversation area, it moves naturally into the terminal’s scrollback and is no longer managed as part of Opair’s real estate.

“That’s all well and good,” you might be saying, “but isn’t using Opair much slower than using Claude Code?” (or whatever). Well, it depends on what you’re measuring. It’s true that Opair might write lines of code more slowly than a harness with more autonomy does. But since when has anything related to lines of code been a good metric for productivity? We should measure when features make it to production and users are happy. We should measure the frequency and severity of bug reports in the field. We should measure the difficulty and cost of future maintenance. Those are much trickier metrics to pin down and so answering the question of whether using Opair is slower or faster than other harnesses is trickier too.

For what it’s worth, Opair doesn’t feel slower to me. But even if it did, that wouldn’t make me not want to use it. Speed is not the tradeoff here. The tradeoffs are understanding, ownership and mental models. Or at least, they are for me. I suspect they’re not the tradeoffs for anyone else because my Show HN got one upvote and I know that was from my friend Ian.