3行でいうと

  • ヘッドレス(非対話)は、-p(--prompt)を付けるか、TTYのない環境で動かすと始まります。出力は text、json、stream-json から選べ、終了コードは 0、1、42、53 の4つが公式に書かれています。ただし、公式のヘッドレスのページには、ツールの承認の扱いの説明が見つかりませんでした。信頼するフォルダを有効にしている場合、未信頼のフォルダでは FatalUntrustedWorkspaceError で止まるので、--skip-trust か GEMINI_CLI_TRUST_WORKSPACE=true の判断が要ります。
  • MCPは settings.json の mcpServers に書くか、gemini mcp add で足します。公式は、起動するサーバーの環境から *TOKEN* や *KEY* などの名前の変数を自動で取り除く、と書いています。サーバーに渡したい鍵は、env に明示します。trust: true は、そのサーバーの確認を全部飛ばす設定です。
  • Extensionsは、MCP、カスタムコマンド、フック、スキルなどを1つにまとめて配る形式です。公式のギャラリーは「Googleは、これらの拡張の機能や安全性を審査も保証もしない」と書いています。入れる前に中身を読むのが前提です。
  • GitHub Actionの run-gemini-cli には、公式の完成した例(dispatch、review、triage、invoke)があります。信頼できない入力(forkのPR、外部の人のissue)を扱うときの注意が、公式のページに具体的に書かれています。

この記事は、実際に使って確かめた記録ではありません。運営者はGeminiを入れていますが、使い心地はこの記事には書いていません。この記事は、2026年10月24日に公式ドキュメントを読んでまとめたものです。コマンド、設定のキー、YAMLやJSONの例は、公式に書かれたとおりに写しました(空行などの体裁は整えています)。ワークフローのYAMLのうち、公式のファイルを要約の形でしか読めなかったものは、そのとおりに断って「構造」として書き、僕らが部品を組み合わせた例には、そのつど「組み合わせです」と書いています。取得したのはWebFetchによる要約なので、読み切れていない箇所があります。Gemini CLIの導入とGEMINI.md、MCPとExtensionsの概観は前のガイド(04、05)に、承認モード、信頼するフォルダ、サンドボックス、ポリシーは前のガイド(06)に書いたので、ここでは、実際に使う手順に踏み込みます。

先に結論

前提:用語をそろえる

先に確かめること:2026年6月18日の告知

前のガイド(05)に書いたとおり、geminicli.comのほとんどのページの冒頭に、「無料枠とGoogle Oneの利用者は、2026年6月18日にAntigravity CLIへ移った」という趣旨の告知があります。この記事の例は、その告知付きのページ(ヘッドレスは更新2026年3月10日、自動化の手引きは3月9日、拡張のリファレンスは5月14日)に書かれたものです。自分の認証方式が今も使えるかは、先に確かめてください。

ヘッドレス実行:-p で、人のいない場所の入口に立つ

どう始まるか

公式のヘッドレスのページは、ヘッドレスモードを「対話のUIなしで、テキストかJSONを返す仕組み」と説明しています。始まる条件は2つです。TTYのない環境で動かすか、-p(--prompt)で問いを渡すかです。自動化の手引きは、-p なしの位置引数は、入力か出力がパイプやリダイレクトされていない限り、対話モードを始める、と書いています。CLI参照の表では、-p は「標準入力があればその後ろに足され、非対話を強制する」とされています。

公式の例は、次のとおりです。

gemini -p "Write a poem about TypeScript"
cat error.log | gemini -p "Explain why this failed"
git diff | gemini -p "Write a commit message for these changes"

WindowsのPowerShellでは Get-Content error.log | gemini -p "..." と書く、と公式の手引きにあります。

関係するフラグ(CLI参照より)

フラグ 別名 既定 公式の説明の要点
--prompt -p なし 問いの文。標準入力に足される。非対話を強制する
--prompt-interactive -i なし 問いを実行して、そのまま対話に入る
--output-format -o text text、json、stream-json
--approval-mode なし default default、auto_edit、yolo、plan
--allowed-tools なし なし 非推奨。公式は、代わりにポリシーエンジンを案内
--allowed-mcp-server-names なし なし 使ってよいMCPサーバー名(配列)
--extensions -e なし 使う拡張(配列)。省略すると、有効な拡張すべて
--skip-trust なし false このセッションに限り、ワークスペースを信頼する

配列のフラグは、カンマ区切りか、複数回の指定で渡せる、と公式にあります。--yolo(-y)と --allowed-tools は非推奨で、扱いは前のガイド(06)と同じです。

-p が信頼の手前で止まることがあります。 公式の「信頼するフォルダ」のページによると、この機能は既定では無効(security.folderTrust.enabled を true にすると有効)です。有効にしていて、未信頼のフォルダで非対話(ヘッドレス)に動かすと、確認の画面を出せないため、FatalUntrustedWorkspaceError を出して終了します。回避には、--skip-trust を付けるか、環境変数 GEMINI_CLI_TRUST_WORKSPACE=true を設定します。どちらもそのセッションだけで、信頼の決定を保存しません。信頼してよいフォルダかどうかを決めてから使ってください(フォルダの信頼は06を参照)。

出力形式と終了コード

公式のヘッドレスのページに書かれている内容です。

形式 中身
json 1つのJSON。response(最終の答え)、stats(トークン使用量とAPIの遅延)、error(失敗したときの詳細。任意)
stream-json 1行1イベントのJSONL。init(セッションIDとモデル)、message、tool_use、tool_result、error(致命的でない警告)、result(最終の結果と、モデルごとのトークンの内訳)
終了コード 意味
0 成功
1 一般のエラー、またはAPIの失敗
42 入力のエラー(プロンプトや引数が不正)
53 ターン数の上限を超えた

ターン数の上限は、公式のGitHub Actionの例で model.maxSessionTurns が25に設定されています(後の節)。ヘッドレスのページ自体には、この設定の説明は見つかりませんでした。

公式の自動化の手引きにある3つの例

公式の「Automate Tasks with Headless Mode」には、シェルスクリプトの例が3つあります。例2と例3のコードは公式のとおりです(macOS/Linux版)。

例1: フォルダ内のPythonファイルごとに、gemini -p "Generate a Markdown documentation summary for @$file. ..." > "${file%.py}.md" をループで回し、READMEを作る(公式はbashとPowerShellの両方を載せています)。

例2:JSONで結果を受け取り、jq で取り出す。 公式は、--output-format json と jq の組み合わせで、モデルが返した純粋なJSONが得られる、と書いています。

#!/bin/bash

# Ensure we are in a project root
if [ ! -f "package.json" ]; then
  echo "Error: package.json not found."
  exit 1
fi

# Extract data
gemini --output-format json "Return a raw JSON object with keys 'version' and 'deps' from @package.json" | jq -r '.response' > data.json

例3:ステージ済みの差分から、コミットメッセージを作る関数。

function gcommit() {
  # Get the diff of staged changes
  diff=$(git diff --staged)

  if [ -z "$diff" ]; then
    echo "No staged changes to commit."
    return 1
  fi

  # Ask Gemini to write the message
  echo "Generating commit message..."
  msg=$(echo "$diff" | gemini -p "Write a concise Conventional Commit message for this diff. Output ONLY the message.")

  # Commit with the generated message
  git commit -m "$msg"
}

公式は、WindowsのPowerShell版も載せています。なお、例3は、生成された文をそのまま git commit -m に渡します。内容を確かめる手順は公式の例に入っていません(これは僕らの見立てです。履歴に残る文なので、最初は目で確かめてから通すのが無難だと思います)。

承認の扱いは、書かれていない

ここが大事です。公式のヘッドレスのページにも、自動化の手引きにも、ツールの承認(ファイルの書き換えやシェルの実行を、確認なしで通すか)の説明は、読んだ範囲では見つかりませんでした。前のガイド(06)に書いたとおり、ポリシーのページから読めるのは、ask_user が非対話では拒否として扱われること、書き込み系の既定が ask_user であることです。読むだけの用途(要約、説明、差分のレビュー)なら関係が薄く、書き込みをさせたいなら、先に承認の設定を決める必要があります。どう決めるかは、06の「自動化(-p)の場面」を見てください。

MCP:外の道具につなぐ

設定の書き方

公式の「MCP servers」のページは、settings.json の mcpServers に、サーバーごとの設定を書くとしています。基本の形は次のとおりです。

{
  "mcpServers": {
    "serverName": {
      "command": "path/to/server",
      "args": ["--arg1", "value1"],
      "env": {
        "API_KEY": "$MY_API_TOKEN"
      },
      "cwd": "./server-directory",
      "timeout": 30000,
      "trust": false
    }
  }
}

つなぎ方は、書いた項目で決まります。command ならstdio、url ならSSE、httpUrl ならStreamable HTTPです。主な項目は次のとおりです。

項目 公式の説明の要点
command/url/httpUrl どれか1つが必須。起動コマンド、SSEのURL、Streamable HTTPのURL
args、cwd stdioの引数と作業フォルダ
env サーバーに渡す環境変数。$VAR、${VAR}、Windowsは %VAR% も使える。未定義の変数は空文字になる
headers url/httpUrl に付けるHTTPヘッダー
timeout ミリ秒。既定は600,000(10分)
trust true にすると、そのサーバーの道具呼び出しの確認をすべて飛ばす。既定は false
includeTools このサーバーから使う道具の許可リスト
excludeTools モデルから隠す道具。includeTools より優先される

全体の許可と除外は、mcp.allowed(このサーバー名だけつなぐ)と mcp.excluded(このサーバー名にはつながない)で書けます。

公式の手順:GitHubのMCPサーバーをつなぐ(チュートリアルより)

前提は、Gemini CLI、Docker、リポジトリ権限のあるGitHubの個人用アクセストークン(PAT)です。公式は、細かい権限のPATを作り、MetadataとContentsを読み取り、IssuesとPull Requestsを読み書きにする、と書いています。トークンは環境変数に入れます。

export GITHUB_PERSONAL_ACCESS_TOKEN="github_pat_..."

~/.gemini/settings.json(またはプロジェクトの .gemini/settings.json)に、次を足します。

{
  "mcpServers": {
    "github": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "GITHUB_PERSONAL_ACCESS_TOKEN",
        "ghcr.io/github/github-mcp-server:latest"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    }
  }
}

Gemini CLIを再起動し、/mcp list で、✓ github: docker ... - Connected と出れば成功です。Disconnected なら、Dockerが動いているか、トークンが有効かを見る、と公式にあります。使うときは、自然な文章で頼みます(公式の例は「List the open PRs in the google/gemini-cli repository.」)。道具が見つからないときは /mcp reload です。

コマンドで足す:gemini mcp

公式は、settings.json を手で書く代わりのコマンドも用意しています。gemini mcp add は、既定ではプロジェクトの .gemini/settings.json に書き、--scope user で ~/.gemini/settings.json に書けます(-s, --scope)。

# Stdio
gemini mcp add -e API_KEY=123 -e DEBUG=true my-stdio-server /path/to/server arg1 arg2 arg3

# HTTP
gemini mcp add --transport http --header "Authorization: Bearer abc123" secure-http https://api.example.com/mcp/

# SSE
gemini mcp add --transport sse sse-server https://api.example.com/sse/

gemini mcp add には、--include-tools と --exclude-tools(カンマ区切りで道具を絞る)、--trust(確認を全部飛ばす。使う前に下の「確認を飛ばす」の注意を読む)、--timeout、-H, --header(HTTP系)などのフラグもあります(公式のオプション一覧より)。

そのほかに、gemini mcp list(状態の一覧)、gemini mcp remove <name>、gemini mcp enable <name> と disable <name>(設定を消さずに切る。--session で今のセッションだけ)があります。list の注意として、stdioのサーバーは、信頼したフォルダの中でだけ「Connected」と表示される、とあります(フォルダの信頼は06を参照。gemini trust で今のフォルダを信頼する、と公式にあります)。

対話の中では /mcp(list、desc、schema、auth、enable、disable、reload)が使えます。公式の別ページの一覧より。

鍵の扱い:環境変数は、自動で取り除かれる

公式のMCPのページは、サーバーを起動するとき、ホストの環境から機密らしい変数を自動で取り除く、と書いています。対象は、GEMINI_API_KEY、GOOGLE_API_KEY などと、名前に *TOKEN*、*SECRET*、*PASSWORD*、*KEY*、*AUTH*、*CREDENTIAL* を含むものです。一方、サーバーの env に書いた変数は「信頼されたもの」として取り除かれません。公式は、鍵を直接書かず、"MY_KEY": "$MY_KEY" のように展開で渡すよう勧めています。上のGitHubの例が、まさにこの形です。

つまり、サーバーが動かないとき、「鍵がホストの環境にあるのに渡っていない」という原因がありえます。env に明示してあるかを見る、というのは、公式の説明から読める手順です。

使える道具を絞る、確認を飛ばす

道具の絞り込みは、サーバーの設定に "includeTools": ["safe_tool", "file_reader", "data_processor"] のように許可リストを書きます(公式の例の形)。

確認の出方は、trust が true なら出ません。false なら、「今回だけ」「この道具を常に許可」「このサーバーを常に許可」「キャンセル」から選ぶ、と公式にあります。trust について、公式は、完全に自分で管理しているサーバーにだけ使うよう書いています。環境変数の鍵と、権限の広すぎるPATについても、リポジトリをまたいで情報が漏れうる、という注意があります。

名前の付け方

公式は、サーバー名にアンダースコアを使わず、my-server のようにするよう書いています。MCPの道具は mcp_{サーバー名}_{道具名} という名前になり、ポリシーの解釈が、mcp_ の後ろの最初のアンダースコアで分かれるため、アンダースコアがあるとワイルドカードや安全のルールが「黙って効かなくなる」ことがある、とあります。

遠隔のサーバーとOAuth

url か httpUrl のサーバーが401を返すと、CLIが認可の入口を探し、ブラウザを開いてログインさせ、受け取ったトークンを保存します。トークンは ~/.gemini/mcp-oauth-tokens.json に置かれる、と公式にあります。/mcp auth と /mcp auth <サーバー名> で認証できます。

CIでの落とし穴。 公式は、この流れには、ブラウザを開け、http://localhost:<ポート>/oauth/callback へのリダイレクトを受けられる環境が要る、と書いています。ヘッドレスの環境、X11転送のないSSH、ブラウザのないコンテナでは失敗します。つまり、OAuthで入るMCPサーバーは、人のいないCIには、そのままでは向きません(公式の記述からの僕らの読みです)。公式のGitHub Actionの例が、GitHubのMCPサーバーにトークンを環境変数で渡しているのは、この制約と合っています。

このほか、Google Cloudの保護されたサービス向けに、authProviderType の google_credentials(ADC)と service_account_impersonation があります。設定の細部は、公式のページを見てください(僕らは例のうち、google_credentials の形までを確認しました)。

カスタムコマンド:よく使う頼み方を、TOMLに残す

公式の「Custom commands」のページの要点です。

置き場所と名前。 ~/.gemini/commands/(どのプロジェクトでも)と、<project>/.gemini/commands/(そのプロジェクト。リポジトリに入れて共有できる)があります。同じ名前なら、プロジェクト側が使われます。サブフォルダは名前空間になり、git/commit.toml は /git:commit です。編集したら /commands reload、一覧は /commands list です。

書き方(TOML)。 prompt は必須、description(/help に出る一行)は任意です。

差し込み。 公式は3種類を挙げています。

記法 働き 公式の注意
{{args}} コマンド名の後ろに打った文字に置き換わる !{...} の中では、自動でシェル用にエスケープされる
!{...} シェルを実行し、出力をプロンプトに入れる 実行前に確認の画面が出て、引数を埋めた後の実際のコマンドが見える。波かっこは釣り合っている必要がある
@{...} ファイルの中身(フォルダなら再帰)を入れる .gitignore と .geminiignore が有効なら従う。処理の順番は @{}、!{}、{{args}}

{{args}} が書かれていないのに引数が渡されたときは、打った内容全体が、プロンプトの後ろに空行を挟んで足される、とあります。

公式の例の1つは、ステージ済みの差分から、コミットメッセージを作る git/commit.toml です(git diff --staged の出力を !{...} で差し込む形)。拡張の公式チュートリアルにも、検索結果を要約させる例があります。

prompt = """
Please summarize the findings for the pattern `{{args}}`.

Search Results:
!{grep -r {{args}} .}
"""

これは、拡張の中に commands/fs/grep-code.toml として置くと /fs:grep-code "some pattern" になる、と公式にあります。

非対話での動き。 !{...} の確認の画面が、-p のような非対話の実行でどう扱われるかは、読んだ範囲では見つかりませんでした。一方、公式のGitHub Actionの例は、prompt: '/pr-code-review' のように、スラッシュコマンドをそのままプロンプトに渡しています。非対話でもスラッシュコマンドが使える一例です(拡張が持つコマンドの例です)。

他人のTOML。 前のガイド(04)に書いたとおり、他人が作った .toml への注意書きは、見つかりませんでした。!{...} はシェルを走らせるので、他人のものは中身を見てから使うのが無難、というのは僕らの見立てです。

Extensions:まとめて配る、まとめて入れる

探す、入れる、管理する

公式の概要のページは、ギャラリー(geminicli.com/extensions)で探し、GitHubのリポジトリのURLで入れる、と案内しています。

gemini extensions install https://github.com/gemini-cli-extensions/workspace

公式の拡張のリファレンスにあるコマンドです。管理のコマンドは対話の中では使えず、対話では /extensions list を使います。変更は、セッションを再起動した後に効きます。

コマンド 主なフラグ・注意(公式)
gemini extensions install <source> GitHubのURLかローカルのパス。--ref(ブランチ、タグ、コミット)、--auto-update、--pre-release、--consent(確認を飛ばす)、--skip-settings。コピーを入れる。GitHubからは git が要る
gemini extensions enable/disable <name> --scope は user か workspace。既定では全体で有効
gemini extensions update <name>/--all 入れた後の変更を取り込むには、更新が要る
gemini extensions new <path> [template] 雛形から作る(mcp-server、context、custom-commands など)
gemini extensions link <path> 開発中のフォルダへのシンボリックリンク。再インストール不要

CLI参照のページには、これに加えて gemini extensions validate <path> が載っていますが、拡張のリファレンスの表には見つかりませんでした。どの版から使えるかは、読めていません。

ギャラリーの警告。 公式のギャラリーのページは、載っている拡張が公開リポジトリと第三者の開発者のもので、「Googleは、これらの拡張の機能や安全性を審査も、推奨も、保証もしない」と書き、入れる前に、ソースコードと求める権限を調べるよう勧めています。ギャラリーに載せるには、公開のGitHubリポジトリに gemini-cli-extension というトピックを付け、gemini-extension.json をルートに置きます。タグを付けたリポジトリをクローラーが毎日確認し、検証に通れば載る、issueやメールでの申請は要らない、と公式のリリースの手引きにあります(人の審査があるかどうかは、そのページには書かれていません)。つまり「載っている」ことは、安全の目印にはなりません。

中身:gemini-extension.json と置き場所

公式のリファレンスの例(抜粋)です。

{
  "name": "my-extension",
  "version": "1.0.0",
  "description": "My awesome extension",
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["${extensionPath}/my-server.js"],
      "cwd": "${extensionPath}"
    }
  },
  "contextFileName": "GEMINI.md",
  "excludeTools": ["run_shell_command"]
}
置き場所・項目 働き(公式)
mcpServers 起動時に読み込む。同名が settings.json にあれば、settings.json が勝つ。trust 以外のMCPの項目が使える
contextFileName 拡張のフォルダから読む資料。未指定なら、あれば GEMINI.md
excludeTools モデルから隠す道具。"run_shell_command(rm -rf)" のようにコマンド単位でも書ける
commands/ TOMLのコマンド。commands/gcs/sync.toml は /gcs:sync
hooks/hooks.json フック。マニフェストの中には書けない
skills/<名前>/SKILL.md エージェントスキル
agents/*.md サブエージェント。公式は preview feature と書いている
policies/*.toml ポリシーのルール

変数は、gemini-extension.json と hooks/hooks.json の中で、${extensionPath}(拡張のフォルダ)、${workspacePath}、${/}(パスの区切り)が使えます。コマンド名が、ユーザーやプロジェクトのコマンドと重なると、拡張側は /gcp.deploy のように拡張名と点が付きます。

設定と鍵:settings

拡張がAPIキーなどを必要とするときは、settings に書きます。

{
  "name": "my-api-extension",
  "version": "1.0.0",
  "settings": [
    {
      "name": "API Key",
      "description": "Your API key for the service.",
      "envVar": "MY_API_KEY",
      "sensitive": true
    }
  ]
}

sensitive が true なら、値はシステムのキーチェーンに入り、画面ではぼかされます。公式は、拡張とそのMCPサーバーが、シェルの環境をそのまま受け取るわけではなく、HOME、PATH などの安全な標準の変数と、settings の envVar で宣言した変数だけを受け取る、と書いています。必要な変数は、宣言しないと渡りません。

拡張のポリシーは「許可」を増やせない

公式のリファレンスによると、拡張が持つポリシーは、層でいうと2番目(既定より上、ユーザーや管理者より下)です。そして、拡張のポリシーに書いた allow の決定と yolo の設定は、無視されます。拡張が、道具の呼び出しを勝手に自動承認できないようにするためです。公式のポリシーの例は、決定が ask_user のルールでした。

作る手順(公式のチュートリアル)

gemini extensions new my-first-extension mcp-server
cd my-first-extension
npm install
gemini extensions link .

new は、ツールを1つ登録するMCPサーバーの example.js、gemini-extension.json、package.json を作ります。link の後、CLIを再起動して試します。コマンド、GEMINI.md、スキルを足す手順も同じチュートリアルにあります。

配る手順(公式のリリースの手引き)

公式のリリースの手引きは、Gitのリポジトリで配る方法(--ref でブランチ・タグ・コミットを指定でき、既定のブランチを安定版として扱う)と、GitHub Releasesで配る方法(「Latest」のリリースで更新を判定し、プラットフォーム別のバイナリも含められる)を挙げています。更新の判定は、GitHub Releasesならリリースのタグ、Gitのクローンなら git ls-remote で最新のコミットとの比較、ローカルならマニフェストの version の比較です。リポジトリを引っ越すときは、migratedTo を使います。セキュリティの面では、公式のベストプラクティスのページは、権限は必要最小限にし、run_shell_command を使うなら excludeTools で rm -rf * のような危ないコマンドを塞ぎ、MCPサーバーの入力は検証する、と書いています。ただし、同じページには、利用者の同意(コンセント)の案内は見つかりませんでした。

GitHub Action:run-gemini-cli

何ができるか、始め方

公式のREADMEは、GitHubのワークフローにGeminiを組み込み、自律的なエージェント、または @gemini-cli というメンションで呼ぶ協力者として使える、と書いています。PRのレビュー、issueのトリアージ、コードの分析と変更が挙げられています。リポジトリはApache-2.0です。READMEのクイックスタートは5つです。

  1. Google AI StudioでGemini APIキーを取る。
  2. リポジトリのシークレット GEMINI_API_KEY に入れる(Settings > Secrets and variables > Actions)。
  3. .gitignore に次を足す。
# gemini-cli settings
.gemini/

# GitHub App credentials
gha-creds-*.json
  1. ワークフローを選ぶ。Gemini CLIの中で /setup-github を打つか、examples/workflows のものをコピーする。gemini-dispatch.yml は、他のワークフローを呼び出す入口なので、必ず一緒にコピーする。
  2. PRやissueを開くか、@gemini-cli /review、@gemini-cli /triage、または普通の依頼をコメントして試す。

/setup-github の公式の説明は「issueのトリアージとPRのレビューのためのGitHub Actionsを設定する」の一行で、手順は、読んだ範囲では見つかりませんでした。

認証:2つの軸

公式の認証のページは、Google側とGitHub側を分けています。

軸 方法 公式の位置づけ
Google Gemini APIキー いちばん簡単。Google Cloudとの連携は不要
Google Vertex AIのAPIキー 手早い設定。GOOGLE_API_KEY と、変数 GOOGLE_GENAI_USE_VERTEXAI=true
Google Workload Identity Federation 最も安全。GitHubのOIDCトークンを使い、長く使う鍵を保存しない
GitHub 既定の GITHUB_TOKEN APP_ID と APP_PRIVATE_KEY がないとき、自動で使われる。権限は限られ、ジョブが終わると失効する
GitHub 自作のGitHub App 公式は、安全性と細かい制御のために「強く勧める」

公式の例のうち、APIキーとWIFの形は次のとおりです(Vertex AIのキーの例は省きます)。

- uses: 'google-github-actions/run-gemini-cli@v0'
  with:
    prompt: |-
      Explain this code
    gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
- uses: 'google-github-actions/run-gemini-cli@v0'
  with:
    gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
    gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
    gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
    gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
    use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
    prompt: |-
      Explain this code

WIFの設定は、公式が用意したスクリプトで行います。

./scripts/setup_workload_identity.sh --repo "[OWNER]/[REPO]" --project "[GOOGLE_CLOUD_PROJECT]"

公式は、実行するユーザーに、プロジェクトのIAMポリシーの設定や、プールの作成などの権限が要る、と書いています。スクリプトがプールとプロバイダーとサービスアカウントを作り、出力された値を、リポジトリの変数に入れます。サービスアカウントなしの直接WIFは、gcp_token_format: '' にして、gcp_service_account を省く、と公式の注記にあります。Gemini Code Assistを使う方式は、有効なCode Assistの購読が要る、とあります。個人のGoogleログインの扱いは、05に書いたとおりで、確認が要ります。

GitHub Appは、Webhookの「Active」を外し、Contents、Issues、Pull requestsに必要な分だけ権限を付け、秘密鍵(.pem)を保存し、対象のリポジトリにだけ入れます。リポジトリの変数 APP_ID と、シークレット APP_PRIVATE_KEY を設定します(公式の手順より)。

入力(with:)の主なもの

READMEの入力の表から、使う頻度が高いものを選びました。

入力 既定 説明(公式の要点)
prompt You are a helpful assistant. CLIの --prompt に渡す文
settings なし .gemini/settings.json に書かれるJSON。プロジェクトの設定
gemini_api_key なし Gemini APIキー
gemini_cli_version latest latest、preview、nightly、版番号、またはgitのブランチ・タグ・コミット
gemini_model なし 使うモデル
extensions なし 入れるGemini CLIの拡張
upload_artifacts false 成果物をActionの実行に添付する
gemini_debug なし デバッグのログと出力のストリーミング
github_pr_number/github_issue_number イベントから CLIが扱うPRの番号と、issueの番号(カンマ区切りで複数)

出力は、summary(CLIの実行の要約)と error(エラーの出力)です。

READMEの警告が1つあります。環境変数 DEBUG は設定しないでください。Gemini CLIが、Nodeのデバッガーを待って止まってしまいます。デバッグのログを出したいときは、READMEのリポジトリ変数の表にある GEMINI_DEBUG(任意。デバッグログを有効にする)を使います。

extensions の公式の例です。入力の形は「GitHubのURLのJSON配列」で、Actionの実行時に、そのリポジトリから入れられます。

jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - id: gemini
        uses: google-github-actions/run-gemini-cli@v0
        with:
          gemini_api_key: ${{ secrets.GEMINI_API_KEY }}
          prompt: '/security:analyze'
          extensions: |
            [
              "https://github.com/gemini-cli-extensions/security",
              "https://github.com/gemini-cli-extensions/code-review"
            ]

公式の完成したワークフロー4つ

公式のリポジトリの examples/workflows には、4つあります。以下は、僕らが読めた、各ファイルの要約です(YAMLの全文ではありません)。

ワークフロー 働き 読めた構造
dispatch 入口。イベントと @gemini-cli のコマンドで、他を呼び分ける PRのopen、issueのopen、各種コメントで動く。コメントは、投稿者が OWNER、MEMBER、COLLABORATOR のときだけ。forkのPRは対象外
review PRのレビュー workflow_call。タイムアウト7分。権限は contents: read、id-token: write、issues: write、pull-requests: write。公式の拡張 code-review を入れて、プロンプトは /pr-code-review
triage issueにラベルを付ける Geminiはラベルを直接付けない。選んだラベル名を出力し、別のジョブが、リポジトリにあるラベルに限って付ける
invoke(assistant) @gemini-cli への自由な依頼 変更が絡むときは、計画をコメントして、@gemini-cli /approve を待つ

dispatchのコマンドの振り分けは、@gemini-cli /review が review、/triage が triage、/approve が承認、それ以外の @gemini-cli ... が invoke、でした。

入口の条件には、非対称な点があります。公式のdispatchのYAMLを読んだ範囲では、author_association(OWNER、MEMBER、COLLABORATOR)を確かめるのはコメント系のイベントだけで、PRのopen(forkは除外)とissueのopen、reopenには、投稿者の条件がありません。つまり、外部の人が立てたissueでも、triageは動きえます。triageのGemini実行ステップだけ GITHUB_TOKEN を空にしているのは、この入口と合わせて読むと筋が通ります(僕らの見立てです)。「入口」で絞る、「道具」で絞る、「信頼」で絞る、の3つの層を、1つに頼らず重ねる、という整理につながります。

公式のreviewのワークフローの設定(要約)には、安全のための部品が並んでいます。model.maxSessionTurns が25、tools.core は空の配列です。MCPは、ghcr.io/github/github-mcp-server:v0.27.0 というイメージを、バージョンを固定してDockerで起動し、使える道具を3つだけ(add_comment_to_pending_review、pull_request_read、pull_request_review_write)に絞っています。上のチュートリアルは :latest のイメージでしたが、ワークフローの例は版を固定しています。invokeのほうは、includeTools で、読み取りと検索を中心に11個の道具を許可する形でした。

triageのワークフローには、公式のコメントに「信頼できない入力で動くので、認証トークンはここで渡さない」という趣旨の書き込みがあり、Gemini実行のステップの GITHUB_TOKEN は空にされていました。そして、Geminiの出力したラベルを、リポジトリのラベル一覧で絞り込んでから、別のジョブが付けます。僕らが読んだ要約では、これはプロンプトインジェクションへの備えとして説明されていました。この構造は、僕らが「AIの出力をそのまま権限のある操作に使わない」形として、いちばん参考になると考える部分です(僕らの見立てです)。

信頼できない入力:公式の書いていること

公式のGitHub Actionの「信頼」のページ(trust guidance)の趣旨です。

PRレビューのREADMEには、forkの扱いがあります。forkは、悪意ある人が作れるので、既定では動かしません。許可する方法は2つです。dispatchのforkの判定を外し、貢献者が自分のGoogle認証を設定する方法と、pull_request_target を使う方法です。後者について、公式は「細心の注意なく使うと、脆弱性になりうる」と警告しています。ベストプラクティスには、main ブランチの保護(PR必須、承認数、古い承認の取り消し、ステータスチェック)、CODEOWNERS、WIFの利用、秘密を書かないこと、最小権限、OpenTelemetryでの監視、そしてAction自体の版の固定(例:uses: google-github-actions/run-gemini-cli@v0)が並んでいます。なお、公式の例の @v0 は、メジャーの目印のタグで、コミットのSHAではありません。これで「特定の版」の勧めを満たすのかは、公式のページに書かれていません。リリースのページでは、最新が v0.1.22(4月24日付と表示)でした。

CIでの組み立て:公式の部品を、重ねる

ここからは、僕らの整理です。公式の例を読んで、「無人で動かす」ときに決めることを、層に分けました。

層 決めること 公式の部品
入口 誰の、どの操作で動くか dispatchのif条件、author_association、forkの除外
認証 Googleと、GitHubの鍵をどう渡すか WIF、GitHub App、GITHUB_TOKEN の permissions
道具 何を触れるか tools.core、MCPの includeTools、拡張の excludeTools、ポリシー
上限 どこで止めるか model.maxSessionTurns、timeout-minutes、終了コード 53
出力 AIの答えを、どう使うか summary、--output-format json、出力を許可リストで絞る
信頼 未信頼の入力か GEMINI_CLI_TRUST_WORKSPACE、最小権限

下は、上の公式の部品(認証の例、settings、permissions)を、僕らがつなげた最小の例です。公式にこの形のまとまった例があるわけではなく、動かしても確かめていません。settings の中身は、公式のreviewのワークフローの設定の一部です。

name: gemini-readonly-summary
on:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  summarize:
    runs-on: ubuntu-latest
    timeout-minutes: 7
    steps:
      - uses: actions/checkout@v4
      - id: gemini
        uses: google-github-actions/run-gemini-cli@v0
        with:
          gemini_api_key: ${{ secrets.GEMINI_API_KEY }}
          prompt: 'Summarize the open TODO comments in this repository.'
          settings: |-
            {
              "model": { "maxSessionTurns": 25 },
              "tools": { "core": [] }
            }

この例は、人が手で起動する(workflow_dispatch)、リポジトリは読むだけ、ターン数とタイムアウトに上限、という形にしています。tools.core を空にした場合に、実際にどの道具が使えるかは、公式のreviewの例が空にしている、ということ以上は読めていません。動かす前に、自分の版で、安全なリポジトリで確かめてください。

最初の10分でやること

  1. 前提の確認(2分)。 使っている認証方式が今も使えるか。gemini --version の後、gemini -p "Say hello" が通るか。
  2. ヘッドレスを試す(3分)。 git diff | gemini -p "Summarize these changes" のように、読むだけの用途で動かす。次に --output-format json を付けて、jq -r '.response' で取り出す。終了コードは echo $? で見る。信頼するフォルダを有効にしている場合は、FatalUntrustedWorkspaceError で止まることがある(上の「-p が信頼の手前で止まる」を参照)。
  3. MCPを1つだけつなぐ(3分)。 公式のチュートリアルのGitHubの例を、まず読み取り中心のPATで。/mcp list で Connected を確かめ、includeTools で道具を絞る。サーバー名にアンダースコアを入れない。
  4. カスタムコマンドを1つ作る(1分)。 ~/.gemini/commands/ に、prompt だけの .toml を置き、/commands reload。
  5. Actionは、後で。 先に、手元のヘッドレスと、道具の絞り込みが分かってから。GitHub Actionは、workflow_dispatch で、読むだけのリポジトリから。

気をつけること

出典