ERI Specification — Embedded Result Interface

Version: 1.0  |  Status: Stable  |  License: MIT  |  Stability: Level 1 core workflow is stable — we commit to no breaking changes. Changelog

Quick Start — Ship in under a day
  1. Create an embed page — HTTPS, reads state from URL params (10-line example · hello-world.html)
  2. Write a skill.md — tell the Agent how to call your API and construct the embed URL (template · real example)
  3. Ship it — works on most platforms today. No SDK, no approval cycle.

1. Definition · Checklist · 2. Workflow · 3. Conversation Flow · 4. Skill Authoring · 5. Embed Page · 6. Security · 7. Levels · 8. Use Cases · 9. Limitations · 10. Error Handling · 11. Landscape · Governance

1. Definition

AI Agents output text. ERI (Embedded Result Interface) lets them embed interactive UI instead — using only a skill.md and a URL.

Design principles: no new protocol, no runtime dependency, works on any platform that renders iframes — build it once, deploy it everywhere.

RoleResponsibility
AgentUnderstands intent, calls API, constructs embed URL, outputs UI
ProviderWrites skill.md and provides an HTTPS embed page (see minimal example)
PlatformRenders iframes (most already do)

Snapshot-based — the Agent does not monitor the output UI. Each new instruction generates a fresh embed (see Section 3). The third-party app runs independently — it only needs to provide an HTTPS page.

Conformance — an implementation is ERI-compliant at Level 1 when: (1) the Provider serves an HTTPS embed page that reads initial state from URL parameters; (2) the Agent follows the four-step workflow; (3) the Platform renders the iframe with sandbox="allow-scripts". No registration, no certification.

Level 1 Self-Certification Checklist

