Skip to content

Commit e0c19d4

Browse files
committed
Add blog post about skills
1 parent 983cf3d commit e0c19d4

3 files changed

Lines changed: 261 additions & 0 deletions

File tree

‎blog/skills.md‎

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
title: "Skills for AI Agents"
3+
date: 2026-05-14
4+
description: "Testo now ships a set of AI skills for agents. Plus a Composer plugin that pulls skills from vendor packages into your project automatically."
5+
image: /blog/skills/preview.png
6+
author: Aleksei Gagarin
7+
outline: deep
8+
faqLevel: false
9+
---
10+
11+
# Skills for AI Agents
12+
13+
Today I added a set of **AI skills** to Testo — small instructions that an agent (Claude Code, Codex, and friends) loads on demand when it spots a matching task. They live in the [`skills/`](https://github.com/php-testo/testo/tree/1.x/skills) folder.
14+
15+
## What's inside
16+
17+
Nine skills, one per scenario:
18+
19+
- [`testo-write-tests`](https://github.com/php-testo/testo/blob/1.x/skills/testo-write-tests/SKILL.md) — write a regular <attr>\Testo\Test</attr> class with `Assert` / `Expect` / lifecycle hooks.
20+
- [`testo-data-driven`](https://github.com/php-testo/testo/blob/1.x/skills/testo-data-driven/SKILL.md) — parameterize a test: <attr>\Testo\Data\DataSet</attr>, <attr>\Testo\Data\DataProvider</attr>, <attr>\Testo\Data\DataUnion</attr>, <attr>\Testo\Data\DataZip</attr>, <attr>\Testo\Data\DataCross</attr>.
21+
- [`testo-flaky-tests`](https://github.com/php-testo/testo/blob/1.x/skills/testo-flaky-tests/SKILL.md) — <attr>\Testo\Retry</attr> vs <attr>\Testo\Repeat</attr>: believe it or not, they're not the same thing.
22+
- [`testo-inline-tests`](https://github.com/php-testo/testo/blob/1.x/skills/testo-inline-tests/SKILL.md) — <attr>\Testo\Inline\TestInline</attr> right on methods in `src`.
23+
- [`testo-benchmarks`](https://github.com/php-testo/testo/blob/1.x/skills/testo-benchmarks/SKILL.md) — <attr>\Testo\Bench</attr> and how to read Mean / Median / RStDev.
24+
- [`testo-coverage`](https://github.com/php-testo/testo/blob/1.x/skills/testo-coverage/SKILL.md) — setting up `CodecovPlugin`, <attr>\Testo\Codecov\Covers</attr>, Clover / Cobertura / PHPUnit XML reports.
25+
- [`testo-migrate-from-phpunit`](https://github.com/php-testo/testo/blob/1.x/skills/testo-migrate-from-phpunit/SKILL.md) — migrating tests from PHPUnit — a crowd favorite.
26+
- [`testo-plugin-author`](https://github.com/php-testo/testo/blob/1.x/skills/testo-plugin-author/SKILL.md) — write your own Testo plugin.
27+
- [`testo-configure`](https://github.com/php-testo/testo/blob/1.x/skills/testo-configure/SKILL.md) — assemble or fix up `testo.php`.
28+
29+
::: question Why skills at all if there's already `llms.txt`?
30+
[`llms.txt`](https://php-testo.github.io/llms.txt) tells the agent **what** the API offers. Skills tell it **when** to use what and **where the pitfalls are**. They're short, activated by triggers (phrases from the user), and each one sends the agent off to read `llms.txt` for the details. That way the documentation isn't duplicated, and the skills don't go stale alongside the API.
31+
:::
32+
33+
## But copying them into every project is a chore
34+
35+
Right now, for an agent to actually see these skills, you have to drop them into `.claude/skills/` (or wherever your agent is configured to look). Which means either copy-pasting from `vendor/testo/testo/skills/`, setting up symlinks, or… giving up and not using them at all.
36+
37+
So I built a separate package — **[`llm/skills`](https://github.com/roxblnfk/skills)**.
38+
39+
## `llm/skills` — a Composer plugin for skills
40+
41+
The idea is simple: a Composer package declares in its `composer.json` that it's a skill "donor":
42+
43+
```json
44+
{
45+
"extra": {
46+
"skills": {
47+
"source": "skills"
48+
}
49+
}
50+
}
51+
```
52+
53+
A consumer project installs [`llm/skills`](https://packagist.org/packages/llm/skills), and on `composer install` the skills from trusted packages **automatically** end up in `.agents/skills/` (or wherever you point it).
54+
55+
No manual copying, no symlinks, no more "oh no, I forgot to update SKILL.md after `composer update`".
56+
57+
## Come help test it
58+
59+
Just shipped [`llm/skills`](https://github.com/roxblnfk/skills) **v1.0.0**. I have no idea how much demand there'll be for it, so I deliberately didn't pile on features — just a minimal viable mechanism:
60+
61+
- Two commands: `composer skills:update` does the sync, `composer skills:show` is a read-only inspector that tells you what's getting synced, what's skipped, and why. `update` also has a `--dry-run` flag for previewing without writing.
62+
- Declaring the skills folder via `extra.skills.source` in a dependency's `composer.json`.
63+
- Auto-discovery: skills are picked up from a `skills` folder at the package root, even without an `extra.skills` declaration.
64+
- Trusted-vendor whitelist: `extra.skills.trusted` plus `--trust=PATTERN`, with wildcard support (`acme/*`, `*`) and a built-in list of already-trusted packages.
65+
- A "named it, trust it" shortcut: `composer skills:update acme/foo` bypasses the trust list for the duration of the command and turns on auto-discovery for that package along the way.
66+
- Transactional: if two donors declare a skill with the same name, the sync fails *before* touching any files. No half-applied state.
67+
- Non-destructive merge: local edits in `target/<skill>/` survive a sync — only files the donor actually ships get overwritten. You can drop a `local.md` next to someone else's skill and it'll stay.
68+
69+
If you install it and run into something — file an [issue on the repo](https://github.com/roxblnfk/skills/issues). I'm especially curious to hear about scenarios I didn't think of myself: other agents, unusual layouts, security policies in larger teams.
70+
71+
::: warning
72+
The package is 95% vibe-coded, but that's nothing to worry about: it's all covered by tests with a [high MSI](/docs/theory/mutation-testing.md).
73+
:::
74+
75+
## Quick start
76+
77+
1. Install `llm/skills` (and bring Testo up to date while you're at it):
78+
79+
```bash
80+
composer require --dev llm/skills
81+
```
82+
83+
2. Tweak `composer.json` if you want a different target folder (default is `.agents/skills`) or want to extend the trusted-vendor list:
84+
85+
```json
86+
{
87+
"extra": {
88+
"skills": {
89+
"target": ".claude/skills",
90+
"trusted": ["my-vendor/*"]
91+
}
92+
}
93+
}
94+
```
95+
96+
3. See what skills are available:
97+
98+
```bash
99+
composer skills:show --discover
100+
```
101+
102+
4. Pull skills into the project.
103+
104+
Everything from trusted vendors:
105+
106+
```bash
107+
composer skills:update --discover
108+
```
109+
110+
Or specific vendors:
111+
112+
```bash
113+
composer skills:update testo/*
114+
```
115+
116+
5. Wire up auto-update in `composer.json`:
117+
118+
```json
119+
{
120+
"scripts": {
121+
"post-install-cmd": ["@composer skills:update"],
122+
"post-update-cmd": ["@composer skills:update"]
123+
}
124+
}
125+
```
126+
127+
That's it — the Testo skills are now sitting in `.claude/skills/`, and Claude Code will pick them up on its next run. Using a different agent? Just point `target` at whatever path it reads from.
128+
129+
::: tip
130+
`composer skills:show` previews what's about to land where, without touching the disk. Handy to run before your first `update`.
131+
:::

‎public/blog/skills/preview.png‎

2.83 MB
Loading

‎ru/blog/skills.md‎

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
title: "Скиллы для AI-агентов"
3+
date: 2026-05-14
4+
description: "В Testo приехал набор AI-скиллов для агентов. И заодно — Composer-плагин, чтобы тащить скиллы из вендора в проект автоматически."
5+
image: /blog/skills/preview.png
6+
author: Алексей Гагарин
7+
outline: deep
8+
faqLevel: false
9+
---
10+
11+
# Скиллы для AI-агентов
12+
13+
Сегодня добавил в Testo набор **AI-скиллов** — небольших инструкций, которые подгружает агент (Claude Code, Codex и компания), когда видит подходящую задачу. Лежат в папке [`skills/`](https://github.com/php-testo/testo/tree/1.x/skills).
14+
15+
## Что внутри
16+
17+
Девять скиллов, по одному на сценарий:
18+
19+
- [`testo-write-tests`](https://github.com/php-testo/testo/blob/1.x/skills/testo-write-tests/SKILL.md) — написать обычный <attr>\Testo\Test</attr>-класс с `Assert` / `Expect` / lifecycle-хуками.
20+
- [`testo-data-driven`](https://github.com/php-testo/testo/blob/1.x/skills/testo-data-driven/SKILL.md) — параметризовать тест: <attr>\Testo\Data\DataSet</attr>, <attr>\Testo\Data\DataProvider</attr>, <attr>\Testo\Data\DataUnion</attr>, <attr>\Testo\Data\DataZip</attr>, <attr>\Testo\Data\DataCross</attr>.
21+
- [`testo-flaky-tests`](https://github.com/php-testo/testo/blob/1.x/skills/testo-flaky-tests/SKILL.md) — <attr>\Testo\Retry</attr> vs <attr>\Testo\Repeat</attr>: представляете, между ними есть разница.
22+
- [`testo-inline-tests`](https://github.com/php-testo/testo/blob/1.x/skills/testo-inline-tests/SKILL.md) — <attr>\Testo\Inline\TestInline</attr> прямо на методах в `src`.
23+
- [`testo-benchmarks`](https://github.com/php-testo/testo/blob/1.x/skills/testo-benchmarks/SKILL.md) — <attr>\Testo\Bench</attr> и как читать Mean / Median / RStDev.
24+
- [`testo-coverage`](https://github.com/php-testo/testo/blob/1.x/skills/testo-coverage/SKILL.md) — настройка `CodecovPlugin`, <attr>\Testo\Codecov\Covers</attr>, отчёты Clover / Cobertura / PHPUnit XML.
25+
- [`testo-migrate-from-phpunit`](https://github.com/php-testo/testo/blob/1.x/skills/testo-migrate-from-phpunit/SKILL.md) — миграция тестов с PHPUnit — хит.
26+
- [`testo-plugin-author`](https://github.com/php-testo/testo/blob/1.x/skills/testo-plugin-author/SKILL.md) — написать собственный плагин Testo.
27+
- [`testo-configure`](https://github.com/php-testo/testo/blob/1.x/skills/testo-configure/SKILL.md) — собрать или поправить `testo.php`.
28+
29+
::: question А зачем вообще скиллы, если есть `llms.txt`?
30+
[`llms.txt`](https://php-testo.github.io/llms.txt) — это **что** в API есть. Скиллы — это **когда** что применять и **где грабли**. Они короткие, активируются по триггерам (фразам пользователя), и каждый отправляет агента читать `llms.txt` за уточнениями. Так документация не дублируется, а скиллы не протухают вместе с API.
31+
:::
32+
33+
## Но копировать их в каждый проект — лень
34+
35+
Сейчас, чтобы агент увидел эти скиллы, их надо положить в `.claude/skills/` (или куда там настроен ваш агент). А значит — либо копи-пастить из `vendor/testo/testo/skills/`, либо ставить симлинки, либо… забить и не использовать.
36+
37+
Поэтому запилил отдельный пакет — **[`llm/skills`](https://github.com/roxblnfk/skills)**.
38+
39+
## `llm/skills` — Composer-плагин для скиллов
40+
41+
Идея простая: Composer-пакет объявляет в `composer.json`, что он "донор" скиллов:
42+
43+
```json
44+
{
45+
"extra": {
46+
"skills": {
47+
"source": "skills"
48+
}
49+
}
50+
}
51+
```
52+
53+
А проект-потребитель ставит [`llm/skills`](https://packagist.org/packages/llm/skills), и при `composer install` скиллы из доверенных пакетов **автоматически** едут в `.agents/skills/` (или куда настроите).
54+
55+
Никаких ручных копирований, никаких симлинков, никакого "ой, я забыл обновить SKILL.md после `composer update`".
56+
57+
## Присоединяйтесь к тестированию
58+
59+
Только что выкатил [`llm/skills`](https://github.com/roxblnfk/skills) **v1.0.0**. Я не знаю, насколько он окажется востребованным, поэтому фичей особо не накидывал — собрал минимальный жизнеспособный механизм:
60+
61+
- Две команды: `composer skills:update` синкает, `composer skills:show` — read-only инспектор, который показывает, что синкается, что пропущено и почему. У `update` есть `--dry-run` для превью без записи.
62+
- Декларирование папки со скиллами через `extra.skills.source` в `composer.json` зависимостей.
63+
- Auto-discovery: поиск скиллов в пакетах без `extra.skills` по папке `skills` в корне.
64+
- Whitelist доверенных вендоров: `extra.skills.trusted` + `--trust=PATTERN`, поддержка wildcards (`acme/*`, `*`) и встроенный список уже доверенных пакетов.
65+
- Шорткат «назвал — значит доверяю»: `composer skills:update acme/foo` обходит trust-список на время команды и попутно включает auto-discovery для этого пакета.
66+
- Транзакционность: если два донора объявили скилл с одинаковым именем — sync падает *до* того, как тронет файлы. Никаких полусобранных состояний.
67+
- Non-destructive merge: локальные правки в `target/<skill>/` переживают синк, перезаписывается только то, что реально несёт донор. Можно дописать `local.md` к чужому скиллу — он сохранится.
68+
69+
Если поставите и наткнётесь на грабли — кидайте [issue в репозиторий](https://github.com/roxblnfk/skills/issues). Особенно интересно услышать про сценарии, до которых я сам не додумался: чужие агенты, нестандартные раскладки, политики безопасности у больших команд.
70+
71+
::: warning
72+
Пакет навайбкожен на 95%, но переживать об этом не стоит: всё покрыто тестами с [высоким MSI](/ru/docs/theory/mutation-testing.md).
73+
:::
74+
75+
## Быстрый старт
76+
77+
78+
1. Поставить пакет `llm/skills` и обновить Testo.
79+
80+
```bash
81+
composer require --dev llm/skills
82+
```
83+
84+
2. Настроить `composer.json`, если надо складывать скиллы в другую папку (по умолчанию `.agents/skills`) или расширить список доверенных вендоров:
85+
86+
```json
87+
{
88+
"extra": {
89+
"skills": {
90+
"target": ".claude/skills",
91+
"trusted": ["my-vendor/*"]
92+
}
93+
}
94+
}
95+
```
96+
97+
3. Чтобы посмотреть, какие скиллы доступны:
98+
99+
```bash
100+
composer skills:show --discover
101+
```
102+
4. Скачать скиллы в проект:
103+
104+
Всё из списка доверенных вендоров:
105+
```bash
106+
composer skills:update --discover
107+
```
108+
109+
Конкретные вендоры:
110+
111+
```bash
112+
composer skills:update testo/*
113+
```
114+
115+
5. Донастроить `composer.json` на автообновление.
116+
117+
```json
118+
{
119+
"scripts": {
120+
"post-install-cmd": ["@composer skills:update"],
121+
"post-update-cmd": ["@composer skills:update"]
122+
}
123+
}
124+
```
125+
126+
Всё — скиллы Testo лежат в `.claude/skills/`, и Claude Code подхватит их при следующем запуске. Используете другого агента — поменяйте `target` на нужный путь.
127+
128+
::: tip
129+
`composer skills:show` покажет, что куда поедет, без записи на диск. Удобно проверить перед первым `update`.
130+
:::

0 commit comments

Comments
 (0)