От личных промптов к командному процессу

Я технический лидер нескольких команд. В этих командах есть разные экспертизы: frontend, backend на NestJS и NextJS, QA, исследовательская работа. Поэтому проблема с LLM-наработками шире, чем "как мне самому писать код быстрее", а "как опыт и навыки одного человека превратить в автоматизированный процесс для команды или компании".

В первый раз я столкнулся с этой задачей в discovery-команде, где в основном работают исследователи. Один из коллег передал мне базу с интервью, промптами и методиками: проведение синтетических интервью, анализ серии интервью, JTBD-формулировки, красные флаги и защитные барьеры. По сути это уже был набор рабочих LLM-практик.

Но с такими артефактами есть проблема: они полезны, пока человек знает, где они лежат, как их запускать и в каком порядке применять. Для команды это ещё можно объяснить на созвоне. Для нескольких команд это быстро превращается в хаос из файлов, ссылок и устных договорённостей. Тогда задача показалась мне слишком широкой: непонятно было, с какой стороны подступиться к "менеджеру LLM-практик".

Техдолг перестаёт быть строкой в бэклоге

Более узкий и проверяемый кейс появился позже, на техдолге. В какой-то момент техдолг перестаёт быть фоном и становится отдельной продуктовой задачей. У нас это случилось, когда стало понятно, что проекты живут в разных цифровых эпохах.

Где-то была старая Node. Где-то старый Yarn. Где-то устаревший TypeScript, ESLint, Storybook. В одних проектах использовалась одна библиотека форм, в других - другая. С тестами была похожая история: разные раннеры, разные подходы, разная степень поддержки. Иногда всё это встречалось даже внутри одного репозитория. При переключении с проекта на проект, много ресурса уходило на переключение технического контекста, в результате продуктовый контекст оказывался за рамками, что сказывалось на качестве и скорости выполнения задач.

Три проекта, три эпохи runtime и tooling - экскурсия по техдолгу.
Три проекта, три эпохи runtime и tooling - экскурсия по техдолгу.

Важно: это не история про "мы всё делали неправильно". Большая часть проектов досталась нам по наследству. Команды менялись, исчезали, сливались; продукты жили своей жизнью; зависимости обновлялись неравномерно, а старые решения продолжали работать ровно до того момента, пока их не трогали.

Проблема стала совсем конкретной, когда часть проектов нельзя было нормально запустить на современных MacBook. Архитектура процессоров поменялась, и многие устаревшие библиотеки отказывались запускаться в новом окружении. В этот момент техдолг перестал быть абстрактной строкой в бэклоге.

Ручная миграция с LLM всё ещё ручная

В нашей компании есть рекомендуемый стек. В одной команде мы решили проект за проектом переходить к нему: обновлять runtime, пакетный менеджер, линтеры, сборку, тесты, вспомогательные инструменты. Начали с активного проекта, по которому было много текущих задач. Логика была простая: если проект активно развивается, то выигрыш от модернизации будет виден быстрее.

Все равны как на подбор
Все равны как на подбор

На первый проект мы выделили спринт, и один разработчик занимался только этой миграцией. Делали вручную, хотя не совсем "вручную": использовали LLM, просили помогать с ошибками, миграциями, поиском причин падений. И прогресс действительно был. За две недели часть проблем удалось закрыть.

Но другая часть осталась. И что важнее: стало понятно, что сам подход плохо масштабируется. Если на первый проект ушел спринт и при этом результат не гарантирован, то что делать с остальными? В этой команде было порядка тридцати проектов. А если подняться на уровень компании, таких команд около десяти. Даже если каждый следующий проект пойдёт чуть быстрее, всё равно получится процесс, который завязан на ручную работу, память конкретных людей и повторение одних и тех же расследований.

От героических спринтов к повторяемому процессу

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

Вечная борьба с ветряными мельницами
Вечная борьба с ветряными мельницами

Как превратить разовую миграцию в повторяемый процесс

