Reference · Everything it does

Docs › Reference

Everything it does

Intents, variants, the board, Markdown export and screenshots, in full.

What you can say, and what the agent gets#

Intent. Each note can say what it wants. Fix: something is broken. Change: it works but should be different. Question: you want an answer, not an edit. The agent looks, replies in the thread and changes no code. Approve: this is right as it is; the agent leaves it alone and says so. Variants: show me a few versions to compare in the page, and I will pick one (see Variants). A note with no intent is read for what it says. The agent acts on the intent (the skill spells it out), and the board filters by it.

Where it is in the code. Besides the selector and the test id, an annotation carries the component path (the chain of components the element sits in, innermost first, framework plumbing left out: <PayButton> <CheckoutForm> <App>), and with the Vite plugin the exact file, line and column.

How it looks. At the detailed level the agent also gets the element's computed styles (colours as hex, type, size, spacing, border, layout; defaults left out), the chain of ancestors it sits in, and the animations that were running (name, duration, easing, how far through). That is what a note like "too cramped" or "wrong blue" is about.

Pause. The toolbar's pause button (Alt+Shift+P) freezes CSS animations and transitions, Web Animations and video and audio where they are, including ones that start while it is paused, so you can annotate a frame that only exists for 200ms. The annotation records the animations on the element and how far through each was (css slide-in 300ms ease-out (paused at 40%)). Resume puts back only what it paused. Animations driven from JavaScript frame by frame (requestAnimationFrame, canvas, WebGL) cannot be paused.

