メインコンテンツへスキップ

Documentation Index

Fetch the complete documentation index at: https://docs.devinenterprise.com/llms.txt

Use this file to discover all available pages before exploring further.

Cascade フックを利用すると、Cascade のワークフローの重要なポイントでカスタム シェルコマンドを実行できます。この強力な拡張機能により、操作をログに記録したり、ガードレールを適用したり、検証チェックを実行したり、外部システムと連携したりできます。
フックは、Cascade の動作をきめ細かく制御する必要がある上級ユーザーや Enterprise チーム向けに設計されています。基本的なシェルスクリプトの知識が必要です。

構築できるもの

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

フックの仕組み

フックは、特定の Cascade アクションが発生した際に自動的に実行されるシェルコマンドです。各フックは次のように動作します。
  1. 前提情報を受け取る (実行されるアクションの詳細が、JSON として標準入力経由で渡されます)
  2. スクリプトを実行する - Python、Bash、Node.js、または任意の実行可能ファイル
  3. 結果を返す (終了コードと出力ストリームを通じて返します)
pre-hooks (アクションの実行前に動作するフック) の場合、スクリプトは終了コード 2 で終了することでアクションをブロックできます。そのため、pre-hooks はセキュリティポリシーや検証チェックの実装に適しています。

設定

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

システムレベル

システムレベルのフックは、共有の開発マシンで組織全体のポリシーを適用するのに最適です。たとえば、セキュリティポリシー、コンプライアンス要件、必須のコードレビューワークフローの適用に利用できます。Enterpriseチームは、ローカルファイルを管理しなくても、クラウドダッシュボードからフックを設定することもできます。
  • macOS: /Library/Application Support/Windsurf/hooks.json
  • Linux/WSL: /etc/windsurf/hooks.json
  • Windows: C:\ProgramData\Windsurf\hooks.json

ユーザーレベル

ユーザーレベルのフックは、個人の好みや任意のワークフローに最適です。
  • Devin Desktop IDE: ~/.codeium/windsurf/hooks.json
  • JetBrains Plugin: ~/.codeium/hooks.json

ワークスペースレベル

ワークスペースレベルのフックを利用すると、チームはプロジェクト固有のポリシーをコードとあわせてバージョン管理できます。これには、カスタムの検証ルール、プロジェクト固有の統合、チーム固有のワークフローなどを含めることができます。
  • 場所: ワークスペースルートの .windsurf/hooks.json
3 つの場所にあるフックはすべてマージされます。同じフックイベントが複数の場所で設定されている場合、すべてのフックが system → user → workspace の順に実行されます。

基本構造

