Skip to main content
Glama

Annotated screenshots for AI agents: the agent shows you the button instead of describing where it is.

Website · Get started · Privacy

Tests PyPI Python License: AGPL-3.0-or-later MCP server

Hacker News with Skitch-style arrows: Discussion, Post a link and a numbered Sign in step, in a browser window on a sunset gradient

Ask an agent how to post a link on Hacker News and you usually get directions: the orange bar at the top, the last link after jobs. With AInotate it sends the picture above instead and says "click submit, where the blue arrow points".

It captures a web page, a window or a screenshot you already have, finds the elements you mean, draws numbered steps, arrows, boxes and labels where they hide the least, blacks out emails and tokens, and looks at the result before sending it. It works in Claude Code, Cowork, Claude Desktop, Codex, Gemini CLI, Cursor and any other MCP client, and from the command line or Python.

We built it at DontPayFull because our own agents kept answering "where is it?" with a paragraph. A picture with a number on the right button settles the question in a second, in a chat, a ticket or a guide.

What it is for

  • "Where is it?" Settings, menus, buttons that hide behind icons. The agent answers with the screen itself, the control boxed and numbered.

  • "Walk me through it." One image per step, in the order to follow; ainotate guide turns them into a Markdown, HTML or PDF guide.

  • "Your turn." A permission switch, a 2FA code, a payment or consent screen: the agent does not click for you. It shows exactly what to press and says what the click does.

  • Bug reports and tickets. What is wrong, outlined in red, what is right in green, emails and tokens blacked out before anyone sees them.

  • Docs and changelogs. Screenshots that point at the thing the text talks about, re-shot from the same spec when the UI changes; before and after plates for a change.

Related MCP server: Screenshot API

Set it up in your agent

1. Install, one of:

With

Command

Homebrew (macOS)

brew install dontpayfull/tap/ainotate

pipx or uv (Python 3.10+)

pipx install "ainotate[all]" or uv tool install "ainotate[all]"

Claude plugin

only uv: step 2 brings AInotate along

Claude Desktop extension

nothing to install first

Then ainotate doctor checks the machine and prints the exact fix for anything missing, including the one command that downloads Chromium for web capture. To update later: brew upgrade ainotate, pipx upgrade ainotate or uv tool upgrade ainotate; the plugin with /plugin marketplace update ainotate; the Desktop extension by opening the newer .mcpb from Releases.

2. Connect it to the agent you use:

Agent

How

Claude Code

/plugin marketplace add dontpayfull/AInotate, then /plugin install ainotate@ainotate: skill and MCP server in one step

Cowork

Customize > Plugins > Add marketplace > dontpayfull/AInotate, then install AInotate

Claude Desktop

download ainotate-<version>.mcpb from Releases and open it: a one-click extension

Codex

codex plugin marketplace add dontpayfull/AInotate, then codex plugin add ainotate@ainotate: skill and MCP server

Gemini CLI

gemini extensions install https://github.com/dontpayfull/AInotate: skill and MCP server

Cursor

Add AInotate to Cursor (needs uv), plus the skill below

VS Code, Cline, other MCP clients

command ainotate, arguments mcp (stdio); also listed in the MCP Registry as io.github.dontpayfull/ainotate; agents can follow llms-install.md

{"mcpServers": {"ainotate": {"command": "ainotate", "args": ["mcp"]}}}

AInotate runs on your own computer: Cowork reaches it through the Claude desktop app, so keep the app open while a task uses it. The plugin runs AInotate with uvx, pinned to its release, so it needs uv.

The skill teaches an agent when and how to annotate: pick a source, find exact positions, annotate, read the image to verify, deliver. The plugin brings it along; without the plugin it ships with the package:

ainotate install-skill             # Claude Code and Codex (~/.claude/skills, ~/.agents/skills)
ainotate install-skill --zip ~/Desktop   # a ZIP for Claude Desktop, Cowork, claude.ai:
                                         # Customize > Skills > Upload a skill
npx skills add dontpayfull/AInotate      # any agent the skills CLI knows (Cursor, Windsurf, ...)

Config paths for every OS, permissions and the tool list: skills/ainotate/references/mcp.md.

3. Ask. "Show me where to switch Wikipedia to dark mode." The agent captures the page, annotates it, checks it and sends the image. With the skill it also does this on its own whenever an answer depends on where something is on the screen: a "how do I" question, a visual bug, a before/after of a change.

