Skip to main content
Glama
perejaslav

DirectAI MCP

by perejaslav
README.md
# DirectAI MCP — личный сервер статистики и управления Яндекс Директом

> ИИ-агент? Следуй [AGENTS.md](AGENTS.md).

DirectAI MCP is a local MCP server for Yandex Direct stats and management.
Runs on your Windows 11 PC for a single user. Tested on Windows 11 only;
macOS/Linux not supported. Start install at §1 below.

Локальный MCP-сервер: ИИ-ассистенты (OpenCode, Codex и др.) через него читают
статистику и управляют вашими аккаунтами Яндекс Директа.
Только для одного пользователя, работает на вашем компьютере, в интернет
ничего не выставляет.

## Прежде чем устанавливать

Обязательно:

- Windows 11 (инструкции — только для PowerShell; macOS/Linux
  не тестировались и не поддерживаются);
- аккаунт Яндекс Директа с хотя бы одной кампанией (можно черновик);
  для агентств — главный логин агентства;
- своё приложение на oauth.yandex.ru (анкета на 5 минут, права Директ
  и Метрика) — запомните ID приложения;
- одобренный доступ к API Директа (Инструменты → API → заявка с ID
  приложения); одобрение занимает до нескольких дней;
- ИИ-помощник с поддержкой MCP (OpenCode, Codex, Claude Code,
  Claude Desktop, Hermes); сам DirectAI бесплатный, работает локально
  на вашем компьютере, для одного пользователя.

По ходу установки: токен получаете по ссылке, вводите сами в своём
терминале, никогда не в чат.

Желательно: доступ к счётчику Метрики (иначе CRM-выручка не отличается
от условной ценности целей).

Не нужно: программировать, покупать сервер, заранее ставить git или Python.

### С чего начать

1. Создайте приложение и подайте заявку на API — это самое долгое,
   начните с этого (подробности — §1.1, шаг 5).
2. Пока ждёте одобрения — установите DirectAI (§1 или §1.1).
3. Когда заявку одобрят — получите токен и выполните проверку
   (`set-token`, затем `check`).

## 1. Установка с нуля

Нужно: Windows 11, `uv`, `git` (оба ставятся через `winget`, см. §1.1),
токен Яндекс Директа (как получить — см. §1.1, нужен доступ к API).

```powershell
cd $env:USERPROFILE
git clone https://github.com/perejaslav/directai-mcp.git directai-mcp
cd $env:USERPROFILE\directai-mcp
uv tool install --editable .
uv tool update-shell
directai-mcp init
directai-mcp set-token --login ВАШ_ЛОГИН
directai-mcp check
```

Впишите свой логин в `%USERPROFILE%\.directai\accounts.toml` (`[auth] login`,
замените демо-алиасы) между `init` и `set-token`; в `set-token` передайте
тот же логин флагом `--login`.