フック設定の基本構造の例は次のとおりです。
{
  "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 が使用されます。

設定オプション

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

クロスプラットフォームでの動作

command フィールドと powershell フィールドを使用すると、1 つの設定内でプラットフォームごとに適切なコマンドを定義できます。これは、macOS/Linux と Windows が混在する環境を運用するチームで役立ちます。
Platformcommand setpowershell setResult
macOS/Linux(ignored)bash -c 経由で command を実行
macOS/Linuxフックは何も通知されずにスキップされます
Windowspowershell -Command 経由で command にフォールバック
Windowspowershell -Command 経由で powershell を実行
Windowspowershell -Command 経由で powershell を実行
Anyバリデーションエラー
working_directory パラメータについて:
  • 複数の repo があるワークスペースでは、デフォルトは現在作業中の repo のルートです
  • 相対パスはデフォルトの場所 (ワークスペース または repo ルート) を基準に解決されます
  • 絶対パスをサポートしています
  • ~ による home directory の展開はサポートされていません

フックイベント

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

共通の入力構造

すべてのフックは、次の共通フィールドを含む JSON オブジェクトを受け取ります。
FieldTypeDescription
agent_action_namestringフックイベント名 (例: “pre_read_code”, “post_write_code”)
trajectory_idstringCascade 会話全体の一意の識別子
execution_idstring1 回のエージェントターンに対する一意の識別子
timestampstringフックがトリガーされた時点の ISO 8601 タイムスタンプ
model_namestringこのフック呼び出しに関連付けられたモデルの表示名 (例: “Claude Sonnet 4”, “GPT 4.1”) 。これは Cascade のモデルセレクターに表示されるラベルと同じです。Devin Desktop によるモデル表示名の更新に伴い、この値は時間の経過とともに変わる場合があります。モデルを特定できない場合は “Unknown” に設定されます。
tool_infoobjectイベント固有の情報 (フックの種類によって異なります)
以下の使用例では、簡略化のため共通フィールドを省略しています。フックイベントには主に 12 種類あります。

pre_read_code

Cascade がコードファイルを読み取るにトリガーされます。フックが終了コード 2 で終了した場合、この操作はブロックされることがあります。 利用例: ファイルアクセスの制限、読み取り操作の記録、権限の確認 入力 JSON:
{
  "agent_action_name": "pre_read_code",
  "tool_info": {
    "file_path": "/Users/yourname/project/file.py"
  }
}
Cascade がディレクトリを再帰的に読み込む場合、この file_path はディレクトリパスになることがあります。

post_read_code

Cascade がコードファイルを正常に読み取ったにトリガーされます。 利用例: 正常に読み取れたことをログに記録する、ファイルアクセスパターンを追跡する 入力 JSON:
{
  "agent_action_name": "post_read_code",
  "tool_info": {
    "file_path": "/Users/yourname/project/file.py"
  }
}
Cascade がディレクトリを再帰的に読み込む場合、この file_path はディレクトリパスになることがあります。

pre_write_code

Cascadeがコードファイルを書き込む、または変更する前にトリガーされます。フックがコード2で終了すると、アクションがブロックされる場合があります。 使用例: 保護されたファイルへの変更を防ぐ、変更前にファイルをバックアップする 入力JSON:
{
  "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"
      }
    ]
  }
}

post_write_code

Cascade がコードファイルを書き込み、または変更したにトリガーされます。 ユースケース: リンター、フォーマッター、またはテストを実行する; コード変更を記録する 入力 JSON:
{
  "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"
      }
    ]
  }
}

pre_run_command

Cascade がターミナルコマンドを実行するにトリガーされます。フックが終了コード 2 で終了すると、処理がブロックされることがあります。 ユースケース: 危険なコマンドをブロックする、すべてのコマンド実行を記録する、安全チェックを追加する 入力 JSON:
{
  "agent_action_name": "pre_run_command",
  "tool_info": {
    "command_line": "npm install package-name",
    "cwd": "/Users/yourname/project"
  }
}

post_run_command

Cascade がターミナルコマンドを実行したにトリガーされます。 ユースケース: コマンドの実行結果を記録する、後続の処理をトリガーする 入力 JSON:
{
  "agent_action_name": "post_run_command",
  "tool_info": {
    "command_line": "npm install package-name",
    "cwd": "/Users/yourname/project"
  }
}

pre_mcp_tool_use

Cascade が MCP (Model Context Protocol) ツールを呼び出すにトリガーされます。フックがコード 2 で終了すると、このアクションはブロックされることがあります。 ユースケース: MCP の利用状況を記録する、利用可能な MCP ツールを制限する 入力 JSON:
{
  "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"
  }
}

post_mcp_tool_use

Cascade が MCP ツールの呼び出しに成功したにトリガーされます。 ユースケース: MCP の操作を記録する、API の使用量を追跡する、MCP の結果を確認する 入力 JSON:
{
  "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"
  }
}

pre_user_prompt

ユーザーのプロンプトのテキストを Cascade が処理する前にトリガーされます。フック がコード 2 で終了した場合、このアクションがブロックされることがあります。 利用例: 監査のためにすべてのユーザープロンプトを記録する、潜在的に有害なプロンプトやポリシー違反のプロンプトをブロックする 入力 JSON:
{
  "agent_action_name": "pre_user_prompt",
  "tool_info": {
    "user_prompt": "can you run the echo hello command"
  }
}
show_output 設定オプションは、このフックでは適用されません。

post_cascade_response