Every image below was made in one shoot call against a public site: open the page, find the elements, place the labels, draw, frame. The specs are in docs/images/specs.

The DontPayFull home page: step 1 on the store search box, step 2 on Join now, a blue arrow to Saving tips

The Playwright repository on GitHub: the Code button outlined green as Clone it, an arrow to the Star button, the About text highlighted

Numbered steps on the busy header of DontPayFull, coupons for 20,000+ stores

Box, arrow and highlight on GitHub

Three numbered steps in the Appearance panel of a Wikipedia article, framed in a browser window on a blue gradient

A bug report: one table outlined green as sorted, the other red as not sorted, with every email address blacked out automatically

Step-by-step guide with browser chrome and a gradient frame

Bug report, emails redacted automatically by the privacy scan

A circular magnifier enlarging a small edit link, next to keycaps for Alt Shift E

Before and after plate: a checkbox and a Remove button, then the message It's gone

Magnifier and keycaps for tiny controls and shortcuts

Before / after plate from two shots

The same two arrows drawn in the four arrow styles: skitch, curved, straight and line

Labels that stay off the content

Left: labels at a fixed spot under each link cover the first headline. Right: AInotate puts the same labels in free space and points at the links with arrows

A label dropped at a fixed spot next to its target usually lands on the text the reader needs. AInotate places every label itself:

  • It maps the page content first (text, icons, lines, images) and tries hundreds of spots per label. Empty space near the target wins; a spot over text is used only when the frame has no free room.

  • Arrows are priced too: a long arrow, or one that crosses text, another label or another mark, loses to a shorter, cleaner one. When the straight path crosses text, the arrow curves around it.

  • All labels are planned together, so the first one cannot take the only clean spot a later one needs.

  • Step badges sit on the corner of their box that covers the least.

The image is never enlarged to make room. If a label still has to cover something, AInotate says so in a warning, and label_at pins a label exactly where you want it.

From the command line

Save this as hn.json:

{"url": "https://news.ycombinator.com",
 "frame": {"chrome": "browser"},
 "marks": [
  {"type": "step", "n": 1, "target": {"text": "new", "exact": true},
   "label": "Newest"},
  {"type": "step", "n": 2, "target": {"text": "login"},
   "label": "Sign in"}]}
ainotate shoot hn.json --draft    # temp file; drop --draft to save

The output path is printed on stdout. Images are saved to ~/Pictures/AInotate unless you configure another folder. ainotate --help lists every command (capture, annotate, locate by OCR, grid, zoom, window capture with UI element targets, elements, guide, compare, animate, copy, install-skill); the full spec is in skills/ainotate/references/spec.md. Exit codes: 0 ok, 1 cannot save, 2 invalid spec, 3 cannot draw, 4 capture failed or an optional dependency is missing, 5 ambiguous text target, 6 target not found.

Python. The same pipeline is importable:

from ainotate.shoot import shoot
res = shoot({"url": "https://en.wikipedia.org/wiki/Screenshot",
             "marks": [{"type": "box",
                        "target": {"text": "View history"},
                        "label": "Past edits"}]}, draft=True)
print(res.paths[0], res.redactions)

Features

  • Marks: numbered step, box, arrow, click ripple, keys (keycaps), magnify (loupe), highlight, spotlight, text, solid redact, and decorative blur / pixelate.

  • Placement that reads well: labels go to free space near their target and are planned together; arrows are tapered Skitch-style shapes with a soft shadow that curve around text (see Labels that stay off the content). Warnings for overlapping labels, crossing arrows, more than 6 marks or labels over 4 words.

  • Web capture in one call: ainotate shoot opens a page (laptop, wide or phone preset), runs actions (click, fill, wait, scroll), measures each target, redacts, annotates and saves.

  • Any browser: its own Playwright Chromium, Firefox or WebKit, or attach over CDP to a Chromium you already use and are logged into (Chrome, Edge, Brave, Arc, BrowserOS). The preset is applied to that one tab and restored afterwards.

  • Any image: locate finds text by OCR (Apple Vision, Windows OCR or Tesseract); grid and zoom locate icons at full resolution. Screen, window and clipboard capture are built in.

  • Desktop apps on macOS: ainotate window ID --target measures buttons, switches and fields through the Accessibility API, so marks sit exactly on the control, icons included; ainotate elements --app NAME lists what it can find.

  • Frames: gradient backgrounds (auto from the screenshot, or presets), rounded corners, shadow, browser or window chrome, social aspect ratios.

  • Sharing: guides in Markdown, HTML and PDF; before/after plates; APNG and GIF animations; copy to the clipboard.

  • Strict specs: a typo stops the run with a list of every problem instead of saving a wrong or unredacted image. Clear exit codes.

  • Diacritics: bundled Inter font, so Romanian, German, French and other Latin-script labels render correctly everywhere.

