План: скиллы Docsbook под продажи продукта

Дата: 2026-08-01. Основано на аудите кода, не на предположениях: 65 MCP-тулов в src/app/api/mcp/server/route.ts, markdown-lsp (семантический поиск + граф на эмбеддингах), 43 существующих скилла в index.json на момент написания. (К концу третьей сессии на проде: 84 тула = 66 named + 18 webhook-регистраторов, 52 скилла. Цифры ниже по тексту — на момент написания плана.)

Документ — рабочий план. Разделы 1–3 объясняют, из чего строим. Разделы 4–7 — что делаем: сначала на существующих тулах, потом на новых.

Где мы сейчас (обновлено 2026-08-01, конец третьей сессии). Этапы 1 и 2 выполнены, Этап 3 начат — каталог 43 → 52 скилла. Разделы 5 и 5-бис реализованы. На проде живут и проверены боевым вызовом два новых тула: fetch_url (T1) и get_page_diff_impact (T7); скиллы, которые они разблокировали, написаны. Следующая работа — T6 suggest_internal_linksdocs-link-weaver.

Продолжаешь в новом чате — читай §6 → «Как продолжить в новом чате»: там состояние одной таблицей, инварианты каталога, порядок добавления скилла, грабли и точка входа. Цифры в §1 и §4 — на момент написания плана; актуальные статусы отмечены ✅ прямо в таблицах.

Одно предупреждение, которое экономит час. Работа идёт в ДВУХ репозиториях: скиллы — здесь, MCP-тулы — в основном (src/app/api/mcp/server/route.ts + src/lib/mcp/). Приёмка у них разная, и MCP-тул проверяется на проде только с Bearer-токеном: анонимный билдер отдаёт 4 тула из 84, и свежий тул там отсутствует по устройству, а выглядит это как «не задеплоился».


1. Что реально есть под капотом#

1.1 Главная цифра#

65 MCP-тулов существует. Скиллы используют 26. Простаивает 39.

Простаивает почти всё, что относится к продажам и поиску. Ценность уже построена в продукте — но нейросеть про неё не знает, потому что нет скилла, который её оркестрирует. Это дешевле любой новой фичи: писать надо markdown, не код.

1.2 Простаивающие тулы, которые прямо про деньги#

Тул Что отдаёт План Почему это продажи
get_search_rankings живой Google Search Console: position, impressions, clicks, queries + готовый набор «позиция 5–20» free Единственный источник правды для SEO. Сейчас docs-seo гадает по тексту страницы, не зная ни одной реальной позиции
get_search_zero_click поиск сработал, результаты были, читатель отверг все PRO Указывает на заголовки и сниппеты, а не на отсутствие страницы. Zero-result отчёты этот класс пропускают целиком
get_chat_intent разговоры по стадии покупки: evaluation / pricing / integration / support / bug PRO+ Прямой ответ на «кто решает купить и что блокирует»
get_chat_outbound_hosts куда чат реально уводит людей, с отметкой целевой страницы воркспейса PRO «Чат гонит на pricing или сливает трафик на сторону?»
get_content_health скор 0–100 на страницу (dead-end + негатив) PRO Готовая очередь «что чинить первым» без ручной сверки отчётов
get_insights ранжированный дайджест фиксов с оценкой impact PRO+ Практически готовый скилл-редактор внутри одного тула
get_rage_signals 3+ перезаходов на страницу за визит, A→B→A, повторные поиски PRO Где именно сломалось, а не факт, что визит провалился
get_visit_outcomes success / dead end / bounce / partial + self-serve resolution rate PRO Метрика №1 для доки как канала самообслуживания
get_reverse_funnel работает назад от успешных визитов: какие входы ведут к успеху PRO Не требует гипотезы, в отличие от forward-воронки
get_route_patterns реальные последовательности из 2–4 страниц и чем кончаются PRO Отличает задуманный маршрут от трёх случайных заходов
get_metric_timeseries одна метрика по дням. Ровно 6: dead_end_rate, self_serve_resolution_rate, visits, success, dead_ends, median_time_to_first_value PRO «Стало ли хуже» + привязка к дате релиза
get_retention W1/W4 по недельным когортам BUSINESS Единственный когортный взгляд в системе; остальное — снимки
get_change_history коммиты по контенту: days, path, sha, limit Замыкает петлю «правка → эффект», которой сейчас нет вообще
search_docs / write_docs / get_doc_outline чтение и запись контента Позволяет скиллу не только советовать, но и чинить

1.3 markdown-lsp#

