Скилл без аргументов умеет ровно одно: делать то, что в нём написано. Скилл с аргументами становится инструментом: /fix-issue 123 и /fix-issue 456 запускают один текст, применённый к разным задачам.
Вторая тема урока — динамический контекст: аргумент даёт то, что ввёл человек, а динамический контекст — то, что есть в системе прямо сейчас: текущий diff, список веток, версию Node. После урока вы будете уверенно писать плейсхолдеры и не попадаться на ловушки синтаксиса — а их здесь больше, чем в любой другой теме главы.
Что уже умеем и что добавим
Вы умеете создавать скилл, задавать description, управлять вызовом и ограничивать инструменты через allowed-tools. Пока содержимое скилла было статичным. Теперь добавим в него переменную часть: пользовательский ввод и вывод shell-команд.
Что вы узнаете в рамках статьи
- Как передать в скилл весь ввод целиком через
$ARGUMENTS - Как работают позиционные плейсхолдеры
$0,$1,$2и почему отсчёт идёт с нуля - Как объявить именованные аргументы полем
argumentsи подсказать их черезargument-hint - Что происходит, когда аргументов передали меньше, чем ожидает скилл
- Как встроить в скилл вывод shell-команды через
!команда`` и не сломать инвокацию
Ключевые термины
- Плейсхолдер — метка в теле скилла (
$ARGUMENTS,$1,$issue), на место которой Claude Code подставляет значение перед отправкой содержимого модели. - Позиционный аргумент — аргумент, определяемый порядком при вызове, а не именем.
$0— первый,$1— второй. - Именованный аргумент — позиционный аргумент, которому поле
argumentsдало имя; обращение к нему идёт как$имя. - Динамический контекст — вывод shell-команды, выполненной до отправки содержимого модели и вставленной в текст вместо плейсхолдера.
- Служебная подстановка — переменная Claude Code вида
${CLAUDE_SKILL_DIR}, разворачиваемая в путь или значение сессии.
Весь ввод целиком и позиционные плейсхолдеры
Самый простой способ — $ARGUMENTS. Он разворачивается в полную строку аргументов ровно так, как вы её ввели.
---
description: Fix a GitHub issue by number
argument-hint: [issue-number]
---
Find and fix issue $ARGUMENTS. Follow the coding standards of the repository.
Вызов /fix-issue 123 даст модели текст Find and fix issue 123. — остался только результат подстановки.
Когда аргументов несколько, нужны позиционные плейсхолдеры: $ARGUMENTS[N] или короткая форма $N. Здесь главная ловушка урока: отсчёт идёт с нуля. $0 — первый аргумент, $1 — второй, $2 — третий. Пример из документации:
---
name: migrate-component
description: Migrate a component from one language to another
---
Migrate the $0 component from $1 to $2.
Preserve all existing behavior and tests.
Вызов /migrate-component SearchBar JavaScript TypeScript превращается в Migrate the SearchBar component from JavaScript to TypeScript. Привычка из shell, где $1 — первый параметр, работает против вас: перепутав нумерацию, вы получите корректный, но бессмысленный промпт.
Разбор аргументов — shell-подобный, с учётом кавычек. Вызов /my-skill "hello world" second даст $0 = hello world и $1 = second. Без кавычек hello и world стали бы двумя аргументами.
Именованные аргументы и подсказка в автодополнении
Читать $0 и $2 в длинном скилле неудобно. Поле arguments позволяет дать позициям имена — строкой через пробел или YAML-списком:
---
description: Open a PR for an issue
arguments: [issue, branch]
argument-hint: [issue-number] [branch-name]
---
Теперь в теле пишется $issue и $branch. Важно, что именно изменилось: сопоставление всё равно позиционное. С arguments: [issue, branch] плейсхолдер $issue получит первый аргумент, $branch — второй, просто потому что так они объявлены. Это не «ключ=значение»: вызвать /open-pr branch=main issue=42 нельзя. Имена — это читаемость, а не свобода порядка.
Поле argument-hint на подстановку не влияет: это подсказка в автодополнении при наборе /. Формат — текст в скобках: [issue-number] или [filename] [format].
Когда аргументов не хватает
Здесь два разных поведения, и различие важное.
Индексный плейсхолдер без соответствующего аргумента остаётся в тексте как есть. Если скилл содержит $2, а вы передали один аргумент, модель увидит буквальные символы $2.
Именованный плейсхолдер без аргумента разворачивается в пустую строку. С arguments: [issue, branch] и вызовом /open-pr 42 строка Base branch: $branch придёт модели как Base branch:.
Ещё подстраховка: если аргументы переданы, но ни один плейсхолдер их не получил, Claude Code дописывает в конец содержимого строку ARGUMENTS: <ваш ввод>. Ввод не теряется.
Два мелких правила. Литеральный доллар перед цифрой или словом ARGUMENTS экранируется слэшем: чтобы в тексте осталось $1.00, пишите \$1.00. И наоборот: значение аргумента, содержащее текст вроде $1, вставится как литерал и повторно разворачиваться не будет.
Служебные подстановки и запуск скриптов
Кроме аргументов доступны переменные самого Claude Code: ${CLAUDE_SESSION_ID} — ID сессии, ${CLAUDE_EFFORT} — уровень усилий, ${CLAUDE_PROJECT_DIR} — корень проекта, ${CLAUDE_SKILL_DIR} — директория, где лежит SKILL.md этого скилла.
Последняя решает конкретную проблему. Скиллу часто нужен вспомогательный скрипт из своей папки, но рабочая директория сессии может быть любой, и относительный путь сломается. Ключевой момент: ${CLAUDE_SKILL_DIR} подставляется и в теле скилла, и в Bash-правилах allowed-tools. Предодобрение совпадает с реальной командой, и скрипт запускается без запроса разрешения:
---
name: render-chart
description: Render a chart from a CSV file
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/render.sh *)
---
Run `${CLAUDE_SKILL_DIR}/scripts/render.sh <csv-file>` to render the chart.
Динамический контекст: команда вместо плейсхолдера
Синтаксис !команда`` выполняет команду до того, как содержимое скилла отправится модели, и вставляет её вывод на место плейсхолдера. Claude получает готовые данные, а не задание сходить за ними.
---
description: Summarizes uncommitted changes and flags anything risky.
---
## Current changes
!`git diff HEAD`
## Instructions
Summarize the changes above in two or three bullet points, then list any risks.
Инлайн-форма распознаётся, только если ! стоит в начале строки или сразу после пробела. Написав KEY=!`date`, вы получите литеральный текст — команда не выполнится. Для нескольких команд есть многострочный блок, открытый ```!:
## Environment
```!
node --version
git status --short
```
Подстановка выполняется один раз по исходному файлу; вывод вставляется как обычный текст и повторно на плейсхолдеры не сканируется. Рабочая директория — текущая директория сессии, stderr сливается со stdout, таймаут — 2 минуты.
Самое важное — ошибки. Неуспешная команда прерывает всю инвокацию скилла, а не только свой плейсхолдер: Claude вообще не увидит содержимое, вы получите Shell command failed for pattern "...". Поэтому команду, которая штатно возвращает ненулевой код, дописывают через || true. Исключение — поисковые команды: код 1 у grep и подобных считается нормой, коды 2 и выше — ошибкой.
Разница между механизмами простая: аргумент даёт то, что ввёл человек, динамический контекст — то, что есть в системе на момент вызова. Чаще всего их комбинируют:
---
description: Review changes on a branch
arguments: [branch]
argument-hint: [branch-name]
---
## Diff against $branch
!`git diff main...HEAD --stat`
Review the changes above in the context of branch $branch.
Напоследок мелочь: скиллы можно «стакать» в начале одного сообщения. Ввод /write-tests /fix-issue 123 загрузит оба скилла и передаст 123 каждому.
Частые ошибки
- Считать, что
$1— первый аргумент. Отсчёт идёт с нуля: первый —$0. Сбоя не будет, промпт просто получит не те значения. - Ожидать синтаксис «ключ=значение». Поле
argumentsдаёт позициям имена, но аргументы всё равно читаются по порядку. Вызвать/skill issue=42нельзя. - Ставить
!не в начале строки.KEY=!cmd`` останется буквальным текстом: перед!стоит не пробел. - Не страховать команду от ненулевого кода. Одна упавшая команда обрывает всю инвокацию. Там, где ненулевой код нормален, добавляйте
|| true.
Наиболее частые вопросы
- Что вернёт
$3, если я передал два аргумента? — Ничего: индексный плейсхолдер без аргумента остаётся в тексте как есть, модель увидит символы$3. - А именованный плейсхолдер без аргумента? — Он разворачивается в пустую строку. Это ключевое отличие от индексных.
- Куда денется ввод, если в скилле нет плейсхолдеров? — Claude Code допишет в конец содержимого строку
ARGUMENTS: <ваш ввод>. - Как оставить в тексте знак доллара с цифрой? — Экранировать обратным слэшем:
\$1.00. - Зачем
${CLAUDE_SKILL_DIR}, если можно указать путь? — Он резолвится одинаково при любой рабочей директории и подставляется в том числе вallowed-tools, так что скрипт запускается без запроса разрешения.
Итоги
Вы разобрали самую синтаксически плотную часть главы. Теперь вы умеете принимать в скилл весь ввод целиком, разбирать его на позиции с отсчётом с нуля, давать позициям читаемые имена через arguments, подсказывать формат вызова через argument-hint и предсказывать поведение при нехватке аргументов. Вы также знаете, как втянуть в скилл живые данные командой !...``.
Стоит потратить время на практику: здесь ошибки самые незаметные, потому что скилл не падает, а просто работает не так, как вы задумали. Пройдите тесты и соберите пару скиллов с аргументами на своём репозитории. На следующем уроке мы посмотрим на поле context: fork — способ запустить скилл в изолированном контексте, чтобы объёмная задача не засоряла основной разговор.