Free

Від Slash Commands до Skills: коли і як мігрувати

Custom commands об'єднали зі Skills. Коли мігрувати на `.claude/skills/` і що отримуєш натомість.


Перші три статті повністю розібрали слеш-команди: від Markdown-файлу та ін'єкції через !команду до оркестрування через subagent і MCP. Нічого з цього не застаріло — але за лаштунками відбулося офіційне злиття: custom commands тепер входять до Skills.

Твій .claude/commands/review.md досі працює, /review так само доступний, змінювати нічого не треба. Але якщо хочеш, щоб команда обросла новими можливостями (кілька файлів, виконання у fork, автоматична активація за path), новий шлях — .claude/skills/review/SKILL.md. Ця стаття розʼясняє дві речі: як мігрувати і чи варто.


Мінімальна міграція: змінити один path — і все

Обіцянка сумісності від розробників однозначна: .claude/commands/deploy.md та .claude/skills/deploy/SKILL.md обидва реєструються як /deploy і поводяться однаково. У разі колізії імен перемагають skills.

Мінімальні кроки:

cd .claude/commands
mkdir -p ../skills/review
mv review.md ../skills/review/SKILL.md

У вмісті файлу не треба змінювати жодного рядка. YAML frontmatter, !`команда`, @file, $ARGUMENTS — усе залишається сумісним.

Але якщо обмежитися лише цим, читач слушно запитає: а навіщо тоді взагалі мігрувати? Відповідь у тому, що в директорію skill можна покласти скільки завгодно файлів, а command — лише один.


Навіщо мігрувати: чотири речі, яких немає у command

1. Допоміжні файли: винести довгі документи

SKILL.md — це точка входу, а в тій самій теці можна зберігати будь-які супутні файли. Уяви таку структуру:

.claude/skills/review/
├── SKILL.md            # entry point, короткі інструкції + посилання
├── checklist.md        # довгий чек-лист code review
├── examples/
│   └── good-diff.md    # позитивний приклад
└── scripts/
    └── lint.sh         # скрипт, який може викликати SKILL.md

Всередині SKILL.md на них посилаються через відносний path:

Переглянь поточний diff за критеріями з [checklist.md](checklist.md).
Див. [examples/good-diff.md](examples/good-diff.md) для очікуваного формату виводу.

Ці допоміжні файли не потрапляють у context автоматично — Claude читає їх за потреби. Офіційна рекомендація: тримати SKILL.md у межах 500 рядків, а решту виносити в допоміжні файли.

2. disable-model-invocation: які skills запускаються лише вручну

За замовчуванням Claude може сам вирішити викликати відповідний skill, якщо бачить слушний момент. Для команд із побічними ефектами на кшталт /deploy, /commit, /send-email — це небезпечно: ти не хочеш, щоб він «задеплоїв, бо код йому сподобався».

---
name: deploy
description: Деплой у продакшн
disable-model-invocation: true
allowed-tools: Bash(kamal deploy:*), Bash(git push:*)
---

З цим рядком /deploy запускається лише вручну — у діалозі Claude не викличе його з власної ініціативи.

Навпаки, user-invocable: false означає «викликати може лише сам Claude, але в меню / цього skill немає» — підходить для skills-фонових знань (наприклад, legacy-system-context, який Claude автоматично завантажує в потрібних ситуаціях і викликати який вручну не має сенсу).

3. context: fork: запускати skill у subagent

Це найбільше оновлення. У попередній статті ми бачили, що command через allowed-tools: Task може попросити модель підняти subagent — але опис «підніми Explore subagent, щоб…» доводилося писати вручну у самому prompt.

У SKILL достатньо одного рядка frontmatter:

---
name: deep-research
description: Глибоке дослідження символу
context: fork
agent: Explore
---

Дослідь усі використання $ARGUMENTS:
- усі точки виклику
- бізнес-сценарії
- альтернативні реалізації

Поверни зведення ≤300 слів.

Коли ти запускаєш /deep-research SomeClass, увесь SKILL.md стає prompt'ом окремого subagent, виконується агентом типу Explore і наприкінці повертає лише висновок. Context основної розмови залишається повністю чистим.

Це перетворює «підняти subagent» із текстового опису в prompt на декларативний атрибут skill.

4. paths: автоматична активація за типом файлу

---
name: rails-conventions
description: Кодові конвенції цього Rails-проєкту
paths: ["app/**/*.rb", "config/**/*.rb"]
---

