Skills — переносимые навыки

В предыдущей статье мы разбирали субагенты — механизм изоляции контекста для самодостаточных задач. Skills решают другую проблему: как переиспользовать сложную экспертизу (чеклисты, процедуры, соглашения) не засоряя каждый раз контекстное окно, и не создавая субагент только ради набора инструкций?

Ответ — прогрессивное раскрытие (progressive disclosure): Claude всегда знает, что умеет навык (описание), но загружает как это делать (тело SKILL.md) только в момент вызова. Длинный чеклист деплоя, гайдлайны ревью, спецификация API — всё это лежит на диске и не ест токены до тех пор, пока не понадобится.


Анатомия SKILL.md

Навык — это директория с обязательным файлом SKILL.md. Именно директория: рядом с файлом могут лежать скрипты, шаблоны, примеры — и всё это становится частью навыка.

~/.claude/skills/pr-checklist/
├── SKILL.md          # главные инструкции (обязательно)
├── security.md       # детальный чеклист безопасности
├── examples/
│   └── good-pr.md    # пример хорошего PR для ориентира
└── scripts/
    └── check-size.sh # скрипт проверки размера PR

Сам SKILL.md состоит из двух частей: YAML-frontmatter между --- и обычного markdown-тела.

---
name: pr-checklist
description: Code review checklist for pull requests. Use when user asks to review a PR or code changes.
when_to_use: Triggered by "review PR", "check this PR", "pre-merge checklist".
disable-model-invocation: false
allowed-tools: Read Glob Grep Bash(gh *)
---


Quick recall
Что минимально нужно, чтобы skill работал?
Quick recall
Какую проблему решают Skills по сравнению с просто загрузкой длинных инструкций в контекст?

Pull request review checklist

Before approving, verify:

  • [ ] Tests cover the new logic
  • [ ] No hardcoded secrets or credentials
  • [ ] Error handling is explicit
  • [ ] API changes are backward-compatible

For security details, see security.md.

For size check, run: bash scripts/check-size.sh


Обратите внимание на последние строки: `SKILL.md` намеренно лаконичен, он только указывает на детали. Claude читает `security.md` только если это нужно — основной файл не перегружен.

**Правило:** держите `SKILL.md` до ~500 строк. Подробности — в supporting files.

Check yourself
Посмотрите на структуру директории навыка: SKILL.md, security.md, examples/good-pr.md, scripts/check-size.sh. Какие из этих файлов Claude загрузит в контекст при старте сессии?

Где хранить навыки

Место хранения определяет видимость:

УровеньПутьВидимость
Личный~/.claude/skills/<name>/SKILL.mdВсе ваши проекты
Проектный.claude/skills/<name>/SKILL.mdТолько этот проект
Плагин<plugin>/skills/<name>/SKILL.mdГде установлен плагин
EnterpriseManaged settingsВсе пользователи организации

Проектные навыки стоит коммитить в репозиторий — команда получает их автоматически. Если вдруг в .claude/commands/ у вас лежат старые кастомные команды — они по-прежнему работают, но навыки предпочтительнее: они поддерживают supporting files и больше полей frontmatter.

Claude Code следит за директориями навыков в реальном времени: добавление или редактирование SKILL.md вступает в силу в текущей сессии без перезапуска.


Прогрессивное раскрытие в деталях

Механизм работает в три уровня:

flowchart TD A["Старт сессии"] --> B["Уровень 1: Обнаружение\nname + description всех навыков\n(несколько строк на навык)"] B --> C{"Запрос пользователя\nсовпадает с description?"} C -- Да --> D["Уровень 2: Активация\nЗагрузка тела SKILL.md\n+ выполнение !`команд`"] C -- Нет --> E["Навык не загружается\nтокены не тратятся"] D --> F["Уровень 3: Инструкции в контексте\nОстаются до конца сессии\n(или до компакции)"] F --> G["Claude работает\nс актуальными данными"]
flowchart TD
    A["Старт сессии"] --> B["Уровень 1: Обнаружение\nname + description всех навыков\n(несколько строк на навык)"] 
    B --> C{"Запрос пользователя\nсовпадает с description?"}
    C -- Да --> D["Уровень 2: Активация\nЗагрузка тела SKILL.md\n+ выполнение !`команд`"]
    C -- Нет --> E["Навык не загружается\nтокены не тратятся"]
    D --> F["Уровень 3: Инструкции в контексте\nОстаются до конца сессии\n(или до компакции)"] 
    F --> G["Claude работает\nс актуальными данными"]
Три уровня прогрессивного раскрытия: от описания до полного содержимого навыка

Уровень 1 — Обнаружение. При старте сессии Claude получает в контекст только имена и описания всех навыков (поля name, description, when_to_use). Это несколько строк на навык — накладные расходы минимальны даже при наличии десятков навыков.

Уровень 2 — Активация. Когда запрос пользователя попадает под описание навыка, Claude загружает полное тело SKILL.md. Динамический контент (shell-команды) выполняется прямо сейчас — и уже инлайнится в тело перед тем, как Claude его увидит.

Уровень 3 — Инструкции остаются. После загрузки тело навыка остаётся в контексте до конца сессии (или до авто-компакции). При компакции Claude Code сохраняет первые 5 000 токенов каждого активированного навыка; если их накопилось много — менее свежие могут выпасть.

Чтобы навык не активировался автоматически (только вручную через /name), добавьте disable-model-invocation: true. Наоборот, user-invocable: false скрывает навык из /-меню, но Claude продолжает подгружать его сам — полезно для фоновых соглашений.

---
name: deploy
description: Deploy the application to production
disable-model-invocation: true  # только /deploy, никаких сюрпризов
allowed-tools: Bash(./deploy.sh *)
---
Check yourself
Вам нужен навык `/deploy`, который Claude никогда не должен запускать сам — только вручную через команду. Какое поле frontmatter это обеспечит, и почему недостаточно просто не писать description?

