---
title: "My daily agent workflow"
description: "A practical daily workflow for running coding agents with explicit goals, isolated terminals, evidence-based review, controlled merges, and carry-over records."
date: "2026-09-25T00:00:00.000Z"
author: "Carlos Garavito"
tags: ["AI agents", "engineering workflow", "code review"]
canonical_url: "https://cgaravito.dev/en/blog/my-daily-agent-workflow"
last_updated: "2026-09-25T00:00:00.000Z"
locale: "en"
---

On a normal day I have several coding agents running at once. Most of what I have built around them keeps decisions with me, and every piece of work I call done comes with evidence I can open and check. This is the loop I use, with diagrams I drew to walk my team through it in a livestream.

## Choose the loop for the task

Before anything runs I sort the work by what is still unknown and how big it is. Research or an audit goes to a separate research lane first. A single localized change is a dart. A batch of related PRs goes through grilling and becomes a wave plan that I confirm. Whether pilot runs that wave to the end or I merge it slice by slice by hand depends only on whether I have authorized merges. Flash review sits outside these loops, so I can point it at any local diff for a quick second look. Even a small diff sometimes needs research first when it depends on how an external system behaves and I am not sure how.

[[asset:which-loop-color]]

## Resolve every doubt in the grilling

Grilling is my name for the interview where every doubt gets resolved one question at a time. Each question comes with the answer I would recommend and what that choice costs. Facts get looked up rather than asked, and decisions go to the human, which is usually me.

This matters because workers run their goals without stopping to ask anything. An open question here comes back later as a guess inside a PR. I keep each question narrow enough that the answer changes the plan. Once it is decided, the same answer goes into the worker's goal and into the review criteria.

## Plan the wave as PR rows

The plan splits the batch into PR rows. Each row has one deliverable, its dependencies, and one executor. The shape is parallel when rows are independent, a chain when one row changes the base of the next, or phases when groups of rows can move together. I confirm that shape before any agent starts.

I write dependencies down explicitly because a plan that looks parallel can turn into a chain once one PR changes an interface consumed by another. The state file tracks each row's goal, PR, worktree, review, and merge as separate fields. I reconcile it against GitHub, since the plan is not proof that anything happened. A trimmed plan looks like this.

```text
shape: phases
status: kickoff

| id | title | depends on | worker | goal | pr | review | landed |
| -- | ----- | ---------- | ------ | ---- | -- | ------ | ------ |
| P1 | Persist draft state | - | executor A | emitted | - | - | - |
| P2 | Expose preview | P1 | executor B | blocked | - | - | - |
```

## Write goals as completion contracts

Each row gets a goal that works as a completion contract. It has the outcome, context, boundaries and constraints, exact verify commands, and a rule for when to iterate, when it is done, and when to stop, all under 4000 characters.

I copy the verify list from the repository's CI rather than inventing an easier local version. I name the behaviour the worker has to show, because a green command can still hide a missing feature. Any authorization to commit or open a PR is quoted verbatim. Without one, the worker leaves its work uncommitted. Done means evidence I can inspect. A worker that cannot get there reports the blocker and leaves its state for me to inspect. The goal for this post looked roughly like this.

```text
Outcome: both locales preview with every declared asset.
Context: the post is withdrawn, test it in isolated local state.
Boundaries: the post brief and the authoring pipeline only.
Constraints: never publish or change remote state.
Verify: the format, type, test and build gates from CI,
  then read both local previews.
Iterate/done/stop: regenerate from the brief until both
  previews pass, stop on missing evidence or credentials.
```