ユーザーのプロンプトに対する Cascade の応答が完了したに、非同期でトリガーされます。このフックは、最後のユーザー入力以降における Cascade の完全な応答を受け取ります。 使用例: 監査のためにすべての Cascade の応答を記録する、応答パターンを分析する、コンプライアンスレビューのために応答を外部システムに送信する 入力 JSON:
{
  "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 が実行したその他のステップが含まれます。また、どのルールがトリガーされたかに関する情報も含まれます。ルールの使用状況を解析する方法については、トリガーされたルールの追跡の例を参照してください。 show_output 設定オプションは、このフックには適用されません。
response の内容はトラジェクトリデータに由来しており、コードベースや会話に含まれる機密情報が含まれる可能性があります。このデータは、組織のセキュリティおよびプライバシーに関するポリシーに従って取り扱ってください。

post_cascade_response_with_transcript

Cascade がユーザーのプロンプトへの応答を完了したに、post_cascade_response と同様に非同期でトリガーされます。インラインで markdown の要約を提供する代わりに、このフック は会話全体の transcript (会話の先頭から) をローカルの JSONL ファイルに書き出し、そのファイルパスを提供します。 利用例: Enterprise の監査およびコンプライアンスのログ記録、AI が生成した変更の追跡、transcript を外部の可観測性ツールや analytics ツールに渡すこと 入力 JSON:
{
  "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 ファイルを指します。各行は会話の1つのステップを表す JSON オブジェクトで、type フィールドと status フィールドに加えて、ステップ固有のデータを含みます。たとえば、
{"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"}
トランスクリプトには、ファイルの内容、コマンドの出力、ツールの引数、検索結果、適用されたルールなど、顧客に帰属する詳細なデータが含まれます。なお、各ステップの正確な構造は今後のバージョンで変更される可能性があるため、フックを利用する側は変更に強い実装にしてください。 トランスクリプトファイルは、0600 パーミッションで書き込まれます。Devin Desktop はトランスクリプトディレクトリ内のファイル数を自動的に 100 件までに制限し、更新時刻が最も古いものから削除します。 show_output 設定オプションは、このフックには適用されません。 この表は、post_cascade_response フックと post_cascade_response_with_transcript フックの主な違いを示しています。
post_cascade_responsepost_cascade_response_with_transcript
データ範囲最後のユーザー入力以降のステップのみ会話の最初から最後まで全体
形式tool_info.response 内の Markdown 形式の要約tool_info.transcript_path にある構造化された JSONL ファイル
詳細度簡潔で人が読める要約詳細で機械可読なデータ (ファイル内容、コマンド出力など)
提供方法stdin JSON でインライン提供ディスク上のファイル (~/.windsurf/transcripts/)
トランスクリプトファイルには、ファイル内容、コマンド出力、会話履歴など、コードベース内の機密情報が含まれます。これらのファイルは、組織のセキュリティポリシーおよびプライバシーポリシーに従って取り扱ってください。

post_setup_worktree

新しい git worktree が作成・設定されたにトリガーされます。このフックは、新しい worktree ディレクトリ内で実行されます。 ユースケース: .env ファイルやその他の未追跡ファイルを worktree にコピーする、依存関係をインストールする、セットアップスクリプトを実行する 環境変数:
変数説明
$ROOT_WORKSPACE_PATH元のワークスペースの絶対パスです。これを利用すると、元のリポジトリを基準にファイルにアクセスしたり、コマンドを実行したりできます。
入力 JSON:
{
  "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"
  }
}

終了コード

フックスクリプトは、終了コードを通じて結果を通知します。
Exit CodeMeaningEffect
0成功アクションは通常どおり続行されます
2ブロックエラーCascade エージェントには stderr のエラーメッセージが表示されます。pre-hook の場合、このコードによってアクションがブロックされます。
Any otherエラーアクションは通常どおり続行されます
終了コード 2 を使ってアクションをブロックできるのは、pre-hooks (pre_user_prompt, pre_read_code, pre_write_code, pre_run_command, pre_mcp_tool_use) のみです。post-hooks は、アクションがすでに発生した後に実行されるため、ブロックできません。
show_output が true の場合、フックが生成した標準出力と標準エラーは、ユーザーが Cascade UI で確認できる点に留意してください。

ユースケース例

Cascade のすべてのアクションを記録する

監査のために、Cascade が実行するすべてのアクションを追跡します。 設定:
{
  "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):
#!/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アクションの監査証跡を作成します。必要に応じて、入力データを変換したり、独自のロジックを実行したりできます。

ファイルアクセスの制限

Cascade が特定のディレクトリ外にあるファイルを読み取らないようにします。 設定:
{
  "hooks": {
    "pre_read_code": [
      {
        "command": "python3 /Users/yourname/hooks/block_read_access.py",
        "show_output": true
      }
    ]
  }
}
スクリプト (block_read_access.py):
#!/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 が許可されたディレクトリ外のファイルを読み取ろうとすると、このフックはその操作をブロックし、エラーメッセージを表示します。

危険なコマンドをブロックする

Cascade が有害な可能性のあるコマンドを実行しないようにします。 設定:
{
  "hooks": {
    "pre_run_command": [
      {
        "command": "python3 /Users/yourname/hooks/block_dangerous_commands.py",
        "show_output": true
      }
    ]
  }
}
スクリプト (block_dangerous_commands.py):
#!/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()
このフックはコマンドを検査し、危険なパターンが見つかった場合は実行前にブロックします。

組織のポリシーに違反するプロンプトをブロックする

ユーザーが組織のポリシーに違反するプロンプトを送信しないようにします。 設定:
{
  "hooks": {
    "pre_user_prompt": [
      {
        "command": "python3 /Users/yourname/hooks/block_bad_prompts.py"
      }
    ]
  }
}
スクリプト (block_bad_prompts.py):
#!/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 にエラーメッセージが表示されます。

Cascade 応答のログ記録

コンプライアンス監査や分析のため、すべての Cascade 応答をログに記録します。 設定:
{
  "hooks": {
    "post_cascade_response": [
      {
        "command": "python3 /Users/yourname/hooks/log_cascade_response.py"
      }
    ]
  }
}
スクリプト (log_cascade_response.py):
#!/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 生成コンテンツ全体の監査証跡を残します。これを拡張して、外部のロギングシステム、データベース、コンプライアンスプラットフォームにデータを送信することもできます。

トリガーされたルールの追跡

可観測性の確保とメトリクス収集のため、Cascade とのやり取り中に適用されたルールを追跡します。 設定:
{
  "hooks": {
    "post_cascade_response": [
      {
        "command": "python3 /Users/yourname/hooks/track_rules.py"
      }
    ]
  }
}
スクリプト (track_rules.py):
#!/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 パターンにマッチするファイルへのアクセスによってトリガーされるルール
これは、どのルールがモデルに 提示された か、またはファイルへのアクセスによって トリガーされた かを追跡するものであり、モデルが実際にそのルールに 従った かどうかを示すものではありません。会話内ですでに最近表示されたルールは重複排除されるため、しばらく再表示されない場合があります。

編集後にコードフォーマッターを実行する

Cascade による変更後、コードファイルを自動的に整形します。 設定:
{
  "hooks": {
    "post_write_code": [
      {
        "command": "bash /Users/yourname/hooks/format_code.sh",
        "show_output": false
      }
    ]
  }
}
スクリプト (format_code.sh):
#!/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
このフックは、編集のたびにファイル形式に応じた適切なフォーマッターを自動的に実行します。

Worktree のセットアップ

新しいワークツリーが作成されたときに、環境ファイルをコピーして依存関係をインストールします。 設定 (.windsurf/hooks.json 内) :
{
  "hooks": {
    "post_setup_worktree": [
      {
        "command": "bash $ROOT_WORKSPACE_PATH/hooks/setup_worktree.sh",
        "show_output": true
      }
    ]
  }
}
スクリプト (hooks/setup_worktree.sh):
#!/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
このフックにより、各ワークツリーで必要な環境設定が行われ、依存関係が自動的にインストールされます。

ベストプラクティス

セキュリティ

Cascade Hooks の利用は自己責任です: フックは、ユーザーアカウントに付与されたすべての権限でシェルコマンドを自動的に実行します。設定するコードについては、全面的にお客様の責任となります。設計が不十分なフックや悪意のあるフックは、ファイルの変更、データの削除、認証情報の漏えい、システムの侵害を招くおそれがあります。
  • すべての入力を検証する: 入力 JSON は、検証せずに決して信用しないでください。特にファイルパスやコマンドには注意が必要です。
  • 絶対パスを利用する: あいまいさを避けるため、フックの設定では常に絶対パスを利用してください。
  • 機密データを保護する: APIキーや認証情報などの機密情報をログに記録しないようにしてください。
  • 権限を確認する: フックスクリプトに適切なファイルシステム権限が設定されていることを確認してください。
  • デプロイ前に監査する: 設定に追加する前に、すべてのフックコマンドとスクリプトを確認してください。
  • 分離してテストする: メインの開発マシンで有効にする前に、テスト環境でフックを実行してください。

パフォーマンス上の注意点

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

エラー処理

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

フックのテスト

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

Enterpriseでの配布

Enterprise組織では、個々のユーザーが回避できないセキュリティポリシー、コンプライアンス要件、開発標準を適用する必要があります。Cascade Hooksは、Enterprise向けに2つの配布方法をサポートしています。
  1. Cloud Dashboard - Devin Desktopダッシュボードのチーム設定でフックを設定します
  2. System-Level Files - MDMまたは構成管理ツールを使ってフックを展開します
これらの方法は併用でき、すべてのソースのフックが統合されて順番に実行されます。

Cloud Dashboard の設定

チーム管理者は、Devin Desktop ダッシュボードから直接 Cascade Hooks を設定できます。 要件:
  • Enterprise プラン
  • TEAM_SETTINGS_UPDATE 権限
設定手順:
  1. Devin Desktop ダッシュボードのチーム設定に移動します
  2. Cascade Hooks セクションを探します
  3. フックの設定を JSON 形式で入力します
  4. 変更を保存します
ダッシュボードで設定したフックは、すべてのチームメンバーに自動的に配布され、Devin Desktop の起動時に読み込まれます。クラウドで設定されたフックが最初に読み込まれ、続いてシステムレベル、ユーザーレベル、ワークスペースレベルのフックが読み込まれます。
複数のチーム設定がマージされる場合、フックは上書きされず、アクションごとに結合されます。つまり、該当するすべてのチーム設定のフックがまとめて実行されます。

システムレベルでのファイル配置

ファイルベースの設定を利用したい組織や、フックをオフラインで動作させる必要がある組織向けに、必須の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 権限がないエンドユーザーは無効化できません。

MDM と構成管理

Enterprise IT チームは、標準的なツールを使用してシステムレベルのフックをデプロイできます。 モバイルデバイス管理 (MDM)
  • Jamf Pro (macOS) - 構成プロファイルまたはスクリプトを使ってデプロイ
  • Microsoft Intune (Windows/macOS) - PowerShell スクリプトまたはポリシー配布を利用
  • Workspace ONEGoogle Endpoint Management、その他の MDM ソリューション
構成管理
  • AnsiblePuppetChefSaltStack - 既存のインフラストラクチャ自動化を利用
  • カスタムデプロイスクリプト - シェルスクリプト、PowerShell、または使い慣れたツール

検証と監査

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

チームプロジェクト向けのワークスペースフック

プロジェクト固有の規約に対応するには、チームはバージョン管理でワークスペースレベルのフックを利用できます。
# リポジトリに追加する
.windsurf/
├── hooks.json
└── scripts/
    └── format-check.py

# git にコミットする
git add .windsurf/
git commit -m "Add workspace hooks for code formatting"
これにより、チーム全体で開発プラクティスを標準化できます。セキュリティ上重要なポリシーはクラウドまたはシステムレベルで管理し、機密情報はバージョン管理にチェックインしないでください。

追加リソース