> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks de Cascade

> Ejecuta comandos de shell personalizados en puntos clave del flujo de trabajo de Cascade para el registro, los controles de seguridad, la validación y la gobernanza empresarial con hooks previos y posteriores.

Los Hooks de Cascade te permiten ejecutar comandos de shell personalizados en puntos clave del flujo de trabajo de Cascade. Esta potente función de extensibilidad te permite registrar operaciones, aplicar controles, ejecutar comprobaciones de validación o integrarte con sistemas externos.

<Note>
  Los hooks están diseñados para usuarios avanzados y equipos empresariales que necesitan un control preciso sobre el comportamiento de Cascade. Requieren conocimientos básicos de scripting de shell.
</Note>

<div id="what-you-can-build">
  ## Qué puedes crear
</div>

Hooks habilitan una amplia gama de capacidades de automatización y gobernanza:

* **Registro y analítica**: Supervisa cada archivo leído, cambio de código, comando ejecutado, prompt de usuario o respuesta de Cascade para el cumplimiento normativo y el análisis de uso
* **Controles de seguridad**: Impide que Cascade acceda a archivos sensibles, ejecute comandos peligrosos o procese prompts que infrinjan las políticas
* **Garantía de calidad**: Ejecuta linters, formateadores o pruebas automáticamente tras modificar el código
* **Flujos de trabajo personalizados**: Integra sistemas de seguimiento de incidencias, sistemas de notificaciones o pipelines de despliegue
* **Estandarización del equipo**: Aplica estándares de codificación y prácticas recomendadas en toda tu organización

<div id="how-hooks-work">
  ## Cómo funcionan los Hooks
</div>

Los Hooks son comandos de shell que se ejecutan automáticamente cuando se producen acciones específicas de Cascade. Cada hook:

1. **Recibe contexto** (detalles sobre la acción que se está realizando) en formato JSON a través de la entrada estándar
2. **Ejecuta tu script**: Python, Bash, Node.js o cualquier ejecutable
3. **Devuelve un resultado** mediante el código de salida y los flujos de salida

En el caso de los **pre-hooks** (ejecutados antes de una acción), tu script puede **bloquear la acción** si finaliza con el código de salida `2`. Esto hace que los pre-hooks sean ideales para implementar políticas de seguridad o validaciones.

<div id="configuration">
  ## Configuración
</div>

Los Hooks se configuran en archivos JSON que pueden colocarse en tres niveles diferentes. Cascade carga y fusiona los hooks de todas las ubicaciones, lo que da a los equipos flexibilidad para distribuir y gestionar las configuraciones de hooks.

<div id="system-level">
  #### A nivel del sistema
</div>