The format comes from [Goalcraft](https://github.com/grp06/goalcraft), which describes a goal as a compact contract with an outcome, a verification surface, constraints, boundaries, an iteration policy, and a blocked stop condition, with a 4000-character limit.

## Pilot the wave slice by slice

When I have authorized merges, pilot runs the wave on its own, one slice at a time. For each slice it reconciles open PRs with GitHub and the worktrees, writes one goal per ready row, starts every worker in its own terminal, and watches for an opened PR or a stall.

An idle terminal never counts as done. What counts is an opened PR and, later, a review verdict. Then come review, fixes for verified blockers, the merge, and the next slice. Without merge authorization, the loop stops at review and the PRs wait for me.

[[asset:pilot-slice-color]]

## Review, fix and measure again

Review has two layers. A gating reviewer probes the change, usually with mutation probes, and reports blockers with file and line. Blind read-only reviewers from other labs add their findings without seeing each other's.

A fixer only touches verified blockers. I check every reported blocker against the diff before anyone edits anything, so a finding I cannot reproduce never becomes a fix instruction. After two fix rounds, whatever remains gets escalated as a design problem rather than entering a third round.

Every verdict records the base SHA it was measured on. If the base moves, I measure again, because the same head can behave differently once another PR lands. Workers never see the merge authorization and never merge their own PR.

The local-image support this post depends on went through exactly this. PR #272 on this site had two independent review rounds, a fixer closed five nits in eight commits between them, and the second round, measured on head 91a5943, killed 16 of 16 mutants.

For deeper reviews I have published [the read-only review swarm I use](https://github.com/cgaravitoq/my-opencode), with separate review lenses and a verdict tied to the inspected commit.

## Give every agent a terminal and worktree

Every worker, reviewer, and fixer runs in its own terminal and its own git worktree. I can read what it is doing, stop that one process, and inspect what it left behind after a kill, whether that is a mutation a reviewer did not revert or a partial diff from a fixer.

A subagent running inside the conductor gives me no handle to read or stop. When it dies, it says nothing about what it left in the tree.

## Close the wave with carry-over

Closing a wave writes the carry-over for tomorrow, including the exact rows that did not merge and the next decision each one needs. Anything that went wrong and could happen again gets promoted into a shared learnings file that every later wave reads at kickoff. I write the failure mechanism and what changed, so the next wave checks that boundary rather than rediscovering it.

The next morning starts from that record. It is much cheaper than scrolling back through terminal history.

## Research and audit in a separate lane

For research or an audit I write a self-contained brief with the question, the sources to look at, and the output format I want back. The research lane is a disposable session that only sees that brief, never my conversation or my conclusions. It returns findings with a URL and an exact quote.

I still compare each quote with the page, because a URL can be real while the quote is paraphrased or unrelated. For plans that matter I ask the other harness for a second opinion. It critiques once, I answer with one rebuttal, and whatever remains disputed comes to me rather than becoming a long back and forth.

[[asset:research-audit-color]]

## Use a dart for a localized change

A dart is for one localized change that should take minutes. If it is a bug without a repro, I diagnose it first with a reproduction and a hypothesis I can falsify. That tells the worker which behaviour has to change and gives the review something concrete to check.

Then I scope the outcome, the files, and the verify command, and hand it to one worker, or to several when their files do not overlap. Workers implement but do not commit. I read the diff, rerun verification, and only then commit, push, and open a draft PR. I never merge from the dart itself. If review turns up a design-sized question, it stops being a dart and becomes a wave.

[[asset:dart-loop-color]]

## Flash review the current diff

Flash review is the cheapest loop I have. I put the full local diff and its base and head SHAs into the prompt of one cheap read-only model running in its own terminal. It answers approve or reject with file-and-line findings, where a single blocker means reject.

I think a small model doing one concrete job is usually enough for this first pass. The big ones tend to ramble and over-engineer a review. I still open every cited line before I believe it, and a verdict without locations is not something I would fix anything from.

It never comments on a PR. The verdict comes to me, and a change that deserves more than that goes to the multi-lab review swarm.

[[asset:flash-review-color]]

## Why I keep it this way

I think this is a good workflow, mostly because each decision has an owner and each thing I call done has evidence I can open. It matches what I believe about agents in general. The value sits in the harness around the agent, the validation, the review, and the workflow. Agent code that reaches production without a human reviewing it is a failure however good the model is.

That is why I build this tooling around my own workflow rather than adopting someone else's harness as it is. At the end of the day I look at the wave record, which rows merged, which are left, and what I have to decide tomorrow.
