Tutorial de Claude Code Mods: cómo crear, probar e instalar tu primer mod, con 15 ejemplos de la comunidad
Actualizado el

Un mod de Claude Code es un plugin hecho de funciones JavaScript o TypeScript que se ejecutan dentro de Claude Code. Un mod puede dibujar un panel o una fila encima del prompt, añadir un comando slash que se ejecuta al instante y detener o reescribir una llamada a herramienta antes de que se ejecute. Los mods llegaron con Claude Code 2.1.287 el 1 de octubre de 2026 y vienen activados por defecto.
Elige la forma más rápida de empezar:
| Si quieres | Haz esto |
|---|---|
| Tener un mod sin escribir código | Descríbelo en una sesión, por ejemplo "crea un mod que muestre cuánto tardó cada turno". Claude lo escribe y te pregunta una vez si quieres activar la recarga en caliente |
| Instalar el mod de otra persona | /plugin install <name>@<marketplace> en una sesión de terminal, o claude plugin install <name>@<marketplace> en tu shell |
| Cargar una carpeta mientras desarrollas | claude --plugin-dir ./my-mod |
| Probar el agente lateral integrado | /plugin enable cc-plugin-you-should-know@builtin |
Primero comprueba tu versión. claude --version debería mostrar 2.1.287 o posterior. La app de escritorio trae su propia copia de Claude Code, y ahí los mods funcionan desde la 2.1.286. Escribe /status en la pestaña Code para ver cuál tienes.
Qué probé. El 7 de octubre de 2026 creé tres mods con Claude Code 2.1.293 en la pestaña Code de la app de escritorio, en macOS: un guardián de comandos, un medidor de turnos encima del prompt y un comando
/pyenvpara trabajar con Python. Los tres pasanclaude plugin validatey 8 pruebas automatizadas conclaude plugin test. También ejecuté el guardián en vivo, en una sesión con la recarga en caliente activada. Las secciones sobre la comunidad se basan en unos 50 artículos en japonés de Zenn, Qiita y note.com, escritos del 1 al 7 de octubre, en la documentación oficial de los mods (opens in a new tab) y en los datos de escaneo del catálogo awesome-claude-code-mods (opens in a new tab) del 6 de octubre.
- Tutorial de Claude Code Mods: cómo crear, probar e instalar tu primer mod, con 15 ejemplos de la comunidad
- Cómo usar GPT Image 2.5: Flare vs. Sunburst y precios de la API
- Cómo usar DeepSeek Harness: instalación, configuración y tu primer agente
- Runcell Science: alternativa open source a Claude Science para investigación
- Cómo evitar que Mac se duerma: mantener Codex, Claude Code y agentes de IA corriendo
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot: ¿Qué stack de agentes de IA deberías elegir en 2026?
- Cómo Claude Code analiza notebooks de Jupyter en Data Science: lo que sí hace y lo que no
- Claude Code routines: qué son y por qué importan los cron jobs de agentes de IA
- Claude Code Desktop Bypass Permissions: cómo activarlo
- Cómo Construir Dos Agentes en Python con el Protocolo A2A de Google - Tutorial Paso a Paso
- Las 10 principales bibliotecas de visualización de datos en Python que crecen en 2025
Qué es un mod y cuándo usar otra cosa
Antes de los mods, ampliabas Claude Code desde fuera, con hooks de configuración, skills, un script para la línea de estado o un servidor MCP. La diferencia está en dónde se ejecuta el código. Un hook de configuración es un script que Claude Code lanza desde fuera. Las funciones de un mod se ejecutan dentro del propio proceso de Claude Code, así que un mod puede dibujar en la interfaz y ninguna de las otras opciones puede.
La página oficial de introducción los compara más o menos así:
| Mod | Hook de configuración | Skill | Servidor MCP | |
|---|---|---|---|---|
| Qué es | Funciones JS o TS en un plugin | Un comando de shell, una llamada HTTP o un prompt en settings.json | Un archivo SKILL.md con instrucciones | Un proceso externo que le da herramientas a Claude |
| Puede dibujar en la interfaz | Sí | No | No | No |
| Qué puede cambiar | Llamadas a herramientas, prompts, comandos, turnos, la interfaz | Si una llamada sigue adelante, sus argumentos y su resultado, contexto adicional | Lo que Claude sabe y hace | Qué herramientas tiene Claude |
| Elígelo cuando | Quieres un panel, una franja, un comando instantáneo o reescribir un evento | Ya tienes un script que bloquea o registra | Pegas una y otra vez las mismas instrucciones | Claude necesita llegar a un sistema externo |
Una trampa con los nombres. En las páginas de los mods, "hook" significa una función de un mod, y el tipo antiguo se llama "settings hook", lo que aquí llamo hook de configuración. Los hooks de configuración siguen funcionando y no están obsoletos. Un mismo plugin puede contener a la vez un mod, una skill y un servidor MCP.
Dónde funcionan los mods
Los hooks se ejecutan casi en todas partes. Los mods solo dibujan en la terminal y en la app de escritorio.
| Dónde ejecutas Claude Code | Se ejecutan los hooks | Aparece la interfaz del mod |
|---|---|---|
claude en una terminal, incluidas las terminales de editores y JetBrains | Sí | Sí |
| App de escritorio, pestaña Code | Sí | Sí, salvo los elementos exclusivos de la terminal |
| App de escritorio, sesión WSL | No | No |
| Panel de chat de la extensión de VS Code | Sí | No |
claude -p y el Agent SDK | Sí | No |
| Sesiones en la nube | Sí, si el plugin llega a la sesión | No |
Esta tabla sale de la página oficial de introducción. En la práctica, un mod guardián te sigue protegiendo en VS Code y en claude -p, mientras que un medidor no tiene dónde dibujar.
Cuidado con tener dos copias de Claude Code. Varios autores japoneses recibieron errores confusos de validate porque una CLI de terminal antigua instalada con Homebrew, las versiones 2.1.226 y 2.1.234 según sus artículos, convivía con la 2.1.286 que trae la app de escritorio. Comprueba la versión en cada lugar donde uses Claude Code.
Cómo se organiza un mod
Un mod pequeño ocupa tres archivos:
safe-shell/
├── .claude-plugin/
│ └── plugin.json name, version, description
└── hooks/
├── hooks.json { "modules": ["./register.ts"] }
└── register.ts your coderegister.ts exporta una sola función, register(on). Cada llamada a on(event, matcher, hook) añade un hook, y todos los hooks reciben los mismos tres argumentos.
$es el motor. Todo lo que queda fuera de tu propio código pasa por él:$.ui.toast,$.process.run,$.state,$.model.complete.ees el evento, por ejemplo el comando de Bash que Claude está a punto de ejecutar.next(e)pasa el evento a los demás mods y después a Claude Code. Si devuelves un valor sin llamarlo, tu hook responde por su cuenta. Si llamas anext({ ...e, command }), cambias lo que ocurre.
El módulo no tiene Node ni DOM. Ese límite es lo que permite a Claude Code listar todo lo que llama un mod antes de que se ejecute. Pruébalo con la carpeta de cualquier mod:
claude plugin validate ./safe-shellMod 1: un guardián que bloquea comandos destructivos
Si ejecutas Claude en auto mode o con bypass permissions, nada lo frena antes de un git reset --hard. Este mod rechaza tres tipos de comando de shell y deja los archivos .env fuera de la conversación.
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.' },
)
}
}Dos detalles importan más que las expresiones regulares.
El guardián decide antes de llamar a next. En cuanto next se ejecuta, el comando ya se ha ejecutado. Un deny devuelto después no deshace nada.
El .catch hace que falle en cerrado. Claude Code omite un hook que lanza una excepción o que supera su límite de 10 segundos, y un guardián omitido deja pasar el comando. El manejador next.called ? next(e) : deny hace lo contrario y rechaza el comando. validate lista cada hook que puede bloquear una llamada e indica si tiene un .catch. Es lo primero que debes revisar en el guardián de otra persona:
❯ ./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 passedPruébalo sin una sesión
claude plugin test ejecuta los archivos *.test.ts de un mod contra el motor, sin sesión, sin autenticarte y sin red. El kit de pruebas no tiene nada por debajo de tu mod, así que cada prueba registra hooks sustitutos para todo lo que el mod deja pasar:
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()
})El archivo completo tiene cuatro pruebas:
(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 failMi primera ejecución falló con on("tool.call") after the test first called $. Registra los sustitutos al principio de cada prueba, antes de la primera llamada a $.
Qué pasó en una sesión en vivo
Con la recarga en caliente activada, le pedí a Claude que ejecutara echo "the words git reset --hard inside an echo". El guardián lo rechazó con "blocked (git reset --hard throws away uncommitted work)" y apareció una notificación toast. Ese echo era inofensivo. La coincidencia de patrones no distingue un comando de un texto que lo menciona, y tampoco detecta un comando escondido en una variable, un script o un alias. Los autores japoneses que publicaron guardianes parecidos, como rafi-guard, delete-guard y board-guard, cuentan los dos problemas.
Trata un mod guardián como una segunda red de seguridad. Todo lo que no deba ocurrir nunca va también en una regla deny de permisos. Ten en cuenta también el caso contrario. Según la documentación oficial, en una máquina personal sin configuración gestionada, un mod puede aprobar una llamada que una regla deny rechaza. Los mods no corren en un sandbox. Se ejecutan con tus permisos.
Mod 2: un medidor encima del prompt
Los mods dibujan sobre todo en la franja encima del prompt y en el panel lateral. En el escaneo del catálogo del 6 de octubre, el 41% de los mods dibuja en la franja y el 40% abre un panel. Este mod muestra el tiempo, las llamadas a herramientas y los tokens del último turno, con un botón Hide.
Los valores que lee un dibujo van en $.state, y cada uno se declara en un pequeño archivo 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 }
}
}Los hooks cuentan las llamadas a herramientas, leen durationMs y usage de turn.complete y dibujan la franja:
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>
)
})
}En la prueba, tanto en la terminal como en la app de escritorio, la franja se ve así:
Last turn: 42s · 0 tool calls · 18.2k in / 800 out · claude-opus-5-5 [ Hide ]Tres cosas que aprendí al crearlo:
- Guarda los valores que se dibujan en
$.state, no en variables del módulo. Una recarga en caliente vuelve a ejecutarregistery reinicia tus variables, mientras que$.statesobrevive./clearempieza de cero, así que, si un valor tiene que sobrevivir a eso, escríbelo en$.storeen el eventosession.end. - La franja es compartida. Llama a
next(e)y mete su resultado dentro de tuBox, o esconderás la fila de todos los demás mods. Un autor de note.com perdió una franja por culpa de otro mod antes de entender esto. - Los elementos
Textno conservan ningunakey. En las pruebas, búscalos por lo que dicen:ui.find({ type: 'Text', text: /Last turn/ }).
Mod 3: /pyenv, para cuando Claude ejecuta el Python equivocado
Busqué mods de ciencia de datos y encontré un hueco. De los 2690 mods del escaneo del 6 de octubre, ninguno menciona Jupyter, pandas, DataFrames, Polars, venv ni conda en su nombre o en su descripción.
El problema que resuelve este mod es habitual cuando trabajas con datos. La herramienta Bash de Claude ejecuta el primer python3 que haya en tu PATH, y a menudo ese no es el entorno de tu proyecto. Esto es lo que imprimió la sonda en mi 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 installedNo había ningún entorno virtual activo, así que un pip install lanzado por Claude habría acabado en un intérprete global.
El comando /pyenv ejecuta esa sonda y responde en dos partes. text es la fila que ves tú. context es una nota que solo lee el modelo, así que las siguientes llamadas de Claude a Bash saben qué intérprete se está usando sin que tengas que escribir otro 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)})` }
}
})
}El comando slash de un mod ejecuta tu función al momento, sin turno del modelo, incluso mientras Claude está ocupado. $.process.run recibe una lista de argumentos sin pasar por ninguna shell, y corta a los 30 segundos salvo que definas timeoutMs.
¿Ve $.process.run el mismo PATH que la herramienta Bash de Claude? Un autor de la comunidad descubrió que el node de nvm no aparecía en los procesos de un mod, así que lo comprobé con un mod sonda temporal. En mi sesión de la app de escritorio, un $.process.run simple recibió exactamente el PATH de la herramienta Bash y el mismo python3. Ejecutar la sonda a través de una shell de login, zsh -lc, dio la respuesta equivocada. Apuntaba al Python 3.10.9 de python.org, porque una shell de login no interactiva se salta ~/.zshrc, que es donde casi todo el mundo añade rutas al PATH. Quédate con la llamada simple. Si una lectura te parece rara en tu máquina, compárala con !which python3 escrito en el prompt de Claude Code.
Al probarlo encontré otra trampa. Las llamadas sobre $, como $.process.run y $.command.register, también necesitan sustitutos, y el sustituto de una llamada a $ responde con { value: ... }. Si devuelves el resultado sin envolver, el kit lo rechaza.
Si haces casi todo tu análisis en notebooks y no en scripts, esto se queda corto, porque Claude Code edita los archivos .ipynb como JSON y nunca ve el kernel en vivo. RunCell (opens in a new tab) es un agente para notebooks que ejecuta celdas y lee su salida directamente, así que encaja mejor con ese tipo de trabajo.
Deja que Claude escriba el mod
Nada de esto hay que escribirlo a mano. Pídelo en una sesión, por ejemplo "crea un mod que muestre mi uso del límite de 5 horas encima del prompt". Claude carga la skill integrada plugin-authoring y escribe los archivos en ~/.claude/dev-mods/<session-id>/. El primer archivo provoca una sola pregunta, "Enable hot reloading for this session?". Cuando aceptas, cada cambio se recarga al terminar el turno de Claude. Así se crearon y cargaron los tres mods de arriba.
Lo que añaden la documentación y la comunidad:
- Copia la carpeta a un lugar permanente. Autores de Qiita y Zenn cuentan que las carpetas de dev-mods se borran junto con las sesiones antiguas pasados unos 30 días.
- Desarrolla con
claude --plugin-dir ./my-mod. Un mod instalado ejecuta una copia en caché, así que editar su carpeta no cambia nada hasta que actualizas el plugin. - La app de escritorio no acepta opciones de línea de comandos. Define
CLAUDE_CODE_PLUGIN_DIRSen el bloqueenvde~/.claude/settings.json. Para esto, Claude Code ignora la configuración del proyecto. - Ejecuta
/plugin. Una línea en gris como1 mod active · safe-shellconfirma que el mod se cargó. - Arranca con
claude --debugmientras desarrollas. El log de depuración nombra cada hook omitido y cada dibujo que rechazó el motor.
15 mods de la comunidad que vale la pena estudiar
El catálogo awesome-claude-code-mods (opens in a new tab), con 316 estrellas, escaneó 2690 mods públicos en 1265 repositorios el 6 de octubre, cinco días después del lanzamiento. Sus datos muestran lo que construye la gente:
- El 68% añade un comando slash
- El 53% intercepta llamadas a herramientas
- El 41% dibuja encima del prompt y el 40% abre un panel
- El 40% lanza procesos, el 12% llama a un modelo y el 11% usa la red
Estos 15 muestran la variedad. Las estrellas corresponden al 7 de octubre de 2026.
| Mod | Qué hace | Estrellas | Vale la pena por |
|---|---|---|---|
| terminal-browser (opens in a new tab) | Un navegador web junto a la conversación para sitios web, vistas previas de HTML local y pull requests | 3695 | El panel más ambicioso hasta ahora |
| claude-image-view (opens in a new tab) | Miniaturas de las imágenes pegadas encima del prompt, en lugar de [Image #1] | 160 | Dibujar imágenes en la terminal |
| hamzafer/claude-code-mods (opens in a new tab) | Un conjunto: barra de contexto, guardián de radio de impacto, vista previa de Markdown y dashboard de subagentes | 138 | Varios tipos de mod en un solo repo |
| claude-auto-handoff (opens in a new tab) | Pasa una sesión larga a una nueva con un resumen estructurado | 60 | La gestión del contexto |
| prismantis (opens in a new tab) | Respuestas con temas visuales: tablas, código, gráficos con caracteres de caja y texto de derecha a izquierda | 49 | Cambiar el estilo de los propios mensajes de Claude |
| cc-arcade (opens in a new tab) | Nueve juegos encima del prompt que se pausan cuando Claude termina | 41 | Animación con un reloj de fotogramas |
| jev-permission-gate (opens in a new tab) | Un modelo de decisión de Jev evalúa las llamadas a herramientas en auto mode | 28 | Una sección de privacidad cuidadosa: envía tus tres últimos mensajes, de hasta 1500 caracteres cada uno, a la API de TypeSafe |
| prompt-rail (opens in a new tab) | Una barra con tus prompts anteriores; pasa el cursor por encima para leerlos y haz clic para saltar a ellos | 22 | La pieza central de la reseña japonesa de mods con más likes en Zenn |
| claude-paste-view (opens in a new tab) | Vista previa de las imágenes y los textos largos que pegas | 18 | Código pequeño y fácil de leer |
| claude-gfm-render (opens in a new tab) | Alertas de GitHub, listas de tareas y Mermaid en las respuestas, con caracteres de caja o en SVG | 14 | Dibujar distinto según la superficie |
| claude_qamods (opens in a new tab) | qa-guide explica en un panel lateral las preguntas y opciones de Claude | 10 | Mejorar un diálogo integrado |
| CC-Usage-Band (opens in a new tab) | Límites de 5 horas y de 7 días, contexto y tasa de aciertos de caché encima del prompt | 10 | El tipo de mod más común: un medidor |
| harness-scope (opens in a new tab) | Perfiles por repo que ocultan skills, agentes y reglas globales | 1 | El autor midió cómo la lista de skills pasaba de 98 entradas a 49 |
| touch-map (opens in a new tab) | Muestra qué archivos listó, leyó, editó o creó Claude | 0 | Su autor vio que Claude tocó 125 de 304 archivos durante el análisis previo a una refactorización |
| claude-mods-router (opens in a new tab) | Asigna a cada prompt un nivel de esfuerzo con $.model.classify | 0 | Su artículo en Qiita (26 likes) explica que cambiar de modelo rompe la caché de prompts |
Anthropic también publica tres ejemplos en claude-code-playground (opens in a new tab): token-weather, blast-radius y replay-theater. El código fuente de los mods integrados, entre ellos /diff, está en el repositorio claude-code (opens in a new tab).
Buenas prácticas en las que coincide la comunidad
En la primera semana, solo los autores japoneses publicaron unos 50 artículos con mods que funcionan, mediciones e informes de fallos. Estos son los hábitos que se repitieron una y otra vez.
- Lee un mod antes de instalarlo. Clónalo, ejecuta
claude plugin validatey lee las líneashooks:ycalls:. Lee el código fuente allí donde aparezcan$.process,$.http,$.fs.write,$.env.geto$.model. Vuelve a validarlo después de cada actualización. Pasar la validación significa que el motor puede cargar el código, no que el código sea seguro. - Los guardianes deciden antes de
nexty fallan en cerrado. Los mods que solo observan deberían fallar en abierto con.catch(($, e, next) => next(e)), para que un bug en un medidor nunca bloquee tu trabajo. - Espera dentro de las llamadas a
$. Un hook tiene 10 segundos de tiempo propio. Un$.process.runo un$.ui.asken curso no descuenta de ese tiempo, pero tus propias promesas sí. - Nunca guardes ni desestructures
$. Pásalo solo a funciones declaradas en el nivel superior del archivo. Varios autores tenían mods que fallaban al cargar sin ningún aviso hasta que corrigieron esto. - Cuida la caché de prompts. Cambiar de modelo a mitad de sesión, o cambiar el system prompt entre peticiones, invalida la caché.
- Decide según
e.surface.Svgsolo dibuja en la app de escritorio.RastereImagesolo dibujan en la terminal. - Fija una versión si trabajas en equipo. La API está en acceso anticipado y cambia de una versión a otra. Cinco de las seis versiones posteriores al lanzamiento, de la 2.1.288 a la 2.1.293, cambiaron o corrigieron el comportamiento de los mods.
El caso de los secretos enmascarados sirve de advertencia. Un autor de note.com creó un mod que sustituía las API keys en la salida de las herramientas antes de que Claude las viera. Aun así, Claude imprimió los valores reales mientras depuraba una edición fallida con od -c, y un Write del archivo completo guardó los marcadores de posición encima de las claves reales. Solo aguantó una regla deny de permisos sobre el archivo. Un mod que cambia lo que muestra la pantalla no le oculta nada al modelo.
Problemas comunes
| Síntoma | Causa probable | Solución |
|---|---|---|
/plugin no lista el mod | Carpeta que no es de confianza, --safe-mode, --bare o disableAllHooks | Marca la carpeta como de confianza y reinicia sin esa opción |
hooks modules are turned off in this process | Anthropic desactivó en remoto los mods instalados | No hay nada que cambiar en local. Actualiza, porque la 2.1.289 y la 2.1.290 corrigieron dos casos en los que los mods seguían desactivados |
validate falla con "expected record, received undefined" | Una CLI antigua aparece antes en tu PATH | Ejecuta claude --version y actualiza |
| Un hook se omite sin ningún error visible | Lanzó una excepción, por ejemplo al llamar a $.plugin.name(), que es una propiedad | Ejecuta claude --debug y lee la línea que explica la omisión |
| Un panel nunca se abre | Un panel que se abre sin que lo pidas espera a que haya 144 columnas, solo se acopla junto a la transcripción en el diseño de pantalla completa, y /diff puede taparlo | Ensancha la ventana, prueba el diseño de pantalla completa y cierra /diff |
| Funciona en la terminal pero no en la app de escritorio | La app de escritorio incluye su propia versión, y algunos elementos son exclusivos de la terminal | Revisa /status en la pestaña Code y decide según e.surface |
No aparece la interfaz del mod en VS Code ni en claude -p | Esas superficies no dibujan | Recurre a una línea en la transcripción o al texto de un comando |
| Una prueba falla con "nothing beneath the plugins answers" | El kit de pruebas no tiene motor | Añade hooks sustitutos y responde a las llamadas a $ con { value } |
Comparte tu mod
Pon un marketplace.json junto a plugin.json, dentro de .claude-plugin/:
{
"name": "my-mods",
"owner": { "name": "you" },
"plugins": [{ "name": "safe-shell", "source": "./" }]
}Sube la carpeta a GitHub. A partir de ahí, cualquiera puede instalar el mod desde una sesión de terminal:
/plugin install safe-shell --marketplace you/safe-shellEn la app de escritorio, la ruta es +, luego Plugins y luego Add plugin, en sesiones locales y SSH. Si añades el topic claude-code-mod al repositorio, el catálogo de la comunidad suele incluirlo pocas horas después de tu siguiente push.
Preguntas frecuentes
Guías relacionadas
- Claude Code Desktop Bypass Permissions: cómo activarlo
- Claude Code routines: qué son y por qué importan los cron jobs de agentes de IA
- Construye un agente de IA tipo Claude Code con Claude Agent SDK (TypeScript)
- Cómo usar OpenCode: inicio rápido, 7 tips prácticos y cuándo sumar Oh My OpenCode
- Guía de uso de Codex: cómo empezar, 5 tips y best practices