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

何が作れるか

Hooks は幅広い自動化とガバナンス機能を提供します:
  • Logging & Analytics: コンプライアンスと利用分析のために、Cascade によるすべてのファイル読み取り、コード変更、コマンド実行、ユーザーから Cascade へ送信されたプロンプト、および Cascade の応答を追跡
  • セキュリティコントロール: Cascade の機密ファイルへのアクセスや危険なコマンドの実行、ポリシー違反となるプロンプトの処理をブロック
  • 品質保証: コード変更後にリンター、フォーマッター、テストを自動実行
  • カスタムワークフロー: 課題トラッカー、通知システム、デプロイパイプラインと連携
  • チーム標準化: 組織全体でコーディング規約とベストプラクティスを遵守させる

Hooks の仕組み

Hooks は、特定の Cascade のアクションが発生した際に自動で実行されるシェルコマンドです。各 Hook は次の処理を行います:
  1. 標準入力で JSON を受け取り、実行中のアクションに関する詳細なコンテキストを取得
  2. Python、Bash、Node.js など、任意の実行可能ファイルでスクリプトを実行
  3. 終了コードと標準出力/標準エラーを通じて結果を返す
プレフック (アクション実行前に起動) では、スクリプトを終了コード 2 で終了させることでアクションをブロックできます。これにより、プレフックはセキュリティポリシーやバリデーションの実装に最適です。

設定

Hooks は JSON ファイルで設定でき、3 つの異なるレベルに配置できます。Cascade はすべての場所から Hooks を読み込んで統合し、チームが Hook 設定の配布と管理を柔軟に行えるようにします。

システムレベル

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

ユーザー レベル

ユーザー レベルのフックは、個人の嗜好や任意のワークフローに最適です。
  • Windsurf IDE: ~/.codeium/windsurf/hooks.json
  • JetBrains プラグイン: ~/.codeium/hooks.json

ワークスペースレベル

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

基本構成

以下は、hooks 設定の基本的な構成例です。
{
  "hooks": {
    "pre_read_code": [
      {
        "command": "python3 /path/to/your/script.py",
        "show_output": true
      }
    ],
    "post_write_code": [
      {
        "command": "python3 /path/to/another/script.py",
        "show_output": true
      }
    ]
  }
}

設定オプション

各フックは次のパラメータを受け付けます。
ParameterTypeDescription
commandstring実行するシェルコマンド。引数付きの有効な実行可能ファイルであれば任意のものを指定できます。
show_outputbooleanフックの stdout/stderr の出力をユーザー向けの Cascade の UI に表示するかどうか。デバッグに便利です。
working_directorystring省略可。コマンドを実行するディレクトリ。既定はワークスペースのルートです。
working_directory パラメータについて:
  • 複数リポジトリのワークスペースでは、既定値は現在作業中のリポジトリのルートです
  • 相対パスは既定の場所 (ワークスペースまたはリポジトリのルート) から解決されます
  • 絶対パスも使用できます
  • ~ によるホームディレクトリ展開はサポートされていません

フックイベント

Cascade は、エージェントのワークフローにおける主要なアクションを網羅する 12 つのフックイベントを提供します。

共通の入力構造

すべてのフックは、次の共通フィールドを含む JSON オブジェクトを受け取ります:
FieldTypeDescription
agent_action_namestringフックイベント名 (例:「pre_read_code」「post_write_code」)
trajectory_idstringCascade 全体の会話に対する一意の識別子
execution_idstring単一のエージェントのターンに対する一意の識別子
timestampstringフックがトリガーされた時刻の ISO 8601 形式タイムスタンプ
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": "バグ報告",
      "body": "バグの詳細をここに記述"
    },
    "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 形式で含まれます。これには、planner の応答、ツールによるアクション (ファイルの読み取り・書き込み・コマンドの実行) 、および Cascade が実行したその他のステップが含まれます。また、どのルールがトリガーされたかに関する情報も含まれます。ルールの発火状況をどのように解析するかについては、Tracking Triggered Rules の例を参照してください。 show_output 設定オプションは、このフックには適用されません。