Под капотом уже есть то, что обычно и есть весь продукт конкурента: полнотекстовый и семантический поиск на эмбеддингах с гранулярностью страница / заголовок / строка, граф ссылок, backlinks, resolve-link, get-section, экспорт графа. Это делает возможными скиллы, которые рассуждают о смысловой структуре доки, а не только о тексте: находить дубли по смыслу, предлагать недостающие связи, сравнивать наш корпус с чужим.


2. Чего нет: весь наружный мир#

Проверено по коду: в MCP нет ни одного тула, выходящего за пределы воркспейса. Ни fetch, ни crawl, ни SERP, ни цитирований в LLM.

Последствия, которые уже болят:

  • Скиллы, говорящие про конкурентов (docs-imagine, docs-audience-enricher, docs-from-site, docs-create), опираются на веб-тулы самого агента. Работают у того, у кого они есть, и не работают в вебовом чате Docsbook.
  • get_search_rankings говорит, на какой мы позиции, но не говорит, кого обгонять.
  • docs-ai-retrieval учит писать под цитирование LLM — а проверить, цитируют ли нас, нечем.
  • Дока может годами врать про цены и лимиты конкурента, и ни один аудит этого не поймает: все аудиты смотрят внутрь.

Вывод: веб-фетч — не «ещё один тул», а недостающая ось. Без него весь класс рыночных и конкурентных скиллов физически непостроим.


3. Новые тулы: что добавить и что это разблокирует#

По убыванию отдачи.

# Тул Что делает Разблокирует Сложность
T1 fetch_urlСДЕЛАН одна публичная страница как markdown, с лимитом и явным сообщением об усечении competitor-gap, trust-audit, pricing-consistency ✅ — все три написаны оказалась низкой, но не из-за crawl-site.js (это CLI-скрипт): переиспользован боевой safeFetch/robots/htmlToMarkdown из основного репо
T2 fetch_competitor_docs ⏸ отложен обёртка над T1: sitemap → outline → карта чужой доки одним вызовом docs-competitor-gap без ручного обхода 200 страниц — но он и так читает вширь и останавливается рано низкая (поверх T1). Ждём доказательства, что ручной обход дорог
T3 get_serp_context кто реально в топе по нашему запросу замыкает get_search_rankings: знаем позицию, узнаём соперника средняя (внешний API)
T4 get_ai_citations цитируют ли нас ChatGPT / Perplexity / AI Overviews по нашим темам весь GEO-блок становится измеримым средняя
T5 compare_docs семантический дифф двух корпусов через markdown-lsp gap-анализ на эмбеддингах вместо «на глазок» средняя — эмбеддинги уже есть
T6 suggest_internal_links по семантическому графу предложить недостающие связи превращает docs-navigation-linking из аудита в фикс низкая
T7 get_page_diff_impactСДЕЛАН композиция get_change_history × get_metric_timeseries + контрольная группа из нетронутых страниц docs-change-impact ✅ написан — «моя правка сработала?» отвечается впервые низкая, как и ожидалось (композиция существующих)

Про T1 отдельно: он не требовал новых внешних интеграций и новых секретов. Это была самая дешёвая позиция в таблице и одновременно самая разблокирующая — расчёт подтвердился, тул закрыл весь Этап 2 за одну сессию. По той же логике следующий — T7: он тоже ничего не интегрирует, а собирается из двух уже существующих тулов.


4. Категоризация: 4 бизнес-оси вместо 7 технических категорий#

Нынешние категории (analysis / creation / publishing / observability / growth / planning / automation) описывают, что скилл делает. Продуктовник ищет по тому, какую цель он закрывает. Предлагаю бизнес-оси как основную разметку, технические категории оставить служебным тегом.

Ось A — ACQUISITION: привести людей (SEO + GEO)#

Скилл Статус Стоит на
docs-seo СДЕЛАНО ✅ v1.2.0 get_search_rankings вместо гадания по тексту
docs-rank-recovery СДЕЛАНО ✅ новый набор «позиция 5–20» из GSC — самый дешёвый рост трафика, который бывает
docs-query-coverage новый GSC × get_doc_outline: показывают, а страницы под запрос нет
docs-ai-retrieval есть пишет под цитирование LLM
docs-geo-visibility новый · T4 замеряет, цитируют ли нас реально
docs-competitor-gap СДЕЛАНО ✅ новый темы конкурента, которых у нас нет — но выдаёт не дифф оглавлений, а то немногое из него, что нам правда нужно
docs-serp-positioning новый · T3 под кого именно переписывать страницу

Ось B — ACTIVATION: чтобы дошли до ценности#

