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 installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceMCP server for visual feedback, video direction, and QA assertions on web pages, enabling AI agents to read, reply, and resolve annotations in real time.4MIT
- Flicense-qualityAmaintenanceMCP server that exposes web page annotations to AI coding agents, enabling automated implementation of visual feedback and design tweaks.1132
- Alicense-qualityCmaintenanceA MCP server that enables AI coding agents to consume structured UI feedback via click-to-annotate, supporting issue types and severity levels.11MIT
- AlicenseAqualityBmaintenanceMCP 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.8MIT
Related MCP Connectors
MCP server for AgentDocs (agentdocs.eu): read, search, write, comment on & share Markdown docs.
A paid remote MCP for AI agent browser approval MCP, built to return verdicts, receipts, usage logs,
A paid remote MCP for AI agent browser DevTools MCP, built to return verdicts, receipts, usage logs,
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nahar-strativ/Agentic'
If you have feedback or need assistance with the MCP directory API, please join our Discord server