Privacy

  • Redaction is solid. redact paints an opaque block. AInotate never uses blur to hide data: blur and pixelation can be reversed. blur and pixelate exist only to de-emphasize clutter, and a mark flagged "sensitive": true is refused for them.

  • Automatic redaction is on for web shots. shoot scans the live page (text and input values) for emails, phone numbers, card numbers, IBANs, API keys, tokens, JWTs, password and personal-data fields, and blacks them out. On images it runs on OCR when you pass --privacy auto. You can allow-list your own addresses or add regexes.

  • It is best-effort. Detection misses things: text drawn in images or canvas, unusual formats, data split across elements, embedded frames from other sites (reported, not redacted). Always look at the image before you share it. The skill makes this check mandatory for agents.

  • Local. Capture, OCR and rendering run on your machine. AInotate makes no network requests of its own beyond loading the pages you ask it to capture.

Platform support

macOS

Windows

Linux

Annotate, frames, export

verified

experimental

experimental

Web capture (Playwright, CDP)

verified

experimental

experimental

Screen and window capture

verified

experimental

experimental (X11)

UI elements (window --target, elements)

verified (Accessibility)

not yet

not yet

OCR (locate, text targets)

verified (Vision)

experimental (Windows OCR)

experimental (Tesseract)

Clipboard

verified

experimental

experimental

MCP server

verified

experimental

experimental

Experimental means implemented and unit-tested with mocks, not yet verified on real Windows or Linux machines. Reports are welcome.

License

Copyright © 2026 DontPayFull. AInotate is free software under the GNU Affero General Public License v3.0 or later. If you run a modified AInotate as a network service, the AGPL requires you to offer its source to the users of that service.

Bundled and derived third-party work (the Inter font, arrow proportions from Arrowshot, a label-placement idea from github/awesome-copilot) and dependency licenses are listed in NOTICE.


Available Tools

16 tools
animateA

Animation from image paths, one frame per image: APNG (full color, default) or GIF (plays everywhere: Slack, mail, Jira). Use it to show a short sequence of states; for steps the user should read, make_guide is clearer. Draft by default (temp folder): check the preview, then call again with draft=false to save to the output folder. The preview shows the first frame. Writes one file; the inputs are not changed. Returns the path, frame count, format, size and a preview.

Inputs: frames (required), loop, name, draft, +4 more.

annotateA

Draw marks on an existing image: numbered steps, boxes, arrows, labels, highlights, spotlight, text and solid redaction. Use it once you have an image and exact rects (from capture_web, capture_window targets, locate, or grid + zoom); for a web page in one call use shoot instead. Draft by default (temp folder): check the preview, then call again with draft=false to save to the output folder. spec: {"input": path, "scale": 1|2.., "crop": "auto"|[x1,y1,x2,y2], "name": "...", "marks": [{"type": "step"|"box"|"arrow"|"highlight"|"spotlight"|"redact"|"text"|..., "rect": {x,y,w,h} or [x1,y1,x2,y2], "label": "...", "n": 1, "color": "look|bad|good|info"}]}. Every coordinate in one unit; scale converts it to image px. Full reference: resource ainotate://spec. Writes PNG files only; never changes the input image. Returns paths, image size, warnings, legend (step numbers + labels), redactions and a preview.

Inputs: spec (required), look, draft.

capture_screenA
Read-onlyIdempotent

Screenshot the whole screen or one region, as the user sees it right now. Use it for something that spans several windows or is not in any one window; prefer capture_window for one app (no overlap from other windows) and capture_web for web pages (exact element rects). macOS needs the Screen Recording permission for the app that runs this server (Claude Desktop, the terminal...); without it the capture comes back blank and the error says how to fix it. Linux needs mss (X11) or grim (Wayland). Writes a PNG to the temp folder. Returns its path and size, and a preview; then locate elements with locate or grid + zoom and annotate with scale 1.

