An agentic engineering workflow, from ticket to proven PR

October 23, 2026 · 4 min read

For a while, my loop with coding agents went like this. Paste a ticket. Get a diff. Review it. Notice it fixed an easier version of the problem than the one in the ticket. Explain again. Four or more handoffs per ticket, and every one of them went through me.

The slow part wasn't the model. It was me, carrying context from one step to the next. So in September I wrote down what a finished ticket should look like, and built the workflow backwards from that. Three roles do the work: a coding agent that writes and repairs code, a cheaper fact agent that is allowed to look at production, and me, at the few points where a decision is actually mine.

  • Coding agent
  • Fact agent
  • You
  • Files and scripts
The whole loop. Press play, or click any step.

Start with claims, not code

Tickets are vague. “These invoices get booked wrong” can be fixed a dozen ways, and most of them only fix the example in the ticket. So the first step is now a short brief that ends in claims you can check: what should change, where, and one control case that must not change. If a claim can't be checked, the ticket goes back with a question instead of turning into a pull request.

Facts come from production, identities don't

The bugs that matter happen in production, and in our case production holds data from accounting firms that falls under professional secrecy in Germany. The model writing code should never see a client's name. So questions about production go to a separate, cheaper model that is allowed to look.

Its answers pass a privacy gate before anything comes back. It's a plain script: it rejects anything that looks like a name, an email, an IBAN, a tax number or an invoice number, and it only accepts answers explicitly marked as anonymised. What reaches the coding side is counts. How often a branch fired last week is useful. Who it fired for isn't.

The pull request is the evidence

The description isn't a summary of the diff. It says in plain words what changed, then lists the claim, the evidence, the risk and what is still unknown. The evidence is tests, including the control case, plus a replay of real documents through both the main branch and the fix, where again only counts come back. A reviewer should be able to decide from the description alone.

Bounded on purpose

The same session watches CI and review comments and repairs whatever comes up. But it stops after five repair rounds and ten production questions. If it hasn't converged by then, something about the ticket is wrong, and that's a human's call.

Done means proven or blocked

That's the rule the whole loop is built around. A ticket ends with evidence that the claims hold, or with a clear reason it can't be proven yet. There is no third state where it's probably fine.

It edits itself

After each run, a retro step reads the logs, the review threads and the token counts, then proposes changes to the prompts and scripts. Anything that causes friction twice becomes a rule, a script or a test. One small example: the cheaper model's CLI would sometimes hang waiting for input that never came. Now every call closes stdin, and there's a note next to it saying why.

If you're building something similar

Write the definition of done before you write the prompt. Route work by cost: a cheap model for facts and review, a mid-sized one for repairs, the strongest one only for the implementation. And keep the human at the end of the line, deciding, rather than in the middle of it, relaying messages.