Tips & Tricks

Guía completa de permisos de Claude Code | settings.json, Hooks y Allowlist explicados

Guía completa de permisos de Claude Code. Aprende a usar allow/deny/ask, automatización con Hooks, settings.json por entorno y patrones prácticos, todo con código funcional.

Claude Code tiene capacidades extremadamente potentes de operación de archivos y ejecución de comandos. Los permisos (permissions) son lo que te permite controlar ese poder de forma segura. Supera el estado de “lo uso sin entenderlo bien” y diseña un Claude Code que funcione exactamente como lo deseas.

Este artículo explica exhaustivamente, con código funcional, todos los ajustes de .claude/settings.json, los patrones de implementación de Hooks y el diseño de permisos específico por entorno.

Visión general de los permisos

Los permisos de Claude Code se controlan en 3 niveles.

NivelClaveComportamiento
PermitirallowSe ejecuta automáticamente sin diálogo de confirmación
PreguntaraskRequiere aprobación del usuario cada vez
DenegardenyNo puede ejecutarse en absoluto (se rechaza con error)

Los ajustes se escriben en .claude/settings.json. Colocarlo en la raíz del proyecto permite compartirlo con el equipo mediante git; colocarlo en ~/.claude.json lo convierte en una configuración global.

Prioridad (de mayor a menor):
Proyecto .claude/settings.json
    > Global ~/.claude.json
        > Por defecto (todo es ask)

Estructura básica de settings.json

{
  "permissions": {
    "allow": [
      "Read(**)",
      "Glob(**)",
      "Grep(**)",
      "Bash(npm run *)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force*)"
    ],
    "ask": [
      "Write(**)",
      "Edit(**)",
      "Bash(git commit*)"
    ]
  },
  "hooks": {
    "PreToolUse": [],
    "PostToolUse": []
  }
}

Nombres de herramientas y sintaxis de patrones

Los permisos se escriben en el formato “NombreHerramienta(patrón de argumento)”.

Lista de herramientas principales

Nombre de herramientaDescripción
ReadLectura de archivos
WriteCreación de nuevos archivos
EditModificación parcial de archivos existentes
BashEjecución de comandos de shell
GlobBúsqueda por patrón de archivos
GrepBúsqueda de contenido
WebFetchObtención de URL
AgentInicio de sub-agente

Sintaxis de patrones

"Read(**)"          // Permitir lectura de todos los archivos
"Read(src/**)"      // Permitir solo bajo src/
"Read(*.md)"        // Permitir solo archivos .md
"Bash(npm run *)"   // Permitir solo comandos que comiencen con npm run
"Bash(git *)"       // Permitir todos los comandos git
"Bash(rm -rf *)"    // Denegar rm -rf

** coincide con todas las rutas incluyendo directorios; * coincide con un único segmento.

Patrones prácticos

Patrón 1: Desarrollo individual (relativamente permisivo)

{
  "permissions": {
    "allow": [
      "Read(**)",
      "Glob(**)",
      "Grep(**)",
      "Bash(npm *)",
      "Bash(git log*)",
      "Bash(git diff*)",
      "Bash(git status*)",
      "Bash(git add*)",
      "Bash(node *)",
      "Bash(echo *)",
      "Bash(cat *)",
      "Bash(ls *)"
    ],
    "deny": [
      "Bash(rm -rf /)",
      "Bash(rm -rf ~*)",
      "Bash(git push --force *main*)",
      "Bash(git push --force *master*)"
    ],
    "ask": [
      "Write(**)",
      "Edit(**)",
      "Bash(git commit*)",
      "Bash(git push*)",
      "Bash(rm *)"
    ]
  }
}

Patrón 2: Desarrollo en equipo (orientado a la seguridad)

{
  "permissions": {
    "allow": [
      "Read(**)",
      "Glob(**)",
      "Grep(**)",
      "Bash(npm run lint)",
      "Bash(npm run test)",
      "Bash(npm run typecheck)",
      "Bash(git log*)",
      "Bash(git diff*)",
      "Bash(git status*)",
      "Bash(git branch*)"
    ],
    "deny": [
      "Bash(rm -rf*)",
      "Bash(git push --force*)",
      "Bash(git push -f*)",
      "Bash(git reset --hard*)",
      "Bash(git rebase *main*)",
      "Bash(git rebase *master*)",
      "Bash(DROP *)",
      "Bash(TRUNCATE *)",
      "Bash(curl * | bash)",
      "Bash(wget * | sh)"
    ],
    "ask": [
      "Write(**)",
      "Edit(**)",
      "Bash(git commit*)",
      "Bash(git push*)",
      "Bash(git add*)",
      "Bash(npm install*)",
      "Bash(*deploy*)"
    ]
  }
}

