
El comando /permissions parece un menú más. En realidad es la puerta de entrada a un sistema de control de acceso con modos, reglas granulares y orden de evaluación propio. No necesitas dominarlo entero, pero hay tres conceptos que si no conoces te van a morder.
TL;DR Los deny siempre ganan. Los modos cambian el comportamiento de todo. Y la sintaxis
Tool(specifier)acepta wildcards y patrones gitignore. Con eso, controlas el 90%.
Result:
/permissions
Allow rules:
Bash(npm run *) # from .claude/settings.json
Bash(git commit *) # from .claude/settings.json
Edit(/src/**) # from .claude/settings.json
Deny rules:
Bash(git push *) # from .claude/settings.json
Read(.env) # from .claude/settings.json
Los 3 conceptos clave
1. El orden de evaluación: deny siempre gana
Las reglas se evalúan en este orden: deny → ask → allow. La primera coincidencia gana. Si un deny coincide, no importa cuántos allow tengas — la operación se bloquea.
{
"permissions": {
"allow": ["Bash(git *)"],
"deny": ["Bash(git push *)"]
}
}
En este ejemplo, git commit -m "fix" pasa. git push origin main se bloquea. El deny para git push * coincide antes de que el allow para git * tenga oportunidad.
2. Los modos cambian todo el comportamiento
Claude Code tiene 5 modos de permisos. Puedes ciclar entre los tres principales con Shift+Tab durante la sesión:
| Modo | Qué hace |
|---|---|
default |
Pide permiso en cada herramienta nueva |
acceptEdits |
Acepta automáticamente ediciones de archivos |
plan |
Solo lectura — Claude analiza pero no modifica nada |
dontAsk |
Deniega todo lo que no esté explícitamente en allow |
bypassPermissions |
Salta todas las comprobaciones (solo en entornos aislados) |
El modo dontAsk es el que más confusión genera: no es "acepta todo sin preguntar" sino exactamente lo contrario. Deniega todo excepto lo que hayas pre-aprobado con /permissions o en permissions.allow.
¿Quieres automatizar un permiso concreto sin tocar los demás? Esa es la capa programable: un hook puede responder un prompt por ti. El caso típico, auto-aprobar solo el plan de fin de plan mode.
3. La sintaxis acepta más de lo que parece
Las reglas siguen el formato Tool(specifier) con wildcards:
| Regla | Qué permite |
|---|---|
Bash(npm run *) |
Cualquier script npm |
Bash(* --version) |
Cualquier comando con --version |
Edit(/src/**) |
Editar cualquier archivo bajo src/ (recursivo) |
Read(.env) |
Leer .env en el directorio actual |
Read(~/.ssh/*) |
Leer archivos en tu directorio .ssh |
mcp__notion__* |
Cualquier herramienta del servidor MCP Notion |
Para Read y Edit, los patrones siguen la especificación gitignore: * coincide en un directorio, ** es recursivo. En Bash, una regla nunca se compara con un comando encadenado entero: cada parte de un && necesita la suya.
Esta sintaxis se reutiliza fuera de los permisos. El campo if de una entrada de hook lleva una de estas mismas reglas y decide si el hook llega a lanzarse: hooks condicionales.
Dónde se guardan las reglas
| Archivo | Ámbito |
|---|---|
~/.claude/settings.json |
Personal — todos tus proyectos |
.claude/settings.json |
Proyecto — compartido con el equipo |
.claude/settings.local.json |
Proyecto — solo tú (gitignore) |
Las reglas de permisos de los tres archivos se juntan, y un deny de cualquiera bloquea el allow de otro: si el proyecto deniega algo que tú permites, se bloquea, y si tú deniegas algo que el proyecto permite, también. Para el resto de ajustes sí hay un orden de precedencia entre archivos: mira cuál config gana cuando dos chocan. Y si lo que dudas es en qué archivo va cada cosa, no quién gana, esta es la guía.
Si lo que quieres es que Claude Code deje de pedir permiso para todo, la guía de permisos ordena las cinco palancas, de las reglas allow al sandbox, por orden de riesgo.
Documentación oficial: Configure permissions