本文へスキップ
やす研究所 AI Lab
戻る

Cursor Hooks完全ガイド 2026:エージェントを制御する実装手順

Cursor Hooks完全ガイド 2026:エージェントを制御する実装手順

Cursorのエージェントが勝手に.envを読んだり、git push --forceを叩こうとしてヒヤッとしたこと、ありませんか。私は先月、Astroサイトのリポジトリで一度やられました。

それ以来、.cursor/hooks.jsonでエージェントの動きを機械的に止める仕組みを組んでいます。ルールやMCPでは届かなかった「実行の直前でブロックする」領域を埋めてくれるのがCursor Hooksです。

この記事では、2週間かけて実プロジェクトに組み込んだ手順・落とし穴・すぐ動くサンプルまで、Hooksをゼロから使えるレベルで解説します。

結論:Hooksは”実行直前の関所”としてルール/MCPと三層で使う

先に結論から書きます。Cursor Hooksは、.cursor/rules(文脈を渡す)やMCP(道具を渡す)では止められないエージェントの実行そのものに対して、外部スクリプトで介入できる仕組みです。

Cursor 1.7で導入されたHooksは、エージェントの振る舞いをライフサイクルイベントで割り込んで変更でき、シェルコマンドのブロック、編集後のフォーマッタ実行、エージェントの動作をリアルタイムで観測するなどに使えます。

私が実運用で置いている役割分担はこうです。

この三層のうち、Hooksだけが「実行を止める」権限を持っています。ここが決定的な違いです。

Cursor Hooksとは何か:ライフサイクルで割り込む仕組み

HooksはJSONで定義し、エージェントの節目でシェルコマンドやスクリプトを起動する仕組みです。

Cursor 1.7で導入されたHooksは、エージェントループの定義済みステージで外部スクリプトを実行でき、各フックはJSONで設定され独立プロセスとして起動、stdin経由で構造化された入力を受け取りCursorに結果を返します。

公式ドキュメントによると、フックは大きく3カテゴリに分かれます。Agent系(sessionStart/sessionEnd、preToolUse/postToolUse、beforeShellExecution/afterShellExecution、beforeMCPExecution/afterMCPExecution、beforeReadFile/afterFileEdit、beforeSubmitPromptなど)と、workspaceOpen(ワークスペースを開くときに発火し、追加のプラグインパスを返せる)などです。

重要なのは、単なる観測ではなく拒否・許可の判断を返せることです。シェルコマンドやMCPツール実行の前に呼び出され、許可判断を返せます。デフォルトでは、フックが失敗(クラッシュ、タイムアウト、不正なJSON)した場合はfail-openで実行が通ります。failClosed: trueをフック定義に設定すると、失敗時にアクションをブロックする挙動になり、これはセキュリティ重視のbeforeMCPExecutionフックで推奨されます。

つまりHooksは「関所」として機能させる設計になっています。ここを理解していないと、ただログを吐くだけの飾りで終わります。

最短セットアップ:hooks.jsonを配置する3ステップ

実際に動かすまでは驚くほど簡単です。私が最初にやったのは、macOSで通知を出すだけの検証用フックでした。

ステップ1:スコープを決める

設定を置く場所を先に決めます。プロジェクト単位ならリポジトリ内の.cursor/hooks.jsonに置くとバージョン管理でき、チームにも見えます。ユーザーグローバルなら~/.cursor/hooks.json(macOS/Linux)で、開くすべてのプロジェクトに適用されます。

チームで共有したいならプロジェクト、個人のクセ(通知など)ならグローバル。私はロギングと安全策はプロジェクト、通知だけグローバルにしています。

ステップ2:最小のhooks.jsonを書く

エージェントがタスクを終えたら通知するだけの最小構成です。

{
  "version": 1,
  "hooks": {
    "stop": [
      {
        "command": "osascript -e 'display notification \"Done\" with title \"Cursor\"'"
      }
    ]
  }
}

Cursor公式ドキュメントも、エージェントがタスクを完了したときにローカルmacOSの通知を表示する停止フックを簡単な例として提示しており、外部サービスなしで軽量な自動化を組み込めることを示しています。

ステップ3:実行権限を忘れずに

これが最大の落とし穴です。スクリプトをchmodで実行可能にするのは重要でよく見落とされるステップで、これを忘れるとフックはサイレントに失敗し、なぜ動かないのか悩むことになります。

