yandex-direct-manager · git:20261023.7178606 · 2026-10-23 · sha256 73023d1845092e87
yandex-direct-manager git:20261023.7178606A
Immutable. This exact content never changes and is served at /api/v1/blob/73023d1845092e87.
---
name: "yandex-direct-manager"
description: Тактический пайплайн создания рекламной кампании в Яндекс.Директе через MCP — сбор семантики через Wordstat, кластеризация на НЧ/СЧ/ВЧ и Поиск/РСЯ, минусация (3 уровня + кросс), создание объявлений по лимитам Директа, аудит счётчика и настройка целей в Метрике через MCP, выбор стратегии торгов и заливка в DRAFT. Используй когда пользователь говорит «сделай РК в Директе», «собери семантику», «нужны ключи и минусы», «напиши объявления», «запусти кампанию», «залей через MCP». Не для аналитики, не для оптимизации работающих кампаний, не для стратегии бренда — только создание новой кампании от брифа до DRAFT.
---
# Yandex Direct — пайплайн создания кампании
Скилл проводит маркетолога от брифа до залитой в **DRAFT** рекламной кампании в Яндекс.Директе. Фокус — только **создание**: семантика → кластеризация → минусы → объявления → заливка. Аналитика, оптимизация уже работающих кампаний, исследования рынка — **не задача этого скилла**.
Пайплайн опирается на три MCP: `yandex-direct` (прогноз CPC, аудит аккаунта, дедупликация, заливка кампании целиком), `yandex-wordstat` (частотности и сбор семантики на Шагах 1 и 3) и **`yandex-metrika`** (счётчик, история трафика и конверсий сайта, аудит и создание целей и сегментов — Шаги 0.5, 7, 10). Все — **хостовые серверы aihub.click.ru**: локально ничего не запускается, Bun и клон репозитория не нужны. Подключение — `scripts/setup_yandex_direct_mcp.py` (пишет конфиги Cursor / Claude Code / Claude Desktop), общий справочник — `docs/hosted-mcp-setup.md` репозитория пакета. Скилл не проверяет подключение MCP заранее — если на каком-то шаге инструмент не отвечает, обрабатываем ошибку по месту: Шаг 2 уходит на справочник CPC, Шаги 1 и 3 — на `scripts/wordstat_api.py` или браузер, Шаг 7 — на Management API с токеном или инструкции для UI, Шаг 10 — на Директ Коммандер.
## Что нужно от среды
**Обязательный минимум — две способности:**
- **Чтение и запись файлов** в рабочей папке `direct-campaigns/<slug>/`. На этом держится весь пайплайн: каждый шаг порождает артефакт, следующий шаг его читает.
- **Диалог с пользователем** — задать вопрос, получить ответ, дождаться подтверждения. Без этого не работают гейты `[GATE: маркетолог]`, а они здесь не формальность: заливка идёт только после явного «ОК».
Больше ничего обязательного нет. Всё перечисленное ниже — **необязательно**: без любой из этих способностей скилл доходит до конца, но часть данных недобрана.
**Необязательные способности.** У каждой есть ветка «если нет». Идёшь по ветке — **печатаешь пометку о пропуске** в артефакт этого шага (формат ниже).
| Способность | Где нужна | Если нет |
|---|---|---|
| **Запуск кода** — Python 3.9+ и команды оболочки | Шаги 1, 2, 3, 8, 10 (`scripts/*`) | Отдай команду пользователю текстом, попроси прислать вывод и работай с ним как со своим. Если и это невозможно: Шаги 1 и 3 — браузерный пробив частотностей или список от маркетолога; Шаг 8 и Шаг 10 — ручная сверка лимитов по `references/yandex-direct-specs.md` вместо `preflight.py`; Шаг 10 — Директ Коммандер вместо `generate_ads_xlsx`. **Теряется:** автоматическая проверка лимитов Директа перед заливкой — самая дешёвая защита от отклонённых объявлений. |
| **Дочерние агенты** — субагент или форк контекста | Шаги 3–4 | Выполни Шаги 3–4 инлайн по `subagents/semantics.md` и `references/wordstat-filter.md`. Не пересказывай CSV в чат — работай через файлы. **Теряется:** изоляция контекста; тысячи ключей Wordstat останутся в основном разговоре и вытеснят решения Шагов 0–2 к моменту написания объявлений. |
| **Чтение веб-страниц по URL** | Шаг 0 (сайт продукта); Шаг 0.5.2 — только если MCP Метрики не нашёл счётчик (проверка тега на сайте) | Шаг 0 — попроси у маркетолога 5 пунктов словами (H1, бенефиты, CTA, цена/триал, доказательная база), помечай `source: со слов клиента`. Шаг 0.5.2 — попроси прислать `counter_id` из интерфейса Метрики. **Теряется:** сверка заявленного с тем, что реально на сайте. |
| **Поиск в интернете** | Шаг 8 (сверка отстройки с топ-3 выдачи) | Пиши тексты по УТП из брифа, без сверки с конкурентами. **Теряется:** проверка, что заголовки действительно отличают продукт, а не повторяют выдачу. |
| **Вызов MCP-инструментов** (хостовые серверы `yandex-direct`, `yandex-wordstat`, `yandex-metrika`, aihub.click.ru) | Директ: **0.5 (кабинет, счётчики кампаний, черновики)**, шаги 2, 5, 8, 10. Wordstat: шаги 1, 3. Метрика: **0.5 (счётчик, связка с кабинетом, данные сайта)**, 7, 10 | Шаг 2 — справочник CPC из `references/frequency-calculator.md` вместо живого аукциона; Шаг 5 — регионы по справочнику; Шаг 8 — дедупликация ключей по выгрузке от маркетолога; Шаг 10 — Директ Коммандер по `references/direct-commander-import.md`; Шаги 1 и 3 — `scripts/wordstat_api.py` (нужен ключ Cloud) или браузерный пробив по `references/wordstat-browser.md`. Без MCP Метрики: Шаг 0.5.2 — `counter_id` со слов маркетолога, данные сайта не снимаются; Шаг 7 — Management API с OAuth-токеном или инструкции для UI. **Теряется:** живые данные аккаунта и сайта, автоматическая заливка и автоматический пробив частотностей — кампанию, семантику и цели собирает человек руками. |
| **Загрузка картинок в хранилище** — MCP `KeepImage` (`storage_publish_image`) или HTTP через `scripts/upload_creatives_to_storage.py` | Шаг 10Б — заливка РСЯ-картинок | Публичной ссылки для `adimages_add(image_url)` не будет: объявление заливается **без** `image_hashes`, картинки уходят в `10_launch_log.md` списком ручной работы (Директ/Коммандер). Картинки, которые маркетолог дал сразу публичной ссылкой, заливаются и без хранилища. **Теряется:** автоматическая заливка своих/сгенерированных креативов. |
| **Браузер под сессией пользователя** | Шаг 1, Шаг 3 — только когда нет ключа Wordstat | Непробитые фразы помечай `frequency: n/a`. **Прикидку не подставляй:** выдуманная частотность хуже отсутствующей, на ней стоит весь расчёт бюджета. |
| **Сетевые вызовы внешних API по ключу** — Метрика и Wordstat, оба только как фолбек без MCP | Шаг 7 (фолбек); шаги 1, 3 (фолбек) | Шаг 7 без MCP Метрики и без API — режим «инструкции для UI»: скилл готовит план целей, маркетолог заводит их руками. Шаги 1 и 3 без MCP `yandex-wordstat` и без ключа Cloud — браузерный пробив или список ключей от маркетолога. **Теряется:** автоматическая настройка целей, а в фолбеке — автоматический сбор семантики. |
**Отсутствие инструмента в списке — ещё не отсутствие инструмента.** Прежде чем уйти на фолбек «MCP нет», проверь два случая: (1) сервер называется не так, как в тексте (ищи по имени инструмента — `*accounts_get`, `*wordstat_shows_batch`, `*storage_publish_image`, `*yandex_metrika_counters_get`, — а не по имени сервера: Метрика в сессии может называться `metrikaCM`); (2) среда подгружает инструменты отложенно и на старте сессии их ещё не видно — в такой среде сначала поищи инструмент её механизмом поиска (в Claude Code — `ToolSearch`), дождись подключения серверов и только потом решай. Ложный фолбек дорог: браузерный пробив вместо одного вызова на 1000 фраз, Коммандер вместо автозаливки.
**Названия инструментов в тексте ниже — примеры.** Где встречаются `WebFetch`, `Task`, `claude-in-chrome`, `mcp__yandex-direct__*`, `mcp__yandex-wordstat__*`, `mcp__yandex-metrika__*` — это имена из одной конкретной среды, приведённые для наглядности. Ориентируйся на **способность**, а не на имя инструмента: если в твоей среде он называется иначе, но делает то же — используй его.
### Пометка о пропуске
Шаг выполнен без необязательной способности — впиши в артефакт этого шага строку такого вида:
> ⚠️ **пропущено: нет `<способность или источник данных>`** — `<что сделал вместо>`. Потеряно: `<что именно недобрано>`. Как добрать: `<что сделать человеку>`.
Например:
> ⚠️ **пропущено: нет доступа к Вордстату** — частотности не пробиты, в `01_masks.json` стоит `frequency: n/a`. Потеряно: отсев масок ниже порога 150 показов/мес. Как добрать: пробить список на wordstat.yandex.ru и вернуться на Шаг 1.
Все пометки шагов **продублируй сводным списком** в `10_launch_log.md`, раздел «Пропущено из-за среды». Маркетолог должен видеть все пробелы в одном месте, а не искать по десяти файлам. Молча упрощённый результат не отдаём.
### Блокер
Пометка о пропуске значит «сделал хуже, но сделал». **Блокер** значит «дальше нельзя, пока
человек не решит». Блокер не мешает готовить черновик (семантику, структуру, объявления можно
собирать), но **запрещает любую запись в кабинет** (Шаг 10Б) и показывается в каждой сводке
гейта, пока не снят. Список — в `_state.json` → `blockers`, формат:
> ⛔ **блокер: `<что именно>`** — `<почему это нельзя обойти>`. Что сделать: `<конкретное действие человека, со ссылкой, если есть>`. Снимается: `<как скилл поймёт, что снято>`.
| Ситуация | Блокер, а не пропуск, потому что |
|---|---|
| Пустое стоп-поле брифа (Шаг 0) и маркетолог не ответил | Скилл не подставляет критичные настройки сам |
| Нет доступа к кабинету Директа: MCP не подключён, кабинет не виден, ошибка авторизации | Залить некуда. Выход — подключить MCP (`docs/hosted-mcp-setup.md`) или выбрать выгрузку в Директ Коммандер: тогда кампанию заливает человек |
| Интеграция Метрики не подключена в click.ru | Без неё цели не видны. Ссылка: https://help.click.ru/97#connect-yandex-metrica |
| Счётчика на сайте нет или визитов ноль | Конверсии не будут считаться |
| Цели не видны, не созданы или не подтверждены маркетологом; доступ к счётчику только `view` и создать цель нельзя | Оптимизировать не на что |
**Цель Метрики никогда не подменяется догадкой.** Нет подтверждённого маркетологом `goal_id` —
блокер «нет цели для оптимизации», а не «возьму похожую по названию».
## Главный принцип
**Каждый шаг порождает артефакт.** Рабочая папка: `direct-campaigns/<slug>/`. Артефакты накапливаются и являются входами для следующих шагов. На ключевых шагах — гейт `[GATE: маркетолог]` с явным «ОК» перед движением дальше. Заливка происходит **только в DRAFT**. Активация — всегда руками маркетолога.
## Как использовать references
Длинные методологии лежат в `references/` — Claude открывает их в нужный момент.
| Reference | Когда читать | Зачем |
|---|---|---|
| `references/brief.md` | Шаг 0 | Шаблон нового брифа под короткий пайплайн |
| `references/mask-builder.md` | Шаг 1 | Методология двух колонок А (сужающие) × Б (общие) |
| `references/frequency-calculator.md` | Шаг 2 | Формула расчёта частотности + справочник CPC |
| `references/wordstat-filter.md` | Шаг 4 | Пороги НЧ<350/СЧ 350-750/ВЧ>750 + распределение Поиск/РСЯ |
| `references/campaign-structure.md` | Шаг 5 | Правила разбиения семантики на кампании и группы |
| `references/negative-keywords-builder.md` | Шаг 6 | 3 уровня минусов + кросс-минусация |
| `references/metrika-goals-setup.md` | Шаг 0.5.2 (раздел «Чем работаем» + Фаза 1, п. 1–2), Шаг 7 целиком | MCP Метрики: поиск счётчика, аудит целей по факту срабатываний, создание целей и сегментов; шаблоны целей по нишам; фолбек на Management API |
| `references/channel-history.md` | Шаг 0.5.3 целиком; Шаги 2 и 5 — «Как менеджер использует историю» | История каналов: контракт файла (общий с `yandex-direct-audit`), как попросить файл у маркетолога, черновики, пороги выводов |
| `references/yandex-direct-specs.md` | Шаг 8 | Лимиты Директа, форматы, операторы |
| `references/ad-copywriting.md` | Шаг 8 | Формулы заголовков и текстов, требования модерации |
| `references/rsya-creatives.md` | Шаг 8.5 | Техтребования Директа к РСЯ-креативам, workflow генерации по гейтам, чек-лист модерации |
| `references/visual-generation.md` | Шаг 8.5 | Генерация картинок через OpenAI (`generate_creative_images.py`): архитектура, brand.json, форматы |
| `references/bidding-strategy.md` | Шаг 9 | 3-фазная эволюция стратегии торгов |
| `references/yandex-direct-mcp.md` | Шаг 10 + при сбоях MCP | **Справочник MCP:** сигнатуры инструментов, единицы, `dry_run`, хостовое подключение, чего MCP не умеет |
| `references/mcp-account-integration.md` | Шаги 0.5.1, 2, 5, 10 | **Сценарии по шагам:** аудит аккаунта, дедупликация, оценка CPC, регионы и полная последовательность заливки (Use case 5) |
| `references/wordstat-mcp.md` | Шаги 1, 3 + при сбоях Wordstat | **Пробив частотностей через MCP `yandex-wordstat`** (`wordstat_shows_batch`) и цепочка путей расширения семантики (скрипт Cloud API / комбинаторика / браузер) |
| `references/wordstat-browser.md` | Шаг 1 / Шаг 3 (нет ни MCP, ни API-ключа) | Пробив частотностей через браузер пользователя (фолбек вместо симуляции) |
| `references/direct-commander-import.md` | Шаг 10 (фолбек) | Импорт xlsx в Директ Коммандер — когда MCP недоступен |
| `references/ad-legal-topics.md` | Шаг 0 + Шаг 8 | Факт-таблица лицензируемых/запрещённых тем: стоп-гейт и автопредупреждения |
## Как использовать scripts
- `scripts/preflight.py` — проверка `08_creatives.json` против лимитов Директа перед заливкой (Шаг 10). Ошибки — заливка не стартует
- `scripts/generate_ads_xlsx.py` — `08_creatives.json` → xlsx для маркетолога и для фолбека в Коммандер (или CSV)
- `scripts/generate_media_plan.py` — собирает артефакты пайплайна в `media_plan.docx`
- `scripts/keyword_helper.py` — операторы соответствия, базовые минус-листы
- `scripts/forecast_cpc.py` — оценка CPC: разбор `keywordbids_get`, прямой аукцион, либо прогноз по фразам (v4 / Click.ru DRAFT) без MCP `forecast_bids`
- `scripts/generate_creative_images.py` — генерация картинок Шага 8.5 (OpenAI gpt-image-1)
- `scripts/validate_assets.py` — проверка картинок/видео под техтребования Директа
- `scripts/upload_creatives_to_storage.py` — заливка локальных картинок в KeepImage по HTTP и получение публичных ссылок для `adimages_add(image_url=...)` (Шаг 10Б); пишет `assets/storage_manifest.json`. Токен — `clickru` из реестра ключей (его туда кладёт установщик `setup_yandex_direct_mcp.py` при подключении MCP; иначе — `manage_credentials set clickru`). `--check` / `--dry-run` / `--all-assets` / `--files`
- `scripts/manage_credentials.py` / `scripts/credentials.py` — реестр ключей (openai, yandex_direct, clickru) вне рабочей папки
- `scripts/wordstat_api.py` — **основной путь расширения семантики** (Шаг 3, путь 1): клиент Yandex Cloud Search API (Wordstat `topRequests`), `--mode masks` / `--mode semantics` (рекурсивный сбор волнами с ассоциациями); env `WORDSTAT_API_KEY` + `WORDSTAT_FOLDER_ID`; `--check` для проверки. MCP `yandex-wordstat` покрывает только частотности (`wordstat_shows_batch`), семантику не расширяет — см. `references/wordstat-mcp.md`
- `scripts/setup_yandex_direct_mcp.py` — подключение **хостовых** MCP `yandex-direct`, `yandex-wordstat` и `KeepImage` (хранилище картинок) (aihub.click.ru) к Cursor / Claude Code / Claude Desktop одной командой (по умолчанию `--server all`): токен click.ru, `--target`, `--dry-run`, `--remove`, `--click-ru-user-id`. Запускается, когда MCP в среде не видны. KeepImage подключается тем же токеном заголовком `X-Auth-Token` (не токеном в URL). Заодно сохраняет токен click.ru в реестр ключей (`clickru`), поэтому `upload_creatives_to_storage.py` работает сразу после подключения — отдельный `manage_credentials set clickru` не нужен. Локальный stdio-вариант (клон репозитория + Bun) остаётся для разработки самих серверов — см. `references/yandex-direct-mcp.md`
---
## Архитектура: оркестратор + субагенты
Скилл работает как **оркестратор** в основном контексте: держит бриф, `_state.json`, гейты и финальную сборку (медиаплан, заливка). **Самый тяжёлый шаг — сбор и кластеризация семантики — вынесен в изолированный субагент** `semantics` (форк), чтобы тысячи ключей из Wordstat не засоряли основной контекст к моменту генерации объявлений и заливки. Инструкция субагента — в `subagents/semantics.md` (это обычный файл-инструкция, а **не** второй `SKILL.md`).
| Шаг | Где исполняется | Почему |
|---|---|---|
| 0–2 (бриф, разведка аккаунта, маски, прогноз частотности) | **Инлайн** | Решения и гейты; отчёты Метрики короткие (`limit` ≤ 50) — в контекст не бьют |
| 3 — сбор семантики | **Субагент** `semantics` | Тысячи ключей из Wordstat |
| 4 — кластеризация | **Субагент** `semantics` | Чтение того же большого CSV |
| 5–10 (структура, минусы, цели, объявления, стратегия, заливка) | **Инлайн** | Анализ, синтез, заливка |
**Принцип возврата:** субагент собирает семантику в своём контексте, пишет артефакты на диск и возвращает наверх **только сводку ≤20 строк**. Гейт и решение — у маркетолога в основном контексте.
**Фолбек:** если субагент недоступен (старая среда, ошибка форка, путь не резолвится) — оркестратор выполняет Шаги 3-4 **инлайн** по тем же reference/scripts. Делегирование — оптимизация, а не жёсткая зависимость.
Субагент лежит в `subagents/semantics.md` (файл-инструкция, не `SKILL.md`); сам по инициативе модели не запускается — его порождает оркестратор. References и scripts — единые, в корне скилла; субагент читает их по пути от корня.
---
## Проверка версии (один раз за разговор, до Шага 0)
Версия этого скилла — в файле `VERSION` рядом с этим `SKILL.md`. Прочитай его и одним запросом
загрузи актуальную версию: `https://raw.githubusercontent.com/ai-hub-open/yandex-direct-manager/main/VERSION`.
- **Совпадает** — ничего не пиши, переходи к Шагу 0.
- **Загрузить не вышло** (нет сети, нет чтения по URL, ошибка) — не повторяй запрос, ничего не пиши
и не ставь пометку о пропуске: на маршрут это не влияет. Переходи к Шагу 0.
- **На GitHub новее** (сравнивай как semver: 0.18.2 > 0.18.0) — одним коротким сообщением скажи,
что вышла версия X (у пользователя Y), дай ссылку на
[CHANGELOG](https://github.com/ai-hub-open/yandex-direct-manager/blob/main/CHANGELOG.md) и как обновиться:
- Claude Code, скилл установлен плагином: `/plugin marketplace update ai-hub-open`, затем перезапустить сессию;
- скилл загружен архивом (Claude Desktop / claude.ai) или папкой: скачать `yandex-direct-manager.skill`
из [релизов](https://github.com/ai-hub-open/yandex-direct-manager/releases/latest) и заменить старый.
Спроси: обновиться сейчас или продолжить на текущей версии. Ответ «продолжить» — работаем дальше,
к вопросу в этом разговоре не возвращаемся.
**Сам файлы скилла не скачивай и не заменяй**, даже если среда это позволяет: обновление ставит
пользователь. Скилл, который сам переписывает свои инструкции из интернета, — дыра в безопасности.
---
# Workflow: 10 шагов
## Шаг 0. Бриф
**Прочти `references/brief.md` целиком.** В нём — точная формулировка вопросов и формат `00_brief.md`.
**Пришёл бриф от `marketing-strategist`** (`12_brief_for_yandex_direct.md`) — он уже в формате этого брифа: перенеси поля, спроси только «❗ уточнить» и пустые стоп-поля, выбор каналов и УТП стратега не пересматривай. Приложенный с ним `channel_history.md` — сразу вход Шага 0.5.3.
Задай маркетологу **одним блоком** 12 пунктов брифа (продукт, целевая аудитория, посадочная страница, регион, бюджет, каналы, тип запросов, УТП + сужающие, цель в Метрике, CPA-таргет + ценность конверсии + коллтрекинг, существующие материалы, slug проекта, **лицензируемая/запрещённая тематика + документы**).
**Стоп-поля** — без них дальше Шага 0 не идём и **ничего не подставляем сами**: что рекламируем, посадочная страница, регион, бюджет, цель (что считаем конверсией), тематика. Не знает — спроси ещё раз с вариантами; не ответил — блокер. Кабинет выбирается на Шаге 0.5.1, `goal_id` — на Шаге 7. Остальные поля можно закрыть дефолтом с пометкой «гипотеза» (`references/brief.md`).
Параллельно — прочитай сайт продукта инструментом чтения веб-страниц (например, `WebFetch`). **Если такого инструмента в среде нет или страница заблокирована** — попроси у маркетолога 5 пунктов словами: H1, бенефиты, CTA, цена/триал, доказательная база. Помечай `source: со слов клиента` и впиши в `00_brief.md` пометку о пропуске: «пропущено: нет чтения веб-страниц — данные о продукте со слов клиента, с сайтом не сверены».
**Артефакт:** `direct-campaigns/<slug>/00_brief.md` + `_state.json` (current_step, slug, product_name, доступность Wordstat: `wordstat_mcp_available` и/или `wordstat_api_available`; после Шага 0.5 добавляются `direct_client_login`, `direct_account_name`, `direct_mode`, `direct_forecast_available`, `direct_server`, `metrika_server`, `metrika_counter_id`, `metrika_link`, `metrika_history_available`, `channel_history`; на любом шаге — `blockers`, см. «Блокер»).
**[GATE: маркетолог]** «Бриф верный? Идём дальше?»
**[СТОП-ГЕЙТ: тематика]** Сверься с `references/ad-legal-topics.md`. Если продукт из **полностью запрещённых в РФ** тем (азартные игры, оружие, табак, рецептурные, аборты и т.д.) — пайплайн **останавливается**, кампанию в Директе не запустить: сообщи маркетологу прямо и не трать шаги на семантику. Если тема **лицензируемая** (медицина, финансы, алкоголь и т.д.) — зафиксируй в брифе, есть ли документы; без них — предупреждение и блок до предоставления. Учитывай автопредупреждения Директа (они съедают символы объявления на Шаге 8).
## Шаг 0.5. Разведка аккаунта
**Читай:** `references/mcp-account-integration.md` → Use case 0 (для 0.5.1);
`references/metrika-goals-setup.md` → «Чем работаем» и Фаза 1, п. 1–2 (для 0.5.2);
`references/channel-history.md` целиком (для 0.5.3).
Один шаг — три вопроса до любой работы с семантикой: **куда** заливаем (кабинет), **чем**
меряем (счётчик и его связка с кабинетом), **что уже было** (история рекламы клиента).
Подпункты идут подряд, без остановок: маркетолог видит **одну сводку и один гейт** в конце.
Вопрос посреди шага — только там, где без человека не решить: несколько серверов или
кабинетов, несколько счётчиков, черновики без показов.
Подпункты в `_state.json` → `current_step` пишутся **латиницей**: `recon.direct` →
`recon.metrika` → `recon.history` → `recon.done`. Возобновляешь — продолжай с первого
незакрытого.
### 0.5.1 Кабинет Директа
**Сначала найди все сервера Директа в сессии, а не первый попавшийся.** Имя сервера ничего
не гарантирует: он может называться `yandex-direct`, а может `YadLisa`, `YAD-Original`,
`yad_gossa` — ориентируйся на **набор инструментов** (`*accounts_get`, `*campaigns_add`,
`*ads_add_responsive`). Нашёл больше одного — позови `accounts_get({})` на каждом и покажи
маркетологу сводку «сервер → режим (click.ru / прямой OAuth) → кабинеты»: разные сервера
нередко ведут в один и тот же аккаунт, но бывает и наоборот, а перепутанный сервер
обнаружится только после заливки. `accounts_get({})` заодно проверяет связность MCP и
показывает режим подключения.
**Вопрос сразу** (без ответа дальше не пойти), если серверов или кабинетов больше одного:
«Какой сервер, какой кабинет?» Один сервер и один кабинет — берём молча.
Пишет в `_state.json`: `direct_client_login`, `direct_account_name`, `direct_mode`,
`direct_forecast_available`, **`direct_server`** (точное имя выбранного сервера — все
последующие шаги зовут инструменты именно его, а не «любого Директа в сессии»).
Дальше `client_login` подставляется **в каждый** вызов инструментов Директа, относящихся к
кабинету (исключение — `accounts_get`, `forecast_bids`, `dictionaries_*`: они к кабинету не
привязаны).
**Если MCP Директа нет или кабинет не виден** — ⛔ блокер «нет доступа к кабинету»: заливки
не будет. Черновик готовим дальше по ветке без live-данных; в конце маркетолог выбирает —
подключить MCP (`docs/hosted-mcp-setup.md`) и вернуться к Шагу 10 или залить файлами через
Директ Коммандер. Черновики в 0.5.3 тогда не проверяются.
### 0.5.2 Метрика и связка с кабинетом
Счётчик ищем **сразу**, а не на Шаге 7: «Метрики нет» — стоп-алярма, и узнать её лучше до
сбора семантики, а данные сайта подкармливают Шаги 1, 2, 5 и 9.
1. **Сервера Метрики — все, а не первый попавшийся.** Ищи по инструменту
`*yandex_metrika_counters_get` (имя сервера любое — `metrikaCM`, `MetrikaDevadent`,
`yandex-metrika`). Нашёл больше одного — позови `accounts_get({})` на **каждом**: сервер с
пустым `accounts` в выбор не предлагай, но упомяни в сводке. Пустой `accounts_get` с
подсказкой «не подключена Метрика» на **всех** серверах = интеграция не подключена в
click.ru, а не «MCP нет»: попроси подключить и **обязательно дай ссылку на инструкцию**
https://help.click.ru/97#connect-yandex-metrica — без неё маркетолог не найдёт, где это
делается. Не жди: заведи ⛔ блокер «интеграция Метрики не подключена» и иди дальше —
черновик готовить можно, заливать нельзя, пока блокер не снят.
2. **Счётчик — от кампаний кабинета, а не от домена.** Связку «кабинет ↔ счётчик ↔ сервер
Метрики» проверяем **до** отчётов: иначе данные молча соберутся без расходов Директа или по
чужому кабинету. Серверов бывает много (2 Метрики и 4 Директа у одного маркетолога —
норма), а имена ничего не гарантируют: «парный» по названию сервер Метрики может не видеть
счётчик, а агентский со сотней чужих счётчиков — видеть.
- `campaigns_get({ client_login, include_strategy: true, limit: 50 })` на `direct_server` →
`CounterIds` кампаний. У кампании их бывает 2–3 — бери тот, чей сайт совпадает с доменом
брифа; совпадают несколько или ни один — **вопрос сразу**: «по какому счётчику считаем?».
- Ищи этот `counter_id` на **каждом** сервере Метрики: `counters_get({ search: "<counter_id>" })`.
Решает ответ, а не имя: сервер, который его видит, и есть `metrika_server`. Видят
несколько — бери тот, где доступ `own` / `edit`; равны — вопрос.
- `direct_clients_get({ counter_id })` → есть ли `chief_login`, равный `direct_client_login`.
Итог — `metrika_link`:
- 🟢 `green` — счётчик найден и видит кабинет: данные сайта целиком, расходы Директа из Метрики.
- 🟡 `yellow` — счётчик найден, кабинета не видит (`clients` пустой или там другой логин):
визиты, фразы и гео есть, **расходов и CPA Директа из Метрики нет** — их даёт
`report_campaign` Директа на Шаге 2. Это не стоп — строка в сводке.
- 🔴 `red` — `CounterIds` у кампаний есть, но счётчик не виден ни на одном сервере
Метрики: интеграция Метрики в click.ru подключена не под тем аккаунтом Яндекса или не
подключена. Ссылка https://help.click.ru/97#connect-yandex-metrica, дальше с ⛔ блокером.
**Кампаний в кабинете нет** (новый кабинет) — связки ещё быть не может, ищи по домену:
`counters_get({ search: "<домен из брифа>", with_goals: true })` на всех серверах. Несколько
— вопрос «какой основной?». Не найден — проверка тега на сайте и ветки из Фазы 1 референса;
тега нет — **алярма «Метрики нет»** и ⛔ блокер: сказать сразу, пайплайн можно вести до
Шага 6, но до Шага 7 счётчик должен появиться.
3. **Данные сайта (если у счётчика есть трафик).** Не больше 4 коротких отчётов за 90 дней —
`yandex_metrika_report({ counter_id, date1: "90daysAgo", limit: 50, ... })`:
- `preset: "sources_search_phrases"` — реальные поисковые фразы, по которым приходят на
сайт (+ `ym:s:anyGoalConversionRate`): **кандидаты в маски Шага 1** и в сужающие слова;
- **только при `metrika_link: green`** — `preset: "sources_direct_summary"` +
`direct_client_logins: [direct_client_login]`, метрики `ym:ad:*` расхода +
`ym:s:goal<ID>reaches` — **фактические CPC и CPA прошлой рекламы Директа**. При `yellow`
/ `red` отчёт не строим — `ym:ad:*` придут пустыми или по чужому кабинету;
- `dimensions: ["ym:s:regionCity"]` и `["ym:s:deviceCategory"]` с конверсией —
**где и с чего конвертят**: вход для гео Шага 5 и корректировок Шага 9.
Если `total_rows` мизерный или сайт новый — отчёты пропускаются без пометки, это не пробел
среды, а факт: «данных сайта нет». Полный аудит целей — на Шаге 7, здесь не делаем.
Пишет в `_state.json`: `metrika_server`, `metrika_counter_id`, `metrika_link`,
`metrika_history_available`.
### 0.5.3 История каналов
Что прошлая реклама клиента реально дала — по каналам и по типам кампаний Директа: расход,
лиды, CPA и вывод с числами. Без этого скилл планирует «из общих знаний» и повторяет то, что у
клиента уже провалилось. Файл истории просим ещё в брифе (пункт 10); здесь — проверяем то,
что пришло.
1. **Файл `channel_history.md` / `.json` приложен** — проверь шапку (период, что считали
лидом, пороги); чего-то нет — спроси только это.
2. **Файла нет** — попроси его один раз по шаблону из референса: что в нём должно быть и как
его получить скиллами пакета (`yandex-direct-audit` — Директ, `yandex-metrika-manager` —
остальные каналы) или словами. Собираешь со слов сам — **период всегда спрашивай**, лид —
с вариантами ответа (по умолчанию ключевые цели стратегий кампаний). «Рекламы не было» →
идём **без истории**.
3. **Черновики в кабинете** — кампании без единого показа не означают «тип не работает».
**Вопрос сразу:** почему их не запустили; причина — в `note`.
**Пороги выводов** («мало данных», «дорого») у бизнеса бывают свои — поэтому каждый вывод
показываем с числами и порогом, на которых он построен, а не голым ярлыком.
Пишет в `_state.json`: `channel_history: file | client | none`.
### Итог шага: одна сводка, один гейт
**Артефакт:** `_channel_history.md` — единственный файл «что было до нас», две части:
- **«Каналы»** — таблица по контракту из `references/channel-history.md` (из файла аудита, со
слов клиента или пометка «истории нет»);
- **«Сайт по данным Метрики»** — отчёты из 0.5.2 (≤ 20 строк на отчёт + 3–5 выводов) или
строка «данных сайта нет».
**[GATE: маркетолог]** — одним сообщением:
```
Кабинет: <логин> (сервер <имя>, click.ru)
Метрика: счётчик 12345678 (сервер <имя>), связка с кабинетом 🟢, ~400 визитов/день
История: 2026-04..09, лид = «Заявка» + «Звонок» (из файла аудита)
Поиск — работает: CPA 2 500 ₽ при целевом 3 000
РСЯ — не дал лидов: 0 при 410 кликах за 62 дня (порог «мало данных»: <30 кликов / <14 дней)
VK Ads — не дал лидов (со слов клиента: 50 тыс. ₽ за 2 месяца)
Черновики: 2 кампании без показов — не прошли модерацию
Блокеры: нет
Всё верно? Идём к маскам?
```
Истории нет — строка «История: нет, типы кампаний и прогноз — по справочникам».
## Шаг 1. Маски
**Прочти `references/mask-builder.md` целиком.**
**Передать:** УТП и продукт из `00_brief.md`, регион, тип спроса (определяется по контексту брифа: срочный/B2B/премиум/ручная работа/массовый), доступ к Wordstat API.
**Если в `_channel_history.md` есть раздел «Сайт»** — поисковые фразы, которые уже приводят на сайт и конвертят, используй как кандидатов в колонку Б и как подсказки сужающих слов. Помечай их `source: metrika` — маркетологу на гейте видно, что маска взята из реального спроса, а не придумана.
⚠️ В отличие от старого пайплайна, **нет внешнего hypothesis-builder**. Сужающие слова берутся **напрямую из брифа**: если маркетолог дал в поле «УТП» что-то вроде «премиум», «ручная работа», «срочно» — это сужающее. Если в брифе нет явных сужающих — задай один уточняющий вопрос: «Какие 1-3 слова определяют ваш угол отстройки (например: премиум, срочно, для самозанятых)?»
**На выходе:**
- `01_masks_matrix.md` — две колонки А (сужающие) × Б (общие + товарозаменители) с языковыми и смысловыми синонимами
- `01_masks.json` — machine-readable, рабочие маски с частотностями из Wordstat
- `01_masks_wordstat_log.md` — лог итераций
**Частотности масок:** приоритет — MCP Вордстата (`wordstat_shows_batch`, все маски одним вызовом, см. `references/wordstat-mcp.md`). Сервер ищи **по инструменту `*wordstat_shows_batch`, а не по имени** — он может называться `yandex-wordstat`, `Wordstat` или как угодно ещё. Если инструмента нет ни под каким именем — фолбек `scripts.wordstat_api --mode masks` (нужен ключ Cloud Search API). Если нет ни MCP, ни ключа — **пробей частотности через браузер** пользователя (`references/wordstat-browser.md`), а не прикидкой. Пробив в браузере делает оркестратор.
**Два гейта:** (1) первая матрица — «правильное направление?», (2) после расширения и Wordstat — «финальный список?».
## Шаг 2. Прогноз частотности
**Прочти `references/frequency-calculator.md` целиком.** Параллельно — Use case 1–3 из `references/mcp-account-integration.md` (аудит существующих кампаний, дедупликация ключей, оценка CPC).
**Передать:** бюджет на поиск из брифа (доля поиска × общий месячный бюджет), `01_masks.json` (для прогноза CPC через MCP), регион из брифа.
**Приоритет источника CPC:** историческая AvgCpc похожих кампаний (`report_campaign`) → история (`_channel_history.md`, Шаг 0.5: фактический CPA по типам кампаний, а при связке 🟢 — CPC/CPA Директа по Метрике; по ним сверь CPA-таргет из брифа и скажи прямо, если он нереален) → живой аукцион по ключам аккаунта (`keywordbids_get`, парсит `scripts/forecast_cpc.py`) → **прогноз по своим маскам (`forecast_bids`, до 100 фраз, без создания кампании)** → справочник CPC по нишам → override от маркетолога. Сам у маркетолога CPC не спрашиваем.
⚠️ **`forecast_cpc.py` в режиме click.ru создаёт в кабинете временный черновик.** Прямого токена Яндекса нет → скрипт идёт планом Б: заводит DRAFT-кампанию `_CPC_PROBE_<дата>` с масками, снимает аукцион и удаляет её в `finally`. Кампания неактивна и денег не тратит, но это **запись в живой кабинет** — запускай скрипт **только после явного «ОК»**: «Для прогноза цены клика создам в кабинете `<логин>` временный черновик `_CPC_PROBE_<дата>` и сразу удалю. Можно?» Нет «ОК» — бери следующий источник цепочки. После запуска проверь `campaigns_get`, что черновик удалился (если скрипт упал — удалить руками).
⚠️ В режиме прокси click.ru `forecast_bids` недоступен. Есть ли в сессии второе подключение в прямом OAuth — проверь по `_state.json` → `direct_forecast_available` (Шаг 0.5): прогноз можно посчитать там, заливка останется в выбранном кабинете. Нет — справочник CPC.
**На выходе:**
- `02_frequency.md` — 3 сценария (оптимистический/базовый/пессимистический)
- `02_frequency.json` — необходимая суммарная частотность с ×2 запасом
- `_account_audit.md` (если есть похожие существующие кампании) — для контекста и предотвращения каннибализации
**Гейт:** маркетолог подтверждает или корректирует прогноз.
## Шаг 3. Расширение семантики и пробив частотностей [делегируется субагенту `semantics`]
Расширение семантики + кластеризация (Шаг 4) вынесены в изолированный субагент `semantics` (форк): он готовит seed/anchors из `01_masks.json`, расширяет ядро одним из путей ниже, пробивает частотности через MCP `yandex-wordstat` (`wordstat_shows_batch`) или фолбеком, пишет `03_semantics_raw.csv` и сразу кластеризует его. Тысячи ключей остаются в форке.
⚠️ **Сервер `yandex-wordstat` не расширяет семантику.** Он отвечает «сколько показов у фразы», но не «какие ещё запросы бывают»: реально доступен только пакетный пробив частотностей (`wordstat_shows_batch`, до 1000 фраз за вызов). Рекурсивные волны через MCP невыполнимы — расширение берётся отдельно, а MCP пробивает частотности готового списка.
**Что готовит оркестратор:** slug из `_state.json`, регионы из брифа, необходимую суммарную частотность из `02_frequency.json`.
**Как запустить субагент:** порождай дочерний агент через инструмент субагентов/форка твоей среды (например, в Claude Code — Task с `subagent_type: general-purpose`, тулы `Bash Read Write Grep Glob`), **передай ему целиком текст `subagents/semantics.md`** и три аргумента: `slug`, `регионы`, `необходимая_частотность`. Эквивалент вызова:
```
субагент semantics ← subagents/semantics.md аргументы: <slug> "<регионы>" "<необходимая_частотность>"
```
**Субагент возвращает:** сводку ≤20 строк (собрано ключей, путь расширения `cloud-api | combinatorial | list | browser`, распределение по 4 CSV, суммарная частотность vs нужная с флагом НЕДОБОР, причина остановки) + пути к `03_semantics_raw.csv` и `04_keys_*.csv`. Сырьё CSV остаётся в форке.
**Если среда не умеет субагенты/форк** (например, Claude Desktop без инструмента Task, ChatGPT) — выполни Шаги 3-4 **инлайн** по методологии ниже. Делегирование — оптимизация, а не жёсткая зависимость. Инлайн-исполнение не считается пропуском способности и пометки о пропуске не требует: данные собираются те же, страдает только чистота контекста. Но если из-за объёма пришлось урезать сбор — это пропуск, помечай.
**Цепочка приоритетов расширения** (полная методика и правила — `references/wordstat-mcp.md` → «Шаг 3»):
1. **Скрипт Cloud Search API** (`scripts/wordstat_api.py --mode semantics`) — единственный путь с настоящей рекурсией волнами и ассоциациями; нужен ключ `WORDSTAT_API_KEY` + `WORDSTAT_FOLDER_ID` и запуск кода. Частотности — из того же ответа.
2. **Комбинаторная генерация кандидатов** из `01_masks.json` + пакетный пробив через MCP `wordstat_shows_batch` — когда есть только MCP.
3. Список от маркетолога / выгрузка сторонним сервисом + пакетный пробив.
4. Браузерный пробив (`wordstat-browser.md`) — нет ни MCP, ни ключа; делает оркестратор.
Готовим два файла в рабочей папке (нужны для пути 1):
- `_masks_seed.txt` — стартовые семена: узкие комбинации из `01_masks.json` **плюс широкие одиночные слова продукта** (база колонки Б + синонимы: `картины`, `панно`, `холст`). Широкие слова обязательны — без них волна 0 узкая.
- `_anchors.txt` — якоря-основы продуктовых слов колонки Б + синонимов (`картин`, `панно`, `холст`), по одному на строку. Запрос становится семенем следующей волны, только если содержит хотя бы один якорь — это держит рекурсию в теме продукта.
**Путь 1 (предпочтительный) — скрипт Cloud API:** та же логика рекурсивных волн готовым скриптом:
```
python -m scripts.wordstat_api --mode semantics \
--phrases-file direct-campaigns/<slug>/_masks_seed.txt \
--anchors-file direct-campaigns/<slug>/_anchors.txt \
--regions <из брифа> \
--output direct-campaigns/<slug>/03_semantics_raw.csv
```
**Профиль «Стандарт» (дефолт):** глубина 2, до 150 семян на волну, порог семени 10 показов, стоп при <5% нового, ≤1000 вызовов / ≤15 минут. **Профиль «Глубокий»** — флаги `--max-depth 3 --seeds-per-wave 300 --dry-threshold 0.03 --max-api-calls 5000 --max-minutes 40`. Профили — свойство скрипта Cloud API, а не MCP.
**Путь 2 — комбинаторика + пакетный пробив (когда есть только MCP):** сгенерируй кандидатов из `01_masks.json` (продуктовые слова × сужающие × модификаторы намерения × словоформы, 300–1000 штук), пробей пачкой `wordstat_shows_batch`, отсей `stat < 150`, сделай одну волну углубления. Детали — `references/wordstat-mcp.md` → «Шаг 3, путь 2».
Работай файлами: каждая волна/пачка дописывает `03_semantics_raw.csv`, в чат — только итог (1 строка). Тысячи ключей в контекст не тащим.
**Артефакт:** `03_semantics_raw.csv` со столбцами `keyword,frequency,mask_parent,source,depth`. Для Шага 4 значимы первые три столбца.
🚫 **Категорически нельзя** дописывать в `03_semantics_raw.csv` непробитые фразы с выдуманной частотностью. Не пробита — либо `frequency: n/a` с пометкой, либо не в файле.
**Если суммарная частотность ниже необходимой** из `02_frequency.json` — на пути 1 прогони профиль «Глубокий»; если всё равно мало — вернись на Шаг 1, расширь колонку Б (новые товарозаменители/синонимы) или попроси у маркетолога новые сужающие, и допиши их в `_masks_seed.txt` и `_anchors.txt`.
**Если расширения через Cloud API нет** (нет ключа `WORDSTAT_API_KEY` / нет запуска кода) — иди по путям 2–4. Через MCP расширения семантики не будет, только пробив частотностей; в `03_semantics_raw.csv` и в сводке Шага 3 — **обязательная пометка о пропуске**: «пропущено: нет расширения семантики через Вордстат — сервер `yandex-wordstat` умеет только частотности; ядро построено комбинаторикой масок и пробито пакетно. Как добрать: прогнать `scripts/wordstat_api.py --mode semantics` с ключом Yandex Cloud или прислать ядро сторонним сервисом списком».
**Если Wordstat недоступен вообще** (инструмента `*wordstat_shows_batch` нет ни под одним именем сервера — проверь, а не полагайся на имя `yandex-wordstat`; и `python -m scripts.wordstat_api --check` упал / нет ключа / среда не запускает код) — переходим на **браузерный пробив частотностей** (путь 4) через сессию пользователя (`references/wordstat-browser.md`). Пробив делает **оркестратор** (у форка `semantics` браузерных инструментов нет). Непробитые фразы помечаем `frequency: n/a` — прикидку не подставляем. Дальше расчёт бюджета Шага 2 считается непроверенным — так и скажи на гейте.
## Шаг 4. Кластеризация (НЧ/СЧ/ВЧ + Поиск/РСЯ) [делегируется субагенту `semantics`]
4 CSV ниже уже произведены субагентом `semantics` (Шаг 3) — он кластеризует `03_semantics_raw.csv` по этому же reference. Если субагент недоступен, оркестратор делает это инлайн. В любом случае **гейт и решение — здесь, в основном контексте**.
**Прочти `references/wordstat-filter.md` целиком** (нужно оркестратору для проверки распределения на гейте и для инлайн-фолбека).
**Передать:** `03_semantics_raw.csv`, тип ниши и каналы из брифа (Поиск/РСЯ/оба), бюджет (для решения по ВЧ).
**На выходе (4 CSV + summary):**
- `04_keys_search_obligatory.csv` — НЧ + СЧ для Поиска (база)
- `04_keys_search_vch.csv` — ВЧ для Поиска (только при бюджете ≥100к + массовый продукт + бренд)
- `04_keys_rsya.csv` — СЧ + ВЧ для РСЯ
- `04_keys_excluded.csv` — отброшенные с причиной
- `04_wordstat_filter_summary.md` — отчёт + гейт
**Пороги:** НЧ <350, СЧ 350-750, ВЧ >750 показов/мес. Минимум 150 показов/мес — иначе отбрасываем.
**Гейт:** маркетолог подтверждает распределение или корректирует.
## Шаг 5. Структура кампаний
**Прочти `references/campaign-structure.md`.**
### Шаг 5.1. Построение структуры
Модель объявлений одна — **комбинаторное объявление в ЕПК** (классическая ТГО-модель убрана: ТГО заморожены с 30.06, автомиграция ТГО→комбинаторное с 14.07 — их технически не создать). Гейта выбора модели больше нет.
Строй структуру по разделу «Модель структуры (комбинаторная ЕПК)» в `references/campaign-structure.md`:
- **По умолчанию:** 1 угол/сегмент → 1 РК; Поиск+РСЯ+Галерея+Карты обслуживаются одной РК — не разделяем. Групп в РК по умолчанию одна, отдельная группа — только под другой лендинг или ВЧ (правило — `campaign-structure.md` → «Группы внутри кампании»); в каждой группе одно комбинаторное объявление.
- **Если нужна раздельность Поиск/РСЯ** — экспертные варианты ЕПК «только Поиск» / «только РСЯ» (а не отдельные классические кампании).
- Углы/сегменты (Премиум, Срочно, Бренд, B2B) по-прежнему разносятся по отдельным РК.
- **Автотаргетинг на Поиске обязателен** (в ЕПК его нельзя выключить, только ограничить категориями) и может дать половину трафика группы и больше — особенно на узкой семантике. Директ заводит его в каждой группе ЕПК сам и **со всем включённым** — пять категорий и все брендовые запросы, включая конкурентов. Поэтому в структуре у каждой РК задаём **осознанно**: `autotargeting_categories` (какие категории запросов разрешены), `autotargeting_brands` (какие брендовые запросы) и — только для ручных ставок в РК «только Поиск» — `autotargeting_bid`. При автостратегии ставка и приоритет на автотаргетинг не действуют, рычаг один — категории и бренды. По умолчанию предлагаем: целевые + узкие, без брендов + свой бренд; на узкой семантике (<30 фраз в группе) добавляем альтернативные; брендовая РК — только целевые и только свой бренд; бренды конкурентов — только по прямой просьбе брифа. Решение показываем на гейте Шага 5. MCP применяет его на Шаге 10Б (`autotargeting_set`). Детали — `references/campaign-structure.md`.
Жёсткого потолка на число кампаний нет — см. «Много кампаний — мягкая подсказка» в референсе.
**История (`_channel_history.md`, Шаг 0.5).** Тип кампании, у которого в истории
`no_leads` или `expensive`, попал в структуру — **[GATE: маркетолог]** с числами и порогом:
«РСЯ: 80 тыс. ₽, 410 кликов, 0 лидов за полгода. Всё равно закладываем? Что меняем по
сравнению с прошлым разом?» Тип молча не убираем — решение за маркетологом, но с цифрами на
столе. `no_data` — «данных мало, вывода нет»; `never_ran` — вывода нет, учитываем причину из
`note`. Истории нет (`channel_history: none`) — у каждого типа в `05_campaign_structure.md`
пометка **«без истории»**.
**Есть раздел «Сайт» в `_channel_history.md`** — сверь гео брифа с городами, откуда реально конвертят: если 70 % конверсий из одного города, а бриф просит «вся Россия», предложи отдельную РК или корректировку, а не молча следуй брифу. Ретаргет-кампания возможна, только если у счётчика есть трафик (сегменты строятся на Шаге 7).
**Артефакт:** `05_campaign_structure.md` — таблица с колонками `#`, `Кампания`, `Тип`, `Угол`, `Бюджет`, `Группы` + machine-readable `05_campaign_structure.json` для следующих шагов.
**[GATE: маркетолог]** «Эту схему берём? Не объединять ли что?»
## Шаг 6. Минус-слова и кросс-минусация
**Прочти `references/negative-keywords-builder.md` целиком.**
**Передать:** `05_campaign_structure.json`, ключи из всех CSV Шага 4, сужающие слова кампаний, тип ниши.
**На выходе (7 артефактов):**
- `06_negative_keywords_account.csv` — аккаунт-уровень
- `06_negative_keywords_search.csv` — Поиск-уровень
- `06_negative_keywords_rsya.csv` — РСЯ-уровень (короткий)
- `06_negative_keywords_cross.csv` — кросс-минусы по кампаниям
- `06_cross_minus_matrix.md` — наглядная матрица
- `06_negative_keywords.json` — machine-readable, идёт в MCP-заливку
- `06_negative_summary.md` — сводка
**Гейт:** маркетолог подтверждает 3-уровневое распределение + кросс-матрицу.
## Шаг 7. Метрика и цели
**Прочти `references/metrika-goals-setup.md` целиком.**
**Передать:** `counter_id`, сервер Метрики и `metrika_link` из `_state.json` (Шаг 0.5.2), URL сайта и цель в Метрике из брифа, `05_campaign_structure.json`, тип ниши, `direct_client_login`.
**Основной путь — MCP Метрики**, токен Метрики не нужен:
1. **Аудит по факту, а не по названиям:** `goals_get({ counter_id, stats_days: 30 })` → у каждой цели достижения и конверсия за 30 дней. Мёртвые (0 достижений), мусорные (конверсия 30 %+) и пригодные — с конверсиями в неделю. `direct_clients_get` — видит ли счётчик наш кабинет Директа.
2. **План целей** по шаблону ниши. Сначала цели без разработчика (`url`, `phone`, `messenger`, `file`, `visit_duration`), `action` (JS) — только когда иначе никак. Для ретаргет-кампании — 1–3 сегмента (`segments_get` → есть ли уже; новые — с проверкой выражения отчётом).
3. **Предпросмотр:** каждую новую цель и сегмент — через `goals_add` / `segments_add` с `dry_run: true`.
4. **[GATE: маркетолог]** подтверждает план **до** создания.
5. **Создание** без `dry_run`, `goal_id` — в лог сразу; финальная сверка `goals_get`. **Скилл ничего не удаляет в Метрике** — мусорные цели просто не используем.
**Фолбек:** MCP Метрики нет или интеграция не подключена в click.ru (в последнем случае — сначала ссылка на инструкцию https://help.click.ru/97#connect-yandex-metrica) → Management API с OAuth-токеном (scope `metrika-manage`) → режим «инструкции для UI». Пометка о пропуске — обязательна. В режиме «инструкции для UI» маркетолог заводит цель руками и присылает `goal_id`; пока его нет — ⛔ блокер «нет цели для оптимизации», заливки не будет.
**На выходе:**
- `07_metrika_audit.md` — состояние счётчика и таблица целей с достижениями за 30 дней и вердиктом
- `07_metrika_goals_plan.md` — план новых целей и сегментов (до создания)
- `07_metrika_setup_log.md` — лог вызовов (dry-run и боевые)
- `07_metrika_goals.json` — `counter_id`, `goal_ids`, `conversions_per_week`, `segments`, привязка к кампаниям
**Алярма:** если Метрики на сайте нет (или визитов ноль — код снят) — стоп пайплайна (⛔ блокер), маркетолог сначала устанавливает/чинит счётчик. Цель для оптимизации выбирает **маркетолог** на гейте: скилл предлагает, но не назначает цель по похожему названию.
После — привязка к кампаниям на Шаге 10: `counter_ids` и `priority_goals` передаются прямо в `campaigns_add` (или в `campaigns_update` для уже созданной кампании). Ценность конверсии для `priority_goals` берётся из брифа; её нет — передаём только `counter_ids`, цели не выдумываем.
## Шаг 8. Объявления
**Обязательно прочитай** `references/yandex-direct-specs.md` и `references/ad-copywriting.md` **до** написания.
Модель одна — **одно комбинаторное объявление на группу**; групп в РК столько, сколько задано на Шаге 5 (по умолчанию одна). См. `ad-copywriting.md` → «Комбинаторное объявление» и лимиты в `yandex-direct-specs.md`:
- **3-7 заголовков** (≤56 симв., минимум 2 коротких ≤35), обязательное вхождение ключа хотя бы в один. **Отдельного «Заголовка 2» в комбинаторном нет** — есть набор равноправных заголовков с разными углами;
- **2-3 текста** (≤81 симв. без «узких» знаков `! , . ; : "`, их — до 15), каждый самодостаточен;
- картинки (до 5) из ассетов брифа — нет ассетов — без них, TODO в Шаг 8.5. Видео (до 6 в лимите Директа) через MCP не заливаются: файлы маркетолога уходят в `10_launch_log.md` ручной работой;
- быстрые ссылки (4-8; заголовки 1–4 вместе ≤66 симв., 5–8 тоже), уточнения (2-4), отображаемая ссылка;
- **Минусы группы** — узкие, только для этой группы;
- **опциональные элементы роста CTR** (если есть данные в брифе): кнопка действия, цена, промоакция (до +30% CTR), карусель 2–10 изображений — см. `ad-copywriting.md` → «Дополнительные элементы». Цену/акцию/промокод берём только реальные, не выдумываем.
Для лицензируемых тем сверься с `references/ad-legal-topics.md`: Директ вставит автопредупреждения (№334), которые съедают символы — не рассчитывай на полный лимит заголовка/текста.
Артефакт `08_creatives.json` в форме ЕПК (в группе объект `combined_ad`) — схема `assets/creatives_schema_combined_example.json`.
**Финальная проверка через MCP:**
1. Дедупликация ключей через `keywords_get` (Use case 2 в `mcp-account-integration.md`)
2. Прогноз CPC через `report_campaign` с `campaign_ids` похожих кампаний (из `_account_audit.md`) и `date_range: LAST_30_DAYS`; **без `campaign_ids` вызов упадёт**. Иначе берём из `02_frequency.json`
**Артефакты:** `08_creatives.md` (для маркетолога) + `08_creatives.json` (machine-readable). Схема: `assets/creatives_schema_combined_example.json`.
После — `python -m scripts.preflight --workspace <path>`: проверка лимитов комбинаторного (заголовки, тексты с учётом «узких» знаков, длины слов, символы отображаемой ссылки, быстрые ссылки и их суммарная длина по четвёркам, уточнения, наличие файлов картинок, объём минус-фраз). Затем `python -m scripts.generate_ads_xlsx --workspace <path>` → xlsx/csv + `warnings.txt` для маркетолога.
**Если среда не запускает код** — отдай обе команды пользователю текстом и попроси прислать вывод. Не может и он — сверь лимиты вручную по `references/yandex-direct-specs.md` (пройди тот же перечень: заголовки, тексты, длины слов, ссылки, уточнения, объём минус-фраз) и впиши в `08_creatives.md` пометку: «пропущено: нет запуска кода — `preflight.py` не прогонялся, лимиты сверены вручную. Потеряно: машинная проверка перед заливкой. Как добрать: прогнать `python -m scripts.preflight` в среде с Python». Ручная сверка **не отменяет** гейт: объявление с нарушенным лимитом Директ отклонит.
**[GATE: маркетолог]** «Объявления принимаешь?»
## Шаг 8.5. Картинки для РСЯ (приём от маркетолога или генерация)
**Прочти `references/rsya-creatives.md` и `references/visual-generation.md` целиком.**
Скилл работает только с **картинками**: их `adimages_add` заливает, а видео MCP создать нечем (`video_extension_ids` взять негде — `references/yandex-direct-mcp.md` → «Чего MCP не умеет»). Видео маркетолога, если оно есть, не генерируем и не заливаем — пишем файлы списком ручной работы в `10_launch_log.md`.
Если в брифе только Поиск — шаг пропускается. Если РСЯ есть:
0. **Источник визуалов — сперва спроси, потом генерируй.** У картинок два источника,
и приоритет — за маркетологом:
- **Свои креативы маркетолога** (поле «существующие материалы» брифа или прямо
сейчас). Спроси: «Есть свои картинки под РСЯ? Пришли файлы или публичные ссылки —
возьму их, иначе сгенерирую». Присланные **файлы** сложи в `assets/images/`,
присланные **публичные ссылки** запиши в `08_creatives.json` группам как есть
(в Шаге 10Б они пойдут в `adimages_add` напрямую, без KeepImage). Прогони
`python -m scripts.validate_assets --workspace <path>` — не прошедшие
техтребования Директа Директ отклонит (`5004`), верни маркетологу на замену.
Свои картинки закрывают потребность группы — генерацию для неё пропусти.
- **Нет своих** — генерируй по пунктам ниже.
- **Нет ни своих, ни ключей на генерацию** — фолбек-ветка в конце шага (ТЗ дизайнеру).
1. **Pre-flight:** собери `brand.json` в рабочей папке из брифа (product_name, цвета
HEX, style_references). Проверь ключи: `python -m scripts.manage_credentials list`.
Нет ключа openai — попроси пользователя прислать в чат и сохрани:
`python -m scripts.manage_credentials set openai --key <KEY>`. Ключ НИКОГДА
не пишем в артефакты рабочей папки.
2. **Концепции:** добавь в `08_creatives.json` каждой группе
`combined_ad.visual_concepts` (2 концепции: id A/B, type, angle, usp_on_creative —
УТП из Шага 1, углы из гипотез). **[GATE: маркетолог подтверждает концепции]**
3. **Dry-run:** `python -m scripts.generate_creative_images --workspace <path> --dry-run`
→ прочитай 1–2 промпта из `assets/prompts/`.
4. **Тест:** `... --concept A` → одна картинка. **[GATE: нравится? иначе — правь
концепцию/шаблон и --force]**
5. **Полный прогон:** `python -m scripts.generate_creative_images --workspace <path>`
→ до 5 картинок на группу (A×3 форматов + B×2).
6. **Валидация:** `python -m scripts.validate_assets --workspace <path>` — все ассеты
должны пройти (450–5000 px, соотношения, ≤10/100 МБ).
7. **[GATE: маркетолог смотрит assets/images перед заливкой]**
**Фолбек без ключей:** собери `08_5_rsya_creatives_TODO.md` (ТЗ дизайнеру по
`references/rsya-creatives.md`), кампания заливается без визуалов, TODO в launch log.
**Артефакты:** `assets/images/*.png`, `assets/prompts/`,
`assets/generation_log.json`, `assets/validation_report.json`; обновлённый
`08_creatives.json` (`visual_concepts`, `images`).
## Шаг 9. Стратегия торгов
**Прочти `references/bidding-strategy.md` целиком** (подраздел «Комбинаторная ЕПК — одна стратегия на РК»).
В комбинаторной ЕПК Поиск и РСЯ — одна кампания, поэтому **одна стратегия на РК**; `channel` в `09_bidding_strategy.json` переносится из `05_campaign_structure.json`.
**Сетевая сторона — по `channel` РК из `05_campaign_structure.json`** (таблица — `bidding-strategy.md` → «Сочетания сторон в ЕПК»):
- `epk` (поиск + РСЯ) — автостратегия с бюджетом на поиске, `network_strategy: NETWORK_DEFAULT`;
- `epk-search` (только поиск) — автостратегия или ручные на поиске, `network_strategy: SERVING_OFF`;
- `epk-network` (только РСЯ) — `search_strategy: SERVING_OFF`, автостратегия с `weekly_spend_limit` в сети.
`SERVING_OFF` в сети — только когда РСЯ в структуре этой РК нет. Одинаковая автостратегия на обеих сторонах — ошибка `4000`. Ручные ставки (`HIGHEST_POSITION`) выключают РСЯ, поэтому для `epk` их не ставим.
**Бюджет — недельный** (базовая единица 2026, мин. 300 ₽/нед); дневной — только для ручных ставок на Поиске, **тоже от 300 ₽**. **Если РК несколько по разным углам с одной целью** — рассмотри **пакетную стратегию** (общий пул обучения: порог ≥10 конв/нед считается суммарно по пулу, до 100 РК) — это спасает мелкие/премиум РК от «голода» по конверсиям. Детали — в `bidding-strategy.md`.
**Передать:** `05_campaign_structure.json` (кампании + бюджеты), целевые CPC из `02_frequency.json`, целевые CPL/CPA из брифа, `07_metrika_goals.json` (критичный вход — `goal_id` для оптимизации в Фазе 3 **и `conversions_per_week` по каждой цели**), `_channel_history.md` (раздел «Сайт», если есть — устройства и гео для корректировок), состояние коллтрекинга (из брифа), тип ниши.
**Объём конверсий — из Метрики, а не на глаз.** Если у цели сайта уже ≥10 конв/нед со всего трафика, а РК получает заметную его долю — Фаза 3 достижима быстро, скажи это цифрами. Если у макро-цели 1–3 конв/нед — честно: на неё кампания не обучится, предложи оптимизацию на более частую цель воронки или пакетную стратегию. Цель типа `action`, для которой разработчик ещё не поставил событие (0 достижений), целью оптимизации **не** ставим.
**На выходе:**
- `09_bidding_strategy.md` — план с 3-фазной эволюцией (Старт → Промежуточная → Масштаб) и триггерами переключения
- `09_bidding_strategy.json` — machine-readable для заливки: каждая фаза описана **параметрами API** (`search_strategy` / `network_strategy` с типом и обязательными полями), а не свободным текстом. Таблица соответствия — в `bidding-strategy.md` → «Маппинг в API»
- `09_bidding_monitoring.md` — что и когда мониторить
**Заливается только Фаза 1.** Она уходит через MCP вместе с кампанией на Шаге 10 — доделывать руками её не нужно. Фазы 2–3 и триггеры переключения — это **план для маркетолога**, а не работа скилла: скилл кампанию не ведёт и не оптимизирует, он отдаёт условия перехода цифрами в `09_bidding_strategy.md` и `09_bidding_monitoring.md`. Скажи об этом на гейте словами, чтобы не осталось впечатления, что переключение произойдёт само. Пакетную стратегию MCP не умеет: если она рекомендована, пункт уходит в `10_launch_log.md`.
**Главное правило:** на старте — **НЕ** «Максимум конверсий». «Максимум кликов» (с ограничением средней цены клика) 2 недели → ужесточить ограничение средней цены клика → (после 10+ конверсий/нед, для приложений 70/нед) → «Максимум конверсий» с оплатой за конверсии и ограничением CPA.
**Алярма:** если коллтрекинг не настроен (важно для срочного спроса и B2B) → Фаза 3 заблокирована, предупреждение до запуска.
**[GATE: маркетолог]** подтверждает стратегию по каждой кампании.
## Шаг 10. Заливка через MCP + финальные артефакты
### 10А. Финальный чек-лист готовности
Перед заливкой пройдись по ВСЕМ артефактам:
```
✅ 00_brief.md
✅ 01_masks.json
✅ 02_frequency.json
✅ 03_semantics_raw.csv
✅ 04_keys_search_obligatory.csv (+ keys_search_vch.csv если применимо)
✅ 04_keys_rsya.csv (если есть РСЯ)
✅ 05_campaign_structure.json
✅ 06_negative_keywords.json
✅ 07_metrika_goals.json
✅ 08_creatives.json
✅ 09_bidding_strategy.json
✅ region_ids в 05_campaign_structure.json (Use case 4 в mcp-account-integration.md)
```
**Метрика перед заливкой (если есть MCP Метрики):** `goals_get({ counter_id })` — все `goal_id` из `07_metrika_goals.json` существуют и не удалены; `report_bytime({ counter_id, metrics: ["ym:s:visits"], date1: "3daysAgo" })` — визиты идут. Цель пропала или визитов ноль — заливку не начинаем, возвращаемся на Шаг 7.
**Финальная проверка перед заливкой.** Каждая строка получает ✅, ⛔ или 👀 (проверить
руками) и целиком показывается маркетологу в предпросмотре 10Б:
| Что | Как проверяем | ⛔ если |
|---|---|---|
| Кабинет | `client_login`, название и сервер из `_state.json` = кабинет, подтверждённый на Шаге 0.5.1; `accounts_get` отвечает | кабинет не виден, ошибка авторизации |
| Кампания | имя новой кампании не совпадает с существующими в кабинете (`campaigns_get`); не каннибализирует действующие (Use case 1–2 `mcp-account-integration.md`) | дубль имени — переименовать или явно подтвердить |
| Посадочная | URL в объявлениях и быстрых ссылках = посадочная из брифа; страница открывается (чтение веб-страниц) | 404, редирект на чужой домен. Читать страницы нечем — 👀 |
| Бюджет | недельный лимит × 4,3 ≈ месячный бюджет брифа (±10 %); сумма по кампаниям не больше брифа | больше брифа |
| Цель Метрики | `goal_id` подтверждён на Шаге 7, существует и срабатывает (проверка выше) | нет подтверждённой цели |
| Минус-слова | `06_negative_keywords.json` не пуст; минусы кампании ≤ 20 000 символов; кросс-минусация применена | пусто или лимит превышен |
| Юр. риски лендинга | `references/ad-legal-topics.md` → «Проверка посадочной страницы» | лицензируемая тема, а сведений о документах на сайте нет. Остальные риски — 👀 |
Хоть одна ⛔ или открытый блокер из `_state.json` → `blockers` — **заливки нет**. 👀 не
блокирует, но уходит в `10_launch_log.md` → «Проверить руками».
Хоть один артефакт отсутствует — **не запускай заливку**. Вернись на соответствующий шаг.
### 10Б. Заливка через MCP
**Полная последовательность — `references/mcp-account-integration.md`, Use case 5. Здесь только каркас, не дублируй логику.**
MCP заливает всю ЕПК целиком: оболочку кампании (`campaigns_add` с `campaign_type: "UNIFIED"` и обеими сторонами стратегии из `09_bidding_strategy.json`), группы (`adgroups_add` с `group_type: "UNIFIED"`, по одной на каждую из `08_creatives.json`), комбинаторное объявление в каждой (`ads_add_responsive`), быстрые ссылки, уточнения, отображаемую ссылку, ключи, ставки, автотаргетинг (`autotargeting_set` — категории и бренды из `05_campaign_structure.json`) и корректировки.
1. **Pre-flight:** `python -m scripts.preflight --workspace <path>`. Есть ошибки — заливка не стартует. Среда не запускает код — ручная сверка по `references/yandex-direct-specs.md` (см. ветку в Шаге 8) плюс пометка о пропуске; блокирующая роль гейта сохраняется.
2. **Предпросмотр:** весь конвейер с `dry_run: true` — инструменты вернут тела запросов, ничего не создавая, но выполнив все проверки. Покажи маркетологу сводку **вместе с финальной проверкой 10А** (кабинет, посадочная, юр. риски — тоже) и дождись явного «ОК». Любая запись в кабинет — только после него.
3. **Заливка** по порядку: ассеты (картинки → быстрые ссылки → уточнения) → кампания → группа → объявление → ключи → ставки → автотаргетинг (строго после ставок: групповая ставка ложится и на него) → корректировки. ID каждого объекта пиши в `10_launch_log.md` **сразу**, а не в конце: при обрыве заливка продолжается с места, повторный `campaigns_add` создаст дубль. ⚠️ **Но 19-значные ID сейчас приходят от MCP округлёнными** (`references/yandex-direct-mcp.md` → «Конверт ответа»), поэтому идемпотентность по записанному ID **ненадёжна**: при обрыве и повторном проходе проверяй, что уже создано, через `campaigns_get` по имени/дате, а не полагайся только на ID из лога.
4. **Проверяй ответы целиком.** Ответ может быть `success: true` и при этом содержать отклонённые объекты — «вернулось без ошибки» не значит «всё создано».
**Картинки — через KeepImage → `image_url`.** Хостовый MCP Директа не видит локальные файлы, но `adimages_add` теперь принимает `image_url` — публичную ссылку http/https, сервер Директа скачивает файл сам (сверено живьём 03.09.2026). Мост «локальный файл → публичная ссылка» — временное хранилище **KeepImage** (ссылка без авторизации, живёт ≤2 ч; подключение — `docs/hosted-mcp-setup.md`, справочник по `adimages_add` — `references/yandex-direct-mcp.md`). Ссылка нужна живой только на момент вызова: Директ скачивает картинку и сохраняет у себя, дальше ссылка не нужна — TTL не мешает. Порядок на каждую картинку из `combined_ad.images`:
1. **Локальный файл → публичная ссылка.** Приоритет — скрипт: `python -m scripts.upload_creatives_to_storage --workspace <path>` (постит файлы в KeepImage по HTTP, пишет `assets/storage_manifest.json` — соответствие путь → ссылка). Среда без запуска кода — MCP хранилища: инструмент `*storage_publish_image(data_base64=<файл>)` по одной картинке (сервер ищи по инструменту, имя может быть любым — `KeepImage`, `storage`, …) (дорого и ненадёжно для крупных до 10 МБ — base64 рвётся; ужимай или отдавай публичной ссылкой). Картинка уже по публичному URL (маркетолог дал ссылкой) — KeepImage не нужен, шаг 1 пропускается.
2. **Ссылка → хеш.** `adimages_add({ client_login: <из _state.json>, image_url: <ссылка из манифеста>, name: "<имя>", crop: "square"|"wide" })` → `AdImageHash`. По одному вызову на файл, до 5. Вызовы **строго последовательные** — параллельная загрузка на MCP даёт ошибку `waiting on finished stream`.
3. **Хеши → объявление.** Собери `AdImageHash` в `image_hashes` и передай в `ads_add_responsive`. Пиши хеши в `10_launch_log.md` сразу — при обрыве не грузить повторно.
4. **Прибери.** После получения всех хешей ссылки в KeepImage не нужны — `storage_delete(id)` по манифесту (или дай истечь за ≤2 ч).
⚠️ Картинка должна проходить техтребования Директа (Шаг 8.5, `scripts/validate_assets.py`): иначе `adimages_add` вернёт `5004 Invalid image file type` — это отказ **Директа по контенту**, а не проблема KeepImage. **Фолбек** (нет KeepImage и нет запуска кода): объявление заливается **без** `image_hashes`, добавление картинок уходит в `10_launch_log.md` списком ручной работы (интерфейс Директа или Коммандер) с пометкой о пропуске. Остальная цепочка на хостовом MCP работает как обычно.
Кампании остаются в **DRAFT**.
**Что MCP не умеет** — уходит в `10_launch_log.md` честным списком: Библиотека минус-фраз при переполнении лимита кампании, пакетная стратегия, временной таргетинг, кнопка действия/цена/промоакция/карусель, видео, условия ретаргетинга (сегменты Метрики из `07_metrika_goals.json` → `segments` уже созданы — в лог пиши их `segment_id`, чтобы маркетолог собрал из них условие руками). Полный перечень — в `references/yandex-direct-mcp.md` → «Чего MCP не умеет».
**Фолбек — Директ Коммандер.** Если MCP не подключён и `scripts/setup_yandex_direct_mcp.py` не помог, либо маркетологу нужен визуальный ревью структуры до отправки: импорт `ads.xlsx`/`keywords.xlsx` Шага 8 по `references/direct-commander-import.md`.
### 10В. Финальные артефакты для маркетолога
После заливки:
1. `python -m scripts.generate_media_plan --workspace <path>` → `media_plan.docx` (агрегирует все артефакты пайплайна)
2. `python -m scripts.generate_ads_xlsx --workspace <path>` → `ads.xlsx` + `keywords.xlsx` + `warnings.txt`
3. `10_launch_log.md` — итоговый отчёт для маркетолога. Разделы **обязательны** в этом порядке:
- **«Итог»** — 3–5 строк: что залито (кампании, группы, объявления, ключи — с ID), в каком
статусе (DRAFT), что осталось до активации.
- **«Сделал сам»** — по строке на шаг: шаг → артефакт → ✅ / ✅ с пометкой о пропуске.
- **«Данные и источники»** — откуда взято каждое ключевое решение: регион, бюджет, цель,
CPC/CPA, типы кампаний, ключи. Источник — один из: бриф / кабинет Директа / Метрика /
история каналов / Вордстат / справочник / гипотеза (с пометкой «требует подтверждения»).
- **«Блокеры»** — какие были, как сняты; неснятые — первой строкой отчёта.
- **«Пропущено из-за среды»** — см. ниже.
- **«Проверить руками»** — всё 👀 из финальной проверки 10А (юр. риски лендинга и т. п.), что
MCP не умеет (условия ретаргетинга…), что Директ сохранил, но не применяет (`not_in_effect`,
предупреждения 10160/10161), ОРД-маркировка, активация.
**Если среда не запускает код** — оба генератора пропускаются: медиаплан собери прозой прямо в `media_plan.md` по тем же артефактам, таблицу объявлений — таблицей Markdown в `ads.md`. Пометка: «пропущено: нет запуска кода — `media_plan.docx` и `ads.xlsx` не собраны, вместо них `.md`. Как добрать: прогнать `scripts/generate_media_plan.py` и `scripts/generate_ads_xlsx.py` в среде с Python». Для импорта в Директ Коммандер нужен именно xlsx или csv — без запуска кода этот путь фолбека закрыт, скажи об этом прямо.
**Обязательный раздел `10_launch_log.md` — «Пропущено из-за среды».** Собери в него все пометки о пропуске со всех шагов одним списком: какой шаг, какой способности не было, что сделано вместо, что недобрано, что делать человеку. Пусто — напиши «пропусков нет, все шаги выполнены полностью». Этот раздел маркетолог читает **до** активации кампании: он показывает, на каких данных построена кампания, а на каких — нет.
Покажи файлы пользователю тем способом, который есть в среде (например, `computer://`-ссылками): Media plan, Ads, Keywords, Launch log. Способа показать нет — перечисли пути к файлам от корня рабочей папки.
### КРИТИЧНО: ИИ НИКОГДА не активирует кампании сам
Кампании остаются в **DRAFT**. Финальный клик «Активировать» (`campaigns_resume`) делает только маркетолог в интерфейсе Директа.
Активация = реальный расход бюджета. Нужен последний человеческий чек: посадочные открываются, Метрика работает (визиты и цели проверены на 10А — напомни, что JS-цели от разработчика проверяются только после его деплоя), коллтрекинг подключён, бюджеты налиты, ОРД-маркировка включена.
---
# Стиль работы
- **Не клянчи.** Один прямой вопрос за раз. В Шаге 0 — единый блок брифа.
- **Не вываливай простыни.** Артефакт — в файл, сводка в чат 5-10 строк.
- **Гипотеза > пустой вопрос.** «Вот моя версия — согласны?»
- **Цифры сайта > догадки.** Есть счётчик — CPA, конверсии, гео и фразы бери из Метрики; нет — говори «истории нет», а не подставляй средние по рынку как факт.
- **Защищай качество на гейтах.** Если reference сказал «алярма — нет Метрики на сайте» — не закрывай это «ой ладно, как-нибудь без неё».
- **Бюджет важен** — предупреди при <30-50к ₽/мес.
- **Не выдумывай метрики и УТП.** «Не знаю» лучше выдуманного.
- **Пропуск всегда виден.** Шаг, выполненный без необязательной способности среды, получает пометку о пропуске в свой артефакт (формат — в «Что нужно от среды»), а на гейте ты говоришь об этом словами. Молча упрощённый результат — хуже честно недобранного.
- **References обязательны.** На шагах с пометкой «прочти `references/<name>.md` целиком» — это **не намёк**, а обязательное чтение.
# Возобновление
«Продолжаем по Директу» → найди `direct-campaigns/*/`, прочитай `_state.json`, продолжай с того места. Не начинай сначала. Кабинет Директа (`direct_client_login`) и счётчик (`metrika_counter_id`) читай из `_state.json` и **не** спрашивай заново — Шаг 0.5 уже пройден. Оборвался посреди разведки — продолжай с первого незакрытого подпункта по `current_step` (`recon.direct` / `recon.metrika` / `recon.history`). Если кампания уже залита — этот скилл закончил работу; дальнейшие изменения — другая задача.
# При сбое шага
Проверь, что у шага есть все входы: каждый шаг читает артефакты предыдущих (их точный список — в «Передать» и «На выходе» самого шага). Нет входа — возвращайся на шаг, который его порождает, закрывай пробел, потом продолжай.