Skip to main content
Glama

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 server

Related MCP server: vibe-annotations

Установка

npm install -D earmark
import { 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-анимации, element.animate(), <video>, <audio>.

Панель: просмотр, удаление, ответ агенту, копирование 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 мог его использовать.

Инструменты

Инструмент

Назначение

earmark_list_annotations

Незавершённая работа в виде markdown (или format: "json"); ограничение по session

earmark_watch_annotations

Блокирует выполнение, пока человек не создаст аннотацию

earmark_get_annotation

Одна аннотация с полной веткой ответов

earmark_list_sessions

Какие вкладки браузера открыты и какие маршруты были аннотированы

earmark_get_session

Одна вкладка со всеми созданными ею аннотациями

earmark_acknowledge

«Я прочитал, я занимаюсь этим» — булавка становится синей

earmark_ask

Задать уточняющий вопрос — булавка становится янтарной

earmark_resolve

Отметить выполненным с резюме — булавка становится зелёной

earmark_dismiss

Отклонить с причиной, которую видит человек

earmark_clear

Удалить всё

earmark_status

Подключён ли оверлей? Какую конечную точку он должен использовать?

Цикл исправлений, который это обеспечивает:

watch → acknowledge → read the source path → edit the file → resolve → watch

acknowledge важен для всего медленного: без него агент на середине рефакторинга выглядит точно так же, как агент, который вас проигнорировал. Синяя булавка означает, что задача взята, зелёная — действительно выполнена.

Когда отзыв неоднозначен, используйте ask вместо предположений. Вопрос появляется на булавке; ответ человека пробуждает следующий watch.

Статусы

openacknowledgedresolved, с 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

Маршрут

GET /health

проверка состояния + счётчики

GET /annotations?status=open&session=ID

список

POST /annotations

создание (пакетно)

GET /annotations/wait?since=N&timeout=30000

длинный опрос

PATCH /annotations/:id

обновление статуса

POST /annotations/:id/replies

добавление в ветку

DELETE /annotations/:id · DELETE /annotations

удаление · очистка

POST /session

регистрация вкладки / запись смены маршрута

GET /sessions · GET /sessions/:id

вкладки со счётчиками и аннотациями

GET /events?session=ID

SSE-поток; также сигнал активности вкладки

GET /markdown

документ для агента

Флаги: --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 — не производная от исходного кода какого-либо другого инструмента.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all related MCP servers

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,

View all MCP Connectors

Latest Blog Posts

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