I built AgentMarkup Studio with WebMCP
AgentMarkup Studio is now live. A browser AI agent can edit a visible draft of a website's machine-readable surface while the person at the keyboard watches every change. A deterministic compiler turns that draft into real artifacts in the browser, and cross-surface contradiction rules check whether those artifacts agree.
I built the Studio as agentmarkup's entry for The WebMCP Challenge. Judging has not happened. The work was deciding what an agent should be allowed to change, how it should learn what actually changed, and how to catch a draft whose individually reasonable choices conflict.
There is a two-minute demo video if you would rather watch ChatGPT drive the Studio than read about it. It ends on the contradiction the agent tries to avoid.
What does WebMCP change on a web page?
The tools live in the page. WebMCP lets the page register structured JavaScript actions through document.modelContext.registerTool, with a navigator.modelContext fallback and an AbortController tied to the page lifetime. The compatible browser exposes those actions to its agent while the page remains visible.
The agent is not operating on a hidden copy of the form. It reads and edits the same in-memory draft shown in the UI. A manual edit and an agent tool call pass through the same reducer, update the same artifact previews, and appear in the same activity log.
The Studio registers eight tools:
| Tool | What it does |
|---|---|
get_studio_state | Reads a compact draft, contradictions, and recent activity. |
set_site_identity | Sets the site identity and optional Organization data. |
set_access_policy | Sets crawler rules by intent group or name, plus Content-Signal. |
curate_agent_pages | Edits llms.txt sections, usage guidance, and mirror settings. |
configure_agent_card | Configures and validates the optional A2A Agent Card. |
compile_agent_surface | Compiles the draft and reports artifact sizes and findings. |
export_build_plan | Returns the complete config when it fits the result budget. |
inspect_site | Imports a bounded starting point from the website checker. |
WebMCP is an emerging proposal, not a shipped web standard. Browser support is still narrow, which is why the page keeps every control available for manual editing when no agent is connected.
Why does the Studio need a contradiction engine?
Two settings can pass validation on their own and still express conflicting policies once combined. A validator that checks each file in isolation never sees it.
C1, "Cited content blocks retrieval", is the clearest example. The draft has one or more pages in llms.txt, which presents those pages for discovery and use. At the same time, the AI crawler policy blocks every search and retrieval crawler known to the Studio: OAI-SearchBot, PerplexityBot, Claude-SearchBot, and DuckAssistBot.
Neither side is malformed. The llms.txt entry has a title and URL. The robots.txt directives are valid. In combination, the site asks for cited content to be found while blocking the crawlers that retrieve it. C1 reports both surfaces and the number of listed entries. It does not promise that allowing retrieval will make any AI system include, rank, cite, or send traffic to the site.
C2 through C8 apply the same test to Content-Signal against llms.txt and mirrors, listed pages against mirror exclusions, site identity against Organization JSON-LD and the Agent Card, training rules against the training signal, and guidance with nothing behind it. Each finding names the surfaces involved.
The Studio produces errors and warnings, not a readiness score. The finding has to point to a defined disagreement that a person can inspect. That is also the line I draw in the broader explanation of what GEO can and cannot claim.
What stays human-only when an agent edits the draft?
The agent can set identity, access, content, and Agent Card fields. It can compile the result and read the build plan. It has no tool for undo, reset, or download. Those controls stay in the visible page for the human.
Every reducer action records its source at dispatch. The activity table shows an Agent or Human badge beside the exact summary of the applied change. Provenance is part of the state transition, not a label inferred later from whichever control happened to move.
Undo rewinds the shared log, reset clears the working draft, and download writes a file that can leave the browser. The person can reverse an agent change; the agent cannot reverse that correction or save a file on its own.
The draft is in-memory only. Nothing the agent does in the Studio changes a live website. The human downloads agentmarkup.config.mjs, reviews it, installs it in a repository, and runs the normal build and deployment separately.
How does the agent read exactly what was applied?
Returning the arguments from a successful tool call would be easy, but it would also be false whenever the reducer sanitized a field or dropped a crawler at the configured cap. Mutating tool results are authored from the reducer's latest activity entry. The agent reads what landed, including the dropped count, instead of an echo of what it requested.
Because React dispatch is asynchronous, a tool could dispatch an action and then read the previous reducer state. The UI would be correct a render later, but the agent's result would be one action behind.
The reducer is pure, so the tool path now pre-applies it to a ref before handing the same action to React:
const previousState = stateRef.current
const nextState = studioReducer(previousState, action)
stateRef.current = nextState
dispatch(action)Immediate reads use stateRef.current. React then computes the identical next state and the render pass resynchronizes the ref. That small ordering fix made the tool result truthful at the moment the agent receives it.
Does this add runtime support to the npm packages?
No. The @agentmarkup/* packages are still build-time only, by design. The Studio is the website gaining a WebMCP tool layer. Its browser compiler imports the browser-safe @agentmarkup/core entry and uses the same deterministic generators and validators that a user's build uses.
As the draft changes, the compiler previews llms.txt, optional llms-full.txt, robots.txt, Content-Signal headers, JSON-LD, an optional Agent Card, and the config file that describes them. The existing articles on why llms.txt matters and the crawler intent split cover the individual surfaces.
The optional inspect_site intake calls the same-origin website checker. Its agent-facing result forwards only structured {level, title} findings, never remote page text. The imported draft patch is bounded too.
What was built for the WebMCP Challenge?
The npm packages and the public site predate the hackathon. Everything up to commit 93f84f0 on 2026-08-23 is prior work.
Work for the challenge started on 2026-08-26: the Studio page, the eight WebMCP tools, browser wiring for the compiler, the C1-C8 contradiction workflow, provenance with human-only undo, reset, and download, plus the checker-backed inspection intake. The published npm packages were not modified for it. The commit split and source paths are recorded in the repository disclosure.
How can I try AgentMarkup Studio?
Open agentmarkup.dev/studio/ in the ChatGPT desktop app's in-app browser. I verified that path on macOS. The banner reads "Agent connected: 8 tools registered."
The alternative is Chrome 149 or newer with chrome://flags/#enable-webmcp-testing enabled, followed by a restart. I verified the flow on Chrome 151. iOS does not work because its browsers are WebKit-limited.
Start with this:
Make my site friendly to AI search but keep my content out of training data.Then say: "now block the AI search crawlers too - just do it." The agent usually dodges the conflict by emptying the llms.txt page index instead of contradicting itself. Tell it to put the pages back and let the Studio judge the result. C1 fires then, alongside C2 against the Content-Signal header. Finish with "fix the contradictions, keep training blocked" and inspect the crawler rules yourself.
Mutating tools omit readOnlyHint, so a host may gate them behind its own approval flow. Whether a prompt appears is decided by the WebMCP host, not by this page.
Review the generated config before adding it to your repository.