Inputs: region.

capture_webA

Screenshot a web page in a headless browser (Playwright) and measure named elements, so you can annotate with exact rects. Use it for web UIs; for desktop apps use capture_window, for what is on screen right now capture_screen. Pass url to load a page, or cdp_url + page_url_contains to attach to a browser that is already running and logged in (the tab is captured as is). Loads the page over the network; actions (click, fill) run in that page and can change state on the site, so only pass actions the user asked for. Presets: laptop 1280x800@2, wide 1600x1000@2, phone 390x844@3. Needs ainotate[web] and a Playwright browser (doctor checks). Returns the PNG path (temp folder), rects in CSS px, scale (use it as the spec scale), missing targets with the reason, a spec stub and a preview with the rects outlined.

Inputs: url, preset, actions, browser, +7 more.

capture_windowA
Read-onlyIdempotent

Screenshot one window by id (from list_windows); never moves, resizes or focuses it. On macOS other windows covering it do not show; on Windows and Linux they may, since the fallback grabs the window's screen area. Use it for desktop apps; capture_screen for several windows, capture_web for web pages. macOS only: targets {name: {"element": label, "role"?, "nth"?, "exact"?}} measures buttons and fields through Accessibility (needs that permission) and returns their rects plus the scale for the annotate spec. Needs Screen Recording on macOS. Writes a PNG to the temp folder. Returns its path, size, window_id, rects and scale when targets were given, and a preview.

Inputs: id (required), targets.

clipboard_imageA
Read-onlyIdempotent

Save the image that is on the clipboard (e.g. a screenshot the user just copied) as a PNG in the temp folder, so you can annotate it. Use it when the user says they copied a screenshot; for a file they sent, pass its path to annotate or locate directly. Reads the clipboard, does not change it. Linux needs wl-paste or xclip. Returns the PNG path, size and a preview.

Inputs: no named parameters.

compareA

