earmark
earmark
Нажмите на элемент в вашем работающем приложении, скажите, что должно измениться, и ваш агент программирования получит CSS-селектор, файл и строку исходного кода, путь к компоненту, вычисленные стили и геометрию блока — вместо «кнопка справа выглядит неправильно».
Работает в любом фреймворке. Для оверлея не требуется шаг сборки.
┌─ browser ──────────────┐ ┌─ broker ────────┐ ┌─ agent ─────────┐
│ click → annotate │ POST │ store + SSE │ MCP │ list / watch │
│ pins, panel, markdown │───────▶│ long-poll │◀──────▶│ ask / resolve │
│ │◀───────│ .earmark/*.json │ │ dismiss │
└────────────────────────┘ SSE └─────────────────┘ └─────────────────┘Попробуйте за 30 секунд
npm install && npm run exampleОткройте http://127.0.0.1:5173/examples/vanilla/, нажмите стрелку на панели инструментов (внизу справа) или нажмите alt+a, затем щёлкните любой элемент на странице.
Лендинг и полное руководство обслуживаются рядом по адресу http://127.0.0.1:5173/site/ — исходный код в site/index.html, одном автономном файле без зависимостей.
Для синхронизации с агентом в реальном времени запустите брокер во втором терминале:
npm run serverRelated MCP server: vibe-annotations
Установка
npm install -D earmarkimport { createEarmark } from 'earmark';
if (import.meta.env.DEV) {
createEarmark();
}Без бандлера:
<script type="module" src="/node_modules/earmark/src/index.js" data-earmark-auto></script>Параметры
createEarmark({
endpoint: 'http://127.0.0.1:7331', // or false for copy-paste only
hotkey: 'alt+a',
theme: 'auto', // 'auto' | 'light' | 'dark'
persist: true, // keep annotations across reloads
onAnnotate: (annotation) => {},
});Конечная точка по умолчанию указывает на локальный брокер и бесшумно деградирует, когда ничего не прослушивается — оверлей продолжает работать, точка синхронизации просто становится серой.
Использование
Инструмент | Что делает |
➤ | Нажмите на элемент. Shift-клик добавляет ещё, затем клик завершает выбор. |
T | Выделите текст — точная строка — это самое удобное для поиска, что можно передать агенту. |
⛶ | Перетащите область. Сообщает обо всех элементах внутри или отмечает пустую область. |
❊ | Замораживает всё движущееся — CSS-анимации, |
☰ | Панель: просмотр, удаление, ответ агенту, копирование markdown. |
⌘↵ сохраняет аннотацию, esc отменяет, alt+a переключает режим выбора. Каждая аннотация может быть помечена высоким, обычным или низким приоритетом; high сортируется первым для агента.
Режим копирования и вставки
Нажмите Copy markdown на панели и вставьте в своего агента:
## UI feedback — 1 annotation
- **Page:** http://localhost:5173/dashboard
- **Viewport:** 1440×900 @2x, dark mode
- **Framework:** react
### 1. Export button padding is too tight — needs 10px 16px
- **Element:** `<button>` <ExportButton>
- **Selector:** `[data-testid="export-btn"]`
- **Source:** `src/components/Card.tsx:42:7`
- **Component path:** App › Dashboard › Card › ExportButton
- **Text:** "Export"
- **Box:** 66×37 at (194, 376)
- **Computed:** padding: 7px 13px; border-radius: 8px; font-size: 13px
- **Ancestors:** div.row ← section.card ← mainРежим синхронизации с агентом (MCP)
claude mcp add earmark -- npx -y earmark-mcpИли, чтобы записать его в .mcp.json проекта:
npx earmark-mcp initЭтот процесс запускает MCP-сервер и брокер, с которым общается браузер. Если что-то не работает, спросите его почему:
npx earmark-mcp doctor✓ Node version: v24.12.0
✓ sqlite backend: available
✓ MCP registration: earmark is registered in .mcp.json
✓ Broker: responding on http://127.0.0.1:7331 — 1 annotations, 2 sessions
✓ Browser overlay: http://localhost:5173/ (1 annotations)Каждая неудачная проверка выводит команду, которая это исправляет, а doctor завершается с ненулевым кодом, чтобы CI мог его использовать.
Инструменты
Инструмент | Назначение |
| Незавершённая работа в виде markdown (или |
| Блокирует выполнение, пока человек не создаст аннотацию |
| Одна аннотация с полной веткой ответов |
| Какие вкладки браузера открыты и какие маршруты были аннотированы |
| Одна вкладка со всеми созданными ею аннотациями |
| «Я прочитал, я занимаюсь этим» — булавка становится синей |
| Задать уточняющий вопрос — булавка становится янтарной |
| Отметить выполненным с резюме — булавка становится зелёной |
| Отклонить с причиной, которую видит человек |
| Удалить всё |
| Подключён ли оверлей? Какую конечную точку он должен использовать? |
Цикл исправлений, который это обеспечивает:
watch → acknowledge → read the source path → edit the file → resolve → watchacknowledge важен для всего медленного: без него агент на середине рефакторинга выглядит точно так же, как агент, который вас проигнорировал. Синяя булавка означает, что задача взята, зелёная — действительно выполнена.
Когда отзыв неоднозначен, используйте ask вместо предположений. Вопрос появляется на булавке; ответ человека пробуждает следующий watch.
Статусы
open → acknowledged → resolved, с needs-input, когда агент ждёт человека, и dismissed, когда он отклоняет. Булавки имеют цветовую кодировку: оранжевый, синий, зелёный, янтарный, серый.
Сессии
Сессия — это одна вкладка браузера, а не одна загрузка страницы — идентификатор хранится в sessionStorage, поэтому он переживает перезагрузки. Аннотации несут собственный page.url, поэтому сессия, прошедшая по трём маршрутам, даёт агенту одну группу с тремя элементами разных маршрутов.
Навигация в SPA тоже отслеживается: pushState, replaceState, popstate и hashchange обновляют список маршрутов сессии. Вкладка считается подключённой ровно столько, сколько открыт её SSE-поток.
curl http://127.0.0.1:7331/sessionsПути к исходным файлам
Селекторы говорят агенту, что искать с помощью grep. Пути к исходникам говорят ему, где именно искать, а это разница между одной правкой и тремя grep-запросами.
React 19 удалил поле _debugSource в волокне во время выполнения, поэтому это делается на этапе сборки:
// vite.config.js
import earmark from 'vite-plugin-earmark';
export default {
plugins: [react(), earmark()],
};Каждый встроенный JSX-элемент получает data-earmark-src="src/Card.tsx:42:7" во время vite dev. Плагин также внедряет оверлей, поэтому createEarmark() в коде приложения становится необязательным.
earmark({
inject: false, // do not auto-mount the overlay
endpoint: '…', // passed through to createEarmark
applyInBuild: true, // also stamp production builds (off by default)
})Без плагина всё по-прежнему работает — вы получаете селекторы, имена компонентов и текст, только не file:line. Вы также можете добавить data-earmark-src вручную.
Простой HTML и CSS — без шага сборки
У статического сайта нет сборки, которую можно пометить, поэтому earmark определяет исходный код во время создания аннотации:
HTML — документ повторно загружается и разбирается с отслеживанием позиций, затем путь по индексам дочерних элементов проходит по исходному коду. Каждый шаг сверяется с актуальным именем тега, поэтому страница, отрендеренная фреймворком (где обслуживаемый HTML — всего лишь оболочка), не сообщает ничего, а не выдумывает строку.
CSS — каждое правило, соответствующее элементу, сопоставляется с файлом и строкой, где оно объявлено. Это работает везде, в фреймворке и без него.
- **Source:** `index.html:101:11` _(resolved from the served HTML)_
- **CSS rules that style it:**
- `button` → `index.html (inline <style>):49`
- padding: 7px 13px; border-radius: 8px; border: 1px solid var(--line);
- `button.primary` → `index.html (inline <style>):59`
- background: var(--accent); color: rgb(255, 255, 255);Теперь агент знает, что padding, который нужно изменить, находится на строке 49 в общем правиле button, а не в .primary. Встроенные блоки <style> смещаются в свой родительский документ; внешние таблицы стилей сообщают собственный путь; кросс-доменные таблицы стилей пропускаются, поскольку их содержимое недоступно для чтения.
Автономный брокер
npx earmark-server --port 7331
curl http://127.0.0.1:7331/markdownМаршрут | |
| проверка состояния + счётчики |
| список |
| создание (пакетно) |
| длинный опрос |
| обновление статуса |
| добавление в ветку |
| удаление · очистка |
| регистрация вкладки / запись смены маршрута |
| вкладки со счётчиками и аннотациями |
| SSE-поток; также сигнал активности вкладки |
| документ для агента |
Флаги: --host --store --file --no-persist --webhook --token --quiet.
Хранилище
--store json (по умолчанию) записывает читаемый .earmark/annotations.json с задержкой 250 мс. --store sqlite записывает каждое изменение немедленно в .earmark/annotations.db через node:sqlite, поэтому при сбое теряется максимум выполняемый оператор — без зависимостей, Node 22.5+, и он откатывается к JSON, если недоступен. --store memory ничего не сохраняет.
Вебхуки
npx earmark-server --webhook https://hooks.example/earmarkТакже EARMARK_WEBHOOK_URL и EARMARK_WEBHOOKS (через запятую). Каждое событие аннотации отправляется методом POST с заголовком x-earmark-event. Доставка выполняется по принципу «отправил и забыл» с таймаутом 5 с и одной повторной попыткой, поэтому неработающая конечная точка не может заблокировать цикл аннотаций.
Безопасность
Это инструмент разработки.
Брокер привязывается только к
127.0.0.1. Не привязывайте его к0.0.0.0.CORS открыт по замыслу — ваш dev-сервер работает на произвольном origin.
Любая страница, открытая в вашем браузере, может обратиться к loopback-порту. Передайте
--token SECRET, если это важно для вашей машины.Вебхуки отправляют содержимое аннотаций за пределы вашей машины — URL страниц, текст элементов и всё, что вы ввели. Настраивайте только те конечные точки, которыми управляете.
Определение исходного кода повторно загружает вашу собственную страницу и таблицы стилей с того же origin. Никуда ничего не отправляется.
Не запускайте его на общем или публичном хосте.
Тесты
npm testСемь наборов, 88 тестов: поведение хранилища и HTTP, поверхность MCP, управляемая реальным stdio-клиентом, синхронизирующий клиент оверлея, оба бэкенда персистентности, доставка вебхуков, CLI init/doctor и резолверы исходного кода.
Не поддерживается
Только настольные браузеры. Никаких iframe, никакого внутреннего устройства canvas/WebGL, никаких скриншотов. Полный открытый список и обоснование каждого дизайн-решения см. в plan.md.
Лицензия
MIT. Реализация в режиме clean-room — не производная от исходного кода какого-либо другого инструмента.
This server cannot be deployed
Maintenance
Related MCP Connectors
Agent-ready feedback for AI-built apps — read and close UI feedback reports over MCP.
MCP Server for an Agent Task Marketplace
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
An MCP server that automatically collects feedback on your MCP server.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for visual feedback, video direction, and QA assertions on web pages, enabling AI agents to read, reply, and resolve annotations in real time.6MIT
- FlicenseNot gradedqualityAmaintenanceMCP server that exposes web page annotations to AI coding agents, enabling automated implementation of visual feedback and design tweaks.1 npm190-
- AlicenseNot gradedqualityDmaintenanceA MCP server that enables AI coding agents to consume structured UI feedback via click-to-annotate, supporting issue types and severity levels.3 npmMIT
- AlicenseAqualityDmaintenanceMCP server that opens a browser and adds a comment/pencil overlay to every page, letting you annotate live sites and send the marks to your coding agent.82MIT