Что происходит: `init` создаёт `%USERPROFILE%\.directai\` и копирует примеры
конфигов (существующие не трогает); `set-token` маскированно спрашивает токен
и кладёт его в Credential Manager Windows (в файлах токена нет никогда);
`check` проверяет доступ. Ожидание — строки `OK` по каждому аккаунту с числом
кампаний и остатком баллов.

## 1.1. Установка через ИИ-агента — промпт для новичка

Новичок (свой аккаунт Директа, ничего общего с автором) копирует блок ниже
в любого агента (OpenCode, Codex, Claude Code) — агент ставит всё с нуля.

```
Ты помогаешь новичку установить DirectAI MCP с нуля на Windows 11.
Человек не знает git, uv и PowerShell. Объясняй простыми словами,
одно действие за раз. Каждую команду давай отдельно, жди результата.
Правила: бюджеты и стратегию без «да» владельца не менять; guard не выключать никогда;
запись только через план с подтверждением; токен только в Credential Manager.
0. Сначала спроси, одобрен ли уже доступ к API Директа. Нет — начни
с шага 5 (создать приложение и подать заявку: это самое долгое),
затем ставь DirectAI (шаги 1–4), а токен и check — после одобрения.
Доступ уже одобрен — иди по шагам 1–4, затем токен и проверка.
1. Спроси разрешение и поставь git и uv (флаги снимают лишние вопросы):
winget install --id Git.Git -e --accept-package-agreements --accept-source-agreements
winget install --id astral-sh.uv -e --accept-package-agreements --accept-source-agreements
Проверь: git --version и uv --version. Нет команды — обнови PATH в этой сессии
(давай строку одним блоком, проверь, что вставилась одной строкой):
$env:Path = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Environment]::GetEnvironmentVariable("Path","User")
Нет winget — поставь App Installer из Microsoft Store.
2. Склонируй репозиторий (три команды, по одной). Папка directai-mcp уже есть —
не клонируй, а выполни git pull внутри неё:
cd $env:USERPROFILE
git clone https://github.com/perejaslav/directai-mcp.git directai-mcp
cd $env:USERPROFILE\directai-mcp
3. Установи и инициализируй (по одной команде):
uv tool install --editable .
uv tool update-shell
$env:Path = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Environment]::GetEnvironmentVariable("Path","User")
directai-mcp --version
directai-mcp init
Первая установка качает Python несколько минут — это не зависание.
4. Спроси логины кабинетов (это не секрет): главный — владелец будущего токена.
Если кабинетов несколько (агентство: главный логин видит клиентские) —
попроси все. ПОЛНОСТЬЮ замени демо-алиасы в %USERPROFILE%\.directai\accounts.toml:
[auth] login — реальный главный логин, под каждый логин свой [aliases.*].
goals.toml необязателен: названия целей Метрики, можно заполнить позже.
5. Токен. Объясни: создай приложение типа «Для доступа к API или отладки»
на https://oauth.yandex.ru/client/new с правами direct:api и metrika:read.
Redirect URI настраивать не нужно — он фиксирован. Затем открой в браузере ссылку
https://oauth.yandex.ru/authorize?response_type=token&client_id=ID_ПРИЛОЖЕНИЯ&redirect_uri=https://oauth.yandex.ru/verification_code
(подставь ID со страницы приложения) и нажми «Разрешить» — токен появится
в адресной строке. Скопируй ТОЛЬКО значение после access_token= и до &,
не весь URL (вид: access_token=y0_AgA...&token_type=...). Спроси «что видишь?»:
ошибка OAuth — проверить ID приложения и пробелы. Это штатный способ из доки:
https://yandex.ru/dev/direct/doc/ru/concepts/auth-token. Затем подай заявку
на доступ к API в интерфейсе Директа (Инструменты → API → Мои заявки),
инструкция: https://yandex.ru/dev/direct/doc/ru/concepts/register.
В описании заявки укажи «личный учёт статистики и управление своими кампаниями».
Одобрение занимает до нескольких дней — ошибка 58 до этого норма, просто ждём.
Без metrika:read типы ценностей берутся из goals.toml (по умолчанию условные).
6. Токен в чат писать ЗАПРЕЩЕНО. Пусть человек САМ выполнит в своём терминале:
directai-mcp set-token — и введёт токен в скрытое поле. Символы не отображаются —
это нормально: вставить и Enter. Если вставил в чат — останови, попроси
отозвать токен в Яндекс ID и выпустить новый.
7. Проверь: directai-mcp check. Расшифруй итог: OK — работает; 53 — неверный
токен, повторить шаг 6; 58 — нет доступа к API, вернуться к шагу 5; 513 —
у логина нет аккаунта в Директе (создай кампанию в интерфейсе); 152 —
кончились баллы API, подождать до завтра. Коды:
https://yandex.ru/dev/direct/doc/ref-v5/concepts/errors-list.html
8. Самопроверка сервера: directai-mcp probe. Ожидание — две строки OK
(версия сервера, число инструментов, stats_summary найден). Баллы API
не тратятся. Сырые stdio-пробы вручную не делать — только probe.
9. Подключи харнес: сначала спроси, какой — OpenCode, Codex или Claude Code.
Сделай копию его конфига (*.bak), потом ДОПИШИ блок directai-mcp, чужие MCP
не трогай. Готовые блоки — examples/harness-configs.md.
9. Попроси человека САМОГО перезапустить харнес (закрыть все его окна
и открыть заново). В новой сессии пусть спросит:
«Используй только directai-mcp: покажи расходы по всем аккаунтам за вчера» —
и сверит цифры с веб-интерфейсом Директа. Сошлось — готово.
10. Удали свои бэкапы (*.bak-*, *-tool-backup-*), чужие файлы не трогай.
```

## 2. Подключение к харнесам

Команда запуска везде одна — `directai-mcp` (без аргументов: STDIO-сервер).
После настройки перезапустите харнес.

**OpenCode** — файл `%USERPROFILE%\.config\opencode\opencode.json`:

```json
{
  "mcp": {
    "directai-mcp": {
      "type": "local",
      "command": ["directai-mcp"],
      "enabled": true
    }
  }
}
```

**Codex** — файл `%USERPROFILE%\.codex\config.toml`:

```toml
[mcp_servers.directai-mcp]
command = "directai-mcp"
args = []
```

Остальные (Claude Desktop, Claude Code) — готовые фрагменты в
`examples/harness-configs.md`. Если харнес не видит команду, укажите полный
путь к `directai-mcp.exe` (покажет `(Get-Command directai-mcp).Source`).

Проверка (задать ИИ): «Покажи расходы по всем аккаунтам за последние 7 дней» —
итоги должны совпасть с веб-интерфейсом Директа.

## 3. Файлы в `%USERPROFILE%\.directai\`

| Файл | Что внутри и как править |
|---|---|
| `accounts.toml` | Ваши кабинеты: `[auth] login` — владелец токена, под каждый логин свой `[aliases.*]` (короткое имя и роль). Плюс `defaults` (`include_vat`, `max_rows`, `attribution`), секция `[guard]` и секция `[audience]` (`write_enabled`, дефолт `false` — запись в Аудитории выключена), секция `[retargeting]` (`write_enabled`, дефолт `false` — запись ретаргетинга выключена). Секретов здесь нет. Править любым текстовым редактором, применяется со следующего запроса. |
| `rules.toml` | Правила: обязательный DisplayUrlPath, слова для заголовков, пороги `max_budget_ratio` / `max_bid_ratio` (предупреждения при резких изменениях). |
| `goals.toml` | `id цели → Название` (цели Метрики). В отчётах цель видна как «Название (id)», без названия — голый id. Названия вписываете вы. |
| `journal.sqlite` | Журнал всех записей (не удаляйте). |
| `plans\` | Планы записи: один файл на план (общее хранилище для всех процессов сервера, TTL 15 минут, применение ровно один раз; просроченные чистятся автоматически). |
| `exports\` | CSV/MD-выгрузки из отчётов. |
| `logs\` | Логи сервера. |

Переопределить каталог: переменная `DIRECTAI_HOME`. Токен Директа: только
Credential Manager (`directai-mcp`) или переменная `DIRECTAI_TOKEN`. Для
Метрики (v1.17.1) — отдельный токен: `directai-mcp set-metrika-token
--login <логин>` (Credential Manager `directai-mcp-metrika` или переменная
`DIRECTAI_METRIKA_TOKEN`), подробности — §7.1; без него чтение идёт токеном
Директа с примечанием, а запись целей недоступна. Для
Яндекс.Вебмастера можно хранить отдельный токен: `directai-mcp set-token
--webmaster` (Credential Manager `directai-mcp-webmaster` или переменная
`DIRECTAI_WEBMASTER_TOKEN`); без него используется основной токен.
Для Wordstat API Yandex Cloud используется отдельный API-ключ: выполните
`directai-mcp set-token --wordstat`, введите `folderId` каталога AI Studio,
затем ключ в скрытом поле. Ключ хранится в Credential Manager
(`directai-mcp-wordstat` или `DIRECTAI_WORDSTAT_API_KEY`), а `folderId` — в
`[wordstat] folder_id` в `accounts.toml`. Секретный ключ в этот файл не
записывается. Действия Wordstat — только чтение и не используют OAuth-токен
Директа.
Запись в Яндекс Аудитории выключена по умолчанию
(`[audience] write_enabled=false`); включается только явным
`write_enabled = true`, путь тот же: `plan_write` → ваше согласие →
`apply_write`, guard требует имя сегмента `[TEST DirectAI]*`.

## 4. Что умеет сервер

Порядок работы ИИ: `search_actions` → `describe_action` → `run_read`
(чтение) или `plan_write` → показать вам → `apply_write` (запись).

`describe_action` без имени (или с пустой строкой) — статус сервера, вызов
бесплатный (API не тратится): `server_version` (что декларирует установка
пакета, `importlib.metadata`), `code_version` (код, реально запущенный в
процессе), `disk_version` (исходники на диске) и строка «Метрика: …» —
какой токен используется для Метрики (отдельный или токен Директа), §7.1.
Если `code_version` ≠ `disk_version` — блок предупреждения «перезапустите
MCP-сервер»; если `server_version` ≠ `code_version` — «переустановите пакет»
(`uv tool install --force --editable .`, README §7): у editable-установки
метаданные обновляются только переустановкой, перезапуск сервера не поможет.

Чтение (57):

| Действие | Что делает |
|---|---|
| `stats_summary` | Итоги по аккаунтам: показы, клики, расход, конверсии |
| `stats_campaigns` | Статистика по кампаниям |
| `stats_adgroups` | Статистика по группам объявлений |
| `stats_ads` | Статистика по объявлениям |
| `stats_keywords` | Статистика по фразам и автотаргетингу |
| `stats_search_queries` | Поисковые запросы пользователей |
| `stats_regions` | Статистика по регионам местонахождения |
| `stats_placements` | Статистика по площадкам РСЯ |
| `stats_devices` | Статистика по устройствам |
| `stats_audiences` | Статистика по аудиториям и ретаргетингу |
| `stats_compare` | Сравнение двух периодов (только так, не вручную) |
| `stats_custom` | Произвольный отчёт: свои поля и фильтры |
| `campaigns_list`, `campaigns_get` | Список и полные настройки кампаний |
| `adgroups_list` | Группы кампании |
| `ads_list` | Объявления (ссылки, уточнения, DisplayUrlPath; фильтр States, вкл. архивные) |
| `keywords_list` | Фразы группы или кампании |
| `negatives_audit` | Все минус-фразы кампании одним ответом |
| `extensions_list` | Быстрые ссылки, уточнения, изображения |
| `audiences_list` | Аудиторные условия и списки ретаргетинга |
| `bids_get` | Ставки фраз (поиск и сети) |
| `bid_modifiers_get` | Корректировки ставок |
| `dictionaries_get` | Справочники (регионы по названию) |
| `changes_check` | Что менялось с даты |
| `accounts_discover`, `accounts_check`, `accounts_balance` | Кабинеты: поиск, проверка доступа, баллы |
| `counter_check` | Проверка счётчиков Метрики кампании |
| `metrika_goals_list` | Цели счётчиков Метрики: id, название, тип (без статистики) |
| `metrika_traffic` | Метрика: визиты по источникам (source/utm/direct/landing/device/region) |
| `metrika_goals_report` | Метрика: достижения целей и CR, в разрезе group_by — опционально |
| `metrika_bytime` | Метрика: динамика по дням/неделям (визиты, отказы, цель) |
| `metrika_direct_cpa` | Цена заявки по кампаниям: расход Директа + визиты/цели Метрики, CPA |
| `moderation_check` | Статусы модерации объявлений |
| `webmaster_hosts`, `webmaster_summary`, `webmaster_query` | Вебмастер: сайты и подтверждение прав, ИКС и проблемы, произвольный read-ресурс API v4 |
| `audience_segments_list`, `audience_segment_get` | Аудитории: сегменты пользователя (тип, статус, размер) |
| `strategies_get` | Пакетные стратегии: настройки, бюджеты и цели |
| `feeds_get` | Фиды: источник, статус обработки, кампании |
| `dynamic_targets_get`, `dynamic_feed_targets_get`, `smart_targets_get` | Условия динамических объявлений и фильтры смарт-баннеров |
| `businesses_get` | Профили организаций (только по ID) |
| `turbopages_get` | Турбо-страницы: метаданные без содержимого блоков |
| `keyword_bids_forecast` | Прогноз ставок по существующим фразам: объём трафика → ставка → цена (только чтение) |
| `phrases_forecast` | Прогноз показов/кликов/цен для новых фраз до добавления (Live v4, только чтение) |
| `wordstat_top` | Wordstat: популярные и связанные запросы за последние 30 дней |
| `wordstat_dynamics` | Wordstat: динамика частотности по дням, неделям или месяцам |
| `wordstat_regions` | Wordstat: распределение частотности по регионам за последние 30 дней |
| `wordstat_regions_tree` | Wordstat: справочник регионов и иерархия кодов |
| `retargeting_lists_list` | Условия ретаргетинга кабинета: правила человеческим языком, где используются |
| `audience_targets_list` | Привязки аудиторий к группам: условие, состояние, ставка/приоритет |
| `campaign_journal` | Журнал кампании: история правок, результаты по периодам, заметки (пишет md-файл) |
| `campaign_journal_snapshot` | Снимок результатов кампании за период (Директ + Метрика, локально) |
| `campaign_journal_note` | Заметка к кампании: гипотеза, решение, наблюдение, задача (локально) |

### Метрика: отчёты (v1.12.0, только чтение)

- `metrika_traffic` — визиты, пользователи, отказы, глубина, время,
  достижения цели и CR по источникам: `group_by` — `source` (тип источника),
  `utm` / `utm_full`, `direct` (кампании Директа), `landing` (страница входа),
  `device`, `region`. Фильтры `filter_utm_source` / `filter_utm_campaign`
  (точное совпадение).
- `metrika_goals_report` — строки = цели (достижения, CR); в разрезе
  `group_by` — опционально (те же значения).
- `metrika_bytime` — динамика по дням/неделям (`group: day|week`):
  визиты, отказы, выбранная цель.
- `metrika_direct_cpa` — связка с Директом по кампаниям одного логина:
  расход/клики из Директа + визиты/отказы/цели из Метрики; колонки —
  кампания, расход, клики, визиты, клики→визиты %, отказы %, цели, CR %,
  CPA = расход / цели. Расхождение кликов и визитов > 30% —
  флаг «проверить разметку/счётчик».
- Общее: счётчик — `counter_id`, иначе `[metrika] counter_id`, иначе счётчики
  кампаний; период по умолчанию — последние 14 полных дней; цели по
  умолчанию — основная (`primary_conversion_goal_id`), иначе все цели счётчика;
  атрибуция по умолчанию `lastsign` (в шапке); `accuracy=full`, семплирование
  помечается; 403 по счётчику — «нет доступа», без падения.
- Отчёты остаются только на чтение; запись целей счётчика — отдельные
  действия записи, см. §5.3.
- Порядок сопоставления кампаний в `metrika_direct_cpa` (способ — в колонке
  «Связь»): ID → ID+1e8 (у старых кампаний OrderID в Метрике больше
  CampaignId на сто миллионов; «Связь» = ID+сдвиг) → точное имя при единственном
  кандидате («Связь» = имя). Несопоставленные — отдельными блоками
  (кампании логина без расхода / визиты кампаний других логинов /
  «Чужие кампании»).

### Режим выгрузки (dump)

Любое действие чтения принимает параметры `dump_dir` (папка сессии) и
`dump_tag` (суффикс имени). В этом режиме ответ дополнительно сохраняется
в файлы как есть, без преобразований:

- `<NN>_<action>[_<tag>].json` — конверт ответа: `raw_items` (объекты API:
  деньги в micros, enum, null, вложенность; единственное преобразование —
  ID-ключи `*Id(s)` числом → строкой), `requested_field_names`
  (по каким полям читали), `pagination_complete` (все ли страницы
  прочитаны — честно из пагинации, не дефолт), `truncated` (неполон ли
  именно raw), `display_truncated` (обрезан ли только показ для чата),
  `warnings`. Пример: `03_keywords_list.json`, `07_ads_list_morning.json`;
- `manifest.json` — порядок файлов и их sha256 (сборка только по манифесту,
  не по glob);
- `describe_<action>.json` — схема ответа (один раз на действие).

Пример вызова: `run_read({"name": "keywords_list", "params":
{"account": "client-a", "campaign_ids": [900000036],
"dump_dir": "C:/work/dump-session", "dump_tag": "morning"}})`.
Основной потребитель — скилл `yandex-direct-campaign-dump-directai`:
он вызывает чтения, собирает `dump.json`, проверяет полноту валидатором
и строит Markdown/Excel. Вручную данные не пересказываются.

Связанные правила чтения:

- `ads_list`, параметр `states`: по умолчанию архивные не возвращаются;
  `states: ["ARCHIVED"]` (или вместе с `ON`/`OFF`/`SUSPENDED`) включает их.
- Фразы — целиком по умолчанию (включая внутрифразные минус-слова);
  укороченный показ — только явным `short_phrases: true` и только
  для отображения, raw не трогает.

### Прогноз ставок и спроса (v1.9.0, только чтение)

- `keyword_bids_forecast` — по уже добавленным фразам (`KeywordBids.get`:
  `AuctionBids` → объём трафика/ставка/цена, `Coverage` для сетей):
  ровно один scope (`campaign_id` | `adgroup_ids` | `keyword_ids`),
  ровно один кабинет; таблица «объём → ставка → цена» + медианы цены
  для объёмов 100 и 15. Пример: `run_read({"name":
  "keyword_bids_forecast", "params": {"account": "client-a",
  "keyword_ids": [900000011], "include_network": false}})`.
- `phrases_forecast` — по новым фразам до добавления (Live v4
  `CreateNewForecast` → ожидание → `GetForecast` → `DeleteForecastReport`):
  не более 100 фраз за отчёт, `region_ids[]` обязателен, `currency`
  (по умолчанию RUB). Пример: `run_read({"name": "phrases_forecast",
  "params": {"account": "client-a", "phrases": ["окна пвх"],
  "region_ids": [213]}})`.
- Ограничения: ставки не меняются; на автостратегиях/ЕПК данные
  показываются с пометкой «ставками управляет стратегия, прогноз
  справочный», при отсутствии — «нет данных аукциона» (не ошибка);
  `AuctionBids=null` при RARELY_SERVED, только графических объявлениях
  в группе и всегда для автотаргетинга (показывается отдельно);
  прогноз для новых фраз: не более 5 отчётов одновременно (ошибка 31),
  хранение 5 часов, готовность до ~60 с (таймаут — `forecast_id`
  для повтора); период API прогноза не поддерживает.
- Проверено живьём (10.2026): при поиске SERVING_OFF API всё равно отдаёт
  `AuctionBids` — показываются справочно с пометкой про отключение поиска;
  позиции прогноза — P11..P24, CTR — числом (знак % добавляет рендер).

### Ретаргетинг и аудитории (v1.10.0)

- Чтение всегда доступно: `retargeting_lists_list` — условия кабинета
  (`«выполнили всё ... И НЕ выполнили ничего ...»`, Scope, где используются);
  `audience_targets_list` — привязки к группам (условие, состояние,
  ставка/приоритет). Пример: `run_read({"name": "retargeting_lists_list",
  "params": {"account": "client-a"}})`.
- Правила (A8): в ЕПК/текстово-графических группах — условия `RETARGETING`
  (цели/сегменты Метрики, сегменты Аудиторий); `AUDIENCE` — для медийных
  групп (краткосрочные интересы допустимы и в ТГО); совместимость привязки
  проверяется живьём по `AvailableForTargetsInAdGroupTypes` условия
  (ЕПК-группы API v5 видит как `TEXT_AD_GROUP`).
  На поиске условие сужает аудиторию (AND с фразами), в сетях — расширяет
  (OR). Исключить аудиторию (например, купивших) — только корректировкой
  ставки −100% (`bid_modifiers_set`, вид RETARGETING): «показы этой аудитории
  будут полностью отключены»; в конверсионных стратегиях это меняет целевую
  CPA/ДРР. Условие только из NONE-правил — только для корректировок
  (привязать к группе нельзя).
- Запись выключена по умолчанию: `[retargeting] write_enabled = true`
  в `accounts.toml` (аналог `[audience]`). Примеры:
  посетители сайта за 30 дней без заказа — `retargeting_list_create`
  (ALL-правило «цель визита», NONE-правило «цель заказа»);
  исключить купивших — `bid_modifiers_set` с `kind: RETARGETING`,
  `bid_modifier: 0` на условие купивших.
- Лимиты API: 2000 условий на пользователя, 1000 за вызов; 1–50 правил,
  1–250 аргументов; срок членства 1–540 дней (для целей Метрики);
  не более 50 привязок в ТГО-группе; ставка привязки — ручная стратегия
  (при авто — только приоритет, ставка игнорируется с предупреждением).
- Баллы: `KeywordBids.get` — 15 + 3 за каждые 2000 фраз (оценка в ответе,
  факт — в строке `API:`; при 152 — понятная ошибка с остатком);
  Live-прогноз — без Units (баллы не расходуются). Учёт баллов уже есть
  (`Units` из заголовков, `net_summary`) — переиспользован.
- Каждый ответ помечен «прогноз Яндекса, не гарантия» с датой, регионами
  и валютой (НДС — как отдаёт API, без пересчёта). В dump поля аукциона
  не добавляются. Подсказка также в описании `keywords_add`.

Запись (25, все — только через план, см. §5):

| Действие | Что делает |
|---|---|
| `campaigns_create`, `campaigns_update`, `campaigns_state` | Создание (по умолчанию ЕПК), изменение (в т. ч. ключевые цели), остановка/архив кампаний |
| `adgroups_create`, `adgroups_update` | Создание и изменение групп (тип группы — из типа кампании) |
| `ads_create`, `ads_update`, `ads_state` | Создание (для ЕПК — RESPONSIVE_AD), изменение, состояние объявлений |
| `keywords_add`, `keywords_update`, `keywords_state` | Фразы: пакетное добавление, тексты, состояние |
| `negatives_set` | Минус-фразы кампании/групп и общие наборы |
| `extensions_create` | Ссылки, уточнения, изображения |
| `bids_set` | Ставки фраз (поиск и сети) |
| `bid_modifiers_set` | Корректировки: добавить, изменить, удалить (включая RETARGETING для аудиторий) |
| `metrika_goal_create`, `metrika_goal_update`, `metrika_goal_delete` | Цели счётчика Метрики: создать, изменить, удалить (нужен токен с правом `metrika:write`, см. §5.3) |
| `retargeting_list_create`, `retargeting_list_update`, `retargeting_list_delete` | Условия ретаргетинга: создание, изменение, удаление неиспользуемых (только при `[retargeting] write_enabled=true`) |
| `audience_target_add`, `audience_target_state` | Привязка условий к группам, пауза/возобновление/удаление привязок (только при `[retargeting] write_enabled=true`) |

Запись в Аудитории (экспериментально, выключена по умолчанию
`[audience] write_enabled=false`): `audience_segment_from_file` — создание
сегмента uploading из локального CSV/TXT (phone/email, в API только SHA256-хеши;
имя только `[TEST DirectAI]*`, файл с несколькими колонками без `id_column`
отклоняется) и `audience_segment_delete` — удаление сегмента только
`[TEST DirectAI]*` по живому имени из API. Путь тот же: `plan_write` → ваше
согласие → `apply_write`; без включённого `write_enabled` оба действия
отклоняются до API.

Запись ретаргетинга (v1.10.0, выключена по умолчанию
`[retargeting] write_enabled=false`): `retargeting_list_create` /
`retargeting_list_update` / `retargeting_list_delete` — условия
(цели Метрики, сегменты; удаление — только неиспользуемых, без префикса
`[TEST DirectAI]` нужно явное согласие) и `audience_target_add` /
`audience_target_state` — привязка к группам и её состояние.
Исключение аудитории — только корректировкой −100% (`bid_modifiers_set`,
вид RETARGETING), не условием. Путь тот же: `plan_write` → ваше
согласие → `apply_write`; без включённого `write_enabled` все пять
действий отклоняются до API. Подробности — раздел «Ретаргетинг и аудитории» ниже.

## 5. Как работает запись

1. ИИ вызывает `plan_write` — сервер показывает предпросмотр «было → станет»
   и предупреждения (например, ставка меняется больше чем в 2 раза).
2. Вы читаете предпросмотр и явно разрешаете.
3. ИИ вызывает `apply_write` (с `acknowledge_warnings=true`, если были
   предупреждения) — сервер выполняет, затем **повторно читает объект
   (read-back)** и пишет всё в журнал.
4. Итог: `applied` (подтверждено), `partial` (часть строк отклонена API),
   `failed`, `unverified` (результат неясен — проверить вручную).

Журнал: инструмент `get_operation_log` (последние операции) и файл
`journal.sqlite`. Планы живут в каталоге `plans\` — общем для всех процессов
сервера: план, созданный в одном процессе, применяется из любого другого
ровно один раз (повтор — «уже применён», истёкший — «просрочен»,
неизвестный id — «не найден»). Прямых записей в обход плана не бывает. Что можно где:
бюджеты и смена стратегии запрещены везде (к ключевым целям относится
изменение их набора и ценностей); в боевых кампаниях разрешены
фразы (добавление, пауза/запуск), объявления (создание, тексты, ссылки),
ссылки/уточнения, регионы групп, минусы и площадки (добавление), ставки
и корректировки; замена целиком (replace), пауза кампаний и объявлений,
удаления — только в тестовых кампаниях `[TEST DirectAI]*`.

## 5.1. Создание кампаний: ЕПК по умолчанию

- `campaigns_create` создаёт `UNIFIED_CAMPAIGN` (ЕПК, запрос на `json/v501`).
  Legacy `TEXT_CAMPAIGN` — только явным `campaign_type="TEXT_CAMPAIGN"`
  с предупреждением «устаревший тип».
- `campaigns_update`: блок стратегии и версия запроса — по типу кампании
  (`UnifiedCampaign`/`v501` для ЕПК).
- `adgroups_create`: тип группы API выводит из кампании; неизвестная
  кампания или тип — отказ до API.
- `ads_create`: для ЕПК используйте `responsive_ads` (`RESPONSIVE_AD`,
  запрос на `v501`); `TEXT_AD` допустим, но API конвертирует его
  (10251) — предупреждение требует подтверждения. Совместимость типа
  группы/кампании проверяется до API. DisplayUrlPath обязателен
  для обоих типов и сверяется в read-back.
- Цепочка создания: кампания → группа → фразы → объявление отдельными
  планами; модерация (`ads_state moderate`) в цепочку не входит и
  заблокирована guard по умолчанию — только отдельным шагом
  с явного решения пользователя.

## 5.2. Ключевые цели (`campaigns_update`: `priority_goals`)

Цели и их ценности (`PriorityGoals`) — вход оптимизации, поэтому меняются
тем же планом, что и стратегия: только в тестовой кампании, а в режиме
`confirm` — после явного «да» на конкретный план.

- Формат: список `[{goal_id, value_rub, is_metrika_source_of_value=false}]`.
  `value_rub` — ценность конверсии в рублях (для «Максимум прибыли» —
  маржа); внутрь уходит в микро-единицах (₽ × 1 000 000). Список целей —
  `metrika_goals_list`; `is_metrika_source_of_value=true` API принимает
  только для стратегий с долей расходов (`AVERAGE_CRR`,
  `PAY_FOR_CONVERSION_CRR`).
- Режим один — **замена набора целиком** (`Operation=SET`): не перечислили
  цель — она пропала. Пустой список без явного `priority_goals_reset=true`
  отклоняется до API; `priority_goals_reset=true` — это `PriorityGoals=null`
  (оптимизация на вовлечённые сессии). Оба параметра вместе нельзя.
- Повторяющийся `goal_id`, `goal_id ≤ 0` и `value_rub ≤ 0` — отказ до API.
- Как в API, ключевые цели нельзя передавать кампании в пакетной стратегии
  (и нельзя одновременно с ключом пакетной стратегии в параметрах): такую
  кампанию сначала отвязывают (`PackageBiddingStrategy=null` + новая
  `BiddingStrategy`) — DirectAI этого пока не делает.
- Предпросмотр плана показывает цели и ценности «было → станет», read-back
  после записи перечитывает `PriorityGoals` и сверяет их с запрошенными.

## 5.3. Цели счётчика Метрики (`metrika_goal_create/update/delete`)

Запись целей — через Management API `POST|PUT|DELETE
/management/v1/counter/{counterId}/goal(s)`. Нужен **отдельный токен
приложения Метрики** с правом `metrika:write` (§7.1): без него запись
отклоняется до обращения к API. Если права нет, API отвечает 403, и сервер
объясняет, как перевыпустить токен — токен в сообщениях, логах и чате не
появляется.

`counter_id` — точный id счётчика, без разбора кампаний.

Типы целей и параметры:

| Тип (`type`) | Условия | Особое |
|---|---|---|
| `action` | `conditions=[{operator, value}]`, `operator` = `exact`/`contain`/`start`/`regexp` | JS-событие; `value` — идентификатор события (`ym(...)`) |
| `url` | `conditions=[…]` (те же операторы + `action`/`regexp_action`/`contain_action` для составных целей) | посещение страниц; несколько условий — «ИЛИ» |
| `email`, `messenger`, `search` | `conditions=[…]` | длина значения до 1024 (`email`) / 16384 |
| `phone` | `conditions=[…]` | `hide_phone_number`; значение до 25 символов |
| `file` | `file_all=true` **или** `file_url=…` | ровно одно из двух |
| `social` | `social_all=true` **или** `social_url=…` | ровно одно из двух |
| `step` | `steps=[{type: action|url, conditions:[…]}]`, 2–5 шагов | составная цель, порядок шагов важен |
| `number` | `depth` (≥ 2) | глубина просмотров |
| `visit_duration` | `duration` (секунды, ≥ 1) | длительность визита |

Общее для всех: `name` (1–255), `default_price` (цена по умолчанию,
не отрицательная), `is_favorite`.

- **Мультицели в Management API нет** — типа `multi` в GoalE не существует
  (мультицель есть только в интерфейсе Метрики). Эквивалент «несколько
  условий через ИЛИ» — несколько `conditions` в одной цели, так и работает
  `type=url`/`action`; отдельная попытка создать `multi` отклоняется с этим
  текстом. Типы `chat` и `payment_system` в DirectAI не заведены.
- **Проверки до записи** (живое чтение, до обращения к API): право на
  счётчик (`GET counter/{id}` → `permission`: `own`/`edit`; `view` — только
  просмотр, запись отклоняется), лимит счётчика — до 200 целей, и **точный
  дубль**: тот же тип + те же условия → отказ с id и именем существующей
  цели (порядок условий и краевые пробелы не считаются различием; порядок
  шагов составной цели — считается).
- `metrika_goal_update` — частичное изменение (имя, условия, цена по
  умолчанию, `is_favorite`, `depth`, `duration`). В API `PUT` заменяет цель
  целиком, поэтому сервер читает живую цель и собирает полное тело: поля,
  которые вы не меняли, сохраняются. Ничего не меняется — отказ до API.
  Тип цели и её шаги не меняются; автоцели (`e_purchase`, `call`, `form`,
  `conditional_call` и др. — их нет в GoalE) не обновляются и удаляются
  только вручную в интерфейсе.
- `metrika_goal_delete` — необратимо: собранная по цели статистика пропадёт
  из отчётов. План всегда помечается «⚠ ОПАСНАЯ ОПЕРАЦИЯ» и применяется
  только с `owner_confirmed=true` (в любом режиме guard) и
  `acknowledge_warnings=true`.
- Read-back после каждой записи: сервер заново читает цели счётчика и
  сверяет тип, условия и имя (id новой цели — из ответа POST). При таймауте
  или обрыве связи статус `unverified`, запись **не повторяется вслепую** —
  решение принимает перечитанный список целей.

## 6. Guard (защита)

Опасные операции — строго внутри кампаний `[TEST DirectAI]*`.
Guard это контролирует: перед каждой записью сверяет
**живое имя кампании** через API.

Как завести тестовую кампанию: создайте в интерфейсе Директа кампанию
с именем, начинающимся на `[TEST DirectAI]` (можно черновик); только в ней
доступны replace, пауза кампаний/объявлений, удаления.

Коротко о правилах:
- бюджеты и смена стратегии — запрещены везде, даже в тестовых; к стратегии
  отнесены и ключевые цели с ценностями (см. §5.2);
- в боевых кампаниях можно: фразы, объявления, ссылки/уточнения, регионы,
  минусы и ставки (см. §5);
- только в тестовых: замены целиком, пауза кампаний/объявлений, удаления.

Блокируется: запись вне разрешённого, переименование кампаний,
модерация, чужие общие объекты, неизвестные действия.

Включён по умолчанию (`[guard] guard=true` в `accounts.toml` плюс дефолт
в коде). Выключение — **только вашим решением**: поставьте `guard = false`
(и убедитесь, что нет переменной `DIRECTAI_TEST_GUARD=1`), после тестов
верните `true`.

#### Режим `confirm` (v1.15.0): не запрет, а подтверждение владельца

```toml
[guard]
guard = true
mode = "confirm"   # по умолчанию "block"
```

В режиме `confirm` политические запреты не блокируют, а превращают план
в **«⚠ ОПАСНАЯ ОПЕРАЦИЯ»** со списком причин:
бюджет (`daily_budget`, `strategy` с `WeeklySpendLimit`), смена стратегии,
изменение ключевых целей и их ценностей (§5.2),
модерация, переименование кампании, создание кампании без префикса,
пауза/запуск/архив кампаний и объявлений, правки вне `[TEST DirectAI]*`,
замены целиком, удаление корректировок, чужие общие объекты.

Такой план применяется только `apply_write(..., owner_confirmed=true)` —
агент ставит флаг **лишь после явного «да» владельца в чате на этот
конкретный план**. Предупреждения по-прежнему требуют отдельно
`acknowledge_warnings=true`. В журнал операция пишется с пометкой
`[ОПАСНАЯ, подтверждено владельцем]`.

Жёсткими остаются и в `confirm`: объект не найден/ошибка API, поля
`read_only` (A1), выключенные Аудитории/ретаргетинг (`write_enabled=false`),
неизвестные действия.

Цели Метрики (§5.3) живут вне Директа, поэтому префикс `[TEST DirectAI]*` к
ним не относится: запись проверяет право на счётчик, отсутствие дубля и
лимит 200 целей (это отказ до API), а удаление цели в любом режиме guard
требует `owner_confirmed=true`.

`campaigns_update` снова принимает `name` (одна кампания за план)
и `daily_budget` (₽, `daily_budget_mode` STANDARD|DISTRIBUTED) — в `block`
они отклоняются до API, в `confirm` — опасная операция.
То же и для ключевых целей (`priority_goals`, `priority_goals_reset`): класс
«стратегии» (§5.2), свойств плана (`plan_id`, TTL 15 минут,
`acknowledge_warnings`, `owner_confirmed`) сервер не ослаблял.

### 6.1 Правило для агентов-клиентов MCP

Текст блокировки guard — это **защита, а не ошибка**.

При блокировке агент:

1. останавливается и сообщает вам: какая операция, какой объект, почему
   заблокирована (режим `confirm`: план «⚠ ОПАСНАЯ ОПЕРАЦИЯ» — показывает
   причины дословно и применяет с `owner_confirmed=true` только после
   вашего явного «да» на этот план);
2. **не ищет и не меняет** конфиг guard (`accounts.toml`, секция `[guard]`,
   переменная `DIRECTAI_TEST_GUARD`) и вообще ничего в `safety/`;
3. **не предлагает обход** защиты;
4. **не переносит** операцию на другую кампанию (в т.ч. тестовую) без вашего
   явного указания.

Снятие ограничения — только ваше ручное решение (см. §6). Ни один инструмент
сервера конфиг guard не пишет и не читает наружу: единственный источник —
`accounts.toml` и переменная окружения.

### 6.2 Сравнение периодов и выбор инструмента

1. Сравнение периодов агент выполняет **только через `stats_compare`**
   (A, B, Δ абс., Δ% одним вызовом). Два вызова `stats_*` с ручной
   арифметикой запрещены — они дают разную точность Δ%.
2. Если вы указали конкретный MCP-сервер или инструмент — агент использует
   **только его** и не подменяет другим.

## 7. Обновление

Перед обновлением: закройте все окна харнесов и остановите фоновый
шлюз Hermes (он держит `directai-mcp.exe` даже при закрытых окнах) —
команды выполняет человек в обычном PowerShell:

```powershell
Get-Process directai-mcp -ErrorAction SilentlyContinue | Stop-Process -Force
hermes -p default gateway stop 2>$null
Get-CimInstance Win32_Process |
  Where-Object { $_.CommandLine -match 'hermes|openchamber|opencode' -and $_.ProcessId -ne $PID } |
  ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
