$ sudo teach IT

Каждое утро повторяется один и тот же ритуал: вспомнить, что вы вчера сделали, посмотреть, что осталось незакоммиченным, и сформулировать три пункта для команды. Данные для этого отчёта лежат прямо под рукой — в git-истории и рабочем дереве, — но собираются они руками, каждый раз заново, и что-нибудь обязательно забывается.

Это идеальная форма для скилла: процедура фиксированная, источник данных известен, результат нужен в одном и том же формате. В этом уроке мы соберём скилл /standup от наивной версии до рабочей и по дороге разберём, почему каждое решение принято именно так. После урока вы сможете превращать в скиллы собственные ежедневные ритуалы.

Что уже умеем / что добавим

Вы уже знаете, из чего состоит скилл: директория, файл SKILL.md, YAML-frontmatter и markdown-инструкции. Знаете, что тело скилла попадает в контекст только при вызове, а имя команды берётся из имени директории. Теперь мы применим это к живой задаче и добавим главный приём этого урока — динамический контекст: команды, которые выполняются до того, как содержимое уйдёт модели.

Что вы узнаете в рамках статьи

  • Как выбрать задачу, из которой получится полезный скилл
  • Чем плоха инструкция «посмотри, что я делал» без данных
  • Как встроить вывод git-команд в тело скилла через !команда``
  • Зачем скиллу allowed-tools, || true и disable-model-invocation
  • Как быстро итерировать по скиллу и где его хранить

Ключевые термины

  • Динамический контекст — синтаксис !команда``, при котором команда выполняется до отправки содержимого скилла модели, а её вывод занимает место плейсхолдера.
  • Плейсхолдер — место в теле скилла, куда подставляется результат: вывод команды или значение аргумента.
  • Инвокация скилла — один запуск скилла: подстановка динамических данных, рендер содержимого и передача его модели.
  • allowed-tools — список инструментов, которыми можно пользоваться без запроса разрешения в течение хода, вызвавшего скилл.
  • disable-model-invocation — поле frontmatter, запрещающее Claude загружать скилл самостоятельно; остаётся только ручной вызов /имя.

Наивная версия: инструкция без данных

Начнём с самого очевидного варианта. Создаём директорию и кладём в неё файл:

mkdir -p ~/.claude/skills/standup
$EDITOR ~/.claude/skills/standup/SKILL.md
---
description: Собирает стендап-отчёт за рабочий день
---

Посмотри, что я делал сегодня в этом репозитории, и собери стендап:
что сделано, над чем идёт работа, что мешает.

Формально это работает. Практически — разочаровывает. Claude приходится самому догадываться, откуда взять данные: он выберет какие-то git-команды, возможно не те, возможно с другими границами по времени. Завтра он выберет другие. Результат нестабилен от запуска к запуску, а на сбор данных тратится несколько лишних ходов. Вы описали цель, но не описали процедуру, хотя процедура вам как раз известна.

Рабочая версия: данные приходят раньше модели

Правильное решение — вшить команды прямо в тело скилла. Синтаксис !`команда` выполняет команду до того, как содержимое отправится модели, и подставляет вывод на место плейсхолдера. Claude получает уже готовые данные, а не задание их добыть.

---
description: Собирает стендап-отчёт за день по git-истории
argument-hint: [период]
disable-model-invocation: true
allowed-tools: Bash(git log *) Bash(git status *) Bash(git branch *)
---

## Текущая ветка

!`git branch --show-current || true`

## Коммиты за сегодня

!`git log --since=midnight --author="you@example.com" --oneline || true`

## Незавершённая работа

!`git status --short || true`

## Инструкции

Составь стендап-отчёт по данным выше, строго в трёх разделах:
«Сделано», «В работе», «Блокеры». В «Сделано» — по одному пункту
на смысловую задачу, а не на каждый коммит. В «В работе» — изменённые
файлы и текущая ветка. В «Блокеры» — пиши «нет», если ничего не мешает.
Если коммитов за период нет, так и скажи, не выдумывай активность.

