Харнесс вокруг кодящего агента, или Как я создал собственного монстра

от автора

Качество работы с кодящим агентом почти не зависит от того, какая под капотом модель. Я довольно долго в это не верил — менял модели, крутил промпты, ждал следующий релиз. А разница, оказалось, не в модели. Она в том, что вокруг модели: есть ли у агента память между сессиями, карта проекта, правила, руки и место под результат. Голая модель — это эрудит без рабочего места. Каждый разговор она начинает с чистого листа.

Вот это всё вокруг модели — память, карта, правила, руки — и называется харнесс. Ниже — разбор моего харнесса целиком, слой за слоем, на одном реальном проекте: пять сервисов, Kubernetes, прод. Не идеальная схема из README, а то, что видно в логах: что реально вызывается каждый день, а что я нагородил и забыл. Спойлер: половина подключённых MCP-серверов за 98 сессий не вызвалась ни разу. Сразу оговорюсь: сессии сохранились не все — у Claude Code, похоже, есть ротация логов, часть истории потерялась. Так что мои числа — это нижняя граница, реальные ещё выше.

И ещё одна рамка, важная для всего дальнейшего: это не сетап, развёрнутый за вечер по чек-листу. Он нарастал три месяца вместе с проектом — слой за слоем, под конкретную боль. Что-то приживалось, что-то я выбрасывал. К примеру, пробовал claude-mem (80+ тысяч звёзд на GitHub) как слой памяти — база за пару недель распухла до 700 МБ почти бесполезной выжимки, а потом застарелый баг сожрал пять ядер CPU, пришлось снести. Звёзды инструмента и его пригодность — разные вещи; рабочий харнесс собирается из того, что выжило в твоём проекте, а не из топа трендов. Про сам хайп вокруг харнессов — почему репозитории набирают по 200 тысяч звёзд за полгода и как отличить накрученное от рабочего — у меня был отдельный разбор. Этот пост — оборотная сторона того же сюжета: не аудит чужих витрин, а моя собственная кухня, со всеми кривыми углами. Отсюда и «монстр» в заголовке: его не проектировали — он таким вырос.

Зачем вообще проект, а не абстракции

Чтобы числа были не в вакууме. Технически это многосервисная аналитическая платформа, всё в одном репозитории:

  • Next.js 16 — фронт и API. Чат-агент собран на AI SDK v6 (ToolLoopAgent), провайдеры — Anthropic и Google. UI на shadcn/ui + AI Elements, состояние — Jotai, данные — Drizzle ORM поверх PostgreSQL (PostGIS и pgvector для гео и RAG).

  • Аналитический MCP-сервер (Python, FastMCP) — два с лишним десятка инструментов поверх DuckDB: SQL, визуализация, профилирование.

  • Sandbox MCP (TypeScript, @anthropic-ai/sandbox-runtime) — изолированное исполнение Python/JS/bash, чтобы агент реально считал, а не выдумывал числа.

  • Расчётный солвер (Python, FastAPI) — тяжёлый сервис, математические модели, со своими 500+ тестами.

  • Sync-сервис (Python, APScheduler) — фоновой сбор внешних данных, без HTTP.

Деплой — Helm на одноузловой MicroK8s, отдельные кластеры под прод и стейджинг, один чарт. Кроме пяти app-сервисов, кластер несёт PostgreSQL, Redis и SeaweedFS (S3-совместимое хранилище под датасеты, файлы и бэкапы). Канонический номер версии — в одном файле, bump-my-version держит остальные манифесты синхронными, CI по git-тегу v* собирает Docker-образы и катит стейджинг сам, прод — вручную. Локально то же поднимается одним docker compose.

Смысл для темы поста: система настоящая, агенту нельзя «примерно». Каждый слой ниже закрывает конкретную боль этого масштаба.

Слой 1. Конституция — файлы, которые агент читает первыми

Поведение агента в проекте задаёт не один файл, а набор корневых документов.

