ANTIGRAVITY LABJP
Articles/Agents & Manager
Agents & Manager/2026-06-02Advanced

Rehearsing an Agent's Actions Before They Touch Production — Designing a Zero-Side-Effect Dry-Run Layer

Some accidents survive shadow mode and canaries: the very first time an agent touches an external API. This is the design and TypeScript implementation of a zero-side-effect dry-run layer you can bolt onto Antigravity's parallel agents, with the real numbers from running six sites autonomously.

antigravity435agents129dry-runside-effectsoperations25architecture19reliability11

Premium Article

One day I was running an agent that rewrites production Remote Config values, and my blood ran cold. All I wanted was to flip one campaign flag to true. But the agent had decided to tidy up a few stale keys along the way, and its plan included deleting settings that were still live. I happened to be watching the log that time, and stopped it just before it applied. But if it had been an overnight job, the display logic across the wallpaper apps I run might have broken all at once.

As a solo developer, I hand most routine work to Antigravity's parallel agents, but I never quite shook the fear around one category of action: when an agent changes something external. Code changes can be reviewed and rolled back. But AdMob settings, App Store Connect metadata, production Remote Config values, Cloudflare DNS — once you hit those, they are hard to un-hit.

Woodworkers have a saying: "Measure as often as you like; cut only once." Check the dimension as many times as you need, but make the cut just once. Ever since I started delegating external actions to agents, I've wanted to rebuild that instinct as a mechanism. This note is the record of the zero-side-effect dry-run layer I built for exactly that. It includes a minimal, working TypeScript implementation, and I hope it helps anyone else operating agents that carry external side effects.

Shadow mode and canaries can't protect the "first time"

Shadow execution and canaries are well-known safety devices for agents, and at first I assumed they were enough. But in practice, I found neither one protects the very first time an agent touches production.

Shadow execution runs an agent alongside production while discarding its output. It's great for observation, but it doesn't apply to side-effecting actions. The shadow of "rewrite Remote Config" is a contradiction: if you don't write, there's nothing to observe; if you do write, production has already changed. It works for read-heavy agents, but it can't protect a write agent's first run.

Canaries apply a change to a small slice of users or targets first, then widen it if nothing breaks. That helps after application. But what scared me was when the application itself was wrong. In the Remote Config example, the plan to "delete a live setting" was the error — and applying that error to 1% or to 100% is still an error. Canaries narrow the blast radius of a correct change; they don't reject an incorrect change in advance.

What I needed was a way to see, completely but without any side effects, exactly what was about to happen — before it happened. That is a dry-run. In engineering terms, I wanted the relationship between terraform plan and terraform apply, available for any external action an agent might take.

A dry-run only works if side effects are funneled

When you try to add a dry-run after the fact, you usually hit the first wall immediately: side effects are scattered all over the code, and there's no single point where "stop here and you stop every change." If each agent tool calls fetch or hits an SDK on its own, adding a dry-run means sprinkling conditionals across every site — and you will miss one. The moment a single call slips through unguarded, the dry-run lies.

So the starting point of the design is not the dry-run mechanism itself. It is funneling every externally-mutating action through one place. I call this the side-effect boundary. Tools never execute side effects themselves; they declare to the boundary, "I want to make this change." In production mode the boundary executes it; in dry-run mode it records it without executing. Only once this is unified does a dry-run become trustworthy.

// effect.ts — the type for a "planned action" representing an external side effect
export type EffectKind =
  | "http"          // a write request to an external API
  | "kv-write"      // a write to KV / Remote Config, etc.
  | "file-write"    // a write to a repo or asset
  | "delete";       // a deletion of something (split out — it's the most dangerous)
 
export interface Effect {
  kind: EffectKind;
  // a one-line summary a human can read to understand what will happen
  summary: string;
  // structured detail used when actually executing
  target: string;                 // e.g. "remote-config/campaign_flag"
  before?: unknown;               // value before the change (only if obtainable)
  after?: unknown;                // value after the change
  // the executor, called on real application. Never called during a dry-run.
  commit: () => Promise<void>;
}

The key is that an Effect bundles together the declaration of intent and the function that actually does it (commit). The declaration is what you show a human during the dry-run; commit runs only on real application. Locking both into the same object makes it far harder to drift into "the plan said delete X, but execution deleted Y."

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Get the full TypeScript implementation of a SideEffectBoundary that funnels all external mutations through one point, plus the Effect recorder that captures the plan
Understand how a dry-run solves a different problem than shadow mode and canaries, and how to decide which one a given situation needs
Learn the real operating numbers and gotchas — how unintended production changes went from a few a month to zero after adding the dry-run layer
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Agents & Manager2026-06-22
Your Antigravity Custom Tools Don't Break by Design — They Break on Re-execution: Field Notes on Idempotency and Error Contracts
Once you add a custom tool to an Antigravity agent, the real production problem is re-execution and duplicated side effects. Here are the idempotency keys, error contracts, health gates, and tool-sprawl checks that actually held up in practice.
Agents & Manager2026-06-19
Parallel or Keep It Serial: The Break-Even Point When Orchestrating Multiple Agents
Should you run agents in parallel or keep them serial? A simple way to estimate the break-even between coordination cost and saved wall-clock time, plus how I actually split parallel vs serial across four scheduled sites.
Agents & Manager2026-06-17
Making Managed Agent Batches Safe to Re-run: Idempotency and Checkpoints
Running overnight batches on the Antigravity 2.0 Managed Agents API makes recovery from partial failure unavoidable. Starting from a duplicate-post incident, I share the implementation of idempotency keys, a checkpoint store, and resume logic, with real numbers from solo operations.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →