関連 issue: #64 Geminiにレビューとかさせられる?
Gemini CLI を使ったコードレビュー・仕様書レビュー機能を run_review MCP tool として Butler に追加する。
2 種類のレビュー方式の品質を検証した結果:
| 方式 | 実行方法 | 品質 | 速度 |
|---|---|---|---|
| quick | gemini --output-format text + diff を stdin |
★★ | 10-20秒 |
| thorough | gemini --approval-mode plan --output-format text + diff を stdin |
★★★ | 30-90秒 |
thorough は Gemini がリポジトリを能動的に読み、実装との乖離・テスト欠落・cross-file 不整合を検出できる。
quick は diff のみを見るため、基本的な問題は網羅できるが実装照合はできない。
plan mode で diff を渡す場合は必ず stdin 経由にする。plan mode は git diff などのコマンド実行がブロックされるため。
depth 選択の設計方針(issue #64 コメント参照)depth 未指定時にツール自身が need_input を返し、選択肢をユーザーに提示させるneed_input の判定は Butler(mcp_facade.py) で行う。Maid には渡さないBrain / Claude Code
-> run_review MCP tool(mcp_facade.py)
|
+-- depth 未指定 → need_input を即返す(Maidは呼ばない)
|
+-- depth 指定あり → TaskContract(intent="review") → execute_task
-> runtime routing
-> GeminiCliReviewMaid
-> gemini CLI
-> Google AI Pro / Gemini Code Assist
run_review
git diff をもとに Gemini CLI でコードまたは仕様書をレビューします。
depth は必ずユーザーに選ばせてください。自己判断で埋めないでください。
- quick: diff のみ参照。10〜20秒。軽い確認向け
- thorough: リポジトリを読んで実装と照合。30〜90秒。マージ前・仕様乖離の確認向け
issue_id を指定すると、レビュー結果を Gitea の issue コメントに投稿します。
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
project_root |
str | ○ | レビュー対象リポジトリのパス |
base_ref |
str | ○ | 比較元(例: "main") |
depth |
str | None | △ | "quick" or "thorough"。省略時は need_input を返す |
head_ref |
str | None | — | 比較先(省略時: HEAD) |
diff_paths |
list[str] | None | — | 絞り込み対象パス(省略時: 全差分) |
issue_id |
int | None | — | 指定時: Gitea issue コメントにも投稿 |
{
"status": "need_input",
"summary": "レビュー方式を選択してください",
"options": {
"quick": "diff のみ参照。10〜20秒。軽い確認向け",
"thorough": "リポジトリを読んで実装と照合。30〜90秒。マージ前・仕様乖離の確認向け"
}
}
この返却は execute_task を呼ぶ前に mcp_facade.py 内で完結させる。
- maid_id: gemini_cli_review
kind: cli
label: Gemini CLI Review
provider: google_ai_pro
model: gemini-cli-auto
role: review
enabled: true
launch_config:
entrypoint: butler.maids.gemini_cli_review_maid:GeminiCliReviewMaid
command_env_vars:
GOOGLE_GENAI_USE_GCA: "true"
GEMINI_CLI_TRUST_WORKSPACE: "true"
verification_profile:
match_fields: []
file_checks: []
http_checks: []
test_commands: []
exact_output: []
- intent: review
maid_id: gemini_cli_review
delegatable: true
conditions_json: {}
retry_policy_json: {}
mcp_facade.py から execute_task に渡す際の payload:
payload = {
"base_ref": base_ref,
"head_ref": head_ref or "HEAD",
"depth": depth, # "quick" or "thorough"
"diff_paths": diff_paths or [],
"issue_id": issue_id, # int or None
}
constraints.implicit_scope は [f"repo:{Path(project_root).name}"] で固定。
success_criteria は ["review report generated"] で固定(Maid が判定しない)。
payload から git diff コマンドを構築・実行してテキストを取得するissue_id が指定されている場合は Gitea issue コメントに投稿する(issue_backend 経由)1. payload から base_ref / head_ref / depth / diff_paths / issue_id を取り出す
2. git diff {base_ref}...{head_ref} -- {diff_paths} を subprocess で実行してテキスト取得
3. diff が空なら need_input を返す("差分がありません")
4. depth に応じた gemini CLI コマンドを構築する
- quick: gemini --output-format text -p "{prompt}"
- thorough: gemini --approval-mode plan --output-format text -p "{prompt}"
5. diff テキストを stdin に渡して gemini CLI を実行する
6. stdout をレビュー結果テキストとして受け取る
7. issue_id が指定されていれば issue_backend.comment_issue() でコメント投稿する
8. ResultContract(status="ok", evidence={"review_text": ..., "issue_comment_posted": ...}) を返す
env = {
"GOOGLE_GENAI_USE_GCA": "true",
"GEMINI_CLI_TRUST_WORKSPACE": "true",
**os.environ,
}
cmd = ["gemini", "--output-format", "text", "-p", prompt]
if depth == "thorough":
cmd = ["gemini", "--approval-mode", "plan", "--output-format", "text", "-p", prompt]
result = subprocess.run(
cmd,
input=diff_text,
capture_output=True,
text=True,
timeout=180,
cwd=project_root,
env=env,
)
stdin に diff を渡すことで、plan mode でも git diff コマンドの実行なしに diff を参照できる。
以下の git diff をシニアエンジニアとしてレビューしてください。
必要であれば関連ファイルを読んで実装と照合してください。
## バグ・論理エラー(重要度: high)
## 設計・アーキテクチャ上の問題(重要度: medium)
## テスト・エッジケースの漏れ(重要度: medium)
## コードスタイル・可読性(重要度: low)
問題がないセクションは省略してください。
diff:
-p に渡し、実際の diff は stdin 経由で追加される(Gemini CLI は -p のプロンプトと stdin を結合する)。
stderr に以下のキーワードが含まれる場合は need_input を返す:
"Auth method""GEMINI_API_KEY""Sign in"ResultContract(
status="need_input",
summary="Gemini CLI の認証が必要です。gemini コマンドを対話起動して Sign in with Google を完了してください。",
evidence={"stderr_excerpt": stderr[:500]},
)
{
"review_text": str, # Gemini のレビュー全文
"depth": "quick" | "thorough",
"base_ref": str,
"head_ref": str,
"diff_lines": int, # 差分の行数
"issue_comment_posted": bool, # Gitea コメント投稿済みか
"issue_id": int | None,
}
butler/maids/gemini_cli_review_maid.pytests/test_gemini_cli_review_maid.py| ファイル | 変更内容 |
|---|---|
butler/mcp_facade.py |
run_review tool 追加、depth 未指定時の need_input 判定 |
config/maid_registry.yml |
gemini_cli_review エントリ追加 |
config/intent_maid_routes.yml |
intent: review route 追加 |
test_quick_mode_calls_gemini_without_plan_modetest_thorough_mode_calls_gemini_with_plan_modetest_diff_passed_via_stdintest_empty_diff_returns_need_inputtest_auth_error_returns_need_inputtest_issue_comment_posted_when_issue_id_giventest_no_issue_comment_when_issue_id_nonetest_timeout_returns_failedmock 方針:
subprocess.run は mock するissue_backend.comment_issue は mock するtest_run_review_returns_need_input_when_depth_missingtest_run_review_dispatches_task_when_depth_given| 観点 | implement | review |
|---|---|---|
| git branch 作成 | あり | なし |
| Butler 側 commit | あり | なし |
| verification | あり | なし |
| scope チェック | あり | なし |
| 出力 parse | JSON | テキストそのまま |
| Gitea 投稿 | なし(Brain が work_publish) | オプションで Maid が投稿 |
| depth 判定 | なし | Butler(mcp_facade)が担当 |
review_type: "code" | "spec" パラメータを追加する余地を残す[ERROR] Invalid stream を出すケースへの対処
failed を返す