Você construiu skills, subagents, hooks e MCP config sólidos pro seu projeto. Agora como distribuir isso pra todo o time, pra múltiplos clientes da agência, ou pra toda a organização? A resposta é plugins: pacotes versionáveis que empacotam harness engineering reutilizável. Instalados com claude plugin install, com namespace, semver, CHANGELOG, marketplace. Este módulo mostra como construir, versionar, distribuir e manter um plugin real.
Anatomia de um plugin
my-team-tools/
├── plugin.json # manifest obrigatório
├── README.md # documentação
├── CHANGELOG.md # histórico de versões (semver)
├── LICENSE
├── skills/
│ ├── commit-standard/
│ │ ├── SKILL.md
│ │ └── scripts/validate.sh
│ ├── pr-template/
│ │ └── SKILL.md
│ └── security-audit/
│ ├── SKILL.md
│ ├── scripts/run-audit.sh
│ └── reference/owasp-checklist.md
├── agents/
│ ├── code-reviewer/
│ │ └── AGENT.md
│ └── security-auditor/
│ └── AGENT.md
├── hooks/
│ └── hooks.json # hooks registrados automaticamente
├── mcp/
│ └── servers.json # MCP servers que o plugin expõe
└── tests/
├── integration.sh
└── fixtures/
└── sample-prompt.json// plugin.json
{
"name": "my-team-tools",
"version": "2.3.1",
"description": "Skills, agents e hooks padronizados do time de plataforma",
"author": "Platform Team <platform@empresa.com>",
"license": "MIT",
"homepage": "https://github.com/empresa/my-team-tools",
"repository": "git+https://github.com/empresa/my-team-tools.git",
"claudeCodeVersion": ">=2.1.0",
"entrypoints": {
"skills": "./skills/",
"agents": "./agents/",
"hooks": "./hooks/hooks.json",
"mcp": "./mcp/servers.json"
},
"settings": {
"defaultPermissions": {
"allow": ["Bash(git status)", "Bash(git diff:*)"]
}
},
"dependencies": {
"other-plugin": ">=1.0.0"
}
}Estrutura de hooks/hooks.json
// hooks/hooks.json — hooks que o plugin registra automaticamente
{
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${PLUGIN_DIR}/hooks/PreToolUse/security-check.sh",
"timeout": 10
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${PLUGIN_DIR}/hooks/PostToolUse/lint.sh"
}
]
}
],
"Stop": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "${PLUGIN_DIR}/hooks/Stop/audit.sh"
}
]
}
]
}
// ${PLUGIN_DIR} é substituído pelo caminho real do plugin instalado.
// Scripts ficam em plugin/hooks/<event>/ por convenção.Instalação e gerenciamento
# Instalar plugin de repositório Git:
claude plugin install https://github.com/empresa/my-team-tools
# Instalar versão específica (branch/tag/commit):
claude plugin install https://github.com/empresa/my-team-tools#v2.3.1
claude plugin install https://github.com/empresa/my-team-tools#develop
# Instalar de diretório local (desenvolvimento):
claude plugin install ./my-team-tools
# Listar plugins instalados:
claude plugin list
# Output típico:
# NAME VERSION SCOPE STATUS
# my-team-tools 2.3.1 user enabled
# security-scanner 1.1.0 user enabled
# legacy-plugin 0.9.0 project disabled
# Enable/disable:
claude plugin enable my-team-tools
claude plugin disable legacy-plugin
# Update:
claude plugin update my-team-tools # última versão
claude plugin update my-team-tools@2.4.0 # versão específica
# Desinstalar:
claude plugin uninstall my-team-tools
# Reload após mudanças em plugin local (dev):
/reload-plugins
# Scopes:
# - user: instalado em ~/.claude/plugins/ (todo projeto)
# - project: instalado em .claude/plugins/ (só este projeto, commitável)Marketplace: discovery e distribuição
# Listar plugins disponíveis:
claude plugin search security
claude plugin search --category deployment
# Instalar do marketplace oficial:
claude plugin install anthropic/security-scanner
# Marketplaces customizados (empresa tem o seu):
claude plugin install mycompany/team-tools --registry https://plugins.internal.empresa.com
# Configurar registry padrão:
claude plugin config set registry https://plugins.internal.empresa.com
# Marketplace interno (exemplo de servidor simples):
# - Endpoint /plugins.json lista plugins disponíveis
# - Endpoint /plugins/<name>/<version>.tar.gz serve o pacote
# - Autenticação via OAuth ou token (header Authorization)Caso real: plugin ffv-academy-tools
ffv-academy-tools/ # Plugin pro projeto do blog técnico
├── plugin.json
├── README.md
├── CHANGELOG.md
├── skills/
│ ├── novo-modulo/
│ │ ├── SKILL.md # /novo-modulo <trilha> <slug>
│ │ └── reference/
│ │ ├── module-template.md
│ │ └── conventions.md
│ ├── validar-currículo/
│ │ ├── SKILL.md # /validar-currículo
│ │ └── scripts/check-slugs.sh # detecta duplicatas
│ ├── zip/
│ │ └── SKILL.md # /zip (build + deploy script)
│ └── release-drawio/
│ ├── SKILL.md # /release-drawio
│ └── scripts/regenerate.sh
├── agents/
│ └── quiz-reviewer/
│ └── AGENT.md # revisa quizzes por qualidade pedagógica
├── hooks/
│ └── hooks.json # registra hooks do plugin
└── tests/
└── integration.sh# ffv-academy-tools/skills/novo-modulo/SKILL.md
---
name: novo-modulo
description: Cria um novo módulo/artigo na trilha correta do FFV Academy
allowed-tools: "Read Edit Write Glob Grep"
argument-hint: "[trilha-id] [slug] [título]"
---
# Novo Módulo
Trilha: $1
Slug: $2
Título: $3
## Verificações
1. Valide que trilha "$1" existe em src/lib/curriculum.ts
2. Valide que slug "$2" ainda NÃO existe no curriculum
3. Valide que slug está em kebab-case
## Criação
1. Adicione entrada de módulo em curriculum.ts (dentro da trail $1)
Use o template em ${CLAUDE_SKILL_DIR}/reference/module-template.md
2. Crie src/app/aprenda/$2/page.tsx
Use padrão dos módulos existentes da trilha
3. Adicione 3 perguntas de quiz com distratores realistas
## Convenções
Consulte ${CLAUDE_SKILL_DIR}/reference/conventions.mdVersionamento e lifecycle
| Tipo de mudança | Bump | Exemplo |
|---|---|---|
| Nova skill/agent sem mudar existentes | minor (2.3.1 → 2.4.0) | + skill /new-feature |
| Fix de bug em hook/skill existente | patch (2.3.1 → 2.3.2) | corrige regex do lint hook |
| Skill renomeada ou removida | major (2.3.1 → 3.0.0) | /deploy-v1 → /deploy |
| Hook muda matcher (comportamento) | major | PreToolUse Bash → PreToolUse Bash(git:*) |
| Tool adicionado ao allowed-tools | minor | + Edit(docs/**) |
| Tool removido de allowed-tools | major | - Write(**) |
| Estrutura de frontmatter muda | major | context: fork passa a ser obrigatório |
| Documentação ou README | patch | typo fix |
# CHANGELOG.md (padrão Keep a Changelog)
## [2.4.0] — 2026-04-15
### Added
- Skill /security-audit-quick: versão rápida do /security-audit
- Agent `performance-analyzer`: analisa queries SQL, identifica N+1
### Changed
- Skill /deploy agora suporta `--dry-run`
- Hook PostToolUse auto-format inclui .rs (rustfmt)
### Fixed
- Hook Stop no Slack: corrige escape de caracteres especiais em $USER
- Skill /pr-template: funciona em repos sem template padrão
## [2.3.1] — 2026-04-01
### Fixed
- Plugin não carregava em Windows (path separator)
## [2.3.0] — 2026-03-28
### Added
- Skill /changelog: gera CHANGELOG.md a partir de commits
- Agent `docs-writer`: gera docstrings automáticas
### Changed (BREAKING em major next)
- DEPRECATED skill /old-deploy → migrar pra /deploy antes de v3.0.0Testes para plugin profissional
#!/bin/bash
# tests/integration.sh — CI roda antes de publicar nova versão
set -e
PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$PLUGIN_DIR"
echo "▶ Validando plugin.json..."
cat plugin.json | jq . > /dev/null
VERSION=$(jq -r .version plugin.json)
echo " Versão: $VERSION"
echo "▶ Validando skills..."
for skill in skills/*/; do
NAME=$(basename "$skill")
[ -f "$skill/SKILL.md" ] || { echo "FAIL: $NAME sem SKILL.md"; exit 1; }
# Frontmatter válido?
head -30 "$skill/SKILL.md" | grep -q "^name:" || { echo "FAIL: $NAME sem frontmatter"; exit 1; }
echo " ✓ skill: $NAME"
done
echo "▶ Validando hooks..."
if [ -f "hooks/hooks.json" ]; then
cat hooks/hooks.json | jq . > /dev/null || { echo "FAIL: hooks.json inválido"; exit 1; }
# Scripts referenciados existem?
for script in $(jq -r '.. | .command? // empty' hooks/hooks.json); do
RESOLVED=$(echo "$script" | sed "s|\${PLUGIN_DIR}|$PLUGIN_DIR|")
[ -x "$RESOLVED" ] || { echo "FAIL: hook script não executável: $RESOLVED"; exit 1; }
done
fi
echo "▶ Teste de smoke: instalação local e invocação de skill..."
TMPDIR=$(mktemp -d)
cp -r . "$TMPDIR/plugin"
claude plugin install "$TMPDIR/plugin" --scope user-local
claude -p "/validate-plugin-test" --max-turns 1 || true
claude plugin uninstall $(jq -r .name plugin.json)
rm -rf "$TMPDIR"
echo "✅ Todos os checks passaram"Plugins transformam harness em produto interno. O que começa como “ah, commitei umas skills em .claude/” vira “distribuímos v2.4 do plugin em 15 repos da org com um comando”. Empacote quando houver reúso real (3+ projetos, 2+ times). Versione com semver. Documente com CHANGELOG. Teste com CI. Namespace para permitir overrides. Publique num marketplace interno. Esse é o próximo nível de produtividade — cada dev novo já chega com o harness do time carregado.
Último módulo da trilha: Claude Agent SDK em produção — quando sair do CLI e usar o SDK Python/TypeScript. query(), custom tools, subagents programáticos, hooks programáticos, MCP servers. Dois scripts reais: GitHub Action que revisa PRs e cron de PR triage em Node.