Add a badge to your README: [![ERI Compatible](https://img.shields.io/badge/ERI-Compatible-6366f1)](https://github.com/2234839/eri-spec) ERI Compatible

2. Workflow

1. UnderstandExtract intent
2. Call APIGet structured data
3. Construct URLEncode params
4. Output UIiframe / plain text

Steps 2 and 4 involve external systems:

Call API Agent — The Agent calls the third-party app's API from the server side (not from the user's browser). Standard HTTP, structured JSON. No CORS (Cross-Origin Resource Sharing) configuration needed.

POST /api/calculate
Body: {"expr": "99.5 * 3"}
Response: {"expr": "99.5 * 3", "result": 298.5}

Output UI Agent Platform — The Agent outputs an iframe. Most web-based Agent UIs render iframes with automatic sandbox attributes. Unsupported platforms degrade to plain text.

<iframe sandbox="allow-scripts" src="https://app.example.com/embed#encoded_data" width="100%" height="300"></iframe>

3. Conversation Flow

Iframe edits don't notify the Agent. On each new turn:

  1. Agent reads previous results from context
  2. Combines new input with context, calls API again
  3. Outputs a fresh embed (old one is not updated)

Context comes from the Agent platform's conversation history — the Agent sees its own previous text output (including API results). No special state mechanism needed.

User: "Calculate 3 items at $99.5 each"
Agent: Calls API → outputs iframe showing 99.5 * 3 = 298.5

(user modifies values in the iframe — Agent is unaware)

User: "Add 8% tax"
Agent: Reads context (last result: 298.5), calls API with 298.5 * 1.08
       → outputs new iframe showing 298.5 * 1.08 = 322.38

4. Skill Authoring Provider

Place a skill.md file where the Agent can discover it — custom instructions, GPT actions, Claude skill files, or any platform-provided mechanism for defining Agent behavior. The format is the same across all platforms.

A minimal ERI Skill:

---
name: tool-name
description: What this Skill does
---
## Workflow
1. Extract parameters from user input
2. Call API: POST https://api.example.com/calculate
   Body: {"expr": "expression"}
3. Encode API response as URL hash
4. Output as iframe: https://app.example.com/embed#<encoded_response>
   (fallback to plain text if platform cannot render)

The frontmatter (name, description) follows standard YAML convention. The body section heading (## Workflow, ## 工作流, or any heading you choose) and its content are freeform — write in whatever natural language the Agent understands. The format is plain Markdown.

PlatformWhere to place skill.md content
ChatGPTCustom Instructions, or GPT Actions in a custom GPT
ClaudeClaude Code: CLAUDE.md or .claude/ skill files. Claude.ai: Project instructions.
GeminiSystem Instructions (Gemini API or Google AI Studio)
Custom AgentAny mechanism for defining Agent behavior (system prompt, config file, etc.)

Complete examples: NoteCalc (real implementation) · Template (copy and fill in).

5. Embed Page Requirements Provider

RequirementDescription
HTTPSMust serve over HTTPS
URL param readingRead initial state from URL hash (recommended) or query params. Recommended encoding: encodeURIComponent(JSON.stringify(data)) — but any format the embed page understands is valid.
Self-containedHandle all interactions internally. No host JS/CSS dependencies. Responsive layout.
Accessibility (recommended)ARIA labels, keyboard navigation, focus management. Follow WCAG guidelines where practical.
Level 2 bridge (optional)Implement ui/* JSON-RPC bridge for bidirectional communication — see Section 7
Theme adaptation (optional)Read URL params or host colors to match light/dark theme
Iframe sizing (recommended)Design for a responsive width (agents typically set width="100%"). Default height of 300–400px works for most embeds. For Level 2, use the ui/message JSON-RPC method to dynamically adjust height.

Minimal Embed Page Example

The Agent calls the API server-side and passes the result to the embed page via URL hash. The page only renders — no computation inside the iframe.

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1"></head>
<body>
<div id="out" style="font-size:24px"></div>
<script>
  const raw = decodeURIComponent(location.hash.slice(1));
  try {
    const data = raw ? JSON.parse(raw) : null;
    document.getElementById('out').textContent =
      data ? data.expr + ' = ' + data.result : 'No data';
  } catch (e) {
    document.getElementById('out').textContent = 'Unable to load results.';
  }
</script>
</body>
</html>

This minimal example renders a result, handles empty state, and catches malformed data. For a working page you can open right now, see hello-world.html — it reads a name from the URL hash and lets the user edit it. A production embed page adds responsive layout, input validation, and theme adaptation.

6. Security

RoleRules
PlatformAdd sandbox="allow-scripts" to iframes. Warning: adding allow-same-origin together with allow-scripts lets the iframe access its own origin's cookies and storage — only use it if the embed page needs its own cookies/storage. The iframe still cannot access the parent page across origins. Never pass user credentials to third-party iframes. If the platform uses Content Security Policy (CSP), add the embed page's origin to frame-src.
ProviderDon't rely on document.cookie (may be unavailable in sandbox). Don't use window.opener or window.top for navigation/DOM access (window.parent.postMessage for Level 2 is safe). Sanitize all inputs against XSS (Cross-Site Scripting). Never place PII (Personally Identifiable Information) or sensitive data in URL hash/query params — URLs are logged in browser history, proxy logs, and referrer headers. For sensitive data, pass a short-lived token in the URL and fetch actual data via an API call inside the embed page.

7. Progressive Levels

LevelCapabilityWho needs to act
0Plain text outputAgent only — nothing else needed
1iframe embeddingProvider embed page + Platform iframe support (most already have this)
2Bidirectional communicationLevel 1 + Provider Platform both implement MCP Apps host bridge (ui/* JSON-RPC 2.0 over postMessage)

Use Level 2 when the platform must react to user edits inside the iframe (e.g. auto-save, live previews). ERI Level 2 uses the same ui/* JSON-RPC 2.0 bridge defined by MCP Apps — no custom message format. This means an ERI Level 2 embed page is directly compatible with MCP Apps–enabled platforms.

MethodDirectionPurpose
ui/initializeplatform → iframeHandshake: platform sends session info and capabilities
ui/notifications/tool-inputplatform → iframeDelivers tool call input arguments to the iframe
ui/notifications/tool-resultplatform → iframeDelivers tool execution result back to the iframe
tools/calliframe → platformiframe requests the platform to call a tool
ui/messageiframe → platformiframe sends a follow-up message (e.g. user edited a value)
/** Platform → iframe: initialize on load */
window.addEventListener("message", (event) => {
  if (event.origin !== "https://agent-platform.example.com") return;
  const { method, params } = event.data;
  if (method === "ui/initialize") {
    // Store session info (params.sessionId, params.capabilities)
  }
});

/** iframe → Platform: user edited a value (notification, no response) */
window.parent.postMessage({
  jsonrpc: "2.0",
  method: "ui/message",
  params: {
    content: { type: "text", text: "User changed items.price to 199" }
  }
}, "https://agent-platform.example.com");

/** iframe → Platform: request a tool call (expects response with matching id) */
window.parent.postMessage({
  jsonrpc: "2.0",
  id: 1,
  method: "tools/call",
  params: { name: "updateCart", arguments: { items: [...], total: 597 } }
}, "https://agent-platform.example.com");

// Platform responds: { jsonrpc: "2.0", id: 1, result: { content: [...] } }

8. Use Cases

Fits — any scenario where the user wants to tweak the Agent's output:

ScenarioWhat the embed page does
Calculator / spreadsheetRenders expressions and results; user edits values inline
Chart / dashboardRenders a visualization; user adjusts filters or date range
Map / locationRenders an interactive map; user pans, zooms, or selects a pin
Form / survey builderRenders a preview; user reorders fields or changes options
Document editorRenders formatted content; user adjusts layout or typography
Design toolRenders a preview; user tweaks colors, spacing, or dimensions
Code playgroundRenders code with syntax highlighting; user edits and sees output

Does not fit: Pure information queries (no interaction needed), long-form text generation, real-time sync (ERI is snapshot-based).

9. Limitations

Large Data Pattern

When the API response exceeds URL size limits, use a token-based approach instead of encoding data in the URL:

/** Agent: call API, receive a result token instead of full data */
POST /api/report
Response: {"resultToken": "abc123", "summary": "Q1 revenue: $1.2M"}

/** Agent: embed with token, include text summary as fallback */
<iframe src="https://app.example.com/embed#abc123" ...></iframe>

/** Embed page: fetch full data using the token */
const token = decodeURIComponent(location.hash.slice(1));
const data = await fetch('/api/results/' + token).then(r => r.json());

10. Error Handling

FailureAgent behavior
API returns error or timeoutReport the error in plain text. Do not embed an iframe with error state.
Embed URL unreachableOutput plain text fallback. The user still receives the API result.
Platform blocks iframeDegrade to plain text — the Agent's text output remains visible.
URL-encoded data exceeds limitsProvider should design embed page to accept a short token and fetch data server-side.

ERI's text fallback is not a bug — it's the baseline. Every ERI output should include a text summary so the user always gets value regardless of iframe rendering.

11. Industry Landscape

ERI operates at the output layer — how the Agent presents results to the user. It is complementary to tool invocation protocols (MCP, Function Calling, REST) which operate at the input layer — how the Agent calls external systems. The spec is agnostic about how the API is called.

Three approaches exist for interactive Agent output:

ERIMCP AppsA2UI (Google)
HowEmbed via URL (iframe)Sandboxed iframe mini-appsDeclarative JSON UI schema
You buildHTTPS embed page + skill.mdMCP-compatible app packageComponent catalog + A2UI schema
Platform needsRender iframes (already done)MCP runtimeA2UI renderer
Works today?Yes — most platformsMCP-enabled onlyA2UI-enabled only
CapabilitiesFull web platformPlatform APIs, real-time syncNative rendering

MCP Apps and A2UI offer richer capabilities (native APIs, real-time sync, platform integrations) — ERI trades those for universal availability today. Since MCP Apps also uses sandboxed iframes and the same ui/* bridge (Section 7), ERI embed pages carry forward unchanged.

What ERI adds over a plain ad-hoc iframe:

Without ERIWith ERI
DiscoveryAgent doesn't know your app existsskill.md tells the Agent when and how to use your app
API contractEach Agent–provider pair is custom-builtStandardized: call API → encode result → embed URL
Fallbackiframe fails = broken outputAgent falls back to plain text automatically
Cross-platformPrompt-engineer per Agent platformOne skill.md works on ChatGPT, Claude, Gemini

Normative References

Governance

ERI is a community specification maintained by the original author. Level 1 core workflow is frozen — no breaking changes. Additive changes (new use cases, Level 2 message types) follow an open proposal process via GitHub Issues. All substantive changes require a Pull Request with review. See CONTRIBUTING.md for details.