CLAUDE.md — главная инструкция. Не README для людей, а правила для модели: как собрать каждый сервис, что нельзя трогать («не редактируй components/ui/ — ими управляет CLI shadcn, оборачивай рядом»), куда класть какой документ, на каком языке отвечать. Она слоистая: сверху мой личный кросс-проектный слой (~/.claude/ — язык, принципы, протокол завершения сессии), под ним слой проекта, ещё ниже — правила с привязкой к путям. Правила для MCP-кода подхватываются, только когда трогаешь MCP-код; правила фронта — только на фронте. Агент не тонет в простыне «общих правил» — ему прилетает ровно то, что относится к файлу под рукой.

PRODUCT.md — продуктовый бриф: для кого, как звучит, на что похож и на что нет (явные anti-references). Без него агент пишет технически верный, но безличный UI.

DESIGN.md — источник правды по дизайну: палитра в токенах, типографика, принципы. То, что не даёт каждый раз изобретать «свой оттенок синего»: любой UI-код сверяется с токенами отсюда, а не с фантазией модели.

CONTEXT.md — словарь домена (приём тащу из другого репозитория). Термины, связи, зафиксированные неоднозначности. Отдельная поверхность, которую агент читает и правит: встретил расхождение в именовании — дописал сюда, а не расплодил третий синоним. Без словаря каждая сессия заново выводит термины из контекста, и каждый раз чуть по-своему.

docs/agent-docs/ — живая документация: architecture.md (карта сервисов, списки инструментов), conventions.md, deployment.md (как катить релиз, откат, диагностика подов). Всегда-актуальный срез. Причём архитектурный файл — производная: канон решений лежит в ADR, а здесь только снимок со ссылками.

Слой 2. Память — граф задач и память агентов

Память двухконтурная — и обе работают, а не лежат для вида.

Первый контур — beads (bd), трекер задач. Веду его не как плоский TODO.md, а как граф зависимостей. Прямо сейчас в графе проекта 106 задач: 55 закрыто, 50 открыто, 48 готовы к работе (bd ready отдаёт только незаблокированные), пара заблокирована чужими. Проверяется одной командой — bd stats. Почему граф, а не список: список не знает, что задача B блокирована задачей A, и не умеет восстановить контекст после сжатия диалога. bd prime поднимает состояние проекта одной командой на старте сессии или после компакта. Markdown-списки задач я запретил сознательно — они дрейфуют между сессиями и конфликтуют с графом.

Второй контур — память самих суб-агентов. У каждой специализированной роли (архитектор, бэкенд, инфра, фуллстек) своя папка: MEMORY.md плюс отдельные файлы под решения по проекту и под полученный фидбэк. Агент-бэкенд однажды получил правку — и больше не повторяет ту же ошибку. Это и есть превращение «эрудита» в «коллегу, который тут уже три месяца».

Слой 3. Документация — структура, а не свалка

Документы не валятся в корень — под каждый тип своя папка со строгим именем. И это не абстрактное правило: вот что реально накоплено за три месяца (любая строка проверяется через find … | wc -l):

Папка

Что лежит

Сейчас

docs/plans/

планы реализации

162

docs/specs/

дизайн-спеки

157

docs/reports/

отчёты, ревью, аудиты

48

docs/adr/

решения, по файлу на каждое

15

docs/agent-docs/

живая архитектура

Сотни документов, и каждый лежит ровно в своей папке. ADR пишутся скилом adr-skill в immutable-формате MADR: скан кода → сократический опрос → черновик → ревью. Решение, принятое в апреле, не теряется в чате — это отдельный файл, на который ссылается архитектурный обзор. Правило жёсткое: не плоди новые директории, клади в существующую. Именно это держит документацию навигируемой через полгода — место у каждого типа ровно одно.

Отдельно — исследования. Это не «заметка по ходу дела», а самостоятельный жанр: датированный документ с провенансом (откуда взято), разделом источников и статусом. В соседнем репозитории они производятся по конвейеру (скил research-pipeline): сбор источников → параллельные суб-агенты по официальным источникам → content-addressed снапшоты → независимый верификатор → попытка опровергнуть собственные выводы → канонизация. Ресёрч — это топливо: сегодня тема, через месяц тот же документ становится основой для решения, спеки или вот этого поста.