AI skills, agents и plugins - инструменты, которые созданы именно для того, чтобы их переиспользовать и они хорошо ложатся на задачи с техдолгом.

Миграции редко состоят из одного промпта. "Обнови Node" - это не действие, а целый процесс: найти текущую версию, понять, какие пакеты блокируют следующий major, обновить CI, lockfile, проверить сборку. То же самое с Yarn, ESLint, TypeScript, Storybook, миграцией с CodeceptJS на Playwright или с webpack на rspack. В каждой задаче есть порядок шагов, типовые блокеры, проверки и границы.

Я начал упаковывать это в скиллы. На минимальном уровне скилл - это папка с SKILL.md, где в frontmatter описано, когда его вызывать и что он делает:

---
name: bump-node-major
description: >-
  Итеративный подъём major-версий Node.js. Скилл проверяет текущий runtime,
  находит блокеры зависимостей и предлагает следующий безопасный hop.
scope: any
---

В реальности полезный скилл быстро становится чуть больше, чем один markdown-файл:

skills/bump-node-major/
├── SKILL.md
├── scripts/
│   ├── detect-current-node.sh
│   ├── analyze-blockers.mjs
│   └── plan-iterative-bump.mjs
├── assets/
│   ├── blockers.json
│   └── Dockerfile.template
└── references/
    └── breaking-changes.md

Запахи, которые можно проверить

Довольно быстро скиллы разделились на несколько типов.

Первый тип - диагностические. С них начинается работа, потому что перед миграциями нужно понять, что именно болит в репозитории. Главным здесь стал tech-debt: meta-skill, который ничего не меняет в коде, а сканирует проект на "плохие запахи".

Он проверяет runtime, пакетный менеджер, версии Storybook, ESLint, TypeScript, React, Webpack, Jest, Lerna, наличие CodeceptJS, deprecated packages, дублирующиеся инструменты из одной категории и библиотеки со статусом Hold во внутреннем tech radar.

Под "плохими запахами" я имею в виду не абстрактное ощущение "проект старый", а проверяемые сигналы:

  • runtime не закреплён, устарел или больше не поддерживается - проект сложнее запускать, а обновления зависимостей начинают упираться в старое окружение;

  • пакетный менеджер или lockfile требуют внимания - старая major-версия, несовместимый режим работы, раздутый lockfile или накопившиеся dedupe-проблемы;

  • ключевая библиотека или инструмент отстали на несколько major-версий - чем больше разрыв, тем выше риск, что обновление превратится в отдельный проект;

  • библиотека больше не поддерживается или явно deprecated - её лучше удалить, заменить или хотя бы не строить вокруг неё новые изменения;

  • текущее решение не входит в список рекомендуемых - в новых проектах команда уже использует другой стандарт, а старое решение остаётся только из-за наследия;

  • в одной категории живут несколько инструментов с одинаковой ролью - например две библиотеки форм, два тестовых подхода или два bundler-а, между которыми постоянно приходится переключаться;

  • один инструмент блокирует обновление другого - например тестовый стек тянет старые браузерные зависимости и мешает поднять runtime;

  • в репозитории не хватает правил для AI IDE или они плохо оформлены - агентам приходится каждый раз заново угадывать соглашения проекта;

  • часть долга нельзя закрыть в одном репозитории - он требует координации на уровне нескольких проектов или всей компании;

Слепые прослушивание - наш метод
Слепые прослушивание - наш метод

Каждый запах имеет вес. Например, неподдерживаемый runtime бьёт по оценке сильнее, чем небольшое отставание вспомогательного инструмента; дублирование решений в одной категории важнее, чем мелкая возможность почистить lockfile.

Итоговая оценка считается воспроизводимо:

score = max(0, 100 - sum(penalties))

Мне было важно, чтобы запуск скилла на одном и том же коммите давал один и тот же score. Мне было важно, чтобы это был не "взгляд LLM на проект", а стабильная метрика, к которой можно вернуться после миграции и увидеть, стало лучше или нет.

