cd /news/ai-agents/why-i-stopped-handing-agents-a-frame… · home topics ai-agents article
[ARTICLE · art-134490] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Why I stopped handing agents a framework

A developer who has shipped Vue and Angular SPAs describes building @relax.js/core, a small Web Component library with routing, forms, templates and dependency injection and no virtual DOM, specifically so that coding agents can work in it reliably. The developer argues that explicit, greppable code with failure locality and reviewability suits agents better than framework schedulers, since agents cannot open a browser and only see files, type checks and tests. The library ships short agent-facing "skills" files that call out habitual mistakes, such as marking connectedCallback async or adding a duplicate submit listener.

by read5 min views2 publishedSep 19, 2026

I have shipped SPAs in Vue and in Angular. Today most of the UI code in my projects is written by a coding agent, and the library underneath is one I wrote myself: @relax.js/core, a small Web Component library with routing, forms, templates and DI, and no virtual DOM.

That is a strange choice on paper. This series is about why it works, where it does not, and what I had to build to make it work.

An agent has seen millions of Vue components and Angular modules in training. Its first draft of a Vue SFC is usually right. Its first draft of a Relaxjs component is usually wrong :O It carries habits over. It marks connectedCallback as async and expects the browser to wait. It reaches for a reactive store. It adds its own submit listener next to the one the library already owns.

The core skill that ships with the library opens with this sentence, because it is the failure mode:

Patterns carried over from React compile, type-check and do nothing.

I have not written React myself, but I have watched agents write it unprompted, and it is what they reach for when nobody tells them otherwise.

There is a second point against me. Angular's compiler type-checks templates. vue-tsc does the same for Vue SFCs. A typo in a template is a build error before anything runs. In a library where the template is a string, {{user.naem}} is just a string until the page renders. I will come back to that in a later article, because it bothered me enough to fix.

So: worse priors, and until recently weaker static checking. Why bother?

An agent cannot open a browser. It reads files, greps for names, runs the type checker and runs the tests. That is the whole feedback loop. Anything that is only observable at runtime is invisible to it.

Now think about the bugs I spent the most time on in Vue and Angular, the ones that survived review:

watch that fired one tick later than I thought, so the DOM showed the previous value.ngOnInit that assumed an @Input that arrives on the next cycle. None of these are visible in the file where the symptom appears. The cause is in the framework's scheduler, and you find it by opening DevTools, setting a breakpoint and watching. An agent cannot do any of that. It will reason about the file it opened, conclude that the file is correct, and start changing things speculatively. That is the most expensive thing an agent does: producing plausible edits in the wrong place.

Explicit code does not have that class of bug. When the update is this.nameSpan.textContent = user.name at the place where user changed, the update is where the change is. A reviewer can verify it by reading. So can an agent. Nothing decides later whether it ran.

The usual pitch for a small library is "the whole thing fits in the context window". True, and beside the point. An agent rarely needs to read a framework's source; it needs correct memory of the framework's behaviour, and that memory rots with every major version.

The three properties that matter:

Failure locality. The bug is in the file that shows the symptom. No scheduler, no dependency graph, no zone.

Greppability. A typed event class is one grep away from every producer and every consumer. r-click="save()" in a template is one grep away from save. Agents navigate by search, and a connection that is not a shared literal name is a connection the agent will guess at.

Reviewability. The diff says what will happen. Not what the framework will decide to do with it.

Small and explicit is not enough on its own. Three things turned "an agent can in principle work here" into "an agent does work here":

Skills, not docs. The library ships a set of short files an agent loads before it starts, and every sentence in them is something an agent gets wrong from habit. The docs explain how things work; the skills say what you will get wrong. The border between them is stated, and it is worth reading.

Silence turned into errors. A template that cannot resolve a path renders an empty string. For a human that is a blank spot on the page; for an agent it is a green test. Every such quiet failure now reports through one error channel, and a test helper turns the channel into assertions.

A checker. npx @relax.js/core check resolves every template expression against the TypeScript types at the call site and prints tsc-style lines. That closes most of the gap with Angular's template type-checking, and it does so without a compiler in the build.

Then the test seam: `mount()`, `flush()`, `fakeServer()`, `mountRouting()`. The agent verifies by running vitest, not by asking me to click.

If the agent's zero-shot correctness is the whole game, meaning nobody reviews the diff and no skills get loaded, Vue or Angular wins on priors alone. If the app is large with deeply interdependent state, the reactive engine earns its complexity, and I said as much in the library's own README. If you need SSR, there is nothing here for you.

For a small-to-medium SPA where a human reads what the agent wrote, I have found the explicit model cheaper every time, and the rest of this series is the evidence.

Next: what a skill is and why it is not documentation.

── more in #ai-agents 4 stories · sorted by recency
── more on @@relax.js/core 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/why-i-stopped-handin…] indexed:0 read:5min 2026-09-19 ·