Tips & Tricks (Actualizado: 1/6/2026)

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

Guía de permisos de Claude Code: allow/deny/ask, settings.json, hooks PreToolUse, ajustes gestionados y budget seguro con código funcional.

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

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 gestionan oficialmente mediante settings.json. Usa ~/.claude/settings.json para ajustes de usuario, .claude/settings.json para reglas compartidas por el equipo y .claude/settings.local.json para sobrescrituras personales. ~/.claude.json todavía puede guardar estado como MCP, pero las reglas de permisos conviene tratarlas como configuración de settings.json.

Prioridad (de mayor a menor):
Managed settings
    > Argumentos de línea de comandos
        > Local .claude/settings.local.json
            > Project .claude/settings.json
                > User ~/.claude/settings.json

Las permission rules se fusionan entre scopes y se evalúan en orden deny -> ask -> allow

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 trabajos de producción o casi producción, coloca esta configuración como .claude/settings.json activo y empieza con claude --permission-mode plan o con un dontAsk preaprobado. Esto se ajusta mejor al modelo oficial de scopes y permission modes que intercambiar un archivo alternativo mediante una variable de entorno.

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.

2026: Permission budget seguro y revisión de equipo

Aquí permission budget no es un nombre oficial de función. Es el límite operativo de lo que permites ejecutar automáticamente durante la primera semana. Según la documentación oficial al 1 de junio de 2026, las permission rules se evalúan en orden deny -> ask -> allow. Los hooks PreToolUse agregan comprobaciones en tiempo de ejecución, pero no sustituyen un deny o ask que ya coincidió. Por eso el primer budget debe priorizar la reversibilidad antes que la velocidad.

Un budget inicial seguro es pequeño. En allow, deja solo lectura y verificación: Read, Glob, Grep, git status, git diff, git log, npm run lint y npm run test. En ask, pon operaciones que cambian intención: Edit, Write, git add, git commit, git push, npm install y deploy. En deny, pon lo irreversible o sensible: .env, secrets/**, rm -rf, git reset --hard, git push --force, curl | bash, wget | sh y comandos sobre bases de datos de producción. bypassPermissions solo pertenece a contenedores, VMs o devcontainers descartables.

En equipo, revisa .claude/settings.json como código de aplicación. Cada PR debe responder tres preguntas: si todo allow puede ejecutarse muchas veces sin daño, si cada ask representa una confirmación humana real, y si deny cubre secretos, force push, borrados y producción. En organizaciones con administración central, server-managed settings permite fijar disableBypassPermissionsMode y disableAutoMode como "disable", y usar allowManagedPermissionRulesOnly para impedir reglas locales o de proyecto.

Un fallo peligroso es permitir Bash(git *) o Bash(node *) de forma amplia y asumir que Read(.env*) basta para proteger secretos. La documentación oficial aclara que los deny de Read y Edit aplican a herramientas de archivo de Claude Code y a comandos reconocidos, pero no bloquean subprocesos arbitrarios, como scripts Node o Python, que abren archivos directamente. Para proteger secrets, evita Bash amplio y combínalo con sandbox, permisos del sistema operativo y checks PreToolUse.

Define la recuperación antes del incidente. Si aparece una edición no deseada, abre /permissions para ver la regla activa y su origen, revisa git diff y revierte con git restore -p para conservar cambios buenos. Para archivos no rastreados, ejecuta git clean -n antes de borrar. Si un secreto pudo leerse o entrar en el transcript, no basta con corregir .claude/settings.json: rota el token.

Para convertir este artículo en política de repositorio, empieza con permission budget loop y permission audit checklist. Si necesitas plantillas y material listo para usar, compara los productos de Claude Code. Para rollout de equipo, revisión de permisos y onboarding seguro, la consulta es mejor que improvisar reglas.

Prioridad y sobreescritura de archivos de configuración

Cuando existen múltiples archivos de configuración:

~/.claude/settings.json     ← User (compartido entre proyectos)
.claude/settings.json       ← Project (gestionado con git)
.claude/settings.local.json ← Local (personal, en gitignore)
managed-settings.json       ← Managed (política de organización, máxima prioridad)

Las permission rules se fusionan y deny siempre se evalúa antes que allow

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

# ✅ Empezar en plan mode y mantener el .claude/settings.json del worktree seguro para producción
claude --permission-mode plan

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

# ~/.bashrc or ~/.zshrc
alias claude-prod='claude --permission-mode plan'

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
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.