Двенадцать дней от «если вам это нужно» до Tetris
Claude Code Mods — это TypeScript-модули, которые работают внутри движка Claude Code и подключаются к его событиям в виде функций. Boris Cherny, который возглавляет направление Claude Code в Anthropic, анонсировал их пятью словами: «Claude mods are landing now». Пост собрал 2 400 лайков, и кто-то уже успел собрать Tetris прямо в терминале. Tetris, Doom и питомец, который растёт, пока Claude прогоняет ваши тесты, — всё это отрисовывается над полем промпта, без единого токена.
Анонс не ссылается ни на одну страницу документации. Вместо этого — ссылка на issue в GitHub, открытый инженером Anthropic на 12 дней раньше, с одним прописанным в нём условием. Alice Poteat написала, что реакция сообщества, скорее всего, и определит, выйдет ли функция вообще. Спустя 177 комментариев люди уже вовсю тестировали флагованный бинарник, замеряли его тайм-ауты и собирали на нём игры.
| Показатель | Значение |
|---|---|
| Лайков под анонсом | 2 400 |
| Комментариев в issue на GitHub | 177 |
| Типизированная поверхность в сборке этой недели | 10 700 строк |
| Событий на существительных (сборка из issue-треда) | 84 на 19 |
| Mod'ов на GitHub за 48 часов | 31 |
На момент написания страница документации отдаёт 404. Эта статья разбирает четыре способа расширить Claude Code, один полезный Mod, который мы собрали и нарочно сломали, и то, что всё ещё нестабильно, прежде чем вы выпустите свой.
Mod — это функция посередине
Дерево исходников определяет это одним предложением: Mod — это плагин Claude Code, поведение которого живёт в hooks-модуле. Одна запись регистрации подключает события движка в виде функций. На диске это папка плагина, hooks manifest, называющий ровно один модуль, и сам модуль.
Каждый хук — это функция от трёх вещей: $, двери, через которую проходит любой побочный эффект; события; и продолжения — остальной части цепочки под вами. Хуки вложены друг в друга, как middleware. Тот, что зарегистрирован первым, владеет событием, и ничто дальше по цепочке не может его подавить. Этот порядок задаётся конфигурацией, а не установкой. Как говорит Alice Poteat, порядок определяется конфигурацией, а не тем, когда вы установили хук.
Никакого фонового доступа нет. Всё, что делает Mod, проходит через $, поэтому администратор может аудировать, разрешать, запрещать или логировать любое событие. Один из комментаторов сформулировал это так: то, что сделал плагин, — это в точности те вызовы, которые он совершил. Один хук на * видит все события, так что журнал аудита — это одна функция. Mod умеет рисовать, потому что интерфейс — это React. Он работает в том же процессе, на Bun, за 50 микросекунд на 99-м перцентиле. Включается одной переменной окружения. То, что именно будет жить в $, всё ещё дорабатывается вместе с партнёрами раннего доступа.
Четыре способа расширить Claude Code — и когда какой нужен
Shell hook — это скрипт, который движок вызывает в фиксированный момент. Он получает JSON на стандартном вводе и отвечает кодом выхода. У ответа есть потолок: 8 000 символов контекста обратно, а для некоторых хуков — 2 000. По словам Pratham, на Windows они часто ломаются самым странным образом.
Плагин — это коробка. Один манифест объединяет скиллы, агенты, хуки и MCP-серверы. Он устанавливается из marketplace или загружается прямо из папки на диске, и одна команда проверяет коробку прежде, чем что-либо запустится.
Скилл — это текст, который модель читает, когда он ей нужен. Тело скилла загружается только тогда, когда приходит подходящий промпт. Это по-прежнему самый дешёвый способ изменить поведение.
Mod — это та же коробка плюс ещё один файл: hooks manifest, называющий модуль, а сам модуль — это TypeScript, типизированный, работающий в том же процессе, на каждом событии движка. В этом всё отличие.
| Механизм | Что это | Работает | Потолок |
|---|---|---|---|
| Shell hook | Скрипт, вызываемый в фиксированный момент | Отдельный процесс, код выхода | 8 000 символов обратно (2 000 для некоторых хуков) |
| Плагин | Набор скиллов, агентов, хуков, MCP-серверов | Устанавливается или загружается с диска | Проверяется перед запуском |
| Скилл | Текст, загружаемый по подходящему промпту | В контексте модели | Самое дешёвое изменение |
| Mod | Плагин плюс TypeScript hooks-модуль | В том же процессе, на каждом событии | Типизированный, ранний доступ |
Типы приходят из одной slash-команды, которая записывает прямо в ваш проект полный список того, что предлагает $. Старые shell hooks не выведены из обращения, а обёрнуты. На ранней сборке Spencer Morley наблюдал, как обёртка не загрузилась, но осталась объявленной. Правило простое: чтобы изменить то, что знает Claude, — пишите скилл; чтобы запустить скрипт в определённый момент — shell hook; чтобы выпустить набор — плагин; чтобы встроиться внутрь движка — Mod. Shell hook по-прежнему работает везде, где флаг выключен.
Три собственных Mod'а Anthropic — по исходному коду
Три Mod'а поставляются прямо внутри бинарника, и их исходники лежат на GitHub: security-дефолт, панель diff и телеметрия.
Security-дефолт стоит снаружи всех остальных. На машине с managed settings или в организации уровня Team или Enterprise ничто из того, что устанавливает пользователь, не оказывается выше него. Он подключается к 12 событиям, и каждый хук делает одно из трёх: пропускает дальше пользовательский уровень, отклоняет вызывающего с пользовательского уровня по имени или пропускает без изменений. Он падает в закрытое состояние (fails closed), и комментарий в коде говорит об этом двумя словами. Именно это волновало тред: администратор убирает возможность из $, и ничто зарегистрированное ниже не может её вызвать. По словам одного из комментаторов, это принципиально отличается от просьбы к плагину чего-то не делать.
Diff — это панель рядом с транскриптом, показывающая незакоммиченные изменения сессии файл за файлом, обновляющаяся по мере того, как Claude редактирует. Она регистрируется при старте сессии и занимает 27 вспомогательных файлов — не игрушка.
Телеметрия добавляет существительное в $ прямо изнутри создания движка. Она дожидается того, что находится ниже, и возвращает это плюс саму себя. Работает только во внутренних сборках.
В README сказано запускать один из исходников и тестировать один из исходников. Help в сегодняшней сборке перечисляет validate, eval и details. В списке нет test, хотя help для test всё ещё отвечает. Встроенный уровень также отклоняет вашу копию: выпустите плагин с одним из этих имён — и бинарник загрузит свой собственный.
Сорок две строки: Mod, который прячет секреты от модели
Slash-команда, которая записывает типы, на этой сборке выдаёт 11 700 строк: 84 события на 23 существительных. Хук вызова инструмента отвечает результатом или отказом, но никогда текстом. Это задано ядром (core).
Mod состоит из трёх файлов: манифеста плагина, hooks manifest с его единственной строкой и самого модуля. Модуль — это 42 строки. Он дожидается того, что находится ниже, вычищает результат и возвращает его обратно. Четыре паттерна покрывают два формата ключей вендоров, GitHub-токен и всё, что присвоено переменной с именем key, secret или token.
Validate читает исходник до запуска. Он называет событие, к которому подключается модуль, и единственную вещь, которую тот вызывает на $. Единственное предупреждение — отсутствующий author. При загрузке с диска с включённым флагом тестовый файл содержит два ключа, оба заведомо фальшивые, и модель читает «redacted». Своими словами: значения вернулись как redacted, так что она не может увидеть, что в них.
| Показатель | Значение |
|---|---|
| Длина модуля | 42 строки |
| Задержка на переход, с учётом воркера | 28 мс |
| Токенов добавлено в сессию | 0 |
Движок логирует переход как resolved (разрешённый) hooks-модулем. В инвентаре нет ни скиллов, ни агентов — ничего, что работало бы постоянно. Остаётся одно ограничение: скрытое от модели не скрыто от экрана. Транскрипт по-прежнему показывает то, что вывел инструмент. Это уже другой Mod, как в одной строке заметил Max из Ship Notes.
Ломаем: медленная защита — это обойдённая защита
Тот же Mod, одна добавленная строка: sleep на 15 секунд перед вызовом того, что находится ниже. Через десять секунд движок сдаётся, сообщает, что хук превысил свой бюджет и был пропущен (skipped), и вместо него выполняется то, что находится ниже. Команда всё равно выполняется и печатает «hi».
Заменяем sleep на throw: 574 миллисекунды, тот же вердикт — skipped, и команда выполняется.
| Случай | Время | Вердикт |
|---|---|---|
| Здоровый хук | 28 мс | Resolved |
| Throw | 574 мс | Skipped, команда выполнена |
| Зависание | более 10 с | Skipped, команда выполнена |
Оба сбоя заканчиваются одним и тем же словом: skipped. Тред измерил эту асимметрию неделей раньше. Возможность, отсутствующая при загрузке, падает в закрытое состояние (fails closed). Хук, превысивший бюджет, падает в открытое состояние (fails open): громко, но в обход, по словам Spencer Morley. Блокировка без причины просто отправляет модель к другому инструменту. Pratham наблюдал, как она выбрала другой инструмент и всё равно записала файл.
Ответ, который лежит на столе, — это catch. Alice Poteat предлагает catch на возврате хука, который срабатывает, если вы работаете слишком долго или бросаете исключение. Переписанная запись всё равно требует пометки для модели: она видит то, что попросила записать — по соображениям кеширования, — поэтому вы дописываете строку контекста. Бюджет — это ещё и изоляция. Hooks worker работает отдельно, и когда он падает, движок пересоздаёт его и выключает хуки для этой сессии. Решение — не более длинный бюджет, а объявленный catch.
Сорок восемь часов Mod'ов — и что покупает одно предложение
Через два дня: Tetris над полем промпта и ещё семь игр, в которые можно играть, пока работает Claude, — и всё это без единого токена. Doom, оригинал 1993 года, работает в собственном процессе; Mod обращается к нему по локальному HTTP и перерисовывает картинку 10 раз в секунду. Есть дышащий пейсер в спиннере и модель для генерации историй на 260 000 параметров, работающая прямо внутри hooks worker, без единого API-токена.
Реестр просканировал 31 Mod через validate. 14 из них умеют запускать процессы на хосте. 13 видят каждый вызов инструмента.
Демо №8 из треда сообщества обещало, что одно предложение напишет плагин, который прячет секреты до того, как их прочитает модель. Мы попросили такой.
| Показатель | Значение |
|---|---|
| Время | 4 мин |
| Ходов (turns) | 34 |
| Стоимость | $1.23 |
| Строк (плюс тестовый файл) | 190, против наших 42 |
| Тесты | 4 проходят за треть секунды |
Он помечает то, что скрывает, по типу, проходит validate без замечаний и не требует ни API-ключа, ни вызова модели. Один из ответов в треде сформулировал так: allowlists — это продукт, Tetris — это демо.
Вывод: собирайте сейчас, выпускайте позже
Собственные цифры реестра — уже предупреждение. 14 из 31 Mod'а умеют запускать процессы на хосте, и единственная проверка — это статический footprint. Help для eval сам об этом говорит: прошедший набор тестов — это не проверка безопасности.
| Сигнал | Значение |
|---|---|
| Событий 8-го числа | 20 |
| Событий 15-го числа | 84 |
| Версий CLI за две недели | 14 |
| Баллов на Hacker News | 2 |
| Ответов на вопрос о совместимости | 0 |
10-секундный бюджет живёт в рантайме, а не в типах, как заметил Marat. Нет ни строки в changelog, ни страницы документации, ни поста о запуске. Конкурент утверждает, что Anthropic скопировала идею: Ahmad Awais указывает на mods в Command Code — и он же пишет их пример-mod, так что учитывайте это. Пост «ранний доступ, API может измениться» набрал 357 лайков.
Собирайте свой Mod прямо сейчас, если вы уже пишете хуки и хотите получить аудит, редактирование (redaction) или панель. Подождите, если планируете выпустить его для команды, — пока контракт не зафиксирован. Именно эта открытость и позволила пользователям за считаные дни найти и бюджет, который падает в открытое состояние, и несовпадение типов в вызове MCP, и сбой обёртки.
AIDive