Скилл Статус Стоит на
docs-dead-end-hunter есть get_visit_outcomes
docs-rage-fixer новый get_rage_signals — где читатель кружит
docs-title-rewriter СДЕЛАНО ✅ новый get_search_zero_click — заголовки отвергли, страница есть
docs-journey-repair новый get_route_patterns + get_reverse_funnel
docs-health-triage СДЕЛАНО ✅ новый get_content_health + get_insights — план работ на неделю одной командой
docs-link-weaver новый · T6 не находит битые связи, а достраивает недостающие

Ось C — CONVERSION: чтобы купили#

Фокус на продажи. Сейчас здесь один скилл при том, что данных под ось больше всего.

Скилл Статус Стоит на
docs-sales-conversion есть пишет доку так, чтобы продавала
docs-buying-blockers СДЕЛАНО ✅ новый get_chat_intent — что спрашивают на стадии pricing и что блокирует
docs-chat-to-pricing новый get_chat_outbound_hosts — чат ведёт к нам или на сторону
docs-link-click-analyzer есть CTR по CTA
docs-objection-answers новый негатив + unanswered × стадия покупки → страницы-ответы на возражения
docs-pricing-consistency СДЕЛАНО ✅ новый цена в доке против ЖИВОЙ страницы цен (не против константы в репо — это docs-maintenance)
docs-market-positioning новый · T1/T2 наше позиционирование против того, что конкуренты пишут прямо сейчас

Ось D — RETENTION & TRUST: чтобы не ушли и верили#

Скилл Статус Стоит на
docs-maintenance есть стухший контент
docs-sync есть дрейф код↔дока
docs-change-impact СДЕЛАНО ✅ новый · T7 правка × качество визитов на затронутых страницах ПРОТИВ нетронутых. Петля обратной связи закрыта
docs-retention-cohorts новый get_retention (BUSINESS)
docs-trust-audit СДЕЛАНО ✅ новый дока не врёт про интеграции, лимиты и чужие цены, изменившиеся снаружи
docs-semantic-dedup новый · T5 две страницы про одно и то же — каннибализация выдачи и путаница читателя

5. Три режима работы: аудит / рефакторинг / письмо по правилам#

Статус: РЕАЛИЗОВАНО (Этап 1, пункты 6–7). Режим объявляется в metadata.mode, проверяется стражем. Добавился четвёртый — platform (настраивает воркспейс, а не контент): без него 11 скиллов пришлось бы врать про свой режим. Раздел оставлен как обоснование.

Отдельная и недооценённая проблема. Сейчас есть «analysis» (найти) и «creation» (сделать с нуля), а между ними дыра: нет режима «пишу новое, но сразу правильно». Из-за этого docs-analyze находит одни и те же дефекты по кругу — их продолжают порождать.

Режим Когда Что делает Что ему запрещено
audit дока есть, надо понять что не так только отчёт ничего не меняет
refactor дока есть и плохая правит существующее, сохраняя смысл не создаёт новые страницы
authoring guardrail пишем новое свод правил, подключаемый до написания не чинит старое

Третий режим сейчас отсутствует. Предлагаю docs-authoring-rules — один компактный свод (Diátaxis + retrieval-паттерны + стиль + структура + конверсионный минимум), который агент грузит перед написанием любой страницы. (Сделано: 159 строк, правила сжаты из девяти аудиторов, которые ловят эти же дефекты постфактум.)

Это же решает смешение, о котором был вопрос: три непересекающихся режима вместо нынешней каши, где docs-create и docs-analyze частично перекрываются. Каждому скиллу в каталоге проставляется режим — и правило «аудит никогда не пишет» становится проверяемым.


5-бис. Правило: скилл называет потребность, а не тул#

Статус: РЕАЛИЗОВАНО (Этап 1, пункт 0). Цифры ниже — на момент написания плана; по факту нарушителей оказалось 22 из 43, стало 10, и все 10 — тулы-цели. Правило удерживается стражем scripts/check-catalog.js в CI, иначе откатилось бы (см. последний пункт §7).

Проблема#

README продаёт принцип «states the need, not the tool». Факт по коду: 19 из 43 скиллов зашивают имена MCP-тулов. То есть README врёт, а половина каталога нарушает собственную архитектуру.

