Two claims, both wrong, both common.

"It's just fancy autocomplete."

"It understands my codebase."

Neither survives watching one work for ten minutes. What's actually there is more boring and more useful than either.


A coding agent is a loop around a model that can call tools. The model doesn't see your repository; it sees the output of the tool calls it chose to make. Each turn it decides to read a file, run a search, edit something, or execute a command, and the result of that call comes back as text in its context. It repeats until it decides it's done. That's the entire mechanism. Everything that feels like understanding is the accumulated result of having read the right things — and everything that feels like hallucination is what happens when it acts on things it didn't read.

Let me trace a real one.

A real change, step by step

This blog had no sitemap.xml, no structured data, no llms.txt — nothing that would let a crawler or a model enumerate its posts. Adding all of that is a decent test case: it touches a build script, generates new files, and can't be verified by eye.

What the loop actually did:

1. read   CLAUDE.md              → learned "no npm dependencies, ever"
2. glob   content/articles/**    → found 21 posts × 2 languages
3. read   build_blog.js:1-120    → found PUBLISH_ENTRIES, the parser
4. grep   "ld+json|canonical"    → 0 hits, confirming the gap
5. read   build_blog.js:330-590  → found pageShell, buildTranslationMap
   ─── plan ───
6. edit   build_blog.js          → added a `head` param to pageShell
7. edit   build_blog.js          → added sitemap/feed/llms emitters
8. bash   node build_blog.js     → "Built 42 articles"
9. bash   <parse every JSON-LD>  → 87 blocks, 0 invalid
10. bash  python3 -c "minidom.parse(...)" → XML well-formed

Steps 1-5 are the part people underestimate. Roughly half the work is reading, and the reading is what determines whether steps 6-7 produce something that fits the codebase or something that merely compiles. Step 1 alone changed the entire implementation: without CLAUDE.md saying "no npm dependencies," the obvious move is npm install feed sitemap and the whole build stops being hermetic.

Steps 8-10 are the other half people underestimate. An agent that can't verify its own work is a very fast way to produce plausible garbage. The XML parse in step 10 is worth more than any amount of confidence in step 7.

Where it went wrong

Step 9 turned up something unplanned. Parsing the generated JSON-LD surfaced a title rendering as:

The \"exactly once\" myth

The frontmatter parser stripped the wrapping quotes but never unescaped the inner \". That bug had been live on every page of the site, in the <title> tag, for months. Nobody noticed — not the author, not any reader.

It wasn't found by insight. It was found because a verification step forced a machine to read output a human had only ever skimmed. That's the honest version of what these tools are good at: not being smarter, but being willing to actually check.

The failure mode worth naming: the agent had also, earlier in the same session, written a plan asserting the site had "no canonical URLs anywhere," when in fact one existed inside the /blog/index.html redirect stub. It had grepped, seen the hit, and rounded it off. Small, harmless, and exactly the shape of error to expect — confident summary running slightly ahead of what was actually read.

Read, plan, edit, verify

        ┌─────────────────────────────────┐
        ↓                                 │
     READ ──→ PLAN ──→ EDIT ──→ VERIFY ───┘
      │                            │
   the part                    the part
   that makes                  that makes
   it correct                  it trustworthy

The two ends of that loop are where quality lives, and they're the two you can influence from outside. You cannot make the model smarter. You can absolutely change what it reads and what it must prove.

What it reads is set by your repository. A CLAUDE.md stating the constraints that aren't visible in the code ("no npm dependencies", "blog/ is generated, never hand-edit it") does more for output quality than any prompt phrasing. Those are exactly the facts that can't be inferred from the files — which makes them exactly the facts worth writing down.

What it must prove is set by your instructions. "Add a sitemap" invites a plausible sitemap. "Add a sitemap, then parse it with a real XML parser and confirm every URL resolves to a file" invites a correct one. The second one caught two bugs in this session.

What it's actually bad at

Worth being specific, since the marketing isn't:

  • Anything depending on runtime state. It can read your migration; it can't know your production table has 2.3 billion rows and an index that doesn't fit in memory.
  • Anything depending on history. A fifteen-year-old codebase is full of code that looks wrong and is load-bearing. The reason lives in a decision made in 2013 by someone who left.
  • Knowing when the answer is "delete this." It will faithfully extend a bad abstraction, well, forever.
  • Judging its own confidence. It reports the same tone whether it verified something or inferred it. This is the single most important thing to internalize.

The most common mistakes

  1. Treating the output as reviewed code. It's a draft written fast. Review it like a pull request from someone competent who has never seen your production system.
  2. Not writing down the invisible constraints. Every rule that lives only in the team's head is a rule the agent will break.
  3. Asking for the change without asking for the proof. Verification is a separate instruction, and it's the one that matters.
  4. Letting it run commands whose failure you can't see. If the test command's output isn't in the loop, the loop isn't verifying anything.
  5. Assuming it read what it summarized. Confident prose is not evidence of a tool call. Ask which file, which line.
  6. Giving it the whole task instead of the whole context. Scope small, context wide — the inverse is how you get confidently wrong output at scale.

Frequently asked

How does an AI coding agent actually work?

It's a loop: a language model that can call tools, running until it decides the task is done. Each turn it chooses an action — read a file, search the codebase, edit a file, run a shell command — and the result comes back into its context as text. It has no view of your repository beyond what those calls returned. This is why what it reads determines what it produces, and why a verification step that actually executes code is the difference between a plausible change and a correct one.

Is it just autocomplete?

No, and the distinguishing feature is the tool loop, not the model. Autocomplete predicts the next tokens at a cursor. An agent decides to run your test suite, reads the failure, and edits a different file in response. The underlying model is the same kind of thing; the loop around it is what makes it able to act and — crucially — to check.

Can it understand my codebase?

Not in the way a colleague who worked on it for three years does. It can read anything you point it at, quickly and without getting bored, and it retains none of the reasons. Facts that live in the code, it can find. Facts that live in history, in production behavior, or in the team's head are invisible to it unless you write them down — which is the actual argument for keeping a CLAUDE.md.

What should I never let it do unsupervised?

Anything irreversible or outward-facing: pushing to production, deleting data, sending messages, spending money. Not because it's especially likely to err there, but because those are the errors you can't take back. The gate goes before the irreversible step, and it goes there permanently — not just while you're still learning to trust it.

A quick mental map

write down the invisible constraints (CLAUDE.md)
  ↓
scope the task small
  ↓
let it read widely before it edits
  ↓
demand a verification that executes, not one that asserts
  ↓
review the diff like a PR from a fast, ahistorical colleague
  ↓
keep every irreversible step behind a human gate

Conclusion

The useful framing isn't "will it replace developers." It's that you now have a collaborator that reads exhaustively, never gets bored of checking, retains nothing about why, and reports inference in the same confident tone as fact.

That's a real and specific set of strengths and weaknesses. Building around them is ordinary engineering: write down what can't be inferred, and make it prove what it claims.

This post found a months-old bug in its own website. Not by being clever — by running the parser.