Dev Log: 2026-03-30

The thing about documentation is that nobody wants to write it in the moment, and everybody wishes it existed six months later. This session was the rare case where I actually stopped building and started explaining — and the work turned out to be more interesting than I expected. The trigger was mundane enough: a rebase had left the devlog’s anchor commit stale, pointing at history that no longer existed in the same form. A handful of commits needed to be re-recorded against the new topology. But rather than just mechanically advancing the anchor and moving on, I used the pause to ask a harder question: does anyone reading this project actually understand how it works? ...

March 30, 2026 · rbergman

Dev Log: 2026-03-29

The hooks were deadlocking during rebases. Not sometimes — every time. An AI coding agent would kick off a rebase, the hook would fire mid-operation, the hook would try to check pending commits, and the whole thing would just… freeze. The agent couldn’t continue the rebase because the hook was blocking it. The hook couldn’t commit because you can’t commit mid-rebase. A perfect little standoff, both sides waiting politely for the other to go first. ...

March 29, 2026 · rbergman

Dev Log: 2026-03-24

The bug was invisible in the happy path. That’s what made it so irritating. --range has two ways to find entries: anchor-based lookup (find the entry whose anchor commit lives in the range) and diff-based discovery (scan the actual changes). In v0.15.3, the diff-based path was a fallback — it only kicked in when anchor lookup returned zero results. Which sounds reasonable until you think about what happens when anchor lookup returns some results but not all of them. ...

March 24, 2026 · rbergman

Dev Log: 2026-03-23

The query --range feature worked perfectly — right up until someone squash-merged a branch. That’s the kind of bug that doesn’t show up in your happy-path tests. You build a commit-range filter, you test it against normal merges, everything resolves beautifully. Then a squash merge comes along and rewrites history into a single commit with a brand new SHA, and suddenly your carefully anchored entries point at commits that no longer exist on main. The query returns nothing. Not an error, not a warning — just silence. ...

March 23, 2026 · rbergman

Dev Log: 2026-03-14

Beads hit 0.60 and it was one of those releases where you get to delete stuff, which is always the best kind of upgrade. The backstory: we’d been carrying around workarounds for Dolt sync — raw dolt push/dolt pull invocations, manual port management, the kind of duct tape you accumulate when the underlying tool hasn’t quite caught up yet. Beads 0.60 fixed the push/pull story and moved to ephemeral ports, which meant all those workarounds went from “necessary evil” to “dead code in our guidance docs.” ...

March 14, 2026 · rbergman

Dev Log: 2026-03-13

There’s a particular kind of satisfaction in deleting workarounds. Not the satisfaction of building something new — that’s additive, expansive. This is subtractive. You’re removing code that should never have existed, except it had to exist, because the tool you depended on wasn’t ready yet. Beads 0.60 landed, and with it, bd dolt push and bd dolt pull just… work. No more raw Dolt commands. No more hardcoded ports, then hash-derived ports, then manual port configuration. Ephemeral ports, assigned by the OS, the way it should have been from the start. Three versions of port strategy in as many releases — a textbook case of accidental complexity burning off as a tool matures. ...

March 13, 2026 · rbergman

Dev Log: 2026-03-07

Every project has its plumbing. The kind of work that doesn’t show up in feature lists or changelogs but quietly determines whether your tools actually work when you sit down Monday morning. This week was a plumbing week. It started, as these things do, with a misleading error message. Two projects sharing the same machine, both running Dolt databases, both defaulting to port 3307. The symptom was “port in use by non-dolt process” — which sent me chasing phantom processes and stale PID files before the obvious dawned: two databases, one port, no collision prevention. The fix was straightforward enough — assign a unique port — but the real problem was upstream. Beads 0.59 was already shipping hash-derived ports, designed precisely to prevent this class of collision. I’d been working around a problem that was already solved; I just hadn’t migrated yet. ...

March 7, 2026 · rbergman

Dev Log: 2026-03-05

The hooks weren’t working. Not “broken” in the dramatic sense — no stack traces, no crashes. Worse: they were silently doing nothing. Agents would finish a session, skip documentation, and nobody noticed because the echo-and-grep pipeline that was supposed to remind them just… printed to stdout where Claude Code quietly consumed it and moved on. This is the kind of bug that makes you question your assumptions about how tools communicate. The old hooks used plain-text output — echo "Hey, you have pending commits" — which is perfectly reasonable if you’re talking to a human terminal. But Claude Code doesn’t enforce plain text. It enforces structured JSON with specific fields like permissionDecision and deny. Everything else is decoration. So the hooks had been decorating for weeks, and every session ended with undocumented commits. ...

March 5, 2026 · rbergman

Dev Log: 2026-03-03

The stale anchor bug was one of those embarrassing gaps where the system claimed to be self-healing but quietly wasn’t. timbers pending, timbers prime, and the MCP path all handled ErrStaleAnchor gracefully — if a squash merge made the anchor commit unreachable, they’d accept the fallback commits from GetPendingCommits and carry on. But timbers log and timbers batch log? They treated it as fatal. The exact commands you’d reach for after seeing the “you have pending commits” nudge would just… blow up. Accepting the fallback and warning instead of dying was a small fix scattered across a handful of files, but the test proving it works is worth more than the fix itself. ...

March 3, 2026 · rbergman

Dev Log: 2026-03-01

The kind of day where you’re prepping to drive traffic to your project and realize you need to sweep the porch first. Started with the biggest chunk of actual feature work: a --models flag and multi-CLI piping documentation. The motivation is simple — not everyone lives in Claude-land, and users on codex or gemini CLIs had zero guidance. The new draft_models handler exposes ProviderInfos() so agents can self-service discover which providers are configured and what API keys they need. A surprisingly hefty chunk of plumbing scattered across the codebase to make that work. ...

March 1, 2026 · rbergman