Los hooks a nivel del sistema son ideales para aplicar políticas de toda la organización en máquinas de desarrollo compartidas. Por ejemplo, puedes usarlos para aplicar políticas de seguridad, requisitos de cumplimiento o flujos de trabajo obligatorios de revisión de código. Los equipos Enterprise también pueden configurar hooks desde el [panel de control en la nube](#cloud-dashboard-configuration) sin tener que gestionar archivos locales.

* **macOS**: `/Library/Application Support/Windsurf/hooks.json`
* **Linux/WSL**: `/etc/windsurf/hooks.json`
* **Windows**: `C:\ProgramData\Windsurf\hooks.json`

<div id="user-level">
  #### Nivel de usuario
</div>

Los hooks a nivel de usuario son ideales para preferencias personales y flujos de trabajo opcionales.

* **Devin Desktop IDE**: `~/.codeium/windsurf/hooks.json`
* **Plugin de JetBrains**: `~/.codeium/hooks.json`

<div id="workspace-level">
  #### A nivel del espacio de trabajo
</div>

Los hooks a nivel del espacio de trabajo permiten a los equipos gestionar las versiones de las políticas específicas del proyecto junto con su código. Pueden incluir reglas de validación personalizadas, integraciones específicas del proyecto o flujos de trabajo específicos del equipo.

* **Ubicación**: `.windsurf/hooks.json` en la raíz de tu espacio de trabajo

<Note>
  Los hooks de las tres ubicaciones se **combinan**. Si el mismo evento de hook está configurado en múltiples ubicaciones, todos los hooks se ejecutarán en este orden: sistema → usuario → espacio de trabajo.
</Note>

<div id="basic-structure">
  ### Estructura básica
</div>

A continuación se muestra un ejemplo de la estructura básica de la configuración de hooks:

```json theme={null}
{
  "hooks": {
    "pre_read_code": [
      {
        "command": "python3 /path/to/your/script.py",
        "powershell": "python3 C:\\path\\to\\your\\script.py",
        "show_output": true
      }
    ],
    "post_write_code": [
      {
        "command": "python3 /path/to/another/script.py",
        "show_output": true
      }
    ]
  }
}
```

En este ejemplo, `pre_read_code` especifica tanto un comando para macOS/Linux como un comando de PowerShell para Windows. El hook `post_write_code` solo especifica `command`, por lo que se ejecutará en macOS/Linux y, en Windows, usará PowerShell como alternativa.

<div id="configuration-options">
  ### Opciones de configuración
</div>

Cada hook acepta los siguientes parámetros:

| Parámetro           | Tipo    | Descripción                                                                                                                                    |
| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `command`           | string  | El comando de shell que se ejecutará en **macOS/Linux** (mediante `bash -c`). Debe especificarse al menos uno de `command` o `powershell`.     |
| `powershell`        | string  | Opcional. El comando que se ejecutará en **Windows** (mediante `powershell -Command`). Si se omite en Windows, se usa `command` como fallback. |
| `show_output`       | boolean | Indica si se debe mostrar la salida stdout/stderr del hook en la UI de Cascade visible para el usuario. Útil para depuración.                  |
| `working_directory` | string  | Opcional. El directorio desde el que se ejecutará el comando. El valor predeterminado es la raíz de tu espacio de trabajo.                     |

<div id="cross-platform-behavior">
  #### Comportamiento en distintas plataformas
</div>

Los campos `command` y `powershell` permiten definir comandos adecuados para cada plataforma en una sola configuración. Esto resulta útil para equipos con entornos mixtos de macOS/Linux y Windows.

| Plataforma  | `command` configurado | `powershell` configurado | Resultado                                                     |
| ----------- | :-------------------: | :----------------------: | ------------------------------------------------------------- |
| macOS/Linux |           ✓           |        (ignorado)        | Ejecuta `command` mediante `bash -c`                          |
| macOS/Linux |           ✗           |             ✓            | El hook se omite silenciosamente                              |
| Windows     |           ✓           |             ✗            | Usa `command` como alternativa mediante `powershell -Command` |
| Windows     |           ✗           |             ✓            | Ejecuta `powershell` mediante `powershell -Command`           |
| Windows     |           ✓           |             ✓            | Ejecuta `powershell` mediante `powershell -Command`           |
| Cualquiera  |           ✗           |             ✗            | Error de validación                                           |

<Note>
  **Acerca del parámetro `working_directory`:**

  * En espacios de trabajo con varios repos, el valor predeterminado es la raíz del repo en el que se está trabajando en ese momento
  * Las rutas relativas se resuelven desde la ubicación predeterminada (espacio de trabajo o raíz del repo)
  * Se admiten rutas absolutas
  * No se admite usar `~` para expandir el directorio de inicio
</Note>

<div id="hook-events">
  ## Eventos de hook
</div>

Cascade ofrece doce eventos de hook que cubren las acciones más importantes del flujo de trabajo del agente.

<div id="common-input-structure">
  ### Estructura de entrada común
</div>

Todos los hooks reciben un objeto JSON con los siguientes campos comunes:

| Field               | Type   | Description                                                                                                                                                                                                                                                                                                                                                         |
| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_action_name` | string | Nombre del evento del hook (p. ej., "pre\_read\_code", "post\_write\_code")                                                                                                                                                                                                                                                                                         |
| `trajectory_id`     | string | Identificador único de la conversación general de Cascade                                                                                                                                                                                                                                                                                                           |
| `execution_id`      | string | Identificador único de un solo turno del agente                                                                                                                                                                                                                                                                                                                     |
| `timestamp`         | string | Marca de tiempo ISO 8601 del momento en que se activó el hook                                                                                                                                                                                                                                                                                                       |
| `model_name`        | string | Nombre legible del modelo asociado a esta invocación del hook (p. ej., "Claude Sonnet 4", "GPT 4.1"). Es la misma etiqueta que se muestra en el selector de modelos de Cascade. El valor puede cambiar con el tiempo a medida que Devin Desktop actualiza los nombres visibles de los modelos. Se establece como "Unknown" cuando no se puede determinar el modelo. |
| `tool_info`         | object | Información específica del evento (varía según el tipo de hook)                                                                                                                                                                                                                                                                                                     |

En los siguientes ejemplos, los campos comunes se omiten por brevedad. Hay doce tipos principales de eventos de hook:

<div id="pre_read_code">
  ### pre\_read\_code
</div>

Se activa **antes** de que Cascade lea un archivo de código. Puede bloquear la acción si el hook finaliza con el código 2.

**Casos de uso**: Restringir el acceso a archivos, registrar operaciones de lectura, comprobar permisos

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "pre_read_code",
  "tool_info": {
    "file_path": "/Users/yourname/project/file.py"
  }
}
```

Este `file_path` puede ser la ruta de un directorio cuando Cascade lee ese directorio de forma recursiva.

<div id="post_read_code">
  ### post\_read\_code
</div>

Se activa **después** de que Cascade lea correctamente un archivo de código.

**Casos de uso**: Registrar lecturas exitosas, hacer seguimiento de los patrones de acceso a archivos

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_read_code",
  "tool_info": {
    "file_path": "/Users/yourname/project/file.py"
  }
}
```

Este `file_path` puede ser la ruta de un directorio cuando Cascade lee un directorio de forma recursiva.

<div id="pre_write_code">
  ### pre\_write\_code
</div>

Se activa **antes** de que Cascade escriba o modifique un archivo de código. Esto puede bloquear la operación si el hook finaliza con el código 2.

**Casos de uso**: Evitar modificaciones en archivos protegidos, crear copias de seguridad antes de los cambios

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "pre_write_code",
  "tool_info": {
    "file_path": "/Users/yourname/project/file.py",
    "edits": [
      {
        "old_string": "def old_function():\n    pass",
        "new_string": "def new_function():\n    return True"
      }
    ]
  }
}
```