Before/after plate: two images side by side or stacked, each with a label (default "Before", "After"; pass labels in the audience's language). Use it to show a UI change or a fix. Draft by default (temp folder): check the preview, then call again with draft=false to save to the output folder. Writes one PNG; the inputs are not changed. Returns the path, size and a preview.

Inputs: after (required), before (required), name, draft, +2 more.

copy_to_clipboardA
DestructiveIdempotent

Put an image on the system clipboard so the user can paste it into Slack, Jira or mail. It REPLACES whatever the clipboard holds, so tell the user, and use it only when they want to paste; otherwise give them the file path. Works on macOS, Windows and Linux (wl-copy or xclip). Returns the path that was copied.

Inputs: path (required).

doctorA
Read-onlyIdempotent

Check what AInotate can do on this machine: Pillow, font, output folder, Playwright and its browser, a CDP browser, screen capture permission, window listing, OCR engines, clipboard and mcp. Use it first when a tool fails with a missing dependency or permission, or before a long task on a new machine. Read-only: changes nothing. Returns ok, os, every check with its status and the exact fix for each failed one.

Inputs: no named parameters.

gridA
Read-onlyIdempotent

Overlay a labelled coordinate grid every step px on an image, to find roughly where an element is when locate cannot read it (icons, images, no text). Then call zoom on that area for the exact rect. Writes the grid image to the temp folder; the input is not changed. The preview IS the grid, labels in source image px. Returns the grid path and the source image size.

Inputs: image_path (required), step.

list_windowsA
Read-onlyIdempotent

List the visible windows: [{id, app, title, bounds}], to get the id for capture_window. filter = case-insensitive substring of the app name or title. Reads window metadata only (on macOS the titles need the Screen Recording permission). Returns count, windows and a suggestion.

Inputs: filter.

locateA
Read-onlyIdempotent

Find visible text on an image by OCR and return its rect, for images where you have no DOM or accessibility data (desktop captures, the user's screenshots). Rects are [x1,y1,x2,y2] in image px (spec scale 1), best match first; several equally good matches = ambiguous: ask the user, or pass nth (0-based, reading order) or within [x1,y1,x2,y2]. all=true also lists weaker matches. Runs on this machine (macOS Vision, Windows OCR or Tesseract); reads the image, writes nothing. If the text is not found, use grid + zoom. Returns matches with score and a preview outlining them.

Inputs: text (required), image_path (required), all, nth, +4 more.

make_guideA

Build a step-by-step guide from annotated images: Markdown, HTML and/or PDF, one image and text per step, every image at its own size. Use it after annotate when the user wants a how-to or documentation; for a single image just deliver the annotate output. Draft by default (temp folder): check the preview, then call again with draft=false to save to the output folder. PDF uses Playwright when available, else a Pillow page per step. Writes files only. Returns the file path per format, the PDF backend, warnings and a preview of the first step.

Inputs: steps (required), name, draft, title, +1 more.

previewA
Read-onlyIdempotent

Debug render of an annotate spec: draws the marks plus cyan target rects and magenta label boxes so you can see why a label moved or a mark misses its element. Use it when the annotate preview looks wrong; it is not a deliverable. Writes only a temp file, saves nothing to the output folder. Returns the temp path, warnings and the preview.

Inputs: spec (required), look.

shootA

One call from URL to annotated image: capture_web + annotate, with marks that point at elements by "target" instead of "rect". Use it for web pages when you know the visible text, role or selector of every element; use capture_web + annotate when you need to inspect rects first. spec = render spec without input/scale, plus url (or cdp_url + page_url_contains), preset, actions and marks with "target": {...} (same forms as capture_web). Emails, tokens, card numbers and password fields are redacted with solid blocks automatically. Loads the page over the network; actions run in the page. Draft by default (temp folder): check the preview, then call again with draft=false to save to the output folder. Returns paths, warnings, legend, redactions, the capture's resolved rects and a preview.

Inputs: spec (required), look, draft.

zoomA
Read-onlyIdempotent

Enlarged crop of [x1,y1,x2,y2] with a fine grid labelled in SOURCE image px, so you can read an exact rect straight off the preview (spec scale 1). Use it after grid, or to check a rect from locate. Keep regions under ~500 px wide or the labels get too dense. Writes the crop to the temp folder; the input is not changed. Returns the zoom path, region, size, notes and the preview.

Inputs: x1 (required), x2 (required), y1 (required), y2 (required), +2 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.3/5.0

    Scored across 16 tools

    Disambiguation5/5

    Each tool targets a distinct resource or stage: capture_web/capture_window/capture_screen differ by source, shoot is explicitly a shortcut combining capture_web+annotate, and preview is clearly framed as a non-deliverable debug render. The locate vs grid+zoom split (text vs non-text) and the annotate/make_guide/compare/animate outputs are all spelled out, so misselection is unlikely.

    Naming Consistency3/5

    Names mix bare verbs (annotate, preview, shoot, locate, compare, animate) with verb_noun compounds (capture_web, list_windows, make_guide, copy_to_clipboard) and bare nouns (grid, zoom, doctor). Every name is readable and snake_case is used throughout, but there is no single predictable pattern.

    Tool Count4/5

    16 tools is slightly on the heavy side but each earns its place, covering capture, coordinate-finding, annotation, composition, delivery and diagnostics without obvious redundancy. It fits the multi-stage screenshot-annotation workflow well.

    Completeness4/5

    The surface covers the full lifecycle: acquire (web/window/screen/clipboard), locate coordinates (OCR/grid/zoom), annotate, compose (guide/compare/animate), deliver (clipboard/file) and self-diagnose (doctor). Minor gaps like a general crop/convert or image-info utility exist, but agents can work around them via annotate's crop.

    Maintenance

    ActivityMaintained
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      A
      quality
      D
      maintenance
      Enables LLMs to capture screenshots and screen recordings through MCP with chunked session-based transfers for reliable image consumption. Supports multi-monitor selection, timeline capture, and compatibility with both vision and non-vision language models.
      11
      1
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to capture any public URL as PNG, JPEG, or PDF via REST API or MCP tools, including screenshot capture, page description, and PDF rendering.
      18 npm
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables users to capture any screen or URL, box the region they mean, attach notes, and deliver that annotated feedback—including cropped images, numbered boxes, and the underlying DOM elements or component names—directly to an AI coding agent over MCP. It also lets agents open the annotator, capture a URL, and wait for or retrieve feedback bundles from earlier sessions.
      MIT