All posts

When your user is an agent, the hard part is not capability. It is honesty.

This site is a git repository full of markdown. That was already true. What changed in the middle of July is that an AI can now edit it directly — list the pages, read one, write one, change the theme, build a preview, and hand a human the last button.

The abilities took a few days. Everything after that was one bug wearing different clothes.

The bug

Ask the verifier to check a post. It answers:

problems: []
verdict: looks clean

It had never read the post.

The tool derived the public URL from the file path, guessed the wrong prefix, and requested a page that did not exist. The site answered that request with a **soft 404** — HTTP 200, home page body. So the verifier fetched something, parsed something, found nothing wrong with it, and reported success about a page it had not seen.

Every part of that chain is individually reasonable. Together they produce a green light that means nothing, and the green light is the *only* thing the caller receives.

Why an agent is a worse victim of this than you are

If you had opened that URL yourself, you would have solved it in half a second. Your post is not there, the home page is, something is wrong. You have peripheral vision: you see the whole page, you notice the wrong headline, you feel the mismatch before you can articulate it.

An agent receives the JSON and nothing else. **The tool's self-report is not part of its perception — it is the entirety of its perception.** There is no glance, no "huh, that looks odd," no accidental noticing. A confident wrong field is not a hint to be weighed against other evidence. It is simply what happened, as far as the caller can ever know.

Which means the usual API virtues invert. For a human-facing tool, a slightly optimistic status line is a cosmetic sin. For an agent-facing tool it is a data-integrity failure, because the agent will act on it, report it upward as fact, and a person three steps away will make a decision on top of it.

The same shape, five more times

Once you have the lens, the backlog reads differently. In two weeks:

  • **A build takes a while, so the publish call looked like a hang** — and a hung call reads, to a caller with no clock, as a failure. It now sends a heartbeat, so a working publish stops looking broken.
  • **An unknown OAuth client got a bare HTTP 500**, which any caller correctly interprets as "this service is broken" rather than "you used the wrong client id."
  • **Two different tools reported the same field, computed two different ways**, and so shared one lie between them.
  • **Cloudflare serves a previous deployment per-page for a while after a deploy**, so reading back your own change could hand you the old one, indistinguishable from the new one.
  • **The site had no real 404 page**, which is where the first bug came from — and a soft 404 poisons every verifier that will ever point at the site, not just this one.

None of these were missing features. Every one was the tool being confidently wrong to something that could not check.

The rulers that cried wolf

There is a mirror-image failure, and we shipped that too.

One checker flagged a link-arrow convention and fired on **thirteen pages that were correct**. Another, pointed at an unrelated website as a test, reported **thirty-five problems** on a site that was fine.

A checker that fires on correct work is worse than no checker, and specifically worse for an agent. A person learns "that lint is noisy" and keeps a private discount factor. An agent has no such folklore. It either believes the findings and "fixes" thirteen correct pages, or it learns to skip that field entirely — at which point the one true finding, whenever it arrives, is skipped too.

**Precision is not a nicety in a ruler. It is the whole thing.** A check nobody can act on is noise, and noise in a machine-read channel does not get filtered by taste.

What two weeks actually went into

Almost none of it was new abilities. It was:

  • **Declared blast radius.** Every tool now states whether it is read-only or destructive, so a caller can reason about what it is holding before it pulls.
  • **Optimistic locking on writes.** A save that was composed against an older version is *refused*, not silently applied over whoever wrote in between. With several agents working the same repository, this is the difference between collaboration and a coin toss.
  • **Provable freshness.** You can pass the build id you just made, and the reader will tell you whether the page you are looking at really is that build — or say `STALE READ` and, crucially, tell you not to draw conclusions and not to rebuild, because rebuilding will not make it arrive faster.
  • **A real 404**, so a wrong guess fails loudly instead of succeeding wrongly.
  • **Warnings for content the renderer silently discards**, because "your text is gone and nobody mentioned it" is the same bug at the content layer.
  • **Refusing to guess a public URL at all.** The tool that creates a post used to return one. It was wrong. It now returns a note explaining that only the build knows, which is less helpful and completely true.

That last one is the whole philosophy in one change. **For an agent-facing tool, "I do not know" is a feature, and a confident wrong answer is a defect — and they are the same sentence with the sign flipped.**

How we found all of it

By using it on our own site, for real work, until it hurt. Not a test suite — a person and an agent trying to publish actual pages and hitting actual walls, twice, with the second pass finding the things the first pass had been too polite to notice.

I will put the strongest evidence at the end. **This post was written, verified and published through that tool, by an agent, and during the process the freshness check caught two stale reads and refused to call them clean.** A month ago it would have said `looks clean` both times, and you would be reading a slightly wrong version of this sentence without either of us knowing.

The boring footnote

The editing layer is feelreef — the site's content stays plain markdown in the site's own git repository, which is what makes an agent editing it a safe idea rather than a terrifying one. Publishing to the live domain is deliberately still a human pressing a button.

Keep reading

Notes from the workshop — the door is open.