Skip to content
Lab / Building AllStillGood / 02
AIEngineeringBuild in public

AI agents are fast at plausible. That's the part to watch.

How we actually use coding agents — a Figma file turned into components, debugging by hypothesis — and the day one confidently recommended a security control that wouldn't have seen a single request.

Aug 2, 2026Daniel5 min readAllStillGood

"Add IP-based rate limiting to the auth flow." The agent read around the repo for about as long as it takes to read this sentence and came back with an answer: put a rule in the Cloudflare WAF. The domain was managed through Cloudflare. The project already used Turnstile. It fit.

It was also, as things were wired at the time, a control that might never have seen a single one of those requests.

Nothing about that answer was stupid, and that's exactly why it's worth writing down.

What we actually use them for

We use AI coding agents mainly as a pair programmer and as a fast way to get oriented in a codebase — implementation, debugging, code review, and arguing through different technical approaches before committing to one. We still review what comes back and make the final call ourselves. That isn't a disclaimer bolted onto the end; it's the shape of the whole workflow.

A design file, turned into components

The clearest win is frontend work. When we need to build a new interface, we can let the agent read the design through a Figma MCP server, or hand it the design context some other way, and it will produce a first pass — the components, the layout, the reusable structure underneath.

What comes back is a starting point, not a result. We go through it for the things a design file never says out loud: where the component boundaries should actually sit, how it behaves between breakpoints, whether it can be operated from a keyboard, and what it does when the data is empty, slow, or wrong. Those last ones are usually the difference between a screen that demos well and a screen that survives.

The gain isn't really "code written faster." It's that we get to the data integration and the product logic days earlier, instead of spending that time hand-building components we already knew how to build. The well-understood, tedious part is the part worth handing over.

Debugging by hypothesis

The other genuine strength is search. An agent can go through a large repository far faster than we can by hand.

The pattern that works for us: describe the problem, say what we currently think is causing it, and ask it to trace the relevant files and the data flow. It comes back with the places that could plausibly be involved. We read those findings, discard the ones that don't hold up, form the next hypothesis with it, and then test the proposed fix.

What makes that work is treating it as an investigation with several rounds rather than a diagnosis. The first answer is a lead. Accepting the first answer is how you end up carefully fixing something that was never broken.

The rate limiter that wouldn't have run

Then there's the failure mode, which is the actual reason for this post.

On one project we wanted IP-based rate limiting on the authentication flow. The agent looked around, noticed that the domain was managed through Cloudflare and that the project used Turnstile, and immediately recommended a Cloudflare WAF rule. Confident, specific, and the kind of answer you nod along to.

What it hadn't done was establish where the requests actually go. The app was hosted on Vercel, and having a domain's DNS at Cloudflare is not the same thing as having traffic proxied through Cloudflare. A record can resolve the name and send the visitor straight to the origin, in which case Cloudflare never sees the request again. A rule in front of a path nothing travels isn't a control; it's a screenshot of one.

Turnstile didn't settle it either. It's a widget in the page plus a server-side verification call, and it works the same whether or not anything sits in front of your origin. Two pieces of circumstantial evidence had been treated as a conclusion about the request path.

Once we pointed at the deployment context, the conversation got useful. We went back through the options with the real request path in mind — a rule at the platform edge using Vercel's firewall, or a rate limiter in the application itself, sitting where the request definitely arrives — and weighed them properly instead of taking the first thing that fit.

Plausible is not verified

The lesson isn't "don't trust AI." It's narrower than that, and more useful.

An agent is very fast at producing a solution shaped like the problem. When a piece of context is missing, it doesn't stop and ask — it fills the gap with the most reasonable-looking assumption and carries on, at exactly the same confidence as everything else it says. There is no tonal difference between something it verified and something it inferred. That's the part to watch, and it isn't a bug you can prompt your way out of. It's what the tool does.

The failure isn't wrong code. It's a right-sounding answer resting on a fact nobody checked.

So for anything touching infrastructure, security, or data access, we now ask for the same sequence: inspect the current architecture, state your assumptions, compare the available options — and only then make a recommendation. Make it say what it believes about the environment before it says what to do about it. An assumption written down is cheap to correct. The same assumption buried inside a recommendation is not.

For frontend work and most day-to-day implementation we don't bother with any of that. Being wrong there is visible immediately and costs nothing. The discipline should scale with what it costs to be wrong.

The same idea, built into the product: findings come out as a brief written for the AI tool you build with, so the agent starts from checked context instead of inferring it.

That gap — a confident answer nobody checked against reality — is the one AllStillGood was built around. It's the same mechanism behind the check in the first post of this series: an app can pass every test you thought to run, deploy green, and still be readable by strangers. A green deploy is a story about your app, not a verification of it.

Different scale, same habit. Check the thing itself rather than the story about the thing — and check it again after the next change.