Skip to content

NevaMind-AI/html-in-the-loop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HTML in the Loop

html-in-the-loop is a local MCP server for agent-generated interactive HTML.

It lets Claude Code or another MCP client:

  1. Create a local browser session.
  2. Render self-contained HTML in a sandboxed iframe.
  3. Capture user clicks, input changes, form submissions, and custom AgentBridge.emit(...) events.
  4. Return the structured browser interaction to the agent as the next input.

Install

From this repo:

npm install
npm run build

Add it to Claude Code:

claude mcp add html-in-the-loop --scope user -- node /absolute/path/to/html-in-the-loop/dist/index.js

For this checkout, that will usually be:

claude mcp add html-in-the-loop --scope user -- node /Users/chenhong/project/html-in-the-loop/dist/index.js

Tools

  • create_session: starts the localhost runtime and returns a session URL.
  • render_html: renders or replaces the HTML for a session.
  • wait_for_interaction: waits for the next structured user interaction.
  • get_events: reads stored events, including events created after a wait timed out.
  • get_session_state: inspects a session.
  • list_sessions: lists active sessions.
  • close_session: closes a session.

The local web runtime listens on 127.0.0.1. It uses port 17321 by default and tries nearby ports if that port is busy. Set HTML_IN_THE_LOOP_PORT to choose a different starting port.

Generated HTML Contract

Generated HTML can emit events manually:

<button onclick="AgentBridge.emit('choose_plan', { plan: 'pro' }, { step: 2 })">
  Choose Pro
</button>

Or use data attributes:

<button
  data-agent-event="choose_plan"
  data-agent-payload='{"plan":"pro"}'>
  Choose Pro
</button>

Forms emit all fields automatically. If data-agent-event is omitted, the event type defaults to form_submit:

<form data-agent-event="submit_preferences">
  <input name="audience" value="developers">
  <button type="submit">Continue</button>
</form>

Standalone controls also emit committed input changes automatically:

<input name="topic" placeholder="What should the agent work on?">
<textarea name="notes"></textarea>
<select name="priority">
  <option>low</option>
  <option>high</option>
</select>
<div contenteditable data-agent-name="freeform_notes"></div>

These controls emit field_change events, while contenteditable regions emit content_edit. Inputs inside a form include both the changed field and the current form fields in the payload. The bridge supports text, search, email, number, range, checkbox, radio, date/time, color, file metadata, textarea, select, multi-select, and contenteditable inputs. Add data-agent-input-event="custom_type" to override a field-level event type, or data-agent-ignore on a subtree to opt out.

The event returned to the agent has this shape:

type AgentHtmlEvent = {
  id: number;
  source: "html-in-the-loop";
  session_id: string;
  type: string;
  payload: Record<string, unknown>;
  state?: Record<string, unknown>;
  timestamp: number;
  html_version: number;
};

Claude Code Usage Pattern

Ask Claude Code something like:

Use html-in-the-loop to make an interactive PRD direction picker.
After I choose one direction in the browser, continue writing the PRD from that event.

The agent should:

  1. Call create_session.
  2. Generate HTML and call render_html.
  3. Tell you to open the returned URL.
  4. Call wait_for_interaction.
  5. Continue from the returned event.

Security Model

  • Generated HTML is rendered inside a sandboxed iframe.
  • The iframe is not granted allow-same-origin.
  • Events are accepted only from the session URL using a per-session token.
  • Event payloads are capped at 64KB.
  • HTML payloads are capped at 1MB.
  • The local server binds to 127.0.0.1, not a public interface.
  • Do not put secrets into generated HTML.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors