Contenido
Las reglas de permisos de Claude Code te permiten escribir entradas allow / ask / deny en settings.json para especificar, de forma granular, qué herramientas, comandos, archivos y dominios se ejecutan sin preguntar, piden confirmación cada vez o están prohibidos. Se pueden compartir en todo un equipo, de modo que bloqueas con certeza lo peligroso mientras dejas que el trabajo seguro y rutinario se ejecute sin interrupciones.
Esta guía explica qué son las reglas de permisos (y en qué se diferencian de los modos de permisos), la precedencia allow/ask/deny, la sintaxis de las reglas, la jerarquía de settings.json y recetas prácticas, todo basado en la especificación oficial.
Control granular con allow / ask / deny
Se evalúa deny → ask → allow (gana la primera coincidencia)
deny
Prohibido (gana sobre todo)
ask
Pregunta cada vez
allow
Se ejecuta sin preguntar
1. Qué son las reglas de permisos (frente a los modos)
Claude Code usa un sistema de permisos por niveles. Las lecturas (ver archivos, Grep, etc.) no necesitan aprobación; los comandos Bash y las ediciones de archivos sí, y sobre esa base, las reglas te permiten especificar excepciones granulares (fuente: la documentación oficial "Configure permissions" de Claude Code).
Es fácil confundir las reglas con los modos de permisos. Los modos son la base amplia de "con qué frecuencia pregunta" (default/acceptEdits/auto, etc.); las reglas son especificaciones por herramienta y por comando. Funcionan juntos: el modo establece la base y las reglas la anulan con "permite siempre esto" o "nunca permitas aquello".
💡 Las reglas las hace cumplir Claude Code, no el modelo. Tu prompt o tu CLAUDE.md moldean lo que Claude intenta hacer, pero no lo que está permitido. Concede o revoca el acceso mediante /permissions, las reglas, los modos o un hook PreToolUse.
2. allow / ask / deny y la precedencia
Hay tres tipos de regla. El comando /permissions las lista y edita (y muestra de qué settings.json procede cada una).
Se ejecuta sin preguntar
La herramienta o el comando indicado se ejecuta sin aprobación manual.
Pregunta cada vez
Pide confirmación en cada uso. Una coincidencia con ask pregunta aunque también coincida un allow más amplio.
Prohibido (máxima prioridad)
Bloquea la herramienta. Gana sobre cualquier allow, y un deny en cualquier nivel siempre prevalece.
Las reglas se evalúan deny → ask → allow. La primera coincidencia decide el resultado, y la especificidad de la regla no cambia el orden. Un deny amplio Bash(aws *) gana sobre un allow más específico Bash(aws s3 ls). La idea: un deny no puede llevar excepciones de lista de permitidos.
⚠️ Las dos formas de deny se comportan de manera distinta: un nombre de herramienta a secas como Bash elimina la herramienta por completo del contexto de Claude (Claude nunca la ve). Una regla acotada como Bash(rm *) mantiene la herramienta disponible y bloquea solo las llamadas que coinciden.
3. Sintaxis de las reglas (Tool(specifier))
El formato es Tool (todo) o Tool(specifier) (algo concreto). Cada herramienta tiene su propio estilo de especificador.
| Herramienta | Ejemplo | Significado |
|---|---|---|
| Bash | Bash(npm run *) | Comandos que empiezan por npm run (el * final = límite de palabra) |
| Read / Edit | Read(./.env) | Leer el .env del directorio actual (ruta estilo gitignore) |
| WebFetch | WebFetch(domain:example.com) | Peticiones a example.com |
| MCP | mcp__github__get_* | Las herramientas get_ del servidor github |
| Agent | Agent(Explore) | El subagente Explore |
Los comodines de Bash pueden aparecer en cualquier sitio. Bash(ls *) (espacio + *) coincide con ls -la pero no con lsof (límite de palabra); Bash(ls*) (sin espacio) coincide con ambos. Un :* final equivale a *.
// Permitir comandos seguros, denegar git push
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)"
],
"deny": [
"Bash(git push *)"
]
}
}
Cuidado con los comandos compuestos. Claude Code entiende separadores como && || ; |, y cada subcomando debe coincidir de forma independiente. Bash(safe-cmd *) no permite safe-cmd && rm -rf .. Ten en cuenta que los comandos de solo lectura (ls/cat/grep/find/pwd, etc.) se ejecutan sin preguntar en todos los modos, y los envoltorios como timeout/nice/nohup se eliminan antes de la comparación.
Las rutas de Read/Edit siguen la semántica de gitignore con cuatro anclas:
| Forma | Ancla | Ejemplo |
|---|---|---|
//path | Absoluta del sistema de archivos | Read(//tmp/x) |
~/path | Home | Read(~/.ssh/**) |
/path | Raíz del proyecto | Edit(/src/**) |
path / ./path | Directorio actual | Read(.env) |
※ /Users/... NO es absoluta: es relativa a la raíz del proyecto. Usa //Users/... (doble barra) para rutas absolutas. Read(.env) equivale a Read(**/.env) y coincide con todos los .env que haya por debajo.
4. Jerarquía y precedencia de settings.json
Las reglas viven en settings.json. Hay varios archivos, y los niveles más altos son más fuertes. La regla clave: un deny en cualquier nivel siempre vence a un allow en cualquier otro nivel.
| Prioridad | Ubicación | Uso |
|---|---|---|
| 1 (la más fuerte) | Managed settings | Política de la organización. Usuarios y CLI no pueden anularla |
| 2 | Argumentos de línea de comandos | Anulaciones temporales de la sesión |
| 3 | .claude/settings.local.json | Ajustes personales del proyecto (gitignored) |
| 4 | .claude/settings.json | Ajustes compartidos del proyecto (versionados) |
| 5 | ~/.claude/settings.json | Ajustes de usuario para todos los proyectos |
// .claude/settings.json (compartido por el equipo)
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": ["Bash(npm run *)", "WebFetch(domain:docs.example.com)"],
"deny": ["Read(.env)", "Read(**/secrets/**)", "Bash(git push *)"],
"additionalDirectories": ["../shared-lib"]
}
}
El modo de permisos por defecto también se fija aquí, como defaultMode (detalles de los modos). Para leer o editar fuera del directorio de trabajo, añade rutas a additionalDirectories.
5. Recetas prácticas
Combinaciones habituales. La forma básica: denegar con certeza lo peligroso y permitir la rutina segura para automatizarla.
🔒 Proteger archivos de secretos
deny: ["Read(.env)", "Read(**/secrets/**)", "Read(~/.ssh/**)"]. Bloquea las lecturas de raíz.
🚀 Confirmar siempre las operaciones de riesgo
ask: ["Bash(git push *)", "Bash(rm *)"]. Obliga a confirmar incluso en modo auto.
⚡ Automatizar el trabajo rutinario
allow: ["Bash(npm run *)", "Bash(git commit *)"]. Tests, builds y commits se ejecutan sin interrupciones.
Restringir URLs mediante patrones de argumentos de Bash es frágil (curl http://github.com/ * se sortea fácilmente con -X GET o con la expansión de variables). En su lugar, deniega curl/wget y permite dominios concretos con WebFetch(domain:...). Para un control más estricto, valida las URLs en un hook PreToolUse.
6. Trampas y confusiones habituales
- El deny lo hace cumplir Claude Code, no el modelo. Escribir "no leas esto" en tu prompt o en CLAUDE.md no lo impedirá sin una regla.
- El deny de Read/Edit no detiene el acceso indirecto. Se aplica a las herramientas de archivo integradas y a
cat/head/sed, pero no a un script de Python o Node que abra archivos por su cuenta. Para una protección a nivel de sistema operativo, usa también el sandboxing. - Atención a los ejecutores de entornos.
devbox run *,npxydocker execejecutan sus argumentos como un comando, así queBash(devbox run *)también permitedevbox run rm -rf .. Escribe reglas que incluyan el comando interno. - Los hooks no anulan las reglas. Un hook PreToolUse puede ampliar permisos, pero deny/ask se evalúan independientemente de lo que devuelva el hook (la prioridad del deny no cambia).
※ El comportamiento se corresponde con la documentación oficial de Claude Code (Configure permissions / Settings), a fecha de junio de 2026. Puede cambiar: consulta la documentación oficial para lo más reciente.
Resumen
Tres ideas clave sobre las reglas de permisos de Claude Code.
- Qué son: allow/ask/deny en
settings.jsonpara conceder, preguntar o prohibir por herramienta, comando, archivo y dominio. Los modos fijan la base; las reglas se ocupan de los detalles. - Precedencia: deny → ask → allow (gana la primera coincidencia; la especificidad es irrelevante). Un deny en cualquier nivel siempre gana. Niveles: managed > CLI > local > project > user.
- Sintaxis:
Tool(specifier). Bash usa comodines (espacio + * es un límite de palabra), Read/Edit usan rutas estilo gitignore, WebFetch usa domain:. Los comandos compuestos necesitan que coincida cada subcomando.
"Bloquear con certeza lo peligroso y automatizar la rutina segura" es el corazón del diseño de reglas. Combínalo con los modos de permisos, los hooks y el ajuste de esfuerzo para ejecutar Claude Code de forma segura y fluida.
Preguntas frecuentes
Q. ¿En qué se diferencian las reglas de permisos de los modos?
A. Los modos son la base amplia de confirmación (default/acceptEdits/auto, etc.); las reglas son especificaciones por herramienta y por comando. Funcionan juntos, y las reglas anulan los modos (p. ej., las reglas ask/deny siguen aplicándose en modo auto).
Q. Lo permití, ¿por qué sigue preguntando?
A. Porque la evaluación es deny → ask → allow. Si un ask (o deny) distinto también coincide con la llamada, gana incluso sobre un allow más específico. La especificidad no cambia el orden.
Q. ¿Dónde pongo settings.json?
A. Compartido por el equipo: .claude/settings.json (versionado). Personal: .claude/settings.local.json (gitignored). Para todos los proyectos: ~/.claude/settings.json. Para una aplicación a nivel de toda la organización, usa managed settings (no se pueden anular).
Q. ¿Cómo me aseguro de que .env nunca se lea?
A. Pon deny: ["Read(.env)", "Read(**/secrets/**)"]. Ten en cuenta que esto se aplica a las herramientas de archivo integradas y a los comandos tipo cat, pero no a las lecturas indirectas mediante un script. Para una protección a nivel de sistema operativo, activa también el sandboxing.
Q. ¿Puedo restringir URLs o archivos mediante argumentos de Bash?
A. No de forma fiable. curl http://github.com/ * se sortea fácilmente con opciones o con la expansión de variables. Para limitar URLs, deniega curl/wget y usa WebFetch(domain:...), o valida en un hook PreToolUse.