私も最初の30分をこれで溶かしました。シェルスクリプトを呼び出す場合はchmod +x .cursor/hooks/*.shを必ず。

うまく動かないときは、Cursorの出力チャネルに”Hooks”というチャネルがあり、JSONの不正や実行しようとしたコマンドなど大量のデバッグ情報を確認できます。「Output channels」から「Hooks」を選ぶと開けます。ここを見ずに悩むのは時間の無駄です。

今日から効くHooksレシピ4選

通知だけで満足せず、実務で本当に助かる4つを紹介します。

レシピ1:破壊的なgitコマンドを止める

git push --forceをmain以外で叩いたら止める、みたいなガードはbeforeShellExecutionの得意分野です。

シェルコマンド実行前にCursorはフックを呼び出し、実行してよいか判断できます。stdinにはconversation_idgeneration_idcommandcwdhook_event_nameworkspace_rootsなどが渡されます。

このcommandフィールドを正規表現でチェックし、危険なパターンなら{"permission": "deny"}を返すだけ。私はrm -rf--force系を常時ブロックしています。

レシピ2:.envや秘密ファイルの読み取りを拒否する

beforeReadFileで機密ファイルへの参照を落とします。このフックは同フォーマットの出力JSONを尊重するので、ファイル読み取り(CursorがファイルコンテンツをLLMに送ること)の許可・拒否を指示できます。GitHub APIキーを含むファイルの読み取りを拒否する実例もあります。

.env*.pem~/.aws/credentialsあたりは問答無用でdenyにしておくと精神衛生上いいです。

レシピ3:編集後に自動フォーマット

afterFileEditでBiomeやPrettierを走らせます。TypeScriptプロジェクトでBunを使う例だと、こんな感じで型安全に書けます。

import type { AfterFileEditPayload } from "cursor-hooks";
const input: AfterFileEditPayload = await Bun.stdin.json();
if (input.file_path.endsWith(".ts")) {
  await Bun.$`bunx @biomejs/biome lint --fix --unsafe ${input.file_path}`;
}

afterFileEditペイロードを受け取り、.tsファイルならBiomeでlint —fix —unsafeを走らせるパターンです。

エージェントが書いたコードが自動で整うので、レビュー時のノイズが目に見えて減りました。

レシピ4:シークレット漏洩の検知

編集や実行の前段でAWSキーやJWTらしき文字列を検知して止める。具体的にはmain/dev以外でのgit push --forceの遮断、コミット時のconventional commitメッセージ強制、AWSキー・JWT・.pemブロックを含むシェルコマンドやファイル編集の拒否、.envやインフラ設定への編集を明示許可なしにブロック、といった使い方ができます。

完璧な検知は無理でも、うっかり事故を9割減らすには十分。私はgrep -E '(AKIA[0-9A-Z]{16}|-----BEGIN)'を通しています。

Hooksを本番運用する前に知っておく3つの落とし穴

便利なので油断しがちですが、地雷もあります。

落とし穴1:fail-openがデフォルト

先ほども触れましたが、フックがバグって落ちるとアクションはそのまま通ります。セキュリティ用途ではfailClosed: trueを必ず付けること。忘れると「ガードしてるつもり」の状態で素通りします。

落とし穴2:Cloud Agentsではユーザー設定が効かない

これを知らずに、ローカルで動いたのにCloud Agentで動かず数時間溶かしました。プロジェクトフック(リポジトリ内の.cursor/hooks.json)とTeamフック(Enterpriseでダッシュボードから配布)、Enterpriseフック(組織全体で管理)はcloud agentで実行されますが、ユーザーレベルフック(~/.cursor/hooks.json)はcloud agentでは利用できません。cloud agent VMはローカルのホームディレクトリ設定にアクセスできないためです。

チーム運用したいならプロジェクト単位に集約するのが正解です。

落とし穴3:プロンプトベースのフックはクラウドで動かない

Cloud Agentはコマンドベースのフックのみを実行します。プロンプトベースのフックはフックとエージェントループ間の認証配線が必要ですが、クラウド実行環境では利用できません。

自然言語でジャッジさせるフック(LLMに判定させるタイプ)は、ローカル専用と割り切って設計する必要があります。

それから、セキュリティの基本として。コマンドは最小権限で実行し、フックでsudoは避ける。シークレットはハードコードせず環境変数やOSキーチェーン、シークレットボルトを使う。フックがエージェント出力やファイルパスを読む場合は、サニタイズとバリデーションを行う。ここは手を抜かないほうがいいです。

ルール/コマンド/スキルとの使い分け

Cursorには似た機能が並んでいて混乱しやすいので整理します。

Hooksはカスタムスクリプトを使ってエージェントループを観測・制御・拡張します。特定イベントの前後で実行され、エージェントの挙動をブロック・変更・監査できます。もっとも強力で、もっとも複雑な機能です。

選び方の指針としてはこうです。

まずルールで譲れない前提を固め、繰り返すワークフローにコマンドを追加、ドメイン知識はスキルとしてオンデマンドで、プログラマティックな制御が必要になったらHooksに手を出す——この順で導入するのが失敗が少ないと感じています。

いきなりHooksから入ると、書きすぎて自分の首を絞めます。私も最初、afterFileEditにlintを重ねすぎてエージェントの応答が遅くなり、外した経験があります。

まとめ:今日からやる4つのアクション

Hooksは強力ですが、正直、最初は半信半疑でした。「JSONひとつでそんなに変わる?」と。実際に組んでみて印象が変わったのは、.envの誤読を1回止めた瞬間です。

最後に、この記事を読み終えたらやる順番を残しておきます。

  1. .cursor/hooks.jsonを作り、stopイベントで通知だけ動かす(最短5分)
  2. beforeShellExecution--force系の破壊コマンドを1つdenyする
  3. beforeReadFile.env*.pemを拒否する
  4. afterFileEditにフォーマッタを繋ぐ(遅くなったら外す)

この4つで、エージェントの事故率は体感でかなり下がります。ルール・MCPと三層で組めば、Cursorはもう”暴走するかもしれないアシスタント”ではなく、決められた線路の中で走る便利な同僚に変わります。

次に読むなら、.cursor/rulesの書き方と、MCPサーバー設定の記事あたりが対になっておすすめです。Hooksは最後の関所として、あとから足す位置づけで十分効きます。

参考リンク


この記事をシェア:

次の記事
Claude Code 内蔵ブラウザ実践2026:Cmd+Shift+Bで開発ループを閉じる手順