MCP-first, CLI и skills: решение для 1.11
Дата: 2026-10-01. Статус: исследование для задачи mcp-first-rule-versus-skills-over-cli; это не изменение правила и не утверждение экономии.
Вопрос
Есть внешняя гипотеза «skills over CLI»: агенту достаточно навыка, который запускает локальную команду. Она не доказывает, что MCP дороже или хуже для TAUSIK. Проверяем одинаковую операцию на трёх разных слоях:
- Skill — текстовый алгоритм и выбор следующего действия.
- MCP или CLI — транспорт вызова.
- ProjectService — реализация правила и запись в БД.
Смешение этих слоёв дало бы ложную дилемму: skill не заменяет реализацию операции, а MCP и CLI не обязаны иметь две реализации.
Что подтверждено в коде и замерах
| Наблюдение | Доказательство | Следствие |
|---|---|---|
CLI создаёт ProjectService через service_factory.get_service(), а MCP — тот же ProjectService поверх SQLiteBackend. | scripts/service_factory.py; harness/claude/mcp/project/server.py::_get_service. | Для обычной операции бизнес-правило и БД одни; две оболочки не требуют двух реализаций. |
MCP-обработчики вызывают методы svc.task_*; CLI cmd_task вызывает те же svc.task_*. | handlers_task.py; project_cli_task.py. | Исправление правила должно жить в service-слое; транспортные отличия надо тестировать на границе. |
| MCP объявляет схему аргументов и до вызова отклоняет неизвестные аргументы. | tools.py; server.py::reject_unknown_arguments. | Для агента это структурированный вызов без shell-цитирования и без молча потерянного поля. |
Windows cmd.exe разбирает >, <, &, ` | до.cmd`-обёртки. В прежнем замере 5 из 9 враждебных аргументов искажались, 2 — молча. | docs/ru/cli.md. |
| MCP-процесс может исполнять старый импортированный код после правки дерева; CLI запускает код с диска заново. | docs/ru/troubleshooting.md; tausik_self_check. | При drift_detected, sibling process или зависании CLI — оправданный временный маршрут, пока IDE перезапускается. |
В этой Codex-смене 10 вызовов task_show через MCP завершились 10/10: медиана 39 мс (35–50), сериализованный результат 5 495 символов. Десять fresh CLI вызовов завершились 10/10: медиана 439 мс (410–463), output 410 символов. | Живой равный прогон текущей смены, 2026-10-01. | Это доказательство process/transport latency, а не качества или токенов: MCP в этом замере был stale и возвращал full payload, свежий CLI — текущий compact output. Payloads несопоставимы. |
| Исторический замер не доказывает превосходство одного транспорта: из 1 530 CLI-вызовов с MCP-двойником 1 216 (79,5%) всё равно пошли через CLI; MCP составлял 29,1% всех framework-вызовов. | scripts/route_map.py, docs/ru/doctor.md, сессия #233. | Это сигнал о несоблюдении/неудобстве прежнего правила, но не токенный бенчмарк и не причина переворачивать правило. 20,5% CLI-вызовов не имеют MCP-двойника; цепочка и многострочный ввод также меняют выбор. |
| Codex-журнал даёт нативные записи ответов и токенов, а не разрез «токены на MCP против CLI». Первый снимок: 98 ответов, 11 815 495 input, 79 184 output; 1 054 чужих или неатрибутированных ответа исключены. | docs/ru/codex-economy-baseline.md; scripts/usage_codex.py. | Сейчас нельзя честно назвать разницу токенов, числа модельных ответов или retry-rate MCP/CLI на одном и том же случае. |
Kilo определяет выбранный GLM из KILO_MODEL/конфига, но не предоставляет здесь нативный журнал, аналогичный Codex. | scripts/providers/kilo.py. | Живой GLM-замер транспорта, число ответов и расход — unknown, пока release acceptance не даст внешнюю запись. |
У Codex в наблюдённом turn_context нет схем инструментов и нет признака tools_deferred. | docs/ru/context-economy.md; scripts/context_block_audit.py. | Нельзя приписывать MCP ни стоимость всех 147 схем на каждом ходу, ни экономию от их якобы отложенной загрузки. Статус схем для этого хоста — unknown. |
Отдельная проверка общего результата уже существует: тест tests/test_usage_codex.py::test_cli_and_mcp_share_native_report подтверждает, что метрики Codex через CLI и MCP используют один и тот же отчёт. Это полезная проверка отсутствия расхождения результата, но не latency- или token-бенчмарк.
Сравнение путей на обязательных хостах
| Критерий | MCP | CLI через skill | Вывод для Codex / Kilo GLM |
|---|---|---|---|
| Поиск действия | list_tools отдаёт объявленные инструменты; область задачи и tiers могут сузить surface. | Агент должен знать команду из skill/документации и разобрать --help. | MCP удобнее для атомарной агентской операции. Фактический объём схем, вводимый Codex/Kilo в контекст, неизвестен. |
| Аргументы | Объект по схеме; неизвестные ключи отклоняются. | Shell и parser; на Windows действует guard, но он обнаруживает повреждение после поведения cmd.exe. | MCP предпочтителен для сложного/многострочного текста и записи доказательств. |
| Реализация и гарантии | ProjectService и service-level QG. | Тот же ProjectService и те же QG. | Качество закрытия не должно зависеть от выбора оболочки. |
| Свежесть | Долгоживущий server может стать stale; есть tausik_self_check. | Новый процесс читает текущий код. | После изменения MCP-кода или зависания: диагностировать, перезапустить IDE; CLI допустим как временный обход. |
| Несколько шагов | Внутри одного outer tool round Codex может batch-ить несколько MCP-вызовов. Некоторые цепочки всё же не выражены одним MCP tool. | Внутри того же outer tool round можно batch-ить CLI-команды; одна shell-цепочка может скрыть промежуточную ошибку, если написана небрежно. | Сам transport не определяет число model responses. В этой длинной смене журнал содержит 491 exec вызов, 294 с TAUSIK/project-командами, из них 120 отвечают консервативной compound/batch-эвристике. Это описательная статистика, не matched-case savings. Compound MCP добавлять только когда один бизнес-результат атомарен. |
| Retries | Повторять только идемпотентный отказ после причины; сервер сериализует вызовы на общем соединении. | Те же правила повторов, но возможны shell/цитирование/exit-code ошибки. | Нет сравнимого live retry-rate. Любой будущий замер обязан назвать операции и причины повторов. |
| Число модельных ответов и токены | Нет текущей привязки ответа к транспорту. | Нет текущей привязки ответа к транспорту. | Unknown для Codex и GLM. Метрика — точные response ID, input/output, retries и приемка на паре одинаковых случаев. |
Третий вариант: одна реализация, две тонкие оболочки
Это уже базовая архитектура TAUSIK и её надо закрепить как правило разработки 1.11:
skill (алгоритм) ─┬─ MCP schema/handler ─┐
└─ CLI parser/handler ─┼─ ProjectService ─ SQLite
└─ единые QG и результатТонкая оболочка имеет право только разобрать/проверить свой транспортный ввод, вызвать service и отрендерить ответ. Нельзя переносить QG, состояние или побочный эффект в одну оболочку без того же пути у второй. Исключение должно быть названо как CLI-only operator/maintenance действие, а не маскироваться под «MCP-first».
Новый compound MCP вызов оправдан только если он заменяет несколько вызовов, которые вместе образуют один атомарный результат (пример: session_open). Он не является поводом объединять независимые решения, скрывать промежуточный отказ или делать отдельный service-путь.
Рекомендация для 1.11
Сохранить MCP-first для атомарных агентских операций, но уточнить его операционно: skill определяет порядок, MCP — предпочтительный транспорт при доступном свежем сервере, CLI — равноправный fallback и путь для CLI-only/ локальных операций. Это не «skills over CLI»: skill не выбирает другую реализацию.
- Оставить общую реализацию и две тонкие оболочки; новые QG и task-state сначала появляются в
ProjectService. - В skills сначала называть MCP-вызов, затем коротко указывать CLI fallback. Для
mode=packageи прочих bounded reads не загружать full output без причины. - Когда
tausik_self_checkвидит stale runtime либо MCP-вызов зависает, не ретраить бесконечно: зафиксировать причину, перезапустить IDE; до этого использовать CLI той же операции. - Не менять правило на CLI-first и не заявлять токенную экономию до парного замера: один task case, одинаковый prompt/model/effort/tool catalogue, точные response ID, результат приемки, число retries и MCP/CLI transport. Для GLM сначала нужен честный источник таких записей.
Решение и отклонённые альтернативы
Решение: до отдельной записи владельца сохранить MCP-first в уточнённой форме выше и принять «one implementation + two thin wrappers» как критерий 1.11. Оно соответствует текущему service-слою, не ухудшает Windows-путь и оставляет практический выход из stale MCP.
Отклонено: CLI-first / skills-over-CLI как общее правило. Единственный внутренний процент (79,5%) измеряет привычку маршрута, а не качество, токены или успех; он включает операции без MCP-двойника. Кроме того, есть измеренная цена Windows-цитирования.
Отклонено: MCP-only. У CLI есть законные CLI-only действия и важная роль при stale server. Принудительное MCP-only превратило бы диагностируемую деградацию в блокировку работы.
Не решено измерением: сравнение latency, токенов, tool-schema injection, количества model responses и retry-rate между MCP и CLI на Codex; все те же значения для Kilo/GLM. Эти unknown не надо закрывать догадкой и не надо использовать как доказательство экономии.
Минимальный следующий замер
Для каждого из Codex и Kilo/GLM — один простой и один средний case, максимум одна попытка на транспорт. На паре сохраняются: хост, модель, effort, prompt, каталог инструментов/его статус unknown, transport, response IDs, input, cached input, output, reasoning output, wall time, retries с причиной и результат тех же acceptance checks. Сравнивать можно только пару с одинаковой приёмкой; расхождение модели, неизвестная атрибуция или другая задача оставляет вердикт inconclusive.