Tutorial de Claude Code Mods: como criar, testar e instalar seu primeiro mod, com 15 exemplos da comunidade
Atualizado em

Um mod do Claude Code é um plugin feito de funções JavaScript ou TypeScript que rodam dentro do Claude Code. Um mod pode desenhar um painel ou uma linha acima do prompt, adicionar um slash command que roda na hora e barrar ou reescrever uma chamada de ferramenta antes que ela rode. Os mods chegaram no Claude Code 2.1.287, em 1º de outubro de 2026, e vêm ativados por padrão.
Escolha o caminho mais rápido:
| Você quer | Faça isto |
|---|---|
| Ter um mod sem escrever código | Descreva o mod numa sessão, por exemplo "crie um mod que mostre quanto tempo cada turno levou". O Claude escreve o código e pergunta uma vez se pode ativar o hot reload |
| Instalar o mod de outra pessoa | /plugin install <name>@<marketplace> numa sessão no terminal, ou claude plugin install <name>@<marketplace> no seu shell |
| Carregar uma pasta enquanto desenvolve | claude --plugin-dir ./my-mod |
| Testar o agente lateral embutido | /plugin enable cc-plugin-you-should-know@builtin |
Antes de tudo, confira sua versão. O claude --version deve mostrar 2.1.287 ou mais recente. O app Desktop traz a própria cópia do Claude Code, e nele os mods funcionam a partir da 2.1.286. Digite /status na aba Code para ver qual versão você tem.
O que eu testei. Em 7 de outubro de 2026, criei três mods no Claude Code 2.1.293, na aba Code do app Desktop no macOS: um guard de comandos, um medidor de turno acima do prompt e um comando
/pyenvpara trabalho com Python. Os três passam noclaude plugin validatee em 8 testes automatizados rodados comclaude plugin test. Também rodei o guard ao vivo numa sessão com hot reload ativado. As seções sobre a comunidade se baseiam em cerca de 50 posts em japonês publicados no Zenn, no Qiita e no note.com entre 1º e 7 de outubro, na documentação oficial de mods (opens in a new tab) e nos dados de varredura do catálogo awesome-claude-code-mods (opens in a new tab) de 6 de outubro.
- Tutorial de Claude Code Mods: como criar, testar e instalar seu primeiro mod, com 15 exemplos da comunidade
- GPT Image 2.5: como usar, Flare vs Sunburst e preços da API
- Como usar o DeepSeek Harness: instalar, configurar e rodar seu primeiro agente
- Runcell Science: alternativa open source ao Claude Science para pesquisa com IA
- Como impedir o Mac de dormir: mantenha Codex, Claude Code e agentes de IA rodando
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot: qual stack de agentes de IA você deve escolher em 2026?
- Como o Claude Code analisa notebooks Jupyter em Data Science: capacidade real, limites e alternativa melhor
- Claude Code Routines: rotinas e cron jobs para agentes de IA
- Claude Code Desktop: como ativar Bypass permissions
- Como Construir Dois Agentes Python com o Protocolo A2A do Google - Tutorial Passo a Passo
- Top 10 bibliotecas de visualização de dados em Python em 2025
O que é um mod e quando usar outra coisa
Antes dos mods, você estendia o Claude Code por fora, com settings hooks, skills, um script de status line ou um servidor MCP. A diferença está em onde o código roda. Um settings hook é um script que o Claude Code inicia por fora. As funções de um mod rodam dentro do próprio processo do Claude Code. Por isso um mod consegue desenhar na interface, e nenhuma das outras opções consegue.
A visão geral oficial compara as opções mais ou menos assim:
| Mod | Settings hook | Skill | Servidor MCP | |
|---|---|---|---|---|
| O que é | Funções JS ou TS num plugin | Um comando de shell, uma chamada HTTP ou um prompt no settings.json | Um arquivo SKILL.md com instruções | Um processo externo que dá ferramentas ao Claude |
| Pode desenhar na UI | Sim | Não | Não | Não |
| O que pode mudar | Chamadas de ferramenta, prompts, comandos, turnos, a UI | Se uma chamada segue adiante, seus argumentos e seu resultado, contexto extra | O que o Claude sabe e faz | Quais ferramentas o Claude tem |
| Escolha quando | Você quer um painel, uma faixa, um comando instantâneo ou reescrever um evento | Você já tem um script que bloqueia ou registra logs | Você vive colando as mesmas instruções | O Claude precisa acessar um sistema externo |
Uma armadilha de nomes. Nas páginas sobre mods, "hook" quer dizer uma função de um mod, e o tipo antigo se chama "settings hook". Os settings hooks continuam funcionando e não foram descontinuados. Um mesmo plugin pode reunir um mod, uma skill e um servidor MCP.
Onde os mods funcionam
Os hooks rodam em quase todo lugar. Já o desenho só acontece no terminal e no app Desktop.
| Onde você roda o Claude Code | Os hooks rodam | A UI do mod aparece |
|---|---|---|
claude num terminal, incluindo terminais de editores e JetBrains | Sim | Sim |
| App Desktop, aba Code | Sim | Sim, exceto elementos exclusivos do terminal |
| App Desktop, sessão WSL | Não | Não |
| Painel de chat da extensão do VS Code | Sim | Não |
claude -p e o Agent SDK | Sim | Não |
| Sessões na nuvem | Sim, se o plugin chegar à sessão | Não |
Essa tabela vem da visão geral oficial. Na prática, um mod de guard continua protegendo você no VS Code e no claude -p, enquanto um medidor não tem onde desenhar.
Cuidado com duas cópias do Claude Code. Vários autores japoneses viram erros confusos no validate porque um CLI antigo do Homebrew no terminal, nas versões 2.1.226 e 2.1.234 segundo os relatos, convivia com a 2.1.286 embutida no app Desktop. Confira a versão em cada lugar onde você usa o Claude Code.
Como um mod é organizado
Um mod pequeno tem três arquivos:
safe-shell/
├── .claude-plugin/
│ └── plugin.json name, version, description
└── hooks/
├── hooks.json { "modules": ["./register.ts"] }
└── register.ts your codeO register.ts exporta uma função, register(on). Cada chamada on(event, matcher, hook) adiciona um hook, e todo hook recebe os mesmos três argumentos.
$é a engine. Tudo o que fica fora do seu código passa por ela:$.ui.toast,$.process.run,$.state,$.model.complete.eé o evento, por exemplo o comando Bash que o Claude está prestes a rodar.next(e)entrega o evento aos outros mods e depois ao Claude Code. Se você retornar sem chamá-lo, seu hook responde sozinho. Se chamarnext({ ...e, command }), você muda o que acontece.
O módulo não tem Node nem DOM. É esse limite que permite ao Claude Code listar tudo o que um mod chama antes de ele rodar. Teste em qualquer pasta de mod:
claude plugin validate ./safe-shellMod 1: um guard que bloqueia comandos destrutivos
Se você roda o Claude em auto mode ou com bypass permissions, nada o impede antes de um git reset --hard. Este mod recusa três tipos de comando de shell e mantém os arquivos .env fora da conversa.
import type { Register } from 'claude-code'
// Shell commands an agent should never run without a human typing them.
const BLOCKED: { pattern: RegExp; reason: string }[] = [
{
pattern: /\brm\s+-[a-zA-Z]*[rR][a-zA-Z]*\s+(\/|~|\$HOME)\/?\*?(\s|$)/,
reason: 'recursive delete of / or the home folder',
},
{
pattern: /\bgit\s+push\b.*(--force\b|--force-with-lease\b|\s-f\b).*\b(main|master)\b/,
reason: 'force push to main or master',
},
{
pattern: /\bgit\s+reset\s+--hard\b/,
reason: 'git reset --hard throws away uncommitted work',
},
]
// .env, .env.local, config/.env.production ... but not .env.example.
const isSecretEnvFile = (path: string) =>
/(^|\/)\.env(\.[^/]+)?$/.test(path) && !/\.(example|sample|template)$/.test(path)
export const register: Register = on => {
on('tool.call', { tool: 'Bash' }, ($, e, next) => {
const hit = BLOCKED.find(rule => rule.pattern.test(e.command))
if (hit === undefined) {
return next(e)
}
$.ui.toast(`safe-shell blocked: ${hit.reason}`)
return { deny: `safe-shell: blocked (${hit.reason}). Ask the user to run it themselves.` }
}).catch(($, e, next) =>
// Fail closed: if the guard itself breaks, refuse instead of letting the command through.
next.called ? next(e) : { deny: 'safe-shell: the guard failed, so the command was not run.' },
)
for (const tool of ['Read', 'Edit', 'Write'] as const) {
on('tool.call', { tool }, ($, e, next) =>
isSecretEnvFile(e.file_path)
? { deny: `safe-shell: ${e.file_path} holds secrets and stays out of the conversation.` }
: next(e),
).catch(($, e, next) =>
next.called ? next(e) : { deny: 'safe-shell: the guard failed, so the file was not touched.' },
)
}
}Dois detalhes importam mais do que as regexes.
O guard decide antes de chamar next. Depois que o next roda, o comando já rodou. Um deny retornado depois disso não desfaz nada.
O .catch faz o guard falhar fechado. Quando um hook lança um erro ou estoura o limite de 10 segundos, o Claude Code pula esse hook, e um guard pulado deixa o comando passar. O handler next.called ? next(e) : deny recusa o comando nesse caso. O validate lista cada hook que decide se uma chamada segue e diz se ele tem um .catch. É a primeira coisa a conferir no guard de outra pessoa:
❯ ./register.ts hooks: tool.call{tool=Bash}, tool.call{tool=Read|Edit|Write}
❯ ./register.ts gating hook with .catch: tool.call{tool=Bash}
❯ ./register.ts gating hook with .catch: tool.call{tool=Read|Edit|Write}
❯ ./register.ts calls: $.ui.toast
✔ Validation passedTeste sem abrir uma sessão
O claude plugin test roda os arquivos *.test.ts de um mod contra a engine, sem sessão, sem login e sem rede. O kit de testes não tem nada abaixo do seu mod, então cada teste registra hooks substitutos para tudo o que o mod repassa:
import { expect, test } from 'claude-code/testing'
const ran = { stdout: 'ran', stderr: '', interrupted: false }
test('blocks rm -rf on the home folder', async ($, on) => {
on('tool.call', { tool: 'Bash' }, () => ({ result: ran }))
const answer = await $.tool.call({ tool: 'Bash', command: 'rm -rf ~' })
expect(answer.deny).toContain('recursive delete')
})
test('lets ordinary commands through', async ($, on) => {
on('tool.call', { tool: 'Bash' }, () => ({ result: ran }))
const answer = await $.tool.call({ tool: 'Bash', command: 'rm -rf ./build && python -m pytest -q' })
expect(answer.deny).toBeUndefined()
})O arquivo completo tem quatro testes:
(pass) blocks rm -rf on the home folder [16.23ms]
(pass) blocks a force push to main [7.73ms]
(pass) lets ordinary commands through [7.22ms]
(pass) keeps .env out of Read but allows .env.example [9.40ms]
4 pass
0 failMinha primeira execução falhou com on("tool.call") after the test first called $. Registre os substitutos no começo de cada teste, antes da primeira chamada a $.
O que aconteceu numa sessão ao vivo
Com o hot reload ativado, pedi para o Claude rodar echo "the words git reset --hard inside an echo". O guard recusou com "blocked (git reset --hard throws away uncommitted work)", e apareceu um toast. Esse echo era inofensivo. A comparação por padrões não distingue um comando de um texto que só o menciona, e também deixa passar um comando escondido numa variável, num script ou num alias. Autores japoneses que publicaram guards parecidos, como rafi-guard, delete-guard e board-guard, relatam os dois problemas.
Trate um mod de guard como uma segunda rede de proteção. O que nunca pode acontecer também deve estar numa regra de permissão deny. Fique atento ao sentido contrário também. A documentação oficial diz que, numa máquina pessoal sem configurações gerenciadas, um mod pode aprovar uma chamada que uma regra deny recusa. Os mods não rodam em sandbox. Eles rodam com as suas permissões.
Mod 2: um medidor acima do prompt
A faixa acima do prompt e o painel lateral são onde os mods mais desenham. Na varredura do catálogo de 6 de outubro, 41% dos mods desenham na faixa e 40% abrem um painel. Este mod mostra o tempo, as chamadas de ferramenta e os tokens do último turno, com um botão Hide.
Os valores que um desenho lê ficam em $.state, e você declara cada um num pequeno arquivo de tipos:
// types/index.d.ts, named in plugin.json as "types": "./types/index.d.ts"
export type TurnStats = {
seconds: number
tools: number
inputTokens: number
outputTokens: number
model: string | null
}
declare module 'claude-code' {
interface PluginState {
'turn-meter': { last: TurnStats | null; isHidden: boolean }
}
}Os hooks contam as chamadas de ferramenta, leem durationMs e usage de turn.complete e desenham a faixa:
import { atom, read, update } from 'claude-code'
import type { Register } from 'claude-code'
import type { TurnStats } from '../types'
const last = atom({ plugin: 'turn-meter', key: 'last' } as const, null)
const isHidden = atom({ plugin: 'turn-meter', key: 'isHidden' } as const, false)
const formatTokens = (n: number) => (n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n))
export const register: Register = on => {
let tools = 0
on('prompt.submit', ($, e, next) => {
tools = 0
return next(e)
})
on('tool.call', ($, e, next) => {
// Count the main conversation's calls; subagents carry an agentId.
if (e.agentId === undefined) tools += 1
return next(e)
})
on('turn.complete', async ($, e, next) => {
if (e.agentId !== undefined) return next(e)
const usage = e.usage
const stats: TurnStats = {
seconds: Math.round(e.durationMs / 1000),
tools,
inputTokens: usage
? usage.input_tokens + usage.cache_read_input_tokens + usage.cache_creation_input_tokens
: 0,
outputTokens: usage?.output_tokens ?? 0,
model: usage?.model ?? null,
}
await update($, last, () => stats)
if (stats.seconds > 120) $.ui.toast(`That turn took ${stats.seconds}s`)
return next(e)
})
on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
const stats = await read($, last)
if (e.props.hasSurvey || stats === null || (await read($, isHidden))) return next(e)
const { Box, Button, Text } = $.ui.resolve(e)
const model = stats.model === null ? '' : ` · ${stats.model}`
// The band is shared by every mod: keep what the mods beneath drew, then add a row.
const below = await next(e)
return (
<Box flexDirection="column">
{below}
<Box>
<Text dimColor>
{`Last turn: ${stats.seconds}s · ${stats.tools} tool calls · ${formatTokens(stats.inputTokens)} in / ${formatTokens(stats.outputTokens)} out${model} `}
</Text>
<Button key="hide" label="Hide" onPress={() => update($, isHidden, () => true)} />
</Box>
</Box>
)
})
}No teste, tanto no terminal quanto no Desktop, a faixa mostra:
Last turn: 42s · 0 tool calls · 18.2k in / 800 out · claude-opus-5-5 [ Hide ]Três coisas que aprendi construindo este mod:
- Guarde os valores desenhados em
$.state, não em variáveis do módulo. Um hot reload roda oregisterde novo e zera suas variáveis, mas o$.statesobrevive. O/clearrecomeça do zero, então grave em$.storenosession.endse um valor precisar durar mais do que isso. - A faixa é compartilhada. Chame
next(e)e coloque o resultado dentro do seuBox, senão você esconde a linha de todos os outros mods. Um autor do note.com perdeu uma faixa para outro mod antes de descobrir isso. - Elementos
Textnão guardamkey. Nos testes, encontre-os pelo texto que exibem:ui.find({ type: 'Text', text: /Last turn/ }).
Mod 3: /pyenv, para quando o Claude roda o Python errado
Fui atrás de mods para ciência de dados e encontrei uma lacuna. Dos 2.690 mods da varredura de 6 de outubro, nenhum menciona Jupyter, pandas, DataFrames, Polars, venv ou conda no nome ou na descrição.
O problema por trás deste mod é comum em trabalho com dados. A ferramenta Bash do Claude roda o python3 que aparecer primeiro no seu PATH, e muitas vezes esse não é o ambiente do seu projeto. Veja o que a verificação imprimiu na minha máquina:
python: /Users/<you>/.local/bin/python3 (3.14.2)
env: none (system or tool-managed Python)
pandas: 3.0.1
numpy: 2.4.2
polars: not installed
matplotlib: 3.11.0
pygwalker: not installedNenhum ambiente virtual estava ativo, então um pip install feito pelo Claude teria ido para um interpretador global.
O comando /pyenv roda essa verificação e responde em duas partes. text é a linha que você vê. context é uma nota que só o modelo lê, assim as próximas chamadas Bash do Claude já sabem qual interpretador está em uso, sem você precisar escrever outro prompt.
import type { Register } from 'claude-code'
// Reads package versions from metadata instead of importing them, so it stays fast.
const PROBE = `
import os, sys
from importlib.metadata import PackageNotFoundError, version
env = os.environ.get("VIRTUAL_ENV") or os.environ.get("CONDA_PREFIX") or "none (system or tool-managed Python)"
print(f"python: {sys.executable} ({sys.version.split()[0]})")
print(f"env: {env}")
for name in ("pandas", "numpy", "polars", "matplotlib", "pygwalker"):
try:
print(f"{name}: {version(name)}")
except PackageNotFoundError:
print(f"{name}: not installed")
`
export const register: Register = on => {
on('session.start', async ($, e, next) => {
await $.command.register({
name: 'pyenv',
description: "Show which Python, environment and data packages this session's shell uses",
})
return next(e)
})
on('command.run', { command: 'pyenv' }, async $ => {
try {
const probe = await $.process.run(['python3', '-c', PROBE], { timeoutMs: 15_000 })
if (probe.exitCode !== 0) {
return { text: `pyenv: python3 exited with ${probe.exitCode}: ${probe.stderr.trim().slice(0, 300)}` }
}
const report = probe.stdout.trim()
// `text` is the row you see; `context` is a note only the model reads.
return {
text: report,
context: [`Python environment of this session's shell, from /pyenv:\n${report}`],
}
} catch (error) {
return { text: `pyenv: could not run python3 (${String(error).slice(0, 200)})` }
}
})
}O slash command de um mod roda sua função na hora, sem turno do modelo, mesmo com o Claude ocupado. O $.process.run recebe uma lista de argumentos, sem shell, e expira depois de 30 segundos, a menos que você defina timeoutMs.
O $.process.run enxerga o mesmo PATH da ferramenta Bash do Claude? Um autor da comunidade notou que o node do nvm não aparecia nos processos de um mod, então conferi com um mod temporário de verificação. Na minha sessão do Desktop, um $.process.run simples recebeu exatamente o PATH da ferramenta Bash e o mesmo python3. Rodar a verificação por um login shell, com zsh -lc, deu a resposta errada. Ele encontrou o 3.10.9 do python.org, porque um login shell não interativo pula o ~/.zshrc, onde fica a maior parte das adições ao PATH. Fique com a chamada simples. Se o resultado parecer estranho na sua máquina, compare com !which python3 digitado no prompt do Claude Code.
Testar esse mod revelou mais uma armadilha. As chamadas em $, como $.process.run e $.command.register, também precisam de substitutos, e um substituto para uma chamada a $ responde { value: ... }. Se você retornar o resultado puro, o kit recusa.
Se a maior parte da sua análise acontece em notebooks, e não em scripts, isso só ajuda até certo ponto, porque o Claude Code edita arquivos .ipynb como JSON e nunca vê o kernel em execução. O RunCell (opens in a new tab) é um agente para notebooks que roda células e lê a saída delas diretamente, por isso serve melhor para esse tipo de trabalho.
Deixe o Claude escrever o mod
Você não precisa escrever nada disso à mão. Peça numa sessão, por exemplo "crie um mod que mostre meu uso de 5 horas acima do prompt". O Claude carrega a skill embutida plugin-authoring e grava os arquivos em ~/.claude/dev-mods/<session-id>/. O primeiro arquivo dispara uma única pergunta, "Enable hot reloading for this session?". Depois que você aceita, o Claude Code recarrega cada edição quando o turno do Claude termina. Foi assim que criei e carreguei os três mods acima.
O que a documentação e a comunidade acrescentam:
- Copie a pasta para um lugar permanente. Autores no Qiita e no Zenn relatam que as pastas de dev-mods são apagadas junto com as sessões antigas depois de cerca de 30 dias.
- Desenvolva com
claude --plugin-dir ./my-mod. Um mod instalado roda uma cópia em cache, então editar a pasta dele não muda nada até você atualizar o plugin. - O app Desktop não aceita flags. Defina
CLAUDE_CODE_PLUGIN_DIRSno blocoenvdo~/.claude/settings.json. As configurações de projeto não valem para isso. - Rode
/plugin. Uma linha esmaecida como1 mod active · safe-shellconfirma que o mod carregou. - Comece com
claude --debugenquanto desenvolve. O log de debug aponta cada hook pulado e cada desenho que a engine recusou.
15 mods da comunidade que vale a pena estudar
O catálogo awesome-claude-code-mods (opens in a new tab), com 316 estrelas, varreu 2.690 mods públicos em 1.265 repositórios no dia 6 de outubro, cinco dias depois do lançamento. Os dados da varredura mostram o que as pessoas constroem:
- 68% adicionam um slash command
- 53% interceptam chamadas de ferramenta
- 41% desenham acima do prompt, 40% abrem um painel
- 40% iniciam processos, 12% chamam um modelo, 11% usam a rede
Estes 15 mostram a variedade. As estrelas são de 7 de outubro de 2026.
| Mod | O que faz | Estrelas | Por que ler |
|---|---|---|---|
| terminal-browser (opens in a new tab) | Um navegador web ao lado da conversa para sites, previews de HTML local e pull requests | 3.695 | O painel mais ambicioso até agora |
| claude-image-view (opens in a new tab) | Miniaturas das imagens coladas acima do prompt, no lugar de [Image #1] | 160 | Desenhar imagens no terminal |
| hamzafer/claude-code-mods (opens in a new tab) | Um conjunto com barra de contexto, guard de blast radius, preview de Markdown e painel de subagents | 138 | Vários tipos de mod num só repositório |
| claude-auto-handoff (opens in a new tab) | Passa uma sessão longa para uma sessão nova com um resumo estruturado | 60 | Gerenciamento de contexto |
| prismantis (opens in a new tab) | Respostas com tema: tabelas, código, gráficos em arte de caracteres, texto da direita para a esquerda | 49 | Mudar o visual das próprias mensagens do Claude |
| cc-arcade (opens in a new tab) | Nove jogos acima do prompt que pausam quando o Claude termina | 41 | Animação com um relógio de quadros |
| jev-permission-gate (opens in a new tab) | Um modelo de decisão Jev julga as chamadas de ferramenta no auto mode | 28 | Uma seção de privacidade cuidadosa: ele envia suas três últimas mensagens, com até 1.500 caracteres cada, para a API da TypeSafe |
| prompt-rail (opens in a new tab) | Uma barra com seus prompts anteriores; passe o mouse para ler, clique para ir até ele | 22 | Destaque da análise de mods em japonês mais curtida no Zenn |
| claude-paste-view (opens in a new tab) | Prévia de imagens coladas e de textos longos colados | 18 | Código pequeno e fácil de ler |
| claude-gfm-render (opens in a new tab) | Alertas do GitHub, listas de tarefas e Mermaid nas respostas, em arte de caracteres ou SVG | 14 | Desenhar de um jeito diferente em cada superfície |
| claude_qamods (opens in a new tab) | O qa-guide explica as perguntas e as opções do Claude num painel lateral | 10 | Melhorar um diálogo nativo |
| CC-Usage-Band (opens in a new tab) | Limites de 5 horas e de 7 dias, contexto e taxa de acerto do cache acima do prompt | 10 | O tipo de mod mais comum: um medidor |
| harness-scope (opens in a new tab) | Perfis por repositório que escondem skills, agents e regras globais | 1 | O autor mediu a lista de skills caindo de 98 para 49 entradas |
| touch-map (opens in a new tab) | Mostra quais arquivos o Claude listou, leu, editou ou criou | 0 | O autor viu que o Claude mexeu em 125 de 304 arquivos durante um único levantamento para refatoração |
| claude-mods-router (opens in a new tab) | Encaminha cada prompt para um nível de esforço com $.model.classify | 0 | O artigo no Qiita, com 26 curtidas, observa que trocar de modelo quebra o cache de prompt |
A Anthropic também publica três exemplos no claude-code-playground (opens in a new tab): token-weather, blast-radius e replay-theater. O código-fonte dos mods embutidos, entre eles o /diff, está no repositório claude-code (opens in a new tab).
Boas práticas que a comunidade adotou
Na primeira semana, só os autores japoneses publicaram cerca de 50 posts com mods funcionando, medições e relatos de falhas. Estes são os hábitos que mais se repetiram.
- Leia um mod antes de instalar. Clone o repositório, rode
claude plugin validatee leia as linhashooks:ecalls:. Leia o código-fonte onde aparecer$.process,$.http,$.fs.write,$.env.getou$.model. Rode a validação de novo a cada atualização. Passar na validação significa que a engine consegue carregar o código, não que o código é seguro. - Guards decidem antes do
nexte falham fechados. Mods que só observam devem falhar abertos, com.catch(($, e, next) => next(e)), para que um bug num medidor nunca bloqueie seu trabalho. - Espere dentro das chamadas a
$. Um hook tem 10 segundos de tempo próprio. Um$.process.runou um$.ui.askem andamento não conta nesse limite, mas as suas próprias promises contam. - Nunca guarde nem desestruture
$. Passe o$só para funções declaradas no nível superior do arquivo. Vários autores tinham mods que falhavam ao carregar sem nenhum aviso até corrigirem isso. - Cuidado com o cache de prompt. Trocar de modelo no meio da sessão, ou mudar o system prompt entre requisições, joga o cache fora.
- Trate cada
e.surfaceseparadamente.Svgsó desenha no app Desktop.RastereImagesó desenham no terminal. - Fixe uma versão para uso em equipe. A API está em acesso antecipado e muda entre versões. Cinco das seis versões lançadas depois da estreia, da 2.1.288 à 2.1.293, mudaram ou corrigiram o comportamento dos mods.
Mascarar segredos é a história que serve de alerta. Um autor do note.com criou um mod que trocava as chaves de API na saída das ferramentas antes que o Claude as visse. Mesmo assim, o Claude imprimiu os valores reais ao depurar com od -c uma edição que falhou, e um Write do arquivo inteiro gravou os placeholders por cima das chaves verdadeiras. Só uma regra de permissão deny no arquivo resistiu. Um mod que muda o que aparece na tela não esconde nada do modelo.
Problemas comuns
| Sintoma | Causa provável | Solução |
|---|---|---|
O /plugin não lista o mod | Pasta não confiável, --safe-mode, --bare ou disableAllHooks | Marque a pasta como confiável e reinicie sem a flag |
hooks modules are turned off in this process | A Anthropic desligou remotamente os mods instalados | Não há nada para mudar na sua máquina. Atualize, porque a 2.1.289 e a 2.1.290 corrigiram dois casos em que os mods continuavam desligados |
O validate falha com "expected record, received undefined" | Um CLI antigo aparece antes no seu PATH | Rode claude --version e atualize |
| Um hook é pulado sem erro visível | Ele lançou um erro, por exemplo ao chamar $.plugin.name(), que é uma propriedade | Rode claude --debug e leia a linha do hook pulado |
| Um painel nunca abre | Um painel que abre sem você pedir espera a janela ter 144 colunas, só fica ao lado da transcrição no layout em tela cheia, e o /diff pode cobri-lo | Aumente a largura da janela, teste o layout em tela cheia, feche o /diff |
| Funciona no terminal, mas não no Desktop | O Desktop traz a própria versão, e alguns elementos só existem no terminal | Confira o /status na aba Code e trate cada e.surface separadamente |
Nenhuma UI de mod no VS Code ou no claude -p | Essas superfícies não desenham | Use como alternativa uma linha na transcrição ou o texto de um comando |
| Um teste falha com "nothing beneath the plugins answers" | O kit de testes não tem engine | Adicione hooks substitutos e responda às chamadas a $ com { value } |
Compartilhe seu mod
Coloque um marketplace.json ao lado do plugin.json, dentro de .claude-plugin/:
{
"name": "my-mods",
"owner": { "name": "you" },
"plugins": [{ "name": "safe-shell", "source": "./" }]
}Faça push da pasta para o GitHub. Depois disso, qualquer pessoa pode instalar o mod numa sessão no terminal:
/plugin install safe-shell --marketplace you/safe-shellNo app Desktop, em sessões locais e SSH, o caminho é +, depois Plugins, depois Add plugin. Se você adicionar o tópico claude-code-mod ao repositório, o catálogo da comunidade costuma incluir o mod poucas horas depois do seu próximo push.
FAQ
Guias relacionados
- Claude Code Desktop: como ativar Bypass permissions
- Claude Code Routines: rotinas e cron jobs para agentes de IA
- Construa um Agente de IA Estilo Claude Code com Claude Agent SDK (TypeScript)
- Guia prático de como usar o OpenCode: primeiros passos, 7 dicas e quando somar Oh My OpenCode
- Guia prático de como usar o Codex: primeiros passos, 5 dicas e best practices