Patrón 3: Entorno de producción (solo lectura)

{
  "permissions": {
    "allow": [
      "Read(**)",
      "Glob(**)",
      "Grep(**)",
      "Bash(git log*)",
      "Bash(git diff*)",
      "Bash(git status*)",
      "Bash(git show*)",
      "Bash(cat *)",
      "Bash(ls *)",
      "Bash(ps *)",
      "Bash(df *)",
      "Bash(top *)"
    ],
    "deny": [
      "Write(**)",
      "Edit(**)",
      "Bash(git push*)",
      "Bash(git commit*)",
      "Bash(git reset*)",
      "Bash(rm *)",
      "Bash(mv *)",
      "Bash(*deploy*)",
      "Bash(*restart*)",
      "Bash(*kill *)"
    ],
    "ask": []
  }
}

En producción, esto se especifica con CLAUDE_SETTINGS=.claude/settings.production.json claude.

Patrón 4: Solo generación de contenido (el patrón usado en este sitio)

{
  "permissions": {
    "allow": [
      "Read(**)",
      "Glob(**)",
      "Grep(**)",
      "Write(site/src/content/**)",
      "Write(content/**)",
      "Edit(site/src/content/**)",
      "Edit(content/**)",
      "Bash(git log*)",
      "Bash(git diff*)",
      "Bash(git status*)",
      "Bash(node scripts/*)",
      "Bash(QIITA_TOKEN=* node scripts/qiita-publish.mjs)"
    ],
    "deny": [
      "Bash(rm -rf*)",
      "Bash(git push --force*)",
      "Edit(.env*)",
      "Read(.env*)"
    ],
    "ask": [
      "Bash(git add*)",
      "Bash(git commit*)",
      "Bash(git push*)",
      "Bash(bash scripts/deploy.sh*)"
    ]
  }
}

