PromptABCD
FeaturesLearnHow it worksUse casesFAQGuideBlogContext Blocks
Sign inGet started free
Sign inSign up
PromptABCD

A calm home for your best AI prompts. Save them once, find them in seconds, reuse them forever.

Product

  • Features
  • Chrome Extension
  • Free Courses
  • How it works
  • Use cases
  • Blog
  • Context Blocks
  • Export Anywhere
  • FAQ

Resources

  • User guide
  • Learn prompting
  • Sign in
  • Get started free

© 2026 PromptABCD. All rights reserved.

Privacy PolicyTerms and Conditions
Home/Blog/AI Harness/Building a Dry-Run Mode for Your Harness
AI Harness

Building a Dry-Run Mode for Your Harness

See exactly what an agent would do before it touches production. An agent harness dry run runs the full loop, simulates mutating tools, and hands you the plan to review.

September 9, 2026·8 min read
ShareShare
⚡Featured Prompt— copy and use right now
def dispatch(call, dry_run=False):
    tool = TOOLS[call.name]
    if dry_run and tool.mutates:
        PLAN.record(call.name, call.args)        # log the intent
        return tool.simulate(call.args)          # fake but plausible result
    return tool.execute(call.args)               # real execution

Picture this: you've built an agent that manages cloud infrastructure, and you're about to let it run against production for the first time. You're fairly sure it'll do the right thing. "Fairly sure" is not a feeling you want about something that can delete databases. What you want is to watch it decide what it would do — every tool call, every argument — without any of it actually happening. That's an agent harness dry run, and it's one of the highest-value features you can add to a harness that takes real actions. This post covers what it is, why it changes how you ship agents, and how to build one that's actually faithful.

The idea is borrowed from infrastructure tooling, where

terraform plan
shows you the changes before
terraform apply
makes them. An agent dry run is the same contract: show the full plan of actions, execute none of them, let a human read it and decide.

What Is an Agent Harness Dry Run?

An agent harness dry run executes the full agent loop — the model reasons, decides on tool calls, produces arguments — but every tool that would change the world instead returns a simulated result and records what it would have done. The agent runs to completion; the world stays untouched. At the end, you have a complete transcript of intended actions to inspect.

The distinction that makes it useful is between read tools and write tools. Read tools (search, fetch, look up) can run for real in a dry run — they don't change anything, and their real results make the agent's decisions realistic. Write tools (delete, send, charge, deploy) are the ones that get intercepted, returning a plausible fake result so the agent can continue reasoning as if they'd succeeded.

hljs python
[object Object], ,[object Object],(,[object Object],):
    tool = TOOLS[call.name]
    ,[object Object], dry_run ,[object Object], tool.mutates:
        PLAN.record(call.name, call.args)        ,[object Object],
        ,[object Object], tool.simulate(call.args)          ,[object Object],
    ,[object Object], tool.execute(call.args)               ,[object Object],

What this does: In dry-run mode, any tool marked as mutating records its intended call and returns a simulated result instead of executing, while read-only tools run normally. The agent proceeds through its whole loop believing its actions worked, and you collect a complete plan of everything it would have changed. One flag turns a live agent into a planner.

Why It Matters

A dry run collapses the risk of the first live run. Instead of "let's run it and watch nervously," you run it in dry mode, read the plan, confirm every intended action is sane, and then run for real with confidence. The scary first-contact-with-production moment becomes a document review.

It also changes how you develop. You can iterate on prompts and tools by running dry against real scenarios and reading what the agent decides, without side effects and without cleanup. A whole class of "run it, see what broke, undo the damage, try again" development loops disappears, replaced by "run dry, read the plan, adjust." That's faster and far less nerve-wracking.

⚠️ Common mistake: Building a dry run that skips mutating tools entirely instead of simulating them. If a delete tool just returns nothing in dry mode, the agent's next decision is based on a world where the delete didn't happen — which diverges from reality and produces a plan you can't trust. The simulation has to be plausible — return what a real success would have returned — so the rest of the run stays realistic.

Making Simulations Faithful

The value of an agent harness dry run is only as good as its simulations. A dry run whose fake results don't resemble real ones produces a plan that wouldn't match the real execution — worse than useless, because it looks authoritative while being wrong.

The best pattern is to have each tool define its own simulation alongside its execution, so the fake result mirrors the real one's shape and the person maintaining the tool maintains both together.

hljs python
[object Object], ,[object Object],(,[object Object],):
    mutates = ,[object Object],

    ,[object Object], ,[object Object],(,[object Object],):
        n = db.delete(args[,[object Object],], args[,[object Object],])
        ,[object Object], {,[object Object],: n}

    ,[object Object], ,[object Object],(,[object Object],):
        n = db.count(args[,[object Object],], args[,[object Object],])   ,[object Object],
        ,[object Object], {,[object Object],: n, ,[object Object],: ,[object Object],}

What this does: The real

execute
deletes and reports the count;
simulate
runs a read-only count of what would match and returns the same shape flagged as simulated. The agent sees a realistic "deleted: 340" and reasons correctly, while the database is untouched — and the plan tells the human exactly how many rows were at stake. Simulation reuses the real query logic to stay honest.

⚡ Pro tip: Have simulations return real previews wherever they can — a count of affected rows, the actual recipients an email would go to, the real diff a change would apply. A dry run that says "would delete 340 rows from