Процесс начинается с порядка действий

На выходе tech-debt даёт не просто список проблем, а план: что чинить первым, что можно сделать в рамках текущего репозитория, что требует внешней координации, и какой skill нужен для следующего шага.

node_eol / node_outdated

bump-node-major

yarn_classic / yarn_berry_pre_v4

bump-yarn

storybook_outdated

bump-storybook

eslint_outdated

bump-eslint

codecept_present

migrate-codecept-to-playwright

deprecated_packages

cleanup-unused-deps

duplicates_bundler

keep rspack; drop webpack

Главная проблема, с которой столкнулся разработчик на первом проекте, была не в том, что "непонятно, как поднять версию". Проблема была в зависимостях между миграциями. Node нельзя нормально обновить, пока какой-нибудь пакет жёстко тянет старый canvas или puppeteer. Переход на новый Storybook может упереться в TypeScript, ESM или пакетный менеджер. Эти зависимости тоже нужно было заложить в модель, иначе вместо плана получается список "хороших" советов в случайном порядке.

Поэтому каждый migration skill должен начинаться с pre-flight проверки: можно ли запускать его прямо сейчас. Если нельзя, он должен объяснить, что именно блокирует запуск, какой skill применить раньше или что нужно доработать вручную: закрепить Node в .nvmrc, убрать deprecated package, обновить package manager, разнести две миграции по разным MR, подготовить тестовую базу.

Разным миграциям нужны разные правила

Второй тип - bump-* скиллы. Они поднимают версии: bump-node-major, bump-yarn, bump-eslint, bump-storybook, bump-typescript, bump-rspack, bump-husky. В них главное не "поставить latest", а пройти миграцию маленькими шагами: один major hop, отдельный MR, pre-flight проверки, явные stop conditions.

Третий тип - migrate-* скиллы. Они переводят проект с одного решения на другое: migrate-codecept-to-playwright, migrate-webpack-to-rspack. Это уже не просто подъём версии, а смена инструмента, поэтому там больше правил про границы миграции, совместимость конфигов и то, что нельзя смешивать в одном MR.

Четвёртый тип - подготовительные и санитарные скиллы вроде cleanup-unused-deps. Они не всегда выглядят эффектно, но часто уменьшают поверхность перед большой миграцией: меньше старых пакетов, меньше ложных блокеров, меньше кода, который может сломаться по дороге.

Меньше магии, больше повторяемости

Всё, что можно было сделать детерминированно, я старался выносить в scripts/. Скрипт лучше подходит для механической работы: прочитать package.json, найти версии, проверить lockfile, посчитать score, построить diff. Он не галлюцинирует, одинаково работает на одном и том же commit и выполняется локально.

LLM при этом остаётся не без работы. Она помогает принять решение, объяснить план, разобрать ошибку, переписать конфиг или адаптировать миграцию под конкретный проект. Но чем больше рутины делегировано скриптам, тем меньше модель тратит контекст на механические проверки и тем меньше шансов, что она "увидит" в репозитории то, чего там нет. Токены тратятся не на сам факт локального выполнения скрипта, а на то, что мы передаём модели: промпты, файлы, код, stdout и её ответы. Поэтому большой сырой вывод скрипта всё равно лучше фильтровать и структурировать.

Можно ли сделать диагностику переносимой?

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

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

Так появился публичный репозиторий sergeychernov/repo-audit-skills. В нём есть более универсальный audit-debt: он не знает особенностей моей компании, внутреннего tech radar и конкретных корпоративных правил. Вместо этого он работает от профиля репозитория: после audit-init читает .audit/profile.json, проверяет только релевантные сегменты стека, сравнивает версии с npm latest, учитывает deprecated packages, считает score 0-100 и пишет отчёт в .audit/reports/debt.json.

