Journal
4 min read

My tools were sorting, not thinking

Two tracking tools in five weeks, a third on the way, and the feeling of going in circles. The day I asked a blank session to tear my process apart, and what came out of it: Foundry.

By late June I was on my second tracking tool in five weeks, and already preparing the move to a third. With the same feeling every time: going in circles.

Each time, I told myself the tool was the problem. The GitHub board that ate my API quota. The Obsidian notes that stepped on each other at sync time. So I migrated, rewrote my commands, and two weeks later I was just as annoyed.

The tool was not the problem.

First in the list

I had eight home-made commands to steer my projects with Claude Code. /next-issue to know what to do, /start-issue to begin, /open-pr, /merge-pr, and a few more.

/next-issue was this: sort the tickets by priority, then by size, then by date. And print the first one.

That's it. It didn't look at what blocked what. Or at what was half done. Or at what would unblock the most work behind it. The model never even saw the backlog: a Python script had already decided, and the model read me the verdict.

I had a model able to reason about a whole project, and I was using it to read the first row of a sorted table out loud.

July 1st

That day I packed everything up: my eight commands, the Python behind them, the history of my migrations. And a note, roughly: here's my process, it's too binary, tear it apart.

I handed that to a blank session. No context, nothing to defend.

It found what I could feel but couldn't put into words. And one thing I hadn't seen at all: my "green CI before merging" rule only existed in a piece of text. The code sent the merge without checking anything.

A session in a hurry could merge red. Nothing stopped it, apart from its good will.

All backwards

I had put the judgment in the code, and the rules in the prose. Exactly the wrong way round.

Sorting tickets is judgment: it depends on context, and a model does it very well if you show it the data. I had frozen it into a sorted().

Green CI is a rule: it's not up for discussion, and it shouldn't depend on anyone's mood. I had entrusted it to a paragraph.

Foundry starts from there. Judgment in the skills, invariants in the code.

On the read side, the Python returns the project's whole graph — the links between tickets, the acceptance criteria, the progress — and decides nothing. The priority ranking still exists, but it's one field among others. The model can override it, as long as it says why.

On the write side, it's the opposite. The merge goes through a gate, and the gate is in Python:

proven = any(c.status == "completed" and c.conclusion == "success" for c in checks)
...
"passed": (proven or waived) and not pending and not failing,

It takes at least one check that really succeeded. Nothing pending, nothing red. Zero checks doesn't pass. All checks skipped doesn't either: "nobody said no" is not a yes.

No more re-arguing

The other half of "going in circles" was this: reopening decisions I had already made. You settle an architecture choice on a Tuesday, and three weeks later a fresh session cheerfully suggests the option you had ruled out.

Now every decision is written down. Before touching a topic, Foundry loads the ones that concern it and treats them as settled. An idea that was already refused gets refused again, with the decision's number. To change your mind, you have to do it on purpose.

Four Frenchmen

Since August, the work is split between four roles. I gave them names from home.

Lupin explores the repository. He gets in everywhere and touches nothing.

Eiffel builds, one ticket at a time.

Maigret reviews the diff before the merge. He arrives knowing nothing of the conversation that produced the code, and he only believes what he sees.

Vauban only shows up for architecture.

Each runs on the model it needs. You don't need the most expensive one to go read three files.

Where I am

The first commit is from July 1st. The next day, I was on the eighth version.

Two months later: sixteen skills, about 36,700 lines of Python, 1,346 tests. It runs on Claude Code and on Codex. And it steers Orfeo, Luchamon and Souffle.

Thirty-six thousand lines for a personal tool. From the guy who says "no over-engineering" all day long.

I don't stand by it. But it works well.

In the next articles: how I wore out my tracking tools one after another, what "proven green" means, and why almost all my measurements came back stamped "inconclusive".

— Pato