Архив переписки с AI-агентом хранит разговор о проекте, а не итоговые решения. На этом расхождении строится критика подхода, при котором контекст разработки живёт в истории чатов: в переписке остаются варианты, отброшенные гипотезы и сообщения, противоречащие друг другу, а контрактов, границ модулей и критериев приёмки, которые можно сверить с кодом, там нет. Автор статьи на Хабре разбирает эту проблему и предлагает держать контекст в репозитории.
Ключевой тезис: восстановленная история остаётся текстом, который новый агент обязан прочитать и заново интерпретировать. Проверить интерпретацию нечем, потому что нет объекта сверки. Агент может уверенно пересказать решение, отменённое через двадцать сообщений, и начать править код по устаревшему плану.
Альтернатива из статьи: методика GRACE (лицензия MIT, автор osovv), где замысел, границы модулей и проверки лежат рядом с кодом, плюс надстройка doubled-graph со сценарием миграции, графом вызовов через CodeGraphContext и MCP-обёрткой. Ниже механика, пример разметки и трезвая оценка ограничений.
Почему контекст в чате не решает проблему
Разговор и решение: это не одно и то же
В переписке перемешаны два типа артефактов. Первый - обсуждение: гипотезы, отброшенные варианты, уточняющие вопросы, спор о том, как лучше назвать функцию. Второй - итоговые решения: контракт функции, границы модуля, критерий приёмки. Чат хранит первое. Второе либо теряется, либо остаётся абзацем текста, который нельзя сопоставить с конкретным файлом.
Восстановленная история остаётся текстом, который новый агент обязан прочитать и заново интерпретировать. Проверить эту интерпретацию нечем: в переписке нет ни контрактов, ни границ модулей, ни критериев приёмки, которые можно сверить с кодом.
Разница практическая. Контракт функции можно проверить линтером и сверкой с реальными экспортами: совпадает или нет. Пересказ того же контракта в чате проверяется только повторным чтением пересказа. Отсюда типичный сбой: агент цитирует абзац из середины диалога как действующее правило, хотя правило поменяли позже.
Налог на каждую новую сессию
Восстановление контекста автор называет налогом с каждой новой сессии. Знание о проекте, живущее в переписке, приходится собирать заново столько раз, сколько сменится инструмент. И каждый раз решать, какое из противоречащих сообщений было последним.
Смена модели, новый чат, обрыв сессии по лимиту токенов дают один и тот же эффект. Разработчик платит временем не за работу над кодом, а за реконструкцию того, что уже было решено.
Оговорка по фактам: чисел автор не приводит и контролируемого эксперимента не ставил. Это качественное наблюдение из полугодовой практики, а не замер. Смежные задачи решают и другими способами: в разборе автоматизации длительных задач с локальными LLM состояние переносится в новую сессию через автоматический handover-документ, и там тоже речь о снижении ручной сборки контекста, а не об измеренном ускорении.
Что такое GRACE: замысел, границы и проверки рядом с кодом
Методику сделал osovv, распространяется она под лицензией MIT. Идея простая: замысел, границы модулей и проверки лежат в репозитории рядом с кодом. Не в голове разработчика и не в архиве диалога, а в файлах, которые версионируются вместе с исходниками.
Пять context-файлов, граф модулей, записи проверок и бандлы изменений
- Пять context-файлов фиксируют замысел и рамки проекта в нормативном виде: агент читает постановку, а не переписку о постановке.
- Граф модулей описывает связи и зависимости между модулями, по нему видно, что от чего зависит и что затронет правка.
- Записи проверок отвечают на вопрос, чем подтверждена работоспособность модуля.
- Бандлы изменений фиксируют, что именно менялось в рамках правки.
Все четыре класса артефактов живут в репозитории: попадают в коммиты, в диффы, в код-ревью. Детализированное содержание каждого файла в разобранном фрагменте статьи не раскрыто, поэтому роли перечислены по описанию методики, без догадок о внутреннем формате.
Чем это отличается от README и ADR
README отвечает на вопрос, что это за проект и как его запустить. ADR фиксирует одно решение и причины, по которым его приняли. Артефакты GRACE привязаны к модулям и функциям и рассчитаны на автоматическую сверку с кодом: линтер якорей, два графа, детектор дрейфа. Это наблюдение о характере артефактов. Заменой README или ADR методика не заявлена, и в источнике такого сравнения нет.
Разметка кода якорями: MODULE_CONTRACT, CONTRACT, MODULE_MAP и LINKS
Код размечен якорями, парными комментариями, которые линтер проверяет на парность, уникальность и соответствие реальным экспортам. Разметка живёт в том же файле, что и код, поэтому расхождение видно при первом же прогоне проверки.
Пример контракта модуля и функции
// START_MODULE_CONTRACT
// PURPOSE: validate JWT and resolve User
// SCOPE: src/auth/validate.ts
// DEPENDS: M-AUTH-TOKENS
// LINKS: M-AUTH-VALIDATE
// ROLE: RUNTIME
// MAP_MODE: EXPORTS
// END_MODULE_CONTRACT
// START_CONTRACT: validateUser
// PURPOSE: validate JWT, resolve user
// INPUTS: req: Request (with Authorization: Bearer header)
// OUTPUTS: User | null (null if invalid, never throws)
// SIDE_EFFECTS: none
// END_CONTRACT: validateUserПоля контракта модуля отвечают за разные вещи. PURPOSE описывает назначение, SCOPE привязывает запись к файлу src/auth/validate.ts, DEPENDS указывает зависимость от модуля токенов M-AUTH-TOKENS, LINKS связывает файл с модулем M-AUTH-VALIDATE, ROLE задаёт роль в рантайме, MAP_MODE определяет, что попадёт в карту модуля (в примере EXPORTS).
| Поле CONTRACT | Что фиксирует | Значение в примере |
|---|---|---|
| PURPOSE | Зачем существует функция | validate JWT, resolve user |
| INPUTS | Входные данные и их форма | req: Request с заголовком Authorization: Bearer |
| OUTPUTS | Что возвращается и при каких условиях | User | null, null при невалидном токене, исключение не бросает |
| SIDE_EFFECTS | Побочные эффекты | none |
Два последних поля дают проверяемые утверждения. «Never throws» и «side effects: none» можно подтвердить или опровергнуть тестом, а расхождение с кодом видно на ревью без чтения всей функции. Внутри тела функции в примере размечаются ещё и блоки: START_BLOCK_DECODE_JWT и END_BLOCK_DECODE_JWT для декодирования токена, START_BLOCK_CHECK_CLOCK_SKEW и END_BLOCK_CHECK_CLOCK_SKEW для проверки расхождения часов.
LINKS решает задачу навигации: поле связывает файл с модулем, чтобы при grep модель могла определить принадлежность файла модулю. Без такой привязки поиск по коду даёт список путей без контекста. MODULE_MAP и поле MAP_MODE в примере задают, что попадает в карту модуля; формат самой карты в разобранном фрагменте не детализирован.
Что проверяет линтер якорей
- Парность. У каждого START есть соответствующий END. Незакрытый блок означает, что границы контракта в файле не определены.
- Уникальность. Идентификаторы якорей не дублируются, иначе два разных места кода претендуют на одну запись замысла.
- Соответствие экспортам. Якорь ссылается на реально существующий экспорт, а не на функцию, которую переименовали три месяца назад.
Практический смысл третьей проверки: якорь, указывающий на несуществующий экспорт, и есть дрейф между замыслом и кодом. Его видно точечно, без чтения всего файла и без вопросов агенту.
Два графа: declared по замыслу и computed по AST
Утилита строит два графа. Declared собирается по замыслу: из разметки якорями и context-файлов. Computed строится по AST, то есть по фактическому коду. Расхождение между графами и есть предмет работы детектора. Формат графов и алгоритм сверки в разобранном фрагменте статьи не раскрыты, это внутренняя механика утилиты.
Похожую задачу решают локальные анализаторы кода, но с другим акцентом. repopedia парсит код через tree-sitter и складывает граф в SQLite, отвечая на вопрос, как устроен код. TeaRAGs добавляет к графу вызовов семантический поиск и git-метрики. GRACE работает иначе: он сверяет фактический код с заявленным замыслом, а не только описывает структуру.
Детектор дрейфа detect_changes и типы расхождений
- code_without_module. Код есть, а модуля в замысле нет. Типичный случай: файл или функцию добавили мимо разметки, и в declared-графе они не отражены.
- missing_verification. У модуля нет записи проверки. Формально код на месте, но подтверждения работоспособности нет.
Ценность в том, что дрейф обнаруживается до того, как агент начнёт строить работу на устаревшем представлении о проекте. Другие типы расхождений в разобранном фрагменте не перечислены, поэтому список стоит уточнять в самом репозитории утилиты.
doubled-graph: что автор добавил к GRACE
К upstream-методике автор добавил три вещи, которых там не было: сценарий миграции существующего кода, граф вызовов через CodeGraphContext и MCP-обёртку. Всё вместе называется doubled-graph. По словам автора, он использует её полгода; это личный опыт, а не результат измерений.
Граф вызовов через CodeGraphContext
Граф вызовов показывает связи между функциями, тогда как declared и computed работают на уровне модулей. Разница ощутима при правке: изменение в одной функции задевает вызывающих, и это видно до запуска тестов. Интеграция с CodeGraphContext - добавление автора, в upstream GRACE такого слоя не было. Детали реализации в разобранном фрагменте не описаны.
MCP-обёртка: контекст как инструмент агента
MCP-обёртка отдаёт контекст агенту как инструмент. Агент запрашивает нужное через MCP: контракт модуля, связи, записи проверок. Пересказывать структуру проекта в промпте и надеяться, что агент запомнит, больше не нужно.
Смежную задачу решает Later Bender, отдельный слой состояния проекта с задачами, заметками и runbook'ами, к которому подключаются разные модели через MCP. Там состояние живёт в сервисе, в doubled-graph контекст остаётся в репозитории рядом с кодом. Детали реализации MCP-обёртки в разобранном фрагменте не раскрыты.
Режимы migration и post_migration: как перевести существующий код на GRACE
Для проектов, которые уже написаны, есть режим migration: приведение существующего кода к разметке якорями и построение графов. Режим post_migration включается после: это работа в уже размеченном репозитории, где дальше поддерживают якоря, графы и записи проверок.
Сценарий миграции - добавление автора, которого в upstream не было. Пошаговых команд в разобранном фрагменте нет. Логика режима такая: разметить существующий код, построить графы, дальше гасить расхождения, которые показывает detect_changes, и закрывать пропущенные записи проверок. Точные шаги задают готовые промпты.
Установка через pipx и готовые промпты
Утилита ставится через pipx. В комплекте идут готовые промпты для нового проекта и для миграции, и это заметно снижает порог входа: не нужно самому формулировать постановку для агента и угадывать порядок шагов. Конкретные версии пакета, флаги CLI и текст промптов в разобранном фрагменте не приведены, их стоит смотреть в репозитории.
Десять обязательных принципов методики
Методика содержит десять обязательных принципов. Их роль понятна из механики: без соблюдения правил разметка и графы деградируют в мёртвые артефакты, которые никто не обновляет. Детектор дрейфа начинает выдавать шум, записи проверок устаревают, якоря ссылаются на переименованные функции.
Полный список из десяти пунктов в разобранном фрагменте не приведён. Из описанной механики следуют как минимум такие требования: START и END должны быть парными, идентификаторы якорей уникальны, якоря соответствуют реальным экспортам, у модуля есть запись проверки, бандлы изменений обновляются вместе с кодом. Остальные принципы стоит читать в самом репозитории, а не додумывать по названию методики.
Ограничения подхода и как проверить его на своём проекте
Автор прямо оговаривает: контролируемого эксперимента он не ставил и чисел не приводит. Полгода использования doubled-graph - личный опыт, а не замер. Поэтому материал стоит читать как практический разбор подхода, а не как подтверждённое сравнение с хранением контекста в чатах. Любые ожидания по ускорению остаются гипотезой, которую проверяют на своём репозитории.
Кому подход вряд ли окупится
- Одноразовые скрипты и прототипы на пару дней. Разметка якорями, context-файлы и графы стоят дороже, чем сам код, который никто не будет сопровождать.
- Проекты без повторяющихся сессий. Если агент заходит в код один раз, налог на восстановление контекста платить не приходится, и выгода исчезает.
- Работа без AI-агента в цикле. Ценность разметки в том, что её читает модель; при полностью ручной разработке часть артефактов превращается в формальность.
- Команды без дисциплины поддержки. Если якоря и записи проверок не обновляют вместе с кодом, detect_changes начнёт выдавать расхождения пачками, и его перестанут читать.
Цена подхода складывается из разметки каждого модуля, ведения context-файлов, записей проверок и бандлов, а также поддержки графов и линтера. Это аргументированная оценка, а не измеренная цифра.
Тест на переносимость контекста
- Возьмите агента, который проект никогда не видел: другая модель, пустой чат, без истории и без подсказок.
- Дайте ровно один промпт: «прочитай, что здесь есть, и расскажи, как устроен проект и что в нём сейчас происходит».
- Сверьте ответ с реальным устройством проекта: границы модулей, зависимости, что сейчас в работе.
- Повторите то же на репозитории, где контекст живёт только в переписке, и сравните ответы.
Это качественная проверка, а не бенчмарк. Она показывает главное: сколько контекста проект отдаёт сам, без сопроводительного рассказа разработчика. Если агент с первого промпта называет модули, их зависимости и текущее состояние, контекст в репозитории работает. Если отвечает общими словами, начните с одного модуля: разметьте его якорями, заведите запись проверки и посмотрите, что покажет detect_changes. Полное описание методики и утилиты - в исходной статье автора.