Start-Sleep -Seconds 2
Get-CimInstance Win32_Process |
  Where-Object { $_.Name -eq 'directai-mcp.exe' -or $_.CommandLine -match 'hermes|openchamber|opencode' } |
  Select-Object ProcessId, Name
```

Фильтр по `python.exe … hermes_cli.main … gateway run` не использовать:
Hermes запущен отдельным процессом (direct spawn) и таким фильтром не ловится.
Чужие процессы агент не убивает — команды выполняет человек.

Проверка перед переустановкой (c и d должны быть OK):

```powershell
directai-mcp doctor --preinstall
```

Обновление с бэкапом вне uv tool dir и откатом при ошибке
(без `exit` — он закрывает окно PowerShell):

```powershell
cd $env:USERPROFILE\directai-mcp
git pull
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
$tooldir = uv tool dir
Copy-Item "$tooldir\directai-mcp" "$env:USERPROFILE\directai-mcp-tool-backup-$stamp" -Recurse
uv tool install --force --editable .
uv tool update-shell
if ($LASTEXITCODE -ne 0) {
  Remove-Item "$tooldir\directai-mcp" -Recurse -Force
  Copy-Item "$env:USERPROFILE\directai-mcp-tool-backup-$stamp" "$tooldir\directai-mcp" -Recurse
  Write-Output "ОТКАТ: инструмент восстановлен из бэкапа"
} else {
  directai-mcp check
  directai-mcp probe
  Remove-Item "$env:USERPROFILE\directai-mcp-tool-backup-$stamp" -Recurse -Force
}
```

`init` после обновления можно повторить: существующие конфиги не затрутся,
недостающие (например, новые примеры) докопируются. После обновления
откройте харнесы заново и запустите Hermes (сервер подхватывается при
старте). Никогда не делайте `cd` внутрь каталога установки (`uv tool dir`):
бэкап перед установкой — только вне tool dir (копии внутри tool dir `uv`
считает инструментами и выдаёт `malformed`); бэкап удаляется только при
успехе, при ошибке — откат из бэкапа.

## 7.1. Отдельный токен Метрики (v1.17.1)

Метрика больше не работает на токене Директа: у приложений «для авторизации
пользователей» лимит 3 группы разрешений, поэтому права `metrika:read` и
`metrika:write` живут в отдельном приложении Яндекс OAuth и хранятся в своём
ключе Credential Manager (`directai-mcp-metrika`).

Поведение по умолчанию:

- **чтение** Метрики (`metrika_traffic`, `metrika_goals_list`,
  `metrika_goals_report`, `metrika_bytime`, `metrika_direct_cpa`,
  `counter_check`, снимки журнала) идёт отдельным токеном, если он есть;
- **без отдельного токена** чтение продолжает работать на токене Директа, а в
  ответе появляется примечание «Метрика читается токеном Директа…»;
- **запись целей** (`metrika_goal_create/update/delete`) без отдельного токена
  не начинается: `Ошибка подготовки: запись целей Метрики требует отдельный
  токен Метрики (metrika:write)…` — до обращения к API.

Выпуск токена (шаги выполняет владелец, токен в чат не передаётся):

1. В приложении Метрики включены права **«Яндекс Метрика» → чтение и
   изменение** (`metrika:read` + `metrika:write`), Redirect URI
   `https://oauth.yandex.ru/verification_code` — как у приложения Директа.
