Привет, Хабр. Я решил, что пора и мне что‑то написать. Пишу на Ruby уже 7 лет. Долгое время я был противником использования ИИ в разработке поскольку считал, что тогда человек сам теряет навыки и ничему не учится, а также пропадает понимание того, как работает сервис. В целом эти утверждения до сих пор считаю верными, но свое отношение к ИИ изменил. Как говориться: кто не переобувается, у того ноги воняют. Подсаживался на иглу ИИ я потихоньку, с ощущением будто бы делаю, что‑то постыдное. Чуть‑чуть дипсика, потом тайком использовал курсор, но так чтобы никто ничего не понял. Но в какой‑то момент понял, что мир изменился и либо я адаптируюсь, либо останусь за бортом. Поделюсь тем, к чему пришел за время работы.
На RubyRussia 2025, слушая доклад о системной архитектуре, я зацепился за мем:

Тогда я ещё не знал, как часто буду говорить эту фразу.
Она мне настолько понравилась, что я стал отвечать ей на неудобные вопросы. «А можем мы реализовать эту фичу?». Ну, в принципе можем, зависит от контекста. «Как думаешь, нужно ли проверить этот функционал при тестировании?». полностью прослушав вопрос Смотря в каком ключе рассматривать использование фичи. «Будем добавлять кэширование?». Смотря какая нагрузка.
Фраза была правдивой и бесполезной одновременно. Она верна практически всегда и поэтому ничего не меняет. У попугая нету проблемы с точностью. Его проблема в том, что за фразой ничего не стоит.
Смысл поменялся, когда я перестал ссылаться на воображаемый контекст и начал его коммитить. по сути выяснилось, что «всё зависит от контекста» это не отговорка. Это описание архитектуры. У контекста появились понятные очертания: MCP, скиллы, markdown‑файлы и графы.
По сути у агента ровно та же болезнь, что была у моих отговорок. Он отвечает бесполезно, когда не знает контекста. Только вот агенту контекст можно выдать, а я просто уходил от ответа.
Самый показательный случай для меня был про одну строчку. В моём Rails‑проекте pattern matching на результате операции работает только если писать Failure([:not_found, ]), с массивом. Без массива ветка молча не срабатывает: не падает, не ругается, просто не выполняется. Агент раз за разом писал Failure(:notfound), спека краснела, я правил руками, а в следующей сессии он писал так же. Промпт «пиши правильно» тут не помогает никак, так как это знание не выводится из кода, его в коде физически нету. Помогла одна строка в CLAUDE.md. С тех пор ошибка не повторялась.
Полгода я собирал контекст в двух режимах сразу, на работе и в пет‑проекте. Как показала моя практика есть разные подходы к сборке контекста, я использовал два и оба они имеют право на жизнь. На работе знание уже записано: в вики, в тикетах, в мердж‑реквестах. Его не нужно создавать, надо только подключить. В пет‑проекте знания нету ни у кого, кроме меня, его приходится производить: описаниями, правилами и графами.
Половину времени я работаю в чужой системе знаний, половину в своей.
Сделай красиво тоже работает, но все зависит от контекста
Про промпт‑инжиниринг написано уже много, на Хабре есть большой разбор Context Engineering. Пересказывать не буду, скажу только то, что понял на своей практике.
Промпт — это формулировка задачи. «Сделай задачу», «почини баг», «напиши тест». У меня она за полгода почти не поменялась. Менялось другое. Что агент успел прочитать до того, как я нажал enter. До каких систем он дотянулся, какие файлы у него под рукой, куда ему ходить запрещено.
Поэтому когда результат плохой, я теперь не переписываю промпт в пятый раз. Смотрю, чего агент не видел.
Две стороны одной медали
Работа | Пет‑проект | |
|---|---|---|
Кто владеет знанием | Команда, десятки людей | Только я |
Где оно лежит | Вики, тикеты, мердж‑реквесты, история ревью | Нигде. У меня в голове |
Задача агента | Найти и достать нужное | Получить то, чего не существует |
Чем решается | MCP к внешним системам | markdown‑файлы, скиллы, граф |
Моя роль | Подключить | Сформулировать |
Как выглядит провал | Уверенно цитирует тикет двухлетней давности | В какой‑то момент у меня в docs файлах скопились скриншоты багов и множество спеков. В итоге агенту нужно было несколько попыток чтоб сменить отступы |
Последняя строка общая. В обоих контурах агент ломается одинаково, он верит написанному.
Работа
На работе я не написал агенту почти ни одной строки документации. Она уже была написана до меня. Нужно было только до нее дотянуться.
Трекер
Начал я с трекера, ибо хожу туда чаще всего.
Оказалось, что задача это не текст тикета. В описании один сценарий, а через неделю в комментариях аналитик передумал и решение приняли прямо в треде. Пока агент читал только описание, он делал то, что уже отменили. Промпт при этом был тот же самый, «сделай задачу».
Ещё в трекере лежит то, чего вообще нигде больше нету. Кто до меня трогал этот кусок, почему его откатили.
Вики
Потом я подключил вики, так как во многих задачах были ссылки на статьи и они тоже нужны для формирования контекста. Важно было при этом не забить контекст одной страницей, поэтому я реализовал логику, при которой агент сначала забирает все заголовки со страницы, а потом уже читает нужные пункты.
До подключения вики нужно было копипастить нужные пункты и проверять их на актуальность. Теперь агент делает это за меня.
GitLab
Последним пришёл GitLab, и тут контекст перестал быть текстом.
Красный пайплайн на боте, который обновляет зависимости, это не документ. Это состояние системы прямо сейчас: лог упавшей джобы, диффа, ветка. Агент читает лог, вносит минимальную правку, пушит и ждёт зелёного. Никакого знания «о проекте» тут в целом и нету, нужен доступ к тому, что происходит.
Что агенту позволено
Отдельная история, которая к контексту относится не меньше.
Комментарий в трекере уходит от моего имени, его видит команда и по нему летят нотификации. Поэтому у агента прописано: статус, ворклог и привязку MR делай молча, свободный текст и упоминания людей только черновиком, я подтверждаю.
Тут я ничего не придумывал. Знание уже было написано, мне оставалось дать к нему доступ.
Пет‑проекты
Второй контур это мои личные проекты. Тут подключать нечего, поскольку знания нету ни в вики, ни в тикетах. Оно есть только у меня в голове, а агенту от этого ни горячо ни холодно.
Поэтому всё, что в первом контуре я подключал, тут пришлось написать руками.
CLAUDE.md
CLAUDE.md агент читает в начале каждой сессии. Туда я записываю то, обо что он уже споткнулся.
Про Failure([:not_found, ]) я рассказал в начале. Там же лежит, что performlater нельзя вызывать внутри транзакции: воркер стартует раньше коммита, не видит строку и молча выходит, а запрос навсегда остаётся в queued. На проде с Solid Queue это не проявляется, локально на async‑адаптере проявляется через раз. И что неймспейсинг в бекенде двойной, app/operations/operations/..., иначе Zeitwerk конфликтует с моделями.
Из кода это не выводится.
фрагмент из CLAUDE.md
CLAUDE.md Монорепо редактора документов «Свод» (рабочее имя markdown-editor): frontend/ — React 19 + Vite + TipTap, весь MVP; backend/ — Rails 8.1 API-only на dry-rb + Postgres. Продукт русскоязычный: UI-строки, сообщения об ошибках и комментарии — на русском. instruction.md фиксирует 8-этапный план. «Выполняй пункт N» = работа строго по этому пункту. Где искать контекст docs/knowledge-base/README.md — канон решений по продукту, сценариям, архитектуре, roadmap. Читать первым при содержательной задаче. docs/codebase-map.md — описательная карта кода (роуты, сторы, рендереры, слои backend'а). docs/patterns/ — шаблоны Operation / controller / spec. Смотреть до написания своего. docs/context-hygiene.md — что не грузить в контекст и куда архивировать; читать в сессиях с документами, планами, багами. docs/knowledge-base/CHANGELOG.md — вход в историю изменений. Не читать по своей инициативе (только по прямой ссылке): docs/superpowers/_archive/, docs/bugs/_closed/, docs/design-spec/, docs/market/, design-reference/ui_kits/*/dist/, сборки и логи. Команды make help — полный список. Всё гоняем через Makefile (внутри docker compose), не через ручной docker compose exec .... make check = lint + тесты обеих частей + security (brakeman + bundler-audit) — тот же набор гейтов, что в CI; make test-watch — Vitest в watch; make logs — хвост backend-логов.
Карта кода
docs/codebase-map.md, 94 строки. Описательный обзор: какие есть роуты, где лежат сторы, из чего состоит бекенд.
Смысл в том, что агенту не надо грепать репозиторий, чтобы понять куда идти. Он читает 94 строки и открывает нужный файл.
Как я превратил контекст в свалку и героически с этим боролся
Тут я понял то, чего от себя не ожидал. Половина работы с контекстом это не собрать, а выкинуть. Параллельно я делал 2 проекта и в одном все изменения проходили быстро и без проблем, а вот на втором изменения вводились с боем и мучениями, а также я за 2 часа сжигал лимиты max(x5) подписки. Уже решил, что дело в новой версии opus, но оказалось, что контекст просто забит мусором.
Устаревший файл хуже отсутствующего, агент ему верит и это наносит больше вреда.
Поэтому есть docs/context-hygiene.md и правило: закрыли баг, выполнили план, реализовали спек, всё это тем же коммитом уезжает в archive/ или closed/. А в CLAUDE.md лежит явный список «сюда не ходить без прямой ссылки».
Граф
Когда описаний стало много, я прогнал проект через graphify. Из 93 файлов и примерно 2,4 миллиона слов получилось 3508 узлов, 7016 рёбер и 420 сообществ. Стоило это 145 тысяч входных токенов, один раз.
На выходе карта, которую руками никто не рисовал: «Экспорт в DOCX», “Реестр блоков”, «Сборка расширений TipTap».
Читать её целиком всё равно нельзя, graph.html весит 3 мегабайта. Работает только запросами.

Скилл
Модель шаблонов вынесена в скилл и MCP, чтобы внешний агент собирал шаблоны по актуальным правилам.
Если тронуть конструктор и не обновить скилл, ничего не сломается. Сборка зелёная, тесты зелёные, а агент собирает шаблоны по правилам, которых уже нету.
Лечится тем, что make check падает, если сгенерированные знания разошлись с реестром блоков. Глазами такое не заметить.
Полгода тут ушли на то, чтобы построить структуру, которая будет запоминать необходимое, выкидывать лишнее и проверять знания.
Статистика
Без какой‑либо статистики все высказывания не имеют смысла. Поскольку формировать контекст я закончил только в апреле, то данные за такой короткий период мало что доказывают, но все же.

В рамках нашего рабочего процесса в story мы закрываем свои задачи и там же создаются дефекты. На этом графике по скольким задачам до и после апреля открывались дефекты. Опять же пока прошло слишком мало времени, чтобы что‑то заявлять, но все равно здесь можно увидеть тренд на уменьшение заведенных дефектов.

Второй график показывает долю моих МРов в которых были какие‑либо комментарии по итогам ревью.
На картинке доли MR по количеству прилетевших комментариев, от нуля до шести и больше. Комментариев ревью на один мой MR стало 0.49 вместо 1.57. Доля MR, прошедших вообще без замечаний, выросла с 71% до 83%.
В пет‑проекте мерить нечего, там нету ни тестировщика, ни ревьюера, и сравнивать не с чем. Что там реально видно, я показал выше.
Что общего
Контуры разные, а правила из них вышли одинаковые.
Контекст должен быть адресуемым. «Оно где‑то в репозитории» не работает, нужен путь, ссылка или доступ. У контекста есть срок годности, и его надо периодически перечитывать и выкидывать. Описание дешевле кода, а когда описаний много, граф дешевле описаний.
Ну и самое важное:

К сожалению, агент пока не умеет читать мои мысли, поэтому если знание только в моей голове, то прийдется дать ему его, а не пытаться заставить вспомнить его то, чего он не знает
Подытожим
Это первая статья которую я когда либо писал, надеюсь она будет кому‑то полезной.
Кстати, системным архитектором я так и не стал.
Но фраза перестала быть отговоркой. Раньше я отвечал «зависит от контекста», и на этом разговор заканчивался. Теперь на такой вопрос я отвечаю, ссылаясь на источники.
Разница между мной и попугаем в том, что я в итоге зафиксировал, от какого именно контекста всё зависит.