Важная деталь синтаксиса: ! распознаётся, только если стоит в начале строки или сразу после пробельного символа. Запись вида BRANCH=!`git branch --show-current` командой не считается — плейсхолдер останется литеральным текстом. Если команд подряд несколько, удобнее блок, открытый ```!:

## Окружение

```!
git branch --show-current
git status --short
```

Инженерные решения во frontmatter

Каждая строка frontmatter здесь появилась не для красоты.

disable-model-invocation: true — стендап нужен по расписанию человека, а не тогда, когда Claude решил, что момент подходящий. Побочный выигрыш: описание скилла перестаёт занимать место в контексте, потому что модели оно больше не нужно для выбора.

allowed-tools — обязательная строка, а не рекомендация. Внедрённые команды никогда не спрашивают разрешение. Если проверка разрешений вернула не «allow», вся инвокация прерывается с сообщением вида Shell command permission check failed for pattern "..." — отчёта вы не увидите вовсе. Предодобрение снимает вопрос.

|| true — страховка от падения. Неуспешная команда прерывает не свой плейсхолдер, а всю инвокацию: Claude вообще не получает содержимое скилла, вы получаете Shell command failed for pattern "...". Тонкость: для поисковых и сравнивающих команд код возврата 1 считается нормальным результатом, а коды 2 и выше — ошибкой. Для остальных ошибкой считается любой ненулевой код, поэтому || true дописывают там, где ненулевой код штатен.

argument-hint: [период] — подсказка в автодополнении. Сама подстановка аргументов в тело скилла — тема следующего урока; пока это просто анонс того, что скилл ожидает период.

Формат вывода и цикл итерации

Отдельно стоит явно задать структуру отчёта в инструкциях. Без этого каждый запуск даёт немного разный формат, и коллеги перестают воспринимать отчёт с одного взгляда. Ожидаемый результат выглядит так:

Сделано:
- Починил валидацию токена в auth-middleware (3 коммита)
- Обновил схему миграции для таблицы sessions

В работе:
- Ветка feat/session-cleanup, изменены 4 файла, не закоммичены

Блокеры:
- нет

Доводить скилл до этого вида удобно короткими шагами. Claude Code следит за директориями скиллов, и правки SKILL.md подхватываются в текущей сессии без перезапуска. Цикл «поправил файл — вызвал /standup — посмотрел вывод» занимает секунды. Перезапуск нужен лишь в одном случае: если вы создали каталог скиллов верхнего уровня, которого не было на старте сессии.

Осталось решить, где скилл живёт. ~/.claude/skills/standup/ — личная привычка, доступная во всех ваших проектах. .claude/skills/standup/ в репозитории — командное соглашение: файл едет в git, и стендап у всех получается одинаковым. Помните про приоритет: если скилл с таким именем есть на обоих уровнях, персональный перекроет проектный.

Частые ошибки

  • Забыть allowed-tools. Внедрённая команда не спросит разрешение — она просто оборвёт инвокацию с Shell command permission check failed. Перечисляйте паттерны для всех команд из тела скилла.
  • Оставить команду без || true. Одна неуспешная команда роняет весь скилл, а не свой блок. Особенно обидно, когда причина — пустой результат, а не реальная поломка.
  • Поставить ! не в начале строки. После другого символа плейсхолдер остаётся текстом, команда не выполняется, и Claude видит инструкцию вместо данных.
  • Не задать формат отчёта. Без явной структуры каждый запуск выдаёт свою композицию, и смысл автоматизации теряется.

Наиболее частые вопросы

  • Почему не оставить Claude свободу самому выбрать git-команды? — Потому что предсказуемость и есть цель. Вшитые команды дают один и тот же срез данных каждый день.
  • Что будет, если за день ничего не закоммичено? — git log вернёт пустой вывод, скилл отработает штатно. Поэтому в инструкциях полезно прямо сказать, как описывать день без коммитов.
  • Нужно ли перезапускать Claude Code после правки SKILL.md? — Нет, изменения подхватываются в текущей сессии.
  • Можно ли вызвать /standup, если стоит disable-model-invocation: true? — Да. Это поле закрывает только автоматическую загрузку моделью, ручной вызов работает.
  • Куда попадает stderr внедрённой команды? — При bash он по умолчанию сливается в stdout и оказывается во внедрённом тексте.

Итоги

Вы прошли путь, который повторяется почти на каждом полезном скилле: наивная формулировка цели, столкновение с нестабильностью, перенос известной процедуры внутрь скилла и обвязка, которая не даёт ему упасть. Теперь у вас есть рабочий /standup, а вместе с ним — понимание, почему allowed-tools и || true не мелочь, а условие того, что скилл вообще запустится.

Возьмите этот шаблон и приложите к другим своим ритуалам: сводка перед code review, чек-лист перед релизом, обзор чужих изменений за неделю. А на следующем уроке мы научим скиллы принимать аргументы — и тот самый [период] из argument-hint наконец начнёт работать по-настоящему.

На следующий урок