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 アクションが発生した際に自動的に実行されるシェルコマンドです。各フックは次のように動作します。
- 前提情報を受け取る (実行されるアクションの詳細が、JSON として標準入力経由で渡されます)
- スクリプトを実行する - Python、Bash、Node.js、または任意の実行可能ファイル
- 結果を返す (終了コードと出力ストリームを通じて返します)
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 が使用されます。
各フックでは、次のパラメータを指定できます。
| パラメータ | 型 | 説明 |
|---|
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 | 任意。コマンドを実行するディレクトリ。既定ではワークスペースルートが使用されます。 |
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 | ✗ | ✗ | バリデーションエラー |
working_directory パラメータについて:
- 複数の repo があるワークスペースでは、デフォルトは現在作業中の repo のルートです
- 相対パスはデフォルトの場所 (ワークスペース または repo ルート) を基準に解決されます
- 絶対パスをサポートしています
~ による home directory の展開はサポートされていません
Cascade には、エージェントのワークフローにおける主要なアクションをカバーする 12 種類のフックイベントがあります。
すべてのフックは、次の共通フィールドを含む 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 種類あります。
Cascade がコードファイルを読み取る前にトリガーされます。フックが終了コード 2 で終了した場合、この操作はブロックされることがあります。
利用例: ファイルアクセスの制限、読み取り操作の記録、権限の確認
入力 JSON:
{
"agent_action_name": "pre_read_code",
"tool_info": {
"file_path": "/Users/yourname/project/file.py"
}
}
Cascade がディレクトリを再帰的に読み込む場合、この file_path はディレクトリパスになることがあります。
Cascade がコードファイルを正常に読み取った後にトリガーされます。
利用例: 正常に読み取れたことをログに記録する、ファイルアクセスパターンを追跡する
入力 JSON:
{
"agent_action_name": "post_read_code",
"tool_info": {
"file_path": "/Users/yourname/project/file.py"
}
}
Cascade がディレクトリを再帰的に読み込む場合、この file_path はディレクトリパスになることがあります。
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"
}
]
}
}
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"
}
]
}
}
Cascade がターミナルコマンドを実行する前にトリガーされます。フックが終了コード 2 で終了すると、処理がブロックされることがあります。
ユースケース: 危険なコマンドをブロックする、すべてのコマンド実行を記録する、安全チェックを追加する
入力 JSON:
{
"agent_action_name": "pre_run_command",
"tool_info": {
"command_line": "npm install package-name",
"cwd": "/Users/yourname/project"
}
}
Cascade がターミナルコマンドを実行した後にトリガーされます。
ユースケース: コマンドの実行結果を記録する、後続の処理をトリガーする
入力 JSON:
{
"agent_action_name": "post_run_command",
"tool_info": {
"command_line": "npm install package-name",
"cwd": "/Users/yourname/project"
}
}
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"
}
}
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"
}
}
ユーザーのプロンプトのテキストを Cascade が処理する前にトリガーされます。フック がコード 2 で終了した場合、このアクションがブロックされることがあります。
利用例: 監査のためにすべてのユーザープロンプトを記録する、潜在的に有害なプロンプトやポリシー違反のプロンプトをブロックする
入力 JSON:
{
"agent_action_name": "pre_user_prompt",
"tool_info": {
"user_prompt": "can you run the echo hello command"
}
}
show_output 設定オプションは、このフックでは適用されません。
ユーザーのプロンプトに対する 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_response | post_cascade_response_with_transcript |
|---|
| データ範囲 | 最後のユーザー入力以降のステップのみ | 会話の最初から最後まで全体 |
| 形式 | tool_info.response 内の Markdown 形式の要約 | tool_info.transcript_path にある構造化された JSONL ファイル |
| 詳細度 | 簡潔で人が読める要約 | 詳細で機械可読なデータ (ファイル内容、コマンド出力など) |
| 提供方法 | stdin JSON でインライン提供 | ディスク上のファイル (~/.windsurf/transcripts/) |
トランスクリプトファイルには、ファイル内容、コマンド出力、会話履歴など、コードベース内の機密情報が含まれます。これらのファイルは、組織のセキュリティポリシーおよびプライバシーポリシーに従って取り扱ってください。
新しい 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 Code | Meaning | Effect |
|---|
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 が実行するすべてのアクションを追跡します。
設定:
{
"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 応答をログに記録します。
設定:
{
"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
このフックは、編集のたびにファイル形式に応じた適切なフォーマッターを自動的に実行します。
新しいワークツリーが作成されたときに、環境ファイルをコピーして依存関係をインストールします。
設定 (.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 に書き込みます。
- 安全に失敗させる: フックでエラーが発生した場合は、その処理を中断すべきか、それとも続行を許可すべきかを検討します。
- まずはログ記録から始める: データの流れを把握するために、まずはシンプルなログ記録用フックを実装します。
show_output: true を利用する: 開発中は出力を有効にして、フックが何をしているか確認します。
- ブロック動作をテストする: 終了コード 2 で、pre-hook での処理が正しくブロックされることを確認します。
- すべてのコードパスを確認する: スクリプトで成功時と失敗時の両方のケースをテストします。
Enterprise組織では、個々のユーザーが回避できないセキュリティポリシー、コンプライアンス要件、開発標準を適用する必要があります。Cascade Hooksは、Enterprise向けに2つの配布方法をサポートしています。
- Cloud Dashboard - Devin Desktopダッシュボードのチーム設定でフックを設定します
- System-Level Files - MDMまたは構成管理ツールを使ってフックを展開します
これらの方法は併用でき、すべてのソースのフックが統合されて順番に実行されます。
チーム管理者は、Devin Desktop ダッシュボードから直接 Cascade Hooks を設定できます。
要件:
- Enterprise プラン
TEAM_SETTINGS_UPDATE 権限
設定手順:
- Devin Desktop ダッシュボードのチーム設定に移動します
- Cascade Hooks セクションを探します
- フックの設定を JSON 形式で入力します
- 変更を保存します
ダッシュボードで設定したフックは、すべてのチームメンバーに自動的に配布され、Devin Desktop の起動時に読み込まれます。クラウドで設定されたフックが最初に読み込まれ、続いてシステムレベル、ユーザーレベル、ワークスペースレベルのフックが読み込まれます。
複数のチーム設定がマージされる場合、フックは上書きされず、アクションごとに結合されます。つまり、該当するすべてのチーム設定のフックがまとめて実行されます。
ファイルベースの設定を利用したい組織や、フックをオフラインで動作させる必要がある組織向けに、必須のhooks.json設定をOSごとに以下の場所へ配置してください。
macOS:
/Library/Application Support/Windsurf/hooks.json
Linux/WSL:
Windows:
C:\ProgramData\Windsurf\hooks.json
対応するシステムディレクトリにフックスクリプトを配置してください (例: Unix システムでは /usr/local/share/windsurf-hooks/) 。
システムレベルのフックは、ユーザーおよびワークスペースのフックよりも優先され、root 権限がないエンドユーザーは無効化できません。
Enterprise IT チームは、標準的なツールを使用してシステムレベルのフックをデプロイできます。
モバイルデバイス管理 (MDM)
- Jamf Pro (macOS) - 構成プロファイルまたはスクリプトを使ってデプロイ
- Microsoft Intune (Windows/macOS) - PowerShell スクリプトまたはポリシー配布を利用
- Workspace ONE、Google Endpoint Management、その他の MDM ソリューション
構成管理
- Ansible、Puppet、Chef、SaltStack - 既存のインフラストラクチャ自動化を利用
- カスタムデプロイスクリプト - シェルスクリプト、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"
これにより、チーム全体で開発プラクティスを標準化できます。セキュリティ上重要なポリシーはクラウドまたはシステムレベルで管理し、機密情報はバージョン管理にチェックインしないでください。