A WebMCP build about stale plans, exact human approval, and why the failure path mattered more than the happy path.
Rehearse starts with an unsafe temporary-clinic floor plan. The route looks plausible at a glance, but exact geometry finds six risks: two blocked route legs, an obstructed exit approach, two constrained turning spaces, and one object overlap.
A browser agent can inspect that geometry through WebMCP and stage the smallest repair it can find. Six proposed moves appear as ghost shapes. The predicted result passes every configured check.
Then I lock reception in place.
The proposal is now wrong. More importantly, it was approved against the wrong version of reality. When the agent tries to apply it, Rehearse rejects the patch and moves nothing.
That rejection is the part of the project I care about most.
The proposal that should fail
It is easy to build a browser-agent demo where the agent reads a page, calls a tool, and changes something. The happy path looks impressive because it is fast.
The harder question is what happens after the agent has a valid plan but before it is allowed to act.
In Rehearse, the initial scene is revision 1. The agent audits it and stages a six-move proposal against that exact revision. The committed layout does not change. The page shows:
- the proposed object moves as ghost geometry;
- the predicted audit result;
- the base revision;
- a proposal ID; and
- a SHA-256 proposal hash.
The person can inspect the patch before anything consequential happens.
Locking reception is a normal human action, not an artificial error. Perhaps the desk has power, plumbing, or a line-of-sight requirement that the geometry engine does not know about. The lock advances the scene to revision 2.
The six-move proposal still targets revision 1. Rehearse marks it STALE. If the agent calls apply anyway, the command returns a stale-proposal error. The floor plan remains unchanged, and the activity ledger records why the patch failed.
The agent must read the new state and plan again. The replacement proposal contains five moves and excludes reception. Only that current proposal can be approved.
Five tools, but no approval tool
The page exposes five imperative WebMCP tools:
get_layout_staterun_route_auditstage_layout_patchapply_layout_patchverify_layout
There is deliberately no approve_layout_patch tool.
Approval belongs to the visible human interface. The person reviews the current ghost geometry and clicks Approve exact patch. That approval is bound to the proposal hash and current revision. It cannot be reused for a different plan, and it becomes useless if the scene changes again.
This creates a fairly small authority boundary:
- the agent can inspect;
- the agent can calculate;
- the agent can propose;
- the person approves one exact proposal; and
- the agent can apply only while that approval is still current.
The manual controls and WebMCP tools use the same command layer. There is no second, more permissive path hidden behind the demo.
Geometry instead of pixel guessing
The agent does not infer object positions from a screenshot. WebMCP gives it structured scene state in metres: room bounds, object positions, dimensions, locks, current findings, proposal state, and revision numbers.
The deterministic engine runs five planning checks. A bounded-grid A* search evaluates the route, while the repair search moves only eligible, unlocked objects. Stable ordering keeps the same input reproducible.
After the five-move patch is approved and applied, all moves commit atomically. Rehearse reruns the complete audit against revision 3. The route turns green, all five checks pass, and the app produces a receipt containing the before and after revisions, changed object IDs, audit result, and SHA-256 integrity value.
The receipt is not a regulatory certificate. Rehearse is a planning rehearsal, and the constraints are deliberately illustrative. The receipt proves what this engine checked, against which revision, and what changed. It does not pretend to prove more.
Why WebMCP mattered here
Generic browser automation can click buttons and read text. It is much less convincing when an agent needs exact spatial state, a bounded proposal format, explicit failure reasons, and a stable verification result.
WebMCP let the page expose those domain operations directly while keeping the full human interface intact. In a supporting Chrome build, the five tools register natively through document.modelContext. Without WebMCP, the same complete workflow remains available as a human demo.
The app itself has no API key, model call, database, or server requirement. It is a React and TypeScript site deployed as static HTTPS. The interesting part is the contract between the browser agent and the page, not an embedded chat box.
The receipts
The final production flow is:
- Audit revision 1: score 300, six risks.
- Stage the initial six-move predicted-pass proposal.
- Lock reception and advance to revision 2.
- Attempt the old apply and reject it as stale.
- Replan with five moves that preserve reception.
- Approve the exact current proposal in the page.
- Apply atomically and verify revision 3.
- Finish with five of five checks passing and a SHA-256 receipt.
The repository includes eight automated tests, an agent-evaluation catalogue, the native WebMCP testing steps, and the complete source under the MIT licence. The production flow also passed in Chrome with no application console errors, and the interface was checked at large desktop, ordinary laptop, and 390-pixel mobile widths.
AI-assisted development tooling helped with implementation and review; I verified the final behavior through the test suite and the live browser flow.
Try it
- Live app: rehearse-webmcp.netlify.app
- 2:31 demo: Vimeo
- Source and testing guide: github.com/LubuSeb/rehearse
- WebMCP Challenge project: Devpost
The final layout is useful. The stale rejection is the result I trust.



Top comments (0)