И вся эта папка одновременно — Obsidian-vault. Структура выше открывается как граф связанных заметок. Я хожу по проекту через граф ссылок, агент — по тем же файлам через свои инструменты. Один источник, два способа навигации; никакой второй «документации для людей», которая отстаёт от настоящей.

Слой 4. Руки агента — и честно про мёртвый груз

Модель сама по себе умеет только говорить — руки ей дают плагины и MCP-серверы. Плагины ставятся из маркетплейса одной командой. У меня их 13, по назначению:

  • процессы: superpowers — ядро workflow

  • доки и веб: context7 (живые доки библиотек), firecrawl (скрейп), playwright (браузер)

  • языковые серверы: typescript-lsp, pyright-lsp — для точных правок

  • домен и UI: figma, frontend-design, supabase, vercel

  • мета: code-simplifier, skill-creator, security-guidance

Плюс MCP-серверы: codegraph (граф кода), tolaria (vault), pencil, dembrandt — и серверы от плагинов.

А теперь то, что видно только из логов — за 98 сессий:

MCP-сервер

Вызовов

На что

playwright

сотни

demo-видео и UI-тесты, не код

codegraph

28

анализ влияния перед правкой

context7

редко

свежие доки вместо галлюцинаций

tolaria, pencil, figma, supabase, vercel, dembrandt

0

мёртвый груз

Полдюжины серверов подключены — и просто висят, отъедая токены метаданных в каждом промпте.

Отсюда отдельная гигиена: периодический аудит — что вызывалось, а что пора отключить. Установить инструмент дёшево. Дорого — оставить его висеть мёртвым: каждый лишний сервер раздувает контекст и размывает выбор инструмента у модели. Если соберётесь повторять — закладывайте ревизию, а не только установку.

Слой 5. Скилы — переиспользуемые процедуры

Скил — записанная процедура, которую агент подтягивает по триггеру, а не получает заново в каждом промпте. Костяк — пакет superpowers, и по следу в репозитории видно, что из него реально живёт:

  • brainstorming — старт почти любой нетривиальной задачи, а не сразу код; его выход → 157 спек

  • writing-plans — план реализации → 162 плана

  • subagent-driven-development — план исполняется раздачей задач суб-агентам

  • test-driven-development — рабочая петля написания кода

Первые два неслучайно меряются сотнями: это не пара эпизодов, а основной вход почти в каждую задачу. Плюс доменные: impeccable (UI), adr-skill (→ 15 ADR), demo-video-pipeline, ru-text для русских текстов.

Скилы делятся на процессные (брейншторм, отладка — определяют, как подступиться к задаче) и реализационные. Точка входа тонкая, детали — в подпапке references/, чтобы не раздувать контекст. У самого продукта вдобавок свой каталог доменных скилов — агент внутри приложения пользуется тем же механизмом.

Слой 6. Специализация — суб-агенты, и code-review прямо в петле

Поверх всего — делегирование, а не сольная сессия. В выборке 128 запусков суб-агентов против 46 прямых вызовов скилов. Суб-агенты — это роли со своими правами, моделью и памятью: архитектор только проектирует и код не трогает (режим plan), ревьюер ищет дрейф, бэкенд/фронтенд/инфра пишут каждый в своей зоне — архитектор физически не закоммитит код, а ревьюер его не перепишет.

Реальная раскладка из логов:

Суб-агент

Запусков

Зачем

code-review

36

ревью в петле

backend

31

запись кода

frontend / fullstack

13 / 7

запись кода

Explore + general-purpose

31

разведка, поиск

architect / security

3 / 3

крупные решения

code-review на первом месте, и это не случайно. Ревью у меня не разовый финал «в конце проверь», а шаг петли: написали кусок → отревьюили независимым агентом → поправили → прогнали тесты.