Пример — docs-question-clusterer перечисляет пять тулов-коллекторов (get_ai_questions + get_ai_unanswered + get_negative_feedback + get_failed_searches + get_popular_searches). Всё, что они делают, уже описано в их же description внутри MCP-сервера, и описания там подробные. Дублирование в скилле даёт три дефекта:

  • дрейф — тул переименуют или добавят шестой, скилл об этом не узнает;
  • сужение — скилл выдал модели закрытый список из 5 источников при 39 простаивающих; сама она нашла бы, например, get_search_zero_click;
  • ломка вне Docsbook — скилл становится неработающим без нашего MCP, хотя мог бы отработать на grep.

Правило#

Скилл описывает потребность и критерий приёмки. Имя тула допустимо только там, где тул — цель действия, и никогда — там, где тул это способ добыть данные.

Три исключения, где имена остаются:

  1. Платформенные скиллы. docs-setup-workspace буквально и есть «выставь branding / seo / geo / languages». Тул тут не деталь реализации, а предмет скилла — без него скилл ни о чём.
  2. Гейты по планам. Фактическая справка «этого нет на free» спасает от падения на середине. Но формулировать как ограничение потребности, а не как «вызови тул X».
  3. Антидубль-guardrails. «Не пересекайся с docs-gap-finder» — это про скиллы, не про тулы. Остаётся.

Побочный эффект в нашу пользу: скилл без имён тулов честно работает на голом агенте и становится лучше при подключённом MCP — ровно то, что README и продаёт.

Следствие для этого плана#

В разделах 4 и 6 скиллы описаны через «стоит на get_chat_intent» — это язык плана, а не скилла. В сами SKILL.md имена переносить нельзя.


6. Порядок работ#

Этап 1 — ВЫПОЛНЕН 2026-08-01 (коммит 6281fe2)#

Каталог 43 → 48 скиллов. Что фактически сделано против плана:

# Пункт Итог
0 Ревизия по правилу 5-бис 22 нарушителя → 10, и все 10 — тулы-цели (мутации: update_*, set_*, register_webhook_*). README исправлен: продавал принцип, который нарушала половина каталога
1 docs-seo на реальные позиции Аудит стартует с фактических позиций/показов/запросов; без данных деградирует в помеченные гипотезы, а не молча гадает
2 docs-rank-recovery Новый. Набор «5–20» → очередь переписывания, отделяет «не тот интент» от «слабая подача»
3 docs-health-triage Новый. Сигналы → один ранжированный план недели, раздаёт работу исполнителям
4 docs-buying-blockers Новый. Разговоры по стадии покупки + конкурентная разведка
5 docs-title-rewriter Новый. «Поиск сработал, читатель отверг все» → заголовки словами читателя
6 docs-authoring-rules Новый. Третий режим — свод правил ПЕРЕД написанием, 159 строк
7 Режим всем скиллам metadata.mode в схеме + index.json: audit 24 / platform 11 / authoring 8 / refactor 5

Сверх плана — то, без чего пункт 0 откатился бы назад (риск из §7):

  • scripts/check-catalog.js — тест-страж в CI до publish: имена тулов в телах, наличие режима, существование id метрик и путей словаря, поля frontmatter по схеме, счётчики README против каталога. Проверен A/B: ловит подсаженное нарушение, не только зеленеет.
  • Баг в sync-skills.js: git схлопывает целиком новый скилл до папки (?? skills/foo/), поэтому строка не матчила /SKILL.md — релиз с пятью новыми скиллами оценивался как patch вместо minor.

Долг, обнаруженный по ходу Этапа 1 и закрытый позже в тот же день: в metrics/metric-dictionary.json не было id для позиции/показов/CTR из Search Console, поэтому docs-seo и docs-rank-recovery объявляли только traffic/search_ctr — метрику не выдумывали. Что именно сделано и что при этом вскрылось — ниже, в блоке «Долг по словарю».

Как продолжить в новом чате#

Всё ниже — факты, проверенные в работе, а не намерения. Читать до того, как что-то менять.

Состояние на 2026-08-01 (конец второй сессии).

Каталог 52 скилла, 7 категорий. Режимы: audit 28 / platform 11 / authoring 8 / refactor 5
npm docs-skills@1.8.22 (публикует CI, не руками)
Этап 1 ✅ выполнен — каталог 43 → 48, страж в CI, режимы
Долг по словарю метрик ✅ закрыт — GSC-метрики заведены
Этап 2 выполнен полностью: T1 fetch_url + все три скилла, которые он разблокировал (docs-competitor-gap, docs-pricing-consistency, docs-trust-audit)
Этап 3 🟡 начат. T7 get_page_diff_impact + docs-change-impact ГОТОВЫ (см. ниже). Следующий — T6 suggest_internal_linksdocs-link-weaver
Что осталось от Этапа 2 T2 fetch_competitor_docsнамеренно не делали: он оправдан, только когда станет видно, что обход руками через fetch_url дорог. Данных на это пока нет