response の内容は trajectory データから導出されたものであり、あなたのコードベースや会話からの機密情報を含む場合があります。このデータは、所属組織のセキュリティおよびプライバシーポリシーに従って取り扱ってください。

post_cascade_response_with_transcript

Cascade がユーザーのプロンプトへのレスポンスを完了したに非同期でトリガーされます。post_cascade_response と似ていますが、インラインで Markdown 形式の要約を提供する代わりに、このフックは会話の全文 (会話開始時点から) をローカルの JSONL ファイルに書き出し、そのファイルパスを提供します。 ユースケース: Enterprise の監査およびコンプライアンスログ、AI 生成コンテンツの貢献度追跡、外部のオブザーバビリティ/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 ファイルを指します。各行は、typestatus フィールドに加えてステップ固有のデータを持つ、会話の 1 ステップを表す JSON オブジェクトです。例えば、次のようになります。
{"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 パーミッションで書き込まれます。Windsurf はトランスクリプトディレクトリ内のファイル数を自動的に 100 件に制限し、更新時刻が最も古いものから順に削除します。 show_output 設定オプションはこのフックには適用されません。 次の表は、post_cascade_response フックと post_cascade_response_with_transcript フックの主な違いを示しています。
post_cascade_responsepost_cascade_response_with_transcript
Data scope直前のユーザー入力以降のステップのみ会話の最初からの全履歴
Formattool_info.response 内の Markdown サマリーtool_info.transcript_path にある構造化された JSONL ファイル
Detail level要約された人間可読のサマリー詳細な機械可読データ (ファイル内容、コマンド出力など)
Deliverystdin の JSON によるインラインディスク上のファイル (~/.windsurf/transcripts/)
トランスクリプトファイルには、ファイル内容、コマンド出力、会話履歴など、コードベースからの機密情報が含まれます。これらのファイルは、所属組織のセキュリティおよびプライバシーポリシーに従って取り扱ってください。

post_setup_worktree

新しい git worktree が作成・設定されたにトリガーされます。フックは新しい worktree ディレクトリ内で実行されます。 利用例: .env ファイルやその他の Git で管理されていないファイルを worktree にコピーする、依存関係をインストールする、セットアップスクリプトを実行する 環境変数:
VariableDescription
$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"
  }
}

終了コード

