Skip to main content
Команда claude plugin eval запускает ваш plugin на наборе тестовых кейсов и оценивает результаты. Каждый кейс — это реалистичный запрос плюс один или несколько graders. Grader — это проверка pass/fail того, что произвел Claude, например регулярное выражение для ответа, был ли вызван конкретный инструмент или рубрика, которую вторая модель оценивает в ответе. Вам не нужно писать набор вручную; claude plugin eval init спрашивает вас о вашем plugin, предлагает кейсы и graders, пробует их и записывает файлы, и вы можете попросить Claude сделать то же самое из уже открытой сессии. Используйте evals для:
  • Измерения того, насколько надежно ваш plugin направляет Claude к правильному результату
  • Выявления регрессий при изменении plugin или выпуске новой модели
  • Определения того, что plugin вносит в сравнении с отсутствием plugin
Эта страница предназначена для авторов plugin и skills, у которых есть работающий plugin и которые хотят протестировать его поведение, а также для команд, которые ограничивают изменения plugin в CI. Для итерации над одним skill внутри разговора Claude Code skill-creator plugin запускает аналогичное сравнение с собственным форматом evals/evals.json, и ни один инструмент не читает файлы кейсов другого. Чтобы создать plugin, см. Create a plugin; чтобы проверить файлы plugin на синтаксические и схемные ошибки, а не его поведение, используйте claude plugin validate.
Каждый запуск eval и каждый judge grader — это реальный вызов модели на вашем аккаунте, учитываемый в использовании вашего плана или счете API, поэтому сначала проверьте требования. Затем создайте свой первый eval suite или перейдите к Run evals in CI, если у вас уже есть один.

Требования

Для запуска plugin evals вам нужно:
  • Claude Code v2.1.269 или позже. Запустите claude --version для проверки и claude update для обновления.
  • Git 2.31 или позже, если git установлен. Запустите git --version для проверки. Со старой версией git, claude plugin eval останавливается перед запуском любого случая. Без git он работает нормально.
  • Директория plugin с манифестом plugin.json или .claude-plugin/plugin.json, или skills-directory plugin.
  • Та же аутентификация и поставщик модели, которые используют ваши обычные сессии Claude Code. Запуски eval, graders с оценкой judge и claude plugin eval init вызывают модель с вашими учётными данными, поэтому они расходуют лимиты использования вашего плана или учитываются в вашем счёте за API. Когда команда сообщает стоимость, эта цифра — оценка по прейскуранту этих вызовов. Если вы запускаете Claude Code в Amazon Bedrock, Google Cloud’s Agent Platform или Microsoft Foundry, запускайте набор тестов из оболочки, которая экспортирует те же переменные поставщика, что и ваши обычные сессии, поскольку каждый запуск наследует их от этой оболочки, как описано в разделе о поле env.

Как работает запуск eval

Eval suite находится в директории под названием evals/ внутри вашего plugin, расположенной так, как показано в Write and refine cases. Каждый case — это собственная поддиректория с prompt и одним или несколькими graders. Prompt — это что-то, что может напечатать человек, использующий ваш plugin, например запрос, который должен обработать один из его skills.

Что происходит во время запуска

Для каждого запуска case Claude Code запускает свежую, изолированную неинтерактивную сессию только с вашим plugin, отправляет prompt и позволяет Claude работать, пока он не закончит или не достигнет лимита turn или времени case. Затем каждый grader проверяет финальный ответ, полный транскрипт или файл, созданный Claude, и проходит или не проходит.

Как оценивается case

Один запуск недетерминированного агента говорит вам мало, поэтому каждый case по умолчанию запускается три раза. Оценка запуска — это доля его graders, которые прошли, взвешенная, если вы установили веса, и оценка case — это среднее значение по его запускам. Case проходит, когда его оценка соответствует --threshold, по умолчанию 1.0. При вызовах модели suite создает примерно cases × runs запусков агента с plugin и столько же для no-plugin baseline, плюс три коротких вызова judge на llm или baseline grader на запуск.

The no-plugin baseline

Высокая оценка сама по себе не говорит вам, что plugin помог, потому что Claude может работать так же хорошо без него. Чтобы разделить эти два, запуски каждого case повторяются без загруженного plugin, и вы получаете две оценки, WITH и W/OUT. Их разница, Δ, — это то, что внес plugin. Если case оценивается в 1.0 как с plugin, так и без него, plugin не является тем, что заставило его пройти. Два набора запусков называются with-arm и without-arm; Score against the no-plugin baseline охватывает, какие case запускают only with-arm и как graders оцениваются в обоих arms.

Создайте свой первый eval suite

Это пошаговое руководство по написанию одного кейса для вашего собственного плагина, его запуску и чтению результата. Перед началом убедитесь, что у вас есть:
  • Claude Code v2.1.269 или новее и другие требования
  • Терминал, открытый в корневой директории вашего плагина, той, которая содержит plugin.json или .claude-plugin/plugin.json
  • Один скилл в плагине, который вы хотите протестировать, и просьба, которую ввел бы пользователь и которая должна его вызвать
1

Создайте кейсы

Из корня плагина запустите:
Если Claude Code еще не доверяет этой директории, он сначала спрашивает Trust this plugin directory?; ответьте y.Затем открывается интерактивная сессия Claude Code. Claude читает ваш плагин и спрашивает вас, как должен выглядеть хороший результат, предлагает промпты, которые должны и не должны вызывать плагин, разрабатывает graders для каждого, один раз пробно запускает их, чтобы проверить их поведение, и записывает одну директорию кейса на каждый промпт в evals/, каждую названную по своему промпту.Когда Claude сообщит вам, что suite готов, выйдите из этой сессии с помощью /exit или Ctrl+D, чтобы вернуться в оболочку.Если у вас уже есть сессия Claude Code, открытая в корне плагина, вы можете вместо этого попросить Claude там запустить claude plugin eval init. Claude запускает команду и затем задает вам те же вопросы в этом диалоге.Если вы предпочитаете написать кейс самостоятельно, чтобы увидеть, что именно содержат файлы, следуйте разделу Написание кейса вручную и вернитесь сюда, чтобы запустить его.
2

