Your orchestrator treats tools as pure functions. They aren't

The agent-as-orchestrator model assumes tools are clean, stateless, repeatable functions. Real tools send emails, charge cards, and write databases. One unhandled side effect and the plan becomes an audit log of damage.

B

Balagei G Nagarajan

5 MIN READ


Real tools aren't pure functions, they send emails, charge cards, and write databases.Treat them as repeatable and a retry or re-plan does the action twice; fragment the work across agents without shared state and they diverge and conflict (Cognition, Don't Build Multi-Agents, 2025). One unhandled side effect turns the plan into an audit log of damage.

An agent conductor directing tools as if they were notes that vanish after playing, while in reality each tool leaves a permanent glowing mark, a sent message, a charge, a write, that cannot be unmade
Retrying the whole plan re-runs the committed steps and duplicates them; doing nothing leaves the inconsistency.
— from “Your orchestrator treats tools as pure functions. They aren't”

Key facts.

  • Side-effecting tools, send, charge, write, provision, aren't repeatable: a retry or re-plan of a non-idempotent call does the action twice, so side effects need idempotency keys and saga-style compensation (distributed-systems transaction patterns).
  • Fragmenting work across agents without shared state and compensation leads to divergence and conflicting actions, the orchestrator can't reconcile what each agent actually did (Cognition, Don't Build Multi-Agents, 2025).
  • A durable execution engine records which steps completed so a restart replays results instead of re-executing side effects, the basis for exactly-once orchestration (durable-execution practice, e.g. Temporal).

Why does the pure-function assumption break?

Because the orchestration model borrows its intuition from code where calling a function twice is safe. In a notebook, a tool is a pure mapping from input to output: run it again and nothing changes. Production tools are writes against live systems, send an email, charge a card, create an order, terminate an instance, and they're often non-idempotent, so calling one twice does it twice. The agent's control flow makes that easy: it retries on a timeout, re-plans after a partial failure, or runs branches in parallel, and each attempt is a real side effect. Treating a stateful, irreversible action as a repeatable function is the bug, and the orchestrator's confident plan becomes a record of duplicated and unintended actions.

What goes wrong on a partial failure?

Inconsistent state that nobody reconciles. A multi-step plan, reserve inventory, charge the card, create the shipment, can fail at step three with the first two already committed. A pure-function orchestrator has no notion of rolling those back, so the system is left with a charge and no shipment, or a reservation and no order. Retrying the whole plan re-runs the committed steps and duplicates them; doing nothing leaves the inconsistency. this is where coordination and verification failures concentrate, the orchestrator doesn't track which side effects actually happened, so it can't undo or complete them coherently. The plan assumed every step was reversible and free. None of them were.

# Model side-effecting work as a saga: each step has a compensating action
saga = [
 Step(do=reserve_inventory, undo=release_inventory),
 Step(do=charge_card, undo=refund_card, idempotency_key=key),
 Step(do=create_shipment, undo=cancel_shipment),
]
run_saga(saga) # on failure at step N, run undo for steps N-1..1; retries replay via keys

How do you orchestrate real side effects safely?

Stop pretending tools are pure. Make every mutating tool idempotent with a stable key so a retry or a re-plan can't duplicate the action. Model any multi-step, side-effecting workflow as a saga: an ordered sequence where each step has an explicit compensating action, so a failure at step three triggers the undos for steps two and one and leaves the system consistent. Run it on a durable execution engine that records which steps completed, so a restart replays results instead of re-executing side effects. Add dry-run modes, rate limits, and monitoring for anomalous action volume, and gate the irreversible steps. The orchestrator then plans over actions whose effects are tracked, undoable, and safe to retry.

A saga diagram: three forward steps, reserve, charge, ship, each paired with a compensating undo, release, refund, cancel; a failure at the third step triggers the compensations back up the chain to a consistent state

Pure-function assumption versus saga orchestration

RealityPure-function orchestratorSaga orchestration
Tool has side effectsTreated as repeatableTracked, with compensation
Non-idempotent callRetry duplicates itIdempotency key replays result
Partial failureInconsistent state left behindCompensating actions roll back
Restart after crashRe-runs side effectsDurable replay of completed steps
Irreversible stepRuns freelyGated, monitored, dry-run first

Treat tools as pure and one re-plan double-charges a card; a stronger model re-plans more, so it compounds. (cognition.ai)

The pattern is that orchestration assumes pure functions and production gives you stateful, irreversible, non-idempotent tools, so a naive orchestrator duplicates actions and strands the system in inconsistent state. Make calls idempotent, model side-effecting workflows as sagas with compensation, and run them durably, and the orchestrator handles real side effects without multiplying them. Treating the tool boundary as stateful and undoable rather than pure is reliability at the pattern level, which is what VibeModel builds as the Pattern Intelligence Layer.

Frequently asked questions

what's a saga in one line?
An ordered sequence of steps where each has a compensating action, so a failure partway through is undone step by step to leave the system consistent, instead of half-done.

Why not just retry the whole plan?
Because retrying re-runs the steps that already committed their side effects, duplicating charges or orders. Use idempotency keys so completed steps replay, and compensation to undo what shouldn't stand.

Do I need a workflow engine for this?
A durable execution engine makes it far easier by recording completed steps and replaying them after a crash. At minimum you need idempotency keys and explicit compensating actions for every side-effecting step.


Share this post

Join the discussion

Have a take, a war story, or a question? Sign in with GitHub to comment and react. Comments are powered by GitHub Discussions, ad-free and yours to moderate.

Continue Reading

Find where your agent breaks, before you build it

Faultmap maps where your agent will fail from the goal and your data, then hands you the first test suite it has to pass.