---
name: agentframe
description: Use when the user wants something shown graphically rather than described — "show me", "draw", "paint", "sketch", "render", "plot", "chart", "diagram", "visualize", "mock it up", "put it on the frame", "throw it on the screen" — or when a picture beats prose (progress dashboards, UI mockups, charts, rendered results, photos). Requires an Agent Frame server; the user supplies a frame URL and write key.
---

# Put content on the user's Agent Frame

An Agent Frame is a screen you update with an HTTP `POST`.

If the user gave you a frame URL and write key, store them separately:

```sh
export FRAME_URL='https://agentfra.me/their-frame-id'
export FRAME_KEY='their-write-key'
```

The **frame URL** identifies the screen. The **frame ID** is only its last path
segment (`their-frame-id`). Prefer storing the full URL because the host matters.
Never show, log, or put the write key into frame content.

## 1. Put a tiny SVG on the screen

Use this complete pattern first. Replace the text with the user's result; do not
send a placeholder or make a setup call:

```sh
curl -sS -X POST "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY" \
  -H 'Content-Type: image/svg+xml' \
  --data '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 450"><rect width="800" height="450" fill="#111827"/><text x="400" y="225" fill="white" font-family="system-ui" font-size="64" text-anchor="middle" dominant-baseline="middle">YOUR RESULT</text></svg>'
```

Every update replaces the previous content and appears immediately on every
open viewer. Use an SVG `viewBox`; omit fixed `width` and `height` so it fits.

## 2. Show a remote image or page

Send its URL. Agent Frame fetches it for you:

```sh
curl -sS -X POST "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY" \
  -H 'Content-Type: text/url' \
  --data 'https://example.com/photo.jpg'
```

Use an exact URL you trust. For a general request like “show me a puffin,” use
a prompt instead of guessing an image URL:

```sh
curl -sS -X POST "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY" \
  -H 'Content-Type: text/prompt' \
  --data 'a puffin standing on a cliff above the sea'
```

## 3. Send other formats

Markdown:

```sh
curl -sS -X POST "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY" \
  -H 'Content-Type: text/markdown' \
  --data $'# Findings\n\n- Fast\n- Clear\n- Live'
```

HTML:

```sh
curl -sS -X POST "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY" \
  -H 'Content-Type: text/html' \
  --data '<main style="font:8vw system-ui;padding:8vw">Ship it.</main>'
```

A local image file:

```sh
curl -sS -X POST "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY" \
  -H 'Content-Type: image/png' \
  --data-binary @chart.png
```

Supported content includes SVG, HTML, Markdown, plain text, PNG, JPEG, GIF, and
WebP. Set the matching `Content-Type`. If omitted, Agent Frame will try to
detect URLs, images, SVG, HTML, Markdown, and natural-language prompts.

## 4. Create a frame if the user did not give you one

Create and fill it in the same request:

```sh
response=$(curl -sS -H 'Content-Type: text/markdown' \
  --data '# Your frame is ready' https://frame.new)
export FRAME_URL=$(printf '%s' "$response" | jq -r .url)
export FRAME_KEY=$(printf '%s' "$response" | jq -r .writeKey)
printf 'Open: %s\n' "$FRAME_URL"
```

Give the user only `FRAME_URL`. Keep `FRAME_KEY` secret. Reuse both for later
updates instead of creating a new frame each time.

For the current shell, `export` is enough. Across sessions, save them in the
agent's secret/config store. Keep the URL and key as two values. If you need
the ID:

```sh
FRAME_ID=${FRAME_URL%/}
FRAME_ID=${FRAME_ID##*/}
```

That is the complete working path: store URL + key, then `POST` content.

<hr style="border:0;border-top:10px solid #dc2626;margin:3rem 0">

# 🔴 Optional reference below this line

Do not delay the first useful update to read or perform anything below.

## Compose for a screen

- Prefer SVG for diagrams, cards, charts, and text-heavy visuals.
- Use a `viewBox`; make HTML fluid; do not depend on scrolling.
- Show less rather than shrinking everything.
- Make SVG/HTML follow light and dark mode when practical:

```html
<style>
  :root { color-scheme: dark light }
  .bg { fill: #111827 } .ink { fill: #fff }
  @media (prefers-color-scheme: light) {
    .bg { fill: #fff } .ink { fill: #111827 }
  }
</style>
```

## Overlay progress only when work takes time

An overlay is one short status string shown over the current content. The next
content update clears it.

```sh
curl -sS -X POST "$FRAME_URL/overlay" \
  -H "Authorization: Bearer $FRAME_KEY" \
  --data 'building the chart…'
```

Skip overlays for quick one-request updates.

## Use the viewers returned by updates

Each update response includes `viewers`, with viewport size, orientation,
pixel ratio, input type, color scheme, and monochrome status. Send the first
useful update immediately, then use this information to improve the next one.
You can also fetch it directly:

```sh
curl -sS "$FRAME_URL/viewers"
```

## Read or delete content

```sh
curl -sS "$FRAME_URL/raw"

curl -sS -X DELETE "$FRAME_URL" \
  -H "Authorization: Bearer $FRAME_KEY"
```

Reads are open. Writes and deletion require the key.

## Write URLs

A user may give you a URL containing `?key=...`. Extract the key, remove the
query string from the stored frame URL, and use the key in the authorization
header thereafter. Never repeat a write URL to the user or put it in logs.

## JavaScript API

```js
import { openFrame } from 'https://agentfra.me/client.js'

const frame = openFrame(process.env.FRAME_URL, { key: process.env.FRAME_KEY })
await frame.update(svg, { type: 'image/svg+xml' })
await frame.overlay('drawing…')
const viewers = await frame.viewers()
```

## CLI

The optional `frame` CLI reads `~/.config/agentframe/agentframe.toml`:

```toml
[frames.main]
url = "https://agentfra.me/their-frame-id"
key = "their-write-key"
default = true
```

```sh
frame update drawing.svg
frame update 'a puffin on a cliff'
frame overlay 'drawing…'
frame viewers
frame get
frame url
```

Use `--frame <name|url|id>` to select another frame. `FRAME_URL` and
`FRAME_KEY` override the config.

## Signed controllers and frame ownership

Bearer write keys are the simplest option. Agents that maintain Ed25519 keys
can use request-bound signed proofs; fetch `/auth.md` for that protocol.
Humans can claim a frame with its one-use claim URL and a passkey. These are
administrative features, not prerequisites for putting content on the screen.