Запустите suite

Вернитесь в оболочку в корне плагина и запустите каждый кейс в evals/:
Вы уже доверились этой директории на шаге 1, поэтому запуск начинается немедленно. Если вы вместо этого написали кейс вручную, запуск сначала спрашивает Trust this plugin directory? [y/N]; ответьте y. Раздел К чему имеет доступ запуск объясняет, на что вы соглашаетесь.Каждый кейс запускается три раза с вашим плагином и три раза без него, поэтому один кейс — это шесть запусков. По мере завершения каждого запуска печатается строка прогресса с оценкой этого запуска и вердиктом каждого grader.
3

Прочитайте сводку

Когда suite завершится, вы увидите таблицу сводки, за которой следует информация о том, куда был записан отчет:
WITH — это оценка кейса с загруженным вашим плагином, W/OUT — это оценка без него, а положительное Δ означает, что плагин повысил оценку. COST — это оценка стоимости вызовов модели по прейскуранту, а NOTES показывает объяснение неудачного grader с наибольшим весом или ошибку запуска из with-arm.
4

Откройте отчет и повторяйте

Откройте URL Published: или путь Report:, если строки Published: нет, чтобы увидеть вердикт и объяснение каждого grader для каждого запуска, а для llm graders — голоса judge и отрывок, который он оценивал. Строка Published: появляется, только когда ваш аккаунт может публиковать отчеты.Наиболее частое первое открытие — это Δ близко к нулю с неудачным grader tool_used: Skill кейса, что означает, что Claude не выбирает ваш скилл при естественной формулировке. Отрегулируйте description скилла, снова запустите claude plugin eval . и сравните.Чтобы повторять итерации по одному кейсу с меньшим числом запусков, запустите один arm один раз. Один запуск шумный, поэтому подтвердите любое изменение при трех запусках по умолчанию, прежде чем доверять ему. С одним arm таблица показывает столбцы SCORE и PASS% вместо WITH, W/OUT и Δ:
Замените <case-name> на одно из имен директорий в evals/.

Написание и уточнение кейсов

Кейсы, которые пишет claude plugin eval init, — это простые файлы, которые вы можете открыть, изменить и дополнить. Кейс — это каталог внутри каталога eval плагина, который содержит prompt.md, case.yaml или оба файла. Добавьте каждому кейсу хотя бы один grader в виде файла graders/<name>.md или записи graders: в case.yaml, потому что кейс без него не загружается. Чтобы сгруппировать кейсы, вложите их в каталог, который сам не является кейсом; все, что находится внутри каталога кейса, например graders/ и файлы fixtures, принадлежит этому кейсу. Это структура, которую создает claude plugin eval init, и именно ее следует использовать для новых suites. В справочнике по eval suite приведено полное дерево, включая mocks и результаты:

Напишите кейс вручную

Рекомендуемый путь — поручить Claude написание кейсов с помощью claude plugin eval init. Чтобы вместо этого написать кейс самостоятельно, начните с пустого шаблона. Следующая команда создает кейс с именем first-case с заготовкой prompt.md и одним grader-заготовкой и ничего не запускает:
В prompt.md вы пишете сообщение, которое Claude получает в каждом запуске, а в его frontmatter задаете лимиты запуска и инструменты, которые может использовать кейс. Откройте evals/first-case/prompt.md и замените текст-заготовку на задачу, которую должен обработать один из ваших скиллов, сформулированную так, как ее напечатал бы пользователь, а не с указанием названия скилла. Этот пример предназначен для скилла, который составляет сообщения коммитов; используйте собственную задачу:
Каждый запуск начинается в пустом рабочем каталоге, поэтому поместите все, что нужно для задачи, в сам промпт или сначала подготовьте рабочее пространство. Полный список полей frontmatter охватывает модель, таймаут, теги и переменные окружения. Каждый файл в graders/ — это одна проверка, применяемая после запуска. Откройте evals/first-case/graders/criteria.md и замените заготовку на рубрику для модели-судьи, написанную в виде конкретных условий PASS и FAIL:
Затем добавьте второй grader, который проверяет, что ответ был получен именно благодаря вашему скиллу. Создайте evals/first-case/graders/skill-fired.md, заменив your-skill-name на имя каталога скилла в skills/ — это имя, по которому Claude его вызывает:
Эта проверка проходит, если Claude вызвал этот скилл хотя бы один раз во время запуска, в том числе в форме с пространством имен plugin-name:skill-name. В разделе Типы graders перечислены другие доступные проверки, например сопоставление с регулярным выражением или подтверждение создания файла. Сохранив оба файла, запустите кейс так же, как в быстром старте, командой claude plugin eval . из корня плагина.

Задайте лимиты запуска и инструменты в prompt.md

Задайте max_turns, timeout_seconds, model, tags кейса и allowed_tools, которые он может использовать, во frontmatter prompt.md; в справочнике frontmatter prompt.md перечислены все поля и их значения по умолчанию. Claude получает текст ровно так, как вы его написали. Упоминания @path в нем не разворачиваются во вложения файлов, поэтому если Claude нужно прочитать файл, предоставьте для этого инструмент в allowed_tools.

Выберите graders и задайте их вес

