Скиллы для AI-агентов
Сегодня добавил в Testo набор AI-скиллов — небольших инструкций, которые подгружает агент (Claude Code, Codex и компания), когда видит подходящую задачу. Лежат в папке skills/.
Что внутри
Девять скиллов, по одному на сценарий:
testo-write-tests— написать обычный #[Test]#[Test()]Явно помечает метод, функцию или класс как тест.-класс сAssert/Expect/ lifecycle-хуками.testo-data-driven— параметризовать тест: #[DataSet]#[DataSet(array $arguments, ?string $name = null)]Объявляет набор аргументов для параметризованного теста. Можно использовать многократно — каждый атрибут создаёт отдельный запуск., #[DataProvider]#[DataProvider(callable|string $provider)]Предоставляет данные для параметризованного теста из метода или вызываемого объекта., #[DataUnion]#[DataUnion(DataProviderAttribute ...$providers)]Объединяет данные из нескольких провайдеров в один последовательный набор., #[DataZip]#[DataZip(DataProviderAttribute ...$providers)]Объединяет провайдеры попарно по индексу., #[DataCross]#[DataCross(DataProviderAttribute ...$providers)]Создаёт все возможные комбинации из провайдеров (декартово произведение)..testo-flaky-tests— #[Retry]#[Retry(int $maxAttempts = 3, bool $markFlaky = true)]Объявляет политику повторного запуска теста при падении. vs #[Repeat]#[Repeat(int $times = 2, int $maxFailures = 0, bool $markFlaky = true)]Запускает тест фиксированное число раз и решает итог по порогу падений.: представляете, между ними есть разница.testo-inline-tests— #[TestInline]#[TestInline(array $arguments, mixed $result = null)]Объявляет встроенный тест на методе или функции. прямо на методах вsrc.testo-benchmarks— #[Bench]#[Bench(array $callables, array $arguments = [], int $warmup = 1, int $calls = 1_000, int $iterations = 10)]Объявляет бенчмарк для сравнения производительности метода с альтернативными реализациями. и как читать Mean / Median / RStDev.testo-coverage— настройкаCodecovPlugin, #[Covers]#[Covers(string $classOrFunction, ?string $method = null)]Ограничивает, какой исходный код засчитывается в покрытие для данного теста., отчёты Clover / Cobertura / PHPUnit XML.testo-migrate-from-phpunit— миграция тестов с PHPUnit — хит.testo-plugin-author— написать собственный плагин Testo.testo-configure— собрать или поправитьtesto.php.
А зачем вообще скиллы, если есть llms.txt?
llms.txt — это что в API есть. Скиллы — это когда что применять и где грабли. Они короткие, активируются по триггерам (фразам пользователя), и каждый отправляет агента читать llms.txt за уточнениями. Так документация не дублируется, а скиллы не протухают вместе с API.
Но копировать их в каждый проект — лень
Сейчас, чтобы агент увидел эти скиллы, их надо положить в .claude/skills/ (или куда там настроен ваш агент). А значит — либо копи-пастить из vendor/testo/testo/skills/, либо ставить симлинки, либо… забить и не использовать.
Поэтому запилил отдельный пакет — llm/skills.
llm/skills — Composer-плагин для скиллов
Идея простая: Composer-пакет объявляет в composer.json, что он "донор" скиллов:
{
"extra": {
"skills": {
"source": "skills"
}
}
}А проект-потребитель ставит llm/skills, и при composer install скиллы из доверенных пакетов автоматически едут в .agents/skills/ (или куда настроите).
Никаких ручных копирований, никаких симлинков, никакого "ой, я забыл обновить SKILL.md после composer update".
Присоединяйтесь к тестированию
Только что выкатил llm/skills v1.0.0. Я не знаю, насколько он окажется востребованным, поэтому фичей особо не накидывал — собрал минимальный жизнеспособный механизм:
- Две команды:
composer skills:updateсинкает,composer skills:show— read-only инспектор, который показывает, что синкается, что пропущено и почему. Уupdateесть--dry-runдля превью без записи. - Декларирование папки со скиллами через
extra.skills.sourceвcomposer.jsonзависимостей. - Auto-discovery: поиск скиллов в пакетах без
extra.skillsпо папкеskillsв корне. - Whitelist доверенных вендоров:
extra.skills.trusted+--trust=PATTERN, поддержка wildcards (acme/*,*) и встроенный список уже доверенных пакетов. - Шорткат «назвал — значит доверяю»:
composer skills:update acme/fooобходит trust-список на время команды и попутно включает auto-discovery для этого пакета. - Транзакционность: если два донора объявили скилл с одинаковым именем — sync падает до того, как тронет файлы. Никаких полусобранных состояний.
- Non-destructive merge: локальные правки в
target/<skill>/переживают синк, перезаписывается только то, что реально несёт донор. Можно дописатьlocal.mdк чужому скиллу — он сохранится.
Если поставите и наткнётесь на грабли — кидайте issue в репозиторий. Особенно интересно услышать про сценарии, до которых я сам не додумался: чужие агенты, нестандартные раскладки, политики безопасности у больших команд.
Пакет навайбкожен на 95%, но переживать об этом не стоит: всё покрыто тестами с высоким MSI.
Быстрый старт
Поставить пакет
llm/skillsи обновить Testo.bashcomposer require --dev llm/skillsНастроить
composer.json, если надо складывать скиллы в другую папку (по умолчанию.agents/skills) или расширить список доверенных вендоров:json{ "extra": { "skills": { "target": ".claude/skills", "trusted": ["my-vendor/*"] } } }Чтобы посмотреть, какие скиллы доступны:
bashcomposer skills:show --discoverСкачать скиллы в проект:
Всё из списка доверенных вендоров:
bashcomposer skills:update --discoverКонкретные вендоры:
bashcomposer skills:update testo/*Донастроить
composer.jsonна автообновление.json{ "scripts": { "post-install-cmd": ["@composer skills:update"], "post-update-cmd": ["@composer skills:update"] } }
Всё — скиллы Testo лежат в .claude/skills/, и Claude Code подхватит их при следующем запуске. Используете другого агента — поменяйте target на нужный путь.
composer skills:show покажет, что куда поедет, без записи на диск. Удобно проверить перед первым update.
