> ## 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.

# Cascade フック

> Cascade のワークフローの要所でカスタム シェルコマンドを実行し、pre-hook と post-hook を使って、ログ記録、セキュリティ制御、検証、Enterprise ガバナンスを行えます。

Cascade フックを利用すると、Cascade のワークフローの重要なポイントでカスタム シェルコマンドを実行できます。この強力な拡張機能により、操作をログに記録したり、ガードレールを適用したり、検証チェックを実行したり、外部システムと連携したりできます。

<Note>
  フックは、Cascade の動作をきめ細かく制御する必要がある上級ユーザーや Enterprise チーム向けに設計されています。基本的なシェルスクリプトの知識が必要です。
</Note>

<div id="what-you-can-build">
  ## 構築できるもの
</div>

フックにより、幅広い自動化とガバナンス機能を実現できます。

* **ログ記録と分析**: コンプライアンスや使用量の分析のために、読み取られたすべてのファイル、コード変更、実行されたコマンド、ユーザープロンプト、または Cascade の応答を追跡する
* **セキュリティ制御**: Cascade が機密ファイルにアクセスしたり、危険なコマンドを実行したり、ポリシーに違反するプロンプトを処理したりすることをブロックする
* **品質保証**: コード変更後にリンター、フォーマッター、またはテストを自動的に実行する
* **カスタムワークフロー**: issue トラッカー、通知システム、またはデプロイパイプラインと連携する
* **チームの標準化**: 組織全体でコーディング規約とベストプラクティスを徹底する

<div id="how-hooks-work">
  ## フックの仕組み
</div>

フックは、特定の Cascade アクションが発生した際に自動的に実行されるシェルコマンドです。各フックは次のように動作します。

1. **前提情報を受け取る** (実行されるアクションの詳細が、JSON として標準入力経由で渡されます)
2. **スクリプトを実行する** - Python、Bash、Node.js、または任意の実行可能ファイル
3. **結果を返す** (終了コードと出力ストリームを通じて返します)

**pre-hooks** (アクションの実行前に動作するフック) の場合、スクリプトは終了コード `2` で終了することで**アクションをブロック**できます。そのため、pre-hooks はセキュリティポリシーや検証チェックの実装に適しています。

<div id="configuration">
  ## 設定
</div>

フックは、3 つの異なるレベルに配置できる JSON ファイルで設定します。Cascade はこれらすべての場所にあるフックを読み込んでマージするため、チームはフック設定を柔軟に配布・管理できます。

<div id="system-level">
  #### システムレベル
</div>