Frontmatter grader задает его type и, опционально, weight, который увеличивает его вклад в оценку запуска, а также arm, который определяет, как он оценивается относительно базового варианта. Из шести типов regex, tool_used, tool_order и file_exists вычисляются по транскрипту и файлам и ничего не стоят, а llm и baseline вызывают модель-судью и увеличивают стоимость запуска. Graders с пользовательским кодом не поддерживаются. В разделе Типы graders перечислены опции и условие прохождения для каждого типа, а в разделе что может проверять grader — значения, которые принимают target и focus. По умолчанию судьей для graders llm и baseline является модель, которую Claude Code использует для фоновых задач. Передайте --judge-model sonnet или полный ID модели, чтобы выбрать судью самостоятельно.

Выбирайте graders, которые дают стабильный сигнал

Grader llm запрашивает вердикт у модели, поэтому его ответ может различаться между запусками, и тем сильнее, чем длиннее текст, который ему нужно прочитать. Следующие привычки помогают сохранять оценки suite достаточно стабильными, чтобы им можно было доверять:
  • Длинный вывод, например сгенерированный файл, оценивайте с помощью grader regex по содержимому файла: он каждый раз проверяет весь файл одинаково. Используйте graders llm для коротких выводов, с рубриками в виде конкретных условий PASS и FAIL.
  • Дайте каждому кейсу один grader на результат, например финальное сообщение или созданный файл, и один на шаги, которые Claude предпринял для его получения, например tool_used или tool_order. Вместе они показывают, был ли ответ правильным и был ли он получен благодаря вашему плагину.
  • Если grader tool_used: Skill кейса проходит, но Δ отрицательная, сначала подозревайте судью, а не плагин. Небольшая модель-судья может пометить правильный ответ как неправильный, потому что он отформатирован иначе, чем описано в рубрике. Перезапустите с --judge-model sonnet и уточните рубрику, чтобы форматирование не определяло вердикт.
  • Чтобы проверить, что сборка или тест прошли внутри запуска, сделайте так, чтобы промпт просил Claude выполнить их и записать результат в файл, оцените этот файл и убедитесь, что команда была выполнена, с помощью grader tool_used, чей input_match указывает эту команду.

Оценка относительно базового варианта без плагина

Когда тестируется плагин, кейс обычно запускается в двух arms. With-arm — это запуски с загруженным плагином, а without-arm — то же количество запусков вообще без плагина. Сводка и отчет показывают обе оценки и Δ — оценку with-arm минус оценку without-arm. В следующих ситуациях кейс запускает только with-arm, поэтому не получает оценку W/OUT или Δ:
  • Вы передаете --ablation none: каждый кейс запускает один arm, что вдвое снижает стоимость, когда сравнение не нужно, например при доработке graders.
  • Кейс возобновляет транскрипт, а целевой объект — это путь: если целевой объект — например, ., а не имя установленного плагина, кейс с context.history_file по умолчанию запускает один arm, исходя из предположения, что записанный диалог уже отражает работу плагина. Запуск выводит в stderr уведомление single-arm (no Δ) с перечнем таких кейсов. Чтобы сравнить возобновленный ход с плагином и без него, передайте --ablation with-without.
  • Для кейса не найден плагин: когда целевой объект — это путь, кейс, плагин которого Claude Code не смог найти, также по умолчанию запускает один arm. Чтобы исправить это, см. раздел базовый arm не показывает плагин.
В запуске с двумя arms некоторые graders отображаются с scored: false. Проверка вроде «скилл был вызван» никогда не может пройти без плагина, поэтому ее учет приблизил бы without-arm к нулю и завысил бы Δ. Чтобы два arms оставались сопоставимыми, Claude Code исключает такие graders из оценки в обоих arms и показывает их в with-arm только как индикаторы pass/fail. К ним относятся:
  • Каждый grader tool_used, у которого tool — это Skill
  • Каждый grader regex с target: mock_calls и каждый grader llm с focus: mock_calls, если каждый mock-сервер в кейсе объявлен вашим плагином
  • Любой grader, который вы пометили arm: with-only
Три настройки изменяют это исключение:
  • Исключены все graders: если все graders в кейсе входят в исключаемый набор, они вместо этого оцениваются обычным образом, так как иначе оценивать было бы нечего.
  • arm: both: задайте arm: both для grader, чтобы в любом случае оценивать его в обоих arms; это нужно для проверки «не должен вызывать скилл» с min: 0 и max: 0.
  • --ablation none: при --ablation none ничего не исключается, поэтому один и тот же suite может давать разную абсолютную оценку в двух режимах.

Использование другого каталога eval

Если evals/ уже занят другим инструментом, храните suite в другом каталоге. Вы можете указать этот каталог в plugin.json плагина, чтобы его использовали все запуски и все участники, или передать его в командной строке для одного запуска:
  • В plugin.json: добавьте "experimental": { "evals": "quality/evals" }.
  • В командной строке: передайте --eval-dir quality/evals и в claude plugin eval, и в claude plugin eval init.
Если заданы оба варианта, используется каталог из флага. Указывайте относительный путь из простых имен каталогов, например qa или quality/evals. Абсолютный путь или путь, содержащий .., не принимается: в качестве значения флага это ошибка, а непригодное значение в манифесте приводит к выводу строки Warning:, и запуск использует evals/. Кейсы, результаты и вывод init перемещаются в этот каталог.

Установите fixtures и mocks

Кейс может нуждаться в большем, чем prompt: файлы или git репозиторий в workspace, более ранний разговор для продолжения или ответы от MCP серверов, с которыми разговаривает ваш plugin. Каждый из них установлен рядом с кейсом, чтобы запуски оставались повторяемыми.

Заполните workspace или разговор

Каждый запуск начинается в пустом workspace. Когда кейс нуждается в большем, чем prompt, добавьте case.yaml рядом с prompt.md с блоком context:
  • Файлы fixtures или git репозиторий: напишите Bash скрипт в директории кейса и назовите его в context.scaffold_script. Скрипт запускается как вы, вне sandbox агента, и только когда вы передаете --scaffold, поэтому передавайте этот флаг только для suites, которые вы или ваша организация написали.
  • Более ранний разговор для продолжения: сохраните транскрипт как файл .jsonl и назовите его в context.history_file, и prompt кейса становится следующим ходом пользователя. Когда целевой объект является путем, такой кейс запускается без baseline arm по умолчанию.
  • Директории fixtures, которые Claude может читать во время запуска: перечислите их в context.add_dirs.
case.yaml также нуждается в schema_version: "1.1" и name; справочник case.yaml fields содержит полный список. Этот case.yaml заполняет workspace из скрипта и позволяет Claude читать fixtures из директории resources/:
Scaffold скрипт начинается в пустом workspace с небольшой фиксированной окружением: PATH вашей оболочки, HOME установлен на временный домашний каталог запуска, TMPDIR и несколько констант, таких как TERM=dumb. Ничего больше из вашей оболочки не достигает его, и переменные EVAL_* кейса тоже не достигают. Если скрипт завершается с ненулевым кодом или работает дольше 120 секунд, этот запуск получает оценку 0 с ошибкой scaffold failed. Используйте скрипт только для файлов и состояния git, так как конфигурация проекта, которую он записывает, не загружается.

Mock MCP серверы

Вы можете оценить plugin, чьи skills вызывают MCP инструменты без реального сервиса позади них. Поместите один Markdown файл на инструмент под evals/mocks/<server>/<tool>.md для всей suite или под собственную директорию mocks/ кейса для одного кейса, где <server> — это имя сервера в MCP конфигурации вашего plugin. Запуск никогда не запускает реальные MCP серверы вашего plugin, если вы не попросите. Claude Code регистрирует substitute server под каждым именем сервера. Инструменты с файлом mock отвечают из него и разрешены без гранта --allow-tools, и инструмент без файла mock недоступен Claude. Сервер без mocks вообще появляется в строке прогресса кейса как plugin_<plugin>_<server>[not started: no mock]. Body файла — это то, что инструмент возвращает Claude. Этот mock стоит на месте инструмента create_issue на сервере с именем tracker, проверяет input, который Claude отправляет, и эхо-возвращает заголовок. Сохраните его как evals/mocks/tracker/create_issue.md:
Body файла mock и frontmatter принимают эти опции:
  • Подстановки: вставьте поля из input вызова с {{input.<field>}} и содержимое файла fixture рядом с mock с {{file:fixtures/{input.<field>}.json}}.
  • expect:: блок expect: охраняет input. Если вызов нарушает его, запуск прерывается с оценкой 0 и записывает почему, поэтому кейс может утверждать, что ваш plugin попросил сервер сделать.
  • error: true: установите error: true, чтобы вернуть body как ошибку инструмента вместо этого.
  • type: agent: задайте type: agent, чтобы модель-судья отвечала от имени сервера по инструкциям из тела. Вызовы agent mock используют общий бюджет на запуск, равный четырёхкратному значению max_turns кейса, и вызов сверх него прерывает запуск с оценкой 0.
Справочник mock file reference перечисляет каждый ключ и файлы _server.md и _tools.json. Чтобы оценить сами вызовы, укажите grader на target: mock_calls. Чтобы запустить против реальных MCP серверов plugin вместо этого, передайте один из этих флагов. В любом случае эти процессы запускаются как вы, вне sandbox запуска, и их инструменты нуждаются в гранте --allow-tools:
  • --allow-real-servers: запустите реальный процесс для каждого сервера, который вы не замокировали, и продолжайте отвечать замокированные инструменты из их файлов
  • --mocks off: игнорируйте mocks/ полностью и запустите каждый сервер, который объявляет plugin

Воспроизведите ответы agent mock

type: agent mock отвечает с вызовом --judge-model, поэтому его вывод варьируется между запусками и изменяется, если вы измените judge. Когда запуск завершается без ошибки или прерывания, Claude Code сохраняет каждый ответ, который дал agent mock, под директорией результатов в mock-recordings/. Откройте ADOPT.txt там, чтобы увидеть каждую запись и директорию .replay/<server>/, чтобы скопировать ее в, рядом с mock, который ее произвел. После того как вы скопируете запись туда, более поздние запуски отвечают на идентичный вызов из нее без вызова модели. Зафиксируйте mocks/.replay/ вместе с остальной частью mocks/, чтобы запуски CI были повторяемыми.

Запустите evals

Как только suite существует, claude plugin eval запускает его. Вы выбираете, какой plugin и кейсы запускаются с аргументом target, предоставляете любые инструменты, которые кейсы нуждаются за пределами набора только для чтения с --allow-tools, и контролируете количество запусков, модели, стоимость и вывод с другими опциями.

Выберите, что оценивать

Большую часть времени вы запускаете claude plugin eval . из корня plugin, который запускает каждый кейс в suite с загруженным plugin, который вы разрабатываете. Чтобы запустить один файл кейса или оценить установленный plugin вместо того, который вы разрабатываете, передайте другой target: Добавьте --case <glob> для фильтрации по имени кейса и --tag <tag> для сохранения кейсов с любыми из данных тегов. Поместите target перед --tag, --allow-tools и --json. Первые два принимают список и --json принимает опциональный путь, поэтому каждый из них читает target, который следует как его собственное значение.

Предоставьте инструменты

Запуски никогда не останавливаются, чтобы попросить разрешение. Встроенные инструменты, которые нуждаются в гранте, который вы не дали, такие как Bash, Write, Edit, WebFetch и WebSearch, удаляются из сессии, поэтому Claude не может их вызывать вообще. Запуск позволяет только инструменты только для чтения, которые кейс перечисляет в allowed_tools, из Read, Glob, Grep, NotebookRead, Skill, AskUserQuestion, Agent, TodoWrite и инструменты задач TaskCreate, TaskGet, TaskList, TaskUpdate и TaskStop, плюс все, что вы предоставляете с --allow-tools. Этот грант применяется к каждому кейсу в запуске. Чтобы позволить кейсам использовать Bash, Write, Edit, WebFetch или WebSearch, предоставьте их сами:
Когда кейс попросил инструмент, который вы не предоставили, вывод прогресса перечисляет его как not granted. Инструменты на замокированном MCP сервере не нуждаются в гранте. Инструменты на реальном plugin MCP сервере нуждаются как в запущенном сервере, с --allow-real-servers или --mocks off, так и в гранте по имени, такой как --allow-tools "mcp__plugin_my-plugin_github__*"; инструменты MCP plugin названы mcp__plugin_<plugin>_<server>__<tool>. Когда вы предоставляете Bash в любой форме, каждая команда запускается под Claude Code OS-level sandbox. Записи ограничены workspace запуска, ваша домашняя директория и конфигурация Claude Code нечитаемы, и доступ в сеть ограничен доменами, которые вы предоставляете с --allow-tools "WebFetch(domain:example.com)". Если вы предоставляете Bash или PowerShell на машине без backend sandbox, Claude Code отказывает каждому запуску вместо его запуска без ограничений, и кейс показывает ошибку запуска и обычно оценивается в 0. Native Windows не имеет backend, поэтому запустите suites, предоставляющие shell, под WSL2; на Linux сначала установите bubblewrap и socat. См. sandboxing prerequisites.

Опции команды

Эта таблица охватывает опции для количества запусков, моделей, оценки, стоимости, грантов инструментов, mocks и вывода. Запустите claude plugin eval --help для полного списка, который также включает --case, --tag, --eval-dir, --no-scaffold, --report и --verbose.

Запустите evals в CI

В вашей CI работе запустите suite с --json, чтобы написать результат для архивирования, и не пройдите сборку на exit коде. Передайте --trust-plugin, чтобы работа никогда не ждала на первом запросе доверия, закрепите обе модели, чтобы оценки были сравнимы со временем, держите отчет локально и установите потолок стоимости как верхний лимит:
Exit код работы говорит вам, что произошло: Дельта with-minus-without сообщается, но никогда не изменяет exit код, и проблемы с написанием или публикацией HTML отчета тоже не изменяют. Чтобы увидеть, почему кейс оценен низко, запустите его локально без --json, чтобы строки прогресса per-run и grader печатались. CI runner также нуждается в этом на месте:
  • Установка и учётные данные: раннеру CI нужна установка Claude Code и учётные данные в окружении, например ANTHROPIC_API_KEY или переменные вашего облачного провайдера.
  • Доверие: без --trust-plugin, работа, чья директория checkout Claude Code еще не доверяет, нуждается в первом запросе доверия, и запуск, который не может спросить, отказан с exit 1.
  • init в CI: claude plugin eval init нуждается в терминале, чтобы задать вам его вопросы; в CI запустите claude plugin eval init --bare <name>, чтобы получить пустой шаблон.
Чтобы держать стоимости предсказуемыми, дайте быстрым every-change suites только graders, которые не вызывают judge, используйте --ablation none, где вам не нужно Δ, и оставьте partial: true документы и запуски с skippedPaidGraders вне любого тренда, который вы составляете.

Чтение результатов

Каждый запуск, в котором есть хотя бы один кейс, создаёт внутри каталога eval каталог results/<timestamp>/, содержащий aggregate-result.json и report.html. Для цели, заданной путём, он находится внутри плагина; для плагина, указанного по имени, — в вашем текущем каталоге, как показано в таблице целей. Сводная таблица, JSON и отчёт отображают одни и те же данные результатов.

HTML-отчёт

report.html — это единый самодостаточный файл, который не выполняет внешних запросов, поэтому его можно прикрепить к задаче CI или открыть с диска. В этом примере показано начало отчёта для набора из трёх кейсов, запущенного с --threshold 0.8; указанная стоимость является оценкой по прейскурантным ценам и зависит от модели и количества кейсов: Начало отчёта eval: строка вердикта «Plugin effect: +33.3 pts vs baseline, improved 2, flat 1, regressed 0 of 3 cases», пять сводных плиток с оценкой набора, дельтой абляции, базовой оценкой, кейсами, прошедшими порог, и идеальными запусками, затем первый кейс с его дельтой, шкалой оценки и одним запуском, оба грейдера которого показывают pass Читайте его сверху вниз:
  • Строка вердикта и плитки отвечают на вопрос, помог ли плагин в масштабе всего набора. Suite score — это среднее оценок по кейсам с плагином, Ablation Δ показывает, насколько оно выше или ниже базовой оценки, а Cases подсчитывает, сколько кейсов достигли порога. Perfect runs — это доля запусков с плагином, в которых прошли все грейдеры.
  • Каждая карточка кейса показывает собственную Δ кейса и оценку с плагином, с отметкой порога на шкале. Кейс с отрицательной Δ получает красную левую границу, поэтому регрессии заметны при прокрутке.
  • Внутри кейса сначала идут запуски с плагином, а затем базовые запуски. Для каждого запуска перечислены его грейдеры с меткой pass или fail. Не прошедший грейдер уже развёрнут с пояснением, а грейдер llm также показывает голоса судьи и доказательства, которые ему были показаны, — именно здесь можно выяснить, почему запуск получил низкую оценку. Грейдеры, которые не учитываются в оценке, например tool_used: Skill, помечены значком plugin-fired indicator.
  • Prompt и Graders под запусками показывают промпт кейса и рубрику или шаблон каждого грейдера, чтобы тот, кто читает отчёт без набора, мог увидеть, что было запрошено и что считалось хорошим результатом.
Если вы вошли с подпиской claude.ai и для вашей учётной записи доступны артефакты, Claude Code также публикует отчёт как приватный артефакт и выводит Published: <url>. Передайте --no-publish, чтобы оставить его локальным. Если строка Published: не появляется, например при аутентификации с помощью API-ключа, отчётом является локальный файл. Запуск, начатый сессией Claude Code, например когда вы просите Claude запустить набор за вас, также остаётся локальным, а его строка Report: содержит kept local. Добавьте --publish-report к этой команде, чтобы опубликовать его.

Результат в JSON

aggregate-result.json, как и вывод --json, — это версионированный документ с schemaVersion: 1, предназначенный для разбора скриптами CI. Имена полей записываются в camelCase, а новые поля добавляются без переименования существующих, поэтому пишите скрипт так, чтобы он игнорировал нераспознанные поля. Ниже перечислены поля, которые обычно читает скрипт-шлюз. Документ также содержит конфигурацию набора, определения всех грейдеров и результаты грейдеров по каждому запуску с пояснениями и доказательствами:

Что может получить доступ запуск

claude plugin eval загружает skills, hooks и agents целевого плагина и запускает его набор тестов на вашей машине от вашего имени. Указание на плагин — это то же самое решение о доверии, что и claude --plugin-dir, поэтому оценивайте только плагины, которым вы доверяете. Изоляция, описанная в этом разделе, ограничивает то, что может достичь тестируемый агент; это не граница против собственного кода плагина, и набор, который проходит, ничего не говорит о том, безопасен ли плагин.

Доверяйте директории плагина

При первом запуске claude plugin eval для директории Claude Code спрашивает Trust this plugin directory? перед загрузкой чего-либо из неё, если вы уже не приняли приглашение доверия там в интерактивном сеансе claude. Внутри репозитория git ответ «да» доверяет всему репозиторию, также для интерактивных сеансов. Когда stdin или stdout не является терминалом, или под --json, запуск не может спросить и отказывается с выходом 1; передайте --trust-plugin, чтобы утвердить доверие самостоятельно, только для плагина, который вы бы запустили на своей машине. Цель, которую вы называете, а не даёте как путь, то есть установленный плагин или плагин из директории skills, пропускает приглашение. Некоторые части плагина и набора запускаются только при передаче их флага для этого запуска: allowed_tools случая и собственный frontmatter allowed-tools skill не могут расширить ни один из них. Когда плагин поставляется с hooks, которые вы не писали, или вы запускаете его реальные MCP серверы, рассматривайте его оценки как рекомендательные, если вы не запустили его в изолированной среде, такой как контейнер или CI runner, поскольку hooks и серверы работают вне sandbox агента и могут изменять файлы, которые читают грейдеры.

Как запуски изолированы

Каждый запуск получает одноразовую домашнюю директорию, рабочую директорию и конфигурацию Claude Code, и тестируемый агент работает там как дочерний процесс claude -p с загруженным только вашим плагином. Помните об этих последствиях при написании случаев:
  • Ничего личного или на уровне проекта не загружается. Ваши пользовательские настройки, hooks, файлы CLAUDE.md, MCP серверы, другие установленные плагины, память и skills отсутствуют. Конфигурация на уровне проекта не читается нигде: никакая директория .claude/, CLAUDE.md или .mcp.json не загружается выше рабочей области или внутри неё, даже та, которую написал scaffold_script, и директории add_dirs предоставляют доступ только для чтения. Большая часть вашей shell среды также скрывается; только allowlist и переменные EVAL_* достигают запуска. Поставляйте любые skills, agents, hooks или MCP серверы, от которых зависит случай, в плагине под тестом, поскольку scaffold_script может предоставить только файлы и состояние git.
  • Управляемая политика всё ещё может ограничить запуск. Ограничения в управляемых настройках, которые администратор развернул на машине, применяются внутри запуска, поэтому результаты на управляемой машине могут отличаться от неуправляемой на эту политику.
  • Инструмент Artifact отключён. Skill, который публикует artifact, может быть оценён только на основе того, что он производит до этого шага.
  • Определения случаев скрыты от агента. Запуск не может читать директорию eval, поэтому Claude не может видеть приглашение случая, его грейдеры или соседние случаи.
  • Нет сетевого sandbox вне shell команд. Shell команды, которые вы предоставляете, работают под правилами сети sandbox. Грант WebFetch(domain:…) достигает этого домена напрямую, и собственные hooks плагина и любые реальные MCP серверы, которые вы запускаете, могут достичь любого хоста.

Справочник набора тестов

Всё, что может содержать набор тестов, находится в директории evals/ плагина, если вы не настроили другую. Директория считается случаем, когда она содержит prompt.md или case.yaml, и случай без хотя бы одного оценщика не загружается с ошибкой invalid case.yaml, которая называет graders. Это дерево показывает каждый файл, который claude plugin eval читает или записывает в директории eval:

prompt.md frontmatter

prompt.md frontmatter принимает эти поля. Неизвестный ключ является ошибкой:

case.yaml поля

case.yaml описывает тот же случай в YAML и добавляет поля, которые указывают на другие файлы. Требуется schema_version: "1.1" и name. Поля prompt.md description, tags, plugins, runs и expected_outcome находятся на верхнем уровне; model, max_turns, timeout_seconds, allowed_tools, append_system_prompt и env находятся под execution:. Когда оба файла существуют, frontmatter prompt.md переопределяет совпадающие поля case.yaml, тело prompt.md является подсказкой, и graders/*.md добавляются после любых оценщиков, указанных в case.yaml. Эти поля существуют только в case.yaml:

Frontmatter оценщика

Каждый файл оценщика под graders/ принимает эти ключи в frontmatter, плюс опции для его типа. Имя оценщика — это имя файла без .md:

Что может видеть оценщик

Оценщики regex принимают target и оценщики llm принимают focus. Оба принимают одни и те же значения:

Типы оценщиков

Каждый тип оценщика ниже перечисляет его опции и когда он проходит:

Файлы мока

Файл <tool>.md под mocks/<server>/ отвечает на один инструмент. Его тело — это результат инструмента, с подстановками {{input.<field>}} и {{file:fixtures/<name>}}. Его frontmatter принимает эти ключи: Два опциональных файла находятся рядом с файлами инструментов в директории сервера:
  • _server.md: один мок type: agent, который отвечает на несколько инструментов, перечисленных в его ключе frontmatter tools:. <tool>.md для того же инструмента имеет приоритет. Охрана expect: здесь вызывает ошибку загрузки, если только tools: не перечисляет единственный инструмент, поэтому поместите охрану на отдельный <tool>.md
  • _tools.json: сохранённый ответ tools/list от реального сервера, поэтому мокированные инструменты несут свои реальные описания и входные схемы вместо разрешающего заполнителя
Собственная директория mocks/ случая использует тот же макет и переопределяет файлы мока набора тестов файл за файлом.

Шаблоны регулярных выражений в expect

Значение /regex/ в expect: использует небольшой диалект, который Claude Code проверяет при загрузке набора тестов:
  • Литеральные символы, ., экранированные последовательности, такие как \d, и классы символов, такие как [a-z]
  • Квантификаторы *, +, ? и формы {m,n}, каждый применительно к одному символу, экранированной последовательности или классу
  • Необязательный ^ в начале и $ в конце
  • Только флаги i и s
Шаблон за пределами диалекта, например с группой, альтернацией, обратной ссылкой, просмотром вперёд или назад или другим флагом, не даёт случаю загрузиться: случай получает оценку 0, а его ошибка называет шаблон. Чтобы разрешить несколько точных значений, напишите список литералов вместо альтернации. Каждый шаблон проверяет значения только до максимальной длины, и более длинное значение считается нарушением. Квантификаторы могут уменьшать эту длину, а начальный ^ увеличивает её, поэтому привязывайте шаблоны с помощью ^ и используйте как можно меньше квантификаторов.

Troubleshooting

Это проблемы, которые авторы встречают чаще всего, ключевые на том, что вы видите.

“plugin eval is currently in early access”

Ваша сборка предшествует общей доступности команды. Запустите claude update, затем запустите команду снова в свежей сессии.

“plugin eval is currently unavailable”

Anthropic переключила команду выключенной на стороне сервера. Ничто на вашей машине не включает ее обратно; запустите claude update и попробуйте снова в свежей сессии позже.

“is not a trusted plugin directory, and this run cannot stop to ask you about it”

Это первый запуск против директории, которой Claude Code еще не доверяет, и он не может спросить, потому что stdin или stdout не является терминалом, или вы передали --json. Запустите claude plugin eval <dir> один раз в терминале и ответьте на запрос, или передайте --trust-plugin, если вы доверяете коду plugin и suite. См. What a run can access.

“is too old for claude plugin eval”

git на вашем PATH старше версии 2.31, поэтому claude plugin eval остановился перед запуском любого кейса и вышел с кодом 1 с сообщением, называющим вашу версию:
Для каждого запуска Claude Code отключает git hooks, credential helpers и другие программы, которые конфигурация git репозитория может запустить. Это делается через конфигурацию окружения, которую git читает только из версии 2.31. Более старый git игнорирует эту конфигурацию, поэтому suite останавливается, а не оценивает запуски, где эти программы могли бы выполняться. Установите git 2.31 или позже и запустите suite снова. До версии v2.1.283 claude plugin eval не проверял версию git, и на более старом git suite запускался с этими программами оставленными включенными.

“cannot be evaluated where sessions load it”

Вы запустили claude plugin eval в своей оболочке с именем плагина, установленного из маркетплейса, который вы добавили по локальному пути. Сейчас ни одна сессия не смогла бы загрузить плагин из этого маркетплейса, поэтому команда отказывает с этим сообщением и завершается с кодом 1.
Предложение после no session could load it now. указывает, что именно не удалось. Выполните claude plugin marketplace list в своей оболочке и исправьте то, что указано в сообщении. Например, восстановите каталог маркетплейса или верните запись плагина в его каталог. Чтобы оценить исходный код плагина без маркетплейса, передайте его каталог в качестве цели, например claude plugin eval ./plugins/formatter.

“No eval cases found”

Никакой <case>/prompt.md или <case>/case.yaml не существует под директорией eval в действии, или ваши фильтры --case и --tag не соответствовали никакому кейсу. Запустите из корня plugin или запустите claude plugin eval init, чтобы создать suite.

The baseline arm shows no plugin, or delta is zero

Если сводка не имеет столбца W/OUT, или кейс не пройдет с “ablation requested but no plugin resolved”, обычная причина в том, что никакой plugin не был найден для кейса. Если каждый кейс возобновляет транскрипт через context.history_file, отсутствующий столбец ожидается вместо этого, потому что эти кейсы запускаются одной веткой по умолчанию. В противном случае добавьте plugins: ["../.."] к кейсу, давая путь от директории кейса к директории plugin. Если plugin действительно загружен и Δ все еще близко к нулю с неудачным grader tool_used: Skill, это обычно реальное открытие, означающее, что description skill не запускается на формулировке prompt. Отрегулируйте описание и перезапустите ту же suite.

“Agent type ’…’ not found” for one of your plugin’s agents

По умолчанию каждый кейс запускается как с вашим plugin, так и без него, и запуски без него являются базовым запуском без plugin. Когда Claude отправляет одного из агентов вашего plugin в базовом запуске, вызов инструмента Agent не удается с Agent type '<plugin>:<agent-name>' not found. Available agents: .... Список называет только агентов, которые существуют без plugin, такие как встроенные подагенты. Ошибка ожидается, так как Δ сравнивает запуски вашего plugin с базовым. В результате JSON базовые запуски находятся под cases[].arms.without. В запусках с загруженным вашим plugin, кейс, который перечисляет Agent в allowed_tools, может отправить одного из агентов вашего plugin по его пространственному имени, такому как my-plugin:code-reviewer для агента code-reviewer в plugin с именем my-plugin. Чтобы пропустить базовые запуски, передайте --ablation none.

Everything scores zero although the right files were produced

Ваши graders нацелены на files, список созданных путей, когда вы имели в виду содержимое файла. Используйте { source: file, path: <path> } как target или focus. Отдельно, file_exists считает только файлы, созданные во время запуска, поэтому файл, который scaffold создал или который Claude только отредактировал, невидим для него; оцените его содержимое или используйте tool_used на Edit.

A regex over the trace doesn’t match text I can see

  • Wrong target: default target — это last_message, не trace.
  • JSON escaping: когда вы действительно нацеливаетесь на trace, это JSON на строку, поэтому кавычки появляются как \".
  • Regex syntax: regexes используют JavaScript синтаксис, поэтому поместите i в flags вместо написания (?i).

Tools are denied, MCP tools are missing, or Bash won’t run

Все, что за пределами набора только для чтения, нуждается в вашем гранте, такой как --allow-tools Bash Write. Ваши личные MCP серверы никогда не загружаются в запуск. Собственные серверы plugin не запускаются, если вы не opt in, и их инструменты затем также нуждаются в гранте --allow-tools "mcp__plugin_<plugin>_<server>__*"; замокированный инструмент не нуждается ни в чем.

The run exits 1 but the results look fine

Если каждый кейс получил оценку не ниже --threshold, а команда всё равно завершается с кодом 1, причина указывается в строке в stderr, даже при --json. Например, файл кейса не загрузился или запуски завершились ошибкой API. Другие причины см. в разделе коды выхода. Значение --threshold по умолчанию — 1.0, поэтому команда завершается с кодом 1, если любой кейс получил оценку ниже идеальной. Задайте порог, соответствующий требуемой вами оценке.

--json output path must end in .json

Вы поместили target после --json, поэтому он был прочитан как путь вывода. Поместите target первым, как в claude plugin eval . --json, или дайте --json явный путь .json.

A grader shows passed: false under a run that scored 1.0

Этот grader исключен из оценки по дизайну в двухarm запуске, и его поле scored — это false. См. Score against the no-plugin baseline.

“ended on an API error and scored 0 without grading”

Это предупреждение в stderr означает, что API ответил на последний запрос как минимум одного запуска HTTP-ошибкой, например из-за ограничения частоты запросов или лимита использования плана. Такой запуск получает оценку 0 без результатов грейдеров, а команда завершается с ненулевым кодом независимо от оценок и --threshold. Чтобы исправить это, найдите ошибку каждого затронутого запуска и устраните указанную в ней причину, затем снова запустите набор тестов:
  • Без --json: ошибка находится в конце строки прогресса запуска, после error:
  • С --json: ошибка находится в JSON-результате, в cases[].arms.with[].error или cases[].arms.without[].error
В подсчёт входят и базовые запуски. Их оценки никогда не определяют, пройден ли кейс, поэтому все кейсы могут пройти, а команда всё равно завершится неудачей. В запуске с двумя ветками W/OUT и Δ затронутого кейса выводятся как —. О лимите использования или ограничении частоты запросов см. Запуски завершаются ошибкой лимита использования или ограничения частоты запросов на полпути. До версии v2.1.299 такой запуск оценивался по тому, что он успел создать.

Runs fail with a usage-limit or rate-limit error partway through

Запуски, завершившиеся ошибкой лимита использования или ограничения частоты запросов, получают оценку 0 без проверки грейдерами, а команда завершается с ненулевым кодом. Набор тестов всё равно доходит до конца и не помечается как partial. Перезапустите его после сброса лимита, с --runs 1 или фильтром --case, если нужно уложиться в лимит.

“mock call budget exceeded”

Все моки с type: agent в запуске расходуют общий бюджет вызовов, равный четырёхкратному значению max_turns кейса, то есть 40 вызовов при значении по умолчанию 10. Вызовы, на которые отвечают записи из .replay/, тоже учитываются, а строка прогресса mock budget кейса выводит бюджет. Вызов сверх него прерывает запуск с оценкой 0 и этой причиной, поэтому для скилла, который делает много вызовов к мокам агентов, увеличьте max_turns в кейсе.

Runs time out or hit the turn cap

Defaults — это 10 turns и 300 секунд. Поднимите max_turns и timeout_seconds в кейсе для задач, которые нуждаются в большем, и используйте --max-cost-usd как потолок стоимости вместо плотных per-run лимитов.

См. также