← Claude Code Hub
Jul 31, 2026 · 7 min de lectura ✦ Tip #151

--dangerously-skip-permissions en Claude Code: por qué tu script acaba en verde sin haber hecho nada

Tu job de CI llama a `claude -p`, termina con exit 0 y el commit no está. Nadie te avisó de nada, y por eso medio internet acaba pegando `--dangerously-skip-permissions` en el pipeline.

Comparativa en Claude Code headless: a la izquierda lo que devuelve la ejecucion (exit code 0, subtype success, is_error false) en verde, a la derecha lo que paso de verdad (permission_denials 2, el fichero no existe) en rojo, y abajo las tres salidas ordenadas de mejor a peor: allowedTools, permission-mode dontAsk y dangerously-skip-permissions

TL;DR En headless, un permiso denegado no rompe la ejecución. claude -p devuelve exit code 0, "subtype": "success" y "is_error": false aunque Claude no haya tocado un solo fichero. La única huella está en el array permission_denials del JSON, que nadie mira. Léelo y falla el build tú mismo. Y para que Claude sí pueda trabajar, --allowedTools (di exactamente qué puede hacer) o --permission-mode dontAsk (deniega rápido, sin reintentos) antes que el --dangerously-skip-permissions al que llega todo el mundo.

Tu job de CI llama a claude -p, termina en verde, y el commit no está. No hay error, no hay aviso, no hay nada. Lo miras dos veces, no entiendes nada, y acabas donde acaba medio internet: pegando --dangerously-skip-permissions en el pipeline para que "deje de dar problemas".

El problema es que nunca dio problemas. Dio silencio.

Lo que ves, y lo que pasó de verdad

Lancé esto en un repo limpio, en modo Manual, con un comando que no está en mis reglas allow:

claude -p "Run this exact shell command and nothing else: touch ./needsperm.txt" \
  --permission-mode default --output-format json

Lo que devuelve la ejecución:

EXIT CODE : 0
subtype   : success
is_error  : False
denials   : 2  ['Bash', 'Bash']
fichero   : NO creado

Exit 0. success. is_error: false. Y el fichero no existe. Claude lo intentó dos veces, el sistema de permisos lo denegó las dos, y la ejecución terminó declarándose un éxito.

En una sesión interactiva esto no te pasa: aparece el diálogo de permisos y pulsas. Con -p no hay nadie a quien preguntar, así que la llamada se deniega y Claude sigue adelante con lo que le queda. Desde fuera, una ejecución que no pudo hacer su trabajo y una que lo hizo entero son indistinguibles.

Cómo detectarlo, que es lo primero

El dato está ahí, solo que fuera del sitio donde miras. Con --output-format json, cada denegación se apunta en permission_denials:

out=$(claude -p "$PROMPT" --output-format json)
denied=$(printf '%s' "$out" | jq '.permission_denials | length')

if [ "$denied" -gt 0 ]; then
  echo "Claude fue bloqueado $denied veces:"
  printf '%s' "$out" | jq -r '.permission_denials[] |
    "  \(.tool_name): \(.tool_input.command // .tool_input.file_path // "?")"'
  exit 1
fi

Contra la ejecución de arriba, eso imprime:

Claude fue bloqueado 2 veces:
  Bash: touch ./needsperm.txt
  Bash: touch ./needsperm.txt

Ponlo en el job y tu pipeline deja de mentirte. Esto es lo que vale la pena copiar aunque no cambies nada más.

Y usa printf '%s', no echo. El JSON lleva \n dentro de las cadenas y zsh (el shell por defecto de macOS) los convierte en saltos de línea reales, así que echo "$out" | jq te devuelve un parse error que parece un fallo de Claude Code y es tuyo. En bash funciona, que es justo lo que hace que cueste tanto encontrarlo.

Las cuatro salidas, de mejor a peor

Opción Qué hace Para qué sirve
--allowedTools Preaprueba exactamente lo que puede ejecutar CI donde sabes qué va a hacer Claude
--permission-mode dontAsk Deniega todo lo que pediría permiso, sin esperar Pipelines cerrados y entornos restringidos
--permission-mode auto Un clasificador aparte revisa cada acción Tareas largas donde no puedes enumerarlo todo
--dangerously-skip-permissions Se salta las comprobaciones Contenedores y VMs aisladas, y punto

1. --allowedTools, la que deberías usar por defecto

Le dices qué puede hacer y lo hace, sin diálogos y sin abrir la puerta a nada más:

claude -p "corrige los errores de lint" \
  --allowedTools "Read" "Edit" "Bash(npm run lint*)"

Comprobado en la misma prueba de antes: con la regla puesta, el comando se ejecuta y el fichero aparece.

2. --permission-mode dontAsk, cuando prefieres el portazo

Deniega de golpe todo lo que hubiera pedido permiso, y solo deja pasar tus reglas allow, los comandos de solo lectura y lo que apruebe un hook PreToolUse. La documentación lo describe para pipelines de CI y entornos restringidos, y la clave está en esta frase: "the session never waits for input".

La diferencia práctica con el modo Manual es el ruido. En mi prueba, Manual gastó 3 turnos reintentando el comando denegado; dontAsk lo cortó en 2 y sin reintentos.

3. --permission-mode auto, con un tope que conviene conocer

