postMessage Protocol
All postMessage types exchanged between the HyperGen host application and the sandboxed iframe, with exact JSON shapes and origin validation rules.
The host application and the sandboxed iframe communicate via the browser's postMessage API. This section defines all message types, their exact JSON shapes, and the origin validation requirements.
postMessage is used only for host-iframe integration: theming, resize notifications, navigation intents, data exchange, and lifecycle management. Agent communication (SSE streaming, user action submission) flows directly between the iframe and the agent server via HTTP — see SSE Message Format.
Message Envelope
Every HyperGen postMessage MUST be a JSON object with a type field:
interface HyperGenMessage {
type: string;
[key: string]: unknown;
}The type field MUST be a string prefixed with hg:. Messages with unrecognized types SHOULD be silently ignored.
Origin Validation
Host receiving messages from iframe
The host MUST verify that incoming messages originate from the expected iframe:
- Source check:
event.sourceMUST equal the iframe'scontentWindow. This confirms the message came from the correct iframe (critical when multiple iframes exist). - Origin check: If the iframe origin is known,
event.originSHOULD be validated against it. WheniframeOriginis"*", origin checking is skipped.
window.addEventListener("message", function(event) {
// MUST: verify the message source is our iframe
if (event.source !== iframe.contentWindow) return;
// SHOULD: verify origin when known
if (expectedOrigin !== "*" && event.origin !== expectedOrigin) return;
// Process the message...
});Iframe receiving messages from host
The bootstrap document's postMessage handler MUST validate the origin when a specific hostOrigin is configured:
window.addEventListener("message", function(e) {
if (hostOrigin !== "*" && e.origin !== hostOrigin) return;
// Process the message...
});Production deployments SHOULD set explicit origins rather than "*".
Host to Iframe Messages
hg:theme — CSS Variable Injection
Injects or updates CSS custom properties on the iframe's :root element. Used to synchronize the host's design system with the iframe.
interface HgThemeMessage {
type: "hg:theme";
/** CSS custom property key-value pairs. Keys MUST be valid CSS custom property names. */
vars: Record<string, string>;
}Example:
{
"type": "hg:theme",
"vars": {
"--hg-surface": "#1a1a2e",
"--hg-text": "#e0e0e0",
"--hg-accent": "#7c3aed",
"--hg-accent-fg": "#ffffff",
"--hg-border": "#374151",
"--hg-radius": "8px"
}
}Behavior:
- The iframe MUST iterate over
varsand calldocument.documentElement.style.setProperty(key, value)for each entry. - The message is additive — it updates the specified variables without removing previously set ones.
- The host SHOULD send a
hg:thememessage immediately after the iframe loads and whenever the host theme changes (e.g., dark mode toggle).
hg:destroy — Cleanup Signal
Instructs the iframe to shut down: close SSE connections, stop observers, and release resources.
interface HgDestroyMessage {
type: "hg:destroy";
}Example:
{
"type": "hg:destroy"
}Behavior:
- The iframe MUST remove the
sse-connectattribute from the root element to close the SSE connection. - The iframe SHOULD trigger
htmx:sseCloseto clean up HTMX SSE state. - After processing
hg:destroy, the host typically removes the iframe from the DOM.
Iframe to Host Messages
hg:ready — Iframe Ready Signal
Notifies the host that the iframe's bootstrap document has loaded and the postMessage bridge is operational.
interface HgReadyMessage {
type: "hg:ready";
}Example:
{
"type": "hg:ready"
}Behavior:
- The iframe MAY send this message after the bootstrap document's scripts have executed.
- The host MAY use this signal to delay sending
hg:themeuntil the iframe is ready to receive it. - This message is OPTIONAL. The host SHOULD also handle the case where
hg:themeis sent beforehg:ready(e.g., via the iframe'sloadevent).
hg:resize — Content Height Notification
Notifies the host that the iframe content size has changed, enabling the host to resize the iframe element accordingly.
interface HgResizeMessage {
type: "hg:resize";
/** The content height in pixels (document.documentElement.scrollHeight). */
height: number;
/** The content width in pixels (optional). */
width?: number;
}Example:
{
"type": "hg:resize",
"height": 542,
"width": 800
}Behavior:
- The iframe MUST use a
ResizeObserverondocument.bodyto detect size changes. - On each size change, the iframe MUST post an
hg:resizemessage with the currentscrollHeight. - The
widthfield is OPTIONAL. It is included for layouts where width information is useful. - The host SHOULD auto-resize the iframe element by setting its
heightstyle property to the received value, clamped between configured minimum and maximum heights.
hg:navigate — Navigation Intent
Requests that the host application navigate to a URL. The iframe cannot navigate the host directly (the allow-top-navigation sandbox permission is denied).
interface HgNavigateMessage {
type: "hg:navigate";
/** The target URL. May be absolute or relative to the host. */
url: string;
}Example:
{
"type": "hg:navigate",
"url": "/dashboard/reports"
}Behavior:
- Agent-generated HTML can trigger navigation by including elements with a
data-hg-navigateattribute. The bootstrap document's click handler intercepts these clicks and posts thehg:navigatemessage. - Alternatively, agent-generated inline scripts can post
hg:navigatedirectly. - The host MUST validate the URL before navigating (e.g., reject absolute URLs to untrusted domains).
- How the host performs the navigation is implementation-specific (e.g.,
router.push(),window.location.href).
Agent HTML triggering navigation:
<a data-hg-navigate="/settings" href="#">Open Settings</a>hg:data — Arbitrary Data Payload
Sends structured data from the iframe to the host. This is the general-purpose channel for agent-generated UI to communicate results, selections, or state to the host application.
interface HgDataMessage {
type: "hg:data";
/** Any JSON-serializable payload. */
payload: unknown;
}Example:
{
"type": "hg:data",
"payload": {
"action": "item_selected",
"itemId": 42,
"label": "Quarterly Report"
}
}Behavior:
- Agent-generated scripts can dispatch a
CustomEventnamedhg:dataondocument. The bootstrap's event listener catches it and forwardsevent.detailto the host as thepayload. - The host application registers a callback to handle
hg:datamessages. - The
payloadmay be any JSON-serializable value: object, array, string, number, boolean, or null.
Agent HTML sending data:
<button onclick="document.dispatchEvent(new CustomEvent('hg:data', {
detail: { action: 'confirm', orderId: 123 }
}))">
Confirm Order
</button>Complete Type Definition
For implementers using TypeScript, the complete set of message types:
// Host → Iframe
type HostToIframeMessage =
| { type: "hg:theme"; vars: Record<string, string> }
| { type: "hg:destroy" };
// Iframe → Host
type IframeToHostMessage =
| { type: "hg:ready" }
| { type: "hg:resize"; height: number; width?: number }
| { type: "hg:navigate"; url: string }
| { type: "hg:data"; payload: unknown };
// Union of all messages
type HyperGenMessage = HostToIframeMessage | IframeToHostMessage;Message Flow Diagram
Host Application Sandboxed Iframe
│ │
│◄──── hg:ready ────────────────────│ (iframe loaded)
│ │
│──── hg:theme ─────────────────────►│ (inject CSS vars)
│ │
│ │ (SSE streams HTML, user interacts)
│ │
│◄──── hg:resize ──────────────────│ (content grew)
│ │
│◄──── hg:navigate ────────────────│ (user clicked nav link)
│ │
│◄──── hg:data ────────────────────│ (user confirmed action)
│ │
│──── hg:destroy ───────────────────►│ (host removing iframe)
│ │Extensibility
Implementations MAY define additional message types beyond those specified here. Custom message types MUST use the hg: prefix followed by a namespace to avoid collisions:
hg:x-myapp:custom-eventReceivers MUST silently ignore message types they do not recognize.
Iframe Bootstrap Document
The complete HTML document that MUST be loaded into the HyperGen sandboxed iframe, including HTMX, SSE extension, postMessage bridge, and base styles.
CSS Variable Theming
The --hg-* CSS custom property namespace, defined variables, default values, and theme injection mechanism.