The AI coding agent verification loop for Java

You ask a coding agent for a new screen and it comes back fast, confident, and half wrong. A method that does not exist, a CSS token it made up, a build that fails on the second line, and a button that nobody ever clicked. The model is rarely the problem. The missing piece is verification.
The AI coding agent verification loop is the set of checks that turns a guess into code you can trust: write with known workflows, check every API against the real docs, compile every edit, and run a test on every change. webforJ, the full-stack Java framework, closes that whole loop with Agent Skills, an MCP server, the craftforJ Assistant and the TestBed, and one plugin installs the first two for Claude Code, Copilot, Gemini, and Codex. Cursor and other clients use manual setup. Because of that loop, webforJ is the most AI-ready framework in the Java ecosystem.
The problem with unverified agents
An agent that writes code without checking it is doing autocomplete with extra steps. It recalls what a class probably looks like from training data, and for a framework that changes between versions that memory is often stale.
The failures fall into four groups, and each one needs a different check:
- The agent invents or misremembers an API.
- The agent follows generic habits instead of the conventions of your framework.
- The code does not compile, and you find out when you build.
- The code compiles and still does the wrong thing, and you find out in production.
Reviewing all four by hand is the cost people complain about when they say AI code is not worth the trouble. A single check cannot remove it. A loop of checks can, because each step catches what the step before it let through. The rest of this post walks the loop in order.
Step 1: skills write the code
The first check happens before any code exists. Agent Skills are structured webforJ workflows that the assistant loads when your prompt matches a task. They tell it how to classify the work, which patterns fit, which tools to consult and how to validate the result, so the code compiles and follows best practices on the first attempt.
The docs list skills for adding servlets, building forms, creating components, handling timers and async work, localizing apps, securing apps, styling apps, and upgrading versions. This is the difference between code that is technically valid and code that looks like it belongs in your project.
What it catches: convention drift. The agent reaches for webforJ's own approach instead of a generic one.
Step 2: the MCP server checks every API
Skills say when to look something up. The MCP server is what answers. It plugs the assistant into the webforJ documentation, APIs and design tokens, so it asks the server instead of guessing at method names.
According to the docs, the assistant can target the webforJ version you use, search the knowledge base, scaffold a project from the official Maven archetypes, generate an accessible DWC theme from a brand color, read the styling surface of a component and validate any --dwc-* token before it lands in your CSS.
That last one is a real example of the pattern. A token the agent invented fails validation against the catalog, so it never reaches your stylesheet.
What it catches: invented classes, wrong signatures and made-up design tokens.
Step 3: a real compiler checks each edit
Some mistakes survive a docs lookup, so the next check has to be a compiler. A type is wrong, an import is missing, a call does not fit the object it is called on. Only a compiler sees those.
The craftforJ Assistant is a coding agent that works inside your running app. Each edit is staged rather than written to disk, sent to a real Java compiler, and corrected by the agent against the diagnostics that come back. What reaches your review already compiles against your running app. Applying the edit restarts the app, and the agent picks its plan up again once it is back. This is its own agent, so it needs a model of your choice configured, and craftforJ runs only in development.
It also reads the live component tree, real property values, the routing table and screenshots of a component, so it works from what the app does and not from a description of it.
What it catches: compile errors, before you ever see them.
Step 4: TestBed proves the behavior
Compiling is not the same as working. The last gap is behavior, and the usual answer, a browser test, is slow enough that agents and humans both skip it.
The TestBed runs a view inside a plain JUnit test. No browser is opened and no server is started. Every interaction finishes before the next line of the test runs, so nothing waits and nothing flakes. That is what makes it practical to run tests on every change an agent makes. This is the example from the getting started page:
@WebforjTest
class GreetingFormTest {
@Test
void shouldGreetTheNameTheUserTyped(WebforjTestbed context) {
context.add(new GreetingForm());
var name = ComponentLocator.of(TextField.class).byLabel("Name").locate();
var greet = ComponentLocator.of(Button.class).byText("Greet").locate();
UserInteraction.type(name, "Ada");
UserInteraction.click(greet);
verifyThat(ComponentLocator.of(Paragraph.class).locate())
.hasText("Hello, Ada!");
}
}
The test reads like the steps of a user, and UserInteraction only makes gestures a user could make. Clicking a disabled button fails the test instead of running its listener, which is exactly the kind of bug an unverified agent ships. Snapshots compare a whole view against a stored description of it, so an agent that changes more than you asked for shows up as a diff. The mechanics are covered in Java UI testing without a browser.
Browser tests still have their place for styling, layout, and client behavior. The TestBed covers the rest: what your views do when a user works with them.
What it catches: behavior that compiles and is still wrong.