Get Started
Chapter 510 min read

Agents, Autonomy and Where They Break

Tools that run commands and edit files across a repo change the risk profile. Where multi-step autonomy earns its keep, and where it quietly makes a mess.

Autocomplete suggests a line you accept or reject. An agent reads files, runs commands, edits across a repository and iterates until it thinks it is finished. The leverage is much higher and so is the blast radius.

The failure mode is not dramatic. It is twenty small reasonable-looking changes across eleven files, where three are wrong and you did not watch closely enough to know which.

Tasks that suit autonomy

  • Mechanical changes with a verifiable end state — a rename across the codebase, a dependency upgrade, a lint rule applied everywhere
  • Migrations with a clear pattern, where one example teaches the rest
  • Adding a feature that closely mirrors an existing one, with tests to prove it
  • Investigation — 'find everywhere this is called and summarise how it is used' is read-only and genuinely fast
  • Anything where a test suite or a type checker gives objective feedback the agent can act on

Tasks that do not

  • Anything with no automatic way to check the result. Without a signal, the agent cannot tell progress from damage
  • Work spanning a design decision you have not made. It will make the decision for you, silently, in code
  • First contact with an unfamiliar codebase, where you cannot yet judge whether a change is idiomatic
  • Production operations — deployments, migrations against real data, anything touching money or credentials

Scope the task the way you would brief a contractor

The most common cause of a sprawling mess is an under-specified goal. 'Improve error handling' has no end state, so the agent keeps finding more to improve. 'Replace bare throws with AppError in src/api, no other changes' does.

A well-scoped agent task

Goal: migrate src/api/*.ts from the old `db.query` helper
to the new `db.sql` tagged-template client.

Scope:
- Only files in src/api. Do not touch src/lib or tests
- Do not change behaviour, only the call style
- Do not add dependencies

Done when:
- `pnpm typecheck` passes
- `pnpm test` passes with no new failures
- No occurrences of `db.query` remain in src/api

Work file by file and stop after the third file so I can review
before you continue.

Review the diff, not the summary

An agent's closing summary is a description of what it intended. It is generated from the same process that produced the changes, so it inherits the same mistakes — and a wrong change is often described in the summary as a correct one.

Read `git diff`. If the diff is too large to read, the task was too large to delegate, and the fix is to break it up next time rather than to skim faster.

Permissions deserve thought

These tools ask before running commands, and it is tempting to approve everything to stop the interruptions. Approving reads, type checks and tests is reasonable. Approving anything that pushes, deletes, installs or touches credentials is not, and the fact that it has been fine forty times is not evidence about the forty-first.

Keep secrets out of the working directory. An agent reading a `.env` to understand a config is behaving reasonably; that value then existing in a log or a prompt is still a leak.

You are still the author

Whatever tool produced it, your name is on the commit. You will be the one debugging it, explaining it in review, and answering for it when it breaks — and 'the agent wrote it' has never once been a useful answer in an incident review.

That is not an argument against using them. It is the reason to use them on work you can check.

What to take from this chapter

  • Autonomy works where there is an objective signal — tests, types, a build
  • Always start from a clean, committed state on a branch or worktree
  • Define scope and an explicit done-when condition, and ask it to stop for review partway
  • Read the diff; the summary describes intent, not what actually changed
  • Approve read and test commands freely; never blanket-approve push, delete or install

Try it

Pick one mechanical change in your repo with a clear done-when condition. Commit, branch, and write the task with explicit scope and stop points. Then read the full diff before merging, and note anything you would not have written yourself.