Динамический контекст: !\command\``

Это, пожалуй, самая мощная фича навыков. Синтаксис ` !<команда> ` запускает shell-команду до того, как Claude видит содержимое навыка. Результат вставляется прямо в тело:

---
name: diff-review
description: Review the current git diff for risks and quality issues.
---


Quick recall
На каком этапе выполняются shell-команды вида `!`git diff HEAD`` в теле SKILL.md?

Current changes

!git diff HEAD

Your task

Analyze the diff above. Flag: missing error handling, hardcoded values,

breaking API changes, missing tests. Be specific about line numbers.


Когда кто-то вызывает `/diff-review`, Claude Code выполняет `git diff HEAD`, подставляет вывод на место строки с `!`, и только потом передаёт текст Claude. Модель работает с актуальными данными, а не со своими предположениями.

Для многострочных команд есть блочная форма:

````markdown
```!
node --version
npm list --depth=0
git log --oneline -5

````

Важный нюанс: shell-команды выполняются препроцессором, не Claude. Модель видит только текстовый результат — она не знает, что там стояла !-инструкция.


Аргументы

Навыки принимают аргументы через $ARGUMENTS (весь хвост после имени), $ARGUMENTS[N] или сокращённо $N:

---
name: fix-issue
description: Fix a GitHub issue by number
disable-model-invocation: true
arguments: [issue, priority]
allowed-tools: Bash(gh *) Read Glob
---

Fix GitHub issue #$issue with priority $priority.

1. Read the issue: !`gh issue view $issue`
2. Find affected files
3. Implement the fix following our conventions
4. Write tests and create a commit

Вызов /fix-issue 234 high подставит 234 вместо $issue и high вместо $priority. И заметьте: !\gh issue view $issue\`` выполняется с уже раскрытым аргументом — в контекст попадает реальный текст issue #234.

Ещё одна полезная переменная — ${CLAUDE_SKILL_DIR}: абсолютный путь к директории навыка. Удобно ссылаться на скрипты внутри навыка независимо от текущей рабочей директории:

!`bash ${CLAUDE_SKILL_DIR}/scripts/check-size.sh`

context: fork — навык в изолированном субагенте

Навык можно запустить не в основном диалоге, а в изолированном субагенте — для этого добавьте context: fork. SKILL.md становится задачей субагента:

---
name: deep-explore
description: Research a module or concept in depth
context: fork
agent: Explore
---

Research $ARGUMENTS thoroughly:

1. Find all relevant files using Glob and Grep
2. Read and understand the code, tests, and docs
3. Summarize findings with specific file references and line numbers

При вызове /deep-explore auth module Claude Code запускает встроенного субагента Explore с телом SKILL.md как задачей. Результат возвращается в основной диалог, не засоряя его промежуточными поисками. Поле agent принимает любое имя встроенного (Explore, Plan, general-purpose) или кастомного субагента из .claude/agents/.

Это интересное пересечение со Субагентами: context: fork — удобная обёртка, когда задача хорошо описывается статическим промптом. Для более гибких сценариев, где нужен кастомный системный промпт или условная логика, лучше создать полноценный субагент.

Check yourself
Навык с `context: fork` и `agent: Explore` вызывает пользователь. Получит ли этот Explore-субагент содержимое CLAUDE.md проекта?

Практический пример: навык для релизов

.claude/skills/release/
├── SKILL.md
├── changelog-template.md
└── scripts/
    ├── bump-version.sh
    └── check-ci.sh
---
name: release
description: Prepare and publish a release
disable-model-invocation: true
allowed-tools: Bash(git *) Bash(npm *) Bash(./scripts/*) Read Write
---

## Release context

- Current version: !`node -e "console.log(require('./package.json').version)"`
- Latest tag: !`git describe --tags --abbrev=0`
- Changes since tag: !`git log $(git describe --tags --abbrev=0)..HEAD --oneline`
- CI status: !`bash ${CLAUDE_SKILL_DIR}/scripts/check-ci.sh`

## Instructions

Prepare release $ARGUMENTS (e.g. "patch", "minor", "major"):

1. Verify CI is green (see above)
2. Bump version: `bash ${CLAUDE_SKILL_DIR}/scripts/bump-version.sh $ARGUMENTS`
3. Fill in [changelog-template.md](changelog-template.md) based on the commits above
4. Commit and tag: `git commit -am "chore: release vX.Y.Z" && git tag vX.Y.Z`
5. Prompt user to confirm before pushing

Первые строки тела — живые данные о текущем состоянии проекта. Claude не угадывает версию и не читает лишних файлов: всё инлайнится до того, как модель начнёт работу. Скрипты вынесены в scripts/ и вызываются через ${CLAUDE_SKILL_DIR}, работая правильно независимо от того, в какой директории открыта сессия.


Когда skill, а не subagent?

Оба инструмента расширяют возможности Claude, но по-разному:

Используйте навык, когда:

  • Нужно переиспользовать инструкции или соглашения в основном контексте
  • Хотите, чтобы Claude применял знания по ходу работы, а не как отдельную задачу
  • Есть supporting files (шаблоны, скрипты), которые стоит держать рядом
  • Хотите вызвать через /name или чтобы Claude активировал сам

Используйте субагент, когда:

  • Задача самодостаточна и её результат не нужен в главном диалоге
  • Нужна полная изоляция контекста
  • Требуется кастомный системный промпт и набор инструментов
  • Планируете параллельный запуск нескольких экземпляров

Оба механизма дополняют друг друга: субагент с полем skills: получает навыки как прелоадированный контекст, а навык с context: fork запускается в изолированном субагенте.


See also