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/ однозначно — это не «мигрируй сейчас или вымрешь», а расширение «вот тебе новые возможности, без принуждения». Разберись в отличиях, мигрируй по потребности и не гонись за косметической стройностью.