2. Откройте в браузере под своим логином (команда сама напечатает ссылку с
   `client_id` приложения Метрики):

   ```powershell
   directai-mcp set-metrika-token --login ВАШ_ЛОГИН
   ```

3. Разрешите доступ, скопируйте токен из адресной строки и вставьте его в
   скрытое поле, которое задаёт команда. Client secret приложения DirectAI
   не знает и не хранит — OAuth-поток проходит в браузере, как для Директа.
4. Проверка: `directai-mcp check` (строка «Метрика: …») и
   `directai-mcp doctor` (проверка `l. Метрика`). В `describe_action` без
   аргументов тоже есть строка «Метрика: отдельный токен / токен Директа».

Что показывают проверки (значение токена не печатается нигде):

- источник токена и его длина;
- `client_id` приложения, выпустившего токен (`login.yandex.ru/info`) —
  так видно, что Метрике достался именно токен приложения Метрики; если
  приложение чужое, `check` и `doctor` об этом предупреждают;
- читается ли список счётчиков;
- право `metrika:write` **не проверяется**: Яндекс не отдаёт scopes токена, а
  выяснить его можно только записью цели. Поэтому в выводе честно сказано,
  что право подтвердит первая запись (при 403 сервер объяснит, как
  перевыпустить токен).

Отозвать токен — на стороне Яндекс ID (правки приложения → «Отозвать
токены»); новый токен выпускается той же командой.

