Skip to content
All writing
AI EngineeringJun 24, 2026·12 min read

Your Agent Doesn't Need More Autonomy, It Needs a Leash

Autonomous agents demo beautifully and die in production. The ones that survive are on a short, well-designed leash — and the leash is the product.

Every agent demo is the same movie: someone types 'plan my product launch,' the agent spins up subtasks like a caffeinated intern, and the room applauds. Then Monday happens. Real users, real data, real consequences — and the same agent confidently emails the wrong customer list because step three of its self-written plan was slightly cursed.

The workflow engine on my work page runs at 95% task success in production. That number did not come from a better model, a longer prompt, or more autonomy. It came from systematically *removing* autonomy everywhere it wasn't earning its keep. This post is that playbook.

01

Workflow first, agent second

Here's the test that settles most architecture arguments: can you draw the happy path on a whiteboard? If yes, you don't need an agent — you need a workflow where some steps happen to call an LLM. Deterministic order, typed handoffs, retries you control. Save the agent — a loop where the model picks the next action — for the branches you genuinely cannot enumerate ahead of time.

workflow-vs-agent.ts
// known path? write it down. the LLM is an employee, not the manager.
const result = await pipeline(ticket, [
  classify,        // LLM: which category?
  extractFields,   // LLM: pull structured data
  validate,        // code: schemas, not vibes
  route,           // code: rules decide who gets it
  draftReply,      // LLM: writes, never sends
]);

// unknown path? THAT's the agent's job — inside a fence
const plan = await agent.run(goal, {
  tools: allowlist,          // these five tools, nothing else
  maxSteps: 8,               // wander budget
  requireApproval: ['send', 'delete', 'pay'], // the irreversible three
});

Most 'agent' products that actually work are 90% workflow with an agent doing the last unpredictable mile. That ratio is not a compromise — it's the design.

02

Decompose or die

One big prompt asking for one big outcome gives the model maximum room to be wrong and gives you zero places to catch it. Decomposition is the same trick it's always been in software: small steps, each with an output you can *check* — a schema to validate, a constraint to assert, a lookup to verify. When a step fails, you retry that step, not the universe.

03

Guardrails are product decisions

Teams treat guardrails as infrastructure — something to bolt on after the fun part. Backwards. 'What can this thing do without asking?' is the most important product question in the entire build, and someone who owns the user relationship should answer it, not whoever happened to write the tool-calling loop.

  • Default read-only: the agent can look at anything, touch nothing, until a step explicitly grants a write.
  • Tool allowlists per task type — the refund workflow does not get the email tool, ever.
  • Spend and blast-radius caps: max records touched, max money moved, max messages sent per run.
  • Dry-run mode that renders exactly what *would* happen — the diff, not a promise.
04

Checkpoints humans don't hate

Human-in-the-loop earned its bad reputation honestly: most implementations ask for approval on everything, so approvals become rubber stamps, so the checkpoint catches nothing. The fix is placement. Gate only the *irreversible* — sending, deleting, paying. Batch the approvals so a human reviews ten at once with full context. And show a diff, not a log: 'this email, to these 40 people, with this subject' beats twelve pages of agent reasoning every single time.

Tip

If your reviewers approve more than ~95% of checkpoints without edits, the checkpoint is set too early — move it downstream until the approvals start meaning something.

05

Failure budgets, borrowed from SRE

'It should always work' is not an engineering target, it's a wish. Give every step an explicit failure budget — extraction may fail 2% of runs, classification 0.5% — then alert on *drift*, not on individual failures. When a step blows its budget, that's your signal a prompt regressed, a model version shifted under you, or the input distribution moved. Log every tool call with its inputs and outputs; when something goes weird (something always goes weird), the trace is the difference between a five-minute diagnosis and a séance.

A demo is judged by its best run. Production is judged by its worst run that week. Design for the second audience.
06

The leash is why it ships

None of this is anti-agent — it's how you get to *keep* the agent. My MCP post covered giving models hands; this is the part where you decide what those hands may touch, verify what they did, and catch them when they slip. Autonomy isn't the goal. Shipping is. The leash is what turns a spectacular demo into a system a business will actually put between itself and its customers.

Key takeaways

  • 01If you can draw the happy path on a whiteboard, build a workflow with LLM steps — reserve agents for genuine branching.
  • 02Gate human approval at irreversible actions only, and show reviewers diffs, not reasoning logs.
  • 03Give every step a failure budget and alert on drift. Reliability is designed, not prompted.

FAQ

AIAgentsProduction

Related reading