Индекс — index.json на main; в npm-пакет он не входит намеренно (files в package.json), потребители тянут его с raw.githubusercontent.com.

Где что лежит.

Что Где Замечание
Скиллы skills/<name>/SKILL.md, часть в skills/<category>/<name>/ Обе раскладки живые. От вложенности зависит путь metric_dictionary (../../ vs ../../../) — страж это проверяет
Копия для агентов .claude/skills/ Генерируется, руками не править
Индекс index.json Собирается node scripts/build-index.js
Схема frontmatter schema/skill.schema.json additionalProperties: false — лишний ключ роняет проверку
Словарь метрик metrics/metric-dictionary.json Единственный источник id для measures
Страж scripts/check-catalog.js (= npm test) Висит в .github/workflows/publish.yml до publish

Два инварианта каталога — их легко откатить по невнимательности.

  1. Скилл называет потребность, не тул. Имя MCP-тула в теле SKILL.md допустимо, только если тул — цель шага (update_branding, register_webhook_*), и никогда — если это способ добыть данные (get_*, list_*, search_*). Во frontmatter metadata.uses_mcp_tools имена нужны: это машинный контракт для index.json. Аллоулист целей — константа GOAL_TOOLS в страже; read-тул туда добавлять нельзя.
  2. Каждый скилл объявляет metadata.modeaudit / refactor / authoring / platform. Актуальную разбивку смотри в таблице состояния выше (она меняется с каждым скиллом; на конец второй сессии — audit 27 / platform 11 / authoring 8 / refactor 5).

Приёмка любой правки: node scripts/check-catalog.js зелёный. Он же ловит выдуманные id метрик, битые пути словаря и разъехавшиеся счётчики README.

Как добавлять скилл (проверенная последовательность).

  1. Написать skills/<name>/SKILL.md. Не называть read-тулы в теле — только потребность; имена идут в metadata.uses_mcp_tools.
  2. Обновить Related-секции соседей, с которыми скилл граничит, — иначе связь односторонняя, и следующий читатель не поймёт, чем эти скиллы отличаются.
  3. node scripts/sync-skills.js --apply — пересоберёт index.json, счётчики в README каталога и секцию родительского README между <!-- skills:start/end -->. Генератор англоязычный (родительский README англоязычен целиком) — язык не менять.
  4. node scripts/check-catalog.js должен быть зелёным. Он же валидирует словарь метрик.
  5. git pull --rebase origin maingit push.

Грабли, на которые уже наступили (не повторять).

  • Первый git push отбивается rejected — это норма, не авария. CI на каждый пуш в main сам делает chore: release vX [skip ci] и публикует в npm. Лечится git pull --rebase origin main и повтором. Свой npm version / npm publish не гнать — будет version_exists и путаница с тем, выпущена ли версия.
  • Проверять публикацию нужно фактом, и npm pack без версии ВРЁТ. Он отдаёт закэшированный тарбол: показывал 49 скиллов при 51 уже опубликованных, что выглядело как «CI выложил не всё». Правильно — npm pack docs-skills@<версия> --prefer-online, либо gh run view <id> --repo Docsbook-io/docs-skills --log | grep "npm notice". Отсутствие index.json в тарболе — не дефект, см. выше.
  • sync-skills.js чинили трижды за одну сессию — если он «ничего не сделал», это скорее его дефект, чем отсутствие изменений. Уже исправлено: (а) генератор README целил в формат до переписывания Этапа 1 и молча не матчил ничего; (б) package.json правился, но не попадал в коммит; (в) шаг релиза дублировал CI и всегда падал ПОСЛЕ пуша скиллов; (г) счётчик скиллов убран из package.json — он был единственным полем, которое скрипт писал в файле, где CI пишет версию, и давал гарантированный конфликт при каждом новом скилле. Конфликт package.json при rebase теперь возникать не должен; если возник — версию берёшь их, остальные поля свои.