Дотримуйся Rails-конвенцій проєкту:
- використовуй service object замість fat controller
- усі ActiveRecord scope мають бути іменованими
...

Коли ти редагуєш app/models/user.rb, цей skill автоматично додається в context; під час редагування package.json — ні. Точніше, ніж глобальне тло CLAUDE.md — фактично «CLAUDE.md, пошарований за path».


На практиці: апгрейд /plan до skill

Останній приклад /plan з попередньої статті був однофайловою command:

.claude/commands/plan.md

Версія як skill:

.claude/skills/plan/
├── SKILL.md
├── research-prompt.md     # інструкції для subagent 1
└── risk-prompt.md         # інструкції для subagent 2

SKILL.md:

---
name: plan
description: Сформувати план впровадження за Linear-тикетом
disable-model-invocation: true
allowed-tools: mcp__linear__*, Task, Read, Grep, Bash(git log:*)
---

## Context

@.claude/context/architecture.md

## Стан

!`git log --oneline -10`

## Завдання

Отримай опис і коментарі Linear-тикета $ARGUMENTS.

Через Task паралельно підніми два subagent:
1. Дослідження коду: prompt у [research-prompt.md](research-prompt.md)
2. Оцінка ризиків: prompt у [risk-prompt.md](risk-prompt.md)

Зведи обидва результати в: кроки впровадження + список ризиків + рекомендації щодо гранулярності commit.

Prompts двох subagent лежать в окремих файлах — їх можна правити, не чіпаючи SKILL.md. Сам skill залишається компактним, у межах 30 рядків, тоді як допоміжні файли за потреби можуть сягати й кількох сотень рядків кожен.

Якщо не хочеться самому оркеструвати subagents — можна піти радикальніше і кинути весь skill у fork, щоб агент Explore виконав усе одним заходом:

---
name: plan
context: fork
agent: Explore
allowed-tools: mcp__linear__*
---

/plan ENG-4213 → агент Explore в ізольованому context бере весь вміст SKILL.md як завдання → повертає лише фінальний план. Основна розмова залишається повністю чистою.


Коли мігрувати не потрібно

Не кожна command заслуговує на апгрейд. Залишатися в .claude/commands/ доречніше, коли:

  • Вистачає одного Markdown: немає що виносити у checklist, examples чи scripts.
  • Не потрібен fork: завдання щільно зчеплене з основною розмовою і потребує повної історії.
  • Не потрібна автоактивація за path: користувач усе одно запускає її вручну.
  • Не потрібен контроль доступу: нічого поганого, якщо Claude викличе її сам.

Прості /commit, /pr-desc і подібні — frontmatter плюс кілька рядків prompt — у .claude/commands/ виглядають навіть наочніше. Офіційно обидві форми співіснують, і жодну не депрекейтять.


Як виглядає співіснування

На сьогодні найохайніша організація .claude/:

.claude/
├── commands/           # легкі: один файл + простий prompt
│   ├── commit.md
│   └── pr-desc.md
├── skills/             # важкі: багато файлів / fork / контроль доступу
│   ├── plan/
│   │   ├── SKILL.md
│   │   ├── research-prompt.md
│   │   └── risk-prompt.md
│   ├── deploy/
│   │   └── SKILL.md    # disable-model-invocation
│   └── rails-conventions/
│       └── SKILL.md    # автоактивація через paths glob
└── context/
    └── coding-standards.md

Не варто мігрувати все скопом. Сигнал до міграції: «ця command починає розпухати» — понад 200 рядків, хочеться винести документацію, хочеться запускати у subagent. Тоді й змінити path — справа кількох хвилин.


Підсумок

Бажана можливість commands/ skills/
Шорткат-prompt в одному файлі
!`команда` / @file / $ARGUMENTS
Контроль доступу через allowed-tools
Допоміжні файли (посилання, scripts)
disable-model-invocation проти хибних спрацьовувань
Ізольований запуск через context: fork + agent:
Автоактивація за paths: glob

На перших трьох рядках commands і skills повністю еквівалентні; останні чотири — лише у skills. Береш те, що потрібно, решту не чіпаєш.

Офіційний вектор схиляється у бік skills, але обіцянка сумісності commands/ однозначна — це не «мігруй зараз або вимреш», а розширення «ось тобі нові можливості, без примусу». Розберись у відмінностях, мігруй за потреби і не женись за косметичною стрункістю.