### 7.2. Секреты в логах (v1.17.2)

- Логи HTTP-клиентов (`httpx`, `httpcore`) всегда на уровне **WARNING**:
  на INFO логгер пишет URL запроса целиком, а значит и query-параметры.
  Поднимать их уровень нельзя.
- Дополнительно все обработчики логов чистят значения параметров
  `oauth_token`, `token`, `apikey`, `api_key`, `access_token`,
  `refresh_token` → `***`. Тексты сетевых ошибок Метрики чистятся тоже.
- Токены передаются только заголовками (`Authorization: OAuth` / `Bearer` /
  `Api-Key`) и никогда не попадают в URL, ответы инструментов, журнал
  операций и предпросмотр плана.
- Файл лога: `%USERPROFILE%\.directai\logs\directai.log`. Если секрет туда
  попал (например, старая версия): перевыпустите токен и удалите файл —
  он пересоздаётся при следующем запуске.

```powershell
Remove-Item "$env:USERPROFILE\.directai\logs\directai.log"
```

## 8. Типичные ошибки

| Симптом | Что делать |
|---|---|
| Ошибка 53 (авторизация) | Токен недействителен: `directai-mcp set-token`, затем `check` |
| Ошибка 58 (регистрация приложения) | Завершите заявку на доступ к API в интерфейсе Директа |
| Ошибка 513 (логин не подключён) | Логин не привязан к Директу — проверьте `Client-Login`/аккаунт |
| Не хватает баллов API | Подождите сброса лимита; остаток виден в `check` |
| Харнес не видит сервер | Стабильный путь к exe — `(Get-Command directai-mcp).Source` (обычно `%USERPROFILE%\.local\bin\directai-mcp.exe`); перезапуск харнеса, логи в `.directai\logs` |
| План с предупреждениями не применяется | Это защита: повторите `apply_write` с `acknowledge_warnings=true` только после вашего согласия |
| `token missing for login 'X'` | Токен сохранён под другим логином: выполните `directai-mcp set-token --login <[auth] login>` с логином из `accounts.toml` |
| Вебмастер: «нет права» / «токен не принят» | Нужен отдельный токен: `directai-mcp set-token --webmaster` (приложение «для доступа к API» с правом `webmaster:hostinfo`) |
| Метрика: 403 при записи целей | Не хватает отдельного токена Метрики или в нём нет права `metrika:write`: выпустите токен приложения Метрики — `directai-mcp set-metrika-token --login <ваш логин>` (§7.1). Токен в чат не пишите |
| Метрика: «запись целей Метрики требует отдельный токен» | Тот же текст без обращения к API: запись не начинается, пока не выпущен отдельный токен Метрики (§7.1) |
| Метрика: «у вас доступ только просмотр» | Счётчик открыт гостю с уровнем `view`: запись целей на нём невозможна, нужен уровень `edit` |
| Wordstat: «API key missing» или «folderId не настроен» | Выполните `directai-mcp set-token --wordstat`; API-ключ вводится скрыто, `folderId` хранится в `[wordstat]` |
| `Ignoring malformed tool` | Битая копия/рецепт, не повод сносить рабочий инструмент: закройте все окна харнесов и переустановите с `--force` (бэкап — вне tool dir). `uninstall` — только для заведомо мусорных записей |
| `os error 32` при переустановке | exe занят MCP-клиентами: покажите владельцев (`Get-CimInstance Win32_Process -Filter 'Name="directai-mcp.exe"'`, поле `ParentProcessId`), чужие процессы не убивайте. Шлюз Hermes (`python.exe … hermes_cli.main … gateway run`) работает в фоне и держит exe даже при закрытых окнах — человек останавливает его сам (см. §7: остановка сервера и шлюза), после установки запускает Hermes заново. Висящие `opencode serve` — тоже владельцы: их закрывают штатно, не `kill` |
| Как быстро проверить сервер | `directai-mcp --version` → `check` → `probe` (две строки OK, `stats_summary` найден; баллы не тратятся). Сырые stdio-пробы вручную не делать |