Рядом — слэш-команды под частые операции (deploy-check, freeze/unfreeze, review). Честно: часть из них я определил, но они не прижились — по логам почти не вызываю, живут в основном /clear и управление длиной контекста. Это нормально: харнесс растёт быстрее привычек, и лишнее стоит периодически выпалывать. Тот же принцип, что и с мёртвыми MCP.

Слой 7. Хуки — клей, который работает без меня

Хуки — автоматика на события, а не на мою команду:

  • на старте сессии — подгрузка git-контекста и bd prime (состояние задач);

  • перед компактом — напоминание сохранить важное, чтобы не потерять при сжатии;

  • после каждой правки файла — автолинт (ruff/eslint) ровно по изменённому файлу;

  • на попытку тронуть managed-папку — жёсткий блок с подсказкой, куда писать вместо этого;

  • на завершение задачи — quality-gate: прогон pytest + tsc, и при красном он блокирует завершение (exit 2), а не просто ворчит.

В логах этот гейт срабатывает и останавливает работу. Смысл простой: я не помню про линтер и тайпчек — про них помнит харнесс. Дисциплина вынесена из головы в конфиг.

Слой 8. herdr — оркестрация на уровне терминала

Верхний слой — над всеми сессиями сразу. herdr — менеджер рабочих пространств для агентов: сессии, ветки-worktree, вкладки, панели. Через свой хук он видит состояние каждого агента — кто работает, кто ждёт ввода, кто закончил. Когда параллельно крутится несколько агентов в разных worktree, это разница между «оркестром» и «зоопарком»: видно, кому нужен ответ, а кто ещё думает.

Как это складывается в один поток

Слои — не коллекция, они выстраиваются в пайплайн. Вот как течёт задача на практике, по трейсам из сессий:

  1. bd prime / bd ready — поднять контекст, взять незаблокированную задачу;

  2. brainstorming (если фича новая) → спека;

  3. writing-plans → план реализации;

  4. раздача доменным суб-агентам через subagent-driven-development;

  5. TDD-петля: красный тест → зелёный → ruff + tsc;

  6. conventional-commit → git push + версионный тег;

  7. code-review-агент → правки по ревью → повторный прогон тестов;

  8. bd closebd dolt push (синк канонической базы задач).

Параллельные участки — скажем, пять сцен demo-видео — раздаются веером.

Заметьте, где здесь человек: на брейншторме, на ключевых развилках (в логах сотни уточняющих вопросов от агента) и на приёмке. Всё между — сборка, тесты, линт, ревью, синк — едет на автоматике харнесса.

Что в итоге

Я начал с тезиса, что качество почти не зависит от модели. Разбор, надеюсь, показал, от чего оно зависит:

  • память — граф задач плюс память ролей;

  • карта — слоистый CLAUDE.md, словарь домена, живые agent-docs;

  • руки — MCP и плагины, и смелость отключать мёртвые;

  • процедуры — скилы;

  • специализация — суб-агенты с ревью в петле;

  • автоматика — хуки-гейты.

Голая модель в чате — это собеседование. Модель в харнессе — сотрудник.

Ни один слой по отдельности погоды не делает. Работает их сумма: они складываются в поток, где человек остаётся на замысле и приёмке, а сборка едет сама. И отдельно повторю неудобное: половина того, что я подключил, оказалась мёртвым грузом. Полезный харнесс — это не «поставить побольше», а регулярно смотреть в логи и выпалывать то, что не вызывается.

В прошлый раз я закончил вопросом: что вы готовите — ужин на четверых или витрину, на которую сами не сядете обедать. Этот харнесс я наращивал под один проект, и самое глупое, что с ним можно сделать, — набить его чужими звёздными скилами вместо того, что реально работает у тебя. Собранный так каркас снижает порог входа в следующий проект: он стартует не с чистого листа, а с готового рабочего места — твоего, а не из топа трендов.

ссылка на оригинал статьи https://habr.com/ru/articles/1045348/