Skip to main content

Malte Mindedal

How I work with coding agents

Most of my code now starts in Claude Code. I use Codex from time to time, but Claude Code is where I do most of my work. Since July, 121 of the 174 commits I've made across my repositories list Claude as a co-author.

Models matter. Each one has its own character, and the model you choose has a large effect on the quality of the work you get back. But apart from choosing, there's little I can do about how a model performs. What I can shape is the harness and the workflow around it. I think that shapes the result more than most people expect. A structured workflow makes working with agents predictable, and predictable is what I need when I'm the one shipping the code.

My workflow is built on Matt Pocock's skills (opens in a new tab): small, composable instructions for coding agents, based on ordinary engineering practice. Day to day, it's a loop with four steps: grill, spec, ticket, implement.

Grill

Every change starts with a grilling session. The agent interviews me about what I want to build until we reach a shared understanding. It maps the plan as a tree of decisions and asks every question it can already ask, in rounds, with a recommended answer for each. Facts it can find in the codebase, it looks up itself instead of asking me.

The version I use, grill-with-docs, also writes things down as we go. Terms we settle go into CONTEXT.md, the project's glossary, and decisions that need explaining go into decision records. Dispatch's glossary (opens in a new tab) opens with the rule the agent follows from then on: "When a word here fits, use it. Don't coin a synonym."

This is where misunderstandings get caught, before any code exists and while they're still cheap to fix.

Spec

When the grilling is done, to-spec turns the conversation into a spec and publishes it as an issue: the problem, the solution, the user stories and the implementation decisions we made. Before it writes the spec, the agent proposes the seams where the feature will be tested and checks them with me.

The spec is the first thing I review that isn't a conversation. If it's wrong, the grilling missed something, and we go back.

Ticket

to-tickets breaks the spec into tickets. Each ticket is a vertical slice: a narrow path through every layer that can be verified on its own, and small enough to fit in a single fresh context window. Each one lists the tickets that block it, so the order of work is explicit. I review the breakdown, merging or splitting tickets until the granularity is right, and only then are they published.

Small tickets make the next step predictable. An agent working from a small, clear ticket has less room to guess.

Implement

implement works through the tickets with test-driven development at the seams we agreed on: a failing test first, then the code that makes it pass. It runs the type checker and single test files as it goes, and the full suite at the end. Then it reviews its own diff on two separate questions: does it follow the repo's standards, and does it do what the ticket asked? Then it commits.

After that it's my turn. I read the diff before it's merged. Then the loop starts again with the next ticket, or with a new grilling session when something turned out different from what we planned.

Keeping the codebase in shape

Agents write code fast, and a codebase can get messy just as fast. improve-codebase-architecture surveys the code for shallow modules that could be made deeper, with more behavior behind a simpler interface. I pick a candidate and we grill through it like any other change. Two of Dispatch's (opens in a new tab) pull requests came out of it. The first also turned up a real bug: a permit leak that capped concurrency at the claim batch size.

For hard bugs, diagnosing-bugs keeps the agent in a strict order: first a test that fails on the bug, then narrowing it down, forming a hypothesis, instrumenting, fixing, and a regression test at the end. A flaky concurrency test in Dispatch went through that loop.

The harness

The skills run inside a harness that my repositories share:

  • An AGENTS.md with Forrest Chang's guidelines (opens in a new tab), based on Andrej Karpathy's notes on common LLM coding mistakes: think before coding, keep it simple, change only what the task needs, and define what done means before starting.
  • A CONTEXT.md glossary in projects with a domain of their own, like Stash (opens in a new tab) and Dispatch.
  • Checks the agent can run itself. My CV repo's AGENTS.md lists four rules that must hold after every change, such as "each file compiles to exactly one page", together with the commands that verify them.
  • Tests in CI. Stash alone has 41 test files.

None of this is tied to one model. The same skills run in Codex, and the same repo files are there whichever agent opens them.

What I get out of it

Predictability. It's the same four steps every time, and each one ends in something I can read and correct: the answers from the grilling, the spec, the tickets and the diff. The agent does most of the typing, and the decisions stay mine.

I choose the model. The workflow is the part I build.