## 8.1. Диагностика (doctor)

При проблеме подключения — сначала doctor (агент — см. AGENTS.md §4.1):

```powershell
directai-mcp doctor
directai-mcp doctor --skip-api     # без сети
directai-mcp doctor --json         # машинный вывод для скилла
directai-mcp doctor --preinstall   # строгая проверка перед переустановкой
```

Одиннадцать проверок по порядку (версия, exe, процессы, блокировка файла,
конфиг, токены, API, Hermes, Аудитории, ретаргетинг, каталог планов) — каждая OK / WARN / FAIL
с причиной и рекомендуемым действием. Код возврата: 0 — всё OK,
1 — есть WARN, 2 — есть FAIL. Токены не печатаются (только есть/нет/длина).
Занятый exe и работающие сессии по умолчанию — INFO, а не тревога;
строго (WARN/FAIL) — только с `--preinstall` перед переустановкой.
Диагностика read-only: ничего не останавливает и не правит, чинит человек
готовым блоком из `skills/directai-connection-doctor/references/playbooks.md`.

Скилл `directai-connection-doctor` (триггеры: «MCP не работает»,
«os error 32», «hermes не видит», коды 513/58/53) лежит в репозитории
(`skills/directai-connection-doctor/`); установка локально — скопировать
папку в `%USERPROFILE%\.agents\skills\directai-connection-doctor`.

