Operator · Field Notes

An AI delegation framework: hand off the loop, keep the gate

Most advice about delegating work to an AI agent is about handing off more. Better prompts, longer context, more autonomy. My most expensive delegation session went wrong in the other direction: I handed off too little, and kept the wrong half.

The session

One bug. A database insert was failing with invalid input syntax for type integer: "". It took about 25 hand-driven cycles across a multi-hour session to resolve.

I personally ran every server restart, every grep, every database query, and relayed each result back to the agent for the next instruction.

The root cause, when it surfaced, was narrow and clean: the database driver version in use turned a JavaScript null into an empty string on the wire. The fix was to leave nullable columns out of the insert when they were null, so null never reached the driver.

The bug was not hard. The loop was expensive — and almost none of that expense was judgment.

Partway through I said it out loud: “I should not be involved in the debugging — it’s the keystrokes, not the judgment.”

Sorting the session into two lanes

Afterwards I went back through the session and put every step into one of two lanes.

Keystrokes — work an agent with environment access should own:

  • ~25 server restarts
  • repeated pkill / grep / psql
  • applying and reading debug probes
  • pulling branches
  • killing stale processes

Judgment — gate decisions a human, or a contract a human wrote, should make:

  • refusing to merge on POST 200 alone
  • demanding a DB SELECT proving founding_year IS NULL
  • rejecting an edit that re-armed the bug for boolean columns
  • choosing the scoped column-omission workaround over a risky major-version driver bump mid-sprint

Four decisions. Everything else was mechanical.

Where the time actually went

The cycles that cost the most were not hard thinking. They were state that had quietly drifted apart, and each one cost a full round-trip to discover:

  1. Wrong branch checked out in the workspace — a whole test cycle against code that didn’t have the fix.
  2. Stale process serving old code after a pull — twice. Indistinguishable from the fixed version until the worker id was checked.
  3. An old log file read instead of the current run — an empty grep that nearly got read as “the fix isn’t loaded” when the request simply hadn’t fired.
  4. A debug probe placed after the throwing line — so it never ran, and its silence looked like evidence.

None of those four were judgment failures. They were state-ownership failures. Runtime state lived in three places — a local working copy, a running process, a remote branch — and the only thing reconciling them was me, relaying between tools.

The gate that held

Twice in that session, a fix came back with a commit message saying it worked, and it didn’t. What stopped a broken fix from merging was one decision: the definition of done would be a database query showing a real NULL, not a successful HTTP response.

That is the whole difference between a claim and evidence:

A claim Evidence
“Returns 201” SELECT ... founding_year IS NULL returns t

A type-check passing is a precondition to testing, never a substitute for it. “Type-check clean, committed” is a true sentence that doesn’t answer the question.

The framework, in five steps

This is the decision framework I now run before any multi-step loop — debugging, building, testing, deploying:

  1. Separate judgment from keystrokes explicitly. Write down which decisions genuinely need you: merge or not, scope, safety, “is this actually done.” Everything else is keystrokes.
  2. Identify where state lives. If it lives in more than one place, name the one actor who owns reconciling it. If that actor is “me, relaying between tools,” that is the bug.
  3. Define the gate as producible evidence, not a self-report. Not “the agent says it’s done” — a specific artifact that can’t exist unless the work is done: a query result, a test output, a screenshot of the actual end state.
  4. Hand off the loop, keep the gate. The agent owns restart–test–grep–fix. You own go / no-go on the evidence.
  5. Treat static green as necessary, not sufficient.

And one habit: require the agent to confirm fresh state before it tests — new process id, correct branch, current log. That single step would have removed most of my 25 cycles by construction.

If you catch yourself running the sixth restart, stop. That’s the signal you’ve taken back keystrokes that were never yours.

The spec I fill out before I delegate

I turned this into a one-page spec: a state-confirmation step the agent runs first, the end state in one observable sentence, and a definition of done written as evidence rather than a status word. I fill it out before I hand anything off.

The Agent Handoff Spec — $39

Want this done for your business?

Most advice about delegating work to an AI agent is about handing off *more*. Better prompts, longer context, more autonomy.