システムレベルのフックは、共有の開発マシンで組織全体のポリシーを適用するのに最適です。たとえば、セキュリティポリシー、コンプライアンス要件、必須のコードレビューワークフローの適用に利用できます。Enterpriseチームは、ローカルファイルを管理しなくても、[クラウドダッシュボード](#cloud-dashboard-configuration)からフックを設定することもできます。

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

<div id="user-level">
  #### ユーザーレベル
</div>

ユーザーレベルのフックは、個人の好みや任意のワークフローに最適です。

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

<div id="workspace-level">
  #### ワークスペースレベル
</div>

ワークスペースレベルのフックを利用すると、チームはプロジェクト固有のポリシーをコードとあわせてバージョン管理できます。これには、カスタムの検証ルール、プロジェクト固有の統合、チーム固有のワークフローなどを含めることができます。

* **場所**: ワークスペースルートの `.windsurf/hooks.json`

<Note>
  3 つの場所にあるフックはすべて**マージされます**。同じフックイベントが複数の場所で設定されている場合、すべてのフックが system → user → workspace の順に実行されます。
</Note>

<div id="basic-structure">
  ### 基本構造
</div>

フック設定の基本構造の例は次のとおりです。

```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
      }
    ]
  }
}
```

この例では、`pre_read_code` で macOS/Linux 用のコマンドと Windows PowerShell 用のコマンドの両方を指定しています。`post_write_code` フックでは `command` のみを指定しているため、macOS/Linux で実行され、Windows では PowerShell が使用されます。

<div id="configuration-options">
  ### 設定オプション
</div>

各フックでは、次のパラメータを指定できます。

| パラメータ               | 型       | 説明                                                                                                    |
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| `command`           | string  | **macOS/Linux** で実行するシェルコマンド (`bash -c` 経由で実行) 。`command` または `powershell` のいずれか一方は必ず指定する必要があります。     |
| `powershell`        | string  | 任意。**Windows** で実行するコマンド (`powershell -Command` 経由で実行) 。Windows で省略した場合は、`command` がフォールバックとして使用されます。 |
| `show_output`       | boolean | ユーザー向けの Cascade UI に、フックの stdout/stderr 出力を表示するかどうか。デバッグに役立ちます。                                       |
| `working_directory` | string  | 任意。コマンドを実行するディレクトリ。既定ではワークスペースルートが使用されます。                                                             |

<div id="cross-platform-behavior">
  #### クロスプラットフォームでの動作
</div>

`command` フィールドと `powershell` フィールドを使用すると、1 つの設定内でプラットフォームごとに適切なコマンドを定義できます。これは、macOS/Linux と Windows が混在する環境を運用するチームで役立ちます。

| Platform    | `command` set | `powershell` set | Result                                       |
| ----------- | :-----------: | :--------------: | -------------------------------------------- |
| macOS/Linux |       ✓       |     (ignored)    | `bash -c` 経由で `command` を実行                  |
| macOS/Linux |       ✗       |         ✓        | フックは何も通知されずにスキップされます                         |
| Windows     |       ✓       |         ✗        | `powershell -Command` 経由で `command` にフォールバック |
| Windows     |       ✗       |         ✓        | `powershell -Command` 経由で `powershell` を実行   |
| Windows     |       ✓       |         ✓        | `powershell -Command` 経由で `powershell` を実行   |
| Any         |       ✗       |         ✗        | バリデーションエラー                                   |

<Note>
  **`working_directory` パラメータについて:**

  * 複数の repo があるワークスペースでは、デフォルトは現在作業中の repo のルートです
  * 相対パスはデフォルトの場所 (ワークスペース または repo ルート) を基準に解決されます
  * 絶対パスをサポートしています
  * `~` による home directory の展開はサポートされていません
</Note>

<div id="hook-events">
  ## フックイベント
</div>

Cascade には、エージェントのワークフローにおける主要なアクションをカバーする 12 種類のフックイベントがあります。

<div id="common-input-structure">
  ### 共通の入力構造
</div>

すべてのフックは、次の共通フィールドを含む JSON オブジェクトを受け取ります。

| Field               | Type   | Description                                                                                                                                                                            |
| ------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_action_name` | string | フックイベント名 (例: "pre\_read\_code", "post\_write\_code")                                                                                                                                   |
| `trajectory_id`     | string | Cascade 会話全体の一意の識別子                                                                                                                                                                    |
| `execution_id`      | string | 1 回のエージェントターンに対する一意の識別子                                                                                                                                                                |
| `timestamp`         | string | フックがトリガーされた時点の ISO 8601 タイムスタンプ                                                                                                                                                        |
| `model_name`        | string | このフック呼び出しに関連付けられたモデルの表示名 (例: "Claude Sonnet 4", "GPT 4.1") 。これは Cascade のモデルセレクターに表示されるラベルと同じです。Devin Desktop によるモデル表示名の更新に伴い、この値は時間の経過とともに変わる場合があります。モデルを特定できない場合は "Unknown" に設定されます。 |
| `tool_info`         | object | イベント固有の情報 (フックの種類によって異なります)                                                                                                                                                            |

以下の使用例では、簡略化のため共通フィールドを省略しています。フックイベントには主に 12 種類あります。

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

Cascade がコードファイルを読み取る**前**にトリガーされます。フックが終了コード 2 で終了した場合、この操作はブロックされることがあります。

**利用例**: ファイルアクセスの制限、読み取り操作の記録、権限の確認

**入力 JSON**:

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

Cascade がディレクトリを再帰的に読み込む場合、この `file_path` はディレクトリパスになることがあります。

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

Cascade がコードファイルを正常に読み取った**後**にトリガーされます。

**利用例**: 正常に読み取れたことをログに記録する、ファイルアクセスパターンを追跡する

**入力 JSON**:

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

Cascade がディレクトリを再帰的に読み込む場合、この `file_path` はディレクトリパスになることがあります。

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

Cascadeがコードファイルを書き込む、または変更する**前に**トリガーされます。フックがコード2で終了すると、アクションがブロックされる場合があります。

**使用例**: 保護されたファイルへの変更を防ぐ、変更前にファイルをバックアップする

**入力JSON**:

```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>

Cascade がコードファイルを書き込み、または変更した**後**にトリガーされます。

**ユースケース**: リンター、フォーマッター、またはテストを実行する; コード変更を記録する

**入力 JSON**:

```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>

Cascade がターミナルコマンドを実行する**前**にトリガーされます。フックが終了コード 2 で終了すると、処理がブロックされることがあります。

**ユースケース**: 危険なコマンドをブロックする、すべてのコマンド実行を記録する、安全チェックを追加する

**入力 JSON**:

```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>

Cascade がターミナルコマンドを実行した**後**にトリガーされます。

**ユースケース**: コマンドの実行結果を記録する、後続の処理をトリガーする

**入力 JSON**:

```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>

Cascade が MCP (Model Context Protocol) ツールを呼び出す**前**にトリガーされます。フックがコード 2 で終了すると、このアクションはブロックされることがあります。

**ユースケース**: MCP の利用状況を記録する、利用可能な MCP ツールを制限する

**入力 JSON**:

```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>

Cascade が MCP ツールの呼び出しに成功した**後**にトリガーされます。

**ユースケース**: MCP の操作を記録する、API の使用量を追跡する、MCP の結果を確認する

**入力 JSON**:

```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>

ユーザーのプロンプトのテキストを Cascade が処理する**前に**トリガーされます。フック がコード 2 で終了した場合、このアクションがブロックされることがあります。

**利用例**: 監査のためにすべてのユーザープロンプトを記録する、潜在的に有害なプロンプトやポリシー違反のプロンプトをブロックする

**入力 JSON**:

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

`show_output` 設定オプションは、このフックでは適用されません。

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

ユーザーのプロンプトに対する Cascade の応答が完了した**後**に、非同期でトリガーされます。このフックは、最後のユーザー入力以降における Cascade の完全な応答を受け取ります。

**使用例**: 監査のためにすべての Cascade の応答を記録する、応答パターンを分析する、コンプライアンスレビューのために応答を外部システムに送信する

**入力 JSON**:

```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."
  }
}
```

`response` フィールドには、前回のユーザー入力以降における Cascade の応答内容が Markdown 形式で含まれます。これには、プランナーの応答、ツールのアクション (ファイルの読み取り、書き込み、コマンド実行) 、および Cascade が実行したその他のステップが含まれます。また、どの[ルール](/ja/desktop/cascade/memories)がトリガーされたかに関する情報も含まれます。ルールの使用状況を解析する方法については、[トリガーされたルールの追跡](#tracking-triggered-rules)の例を参照してください。

`show_output` 設定オプションは、このフックには適用されません。

<Warning>
  `response` の内容はトラジェクトリデータに由来しており、コードベースや会話に含まれる機密情報が含まれる可能性があります。このデータは、組織のセキュリティおよびプライバシーに関するポリシーに従って取り扱ってください。
</Warning>

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

Cascade がユーザーの`プロンプト`への応答を完了した**後**に、`post_cascade_response` と同様に非同期でトリガーされます。インラインで markdown の要約を提供する代わりに、このフック は会話全体の transcript (会話の先頭から) をローカルの JSONL ファイルに書き出し、そのファイルパスを提供します。

**利用例**: Enterprise の監査およびコンプライアンスのログ記録、AI が生成した変更の追跡、transcript を外部の可観測性ツールや analytics ツールに渡すこと

**入力 JSON**:

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

`transcript_path` は、`~/.windsurf/transcripts/{trajectory_id}.jsonl` にある [JSONL](https://jsonlines.org/) ファイルを指します。各行は会話の1つのステップを表す JSON オブジェクトで、`type` フィールドと `status` フィールドに加えて、ステップ固有のデータを含みます。たとえば、

```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"}
```

トランスクリプトには、ファイルの内容、コマンドの出力、ツールの引数、検索結果、適用された[ルール](/ja/desktop/cascade/memories)など、顧客に帰属する詳細なデータが含まれます。なお、各ステップの正確な構造は今後のバージョンで変更される可能性があるため、フックを利用する側は変更に強い実装にしてください。

トランスクリプトファイルは、`0600` パーミッションで書き込まれます。Devin Desktop はトランスクリプトディレクトリ内のファイル数を自動的に 100 件までに制限し、更新時刻が最も古いものから削除します。

`show_output` 設定オプションは、このフックには適用されません。

この表は、`post_cascade_response` フックと `post_cascade_response_with_transcript` フックの主な違いを示しています。

|           | `post_cascade_response`                | `post_cascade_response_with_transcript`          |
| --------- | -------------------------------------- | ------------------------------------------------ |
| **データ範囲** | 最後のユーザー入力以降のステップのみ                     | 会話の最初から最後まで全体                                    |
| **形式**    | `tool_info.response` 内の Markdown 形式の要約 | `tool_info.transcript_path` にある構造化された JSONL ファイル |
| **詳細度**   | 簡潔で人が読める要約                             | 詳細で機械可読なデータ (ファイル内容、コマンド出力など)                    |
| **提供方法**  | stdin JSON でインライン提供                    | ディスク上のファイル (`~/.windsurf/transcripts/`)          |

<Warning>
  トランスクリプトファイルには、ファイル内容、コマンド出力、会話履歴など、コードベース内の機密情報が含まれます。これらのファイルは、組織のセキュリティポリシーおよびプライバシーポリシーに従って取り扱ってください。
</Warning>

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

新しい [git worktree](./worktrees) が作成・設定された**後**にトリガーされます。このフックは、新しい **worktree** ディレクトリ内で実行されます。

**ユースケース**: `.env` ファイルやその他の未追跡ファイルを worktree にコピーする、依存関係をインストールする、セットアップスクリプトを実行する

**環境変数**:

| 変数                     | 説明                                                                |
| ---------------------- | ----------------------------------------------------------------- |
| `$ROOT_WORKSPACE_PATH` | 元のワークスペースの絶対パスです。これを利用すると、元のリポジトリを基準にファイルにアクセスしたり、コマンドを実行したりできます。 |

**入力 JSON**:

```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">
  ## 終了コード