То есть внутренний tech-debt был заточен под нашу реальность и маршрутизацию на конкретные корпоративные migration skills, а публичный audit-debt стал более переносимой версией идеи: сначала обнаружить стек, потом посчитать технический долг по понятным правилам, а уже после этого предлагать действия. Этот репозиторий я тоже планирую развивать. Когда он станет достаточно зрелым, скорее всего, напишу о нём отдельную статью.

Каждая миграция доучивает skill

Материал для первых скиллов я брал не из головы. У нас уже был реальный MR сотрудника, который обновлял первый проект. Я разобрал его как рабочий сценарий и вытащил инженерные решения: какой порядок шагов сработал, какие ошибки встретились, какие проверки были нужны, где нельзя смешивать две миграции в одном MR. Всё это превращалось в SKILL.md, вспомогательные scripts, assets/blockers.json, references и templates.

Потом я применял эти скиллы на новом проекте. Когда встречался с новой проблемой, решал её и возвращал знание обратно в скилл. Если находился новый блокер - он попадал в blockers. Если появлялся повторяемый pre-flight check - становился скриптом. Если выяснялось, что какую-то миграцию нельзя смешивать с другой, это становилось жёстким правилом.

Skill не рождается идеальным. Каждый следующий проект может его улучшить
Skill не рождается идеальным. Каждый следующий проект может его улучшить

Самое важное изменение было не в том, что LLM начала "лучше писать код". Важнее было то, что у неё появился контекст, который не нужно заново объяснять каждый раз. Скилл задавал рамку: что проверить, где остановиться, что не трогать, какие артефакты должны остаться после шага.

Репозитория со skills недостаточно

На следующем проекте я потратил примерно вдвое меньше времени и довёл обновление до конца. Но главный результат был даже не в этом. После работы остался артефакт: набор скиллов, который можно было применить ещё раз.

И тут появилась следующая проблема.

Когда скиллы лежат только у тебя локально, это личное ускорение. Когда они нужны команде, их надо как-то распространять. Первое очевидное решение - вынести их в отдельный git-репозиторий. Но репозиторий отвечает только на вопрос "где хранить". Он не отвечает на вопросы "как установить", "как обновить", "как подключить в конкретный проект", "как поставить глобально", "как не копировать руками" и "как сделать так, чтобы это работало не только в Cursor".

Мне нужен был слой поверх git-репозитория со скиллами.

Как доставлять skills без копирования руками?

Так появился ide-agents.

Первую версию я сделал в ночь с пятницы на субботу. Боль уже была понятна. Хотелось простой вещи: скиллы и агенты лежат в git-репозитории, а человек из команды может установить их глобально или в конкретный проект без копирования файлов руками.

Ключевой идеей стали symlink. Репозиторий со skills и agents клонируется в пользовательскую папку ide-agents ~/.ide-agents/repos/<repo>, и дальше обновляется обычным git pull. А установка конкретного skill или agent - это не копирование файлов, а создание symlink из пользовательских или проектных настроек IDE на папку артефакта внутри локального репозитория.

Если копировать скилл в .cursor/skills или другую папку IDE, сразу появляются проблемы: копия устаревает, непонятно, откуда она взялась, обновления надо разносить руками. С symlink источник остаётся в клонированном репозитории. Обновление skills - это pull репозитория, установка глобально или в проект - добавление ссылки по нужному пути.

CLI как launcher, браузер как интерфейс

Сначала я думал сделать консольное приложение, как самая простая идея. Но чем дольше я думал про интерфейс, тем запутаннее он выглядел в CLI: выбрать репозиторий, увидеть список skills, включить global или project scope, управлять несколькими IDE, отключать артефакты, показывать ошибки git. Опыт проектирования внутренних инструментов подсказал: для такой задачи нужен не набор CLI-флагов, а нормальная админка.

В текущем виде ide-agents - это npm-пакет. Команда ide-agents создаёт ~/.ide-agents/, поднимает локальный Fastify server и открывает веб-интерфейс в браузере. Backend работает с git, файловой системой и symlink, а React UI даёт нормальный UX для подключения репозиториев и установки агентов и скиллов.