El clasificador de auto mode revisa cada acción en vez de preguntarte. Funciona bien, pero en headless tiene un final: si bloquea 3 veces seguidas o 20 en total, la sesión se aborta, porque no hay nadie a quien pasarle el turno. Ese es el error que verás:

Agent aborted: too many classifier denials in headless mode

4. --dangerously-skip-permissions, la que casi nunca es la respuesta

Es exactamente lo mismo que --permission-mode bypassPermissions. Y hay un detalle que dice bastante: el clasificador de auto mode bloquea por defecto lanzar un agente autónomo sin aprobación ni sandbox, y nombra esta flag como ejemplo. Claude Code frena cuando Claude Code intenta usarla.

Lo que esa flag no se salta (aunque lo parezca)

Aquí hay más matiz del que sugiere el nombre. Ni en modo bypass se saltan:

  • Tus reglas ask explícitas, que siguen abriendo diálogo
  • Las herramientas de conector que tu organización puso en ask
  • Las herramientas MCP marcadas como requiresUserInteraction
  • rm -rf / y rm -rf ~, que siguen preguntando como cortacircuitos, incluso dentro de $(...), de comillas invertidas o de <(...)
  • Desde la v2.1.281, un rm recursivo cuyo objetivo sale solo de una sustitución, como rm -rf "$(pwd)", aunque tengas una regla allow para Bash

En headless eso es una denegación más: lancé rm -rf "$(pwd)" con -p y esta flag en una carpeta desechable, la carpeta siguió ahí, y el JSON volvió con "subtype": "success" y el comando dentro de permission_denials. El mismo detector de arriba lo caza. En una sesión interactiva que nadie vigila, el diálogo espera 2 minutos y, si no contestas, deniega el comando con una sugerencia para reescribirlo, así que la sesión sigue trabajando. CLAUDE_CODE_DISABLE_DANGEROUS_RM_TIMEOUT=1 quita esa espera.

Y dos negativas que te van a morder si automatizas:

--dangerously-skip-permissions cannot be used with root/sudo privileges
for security reasons

En Linux y macOS se niega a arrancar como root o bajo sudo, salvo dentro de un sandbox reconocido (qué cuenta como tal: un contenedor de Docker que corre como root no basta). Y una sesión en background con --bg no arranca en este modo hasta que hayas aceptado el diálogo de responsabilidad una vez en una sesión interactiva. Un contenedor recién creado no lo ha aceptado nunca.

Si en vez del flag confías en "defaultMode": "bypassPermissions" dentro del .claude/settings.json del repo, desde la v2.1.257 se ignora y la ejecución arranca en Manual, sin error: dónde tiene que ir ahora.

Referencia

Modo en headless Qué pasa cuando algo pediría permiso
default (Manual) Se deniega, la ejecución continúa y termina en success
acceptEdits Pasan las ediciones y los comandos de fichero comunes (touch sí, chmod no); el resto se deniega igual de callado
dontAsk Se deniega inmediatamente, sin reintentos ni espera
auto Decide el clasificador; se aborta a los 3 bloqueos seguidos o 20 en total
bypassPermissions Se ejecuta, salvo las excepciones de la lista de arriba

Si lo tuyo es la sesión interactiva y no el pipeline, el mapa es otro: los 6 modos de permisos con Shift+Tab para el día a día, el sandbox para ejecutar sin diálogos con red y disco acotados, y montar a Claude como agente autónomo si lo que quieres es dejarlo trabajando de madrugada.

Para las sesiones interactivas, esta guía ordena las alternativas a --dangerously-skip-permissions para que Claude Code deje de pedir permiso sin perder el control.

Documentación oficial: Permission modes · Non-interactive mode · CLI reference

Requisitos: --permission-mode dontAsk y el resto de valores están en Claude Code v2.1.x; el alias manual para default pide v2.1.200 o superior. Las ejecuciones de este tip las hice en v2.1.220. Los topes del clasificador, el cortacircuitos de rm -rf y las dos negativas de arranque salen de la documentación vigente, no de mis pruebas. La pregunta ante rm -rf "$(pwd)" pide v2.1.281 y la comprobé en esa versión; la espera de 2 minutos sale del changelog.

¿Te ha servido? Haz que wmedia.es te salga antes en Google.

Añadir wmedia.es como fuente preferida en Google
GUÍA GRATUITA

Aprueba menos, pero mejor.

A los diez minutos ya le das a «sí» sin leer. Eso no es revisar, es rezar. La guía de 10 páginas con las cinco palancas, en orden de riesgo.

  • 1. Reglas la primera que coincide gana
  • 2. Modo un dial, no un interruptor
  • 3. Auto mode un clasificador aprueba por ti
  • 4. Sandbox una valla del sistema operativo
  • 5. Bypass solo dentro de un contenedor
¿Eres desarrollador/a Web profesional?

Te llega por email · Te unes a la newsletter Gravitas · Cancela cuando quieras

Permisos de Claude Code: la chuleta para aprobar menos sin perder el control
GUÍA GRATUITA

Aprueba menos, pero mejor.

¿Eres desarrollador/a Web profesional? · Cancela cuando quieras
Workshop para equipos

Multiplica el output de tu equipo sin sacrificar calidad: workshop AI First de 6 a 8 horas, online, sobre la plataforma Claude.

Ver el workshop

¿Harto de aprobar permisos sin leer?