</div>

フックスクリプトは、終了コードを通じて結果を通知します。

| Exit Code | Meaning | Effect                                                                             |
| --------- | ------- | ---------------------------------------------------------------------------------- |
| `0`       | 成功      | アクションは通常どおり続行されます                                                                  |
| `2`       | ブロックエラー | Cascade エージェントには stderr のエラーメッセージが表示されます。pre-hook の場合、このコードによってアクションが**ブロック**されます。 |
| Any other | エラー     | アクションは通常どおり続行されます                                                                  |

<Warning>
  終了コード `2` を使ってアクションをブロックできるのは、**pre-hooks** (`pre_user_prompt`, `pre_read_code`, `pre_write_code`, `pre_run_command`, `pre_mcp_tool_use`) のみです。post-hooks は、アクションがすでに発生した後に実行されるため、ブロックできません。
</Warning>

`show_output` が true の場合、フックが生成した標準出力と標準エラーは、ユーザーが Cascade UI で確認できる点に留意してください。

<div id="example-use-cases">
  ## ユースケース例
</div>

<div id="logging-all-cascade-actions">
  ### Cascade のすべてのアクションを記録する
</div>

監査のために、Cascade が実行するすべてのアクションを追跡します。

**設定**:

```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"
      }
    ]
  }
}
```