Долг по словарю — ЗАКРЫТ 2026-08-01 (43fae3b в каталоге, 9455e5de в родительском репо). search_position, search_impressions, organic_ctr заведены и подключены к docs-seo (1.3.0) и docs-rank-recovery (1.1.0). Что попутно вскрылось и что теперь надо знать:

  • GSC не проходит через слой паттернов. mcp_patterns описывался как id из patterns.ts, а Search Console приходит прямо из get_search_rankings. Фиктивный паттерн заводить не стали: смысл поля расширен (ключ оставлен прежним, чтобы не двигать скомпилированную копию в продукте), а множество допустимых источников вынесено в metrics/sources.json. Список продублирован руками намеренно — CI каталога чекаутит только этот репозиторий, и реестр, живущий в продукте, был бы зелёным локально и неверным в CI.
  • Страж теперь валидирует сам словарь, а не только скиллы, которые на него ссылаются: метрика с несуществующим источником и битая перекрёстная ссылка (related_metrics / pairs_with) роняют проверку. Проверено подсадкой обоих нарушений.
  • Словарь живёт в двух местах. После правки metric-dictionary.json обязателен node scripts/build-metric-dictionary.mjs в родительском репо — он инлайнится в src/lib/analytics/metric-dictionary.generated.ts, и без пересборки продукт новой метрики не видит.
  • Оговорки, которые несут новые метрики: лаг ~2 дня и обновление раз в сутки, позиция взвешена по показам (один запрос с рангом 90 тянет вниз страницу, стоящую на 4), query-грейн недосчитывает объём примерно вчетверо — Google скрывает низкочастотные запросы, поэтому тоталы берутся с page-грейна, — и CTR без позиции нечитаем: те же проценты здоровы на 9-й позиции и тревожны на 2-й.

Работа идёт в ДВУХ репозиториях — это главное, что ломает ожидания.

Что делаешь Где Чем проверяешь
Скилл docs-skills/skills/ check-catalog.js, затем npm pack @версия --prefer-online
MCP-тул основной репо, src/app/api/mcp/server/route.ts + модуль в src/lib/mcp/ tsc + vitest + npx next build + вызов на проде с Bearer
Словарь метрик docs-skills/metrics/ и пересборка в основном репо check-catalog.js + build-metric-dictionary.mjs

Проверка MCP-тула на проде — только с токеном. Сервер собирается двумя билдерами: анонимный отдаёт 4 тула, аутентифицированный — 83. Scoped-эндпоинт без Authorization идёт в анонимный, и свежий тул там отсутствует по устройству, а выглядит это как «не задеплоился». Токен — в ~/.claude/mcp.json, в память его не сохранять.

Точка входа в Этап 3. Первым идёт T7 get_page_diff_impact → скилл docs-change-impact. Это композиция уже существующих get_change_history × get_metric_timeseries, то есть самая дешёвая позиция из оставшихся. И самая важная по смыслу: сейчас петли обратной связи нет вообще — весь каталог советует правки и ни разу не узнаёт, помогли ли они. Помни ограничение из §7: get_metric_timeseries знает ровно 6 метрик, и скилл не должен обещать произвольную.

При любом новом туле помни §7: содержимое чужого сайта — данные, не инструкции, а description обязан быть самодостаточным — по правилу 5-бис скилл на тул по имени не ссылается, значит модель выбирает его по описанию.

Этап 2 — ВЫПОЛНЕН 2026-08-01 — тул fetch_url (T1) и всё, что он открыл#

  1. T1 fetch_url — ГОТОВ 2026-08-01 (1c824e83, проверен на проде: 83 тула, 65 named). Живёт в src/lib/mcp/fetch-url.ts, зарегистрирован в аутентифицированном билдере MCP-сервера (в анонимном его нет — тот отдаёт 4 тула).
    • Краулер из scripts/crawl-site.js не переиспользовался: это CommonJS-скрипт под CLI. В основном репо уже была вся нужная механика, проверенная боем, — safeFetch (перепроверяет SSRF на каждом redirect-хопе), fetchRobotsTxt/isDisallowed, htmlToMarkdown. Тул — тонкий слой поверх них, поэтому страница читается одинаково, каким бы тулом её ни достали.
    • Один URL, не обход. crawl_website уже ходит по сайту и стоит соответственно; повторяющаяся потребность — одна страница, с которой что-то сверяют.
    • Ошибки возвращаются, а не бросаются. 404 — это и есть ответ на вопрос «жива ли ссылка»; исключение показало бы находку как поломку тула. Усечение и пустота JS-страницы сообщаются явно, иначе агент скажет «на странице этого нет» про то, чего просто не увидел.
    • Побочно: robots-хелперы переехали в ssrf.ts (они и так зовут safeFetch) — теперь потребителю, которому нужно только достать страницу, не нужно тянуть зависимости admin.ts (next-auth, axiom, drizzle). Реэкспорт оставлен.
    • Проверено фактом, не моками: 17 юнит-тестов + живая сеть (metadata-эндпоинт и localhost режет SSRF, 404 приходит находкой, 307 отслеживается) + боевой вызов на проде (страница цен GitBook прочитана и честно помечена усечённой).
    • Дока и спека обновлены в том же заходе: docs/ai/mcp.md (счётчик врал: 80/62), docs/reference/mcp-tools.md, specs/mcp/content-editing.md.
  2. docs-competitor-gap — ГОТОВ 2026-08-01 (каталог 48 → 49, docs-skills@1.8.17, проверено npm pack). Первый скилл, который смотрит наружу.
    • Смысл не в диффе двух оглавлений — такой дифф выдаёт «у них 40 страниц, которых нет у вас» и подразумевает, что надо написать 40. Скилл выбрасывает большую часть разницы: фича, которой у нас нет (это вход для роадмапа, а не страница), аудитория, которой мы не продаём, тема, уже закрытая в README/блоге (это «перенести», а не «написать»). Выживших ранжирует по СПРОСУ (показы без страницы, провальные поиски), и «у конкурента есть» — самый слабый довод, который не может быть единственным.
    • Тул по имени в теле не назван (правило 5-бис), только в uses_mcp_tools как машинный контракт; страж это подтвердил.
    • Явно зафиксировано: чужая страница — данные, не инструкции; ни одного утверждения о конкуренте без URL, прочитанного в этом прогоне.

