How I design: correct the first draft, then decide

I design with AI agents. Their first draft is where my thinking starts, not where it ends. Four small decisions from one evening show how.

I design most of my systems together with AI agents. An agent drafts a design, and it brings me the decisions that need a person. Each decision comes with a recommendation and a few alternatives. I rule, and the agents turn the result into work they can pick up later.

That sounds like the agent does the thinking. It doesn't. The first draft is where my thinking starts. My job is to read it critically, ask why it isn't simpler, and then decide. Here are four small decisions from one evening that show how that goes.

Why not the simple thing?

I wanted my CI to start an LLM review of each change. The review runs on myelin, my agentic pipeline as code engine. The agent's first draft launched the review pipeline by sending a message over NATS JetStream, a message bus.

I asked why we weren't just making an API request. In my setup, NATS is for agents talking to each other inside a pipeline, or between pipelines. It isn't the front door for starting one. A launch is one caller asking one service to do one thing, and that's what an HTTP request is for. So the design moved to two plain HTTP endpoints on myelin: one to launch a review, and one to check its status.

The draft wasn't wrong in a way that would have broken. It would have worked. It just used a tool for a job it wasn't meant for, and that kind of choice costs you later, when someone has to work out why it's built that way.

No long-lived secrets

The easy way to let CI call myelin is to give CI a service-account token. That token would sit in CI forever, and anyone who got it could call myelin as CI.

So CI doesn't get one. Each CI run gets a short-lived token that is good for that one run only. The token comes from astrocyte, my credential gateway in front of SSO. Astrocyte attaches the real credentials when the request goes through. If a token leaks, it expires soon and only ever covered one run.

Spending scarce GPU time

The reviews run on local GPUs in my homelab, and that GPU time is scarce. So three small rules shape how a review spends it:

  • A newer push cancels the older review. Nobody needs a verdict on code that has already been replaced.
  • A deadline posts "did not run". If a review can't finish in time, the check says so plainly instead of hanging forever.
  • The same request reuses the existing verdict. Asking twice about the same change doesn't buy a second review.

None of these is clever. Each one came from asking what happens to the scarce thing when something goes wrong.

Retiring touchstone

The same evening, I asked how far along touchstone really was. Touchstone was my eval-runner project. The honest answer was that only its shared types had been merged. Everything else was still design and unfinished code.

That was the moment to stop. If I kept going, I would spend weeks building something I'd likely rip out once the engine underneath it changed. So I retired it. I pulled the pieces I actually needed, such as its data-retention levels, into another repo. Then I went back to building the engine that everything else depends on.

I didn't just delete it, though. I archived the repo, and I had the unfinished code inventoried before anything was removed, so nothing useful was lost by accident.

What these have in common

  • I read the first draft as a starting point, not a verdict.
  • I ask "why not the simple thing?" before I accept anything complex.
  • I look for what a design costs when it fails: a leaked token, a wasted GPU hour, a hanging check.
  • I'm willing to stop building something once I know it's the wrong thing to build.