The framework your AI agent already understands
WebJs is a full-stack JavaScript framework with no build step, so nothing is hidden from your agent. The framework ships in node_modules as plain JavaScript, so an agent opens the file it is calling instead of recalling an API from training data, and your app code is served to the browser exactly as written. Any model debugs the running app against the real source, on the web components and standard HTML it already knows.
Nothing is hidden behind a build step
No build step means two things, and both help your agent. The framework itself sits in node_modules as plain JavaScript with JSDoc, so an agent opens the file it needs at the version you installed, rather than recalling an API from training data. And your own app code is served to the browser exactly as written, so the agent debugs the running app against the real source, never a bundled or minified artifact.
The framework, readable in node_modules
$ ls node_modules/@webjsdev/core/src
component.js html.js render-client.js
css.js directives.js render-server.js
serialize.js router-client.js
$ grep -rn "renderToString" node_modules/@webjsdev
core/src/render-server.js: export async function renderToString(
server/src/ssr.js: const html = await renderToString(tree)
# plain .js with JSDoc. the agent greps the
# framework source straight from node_modules.
Your app code, served to the browser as written
$ curl localhost:5001/components/counter.ts
import { WebComponent } from '@webjsdev/core';
class Counter extends WebComponent({ count: Number }) {
increment() { this.count++; }
}
Counter.register('counter');
# your source, served unbundled. what the
# agent wrote is what the browser fetched.
Four reasons the loop just works
Every one of these falls out of a single decision: no build step, on web standards.
What you write is what runs
No build, no bundler, no minifier. Source files are served as native ES modules, so the code your agent reads on disk is byte for byte the code running in the browser. It debugs against reality, never a compiled or source-mapped artifact.
The whole stack is a grep away
The framework ships as plain JavaScript with JSDoc under node_modules. An agent can open @webjsdev/core, follow SSR into @webjsdev/server, and trace a bug end to end without leaving the repo. The answer is always in the working tree.
No training data required
An agent does not need to have seen WebJs before. It opens the file it is calling in node_modules, learns the real API from the code, and starts producing correct output. New model, same result, because the source is the documentation.
Standard HTML and JavaScript
WebJs is built on web components, custom elements, SSR, and forms. Every model, small or large, is already trained on the platform primitives, so the muscle memory transfers instead of fighting a bespoke abstraction.
The prompt does not have to carry the architecture
Most frameworks leave the big decisions open, and that flexibility is the point of them. But an open decision has to be closed by somebody, and when an agent is writing the code, that somebody is whoever wrote the prompt. So the request grows an appendix of technical instructions, and every one of them is a thing you had to know to ask for. WebJs has already made those calls, so the request stays the request.
Where the decisions are still open
> Build me a table booking app
and put the data in a real database,
use a design system, and write
production ready code and architecture
Where they are already made
> Build me a table booking app
# that is the whole prompt. the rest
# is not left to the model to guess,
# so it is not yours to specify.
Both prompts should produce something you can put in front of customers. Only one of them made that your job to spell out.
Architecture
Where a page lives, where a form submission is handled, and which code is allowed to touch the server are settled by the framework, not improvised per app. The result comes out in the shape a reviewer expects.
Code
Server-rendered pages that work before any script loads, and no build step in between. Running webjs check catches what is outright wrong before it ships, so a mistake surfaces as a failing command rather than as a bug a reader has to find.
Type safety, end to end
Types run the whole way through. A component importing a server function keeps that function's argument and return types at the call site, and a database row carries its schema type into the markup that renders it, with no code generation anywhere in between. An agent has no reason to reach for any.
Database
A scaffolded app is wired to a real database with a schema and migrations from the first command, so an agent reaches for that rather than a list of items living in the code. Swap the database later if you want a different one.
Design system
A palette and a type scale ship as design tokens rather than values scattered through components, so every screen the app grows shares them and restyling the whole thing means editing the tokens, not hunting through the markup.
Agent skills
A scaffolded app ships a skill its coding agent reads on demand, covering the design system, the modules architecture, and the rest of the conventions. One source, understood by Claude Code, Cursor, Copilot, and opencode alike, so the agent looks up how this app is meant to be built instead of importing habits from another framework.
Opinionated is the point, and none of it is a cage. Light DOM components, Tailwind, and Drizzle on SQLite are what a scaffolded app starts with, because something has to be chosen and leaving it open is what pushed the decision into your prompt. Reach for a different ORM, a different database, or a different way of styling and the framework does not object. What you are opting out of is a default, never a dependency the rest of it is built on.
Experiment with any model, freely
Because the framework itself is the context, you are not locked to the one model that happened to memorize a given API. Point a large model or a small one at a WebJs project and it fits the source into context and gets to work. Switch models between tasks and the output stays reliable, because they are all reading the same readable code.
That shows up in the quality of what comes back, not only in whether a model can participate. Routing, the server boundary, and the file layout are settled by convention, and the palette lives in design tokens the root layout sets once, so a smaller model is filling those in rather than inventing them. Taste is still yours to direct, and you still read what an agent hands you. What you stop doing is re-deciding the shape of the app every time you switch.
Human developers get the same deal. There is no hidden compiler output to reverse engineer when something breaks. You open the file, read the JavaScript, and see exactly what ran.
Point your agent at WebJs
Scaffold a full-stack app in one command, then let any model read the source and build. Pages, an API, components, and a database, all on web standards.