<div id="post_write_code">
  ### post\_write\_code
</div>

Se activa **después** de que Cascade escribe o modifica un archivo de código.

**Casos de uso**: Ejecutar linters, formateadores o pruebas; registrar cambios en el código

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_write_code",
  "tool_info": {
    "file_path": "/Users/yourname/project/file.py",
    "edits": [
      {
        "old_string": "import os",
        "new_string": "import os\nimport sys"
      }
    ]
  }
}
```

<div id="pre_run_command">
  ### pre\_run\_command
</div>

Se activa **antes** de que Cascade ejecute un comando en la terminal. Esto puede bloquear la ejecución si el hook finaliza con el código 2.

**Casos de uso**: Bloquear comandos peligrosos, registrar todas las ejecuciones de comandos, agregar comprobaciones de seguridad

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "pre_run_command",
  "tool_info": {
    "command_line": "npm install package-name",
    "cwd": "/Users/yourname/project"
  }
}
```

<div id="post_run_command">
  ### post\_run\_command
</div>

Se activa **después** de que Cascade ejecuta un comando en la terminal.

**Casos de uso**: Registrar los resultados del comando, activar acciones posteriores

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_run_command",
  "tool_info": {
    "command_line": "npm install package-name",
    "cwd": "/Users/yourname/project"
  }
}
```

<div id="pre_mcp_tool_use">
  ### pre\_mcp\_tool\_use
</div>

Se activa **antes** de que Cascade invoque una herramienta MCP (Model Context Protocol). Esto puede bloquear la acción si el hook finaliza con el código 2.

**Casos de uso**: Registrar el uso de herramientas MCP, restringir qué herramientas MCP se pueden usar

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "pre_mcp_tool_use",
  "tool_info": {
    "mcp_server_name": "github",
    "mcp_tool_arguments": {
      "owner": "code-owner",
      "repo": "my-cool-repo",
      "title": "Bug report",
      "body": "Description of the bug here"
    },
    "mcp_tool_name": "create_issue"
  }
}
```

<div id="post_mcp_tool_use">
  ### post\_mcp\_tool\_use
</div>

Se activa **después** de que Cascade invoque correctamente una herramienta MCP.

**Casos de uso**: Registrar operaciones de MCP, supervisar el uso de la API, ver resultados de MCP

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_mcp_tool_use",
  "tool_info": {
    "mcp_result": "...",
    "mcp_server_name": "github",
    "mcp_tool_arguments": {
      "owner": "code-owner",
      "perPage": 1,
      "repo": "my-cool-repo",
      "sha": "main"
    },
    "mcp_tool_name": "list_commits"
  }
}
```

<div id="pre_user_prompt">
  ### pre\_user\_prompt
</div>

Se activa **antes** de que Cascade procese el texto del prompt del usuario. Esto puede bloquear la acción si el hook finaliza con el código 2.

**Casos de uso**: Registrar todos los prompts de los usuarios para fines de auditoría, bloquear prompts potencialmente dañinos o que infrinjan las políticas

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "pre_user_prompt",
  "tool_info": {
    "user_prompt": "can you run the echo hello command"
  }
}
```

La opción de configuración `show_output` no es aplicable a este hook.

<div id="post_cascade_response">
  ### post\_cascade\_response
</div>

Se activa de forma asíncrona **después** de que Cascade complete una respuesta al prompt de un usuario. Este hook recibe la respuesta completa de Cascade desde el último mensaje del usuario.

**Casos de uso**: Registrar todas las respuestas de Cascade para auditoría, analizar patrones de respuesta, enviar respuestas a sistemas externos para revisión de cumplimiento

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_cascade_response",
  "tool_info": {
    "response": "### Planner Response\n\nI'll help you create that file.\n\n*Created file `/path/to/file.py`*\n\n### Planner Response\n\nThe file has been created successfully."
  }
}
```

El campo `response` contiene el contenido en formato Markdown de la respuesta de Cascade desde la última entrada del usuario. Esto incluye respuestas del planner, acciones de las herramientas (lecturas y escrituras de archivos, comandos) y cualquier otro paso que haya realizado Cascade. También incluye información sobre qué [Rules](/es/desktop/cascade/memories) se activaron. Consulta el ejemplo [Tracking Triggered Rules](#tracking-triggered-rules) para ver cómo analizar el uso de Rules.

La opción de configuración `show_output` no se aplica a este hook.

<Warning>
  El contenido de `response` se deriva de los datos de la trayectoria y puede contener información confidencial de tu base de código o de tus conversaciones. Maneja estos datos de acuerdo con las políticas de seguridad y privacidad de tu organización.
</Warning>

<div id="post_cascade_response_with_transcript">
  ### post\_cascade\_response\_with\_transcript
</div>

Se activa de forma asíncrona **después** de que Cascade complete una respuesta al prompt de un usuario, de forma similar a `post_cascade_response`. En lugar de proporcionar un resumen en markdown directamente, este hook escribe la transcripción completa de la conversación (desde su inicio) en un archivo JSONL local y proporciona la ruta del archivo.

**Casos de uso**: registro de auditoría y cumplimiento de Enterprise, seguimiento de contribuciones generadas por IA, envío de transcripciones a herramientas externas de observabilidad o analítica

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_cascade_response_with_transcript",
  "tool_info": {
    "transcript_path": "/Users/yourname/.windsurf/transcripts/{trajectory_id}.jsonl"
  }
}
```