## 8.2. Скиллы сценариев (v1.11.0)

- `directai-campaign-audit` (`skills/directai-campaign-audit/`): разбор кампании —
  настройки, `stats_compare` 14 vs 14 (Δ = A−B, Δ% от базы B), срезы, гигиена,
  план улучшений. Только чтение. Триггеры: «разбери кампанию», «почему просела»,
  «что улучшить», ID кампании.
- `directai-campaign-create` (`skills/directai-campaign-create/`): кампания
  из описания или YAML (`references/campaign-template.yaml`) — бриф,
  `phrases_forecast`, структура таблицей → «да», запись через планы, кампания
  остаётся остановленной. Триггеры: «создай кампанию», описание товара/услуги.
- Установка локально — скопировать папку скилла
  в `%USERPROFILE%\.agents\skills\<имя>`. Общие правила обоих скиллов: бюджеты
  не менять без явного «да» владельца (план «ОПАСНАЯ ОПЕРАЦИЯ»), запись только prepare → подтверждение → apply → read-back,
  DisplayUrlPath всегда заполнять.

## 9. Что отложено

Актуальный список — в `BACKLOG.md` (пункты 4–10: правила бизнеса, Вордстат,
упущенный спрос, напоминания, лиды, позиции SERP, VK Ads) и в «Замеченные
хвосты» там же. Устаревший список «что отложено» здесь больше не ведётся.