Мне вообще кажется, что паттерн "локальный сервер + браузерная админка" недооценён. Обычно выбор представляют как "CLI или полноценное desktop-приложение", но между ними есть удобная середина. CLI остаётся тонким launcher-ом: запустить процесс, выбрать порт, открыть браузер, остановиться по Ctrl+C. А всё, что требует состояния, таблиц, фильтров, модалок, ошибок и подтверждений, уезжает в нормальный web-интерфейс.

CLI сложно использовать, Desktop сложно поддерживать
CLI сложно использовать, Desktop сложно поддерживать

Для ide-agents это особенно хорошо легло на задачу. С одной стороны, инструменту нужен доступ к локальной файловой системе: создать ~/.ide-agents/, клонировать репозиторий, сделать git pull, просканировать SKILL.md, поставить symlink в пользовательскую или проектную папку IDE. С другой стороны, пользователю нужно не просто выполнить одну команду, а управлять каталогами, scopes, включёнными IDE, ошибками установки и состоянием артефактов. Делать это флагами в терминале можно, но быстро становится неудобно.

Локальный сервер решает обе проблемы. Он живёт на машине пользователя, работает с приватными репозиториями и локальными путями, не требует внешнего SaaS и не отправляет куда-то содержимое скиллов. А браузер даёт интерфейс, который легко развивать: карточки, списки, поиск, настройки, статусы, подсказки, подтверждения. Для внутренних developer tools такой формат часто оказывается проще desktop-приложения и дружелюбнее CLI.

Как выглядит установка глазами пользователя?

Экран репозиториев стал точкой входа: здесь подключаются публичные и приватные каталоги, виден текущий layout и состояние clone.

Подключение репозитория со скиллами
Подключение репозитория со скиллами

С точки зрения пользователя сценарий простой: добавить git-репозиторий со скиллами, выбрать нужный skill или agent, нажать Global или Project. Дальше ide-agents сам создаёт symlink в конфигурационную папку включённых инструментов. Для project-level установки он ещё добавляет управляемый блок в .gitignore, чтобы локальные IDE-ссылки не попадали в репозиторий проекта.

Подключение скиллов к проекту или глобально
Подключение скиллов к проекту или глобально

На экране skills важны не только названия, но и scope: один и тот же артефакт можно поставить глобально или только в текущий проект.

Сейчас ide-agents поддерживает Cursor, Codex, Claude Code и OpenCode. Это оказалось важным поворотом. В нашей компании Cursor является приоритетным инструментом, но доступ к токенам и подпискам есть не у всех и не всегда в одинаковом объёме. При этом сами скиллы можно переиспользовать в разных AI IDE. Значит, инструмент не должен быть менеджером только для Cursor.

Один менеджер для разных структур каталогов

Ещё одна важная часть - поддержка разных структур репозиториев. Внутренний каталог может жить как skills/<id>/SKILL.md. Публичные каталоги могут быть flat, где каждый skill лежит в корне. У OpenAI skills структура bucketed: skills/<bucket>/<id>/SKILL.md. ide-agents умеет сканировать эти варианты, читать frontmatter, показывать описания и ставить артефакты под плоским именем.

# nested
skills/my-skill/SKILL.md

# flat
my-skill/SKILL.md

# bucketed
skills/.curated/my-skill/SKILL.md
skills/.system/skill-creator/SKILL.md

Со временем добавилась поддержка agents, зависимостей agent -> skills, metadata из openai-style agents/openai.yaml, starter template для пустых каталогов, публичные suggested repositories и документация.

Подключение агентов к проекту или глобально
Подключение агентов к проекту или глобально

Agents подключаются по той же модели, но могут дополнительно тянуть связанные skills, если агент явно зависит от них.

Выяснилось, что skills - это только начало