La ruta `transcript_path` apunta a un archivo [JSONL](https://jsonlines.org/) en `~/.windsurf/transcripts/{trajectory_id}.jsonl`. Cada línea es un objeto JSON que representa un único paso de la conversación, con los campos `type` y `status`, además de datos específicos de ese paso. Por ejemplo:

```jsonl theme={null}
{"status":"done","type":"user_input","user_input":{"rules_applied":{"always_on":["my-rule.md"]},"user_response":"create a hello world file"}}
{"planner_response":{"response":"I'll create a hello world file for you."},"status":"done","type":"planner_response"}
{"code_action":{"new_content":"print('hello world')\n","path":"/path/to/file.py"},"status":"done","type":"code_action"}
{"planner_response":{"response":"I created the file for you."},"status":"done","type":"planner_response"}
```

La transcripción incluye datos detallados del cliente, como contenido de archivos, salidas de comandos, argumentos de herramientas, resultados de búsqueda y [Rules](/es/desktop/cascade/memories) aplicadas. Ten en cuenta que la estructura exacta de cada paso puede cambiar en futuras versiones, así que diseña cualquier consumidor de hooks para que sea resistente a cambios.

Los archivos de transcripción se escriben con permisos `0600`. Devin Desktop limita automáticamente el directorio de transcripciones a 100 archivos y elimina los más antiguos según su fecha de modificación.

La opción de configuración `show_output` no se aplica a este hook.

Esta tabla muestra las diferencias clave entre los hooks `post_cascade_response` y `post_cascade_response_with_transcript`:

|                         | `post_cascade_response`                            | `post_cascade_response_with_transcript`                                                     |
| ----------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| **Ámbito de los datos** | Solo los pasos desde la última entrada del usuario | La conversación completa desde el principio                                                 |
| **Formato**             | Resumen en Markdown en `tool_info.response`        | Archivo JSONL estructurado en `tool_info.transcript_path`                                   |
| **Nivel de detalle**    | Resumen condensado y legible para personas         | Datos detallados y legibles para máquinas (contenido de archivos, salida de comandos, etc.) |
| **Entrega**             | Integrado mediante JSON por stdin                  | Archivo en disco (`~/.windsurf/transcripts/`)                                               |

<Warning>
  Los archivos de transcripción contendrán información sensible de tu base de código, incluido el contenido de archivos, salidas de comandos y el historial de conversaciones. Maneja estos archivos de acuerdo con las políticas de seguridad y privacidad de tu organización.
</Warning>

<div id="post_setup_worktree">
  ### post\_setup\_worktree
</div>

Se activa **después** de crear y configurar un nuevo [git worktree](./worktrees). El hook se ejecuta dentro del directorio del nuevo **worktree**.

**Casos de uso**: Copiar archivos `.env` u otros archivos sin seguimiento al worktree, instalar dependencias, ejecutar scripts de configuración

**Variables de entorno**:

| Variable               | Descripción                                                                                                                                  |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `$ROOT_WORKSPACE_PATH` | La ruta absoluta del espacio de trabajo original. Úsala para acceder a archivos o ejecutar comandos en relación con el repositorio original. |

**JSON de entrada**:

```json theme={null}
{
  "agent_action_name": "post_setup_worktree",
  "tool_info": {
    "worktree_path": "/Users/me/.windsurf/worktrees/my-repo/abmy-repo-c123",
    "root_workspace_path": "/Users/me/projects/my-repo"
  }
}
```

<div id="exit-codes">
  ## Códigos de salida
</div>

Los scripts de tus hooks comunican los resultados mediante códigos de salida:

| Código de salida | Significado      | Efecto                                                                                              |
| ---------------- | ---------------- | --------------------------------------------------------------------------------------------------- |
| `0`              | Éxito            | La acción continúa normalmente                                                                      |
| `2`              | Error de bloqueo | El agente Cascade verá el mensaje de error de stderr. En los pre-hooks, esto **bloquea** la acción. |
| Cualquier otro   | Error            | La acción continúa normalmente                                                                      |

<Warning>
  Solo los **pre-hooks** (pre\_user\_prompt, pre\_read\_code, pre\_write\_code, pre\_run\_command, pre\_mcp\_tool\_use) pueden bloquear acciones con el código de salida 2. Los post-hooks no pueden bloquearlas porque la acción ya ocurrió.
</Warning>

Ten en cuenta que el usuario puede ver cualquier salida estándar y error estándar generados por hooks en la interfaz de usuario de Cascade si `show_output` es `true`.

<div id="example-use-cases">
  ## Casos de uso de ejemplo
</div>

<div id="logging-all-cascade-actions">
  ### Registro de todas las acciones de Cascade
</div>

Registra todas las acciones que realiza Cascade con fines de auditoría.

**Config**:

```json theme={null}
{
  "hooks": {
    "post_read_code": [
      {
        "command": "python3 /Users/yourname/hooks/log_input.py",
        "show_output": true
      }
    ],
    "post_write_code": [
      {
        "command": "python3 /Users/yourname/hooks/log_input.py",
        "show_output": true
      }
    ],
    "post_run_command": [
      {
        "command": "python3 /Users/yourname/hooks/log_input.py",
        "show_output": true
      }
    ],
    "post_mcp_tool_use": [
      {
        "command": "python3 /Users/yourname/hooks/log_input.py",
        "show_output": true
      }
    ],
    "post_cascade_response": [
      {
        "command": "python3 /Users/yourname/hooks/log_input.py"
      }
    ]
  }
}
```

**Script** (`log_input.py`):

```python theme={null}
#!/usr/bin/env python3

import sys
import json

def main():
    # Leer los datos JSON desde stdin
    input_data = sys.stdin.read()
    
    # Parsear el JSON
    try:
        data = json.loads(input_data)
        
        # Escribir JSON formateado en el archivo
        with open("/Users/yourname/hooks/input.txt", "a") as f:
            f.write('\n' + '='*80 + '\n')
            f.write(json.dumps(data, indent=2, separators=(',', ': ')))
            f.write('\n')
    
        print(json.dumps(data, indent=2))
    except json.JSONDecodeError as e:
        print(f"Error parsing JSON: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
```

Este script añade cada invocación de hook a un archivo de registro, creando un registro de auditoría de todas las acciones de Cascade. Puede transformar los datos de entrada o aplicar lógica personalizada como mejor le parezca.

<div id="restricting-file-access">
  ### Restringir el acceso a los archivos
</div>

Evita que Cascade lea archivos fuera de un directorio específico.

**Config**:

```json theme={null}
{
  "hooks": {
    "pre_read_code": [
      {
        "command": "python3 /Users/yourname/hooks/block_read_access.py",
        "show_output": true
      }
    ]
  }
}
```

**Script** (`block_read_access.py`):

```python theme={null}
#!/usr/bin/env python3

import sys
import json

ALLOWED_PREFIX = "/Users/yourname/my-project/"

def main():
    # Leer los datos JSON desde stdin
    input_data = sys.stdin.read()

    # Analizar el JSON
    try:
        data = json.loads(input_data)

        if data.get("agent_action_name") == "pre_read_code":
            tool_info = data.get("tool_info", {})
            file_path = tool_info.get("file_path", "")
            
            if not file_path.startswith(ALLOWED_PREFIX):
                print(f"Access denied: Cascade is only allowed to read files under {ALLOWED_PREFIX}", file=sys.stderr)
                sys.exit(2)  # El código de salida 2 bloquea la acción
            
            print(f"Access granted: {file_path}", file=sys.stdout)

    except json.JSONDecodeError as e:
        print(f"Error parsing JSON: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
```

Cuando Cascade intenta leer un archivo fuera del directorio autorizado, este hook bloquea la operación y muestra un mensaje de error.

<div id="blocking-dangerous-commands">
  ### Bloqueo de comandos peligrosos
</div>

Evita que Cascade ejecute comandos potencialmente peligrosos.

**Configuración**:

```json theme={null}
{
  "hooks": {
    "pre_run_command": [
      {
        "command": "python3 /Users/yourname/hooks/block_dangerous_commands.py",
        "show_output": true
      }
    ]
  }
}
```

**Script** (`block_dangerous_commands.py`):

```python theme={null}
#!/usr/bin/env python3

import sys
import json

DANGEROUS_COMMANDS = ["rm -rf", "sudo rm", "format", "del /f"]

def main():
    # Leer los datos JSON desde stdin
    input_data = sys.stdin.read()

    # Parsear el JSON
    try:
        data = json.loads(input_data)

        if data.get("agent_action_name") == "pre_run_command":
            tool_info = data.get("tool_info", {})
            command = tool_info.get("command_line", "")

            for dangerous_cmd in DANGEROUS_COMMANDS:
                if dangerous_cmd in command:
                    print(f"Command blocked: '{dangerous_cmd}' is not allowed for safety reasons.", file=sys.stderr)
                    sys.exit(2)  # El código de salida 2 bloquea el comando
            
            print(f"Command approved: {command}", file=sys.stdout)

    except json.JSONDecodeError as e:
        print(f"Error parsing JSON: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
```

Este hook escanea los comandos en busca de patrones peligrosos y los bloquea antes de ejecutarlos.

<div id="blocking-policy-violating-prompts">
  ### Bloqueo de prompts que incumplen las políticas
</div>

Evita que los usuarios envíen prompts que incumplan las políticas de la organización.

**Configuración**:

```json theme={null}
{
  "hooks": {
    "pre_user_prompt": [
      {
        "command": "python3 /Users/yourname/hooks/block_bad_prompts.py"
      }
    ]
  }
}
```

**Script** (`block_bad_prompts.py`):

```python theme={null}
#!/usr/bin/env python3

import sys
import json

BLOCKED_PATTERNS = [
    "something dangerous",
    "bypass security",
    "ignore previous instructions"
]

def main():
    # Leer los datos JSON desde stdin
    input_data = sys.stdin.read()

    # Analizar el JSON
    try:
        data = json.loads(input_data)

        if data.get("agent_action_name") == "pre_user_prompt":
            tool_info = data.get("tool_info", {})
            user_prompt = tool_info.get("user_prompt", "").lower()

            for pattern in BLOCKED_PATTERNS:
                if pattern in user_prompt:
                    print(f"Prompt blocked: Contains prohibited content. The user cannot ask the agent to do bad things.", file=sys.stderr)
                    sys.exit(2)  # El código de salida 2 bloquea el prompt

    except json.JSONDecodeError as e:
        print(f"Error parsing JSON: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
```

Este hook revisa los prompts del usuario antes de que se procesen y bloquea los que contienen patrones prohibidos. Cuando se bloquea un prompt, el usuario ve un mensaje de error en la UI de Cascade.

<div id="logging-cascade-responses">
  ### Registro de respuestas de Cascade
</div>

Registra todas las respuestas de Cascade para auditorías de cumplimiento o análisis.

**Configuración**:

```json theme={null}
{
  "hooks": {
    "post_cascade_response": [
      {
        "command": "python3 /Users/yourname/hooks/log_cascade_response.py"
      }
    ]
  }
}
```

**Script** (`log_cascade_response.py`):

```python theme={null}
#!/usr/bin/env python3

import sys
import json
from datetime import datetime

def main():
    # Leer los datos JSON desde stdin
    input_data = sys.stdin.read()

    # Parsear el JSON
    try:
        data = json.loads(input_data)

        if data.get("agent_action_name") == "post_cascade_response":
            tool_info = data.get("tool_info", {})
            cascade_response = tool_info.get("response", "")
            trajectory_id = data.get("trajectory_id", "unknown")
            timestamp = data.get("timestamp", datetime.now().isoformat())

            # Registrar en archivo
            with open("/Users/yourname/hooks/cascade_responses.log", "a") as f:
                f.write(f"\n{'='*80}\n")
                f.write(f"Timestamp: {timestamp}\n")
                f.write(f"Trajectory ID: {trajectory_id}\n")
                f.write(f"Response:\n{cascade_response}\n")

            print(f"Logged Cascade response for trajectory {trajectory_id}")

    except json.JSONDecodeError as e:
        print(f"Error parsing JSON: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
```

Este hook registra cada respuesta de Cascade en un archivo, lo que crea un registro de auditoría de todo el contenido generado por la IA. Puedes ampliarlo para enviar datos a sistemas externos de registro, bases de datos o plataformas de cumplimiento normativo.

<div id="tracking-triggered-rules">
  ### Seguimiento de las Rules activadas
</div>

Identifica qué [Rules](/es/desktop/cascade/memories) se aplicaron durante las interacciones de Cascade para mejorar la observabilidad y las métricas.

**Configuración**:

```json theme={null}
{
  "hooks": {
    "post_cascade_response": [
      {
        "command": "python3 /Users/yourname/hooks/track_rules.py"
      }
    ]
  }
}
```

**Script** (`track_rules.py`):

```python theme={null}
#!/usr/bin/env python3

import sys
import json
import re
from datetime import datetime

def extract_triggered_rules(response: str) -> dict:
    """
    Parse triggered rules from the Cascade response.
    Rules appear as: - (Rule-Type) Triggered Rule: rule-filename.md
    """
    pattern = r"- \(([^)]+)\) Triggered Rule: (.+?)(?:\s*$)"
    rules = {}

    for match in re.finditer(pattern, response, re.MULTILINE):
        rule_type, rule_name = match.groups()
        if rule_type not in rules:
            rules[rule_type] = []
        rules[rule_type].append(rule_name)

    return rules

def main():
    input_data = sys.stdin.read()

    try:
        data = json.loads(input_data)

        if data.get("agent_action_name") == "post_cascade_response":
            response = data.get("tool_info", {}).get("response", "")
            trajectory_id = data.get("trajectory_id", "unknown")
            timestamp = data.get("timestamp", datetime.now().isoformat())

            rules = extract_triggered_rules(response)
            total_rules = sum(len(v) for v in rules.values())

            # Log to file
            with open("/Users/yourname/hooks/rules_usage.log", "a") as f:
                f.write(f"\n{'='*60}\n")
                f.write(f"Timestamp: {timestamp}\n")
                f.write(f"Trajectory: {trajectory_id}\n")
                f.write(f"Total rules triggered: {total_rules}\n")
                for rule_type, rule_list in rules.items():
                    if rule_list:
                        f.write(f"  {rule_type}: {', '.join(rule_list)}\n")

            print(f"Tracked {total_rules} triggered rules")

    except json.JSONDecodeError as e:
        print(f"Error parsing JSON: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
```

**Tipos de Rules:**

* `Always On` - Rules que siempre se incluyen
* `Model Decision` - Rules cuyas descripciones se mostraron al modelo para su aplicación condicional
* `Manual` - Rules mencionadas explícitamente con @ en la entrada del usuario
* `Global` - Rules globales de `global_rules.md`
* `Glob` - Rules activadas por accesos a archivos que coinciden con patrones glob

<Note>
  Esto indica qué Rules se *presentaron* al modelo o se *activaron* por acceso a archivos, pero no si el modelo realmente *siguió* una Rule. Las Rules que ya se mostraron recientemente en la conversación se deduplican y es posible que no vuelvan a aparecer hasta más adelante.
</Note>

<div id="running-code-formatters-after-edits">
  ### Ejecutar formateadores de código tras las ediciones
</div>

Formatea automáticamente los archivos de código después de que Cascade los modifique.

**Configuración**:

```json theme={null}
{
  "hooks": {
    "post_write_code": [
      {
        "command": "bash /Users/yourname/hooks/format_code.sh",
        "show_output": false
      }
    ]
  }
}
```

**Script** (`format_code.sh`):

```bash theme={null}
#!/bin/bash

# Leer JSON desde stdin
input=$(cat)

# Extraer la ruta del archivo usando jq
file_path=$(echo "$input" | jq -r '.tool_info.file_path')

# Formatear según la extensión del archivo
if [[ "$file_path" == *.py ]]; then
    black "$file_path" 2>&1
    echo "Formatted Python file: $file_path"
elif [[ "$file_path" == *.js ]] || [[ "$file_path" == *.ts ]]; then
    prettier --write "$file_path" 2>&1
    echo "Formatted JS/TS file: $file_path"
elif [[ "$file_path" == *.go ]]; then
    gofmt -w "$file_path" 2>&1
    echo "Formatted Go file: $file_path"
fi

exit 0
```

Este hook ejecuta automáticamente el formateador adecuado en función del tipo de archivo después de cada edición.

<div id="setting-up-worktrees">
  ### Configuración de worktrees
</div>

Copia los archivos de Environment e instala las dependencias cuando se cree un nuevo worktree.

**Configuración** (en `.windsurf/hooks.json`):

```json theme={null}
{
  "hooks": {
    "post_setup_worktree": [
      {
        "command": "bash $ROOT_WORKSPACE_PATH/hooks/setup_worktree.sh",
        "show_output": true
      }
    ]
  }
}
```

**Script** (`hooks/setup_worktree.sh`):

```bash theme={null}
#!/bin/bash

# Copiar archivos de environment del workspace original
if [ -f "$ROOT_WORKSPACE_PATH/.env" ]; then
    cp "$ROOT_WORKSPACE_PATH/.env" .env
    echo "Copied .env file"
fi

if [ -f "$ROOT_WORKSPACE_PATH/.env.local" ]; then
    cp "$ROOT_WORKSPACE_PATH/.env.local" .env.local
    echo "Copied .env.local file"
fi

# Instalar dependencies
if [ -f "package.json" ]; then
    npm install
    echo "Installed npm dependencies"
fi

exit 0
```

Este hook garantiza que cada worktree tenga la Configuración de Environment necesaria y que las dependencias se instalen automáticamente.

<div id="best-practices">
  ## Buenas prácticas
</div>

<div id="security">
  ### Seguridad
</div>

<Warning>
  **Usa Cascade Hooks por tu cuenta y riesgo**: Los hooks ejecutan comandos de shell automáticamente con todos los permisos de tu cuenta de usuario. Eres totalmente responsable del código que configures. Los hooks mal diseñados o maliciosos pueden modificar archivos, eliminar datos, exponer credenciales o comprometer tu sistema.
</Warning>

* **Valida todas las entradas**: Nunca confíes en el JSON de entrada sin validarlo, especialmente en rutas de archivos y comandos.
* **Usa rutas absolutas**: Usa siempre rutas absolutas en la configuración de tus hooks para evitar ambigüedades.
* **Protege los datos sensibles**: Evita registrar información sensible, como claves de API o credenciales.
* **Revisa los permisos**: Asegúrate de que los scripts de tus hooks tengan los permisos adecuados en el sistema de archivos.
* **Audita antes del despliegue**: Revisa cada comando y script de hook antes de agregarlo a tu configuración.
* **Prueba de forma aislada**: Ejecuta los hooks en un entorno de prueba antes de habilitarlos en tu equipo principal de desarrollo.

<div id="performance-considerations">
  ### Consideraciones de rendimiento
</div>

* **Mantén los hooks rápidos**: Los hooks lentos afectarán la capacidad de respuesta de Cascade. Procura que los tiempos de ejecución sean inferiores a 100 ms.
* **Usa operaciones asíncronas**: Para hooks no bloqueantes, considera registrar la información en una cola o base de datos de forma asíncrona.
* **Filtra desde el principio**: Comprueba el tipo de acción al inicio de tu script para evitar procesamiento innecesario.

<div id="error-handling">
  ### Manejo de errores
</div>

* **Valida siempre el JSON**: Usa bloques `try-catch` para gestionar correctamente las entradas malformadas.
* **Registra los errores correctamente**: Escribe los errores en `stderr` para que sean visibles cuando `show_output` esté habilitado.
* **Falla de forma segura**: Si tu hook encuentra un error, considera si debe bloquear la acción o permitir que continúe.

<div id="testing-your-hooks">
  ### Cómo probar tus Hooks
</div>

1. **Empieza con el registro**: Comienza implementando un hook de registro simple para comprender el flujo de datos.
2. **Usa `show_output: true`**: Habilita la salida durante el desarrollo para ver qué hacen tus hooks.
3. **Prueba el comportamiento de bloqueo**: Verifica que el código de salida 2 bloquee correctamente las acciones en los pre-hooks.
4. **Comprueba todos los caminos de ejecución**: Prueba tanto los escenarios de éxito como los de error en tus scripts.

<div id="enterprise-distribution">
  ## Distribución empresarial
</div>

Las organizaciones Enterprise necesitan aplicar políticas de seguridad, requisitos de cumplimiento y estándares de desarrollo que los usuarios individuales no pueden eludir. Cascade Hooks admite dos métodos de distribución empresarial:

1. **Panel en la nube** - Configura los hooks desde Team Settings en el panel de Devin Desktop
2. **Archivos del sistema** - Implementa hooks mediante MDM o herramientas de gestión de configuración

Ambos métodos pueden usarse juntos: los hooks de todas las fuentes se combinan y se ejecutan en orden.

<div id="cloud-dashboard-configuration">
  ### Configuración del panel en la nube
</div>

Los Admin del equipo pueden configurar Cascade Hooks directamente desde el dashboard de Devin Desktop.

**Requisitos:**

* plan Enterprise
* permiso `TEAM_SETTINGS_UPDATE`

**Para configurar:**

1. Ve a **Team Settings** en el dashboard de Devin Desktop
2. Busca la sección **Cascade Hooks**
3. Introduce la configuración de los hooks en formato JSON
4. Guarda tus cambios

Los hooks configurados a través del dashboard se distribuyen automáticamente a todos los miembros del equipo y se cargan al iniciar Devin Desktop. Los hooks configurados en la nube se cargan primero, seguidos de los hooks de nivel de sistema, de nivel de usuario y de nivel de espacio de trabajo.

<Note>
  Cuando se combinan varias configuraciones de equipo, los hooks se combinan por acción en lugar de sobrescribirse. Esto significa que los hooks de todas las configuraciones de equipo aplicables se ejecutarán en conjunto.
</Note>

<div id="system-level-file-deployment">
  ### Despliegue de archivos en el sistema
</div>

Para las organizaciones que prefieren una configuración basada en archivos o necesitan que los hooks funcionen sin conexión, despliega tu configuración obligatoria de `hooks.json` en estas ubicaciones específicas del sistema operativo:

**macOS:**

```
/Library/Application Support/Windsurf/hooks.json
```

**Linux/WSL:**

```
/etc/windsurf/hooks.json
```

**Windows:**

```
C:\ProgramData\Windsurf\hooks.json
```

Coloca tus scripts de hook en el directorio del sistema correspondiente (p. ej., `/usr/local/share/windsurf-hooks/` en sistemas Unix).

Los hooks de nivel de sistema tienen prioridad sobre los hooks de usuario y del espacio de trabajo, y los usuarios finales no pueden deshabilitarlos sin permisos de root.

<div id="mdm-and-configuration-management">
  #### MDM y gestión de la configuración
</div>

Los equipos de TI empresariales pueden desplegar hooks a nivel de sistema con herramientas estándar:

**Gestión de dispositivos móviles (MDM)**

* **Jamf Pro** (macOS) - Despliegue mediante perfiles de configuración o scripts
* **Microsoft Intune** (Windows/macOS) - Usa scripts de PowerShell o implementaciones de políticas
* **Workspace ONE**, **Google Endpoint Management** y otras soluciones de MDM

**Gestión de la configuración**

* **Ansible**, **Puppet**, **Chef**, **SaltStack** - Usa tu automatización de infraestructura existente
* **Scripts de despliegue personalizados** - Scripts de shell, PowerShell o las herramientas que prefieras

<div id="verification-and-auditing">
  #### Verificación y auditoría
</div>

Después del despliegue, verifica que los hooks estén instalados correctamente:

```bash theme={null}
# Verificar que los hooks del sistema estén presentes
ls -la /etc/windsurf/hooks.json  # Linux
ls -la "/Library/Application Support/Windsurf/hooks.json"  # macOS

# Probar la ejecución del hook (debería verse la salida del hook en Cascade)
# Pedir a un desarrollador que ejecute la acción de Cascade correspondiente

# Verificar que los usuarios no puedan modificar los hooks del sistema
sudo chown root:root /etc/windsurf/hooks.json
sudo chmod 644 /etc/windsurf/hooks.json
```

<Note>
  **Importante**: Tu equipo de TI o de seguridad gestiona por completo los hooks a nivel de sistema. Devin Desktop no instala ni gestiona archivos en rutas del sistema. Asegúrate de que tus equipos internos se encarguen del despliegue, las actualizaciones y el cumplimiento de las políticas de tu organización.
</Note>

<div id="workspace-hooks-for-team-projects">
  ### Hooks del espacio de trabajo para proyectos de equipo
</div>

Para las convenciones específicas del proyecto, los equipos pueden usar hooks de espacio de trabajo en el control de versiones:

```bash theme={null}
# Agregar a tu repositorio
.windsurf/
├── hooks.json
└── scripts/
    └── format-check.py

# Confirmar en git
git add .windsurf/
git commit -m "Add workspace hooks for code formatting"
```

Esto permite a los equipos estandarizar las prácticas de desarrollo. Mantenga las políticas de seguridad críticas a nivel de la nube o del sistema, y evite incluir información sensible en el control de versiones.

<div id="additional-resources">
  ## Recursos adicionales
</div>

* **Integración de MCP**: Obtén más información sobre [Model Context Protocol en Devin Desktop](/es/desktop/cascade/mcp)
* **Flujos de trabajo**: Descubre cómo combinar hooks con [los flujos de trabajo de Cascade](/es/desktop/cascade/workflows)
* **Análisis**: Supervisa el uso de Cascade con [Análisis del equipo](/es/desktop/accounts/analytics)
