Annotation prompt format
This is the format Leafy produces when you click Copy as prompt. It's plain markdown, with no JSON envelope, no SDK, and no agent-specific syntax, so it works pasted into Claude Code, Cursor, ChatGPT, Copilot, or anything else that reads text.
Example output
A full prompt for a page with two annotations and one page-level note. A short preamble frames the task for the agent, then page metadata, then the annotations.
# Web page annotations (captured with Leafy)
You are an assistant helping a user with the annotations below. The user
reviewed the web page described here and left these comments / feedback, each
pinned to a specific element on the page. For every annotation you have the
user's comment and details of the element it refers to: its visible text,
plus technical identifiers (selectors, HTML) that pinpoint it if you need them.
Use the annotations as the context for the conversation and help the user with
whatever they're trying to do. Their intent may already be clear from the
comments (for example a change to make, a question to answer, feedback to
summarize, copy to write, or a record to update), or they may tell you next.
If it isn't clear yet, give a short recap of the annotations and ask how you
can help.
Some annotations carry a Severity the author set (Suggestion, Question, Fix
this, or High priority). Treat it as the author's intent and urgency:
prioritize "High priority" and "Fix this" items, answer "Question" items, and
treat "Suggestion" items as optional improvements.
## Page
- Title: Acme Dashboard · Account Settings
- URL: https://staging.acme.dev/settings
- Viewport: 1440×900 (DPR 2)
- Captured: 2026-06-09T11:42:07.000Z
## Annotations
### 1. "Save changes"
- **Comment by Priya Sharma · Jun 9, 2026:** This button stays enabled even when nothing has changed, and clicking it fires a no-op request. Disable it until the form is dirty.
- **Severity:** Fix this
- **Element:** `button` #save-settings
- **React components:** `App > SettingsPage > SettingsForm > SaveButton`
- **CSS selector:** `#save-settings`
- **DOM path:** `/html/body/main/section[2]/form/div[3]/button`
- **Classes:** `btn btn-primary w-full`
- **Attributes:** `type="submit"`, `data-testid="settings-save"`
- **Anchored text:** "Save changes"
- **HTML:**
```html
<button id="save-settings" class="btn btn-primary w-full" type="submit" data-testid="settings-save">Save changes</button>
```
- **Replies:**
- **Sam Okafor · Jun 9, 2026:** Agreed, gate it on form state. @Priya should the tooltip change too?
### 2. "Notifications are sent within 24 hours"
- **Comment by Priya Sharma · Jun 9, 2026:** Copy is outdated. Notifications go out near-instantly since the queue rework. Suggest "usually within a minute".
- **Severity:** Suggestion
- **Element:** `p` (text selection)
- **CSS selector:** `section.notifications > p.helper-text`
- **DOM path:** `/html/body/main/section[3]/p[1]`
- **Classes:** `helper-text text-sm`
- **Anchored text:** "Notifications are sent within 24 hours"
- **HTML:**
```html
<p class="helper-text text-sm">Notifications are sent within 24 hours of the triggering event.</p>
```
## Page-level notes (not tied to a specific element)
### 1. Page note by Sam Okafor · Jun 9, 2026
Whole page still uses the old spacing scale. Worth migrating to the new
tokens while we're in here.
Field reference
Optional fields are simply omitted when there's nothing to say, so agents should not assume every line is present.
Page metadata
| Field | Type | Presence | Purpose |
|---|---|---|---|
| Title | string | Required | The document title of the annotated page. Falls back to “(untitled)”. |
| URL | string | Required | The full URL of the page the annotations were captured on. |
| Viewport | string + number | Required | Viewport size (e.g. 1440×900) and device pixel ratio, so layout-dependent feedback can be reproduced. |
| Captured | ISO 8601 timestamp | Required | When the prompt was generated. |
Element locators
| Field | Type | Presence | Purpose |
|---|---|---|---|
| Heading label | string | Required | Each annotation is a numbered ### heading: the element's visible text in quotes when available, otherwise a tag description like <button> element. |
| Element | tag + id + mode | Required | The element's tag name, its #id if present, and a “(text selection)” marker when the annotation anchors a highlighted text range rather than a whole element. |
| React components | chain string | Optional | On React pages, the component hierarchy above the element (e.g. App > SettingsForm > SaveButton), recovered from the page's fiber tree at copy time, so agents can grep for the component, not just the DOM. |
| CSS selector | string | Optional | A CSS selector that identifies the element. Grep-friendly: paste it into your codebase search to find the component. |
| DOM path | XPath string | Optional | An absolute XPath to the element, as a fallback locator when selectors are ambiguous. |
| Classes | string list | Optional | The element's class list, space-separated. |
| Attributes | key="value" pairs | Optional | Other identifying attributes on the element (e.g. type, data-testid, href). |
| Anchored text | string (≤ 240 chars) | Optional | The selected text or the element's visible text content, truncated, quoted. |
| HTML | fenced html block | Optional | An outer-HTML snippet of the element. Stray triple backticks inside the snippet are neutralised so the fence can't break. |
Comments and severity
| Field | Type | Presence | Purpose |
|---|---|---|---|
| Comment | author + date + text | Required | The annotation's comment with the author's display name and creation date. @mentions are rendered as plain @Name. |
| Severity | "Suggestion" | "Question" | "Fix this" | "High priority" | Optional | How the author triaged the annotation: a suggestion, an open question, something to fix, or high priority. Omitted when not set. |
| Replies | list of author + date + text | Optional | Threaded replies under their parent annotation, oldest first, so the discussion stays attributed. |
| Page-level notes | numbered note blocks | Optional | Comments not tied to a specific element appear in their own section after the annotations, with author, date, and replies. |
A note on stability
The format is versioned informally: the section structure and bold field labels above are stable, and new fields (like severity) are added as optional lines rather than breaking changes. Selectors and DOM paths are deliberately grep-friendly: an agent can paste a CSS selector or a data-testid straight into a codebase search to find the component behind an annotated element.
Try it on a real page
Add Leafy to Chrome, annotate any webpage, and copy the prompt yourself. See Leafy for AI agents for the full workflow.