packages/core/src/templates/default/.agents/skills/inline-embeds/SKILL.md
How to render interactive previews of app screens inline in agent chat via sandboxed iframes. Covers the `embed` fence syntax, the `postNavigate` pop-out helper, and when to prefer an embed over prose / a static image.
npx skillsauth add BuilderIO/agent-native inline-embedsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The chat renderer lets you embed a sandboxed iframe pointing at any same-origin route of this app, rendered inline with your reply. Use this when a live, interactive preview communicates more than prose or a static screenshot — a chart, an email thread, a slide, a form, a ticket.
embed fenceEmit a fenced code block with the language embed:
```embed
src: /email?id=msg_123
aspect: 4/3
title: Re: Q4 planning
```
Keys:
| Key | Required | Notes |
| -------- | -------- | ------------------------------------------------------------------ |
| src | yes | Same-origin path beginning with /. Cross-origin URLs are blocked |
| aspect | no | 16/9 (default), 4/3, 3/2, 2/1, 21/9, 1/1 |
| title | no | Accessible label + hover tooltip |
| height | no | Fixed pixel height when aspect ratio doesn't fit |
The rendered iframe is sandboxed (allow-scripts allow-same-origin allow-forms allow-popups) and referrerpolicy="same-origin". The browser enforces that
the iframe can't navigate the parent window.
Don't embed when plain prose, a bulleted list, or a small table is enough. Don't embed external sites — the renderer blocks cross-origin URLs.
postNavigateEvery embed route should include a small "Open" button so the user can pop the
view out of the chat and into the full app. Import the helper from
@agent-native/core/client:
import { postNavigate, isInAgentEmbed } from "@agent-native/core/client";
export function OpenButton({ path }: { path: string }) {
if (!isInAgentEmbed()) return null;
return (
<button onClick={() => postNavigate(path)}>Open</button>
);
}
postNavigate sends a postMessage to the parent chat window. The chat
renderer validates the message is same-origin, same-iframe, and the path is
relative, then updates the parent URL via history.pushState so react-router
navigates without a page reload.
When the page is loaded directly (not in an iframe), postNavigate falls back
to a same-window navigation, so the button works both ways.
app/routes/email.tsx) that renders the
detail view without the app shell.app/components/layout/Layout.tsx so the
sidebar / header don't render inside the iframe.<OpenButton> that calls postNavigate("/path/to/detail").AGENTS.md so the agent knows
what's embeddable.The framework-level fence renderer and security enforcement apply automatically — no per-template wiring beyond the route and layout bypass.
tools
Public booking flow — the state machine, animations, and URL/app-state sync.
tools
Trigger-based automations — reminders, follow-ups, webhooks — across the booking lifecycle.
tools
Team event types, round-robin assignment, collective bookings, host weights, and no-show calibration.
development
The pure `computeAvailableSlots` function — inputs, outputs, invariants, and debugging guide.