## 10. Знания Директа (пакет A1–A11 + B2)

Авторство части знаний: см. NOTICE.md (awaik/direct-mcp-ai-project, MIT).

- A1: `ENABLE_AREA_OF_INTEREST_TARGETING` отменено 31.08.2026 — только чтение
  (`campaigns_get` + `campaign_setting_notices`); запись отклоняется.
  Поля из `notices` не писать никогда.
- A2: Директ сам добавляет минус-слова в пересекающиеся фразы группы
  (`keywords_list`); автоминус не считать ошибкой.
- A3: операторы минус-фраз — см. раздел «Минус-фразы» ниже.
- A4: корректировки — разные категории перемножаются, внутри категории
  наибольшая, −100% низший приоритет, групповая перекрывает кампанию;
  в конверсионных — влияет на CPA/ДРР (`bid_modifiers_set`).
- A5: GoalId 12 = вовлечённые сессии, 13 = все приоритетные цели (служебные).
- A6: атрибуция — Метрика с 25.06.2026 cross-device, у Директа свои enum;
  каждый `stats_*` показывает `attribution {requested, effective, source}`.
- A7: `WB_MAXIMUM_CLICKS` требует `WeeklySpendLimit`; `AVERAGE_CPC` отдельная
  стратегия с `AverageCpc` (`strategies_get`).
- A8: ЕПК/текстово-графические — `RETARGETING` с goal_id; `AUDIENCE` только
  медийные; поиск AND, сети OR (`audiences_list`).
- A9: макросы трекинга (`campaigns_update`/`adgroups_update`, TrackingParams).
- A10: Турбо-блоки, `clients.site`, CPM-видео — только интерфейс.
- A11: интенты — 5 классов; цену/отзывы/гео не минусовать автоматически.

### Минус-фразы

- `"..."` — запрос только из этих слов; `[]` — порядок; `!` — словоформа;
  `+` — обязательность; полное пересечение минуса с ключом отменяет минус.
- Проверка конфликтов — в `dump_to_xlsx.py` (функция `neg_match`), тесты
  на вымышленных фразах.

### Атрибуция

| Система | Модели |
|---|---|
| Директ | FCCD, LC, LSCCD, AUTO (прямого соответствия Метрике нет) |
| Метрика (legacy → cross-device с 25.06.2026) | lastsign → cross_device_last_significant и др. |

Фактическая модель Reports API отдельно не возвращает: в `effective`
подставляется запрошенная модель (`effective_attribution`), `source` —
откуда взялась (`api` — явно в параметрах, `config` — дефолт accounts.toml).
`effective=null`, `source="not_reported"` — только если модели действительно
нет. Без целей Reports игнорирует AttributionModels (фактически LC) —
это помечается в ответе отдельно.

## 11. Статусы поиска (B1, v1.6.0)

Каждый ответ `campaigns_get`/`campaigns_list` несёт строку
`Статус поиска: <lookup_status>, presence=..., proves_account_empty=...`
и то же в dump-конверте/manifest (`lookup_status`).

| lookup_status | Когда | presence |
|---|---|---|
| `resolved` | объект найден в Campaigns API | `configured` |
| `resolved` | в Campaigns API нет, в Reports есть данные (архив/удалена/чужой доступ) | `statistics_only` |
| `not_observed` | нет ни в API, ни в Reports за проверенный период (период указан в message). Не утверждается, что кампании не существует | `null` |
| `ambiguous` | поиск по имени/подстроке дал >1 совпадения; возвращаются кандидаты (id, name, state) | `null` |
| `incomplete` | ответ частичный (пагинация/лимит/ошибка части запросов); указано, что не проверено | `null` |
| `failed` | ошибка API/сети; код ошибки Директа, без трактовки как «пусто» | `null` |

Проверка Reports для `statistics_only` — только когда Campaigns API вернул
пусто по явному ID; один лёгкий отчёт (`CAMPAIGN_PERFORMANCE_REPORT`,
`CampaignId`, `Impressions`/`Clicks`, период по умолчанию 90 дней,
параметр `lookup_days` переопределяет). Пустой `campaigns_list` —
`proves_account_empty=false` + причины (фильтр, права, логин):
пусто ≠ объекта нет. Запись разрешена только при `resolved+configured`
(guard отклоняет остальное до API).

## 12. Основная цель (B3, v1.6.0)

`accounts.toml`: необязательное поле кабинета `primary_conversion_goal_id`
(вымышленный пример: `900000123`) и переопределение по кампании
`[aliases.<имя>.campaigns.<campaign_id>] primary_conversion_goal_id`
(также `[accounts.<имя>.campaigns.<id>]`, пример: `900000456`).
Приоритет: явный параметр запроса `primary_goal` > кампания > кабинет > нет.
Валидация: целое > 0; служебные `12`/`13` допустимы, но `check` предупреждает
с расшифровкой (вовлечённые сессии / все приоритетные цели); сверка с целями
Метрики — best-effort, отсутствие доступа — предупреждение, не ошибка.
`stats_*`/`stats_compare`: блок `Цель: id=..., label=..., source=param|campaign|account|none`
рядом с атрибуцией; CPA/CR — по этой цели; при `source=none` — как в v1.5.0
+ warning «основная цель не задана, CPA по всем целям».
Правило для агентов: перед оптимизацией читать журнал кампании
(`campaign_journal`) и считать CPA по основной цели.

## 13. Журнал кампании (v1.13.0)

Один Markdown-файл на кампанию: что меняли, почему и что стало с результатами
(`<reports_dir>/journals/<login>/<campaign_id>.md`, перезаписывается при каждом
`campaign_journal`; источник правды — `journal.sqlite`). Привязка операций —
таблица `operation_campaigns` (схему `operations` не меняли; старые записи
привязаны backfill при первом `connect`). Снимки результатов —
`campaign_snapshots` (`direct`: показы/клики/расход/CTR/CPC/конверсии из
`stats_compare`-логики; `metrika`: визиты/отказы/цели/CPA из
`metrika_direct_cpa`-логики; цель по умолчанию — основная; будущие даты
отклоняются до API, как в v1.12.1). Заметки — `campaign_notes`
(`hypothesis|decision|observation|todo`).

Инструменты (все read; заметки и снимки пишут только локально, без write API
Директа и без планов): `campaign_journal` (сборка + файл),
`campaign_journal_snapshot`, `campaign_journal_note`, фильтр
`get_operation_log(campaign_id=...)`. Δ в таблице снимков: Δ = A−B, Δ% от B.

TDQS

B3.1/5.0

Scored across 7 tools

Disambiguation5/5

Each tool maps to a distinct stage or resource: account listing, catalog search, action introspection, read execution, write planning, write application, and logging. The plan/apply pair is complementary rather than ambiguous, and read/execute vs. catalog search are clearly separated.

Naming Consistency5/5

All tool names follow a consistent lowercase snake_case verb-first pattern: list_, search_, describe_, run_, plan_, apply_, get_. The naming style is uniform and predictable across the entire set.

Tool Count5/5

Seven tools is well within the ideal range and each tool earns its place in the workflow. The count matches the server's apparent scope: account discovery, action inspection, read execution, and a two-phase write flow.

Completeness4/5

The toolset covers the main lifecycle well: discover accounts, search and describe actions, run reads, plan writes, apply them, and review the operation log. Minor gaps exist, such as no explicit cancel-plan operation or fetching a single log entry by ID, but agents can work around these.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive