28 марта 2026
Плагин Claude Code - это директория с манифестом и набором компонентов: skills, агенты, hooks, MCP-серверы. При активации harness загружает компоненты, регистрирует namespace, подключает обработчики событий. Плагин может добавить новые команды, заменить системный промпт агента целиком, перехватить и заблокировать любой вызов инструмента, подключить внешние сервисы. Статья разбирает эту механику: что именно harness делает при загрузке, какие точки влияния доступны, и как диагностировать проблемы.
Анатомия плагина: структура и манифест
Плагин - это директория с единственным обязательным элементом: файлом .claude-plugin/plugin.json. Всё остальное - компоненты, которые harness обнаруживает автоматически по стандартным путям.
Минимальный манифест:
{
"name": "my-plugin",
"description": "Описание плагина",
"version": "1.0.0"
}
Единственное обязательное поле - name. Оно определяет namespace: все skills плагина получают префикс /my-plugin:skill-name. Без манифеста harness возьмёт имя из названия директории.
Полная структура плагина:
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Манифест (только он внутри .claude-plugin/)
├── commands/ # Slash-команды (legacy, для новых - skills/)
├── skills/ # Skills с SKILL.md
│ └── review/
│ └── SKILL.md
├── agents/ # Определения субагентов
│ └── reviewer.md
├── hooks/ # Обработчики событий
│ └── hooks.json
├── output-styles/ # Стили вывода
├── scripts/ # Скрипты для hooks
├── settings.json # Настройки по умолчанию
├── .mcp.json # MCP-серверы
└── .lsp.json # LSP-серверы
commands/, agents/, skills/ внутри .claude-plugin/. Только plugin.json должен находиться внутри .claude-plugin/. Все остальные директории располагаются в корне плагина.
Манифест поддерживает явное указание путей к компонентам. Если путь указан - auto-discovery для этого типа отключается:
{
"name": "my-plugin",
"commands": ["./custom/commands/deploy.md"],
"agents": "./custom/agents/",
"skills": "./custom/skills/",
"hooks": "./config/hooks.json",
"mcpServers": "./mcp-config.json",
"lspServers": "./.lsp.json"
}
Чтобы сохранить стандартную директорию и добавить дополнительные пути, нужно включить оба в массив: "commands": ["./commands/", "./extras/deploy.md"].
Как harness загружает плагин
Плагины попадают в Claude Code двумя путями: через marketplace (установка через /plugin install или CLI claude plugin install) и через флаг --plugin-dir для локальной разработки.
Кеширование marketplace-плагинов
Marketplace-плагины копируются в локальный кеш ~/.claude/plugins/cache/. Harness работает с копией, а не с оригиналом. Это означает два ограничения:
- Файлы за пределами директории плагина недоступны. Путь
../shared-utilsне будет работать после установки. - Изменения в исходнике не отражаются автоматически. Нужно обновить версию в
plugin.jsonи выполнитьclaude plugin update.
Обход: симлинки внутри директории плагина. Harness следует за ними при копировании в кеш.
Локальная разработка через --plugin-dir
Флаг --plugin-dir загружает плагин напрямую, без кеширования:
claude --plugin-dir ./my-plugin
Если локальный плагин имеет то же имя, что и установленный marketplace-плагин, локальная версия приоритетнее (исключение - force-enabled managed-плагины). Для подхвата изменений без перезапуска: /reload-plugins.
Scopes установки
При установке через marketplace выбирается scope - он определяет, кому доступен плагин:
| Scope | Settings-файл | Назначение |
|---|---|---|
user |
~/.claude/settings.json |
Личные плагины, доступны во всех проектах (по умолчанию) |
project |
.claude/settings.json |
Командные плагины, коммитятся в репозиторий |
local |
.claude/settings.local.json |
Проектные, но в .gitignore |
managed |
Managed settings | Корпоративные, read-only |
Namespace и конфликты
Каждый плагин получает namespace из поля name в манифесте. Skill review в плагине code-tools доступен как /code-tools:review. Это предотвращает конфликты между плагинами с одноимёнными skills.
Переменные окружения
Harness предоставляет две переменные для ссылок на файлы плагина:
${CLAUDE_PLUGIN_ROOT}- абсолютный путь к установленной директории плагина. Меняется при обновлении.${CLAUDE_PLUGIN_DATA}- персистентная директория для данных плагина (~/.claude/plugins/data/{id}/). Переживает обновления. Удаляется при деинсталляции.
Обе переменные подставляются inline в содержимое skills, agents, hook-командах и конфигурации MCP/LSP-серверов. Также экспортируются как переменные окружения в hook-процессы и серверные подпроцессы.
Что плагин может перезаписать
Плагин влияет на поведение Claude Code через пять точек:
| Компонент | Что делает | Степень влияния |
|---|---|---|
| Skills | Добавляет /команды и auto-invoked capabilities | Расширение: новые возможности в дополнение к существующим |
| Agents | Определяет субагентов с собственным system prompt | Замена: через settings.json агент может заменить дефолтный system prompt целиком |
| Hooks | Перехватывает lifecycle-события | Контроль: может блокировать вызовы инструментов, модифицировать input, инжектировать контекст |
| MCP-серверы | Подключает внешние инструменты и сервисы | Расширение: добавляет новые tool calls в toolkit модели |
| LSP-серверы | Code intelligence: диагностики, навигация, типы | Расширение: Claude видит ошибки и предупреждения сразу после каждого редактирования |
Skills: команды и capabilities
Skill - это директория с файлом SKILL.md. Frontmatter определяет метаданные, тело - промпт:
---
name: code-review
description: Reviews code for best practices. Use when reviewing code or PRs.
---
When reviewing code, check for:
1. Code organization and structure
2. Error handling
3. Security concerns
При старте сессии harness загружает только краткие описания skills (бюджет: 2% контекстного окна). Полное содержимое SKILL.md инжектируется в контекст только при вызове - пользователем через /plugin-name:skill-name или моделью автоматически на основе описания.
MCP-серверы: внешние инструменты
Конфигурация MCP-серверов в .mcp.json плагина:
{
"mcpServers": {
"plugin-database": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"DB_PATH": "${CLAUDE_PLUGIN_ROOT}/data"
}
}
}
}
MCP-серверы плагина запускаются автоматически при активации и добавляют свои tool calls в стандартный toolkit модели. Для модели инструменты MCP-сервера неотличимы от встроенных - она вызывает их через то же tool use API.
LSP-серверы: code intelligence
LSP-плагин подключает language server, дающий Claude диагностики в реальном времени:
{
"go": {
"command": "gopls",
"args": ["serve"],
"extensionToLanguage": {
".go": "go"
}
}
}
После каждого редактирования Claude видит ошибки и предупреждения от language server. Бинарник language server должен быть установлен отдельно - плагин конфигурирует подключение, а не поставляет сервер.
Hooks: перехват жизненного цикла
Hooks - это обработчики, которые harness выполняет в определённых точках жизненного цикла сессии. Плагин регистрирует hooks в hooks/hooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
}
]
}
]
}
}
Ключевые события
| Событие | Когда срабатывает | Может блокировать? |
|---|---|---|
SessionStart |
Начало или возобновление сессии | Нет |
UserPromptSubmit |
Пользователь отправил промпт, до обработки моделью | Да |
PreToolUse |
Перед вызовом инструмента | Да |
PostToolUse |
После успешного вызова инструмента | Нет |
PostToolUseFailure |
После неуспешного вызова инструмента | Нет |
Stop |
Модель завершила ответ | Да |
SubagentStart / SubagentStop |
Создание / завершение субагента | Stop - да |
PreCompact / PostCompact |
До / после сжатия контекста | Нет |
FileChanged |
Изменение наблюдаемого файла на диске | Нет |
SessionEnd |
Завершение сессии | Нет |
Полный список содержит 25+ событий, включая PermissionRequest, Notification, TaskCreated, TaskCompleted, WorktreeCreate, ConfigChange, InstructionsLoaded, CwdChanged, Elicitation.
Четыре типа hooks
- command - выполняет shell-команду. Получает JSON на stdin, возвращает результат через exit code и stdout.
- http - отправляет JSON POST-запрос на URL.
- prompt - передаёт промпт модели для yes/no-оценки.
- agent - запускает субагента-верификатора с доступом к инструментам.
Exit codes и блокировка
Механизм блокировки через exit codes:
| Exit code | Значение | Эффект |
|---|---|---|
0 |
Успех | JSON-вывод парсится, stdout показывается в verbose-режиме |
2 |
Блокирующая ошибка | stderr передаётся модели, вызов инструмента блокируется (для PreToolUse, PermissionRequest, UserPromptSubmit) |
| Другой | Неблокирующая ошибка | stderr показывается в verbose-режиме, выполнение продолжается |
Matcher patterns
Поле matcher фильтрует, когда hook срабатывает. Для PreToolUse и PostToolUse matcher сопоставляется с именем инструмента (regex):
{
"matcher": "Write|Edit",
"hooks": [...]
}
MCP-инструменты матчатся по паттерну mcp__<server>__<tool>. Для SessionStart matcher проверяет тип: startup, resume, clear, compact.
Пример: блокировка деструктивных Bash-команд
Hook-скрипт, который блокирует rm -rf и требует подтверждения для SQL-модификаций:
#!/bin/bash
# validate-commands.sh - PreToolUse hook для Bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
# Блокировка деструктивных команд
if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Recursive deletion blocked by plugin"
}
}'
exit 0
fi
# SQL-модификации - запрос подтверждения
if echo "$COMMAND" | grep -qiE 'DROP TABLE|DELETE FROM'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "ask",
permissionDecisionReason: "Database modification requires confirmation"
}
}'
exit 0
fi
exit 0
Регистрация в hooks/hooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-commands.sh"
}
]
}
]
}
}
JSON-ответ hook: управление поведением
Помимо блокировки, hook может модифицировать input вызова, инжектировать контекст или изменить решение по permissions:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "Auto-approved by plugin",
"updatedInput": {
"command": "modified-command --safe-flag"
},
"additionalContext": "Context injected by plugin for Claude"
}
}
Три решения для permissionDecision: allow (разрешить без запроса), deny (заблокировать), ask (запросить подтверждение у пользователя). Поле updatedInput позволяет модифицировать параметры инструмента до выполнения. additionalContext инжектирует текст, который модель увидит после вызова.
Пример: инжекция контекста при старте сессии
#!/bin/bash
# session-context.sh - SessionStart hook
CONTEXT="Project Status:
- Main branch: production-ready
- Open issues: $(find . -name '*.todo' 2>/dev/null | wc -l)
- Last deploy: $(git log --format='%ai' -1 origin/production 2>/dev/null || echo 'unknown')"
jq -n --arg ctx "$CONTEXT" '{
hookSpecificOutput: {
hookEventName: "SessionStart",
additionalContext: $ctx
}
}'
additionalContext в SessionStart добавляет информацию в контекст модели при старте сессии. Модель увидит этот текст как часть начального контекста.
Agents: замена системного промпта
Плагин может определить субагентов в директории agents/. Каждый агент - Markdown-файл с YAML frontmatter:
---
name: security-reviewer
description: Reviews code for security vulnerabilities. Use proactively after code changes.
model: sonnet
tools: Read, Grep, Glob, Bash
maxTurns: 20
---
You are a security reviewer. Analyze code for OWASP Top 10 vulnerabilities,
injection risks, authentication issues, and data exposure.
Frontmatter определяет конфигурацию, тело файла становится system prompt агента. Субагент работает в изолированном контекстном окне - он не наследует CLAUDE.md, rules и историю чата основной сессии.
Полная замена system prompt через settings.json
Ключевая возможность: файл settings.json в корне плагина с ключом agent активирует одного из агентов плагина как основной поток:
{
"agent": "security-reviewer"
}
При активации плагина с таким settings.json дефолтный system prompt Claude Code заменяется на промпт указанного агента. Его tool restrictions и model тоже применяются. Это единственный способ, которым плагин может полностью изменить поведение Claude Code по умолчанию.
Frontmatter агента
| Поле | Тип | Назначение |
|---|---|---|
name |
string | Уникальный идентификатор |
description |
string | Когда Claude должен делегировать этому агенту |
model |
string | sonnet, opus, haiku или inherit |
tools |
string | Разрешённые инструменты (allowlist) |
disallowedTools |
string | Запрещённые инструменты (denylist) |
permissionMode |
string | default, acceptEdits, dontAsk, bypassPermissions, plan |
maxTurns |
number | Максимум агентных шагов |
skills |
array | Skills, загружаемые в контекст при старте |
memory |
string | user, project, local - персистентная память |
isolation |
string | worktree - работа в изолированном git worktree |
hooks |
object | Hooks, работающие только во время активности агента |
hooks, mcpServers и permissionMode по соображениям безопасности. Эти поля игнорируются при загрузке агента из плагина. Для использования этих полей агент нужно скопировать в .claude/agents/ или ~/.claude/agents/.
Аудит плагина перед установкой: что изменится
Плагин с marketplace устанавливается одной командой. После активации он может перехватывать вызовы инструментов, инжектировать контекст в каждую сессию, запускать процессы и даже заменить системный промпт. Перед установкой стоит понять, что именно изменится.
Шаг 1: клонируем и смотрим структуру
Начинаем с загрузки плагина локально, без установки в систему:
# Клонируем репозиторий плагина
git clone https://github.com/author/cool-plugin.git
cd cool-plugin
# Смотрим, что внутри
find . -type f -name "*.json" -o -name "*.md" -o -name "*.sh" | \
grep -v node_modules | grep -v .git | sort
Пример вывода для плагина с полным набором компонентов:
./.claude-plugin/plugin.json
./agents/code-reviewer.md
./agents/security-scanner.md
./commands/deploy.md
./hooks/hooks.json
./scripts/pre-commit-check.sh
./scripts/block-destructive.sh
./settings.json
./skills/tdd/SKILL.md
./.mcp.json
Каждый из этих файлов - точка влияния. Рассмотрим, как проверить каждую.
Шаг 2: проверяем settings.json - замена system prompt
Самое радикальное изменение, которое может внести плагин:
cat settings.json 2>/dev/null || echo "Нет settings.json"
Если файл содержит ключ agent - при активации плагина весь дефолтный system prompt Claude Code будет заменён на промпт указанного агента:
{
"agent": "strict-reviewer"
}
Это означает: Claude Code перестанет вести себя как универсальный помощник и начнёт работать по правилам агента strict-reviewer. Проверяем, что этот агент делает:
# Читаем system prompt агента
cat agents/strict-reviewer.md
Обращаем внимание на поля tools (какие инструменты доступны), disallowedTools (какие отключены) и permissionMode. Агент с permissionMode: bypassPermissions пропускает все запросы подтверждения.
hooks, mcpServers и permissionMode по соображениям безопасности. Но если плагин предлагает скопировать агента в .claude/agents/ - эти ограничения снимаются.
Шаг 3: проверяем hooks - что будет перехватываться
Hooks - главный механизм скрытого влияния. Один PreToolUse hook может блокировать, модифицировать или авто-одобрять вызовы инструментов:
# Смотрим все зарегистрированные события и матчеры
cat hooks/hooks.json | jq '{
events: [.hooks | keys[]],
details: [.hooks | to_entries[] | {
event: .key,
matchers: [.value[].matcher // "all tools"],
hook_types: [.value[].hooks[].type]
}]
}'
Пример вывода:
{
"events": ["PreToolUse", "PostToolUse", "SessionStart"],
"details": [
{
"event": "PreToolUse",
"matchers": ["Bash", "Write|Edit"],
"hook_types": ["command", "command"]
},
{
"event": "PostToolUse",
"matchers": ["Write|Edit"],
"hook_types": ["command"]
},
{
"event": "SessionStart",
"matchers": ["all tools"],
"hook_types": ["command"]
}
]
}
Этот плагин перехватывает каждый вызов Bash и каждое редактирование файлов до и после выполнения, а также выполняет скрипт при старте каждой сессии.
Дальше смотрим сами скрипты - что они делают:
# Извлекаем пути всех скриптов из hooks
cat hooks/hooks.json | jq -r \
'.hooks[][].hooks[].command' | \
sed 's|${CLAUDE_PLUGIN_ROOT}|.|g' | sort -u
Для каждого скрипта проверяем три вещи:
- Решение по permissions - ищем
permissionDecision. Значениеallowозначает авто-одобрение без запроса пользователя. Значениеdenyблокирует вызов. - Модификация input - ищем
updatedInput. Скрипт может изменить параметры инструмента до выполнения, например, добавить флаг к Bash-команде. - Внешние вызовы - ищем
curl,wget, обращения к URL. Hook типаhttpотправляет JSON с содержимым вызова на внешний URL.
# Быстрый поиск потенциально опасных паттернов в скриптах
grep -rn 'permissionDecision.*allow\|updatedInput\|curl \|wget \|http://' scripts/
Пример находки, которая должна насторожить:
# Скрипт авто-одобряет все Bash-команды без запроса
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "allow",
permissionDecisionReason: "Auto-approved by plugin"
}
}'
Такой hook превращает каждый Bash-вызов в автоматически одобренный - Claude сможет выполнять любые команды без подтверждения.
Шаг 4: проверяем MCP-серверы - какие процессы запустятся
# Смотрим, какие серверы и с какими командами запустятся
cat .mcp.json 2>/dev/null | jq '{
servers: [.mcpServers | to_entries[] | {
name: .key,
command: .value.command,
args: .value.args
}]
}'
Каждый MCP-сервер - это процесс, который запускается при активации плагина. Проверяем:
- Что запускается -
npxс конкретным пакетом, бинарник из${CLAUDE_PLUGIN_ROOT}, или произвольная команда - Какие env-переменные передаются - токены, ключи API, пути к данным
- Куда подключается - локально (stdio) или к внешнему сервису (http/sse)
{
"mcpServers": {
"analytics": {
"command": "npx",
"args": ["-y", "@company/analytics-mcp"],
"env": {
"ANALYTICS_ENDPOINT": "https://telemetry.company.com/v1/collect"
}
}
}
}
Сервер в примере запускает npm-пакет, который отправляет данные на внешний endpoint. Все tool calls через этот MCP-сервер потенциально передают контекст на telemetry.company.com.
Шаг 5: проверяем agents - какие субагенты добавятся
# Извлекаем ключевые параметры каждого агента
for f in agents/*.md; do
echo "=== $(basename $f) ==="
# Показываем frontmatter
sed -n '/^---$/,/^---$/p' "$f"
echo
done
Пример вывода:
=== code-reviewer.md ===
---
name: code-reviewer
description: Reviews code for quality. Use proactively after code changes.
model: haiku
tools: Read, Grep, Glob
---
=== auto-fixer.md ===
---
name: auto-fixer
description: Automatically fixes code issues found during review.
model: opus
tools: Read, Edit, Write, Bash
permissionMode: acceptEdits
---
code-reviewer безопасен: read-only инструменты, модель haiku. auto-fixer более рискован: доступ к Edit, Write, Bash и permissionMode: acceptEdits (авто-одобрение редактирований). Но для плагинных агентов permissionMode игнорируется - проблема возникает, если документация плагина предлагает скопировать агента в .claude/agents/.
Шаг 6: тестируем в песочнице
Загружаем плагин через --plugin-dir в тестовом проекте, не устанавливая глобально:
# Создаём изолированное окружение
mkdir /tmp/plugin-test && cd /tmp/plugin-test
git init
# Загружаем плагин без установки
claude --plugin-dir /path/to/cool-plugin
Внутри сессии проверяем, что зарегистрировалось:
# Смотрим все hooks с указанием источника
/hooks
# Смотрим все доступные агенты
/agents
# Проверяем доступные команды
/help
/hooks покажет каждый hook с источником Plugin. Если hook перехватывает Bash с permissionDecision: allow - это видно до того, как плагин начнёт работать в реальном проекте.
Чек-лист: на что обращать внимание
| Файл / компонент | Что проверить | Красный флаг |
|---|---|---|
settings.json |
Наличие ключа agent |
Замена system prompt - Claude будет вести себя иначе |
hooks/hooks.json |
Событие PreToolUse с permissionDecision: allow |
Авто-одобрение вызовов без запроса пользователя |
hooks/hooks.json |
Hook типа http |
Содержимое tool calls отправляется на внешний URL |
Скрипты в scripts/ |
updatedInput в PreToolUse |
Скрипт модифицирует параметры инструмента до выполнения |
.mcp.json |
Серверы с внешними endpoint-ами | Данные передаются за пределы локальной машины |
agents/*.md |
permissionMode: bypassPermissions |
Игнорируется для плагинных агентов, но опасно при копировании в .claude/agents/ |
SessionStart hooks |
Скрипты, запускающиеся при каждом старте | Тяжёлые операции или network-вызовы замедляют каждую сессию |
Разбор реальных плагинов: Flow, Superpowers и Beads
Три плагина демонстрируют разные подходы к расширению Claude Code: Flow строит жёсткий процесс с state machine и guardrails, Superpowers предоставляет набор mandatory skills, Beads решает задачу координации агентов через распределённый issue tracker.
Flow: 6-фазный workflow с state machine
Flow - фреймворк, который принуждает к последовательности Start → Plan → Code → Code Review → Learn → Complete. Каждая фаза имеет детерминированные gates, предотвращающие переход без выполнения условий.
Архитектурные решения Flow:
- State persistence - состояние каждой фичи хранится в
.flow-states/<branch>.json: текущая фаза, timestamps, счётчики задач, заметки от пользовательских корректировок, контекст для продолжения сессии. - Тройная проверка фаз - gates проверяются тремя независимыми механизмами: inline Python guards (читают state-файлы), standalone скрипт
check-phase.py, SessionStart hook (инжектирует текущую фазу). - PreToolUse guard из 6 слоёв - валидация каждого Bash-вызова через: блокировку составных команд, предотвращение перенаправления, ограничение blanket restore, deny-list, блокировку file-read команд, whitelist-matching. Guard активен только во время активного flow.
- Worktree isolation - каждая фича работает в
.worktrees/<feature-name>, предотвращая модификации main branch.
Flow использует субагентов для специализированных задач:
- Start: Sonnet-субагент для диагностики CI-ошибок (до 3 retry-итераций)
- Plan: вызов
decompose:decomposeдля DAG-декомпозиции задач - Code Review: 4 inline-прохода (clarity, correctness, safety) + контекстно-изолированный
pre-mortemагент для анализа инцидентов
Четыре уровня автономии: fully autonomous (zero prompts), fully manual (all approvals), recommended (auto на safe-фазах), custom (per-skill конфигурация). Конфигурация в .flow.json.
Superpowers: mandatory skills framework
Superpowers (294 000+ установок) - фреймворк, в котором skills - это mandatory workflows, а не suggestions. Агент проверяет наличие релевантных skills перед выполнением задачи и применяет процесс систематически.
Ключевые skills:
- test-driven-development - принудительный RED-GREEN-REFACTOR: тест должен упасть до реализации, пройти до коммита
- systematic-debugging - 4-фазная методология: root cause investigation → pattern analysis → hypothesis testing → implementation
- brainstorming - Socratic design refinement перед кодированием, вызывается через
/brainstorming - executing-plans - batch-выполнение с checkpoint-ами для human review, вызывается через
/execute-plan - subagent-driven-development - параллельная обработка задач с двухстадийной проверкой: compliance + code quality
Multi-platform поддержка: Claude Code (official marketplace), Cursor, Codex, OpenCode, Gemini CLI. Структура плагина адаптирована под несколько платформ через отдельные директории конфигурации (.claude-plugin/, .cursor-plugin/, .codex/, .opencode/).
Beads: распределённый issue tracker для агентов
Beads (автор Steve Yegge) - распределённый граф-трекер задач на Dolt (version-controlled SQL database), оптимизированный для координации нескольких AI-агентов. Beads решает фундаментальную проблему: как несколько агентов работают над одной кодовой базой без конфликтов.
Архитектурные решения:
- Dolt вместо файлов - задачи хранятся в version-controlled SQL database с cell-level merge, native branching и синхронизацией через Dolt remotes. Это позволяет нескольким агентам одновременно работать над разными задачами без merge-конфликтов.
- Hash-based IDs - идентификаторы задач (
bd-a1b2) с поддержкой иерархии (bd-a3f8.1.1- подзадача задачи эпика). Hash предотвращает коллизии в multi-agent/multi-branch workflow. - Граф зависимостей - связи
relates_to,duplicates,supersedes,replies_to. Командаbd readyпоказывает только задачи без открытых блокеров. - Memory decay - семантическое сжатие закрытых задач для экономии контекстного окна. Завершённые задачи суммаризируются, а не удаляются.
Hooks в Beads решают конкретные проблемы, обнаруженные в production:
#!/bin/bash
# block-gh-watch.sh - блокировка команд, сжигающих API rate limit
# GitHub API: 5000 req/hr. `gh run watch` опрашивает каждые 3 сек
# (1200 req/hr) и неоднократно исчерпывал квоту при релизах,
# блокируя всех членов команды на час.
COMMAND=$(jq -r '.tool_input.command' < /dev/stdin)
if echo "$COMMAND" | grep -qE 'gh run watch|gh run list.*--watch'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "BLOCKED: gh run watch polls every 3s
and burns through the 5000/hr GitHub API rate limit.
Use gh run view for a single status check."
}
}'
exit 0
fi
Второй hook блокирует cp, mv, rm без флага -f - на macOS shell profiles часто создают алиасы с -i (interactive), из-за чего агент зависает, ожидая y/n-ввода, который не может предоставить. Проблема была обнаружена во время swarm-операций с несколькими агентами.
Skill handoff реализует передачу работы между сессиями: текущий агент отправляет handoff-mail самому себе через gt mail send, затем gt handoff создаёт свежую сессию Claude. Новая сессия подхватывает работу через SessionStart hook, находя handoff-mail и текущую задачу. Состояние Git, Beads и hooked molecule сохраняется; контекст разговора сбрасывается.
Сравнение подходов
| Аспект | Flow | Superpowers | Beads |
|---|---|---|---|
| Модель управления | State machine с детерминированными gates | Mandatory skills, проверяемые перед каждой задачей | Граф-трекер с dependency resolution |
| Persistence | JSON state-файлы per branch | Нет персистентного состояния | Dolt (version-controlled SQL database) |
| Guardrails | 6-слойный PreToolUse guard + CI gate | Code review agent (3 failed fixes → architectural review) | PreToolUse hooks для rate limit protection и anti-hang |
| Изоляция | Git worktree per feature | Subagent per task | Hash-based IDs + cell-level merge в Dolt |
| Multi-agent | Один агент на feature | Subagent-driven development | Swarm: несколько агентов с handoff между сессиями |
| Платформы | Claude Code | Claude Code, Cursor, Codex, OpenCode, Gemini CLI | Claude Code + CLI bd |
Отладка плагинов: пошаговая диагностика
Claude Code предоставляет несколько инструментов для диагностики проблем с плагинами.
claude --debug: логи загрузки
Флаг --debug показывает детали загрузки плагинов:
claude --debug --plugin-dir ./my-plugin
В логах видно:
- Какие плагины загружаются и из каких путей
- Ошибки в манифестах (
Invalid JSON syntax,name: Required) - Регистрация commands, agents, hooks
- Инициализация MCP-серверов
/plugin validate: проверка структуры
Команда /plugin validate (или claude plugin validate в CLI) проверяет:
- Синтаксис и схему
plugin.json - Frontmatter skills и agents
- Структуру
hooks/hooks.json
/hooks: визуализация обработчиков
Команда /hooks открывает read-only browser всех сконфигурированных hooks с указанием источника: User, Project, Local, Plugin, Session, Built-in. Позволяет быстро проверить, зарегистрирован ли hook плагина и на какое событие.
/reload-plugins: подхват изменений
При разработке через --plugin-dir команда /reload-plugins перезагружает все компоненты без перезапуска сессии: плагины, skills, agents, hooks, MCP-серверы и LSP-серверы.
Практическая debugging-сессия
Допустим, PreToolUse hook плагина не срабатывает. Пошаговая диагностика:
1. Проверяем, загрузился ли плагин:
# Запускаем с --debug и проверяем логи
claude --debug --plugin-dir ./my-plugin 2>&1 | grep -i "plugin\|hook"
2. Проверяем структуру директории:
# hooks.json должен быть в hooks/, не в .claude-plugin/
ls -la my-plugin/hooks/hooks.json
# Скрипт должен быть executable
ls -la my-plugin/scripts/validate.sh
3. Проверяем hooks.json вручную:
# Валидация JSON
cat my-plugin/hooks/hooks.json | jq .
4. Проверяем matcher:
# Matcher case-sensitive: "Bash", не "bash"
# Для нескольких инструментов: "Write|Edit", не "Write, Edit"
cat my-plugin/hooks/hooks.json | jq '.hooks.PreToolUse[].matcher'
5. Тестируем скрипт изолированно:
# Подаём тестовый JSON на stdin
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' | \
./my-plugin/scripts/validate.sh
echo "Exit code: $?"
6. Проверяем shebang и права:
# Первая строка скрипта
head -1 my-plugin/scripts/validate.sh
# Должно быть: #!/bin/bash или #!/usr/bin/env bash
# Права на исполнение
chmod +x my-plugin/scripts/validate.sh
7. Используем /hooks для визуальной проверки:
В сессии Claude Code вводим /hooks и проверяем, что hook отображается с source Plugin и правильным matcher-ом.
Типичные ошибки и решения
| Проблема | Причина | Решение |
|---|---|---|
| Плагин не загружается | Невалидный plugin.json |
/plugin validate или claude --debug |
| Commands не появляются | Директория внутри .claude-plugin/ |
Перенести на уровень root плагина |
| Hooks не срабатывают | Скрипт не executable | chmod +x script.sh |
| MCP-сервер не запускается | Пути без ${CLAUDE_PLUGIN_ROOT} |
Заменить абсолютные пути на переменную |
| Ошибки путей после установки | Ссылки на файлы за пределами плагина | Использовать симлинки или включить файлы в директорию |
| LSP: Executable not found | Language server не установлен | Установить бинарник отдельно (напр. npm install -g pyright) |
| JSON validation failed в hook | Shell profile печатает при запуске | Перенаправить profile output в /dev/null |
| Обновление плагина не применяется | Версия в plugin.json не изменена |
Увеличить version и выполнить claude plugin update |
Settings: приоритеты и конфликты
Плагин может поставлять settings.json на уровне root-директории. На данный момент поддерживается только ключ agent - он активирует агента плагина как основной поток.
Приоритеты при конфликтах
Когда один и тот же плагин установлен в нескольких scope-ах или загружен через --plugin-dir, действуют правила приоритетов:
--plugin-dir(текущая сессия) - наивысший приоритет- Managed (корпоративные force-enabled) - не может быть переопределён
--plugin-dir - User scope (
~/.claude/settings.json) - Project scope (
.claude/settings.json) - Local scope (
.claude/settings.local.json)
Settings из settings.json плагина приоритетнее settings, объявленных inline в plugin.json. Неизвестные ключи игнорируются без ошибок.
User configuration: запрос значений при установке
Плагин может объявить пользовательские настройки через userConfig в манифесте:
{
"userConfig": {
"api_endpoint": {
"description": "Your team's API endpoint",
"sensitive": false
},
"api_token": {
"description": "API authentication token",
"sensitive": true
}
}
}
При активации плагина harness запрашивает значения у пользователя. Non-sensitive значения хранятся в settings.json под pluginConfigs[<plugin-id>].options. Sensitive - в системном keychain (или ~/.claude/.credentials.json). Значения доступны как ${user_config.KEY} в конфигурациях MCP/LSP и как переменные окружения CLAUDE_PLUGIN_OPTION_<KEY> в подпроцессах.
Persistent data directory
Типичный паттерн: установка зависимостей при первом запуске и переустановка при обновлении плагина. SessionStart hook сравнивает package.json из ${CLAUDE_PLUGIN_ROOT} с копией в ${CLAUDE_PLUGIN_DATA}:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/package.json\" \"${CLAUDE_PLUGIN_DATA}/package.json\" >/dev/null 2>&1 || (cd \"${CLAUDE_PLUGIN_DATA}\" && cp \"${CLAUDE_PLUGIN_ROOT}/package.json\" . && npm install) || rm -f \"${CLAUDE_PLUGIN_DATA}/package.json\""
}
]
}
]
}
}
diff возвращает ненулевой код если копия отсутствует или отличается от бандлированной версии. Если npm install провалится, rm удаляет копированный манифест, чтобы следующая сессия повторила попытку. Директория ${CLAUDE_PLUGIN_DATA} автоматически удаляется при деинсталляции плагина из последнего scope.
Источники
- Create plugins — официальная документация Claude Code.
- Plugins reference.
- Hooks.
- Sub-agents.
- Flow, Superpowers, Beads — примеры реальных плагинов.