Когда первая версия заработала, стало видно, что установка - только нижний слой. Если подключить несколько каталогов, в каждом из которых десятки скиллов, ручной просмотр быстро перестаёт работать. Нужен сквозной поиск: по названию, описанию, frontmatter и, возможно, по содержимому SKILL.md.

Почти сразу за этим появляется MCP. Многие полезные сценарии требуют не только инструкций, но и подключений к внешним системам: GitHub, GitLab, Jira, внутренним API, документации, registry. Хочется, чтобы ide-agents мог устанавливать и такие конфигурации, но без хранения секретов в репозитории. Для этого в шаблонах нужны placeholders для токенов и понятный момент, где пользователь заполняет локальные значения.

mcpServers:
  github:
    command: npx
    args:
      - -y
      - "@modelcontextprotocol/server-github"
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_PERSONAL_ACCESS_TOKEN}"

За MCP сразу тянутся зависимости между артефактами. Если агенту для ревью нужен GitHub, а скиллу для аудита нужен доступ к package registry или внутреннему techradar, это должно быть описано явно. Тогда установка артефакта становится не только symlink, а ещё и проверкой зависимостей: какие MCP-серверы нужны, какие переменные окружения ожидаются, что уже настроено локально, а что надо заполнить. Возможно, здесь стоит посмотреть в сторону claude и codex plugins, но модель нужно продумать аккуратно.

Ещё один слой - форматы репозиториев. Сейчас ide-agents уже поддерживает nested, flat и bucketed layouts, потому что реальные публичные каталоги устроены по-разному. Но это почти наверняка не финальная точка. Будут репозитории с monorepo-структурой, несколькими пакетами, registry metadata, версиями артефактов, maybe отдельными manifest-файлами. Если инструмент хочет быть менеджером экосистемы, а не только установщиком одного формата, ему нужно уметь добавлять такие layouts без переписывания всей модели.

ide-agents отвечает за доставку, не за содержание

При этом важно не перепутать ответственность. ide-agents не делает подключаемые скиллы правильными, безопасными или качественными сам по себе. Он не отвечает за то, что именно написано в чужом SKILL.md. Его задача другая: дать удобный способ установить, обновить и отключить skills/agents из публичных и приватных git-репозиториев.

И уже за рамками этой статьи остаётся следующий вопрос: какие ещё командные практики стоит упаковывать в skills и agents. Техдолг оказался удобным первым полигоном, потому что там есть понятные проверки, версии, блокеры и результат. Но та же логика может пригодиться и в других коллекциях: для discovery, для работы с интервью и customer development, для написания статей, для ревью документов, для повторяемых исследовательских процессов. Я пока не хочу смешивать всё это в одну историю: скорее всего, про такие наборы скиллов будут отдельные статьи.

От инженерной находки к командному процессу

Для меня эта история ценна именно этим переходом. Сначала была локальная боль: слишком много проектов, слишком много повторяющихся миграций. Потом появились скиллы как способ сохранить инженерный опыт. А потом понадобился инструмент, который делает этот опыт переносимым.

Если skills и agents - это упаковка знания, то ide-agents - это доставка этой упаковки до команды.

Проект открыт на GitHub: sergeychernov/ide-agents. Мне интересно проверять его на чужих сценариях. Если у вас уже есть коллекции skills или agents, нестандартный формат репозитория, кейс для Codex/Claude Code/OpenCode, идея для MCP-интеграции или просто боль, которую не закрывает текущая модель, приносите issue, pull request или описание кейса. Именно из таких историй обычно и появляются следующие полезные возможности.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как у вас сейчас живут LLM-наработки для разработки?
25%Не используем системно1
50%Каждый хранит у себя2
25%Собираем в docs/wiki1
0%Храним в git рядом с проектами0
0%Упаковываем в rules/skills/agents/plugins0
0%Есть отдельный процесс установки и обновления0
0%Другое (раскрою в комментариях)0
Проголосовали 4 пользователя. Воздержавшихся нет.