フックスクリプトは終了コードで結果を伝達します:
終了コード意味影響
0成功アクションは通常どおり続行
2ブロッキングエラーCascade エージェントは stderr のエラーメッセージを表示します。pre-hook の場合、このコードでアクションをブロックします。
その他エラーアクションは通常どおり続行
pre-hook (pre_user_prompt、pre_read_code、pre_write_code、pre_run_command、pre_mcp_tool_use) のみが、終了コード 2 によってアクションをブロックできます。post-hook は、アクションがすでに実行済みのためブロックできません。
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():
    # 標準入力から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"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():
    # 標準入力から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"アクセス拒否: Cascadeは{ALLOWED_PREFIX}配下のファイルのみ読み取り可能です", file=sys.stderr)
                sys.exit(2)  # 終了コード2でアクションをブロック
            
            print(f"アクセス許可: {file_path}", file=sys.stdout)

    except json.JSONDecodeError as e:
        print(f"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():
    # 標準入力から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がブロックされました: '{dangerous_cmd}' は安全上の理由により許可されていません。", file=sys.stderr)
                    sys.exit(2)  # 終了コード2でCommandをブロック
            
            print(f"Commandが承認されました: {command}", file=sys.stdout)

    except json.JSONDecodeError as e:
        print(f"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():
    # 標準入力から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 レスポンスのログ記録

コンプライアンス監査や Analytics のために、すべての 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():
    # 標準入力から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())

            # 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()
ルールの種類:
  • Always On - 常に有効なルール
  • Model Decision - 条件付き適用のため、その説明が AIモデル に提示されるルール
  • Manual - ユーザー入力で明示的に @ メンションされたルール
  • Global - global_rules.md に定義されたグローバルルール
  • Glob - glob パターンに一致するファイルアクセスによってトリガーされるルール
これは、どのルールが AIモデル に提示されたか、あるいはファイルアクセスによってトリガーされたかを追跡するものであり、AIモデル が実際にそのルールに従ったかどうかを示すものではありません。会話内ですでに直近で提示されたルールは重複排除され、しばらくのあいだ再表示されない場合があります。

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

Cascade がコードファイルを変更した後に、自動で整形します。 設定:
{
  "hooks": {
    "post_write_code": [
      {
        "command": "bash /Users/yourname/hooks/format_code.sh",
        "show_output": false
      }
    ]
  }
}
スクリプト (format_code.sh) :
#!/bin/bash

# 標準入力から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 "Pythonファイルをフォーマットしました: $file_path"
elif [[ "$file_path" == *.js ]] || [[ "$file_path" == *.ts ]]; then
    prettier --write "$file_path" 2>&1
    echo "JS/TSファイルをフォーマットしました: $file_path"
elif [[ "$file_path" == *.go ]]; then
    gofmt -w "$file_path" 2>&1
    echo "Goファイルをフォーマットしました: $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

# 元のワークスペースから環境ファイルをコピー
if [ -f "$ROOT_WORKSPACE_PATH/.env" ]; then
    cp "$ROOT_WORKSPACE_PATH/.env" .env
    echo ".envファイルをコピーしました"
fi

if [ -f "$ROOT_WORKSPACE_PATH/.env.local" ]; then
    cp "$ROOT_WORKSPACE_PATH/.env.local" .env.local
    echo ".env.localファイルをコピーしました"
fi

# 依存関係をインストール
if [ -f "package.json" ]; then
    npm install
    echo "npm依存関係をインストールしました"
fi

exit 0
このフックにより、各ワークツリーで必要な環境構成と依存関係が自動的にセットアップされます。

ベストプラクティス

セキュリティ

Cascade Hooks の使用は自己責任です: Hooks は、あなたのユーザーアカウントに付与された権限の範囲でシェルコマンドを自動実行します。設定したコードの結果については、全てあなたの責任となります。設計不備や悪意のある hook により、ファイルの改変、データの削除、認証情報の漏えい、システムの侵害が発生するおそれがあります。
  • すべての入力を検証する: 特にファイルパスやコマンドに関して、検証されていない入力 JSON を信用しないでください。
  • 絶対パスを使用する: あいまいさを避けるため、hook の設定では常に絶対パスを使用してください。
  • 機微情報を保護する: API キーや資格情報などの機微情報はログに記録しないでください。
  • 権限を確認する: hook スクリプトに適切なファイルシステム権限が設定されていることを確認してください。
  • 導入前に精査する: 設定に追加する前に、すべての hook コマンドとスクリプトをレビューしてください。
  • 隔離環境でテストする: メインの開発マシンで有効化する前に、テスト環境で hook を実行してください。

パフォーマンスに関する考慮事項

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

エラーハンドリング

  • 常に JSON を検証する: 不正な入力に優雅に対処できるよう、try-catch ブロックを使用してください。
  • エラーを適切にログ出力する: show_output が有効な場合に見えるよう、エラーは stderr に出力してください。
  • 安全に失敗する: フックでエラーが発生した場合、そのアクションをブロックすべきか、処理を続行させるべきかを検討してください。

フックのテスト

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

Enterprise 配布

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

クラウドダッシュボードでの設定

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

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

ファイルベースの設定を好む、あるいはフックをオフラインでも動作させる必要がある組織では、必須の 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 またはセキュリティチームが一元的に管理します。Windsurf はシステムレベルのパスにファイルを配置・管理しません。組織のポリシーに従い、内部チームがデプロイ、更新、コンプライアンス対応を適切に実施してください。

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

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

# Commit to git
git add .windsurf/
git commit -m "コードフォーマット用のワークスペースフックを追加"
これにより、チームは開発プロセスを標準化できます。セキュリティ上重要なポリシーはクラウドまたはシステムレベルで管理し、機密情報をバージョン管理にコミット (登録) することは避けてください。

追加リソース