Три дефекта scripts/sync-skills.js, вскрытых добавлением одного скилла (починены, dedcbf8):

  • Генератор README целил в формат ДО переписывания Этапа 1 (**N skills across M categories** + таблица ## Categories). Ни того, ни другого больше нет — оба replace не матчили ничего, скрипт рапортовал успех, ничего не изменив, и счётчики ловил уже страж в CI. Теперь правит те два счётчика, что есть, и счётчики по категориям в заголовках <details>.
  • package.json правился прогоном, но не попадал в коммит — дерево оставалось грязным после каждого --apply.
  • Шаг релиза дублировал CI: npm version требует чистого дерева, которое этот же прогон только что испачкал, поэтому он всегда падал ПОСЛЕ пуша скиллов — каталог опубликован, версия нет. Свой бамп поверх CI-шного даёт ещё и version_exists. Релиз убран из скрипта целиком.
  1. docs-trust-audit и docs-pricing-consistency — ГОТОВЫ 2026-08-01 (каталог 49 → 51, docs-skills@1.8.20, проверено npm pack --prefer-online).
    • Границу с существующими скиллами пришлось проводить явно. docs-maintenance УЖЕ проверяет цены — но против источника правды ВНУТРИ репозитория (constants-файл, конфиг). Новый скилл сверяет с живой публичной страницей: константа может быть верной, а опубликованная страница врать, и наоборот. Обе проверки нужны, и в docs-maintenance дописана Related-секция, иначе связь односторонняя.
    • docs-pricing-consistency узкий и проверяемый: каждая находка цитирует ОБЕ стороны дословно. Сравнивается не число, а число+единица+период+валюта одним фактом — «$19 против $19» не совпадение, если одно за место, другое за воркспейс. Legacy-план — вердикт человека, не скилла.
    • docs-trust-audit шире: любое утверждение о внешнем мире, проверяемое снаружи (партнёрские API, чужие лимиты, версии, внешние ссылки, стандарты). Ключевое: «не смог проверить» — самостоятельный вердикт, не «вероятно, ок»; их слияние и делает такой отчёт бесполезным. Утверждения, чей источник правды — свой репозиторий, объявлены вне области (это docs-sync).
    • Оба audit-режима: цену и утверждение о партнёре правит человек, тихо переписывать деньги аудит не должен.

Ещё один дефект sync-skills.js (38f41da): счётчик скиллов в package.json был ЕДИНСТВЕННЫМ полем, которое скрипт писал в том же файле, где CI пишет версию, — каждый новый скилл давал гарантированный конфликт при rebase (их версия против нашего счётчика), разрулен руками трижды за день. Число убрано: оно живёт в README, где его сверяет страж, а в описании npm-пакета не проверялось ничем и устаревало.

Грабли верификации: npm pack docs-skills отдаёт закэшированный тарбол и показал 49 скиллов при 51 опубликованных. Это выглядело как «CI опубликовал не всё». Проверять npm pack docs-skills@<версия> --prefer-online либо смотреть npm notice в логе CI (gh run view <id> --log).

  1. T2 fetch_competitor_docs — СОЗНАТЕЛЬНО ОТЛОЖЕН. Он оправдан ровно тогда, когда станет видно, что обход конкурента вручную через fetch_url дорог. Такого сигнала пока нет: docs-competitor-gap написан так, чтобы читать вширь и останавливаться, когда новые страницы перестают менять картину, — на 400 справочных страницах это десяток фетчей, а не 400. Делать обёртку до появления доказательства — оптимизация вслепую.

Этап 3 — НАЧАТ — измеримость и семантика#

  1. T7 get_page_diff_impact + docs-change-impact — ГОТОВЫ 2026-08-01 (34982a92; каталог 51 → 52; на проде 84 тула = 66 named + 18 webhook, проверено с Bearer). Петля обратной связи закрыта: каталог больше не советует правки, ни разу не узнавая, помогли ли они.
    • Композиция, а не новый источник. Живёт в src/lib/mcp/page-diff-impact.ts. Сессии за окно тянутся ОДНИМ запросом и нарезаются в памяти по времени и по пути — квота Axiom 600 запросов/час на ОРГ, поэтому «по запросу на коммит» было бы неверной формой, даже если читается естественнее.
    • Контрольная группа — суть тула, а не украшение. Считает те же метрики по НЕтронутым страницам в тех же окнах и кредитует правку, только если она обогнала тренд сайта. Правка, совпавшая с трендом, отдаётся как «эффект неразличим», а не как победа. Проверено A/B: подсадка relative = e (выброс контроля) роняет 2 теста — защита реальная.
    • Матчинг путей чуть не сделали на глазок. Заготовка стрипала docs/ и лепила свои кандидаты. Живой Axiom показал: fields.path несёт путь ФАЙЛА как он лежит в репо, и у части воркспейсов это docs/reference/api.md, у части api.md — стрип склеил бы разные страницы. Правильный ответ уже был в коде: normalizeDocPath (README.mdintroduction, README папки→папка). Тест на «не стрипать docs/» стоит стражем.
    • Три отказа вместо нулей. Коммит моложе after-окна; коммит старше горизонта видимости визитов; выборка ниже порога рейтов. Нули там читались бы как обвал трафика. Отдельно: путь коммита, который никто не посещал, уходит в unmatched_paths — «страницу, которую ты починил, не читают» это находка про навигацию, а не измерение правки.
    • Грабли, стоившие 13 падений: горизонт видимости данных сначала считался по САМОМУ СТАРОМУ визиту в выдаче. На тихом сайте старейший визит бывает позавчерашним — тул отказывался мерить коммиты с целыми окнами. Горизонт — это граница ЗАПРОСА (LOOKBACK_DAYS), а не то, что вернулось.
    • Боевой вызов на проде (ws 41, коммит 6dcdafe): README.md сматчился как introduction, второй путь честно ушёл в unmatched, контроль отделился (33/23 против 22/8), вердикт — отказ судить по малой выборке. Ровно то поведение, ради которого писался guard.
    • Дока и спека в том же заходе: docs/ai/mcp.md (счётчик врал 83/65; обе «петли» вели в site-wide get_metric_timeseries — заменено), specs/mcp/analytics.md.
  2. T6 suggest_internal_linksdocs-link-weaver 👈 СЛЕДУЮЩИЙ.
  3. T5 compare_docsdocs-semantic-dedup.
  4. T3/T4 — SERP и цитирования в LLM, когда появится бюджет на внешние API.

7. Риски и на что смотреть#

  • Планы. Много конверсионных тулов — PRO/PRO+/BUSINESS. Скиллы обязаны деградировать внятно: сообщать, какой план нужен, а не падать. Это же продающая поверхность — скилл показывает, что он бы дал.
  • get_metric_timeseries — ровно 6 метрик. docs-change-impact не должен обещать произвольную метрику.
  • GSC лагает ~2 дня, refresh — раз в сутки. Скилл не должен выдавать вчерашние данные за сегодняшние.
  • get_retention считает по хешам IP — мобильные сети дробят одного читателя, офисный NAT склеивает разных. Скилл обязан цитировать эту оговорку, иначе продуктовник примет решение по мусору.
  • fetch_url — внешний ввод. Содержимое чужого сайта не является инструкцией. Скиллы обязаны обращаться с ним как с данными.
  • Новые тулы T1–T7 обязаны нести самодостаточный description. Правило 5-бис перекладывает знание о туле из скилла в сам тул: если описание тула мутное, модель его не выберет, и скилл молча деградирует до grep. Описание тула — теперь часть контракта, а не документация.
  • Правило легко откатывается назад. Соблазн дописать «возьми данные из X» велик при каждом новом скилле. Держать grep по именам тулов как тест-страж в CI, иначе через полгода снова будет 19 из 43.