Investigators before builders: a 2-phase LLM workflow that rewrites 30% of our plans

Most teams dispatch coding agents straight to the build. We run a read-only investigator phase first — and the findings have rewritten our plan in 30-40% of cases. Here's the shape, the brief format, and what to do when findings contradict the plan.

AppX team ·

Investigators before builders: a 2-phase LLM workflow that rewrites 30% of our plans

Most teams dispatch an LLM coding agent like this: read the task, hand it the files, let it edit. One shot. This is how Claude Code subagents, Cursor agents, and aider all default to running.

We stopped doing that. We now run a mandatory phase 0 in front of every non-trivial task: dispatch 4-6 read-only "investigator" agents in parallel that ONLY explore the codebase and return findings. A separate planning step ingests those findings and decides the actual plan. Only then does the builder get dispatched.

Investigator findings have rewritten the plan in 30-40% of cases. Sometimes the assumed bug is somewhere else. Sometimes the proposed file doesn't exist. Sometimes there's a simpler primitive already in the repo we'd have ignored. That hit rate is why this is non-negotiable for us now.

Why investigators must be read-only

flowchart LR
  P["Draft plan"] --> I["Phase 1 · Investigators<br/><i>read-only, parallel</i>"]
  I --> Q{"Plan still correct?"}
  Q -->|"~30%: no"| RW["Rewrite the plan"]
  RW --> B["Phase 2 · Builders<br/><i>write code</i>"]
  Q -->|"yes"| B
  style I fill:#13203a,stroke:#5e6ad2,color:#dbe2ff
  style B fill:#13241a,stroke:#2ecc71,color:#d7f7e3

The load-bearing constraint: investigators have NO Edit, Write, or Bash-mutation tools. Read, Grep, Glob, and a sandboxed shell for read-only commands. That's it.

Three reasons:

  1. They're cheap. A read-only agent is bounded — it can't get stuck in a 12-iteration edit loop trying to "fix" something it observed. It reads, summarizes, returns. Median run is 30-90 seconds.
  2. They parallelize safely. Six investigators concurrent against the same repo can't step on each other. No file locks, no merge conflicts. A builder running in parallel with anything is a disaster waiting.
  3. They answer the question instead of solving it. The subtle one. Give an agent a hammer and "where does X live?" stops being a file path and becomes a half-finished refactor of X. Read-only agents return findings, not diffs. The planner — armed with all six — decides what to do.

We treat the investigator/builder split the way we treat read-replica vs primary in a database. Different role, different permissions, different blast radius.

How to brief an investigator

The brief is one concrete question. Not a task. Not a goal. A question with a yes/no or a list as the answer.

Bad: "Investigate the auth flow."

Good: "List every code path that issues, refreshes, or revokes a JWT. For each, return file:line, the function name, and one sentence on when it runs."

The brief shape we use:

investigator:
  question: "List every code path that issues, refreshes, or revokes a JWT."
  return_format:
    - file: <path>
      line: <number>
      symbol: <function or class name>
      trigger: <one sentence>
  budget_tokens: 40000
  allowed_tools: [Read, Grep, Glob, Bash(read-only)]
  forbidden_tools: [Edit, Write, NotebookEdit, Bash(mutating)]

The return_format matters more than people think. Free-form findings give you a 2000-word essay with the load-bearing fact buried in paragraph 4. A structured return gives you a table the planner can consume.

We dispatch 4-6 of these in parallel. A typical brief set for a recent bug: "find every writer to users.session_token", "list all middleware on /api/auth/*", "map the call graph from login controller to token-issue", "find every reader of process.env.JWT_*", "list every test exercising login or refresh." Five agents, concurrent, results back in under two minutes.

What to do when findings contradict the plan

This is where most teams fail. They write a plan, dispatch investigators to "confirm" it, and when findings contradict the plan they explain away the contradiction and ship the original anyway. Don't. The investigator just saved you.

Real example, anonymized. Users reported sessions silently invalidating after ~90 seconds. Original plan: "race condition in auth middleware's token-refresh branch, add a mutex." Two files, forty lines.

Investigators came back with a finding nobody asked for: a half-forgotten background job in a billing module was reading the same session_token column to attribute usage, and on a stale read it was writing back the old token, clobbering the just-refreshed one. Auth middleware was innocent. The bug was a cross-module write conflict two directories over.

We threw out the original plan. New plan: add updated_at precondition to the billing job's update, plus a regression test. Three lines. The mutex fix would have shipped, looked like it worked because the race got rarer, and reintroduced itself the next time billing got loaded.

The rule: if findings contradict the plan, rewrite from scratch. Do not force-fit. Sunk cost on a five-minute plan is never worth defending.

The cost math

A round of 5 investigators costs roughly the tokens of one builder. Sounds expensive — until you count the alternative. A builder dispatched on the wrong plan typically burns 3-4x its normal token budget thrashing, then produces a half-correct diff that needs cleanup or a second run.

If investigators rewrite the plan 30-40% of the time, expected saved-builder-runs cover the investigator round on every task, not just the ones that change. The 60-70% of confirms aren't wasted either — they catch one-line gotchas (an import path that moved, a config key that got renamed) that would have cost a builder iteration to find.

Takeaways

  • Run a read-only investigator phase before every non-trivial agent task. 4-6 agents, one concrete question each, parallel dispatch.
  • Read-only is the load-bearing constraint. No Edit, no Write, no mutating Bash. This is what makes them cheap, safe, and honest.
  • Brief them with a question, not a goal. Force a structured return format. Free-form findings hide the load-bearing fact.
  • When findings contradict the plan, throw out the plan and re-plan. Don't pay sunk cost on a five-minute artifact.
  • Cost is roughly one builder per investigator round. Net positive as long as the rewrite rate is above ~10%. Ours is closer to 35%.

Try your own app idea

Describe your app in AppX →