0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kiro Hooksで踏んだ2つの落とし穴 — preToolUseのコマンドフィルタリングとfileEditedの発火しない領域

0
Posted at

はじめに

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/ の監視対応が追加される可能性があります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?