**スクリプト** (`log_input.py`):

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

import sys
import json

def main():
    # stdinからJSONデータを読み込む
    input_data = sys.stdin.read()
    
    # JSONを解析する
    try:
        data = json.loads(input_data)
        
        # フォーマット済みJSONをファイルに書き込む
        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()
```

このスクリプトは、フックが呼び出されるたびにその記録をログファイルに追記し、すべてのCascadeアクションの監査証跡を作成します。必要に応じて、入力データを変換したり、独自のロジックを実行したりできます。

<div id="restricting-file-access">
  ### ファイルアクセスの制限
</div>

Cascade が特定のディレクトリ外にあるファイルを読み取らないようにします。

**設定**:

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

**スクリプト** (`block_read_access.py`):

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

import sys
import json

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

def main():
    # stdinからJSONデータを読み込む
    input_data = sys.stdin.read()

    # 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)  # 終了コード2でアクションをブロックする
            
            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()
```

Cascade が許可されたディレクトリ外のファイルを読み取ろうとすると、このフックはその操作をブロックし、エラーメッセージを表示します。

<div id="blocking-dangerous-commands">
  ### 危険なコマンドをブロックする
</div>

Cascade が有害な可能性のあるコマンドを実行しないようにします。

**設定**:

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

**スクリプト** (`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():
    # stdinからJSONデータを読み込む
    input_data = sys.stdin.read()

    # 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)  # 終了コード2でコマンドをブロックする
            
            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()
```

このフックはコマンドを検査し、危険なパターンが見つかった場合は実行前にブロックします。

<div id="blocking-policy-violating-prompts">
  ### 組織のポリシーに違反するプロンプトをブロックする
</div>

ユーザーが組織のポリシーに違反するプロンプトを送信しないようにします。

**設定**:

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

**スクリプト** (`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():
    # stdinからJSONデータを読み込む
    input_data = sys.stdin.read()

    # 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)  # 終了コード2でプロンプトをブロックする

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

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

このフックは、ユーザーのプロンプトが処理される前に内容を確認し、禁止されたパターンを含むものをブロックします。プロンプトがブロックされると、ユーザーには Cascade UI にエラーメッセージが表示されます。

<div id="logging-cascade-responses">
  ### Cascade 応答のログ記録
</div>

コンプライアンス監査や分析のため、すべての Cascade 応答をログに記録します。

**設定**:

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

**スクリプト** (`log_cascade_response.py`):

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

import sys
import json
from datetime import datetime

def main():
    # stdinからJSONデータを読み込む
    input_data = sys.stdin.read()

    # 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())

            # ファイルに記録する
            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()
```

このフックは、Cascade のすべての応答をファイルに記録し、AI 生成コンテンツ全体の監査証跡を残します。これを拡張して、外部のロギングシステム、データベース、コンプライアンスプラットフォームにデータを送信することもできます。

<div id="tracking-triggered-rules">
  ### トリガーされたルールの追跡
</div>

可観測性の確保とメトリクス収集のため、Cascade とのやり取り中に適用された[ルール](/ja/desktop/cascade/memories)を追跡します。

**設定**:

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

**スクリプト** (`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:
    """
    Cascadeレスポンスからトリガーされたルールを解析する。
    ルールの形式: - (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())

            # ファイルに記録する
            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()
```

**ルールの種類:**

* `Always On` - 常に含まれるルール
* `Model Decision` - 条件付きで適用するために、説明がモデルに提示されたルール
* `Manual` - ユーザー入力で明示的に @メンションされたルール
* `Global` - `global_rules.md` にあるグローバルルール
* `Glob` - glob パターンにマッチするファイルへのアクセスによってトリガーされるルール

<Note>
  これは、どのルールがモデルに *提示された* か、またはファイルへのアクセスによって *トリガーされた* かを追跡するものであり、モデルが実際にそのルールに *従った* かどうかを示すものではありません。会話内ですでに最近表示されたルールは重複排除されるため、しばらく再表示されない場合があります。
</Note>

<div id="running-code-formatters-after-edits">
  ### 編集後にコードフォーマッターを実行する
</div>

Cascade による変更後、コードファイルを自動的に整形します。

**設定**:

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

**スクリプト** (`format_code.sh`):

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

# stdinからJSONを読み込む
input=$(cat)

# jqを使ってファイルパスを抽出する
file_path=$(echo "$input" | jq -r '.tool_info.file_path')

# ファイル拡張子に応じてフォーマットする
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
```

このフックは、編集のたびにファイル形式に応じた適切なフォーマッターを自動的に実行します。

<div id="setting-up-worktrees">
  ### Worktree のセットアップ
</div>

新しいワークツリーが作成されたときに、環境ファイルをコピーして依存関係をインストールします。

**設定** (`.windsurf/hooks.json` 内) :

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

**スクリプト** (`hooks/setup_worktree.sh`):

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

# 元のworkspaceからenvironmentファイルをコピーする
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

# dependenciesをインストールする
if [ -f "package.json" ]; then
    npm install
    echo "Installed npm dependencies"
fi

exit 0
```

このフックにより、各ワークツリーで必要な環境設定が行われ、依存関係が自動的にインストールされます。

<div id="best-practices">
  ## ベストプラクティス
</div>

<div id="security">
  ### セキュリティ
</div>

<Warning>
  **Cascade Hooks の利用は自己責任です**: フックは、ユーザーアカウントに付与されたすべての権限でシェルコマンドを自動的に実行します。設定するコードについては、全面的にお客様の責任となります。設計が不十分なフックや悪意のあるフックは、ファイルの変更、データの削除、認証情報の漏えい、システムの侵害を招くおそれがあります。
</Warning>

* **すべての入力を検証する**: 入力 JSON は、検証せずに決して信用しないでください。特にファイルパスやコマンドには注意が必要です。
* **絶対パスを利用する**: あいまいさを避けるため、フックの設定では常に絶対パスを利用してください。
* **機密データを保護する**: APIキーや認証情報などの機密情報をログに記録しないようにしてください。
* **権限を確認する**: フックスクリプトに適切なファイルシステム権限が設定されていることを確認してください。
* **デプロイ前に監査する**: 設定に追加する前に、すべてのフックコマンドとスクリプトを確認してください。
* **分離してテストする**: メインの開発マシンで有効にする前に、テスト環境でフックを実行してください。

<div id="performance-considerations">
  ### パフォーマンス上の注意点
</div>

* **フックは高速に保つ**: フックが遅いと、Cascade の応答性に影響します。実行時間は 100ms 未満を目指してください。
* **非同期処理を利用する**: ブロックしないフックでは、キューやデータベースへの記録を非同期で行うことを検討してください。
* **早めに絞り込む**: 不要な処理を避けるため、スクリプトの冒頭でアクションの種類を確認してください。

<div id="error-handling">
  ### エラー処理
</div>

* **常に JSON を検証する**: try-catch ブロックを利用して、不正な形式の入力も適切に処理します。
* **エラーを適切に記録する**: `show_output` が有効なときに表示されるよう、エラーは `stderr` に書き込みます。
* **安全に失敗させる**: フックでエラーが発生した場合は、その処理を中断すべきか、それとも続行を許可すべきかを検討します。

<div id="testing-your-hooks">
  ### フックのテスト
</div>

1. **まずはログ記録から始める**: データの流れを把握するために、まずはシンプルなログ記録用フックを実装します。
2. **`show_output: true` を利用する**: 開発中は出力を有効にして、フックが何をしているか確認します。
3. **ブロック動作をテストする**: 終了コード 2 で、pre-hook での処理が正しくブロックされることを確認します。
4. **すべてのコードパスを確認する**: スクリプトで成功時と失敗時の両方のケースをテストします。

<div id="enterprise-distribution">
  ## Enterpriseでの配布
</div>

Enterprise組織では、個々のユーザーが回避できないセキュリティポリシー、コンプライアンス要件、開発標準を適用する必要があります。Cascade Hooksは、Enterprise向けに2つの配布方法をサポートしています。

1. **Cloud Dashboard** - Devin Desktopダッシュボードのチーム設定でフックを設定します
2. **System-Level Files** - MDMまたは構成管理ツールを使ってフックを展開します

これらの方法は併用でき、すべてのソースのフックが統合されて順番に実行されます。

<div id="cloud-dashboard-configuration">
  ### Cloud Dashboard の設定
</div>

チーム管理者は、Devin Desktop ダッシュボードから直接 Cascade Hooks を設定できます。

**要件:**

* Enterprise プラン
* `TEAM_SETTINGS_UPDATE` 権限

**設定手順:**

1. Devin Desktop ダッシュボードの**チーム設定**に移動します
2. **Cascade Hooks** セクションを探します
3. フックの設定を JSON 形式で入力します
4. 変更を保存します

ダッシュボードで設定したフックは、すべてのチームメンバーに自動的に配布され、Devin Desktop の起動時に読み込まれます。クラウドで設定されたフックが最初に読み込まれ、続いてシステムレベル、ユーザーレベル、ワークスペースレベルのフックが読み込まれます。

<Note>
  複数のチーム設定がマージされる場合、フックは上書きされず、アクションごとに結合されます。つまり、該当するすべてのチーム設定のフックがまとめて実行されます。
</Note>

<div id="system-level-file-deployment">
  ### システムレベルでのファイル配置
</div>

ファイルベースの設定を利用したい組織や、フックをオフラインで動作させる必要がある組織向けに、必須の`hooks.json`設定をOSごとに以下の場所へ配置してください。

**macOS:**

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

**Linux/WSL：**

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

**Windows:**

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

対応するシステムディレクトリにフックスクリプトを配置してください (例: Unix システムでは `/usr/local/share/windsurf-hooks/`) 。

システムレベルのフックは、ユーザーおよびワークスペースのフックよりも優先され、root 権限がないエンドユーザーは無効化できません。

<div id="mdm-and-configuration-management">
  #### MDM と構成管理
</div>

Enterprise IT チームは、標準的なツールを使用してシステムレベルのフックをデプロイできます。

**モバイルデバイス管理 (MDM) **

* **Jamf Pro** (macOS) - 構成プロファイルまたはスクリプトを使ってデプロイ
* **Microsoft Intune** (Windows/macOS) - PowerShell スクリプトまたはポリシー配布を利用
* **Workspace ONE**、**Google Endpoint Management**、その他の MDM ソリューション

**構成管理**

* **Ansible**、**Puppet**、**Chef**、**SaltStack** - 既存のインフラストラクチャ自動化を利用
* **カスタムデプロイスクリプト** - シェルスクリプト、PowerShell、または使い慣れたツール

<div id="verification-and-auditing">
  #### 検証と監査
</div>

デプロイ後、フックが正しくインストールされていることを確認してください:

```bash theme={null}
# システムフックが存在することを確認する
ls -la /etc/windsurf/hooks.json  # Linux
ls -la "/Library/Application Support/Windsurf/hooks.json"  # macOS

# フックの実行をテストする（Cascadeにフックの出力が表示されるはず）
# 開発者に該当するCascadeアクションをトリガーさせる

# ユーザーがシステムフックを変更できないことを確認する
sudo chown root:root /etc/windsurf/hooks.json
sudo chmod 644 /etc/windsurf/hooks.json
```

<Note>
  **重要**: システムレベルのフックは、IT チームまたはセキュリティ チームが全面的に管理します。Devin Desktop がシステムレベルのパスにファイルをデプロイしたり管理したりすることはありません。組織のポリシーに従って、デプロイ、更新、コンプライアンス対応は社内チームで行ってください。
</Note>

<div id="workspace-hooks-for-team-projects">
  ### チームプロジェクト向けのワークスペースフック
</div>

プロジェクト固有の規約に対応するには、チームはバージョン管理でワークスペースレベルのフックを利用できます。

```bash theme={null}
# リポジトリに追加する
.windsurf/
├── hooks.json
└── scripts/
    └── format-check.py

# git にコミットする
git add .windsurf/
git commit -m "Add workspace hooks for code formatting"
```

これにより、チーム全体で開発プラクティスを標準化できます。セキュリティ上重要なポリシーはクラウドまたはシステムレベルで管理し、機密情報はバージョン管理にチェックインしないでください。

<div id="additional-resources">
  ## 追加リソース
</div>

* **MCP 統合**: [Devin Desktop の Model Context Protocol](/ja/desktop/cascade/mcp)の詳細をご覧ください
* **ワークフロー**: フックを [Cascade Workflows](/ja/desktop/cascade/workflows) と組み合わせる方法をご確認ください
* **Analytics**: [Team Analytics](/ja/desktop/accounts/analytics) で Cascade の使用量を追跡できます