orders
" is vastly more useful than one that says "would delete." The preview is where the human catches the mistake, so make it concrete.

Using Dry Runs Beyond Development

Once you have a faithful dry run, it powers three things beyond first-run confidence.

It powers approval previews. The plan a dry run produces is exactly what a human approver needs to see — "here's everything this run will do." Feeding the dry-run plan into an approval gate gives reviewers a concrete, complete picture instead of a single action out of context.

It powers testing. A dry run against a fixed scenario produces a deterministic plan you can assert against — "given this input, the agent should plan to call these tools with these arguments." That's a powerful regression test for agent behavior, catching when a prompt change alters what the agent decides to do.

It powers safe demos and audits. You can show stakeholders exactly what an agent would do in real situations without any risk, which is often what unblocks approval to run it live at all.

⚡ Pro tip: Diff the dry-run plan against the actual execution afterward, at least during rollout. If the agent planned to delete 340 rows but really deleted 900, your simulation is drifting from reality and the dry run is lying to you. A periodic plan-versus-reality diff keeps your simulations honest over time as the underlying tools evolve.

Structuring Tools So Dry-Run Is Cheap

The reason many teams never add a dry run is that retrofitting one onto tools designed without it is painful — you end up threading a

dry_run
flag through every function and hoping you caught them all. The fix is to make dry-run a property of the tool interface, so every tool is born knowing how to simulate itself and the harness never has to special-case anything.

Give every tool two required methods,

execute
and
simulate
, and one property,
mutates
. The harness then has a single, uniform rule: in dry-run mode, mutating tools call
simulate
; everything else calls
execute
. New tools inherit the behavior by satisfying the interface, so nobody can add a mutating tool that forgets to support dry-run — the interface won't let them.

hljs python
[object Object], ,[object Object],(,[object Object],):
    mutates: ,[object Object], = ,[object Object],

,[object Object],
    ,[object Object], ,[object Object],(,[object Object],): ...

    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object], ,[object Object],.mutates:
            ,[object Object], NotImplementedError(,[object Object],)
        ,[object Object], ,[object Object],.execute(args)      ,[object Object],

What this does: Makes

simulate
part of the base tool contract, defaulting read-only tools to just run for real (safe) while forcing every mutating tool to define its own simulation or fail loudly at construction. The "forgot to support dry-run" bug becomes impossible to ship, because a mutating tool without a
simulate
raises the moment it's used in dry mode — in testing, not production.

⚡ Pro tip: Make

mutates
default to
True
, not
False
, in your own conventions even though the example above shows
False
for illustration. A tool nobody classified should be assumed dangerous until proven safe, so the failure mode of forgetting to set the flag is "over-cautious simulation" rather than "accidentally executed a real delete during a dry run." Fail safe on the classification, always.

Common Mistakes

The mistake that undermines the whole feature is inconsistent coverage — some mutating tools honor dry-run mode and others don't. A single tool that executes for real during a dry run makes the entire feature untrustworthy, because now a dry run might change something. Mark every mutating tool, and default unmarked tools to "assume mutating" so a forgotten flag fails safe.

The second is letting read tools with side effects slip through. A "search" tool that also logs analytics or increments a counter isn't purely read-only, and running it for real in a dry run leaks side effects. Audit your read tools for hidden writes.

The third is treating the dry-run plan as guaranteed. The real run happens later, against a world that may have changed — the 340 rows might be 350 by then. The plan is a high-confidence preview, not a contract, and irreversible actions still deserve their approval gates even after a clean dry run.

Conclusion

An agent harness dry run turns the riskiest moment — the first live run against real systems — into a document you read before anything happens. Simulate mutating tools faithfully, return real previews, mark every tool honestly, and the same feature powers approvals, behavior tests, and safe demos. It's a small amount of code for a large amount of confidence — and it's the kind of feature that, once you have it, you can't imagine having shipped an action-taking agent without.

Because faithful simulations and the tools they mirror have to evolve together, keep them versioned alongside your prompts in a library like PromptABCD, so the dry-run behavior you built stays in lockstep with the tools it previews — and every agent you ship can show its plan before it touches the world.

ai-harnessdry-runsimulationsafetypreviewsapprovals

Continue Reading

Managing Prompt Templates Across a Harness Codebase
AI Harness

Managing Prompt Templates Across a Harness Codebase

Four divergent copies of one prompt caused a two-day bug. Harness prompt templates management makes prompts versioned, tested, single-source artifacts instead of scattered strings.

September 10, 2026·8 min read
How to Open-Source Your Agent Harness
AI Harness

How to Open-Source Your Agent Harness

An agent harness isn't an ordinary library — it's security-sensitive infra tangled with your secrets. Release an open source agent harness without leaking a key or shipping unusable code.

September 10, 2026·8 min read
Error Taxonomy: Classifying Harness Failures
AI Harness

Error Taxonomy: Classifying Harness Failures

When every failure looks the same, you can't retry, route, or alert correctly. Agent harness error classification gives failures types that drive real behavior.

September 10, 2026·8 min read

Save the prompts from this post

PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.

Start free →
← PreviousTesting Your Harness Against Prompt InjectionNext →Instrumenting a Harness With OpenTelemetry
Share this post:
ShareShare