С чего всё начиналось
Монорепозиторий проекта состоит из 18 сервисов, каждый из которых живёт в своём поддомене. Есть мультиплеерные игры на Go, статические SPA, сервис аутентификации, поддержка пользователей и совместный просмотр видео через WebRTC. Инфраструктура держится на Docker Compose и Traefik. Разработка ведётся совместно с AI-агентом через Copilot Chat в VS Code.
После нескольких месяцев работы накопилось около 150 коммитов с реально интересными решениями: единая страница ошибок через Traefik middleware, non-root пользователи во всех Go-контейнерах, система "активного знания" которая превращает любое решение в автопроверку при коммите. Всё это осело в git-истории и нигде не было описано.
Проблема была понятна заранее: AI-агент отлично работает с кодом, но производством текста для внешней аудитории занимается реже. Мы решили создать специальный скилл, который даёт агенту конкретную инструкцию: собери материал из коммитов, напиши статью по строгим правилам и сохрани её в HTML-файл рядом с блогом.
Анатомия скилла
Файл скилла живёт в служебном каталоге репозитория .github/skills/blog-post/. Внутри лежат frontmatter с именем и описанием, а затем шесть разделов. Каждый раздел оформлен как инструкция с checkboxes и примерами кода, которую агент воспринимает как обязательный протокол.
---
name: blog-post
description: "Создать статью-кейс в стиле Habr по итогам текущей сессии..."
---
## Шаг 1 - Собрать материал
### Источники (читать все перед написанием)
```bash
git log --oneline -20
git show <hash> --stat
git diff HEAD~N HEAD -- domains/<domain>/
```
Также читать: TODO.md, README.md, исходники изменённых файлов.
**Что извлечь:**
- Исходная проблема или нестандартная техническая цель
- Конкретные числа: размер файлов, строки, время, запросы/сек
- Компромиссы и решения, которые были отброшены
Сбор материала как первый шаг
Ключевая идея в том, что агент всегда начинает с чтения, а не с написания. Скилл явно предписывает запустить git log --oneline -20, потом git show для интересных коммитов, а затем прочитать список задач затронутых доменов. Только после этого агент приступает к тексту.
Это важно по одной причине: AI очень хорошо генерирует общие слова про архитектуру, но конкретные цифры берёт только если они были в контексте. Когда агент читает git show a4a7666 --stat и видит "unit-тесты: +11 тестов (было 66 -> стало 77)" или "2 файла, 163 строки добавлено", эти числа попадают в статью. Без явного предписания агент их пропускает.
Из материала скилл предписывает извлечь пять конкретных вещей: исходную проблему, ограничения и мотивацию, подсистемы решения, конкретные числа и компромиссы. Списком, с bullet-points, чтобы агент прошёлся по каждому пункту и нашёл соответствующий материал в истории коммитов.
Правила стиля как технический контракт
Раздел "Правила написания" занимает примерно треть всего файла. Там два блока: запреты на конкретные конструкции и список запрещённых AI-клише. Запреты сформулированы максимально машиночитаемо, как lint-правила:
Строгие запреты:
- Запрещены предложения из 1-3 слов
- Запрещено использовать "—" (тире-разделитель)
- Запрещено использовать классические кавычки-ёлочки
- Запрещено употреблять сокращения вроде "т.к.", "т.е.", "и др."
- Запрещено олицетворение (персонификация объектов)
- Запрещена метафора внутри одной подсистемы
- Запрещён синтаксический параллелизм
- Минимум частиц "не" и приставок "не-" в тексте
Запрещённые AI-клише идут отдельным списком: "важно отметить", "в заключение", "в современном мире", "таким образом", "следует отметить". Это те фразы, которые особенно ярко выдают машинно-сгенерированный текст на Habr.
Технический стек для вывода
Блоговый домен работает на nginx alpine и раздаёт статику из директории public/. Здесь нет SSR и нет отдельного билд-шага. Каждая статья живёт как самостоятельный HTML-файл. Это накладывает конкретное ограничение: все зависимости должны лежать внутри файла или подключаться через CDN.
Скилл прописывает три CDN-библиотеки: highlight.js для подсветки кода, Mermaid для диаграмм, и стили из Cloudflare CDN для highlight.js темы. Инициализация двух библиотек через единый обработчик DOMContentLoaded, чтобы они гарантированно запускались после рендера DOM:
<!-- Подсветка кода -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<!-- Mermaid-диаграммы -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
hljs.highlightAll();
mermaid.initialize({ startOnLoad: true, theme: 'neutral' });
});
</script>
Отдельно прописан механизм fullscreen для схем и SVG-иллюстраций. Каждая диаграмма оборачивается в figure.zoomable, клик по которой открывает overlay с фиксированным позиционированием. Схему можно рассмотреть детально без скролла страницы.
Связь с системой "активного знания"
Скилл blog-post не появился в вакууме. В той же сессии был создан скилл memorize, который описывает как превращать любые договорённости из диалога в устойчивые части репозитория. Разница в природе артефакта: memorize фиксирует правило которое будет применяться автоматически при каждом коммите или редактировании, а blog-post создаёт публичный документ для внешней аудитории.
| Тип знания | Механизм фиксации | Когда применяется |
|---|---|---|
| Соглашение по коду | .github/instructions/*.instructions.md | При редактировании нужных файлов |
| Автопроверка | precommit-check.sh + unit-тест | При каждом коммите |
| Workflow / процесс | .github/skills/*/SKILL.md | При активной работе по скиллу |
| Инженерный кейс | blog.epich.ru/public/*.html | Публичная документация |
Эта классификация позволяет ответить на вопрос "куда положить знание" независимо от его природы. Конвенция о non-root пользователях в Dockerfile ушла в блокирующую проверку precommit-check. Алгоритм создания нового домена ушёл в отдельный скилл new-domain. Рассказ о том, как это всё строилось, идёт в блог.
Что получилось в итоге
Скилл занял 130 строк. Создание этой статьи заняло одну команду в чат: агент прочитал 7 коммитов, изучил два скилла, вытащил конкретные цифры из git show, написал текст по 14 правилам стиля и сохранил HTML с работающим Mermaid и подсветкой кода.
Скилл blog-post зарегистрирован в инструкциях Copilot и в таблице скиллов внутри audit-customizations. Это значит, что precommit-check проверяет существование такого скилла в папке и наличие записи в индексе, иначе коммит блокируется.
Дальнейший план состоит в том, чтобы добавить в скилл автоматическое обновление индекса блога и черновой режим, который мы использовали в этот раз: файл создаётся, но ссылка на него в главном индексе блога остаётся закрытой.