Iframes, shadow DOM and portals. Annotating works inside same-origin iframes (nested ones too, and ones added later or navigated), inside open shadow roots, and in portals (they render into the page, so they simply work). The element is recorded with how to reach it (iframe#preview → shadow root of my-widget), pins land on it in the right place, and the screenshot includes the frame's contents. A selector can reach in with >>>: iframe#preview >>> button.pay. A cross-origin iframe is a wall the browser does not let any script through, so it is picked as one element and its contents are left out of the screenshot (a placeholder is drawn).

Variants: compare versions in the page#

Ask for a few versions of something, flip between them live in your running app, and pick the one you like. Press Annotate, pick the thing, choose Variants, and say what to explore ("three layouts for this header"). The agent puts each version into the code, side by side, and the page shows a switcher over them: Original · Stacked · Compact, with Use this on the one you want. Switching is instant and changes nothing in your code. When you pick, the agent keeps only that version, deletes the others and every trace of the switching, and commits the result as one change. Write back instead ("make Stacked bolder and add one with the button on the right") and the agent changes the versions and offers a new set. Take a pick back before the agent has applied it, or pick again.

How it works, so it works in anything: a version is just an element with two attributes, and Notato needs no framework to see it.

<div data-notato-variant="header" data-notato-variant-name="Original" style="display: contents"> … </div>
<div data-notato-variant="header" data-notato-variant-name="Stacked"  style="display: contents"> … </div>

data-notato-variant is the same on every version of the same thing, and data-notato-variant-name is that version's name. Elements that share a name are one version. The page shows the chosen version and hides the others with a style rule, so it also covers elements the app creates later (a re-render or a hot reload), and the switcher appears and disappears with the markers. Nothing else changes: a reload keeps what you were looking at, and with no server it is a preview with no Use this. With a hot-reload dev server the versions appear as the agent writes them; without one, refresh. Alt+Shift+←/→ steps through versions. Variants only works on elements in the page and in same-origin iframes, not inside shadow roots.

A driver (an agent with a browser tool) can check its work: window.__notato.variants.list() shows each group and which version is showing, and .select(group, name) shows one, so the agent can look at every version before it says they are ready. The Variants choice is only offered where there is a server and an agent on the other end: not in test mode.

Behind it: a variants record on the annotation (the group and the names, each with a one-line summary, the pick and when), the status variant_chosen while the pick waits for the agent, the MCP tool notato_variants_ready, and POST /annotations/:id/variants/choose. A pick arrives through notato_watch marked VARIANT CHOSEN; the board lists the versions with a Pick on each, and webhooks send annotation.variants_ready and annotation.variant_chosen.

Replies reach the agent within its feedback scope. notato_watch delivers replies on notes the agent can read, marked FOLLOW-UP: an answer to a question the agent asked, a note on one you reopened, a request about versions, or more to do on something it already resolved. A reply does not reopen a finished note: the agent reopens it if there is work in it, and leaves it alone for a "thanks". Agents start in Mine; select Shared or All only when you mean to hand them team feedback.

Keeping something from the agent. Two switches, both for people, and both kept by the server, so nothing depends on how a message is worded:

Agents cannot read or change a People only note, including direct reads by id, screenshots, references and exports. App tokens and signed-in people retain access. Turning People only off explicitly shares the note and its thread with agents again.

The browser, React and Angular toolbar can collect a grouped review across pages: write one instruction, annotate each target, then send the group when ready. Drafts survive reloads and stay off the server until sent. Each note can include up to three optimised design reference images, with private asset access and bounded uploads. The board links the targets and can group the inbox By review.

Hide from this app on a completed SDK card hides it privately in this browser; Settings can restore it and the dashboard always retains it. Agents use notato_ask_question to pause a task as Needs your answer, then a public human reply resumes it. notato_get_review reads the whole group before a consistent fix; notato_get retrieves references on demand. See the browser workflow.

Team feedback and checkout queues#

Start with one project ID shared by everyone: each developer's Dev feedback stays Mine, and testers' Test sessions are Shared. For teams that use worktrees or PR-linked reviews, the Assignments page (where each developer connects a dev setup: their own app and agent, technically a checkout or worktree) can optionally assign shared work and record its branch/commit. That execution ownership is separate from feedback visibility and is not required for the ordinary local loop. See the team feedback guide.

The board: every project in one place#

The server serves a board at its own address (http://localhost:4747 in dev mode). One server can hold many projects (each app's project setting is the project its notes file under), and the board is built around that.

Projects. On notato dev a project appears with its first note: nothing to set up. You can also create one first with New project on the board, which shows how to connect each kind of app to it. On a shared server an admin creates every project first: that is what hands out its token, and a note for a project the server does not have is refused, so a typo or a stray app cannot start one. Renaming a project changes only the name people see; deleting one removes its notes, their screenshots and its tokens.

It updates as things happen. Keys in the inbox: j/k (or the arrows) move, / searches, r replies, Cmd/Ctrl+Enter sends, Esc closes. Every note has its own link (#/p/<project>/a/<id>). In dev mode, the name at the foot of the sidebar (or in Settings) sets the name your replies carry, kept in this browser. On a server with accounts, replies use the signed-in account's name. On the full server, Sign out, Account and Appearance are in the account menu; the lightweight shared server keeps Settings › Account. Dialogs keep keyboard focus inside until closed. On a phone the sidebar is a drawer and a note opens over the list.

Copy as Markdown, and export#

Any annotation can be written as Markdown at four levels, to paste into another agent, an issue or a pull request:

LevelWhat it holds
compactA line each: pin, intent, severity, route, comment, element, source. For scanning many
standardWhat it takes to find and fix it: target, source, component path, viewport, a console and network summary, steps, thread
detailedAdds computed styles, ancestors, classes, animations and the environment
forensicEverything captured: the full console and network, other plugins' context, the identity as recorded

The toolbar's copy button copies this page's annotations at the level you pick (remembered). The board copies everything its inbox shows (the ⋯ menu, in the order shown and after the search), and each note from the copy button in its header. From a terminal:

npx notato export --detail compact --status open            # to the terminal
npx notato export --project checkout-web --intent question -o questions.md

notato_get and notato_watch take the same detail, and the server has GET /annotations/:id/markdown?detail= and GET /projects/:id/markdown?detail=&status=&intent=. Nothing here needs screenshots.

Screenshot size#

Browser and mobile SDKs encode the finished, masked screenshot as WebP at quality 85 when it is smaller than PNG. They keep the same dimensions and use PNG if the encoder is unavailable or PNG wins. Old PNG notes, offline queues and bundles continue to work. React Native needs a native rebuild for its optional encoder; Expo Go keeps PNG. See screenshot storage for platform dependencies, compatibility and measured examples.

Screenshots: on or off#

Screenshots are what the agent sees, and they can contain whatever is on screen. They are on by default and can be turned off for a project:

npx notato config                    # what is set, and where each value comes from
npx notato config set screenshots off
npx notato config set screenshots on

That writes notato.config.json in the folder you start Notato from, so it can be committed and shared ({ "screenshots": "off" }). NOTATO_SCREENSHOTS=off overrides the file. The server enforces it: it drops any screenshot a page sends, including from imported bundles, so none is ever stored, and a change applies to the next annotation without a restart. Pages ask the server before each capture, so no screenshot is rendered either, and the popover says so ("No screenshot will be taken: they are turned off"). The annotation is still made, still numbered, and still carries the selector, component and source, which is what the agent works from; the board shows it without an image.

A broken settings file fails safe: screenshots stay off until it is fixed, doctor warns, and the server logs why. A page can also opt out for itself with <Notato screenshots={false} />, which is the only control in test mode with no server; a server that has them off wins over a page that has them on.