La clave es restringir las escrituras a un directorio específico, como con Write(site/src/content/**).

Hooks: Ejecutar procesos antes y después de los permisos

Los Hooks son un mecanismo que ejecuta comandos automáticamente antes y después de la ejecución de herramientas. Se pueden usar para verificaciones de seguridad y formateo automático.

PreToolUse: Hook previo a la ejecución

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git add*)",
        "hooks": [{
          "type": "command",
          "command": "git diff --cached --name-only | grep -E '^\\.env' && echo '🚨 ¡Se detectó adición de .env!' && exit 1 || exit 0"
        }]
      },
      {
        "matcher": "Bash(git commit*)",
        "hooks": [{
          "type": "command",
          "command": "node scripts/secret-scan.mjs"
        }]
      },
      {
        "matcher": "Bash(rm*)",
        "hooks": [{
          "type": "command",
          "command": "echo '⚠️ Comando de eliminación detectado. Se ejecutará en 5 segundos. Ctrl+C para cancelar.' && sleep 5"
        }]
      }
    ]
  }
}

Si un comando de hook devuelve el código de salida 1, la ejecución de la herramienta se bloquea. Este es el punto más importante.

PostToolUse: Hook posterior a la ejecución

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "npx tsc --noEmit 2>&1 | head -20 || true"
        }]
      },
      {
        "matcher": "Bash(git commit*)",
        "hooks": [{
          "type": "command",
          "command": "git log --oneline -3"
        }]
      }
    ]
  }
}

PostToolUse se usa para verificaciones posteriores a la ejecución y efectos secundarios, por ejemplo, ejecutar automáticamente verificaciones de tipos después de editar archivos o mostrar las últimas 3 entradas del registro después de un commit.

Colección de recetas de Hooks prácticos

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(npm install*)",
        "hooks": [{
          "type": "command",
          "command": "echo '📦 Agregando paquete. Por favor revisa package.json.'"
        }]
      },
      {
        "matcher": "Bash(*deploy*)",
        "hooks": [{
          "type": "command",
          "command": "read -p '🚀 A punto de desplegar. ¿Continuar? [y/N] ' ans && [ \"$ans\" = 'y' ] || exit 1"
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write(*.ts)|Edit(*.ts)",
        "hooks": [{
          "type": "command",
          "command": "npx eslint --fix $CLAUDE_TOOL_INPUT_FILE_PATH 2>/dev/null || true"
        }]
      }
    ]
  }
}

Modos de permisos: Nivel de permiso al iniciar

También puedes especificar el modo al lanzar el comando claude.

# Modo normal (sigue settings.json)
claude

# Aprobar automáticamente todas las operaciones (¡peligroso! solo para entornos de confianza)
claude --dangerously-skip-permissions

# Omitir solo operaciones específicas
claude --allowedTools "Read,Grep,Glob"

# Modo no interactivo (usado en CI/CD)
claude -p "Ejecutar pruebas y reportar resultados" --dangerously-skip-permissions

--dangerously-skip-permissions debe usarse solo para automatización CI/CD o scripts de automatización completamente controlados, y evitarse en el uso interactivo diario.

Prioridad y sobreescritura de archivos de configuración

Cuando existen múltiples archivos de configuración:

~/.claude.json              ← Global (compartido entre todos los proyectos)
    +
.claude/settings.json       ← Proyecto (gestionado con git)
    +
.claude/settings.local.json ← Sobreescrituras personales (gitignore recomendado)
    =
Se aplica la configuración combinada

Escribe configuraciones adicionales personales en .claude/settings.local.json y agrégalo a gitignore. Para evitar que las listas de deny del equipo sean sobreescritas por configuraciones personales, el diseño seguro es escribir las reglas deny solo en settings.json.

# Agregar a .gitignore
.claude/settings.local.json

Los 5 errores más comunes

1. Equivocarse con los patrones de comodines

// ❌ Esto solo coincide con el único comando "git"
"Bash(git)"

// ✅ También coincide con git seguido de argumentos
"Bash(git *)"
"Bash(git*)"  // También funciona sin espacio, pero * explícito es más seguro

2. Olvidar que deny tiene prioridad sobre ask

// Con esta configuración, Bash(rm -rf /tmp/test) es capturado por deny y bloqueado
// Nunca llega a ask
{
  "deny": ["Bash(rm -rf*)"],
  "ask": ["Bash(rm*)"]  // ← rm -rf es manejado por deny
}

3. No prestar atención a los códigos de salida de los hooks

# Si el comando del hook PreToolUse siempre devuelve exit 0,
# los fallos de escaneo no bloquearán la ejecución

# ❌ Pasa incluso en caso de error
"command": "node scan.mjs"

# ✅ Controlar explícitamente el código de salida
"command": "node scan.mjs || exit 1"

4. Agregar accidentalmente settings.json a .gitignore

Algunos equipos agregan accidentalmente settings.json—que quieren compartir—a .gitignore. El enfoque correcto es configuración del proyecto bajo git, solo settings.local.json en gitignore.

5. Olvidar cambiar manualmente la configuración de producción

# ❌ Trabajando en producción con la configuración cotidiana

# ✅ Cambiar explícitamente la configuración antes de trabajar en producción
CLAUDE_SETTINGS=.claude/settings.production.json claude

Registrar un alias hace que sea más difícil olvidarlo:

# ~/.bashrc or ~/.zshrc
alias claude-prod='CLAUDE_SETTINGS=.claude/settings.production.json claude'

Depuración de la configuración

Cuando no está claro “por qué se está bloqueando este comando”:

# Verificar la configuración actual
claude --print-settings 2>/dev/null || cat .claude/settings.json

# Verificar qué regla está coincidiendo (modo verbose)
claude --verbose -p "Ejecutar git push"

Resumen: Mejores prácticas para el diseño de permisos

1. Empezar con deny
   → Listar comandos que nunca deben ejecutarse
   → rm -rf, git push --force, DROP TABLE son esenciales

2. Luego configurar ask
   → Operaciones de escritura y despliegue que requieren confirmación

3. Allow para todo lo demás
   → Operaciones de lectura y CI: allow para todo, por eficiencia

4. Automatizar la seguridad con Hooks
   → Escaneo pre-commit, type-check automático después de ediciones

5. Preparar archivos de configuración específicos por entorno
   → settings.json (desarrollo), settings.production.json (producción)

Con una configuración de permisos adecuada, dejarás de hacer clic mecánicamente en botones de aprobación y podrás concentrarte solo en las operaciones que realmente necesitan revisión. Dedicar 30 minutos al diseño inicial hará que cientos de horas futuras de trabajo sean más seguras.

Artículos relacionados

Referencias

#claude-code #permissions #security #hooks #settings #configuration

Lleva tu flujo con Claude Code al siguiente nivel

50 plantillas de prompts probadas en producción, listas para copiar y pegar en Claude Code.

Gratis

PDF gratuito: Hoja de trucos de Claude Code en 5 minutos

Solo deja tu correo y te enviaremos al instante la hoja de trucos en una página A4.

Cuidamos tus datos personales y nunca enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero apasionado por Claude Code. Dirige claudecode-lab.com, un medio tecnológico en 10 idiomas con más de 2.000 páginas.