はじめに
AWS製のAI開発環境 Kiro には、IDEイベントに応じてエージェントアクションを自動実行する Hooks 機能がある。ファイル保存時にlintを走らせたり、ツール実行前にポリシーチェックを挟んだりできる、いわばAIエージェント版のGit Hooksだ。
本記事では、Kiro Hooksを実プロジェクトで運用する中で踏んだ 2つの落とし穴 と、それぞれの対策を共有する。
検証日: 2025年5月
Kiroバージョン: パブリックプレビュー時点
TL;DR
| 問題 | 原因 | 対策 |
|---|---|---|
preToolUse + shell で特定コマンドだけに絞れない |
toolTypes はカテゴリ単位。コマンド内容がhookに渡されない |
askAgent でプロンプト先頭に早期リターン指示 |
.kiro/hooks/ 配下の変更で fileEdited が発火しない |
無限ループ防止のため除外されている(推測) |
userTriggered に変更して手動実行 |
落とし穴1: preToolUseのコマンドフィルタリング問題
やりたかったこと
git push 実行前にポリシーチェックを挟みたい。具体的には:
- ユーザーの明示的な許可を得ているか
- レビュー済みか
- masterへの直接pushでないか
最初に書いたhook
{
"name": "Git Pushポリシー",
"version": "1.0.0",
"when": {
"type": "preToolUse",
"toolTypes": ["shell"]
},
"then": {
"type": "askAgent",
"prompt": "git pushのポリシーチェックを行ってください..."
}
}
何が起きたか
すべてのシェルコマンド実行時に発火する。 ls でも cat でも npm install でも、毎回LLM呼び出しが走る。
toolTypes はツールの カテゴリ でしかフィルタリングできない。利用可能な値は以下の通り:
| toolTypes | 対象 |
|---|---|
read |
ファイル読み取り系 |
write |
ファイル書き込み系 |
shell |
シェルコマンド全般 |
web |
Web検索・フェッチ |
spec |
Spec操作 |
* |
全ツール |
| 正規表現 | MCPツール名にマッチ |
shell カテゴリの中で「git push だけ」に絞る方法がない。
検証: runCommand方式ならコマンド内容を取得できるか?
askAgent だとLLM呼び出しが毎回走るので、runCommand でシェルスクリプトに判定させることを考えた。
{
"when": {
"type": "preToolUse",
"toolTypes": ["shell"]
},
"then": {
"type": "runCommand",
"command": "echo \"USER_PROMPT=$USER_PROMPT\""
}
}
結果: USER_PROMPT={} のみ。 実行予定のコマンド内容はスクリプトに渡されない。引数もstdinも空。
他ツールとの比較(AIによるまとめ)
| ツール | matcherの対象 | コマンド内容の取得 |
|---|---|---|
| Codex (OpenAI) | ツール名のみ | ✅ stdinで tool_input.command がJSON渡し |
| Claude Code (Anthropic) | ツール名のみ | ✅ stdinで tool_input.command がJSON渡し |
| Kiro (AWS) | ツールカテゴリ/名前 | ❌ 渡されない |
Claude CodeやCodexでは、preToolUseに相当するhookでツールの入力パラメータ(実行予定のコマンド文字列)がstdin経由でJSON渡しされる。Kiroではこの仕組みがない。
現状の対策: 早期リターンパターン
askAgent 方式で、プロンプトの 先頭 に早期リターン指示を置く:
{
"name": "Git Pushポリシー",
"version": "1.0.0",
"when": {
"type": "preToolUse",
"toolTypes": ["shell"]
},
"then": {
"type": "askAgent",
"prompt": "実行予定のコマンドを確認し、`git push` を含まない場合は即座に「ポリシーチェック対象外」とだけ出力して終了してください。それ以外の分析や説明は不要です。\n\n`git push` を含む場合のみ、以下を検証してください:\n1. ユーザーの明示的な許可を得ているか\n2. refs/for/ 経由か\n3. masterへの直接pushでないか\n\n全ルール適合時:「ポリシーチェックOK」"
}
}
ポイント:
- プロンプト先頭で早期リターン条件を明示 — LLMは対象外と判断すれば短い応答で終わる
- 毎回LLM呼び出しは走るが、対象外なら応答が短いのでコスト・時間は最小限
- 完璧ではないが、現状のKiroの仕組みでは最善策
MCPツールなら正規表現で絞れる
一方、MCPツールに対しては正規表現でフィルタリングできる。例えばGerritのブランチ作成だけに絞りたい場合:
{
"when": {
"type": "preToolUse",
"toolTypes": [".*create_branch.*"]
},
"then": {
"type": "askAgent",
"prompt": "ブランチ命名規則を検証してください..."
}
}
これは toolTypes がMCPツール名に対する正規表現マッチとして機能するため、ピンポイントで絞れる。シェルコマンドだけがこの恩恵を受けられない のが現状の制約。
今後の期待
Kiroが tool_input(実行予定のコマンド文字列)をhookに渡すようになれば、runCommand 方式でシェルスクリプト側で高速に判定できるようになる。Feature Requestとして期待したい。
落とし穴2: .kiro/hooks/ 配下のファイル変更ではfileEditedが発火しない
やりたかったこと
hookファイルを編集したら自動で品質チェックを走らせたい。Steeringファイルの品質チェックと同じパターンで:
{
"name": "Hook品質チェック",
"version": "1.0.0",
"when": {
"type": "fileEdited",
"patterns": [".kiro/hooks/*.hook"]
},
"then": {
"type": "askAgent",
"prompt": "Hookファイルの品質をチェックしてください..."
}
}
何が起きたか
発火しない。 hookファイルを編集・保存しても、このhookは一切トリガーされない。
検証結果
| パターン | 対象 | 発火 |
|---|---|---|
.kiro/steering/*.md |
Steeringファイル | ✅ 発火する |
.kiro/hooks/*.hook |
Hookファイル | ❌ 発火しない |
src/*.cpp |
C++ソース | ✅ 発火する |
.kiro/skills/**/*.md |
Skillファイル | ✅ 発火する |
.kiro/hooks/ 配下 だけ が fileEdited の監視対象から除外されている。
なぜ除外されているのか(推測)
公式ドキュメントに明記はないが、理由は明白だ:
hookファイル変更 → fileEdited発火 → hookが応答を生成
→ その応答でhookファイルを修正 → fileEdited発火 → ...(無限ループ)
hookファイルの変更でhookが発火すると、hookが自分自身を書き換えるループ が発生し得る。これを防ぐために .kiro/hooks/ は監視対象から除外されていると考えられる。
対策: userTriggeredに変更
fileEdited が使えないなら、手動トリガーにする:
{
"name": "Hook品質チェック",
"version": "2.0.0",
"when": {
"type": "userTriggered"
},
"then": {
"type": "askAgent",
"prompt": ".kiro/hooks/ 配下の全hookファイルを読み込み、以下の観点でチェックしてください:\n1. 命名: kebab-caseで {機能名}.kiro.hook の形式か\n2. 1フック1関心事\n3. JSON構文: 必須フィールドが揃っているか\n4. toolTypes: 適切に絞られているか\n5. プロンプト明確さ\n6. 早期リターン指示の有無\n..."
}
}
userTriggered はKiroのAgent Hooksパネルからワンクリックで実行できる。「必要な時にまとめてチェック」する運用に切り替えた。
代替案: Steeringファイル経由の間接トリガー
もう一つの手として、hookの設計情報をSteeringファイルに書き出し、そのSteeringファイルの変更をトリガーにする方法もある。ただし間接的すぎるので、素直に userTriggered が実用的。
まとめ: Kiro Hooks設計の教訓
これらの経験から得た設計指針をまとめる。
1. preToolUseは「早期リターンパターン」を標準にする
プロンプト構成:
1行目: 対象外の判定条件と即時終了指示
2行目以降: 対象の場合のチェックロジック
全shellで発火する前提で、対象外を最速で弾く設計にする。
2. MCPツールには正規表現フィルタを活用する
toolTypes: [".*create_branch.*"] のように、MCPツール名に対しては正規表現が使える。シェルコマンドと違い、ピンポイントで絞れる。
3. .kiro/hooks/ は監視対象外と心得る
hookの品質チェックは userTriggered で手動実行する設計にする。自動化したい気持ちはわかるが、無限ループ防止のための制約として受け入れる。
4. hookの出力形式を統一する
OK時: ✅ {Hook名} OK
NG時: 箇条書きで具体的な違反内容
対象外時: 「ポリシーチェック対象外」(1行で終了)
出力形式を統一しておくと、hookの結果を見たときの認知負荷が下がる。
参考
この記事の内容はKiroパブリックプレビュー時点のものです。今後のアップデートで tool_input の受け渡しや .kiro/hooks/ の監視対応が追加される可能性があります。