Что такое Crossweft и какую проблему он решает
Crossweft — открытый плагин для Claude Code и Codex, который не даёт ИИ-агенту сказать «готово», пока все связанные части программы не синхронизируются. Для остальных агентов тот же механизм доступен как MCP-сервер. Инструмент создала разработчица программы для ретуши и плагина для Photoshop с локальной нейросетью: к моменту появления Crossweft она потратила на подписки для агентов больше $9 000 и, по собственной оценке, больше миллиарда токенов (разбор истории на Habr).
Проблема, из которой всё выросло, знакома каждому, кто гоняет агента по большому проекту. Внутри одного языка агент работает прилично: переименовал функцию, поправил тип, прогнал тесты. На границе между компонентами ломается тихо. Агент меняет имя службы в одном месте, забывает про второе, сборка и тесты проходят, а на чистой машине продукт не ставится.
Автор называет такие точки «швами». Название инструмента рифмуется с самой проблемой: weft — уток, поперечная нить в ткани, она проходит через все продольные и держит полотно вместе.
Контекст важен: агенты в разработке давно вышли за рамки «напиши функцию». Один разработчик превратил пет-проект на Java в оркестратор задач с git worktree, CLI-сессиями Claude Code и веб-дашбордом. Чем больше автономии у агента, тем дороже ошибка на стыке компонентов.
Почему компилятор не видит «швы» между компонентами
«Шов» — это точка, где разные компоненты должны точно совпадать, но ни один статический инструмент этого не проверяет. Стороны написаны на разных языках, поэтому компилятор не видит ни одного из них (описание швов у автора инструмента).
- маршрут, который вызывает клиент, и тот же маршрут, который регистрирует сервер;
- заголовок с версией протокола;
- поля DTO в Go и TypeScript;
- переменные окружения, которые читает сервис, и те же переменные в .env.example;
- правило округления цены, реализованное на двух языках.
Типы, тесты и линтеры хорошо работают внутри одного языка. Договорённости между компонентами обычно не проверяют, и они держатся на памяти разработчиков. Пока помнят — работает. Забыли — работает до первого пользователя с чистой установкой.
Масштаб виден на структуре самого проекта: продукт автора состоит из четырёх частей (клиент, системная служба, бэкенд, установщики), написанных на C++ и Go, живущих в разных процессах и ставящихся разными установщиками. У каждой границы свой набор совпадений, который нужно держать в актуальном состоянии.
Пример: один идентификатор — три копии
Имя службы определяли в трёх почти одинаковых функциях. На чистой машине служба ещё не была установлена, поиск заканчивался ошибкой, и пустая машина выглядела как старая несовместимая установка. Установщик останавливался с кодом 76. Автор исправила одну копию, две другие остались сломанными, потому что ни компилятор, ни тесты не связывали три функции между собой.
Такой баг не ловят юнит-тесты: они проверяют функцию, а не согласованность трёх её копий. Не ловит его и интеграционный тест, если сценарий не воспроизводит отсутствие установленной службы.
Как работает Crossweft: связи, сторожа и хуки
Crossweft описывает связи между блоками в JSON, привязывает утверждения к литералам в коде и требует, чтобы у каждой рукописной договорённости был сторож, читающий обе стороны. На проекте автора 54 связи на границах компонентов держат 188 сравнений значений (468 мест в коде) и 105 сравнений множеств (цифры из описания инструмента).
Цифры показывают главное: один шов почти никогда не равен одной строке. Один маршрут тянет десяток сверок — путь, метод, схему тела, имя поля, тип, значение по умолчанию.
Сторожа join, set и pair: в чём разница
- join сравнивает конкретные значения. Пример — имя службы, которое должно совпасть в клиенте, установщике и самой службе.
- set сравнивает множества. Пример — список переменных окружения: одинаковый набор в коде и в .env.example, без лишних и без пропущенных.
- pair сравнивает хэши дублированной логики. Пример — правило округления цены, реализованное и на C++, и на Go: обе версии должны давать одинаковый результат.
pair закрывает самый неприятный случай: логика продублирована на двух языках, и свести её к общему модулю нельзя. Хэш фиксирует, что реализации не разъехались, а расхождение вылезает как красная проверка, а не как баг в проде через месяц.
Как хуки останавливают агента
После того как агент считает задачу выполненной, срабатывает хук и запускает проверки. Если хотя бы один сторож красный, агент не может завершить работу и вынужден искать и править рассинхрон. Механизм встроен в плагины для Claude Code и Codex, для остальных агентов работает MCP-сервер. Именно хук превращает набор проверок в принуждение: без него агент просто сообщил бы «готово» и пошёл дальше.
MCP-серверы для работы с кодом уже не редкость. repopedia, например, строит граф кода локально в SQLite через tree-sitter и отдаёт агенту оценку blast radius. Crossweft решает другую задачу: он сверяет договорённости между компонентами, а не ищет нужный фрагмент.
Кому подходит Crossweft и какие у него ограничения
Инструмент рассчитан на мультиязычные проекты из нескольких компонентов, которые пишутся и правятся с помощью ИИ-агентов. Чем больше «швов» и чем меньше они покрыты тестами, тем выше польза. Автор применяет Crossweft на своём продукте с четырьмя компонентами на C++ и Go.
- Нужна начальная настройка: связи между компонентами придётся описать в JSON, и это ручная работа.
- Crossweft закрывает только те швы, которые вы явно описали. Нет описания — нет проверки.
- Нестандартные проверки потребуют собственных плагинов.
- Типы, линтеры и юнит-тесты внутри одного языка он не заменяет.
- Apache-2.0 даёт свободу использования, но не гарантию, что инструмент подойдёт под вашу архитектуру.
Ещё один честный момент: детали реализации сторожей, хуков и MCP-сервера автор раскрывает в анонсе кратко, поэтому перед внедрением стоит свериться с репозиторием и текущей документацией, а не только с описанием задачи.
Когда Crossweft не нужен
Если проект состоит из одного компонента на одном языке, компилятор и система типов уже закрывают почти все связи. Избыточен Crossweft и там, где межкомпонентные договорённости давно покрыты интеграционными тестами или контрактами: новый слой проверок будет дублировать то, что и так ловит CI. Добавлять его стоит, если есть швы, которые агенты реально ломают.
Как начать использовать Crossweft
- Установить плагин для Claude Code или Codex. Для остальных агентов развернуть MCP-сервер.
- Описать связи между компонентами в JSON.
- Привязать утверждения к литералам в коде.
- Настроить сторожей join, set и pair для каждой рукописной договорённости.
- Проверить, что хуки активированы и действительно блокируют завершение задачи.
- Написать собственные плагины для нестандартных проверок, если трёх стандартных видов сторожей не хватает.
Начинать логично с одного шва, который уже ломался в проде. Такой шов вы опишете правильно с первой попытки и сразу увидите, сколько сверок он на самом деле требует.
Работа с агентом упирается ещё и в постановку задачи. Голосовая транскрипция, обязательные тесты и обсуждение архитектуры до кода меняют результат сильнее, чем формулировки промпта: агенту проще не ломать договорённость, о которой он знает заранее.
Чем Crossweft отличается от других подходов
Контрактное тестирование, например Pact, проверяет взаимодействие между сервисами во время выполнения. Оно требует запустить обе стороны, поднять моки и поддерживать сами контракты. Crossweft работает иначе: сверяет литералы и хэши без запуска и делает это в тот момент, когда агент собирается закончить работу.
Интеграционные тесты поймают рассинхрон, если они есть и если покрывают конкретный шов. Проблема в том, что швы редко попадают в покрытие: маршрут из примера выше проверяется только на машине без установленной службы, а такой сценарий в наборе тестов есть не всегда.
Линтеры и статические анализаторы видят один файл, один язык, один процесс. Межъязыковую договорённость они не видят по определению.
Crossweft требует сторожа для каждой рукописной договорённости и не даёт агенту закрыть задачу, пока проверка красная. Это дополнительный слой контроля поверх тестов и линтеров, а не их замена. Практическая ценность появляется там, где несколько компонентов на разных языках собирает ИИ-агент, а все совпадения между ними в голове никто не держит.