{"slug": "gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal", "title": "Gemini API CLI Official Guide (Part 1): Giving Your AI Agent a Stateless Multimodal CLI Toolbox", "summary": "A developer documented a two-track architecture for AI agents using Google's gemini-api CLI (v0.4.6), a standalone Go binary that serves as a stateless multimodal toolbox alongside an agent host such as Antigravity CLI, Codex, or Claude Code. The guide covers installation, API key or OS Keychain authentication, and machine-discoverable schemas designed to prevent agents from tripping over stale flags, dumping raw base64 media into context, or hanging on interactive prompts. It also notes that Google's consumer gemini-cli access for free personal and Google AI Pro/Ultra accounts transitioned to Antigravity CLI (agy) on June 18, 2026.", "body_md": "**Verified environment**: `2026-11-14 21:53` (Asia/Taipei, UTC+8) on macOS Apple Silicon (`ts-m1`), `gemini-api 0.4.6` (supplemented by our `2026-11-15` live Paid Tier run documented in Section 7). Built for both international developers (Dev.to) and the Taiwan / APAC developer community & GDE workshops.\n\n🎬 **Video & Bilingual Navigation**\n\n- ▶️\n**70-second Walkthrough Video (YouTube 16:9)**: [https://youtu.be/Rb5ij419w2Y](https://youtu.be/Rb5ij419w2Y)\n- ⚡\n**13-second Highlight (YouTube Shorts 9:16)**: [https://youtube.com/shorts/82-Z_Jq-ezQ](https://youtube.com/shorts/82-Z_Jq-ezQ)\n- 📱\n**Facebook Reel (9:16)**: [https://www.facebook.com/reel/1484807533581243/](https://www.facebook.com/reel/1484807533581243/)\n- 🇹🇼\n**Original Traditional Chinese Edition (Substack)**: [https://memo.jimmyliao.net/p/gemini-api-cli-part-1-agent-api](https://memo.jimmyliao.net/p/gemini-api-cli-part-1-agent-api)\n\n**June 18, 2026** marks a watershed moment for Google's individual developer CLI entry points: `gemini-cli` consumer access for free personal accounts and Google AI Pro/Ultra (Google One) plans transitioned to **Antigravity CLI (`agy`)**. That transition applies to specific personal/consumer account scopes and should not be oversimplified as every `gemini-cli` mode or enterprise/paid API path disappearing overnight. See the [official Google blog announcement](https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/) for the exact scope.\n\nDevelopers can now adopt a clean **two-track architecture**:\n\n`agy` (or Codex / Claude Code) as the Agent Brain & Host`gemini-api` as the Stateless Multimodal CLI Toolbox`google-gemini/gemini-api-cli`)\nHere, **stateless** means the CLI binary itself does not maintain hidden local chat history between runs; the underlying Interactions API can still persist server-side interactions, resume via `--previous-interaction-id`, or run background jobs. Mistaking \"stateless CLI\" for \"no server-side state exists\" leads to misdesigning multi-turn media pipelines.\n\n`gemini-api` ships as a standalone Go binary. On macOS or Linux, install it using the official installer script:\n\n```\ncurl -fsSL https://raw.githubusercontent.com/google-gemini/gemini-api-cli/main/scripts/install.sh | bash\ncommand -v gemini-api\ngemini-api --version\n```\n\nOn `ts-m1` (Darwin / `arm64`), the installer skipped `/usr/local/bin` (non-writable) and installed `/Users/jimmyliao/.local/bin/gemini-api` (`v0.4.6`; build timestamp `2026-11-11 02:46:39 Asia/Taipei`). Ensure `$HOME/.local/bin` is on your `PATH`:\n\n```\nexport PATH=\"$HOME/.local/bin:$PATH\"\n```\n\nBecause `latest` tracks newer releases over time, pin `GEMINI_VERSION` in CI per the [official CLI installation docs](https://aistudio.google.com/docs/cli#install).\n\nFor standard authentication, use either an environment variable or interactive configuration (**choose one**; no need to mix both):\n\n```\nexport GEMINI_API_KEY=\"YOUR_API_KEY\"\n# OR interactive OS Keychain storage:\ngemini-api configure\ngemini-api whoami\n```\n\nNote that `configure` stores secrets in your OS Keychain, whereas `--no-keyring` / `GEMINI_NO_KEYRING=true` alters secret resolution and should not be casually enabled without understanding the boundary. In our clean isolation harness, every subshell explicitly unset `GEMINI_API_KEY` / `GEMINI_ACCESS_TOKEN` and exported `GEMINI_NO_KEYRING=true`; `gemini-api whoami` reported both credentials `[unset]` and API version `v1beta`. Crucially, `whoami` inspects local configuration sources—it does **not** prove remote API entitlement or quota. See `experiments/01-cli-introspection/results.md` for the full capture.\n\nAI agents routinely trip over stale CLI flags, dump raw base64 media into context windows, or hang forever on interactive prompts. `gemini-api` avoids those traps with machine-discoverable schemas and direct file I/O.\n\nFirst, probing the documentation page itself via `curl -sS -I https://aistudio.google.com/docs/cli` returns:\n\n```\ncontent-type: text/markdown; charset=utf-8\nx-llms-txt: /llms.txt\nlink: </llms.txt>; rel=\"llms-txt\", </llms-full.txt>; rel=\"llms-full-txt\"\n```\n\nOn the binary side, four introspection flags govern agent self-discovery:\n\n```\ngemini-api --usage                 # Complete KDL command tree\ngemini-api generate --schema       # Request body JSON Schema\ngemini-api agent run --schema\ngemini-api generate \"Test prompt\" --dry-run -o json\n```\n\nCaveat from our `v0.4.6` introspection: `--schema` is **not** uniform across every subcommand. `generate`, `image`, `video`, and `agent run` succeeded, while `analyze`, `tts`, and `transcribe` returned `exit code 2` (`unknown flag: --schema`). Inspect each subcommand's `--help` first, and check `agent run --schema` whenever you need full request body fidelity.\n\nDry-run redaction was also verified: passing a synthetic dummy `--api-key` outputs `\"X-Goog-Api-Key\": [\"[REDACTED]\"]`. Note carefully that `--dry-run` validates local request construction—it does **not** verify server model access, billing, or IAM permissions.\n\nWhile the CLI supports both JSON and TOON structured output, **`gemini-api v0.4.6` always emits a JSON request envelope under `--dry-run`**:\n\n```\n{\"dry_run\":true,\"request\":{\"method\":\"POST\",\"url\":\"https://generativelanguage.googleapis.com/v1beta/interactions\",\"headers\":{\"Accept\":[\"text/event-stream\"],\"Content-Type\":[\"application/json\"],\"User-Agent\":[\"google-genai-cli/0.4.6 gl-go/go1.26.10\"]},\"body\":{\"input\":\"Test prompt\",\"model\":\"gemini-3.8-flash\",\"stream\":true}}}\n```\n\nBuilt-in `--jq` also has a quirk under `--dry-run`: running `generate \"Test prompt\" --dry-run --jq '.body.model'` still prints the full envelope (and flips `stream` to `false`). Pipe `-o json` into external `jq` instead when filtering dry-run payloads:\n\n```\ngemini-api generate \"Test prompt\" --dry-run -o json | jq -r '.request.body.model'\n```\n\nFull dummy-key dry-run traces and HTTP header checks are archived in `experiments/02-part1-standard-workflows/sample-dry-runs.md`.\n\nUsing synthetic local fixtures (`input.txt` 64 bytes, `silence.wav` 0.1s 16 kHz mono PCM), all six core commands succeeded cleanly under `--dry-run` (`exit code 0`):\n\n```\ncd experiments/02-part1-standard-workflows\ngemini-api generate \"Test prompt\" --dry-run --output-format json\ngemini-api analyze -i input.txt \"Summarize\" --dry-run\ngemini-api image \"Minimalist cloud database icon\" --out /tmp/gapi-test.jpg --dry-run\ngemini-api tts \"Welcome to the Taiwan developer community\" --out voice.wav --dry-run\ngemini-api transcribe -i silence.wav --out transcript.md --dry-run\ngemini-api video \"A cloud above Taipei\" --out cloud.mp4 --dry-run\n```\n\nEvery subcommand targets `POST https://generativelanguage.googleapis.com/v1beta/interactions`. Understanding how their JSON bodies differ explains how to wire multimodal pipelines:\n\n| Command | Default Model ( `v0.4.6` ) | Key Request Payload Observation | \n|---|---|---|\n| `generate` | `gemini-3.8-flash` | `input` string,`stream:true` | \n| `analyze` | `gemini-3.8-flash` | `user_input.content` array containing text/media + prompt,`store:false` ,`stream:false` | \n| `image` | `gemini-nano-banana-2.1` | `response_format:{\"type\":\"image\"}` ,`stream:false` | \n| `tts` | `gemini-3.8-flash-tts` | `response_format.type:audio` ,`speech_config:[{\"voice\":\"Kore\"}]` ,`store:false` | \n| `transcribe` | `gemini-3.5-transcribe` | `audio/wav` input,`transcription_config.mode.type:verbatim` , diarization & word timestamps | \n| `video` | `gemini-omni-1.2-flash` | `response_format.type:video` ,`background:true` ,`stream:false` | \n\nFile bytes never bloat agent context on `--dry-run`: `analyze` summarizes files as `\"text\":\"<bytes:64>\"` and audio as `\"data\":\"<bytes:3244>\"`. Abbreviated TTS request body observed on `v0.4.6`:\n\n```\n{\n  \"generation_config\": {\"speech_config\": [{\"voice\": \"Kore\"}]},\n  \"input\": [{\"content\": [{\"text\": \"Welcome to the Taiwan developer community\", \"type\": \"text\"}], \"type\": \"user_input\"}],\n  \"model\": \"gemini-3.8-flash-tts\",\n  \"response_format\": {\"type\": \"audio\"},\n  \"store\": false,\n  \"stream\": false\n}\n```\n\nOutput handling flags such as `--out` remain client-side and stay out of the HTTP body. Per `--help`, `tts` outputs 24 kHz mono PCM WAV (adjusting `.mp3` targets back to `.wav`), `transcribe` supports `md`, `text`, `json`, and `srt`, and `video` waits on background completion unless `--async` is passed.\n\nOur running scenario—*\"Understand in 15 Seconds Why AI Agents Need a Multimodal CLI Toolbox\"*—chains these primitives into a version-controlled pipeline:\n\n`generate --stdin` creates the 3-scene 9:16 breakdown.`image --aspect-ratio 9:16 --image-size 1K` generates Scene 1, followed by `image -i scene1-keyframe.jpg` to preserve character and visual style into Scene 2 (`--previous-interaction-id` can also continue live server interactions).`video --aspect-ratio 9:16 --resolution 720p -i` turns the approved Scene 1 keyframe into motion (`background:true`).` tts --multi-speaker \"Host=Kore,CoHost=Puck\"`.` music` + `transcribe --format srt`.` analyze` inspects the 9:16 composition against `storyboard.json`.\nSee `examples/reels-storyboard-pipeline/run-reels-pipeline.sh` and the verbatim trace `examples/reels-storyboard-pipeline/dry-run-trace.md`.\n\n`sample-part1-reels-primitives.sh`)\nRun directly from the workspace root (`examples/part1-multimodal-cli/sample-part1-reels-primitives.sh`); synthetic `fixtures/*` validate MIME handling without incurring API charges:\n\n```\nbash <<'PART_SAMPLE'\n(\nset +x\nset -euo pipefail\ncd examples/part1-multimodal-cli\nunset GEMINI_API_KEY GEMINI_ACCESS_TOKEN GEMINI_ENVIRONMENT_KEY GEMINI_USER_PROJECT\nexport GEMINI_NO_KEYRING=true\nR=../reels-storyboard-pipeline\necho 'Step: offline schema discovery' >&2\ngemini-api video --schema --dry-run </dev/null\necho 'Step: storyboard, keyframes, and style continuity (synthetic MIME fixtures)' >&2\ngemini-api generate --stream=false --stdin 'Generate a 3-scene storyboard from the brief:' --dry-run < \"$R/storyboard-brief.txt\"\ngemini-api image 'Taipei tech Reels keyframe' --aspect-ratio 9:16 --image-size 1K --output-mime-type image/jpeg --out /tmp/part1-scene1.jpg --dry-run </dev/null\ngemini-api image 'Continue Scene 1 style' -i \"$R/fixtures/scene1-keyframe.png\" --aspect-ratio 9:16 --image-size 1K --output-mime-type image/jpeg --out /tmp/part1-scene2.jpg --dry-run </dev/null\necho 'Step: video, dual-speaker voiceover, music, and captions' >&2\ngemini-api video 'Slow camera push on keyframe' --aspect-ratio 9:16 --resolution 720p -i \"$R/fixtures/scene1-keyframe.png\" --out /tmp/part1-scene1.mp4 --dry-run </dev/null\ngemini-api tts --multi-speaker \"Host=Kore,CoHost=Puck\" -f \"$R/dialogue.txt\" --out /tmp/part1-voice.wav --dry-run </dev/null\ngemini-api music 'Tech short background music' --out /tmp/part1-music.wav --dry-run </dev/null\ngemini-api transcribe --format srt -i \"$R/fixtures/voiceover-sample.wav\" --out /tmp/part1-captions.srt --dry-run </dev/null\necho 'Step: keyframe & storyboard QA' >&2\ngemini-api analyze -i \"$R/fixtures/scene1-keyframe.png\" -i \"$R/storyboard.json\" 'Check Reels safe-zone and storyboard alignment' --dry-run </dev/null\n)\nPART_SAMPLE\n```\n\nBeyond direct model primitives, `gemini-api` can launch server-managed Interactions API agents:\n\n```\ngemini-api agent run \"Compare WebRTC SFU architectures\" \\\n  --agent deep-research-preview-04-2026 \\\n  --background --stream=false --dry-run\n```\n\nInspecting the upstream source snapshot (`2030ff1`) under [` internal/sdk/models/interactions/`](https://github.com/google-gemini/gemini-api-cli/tree/2030ff1/internal/sdk/models/interactions) reveals several typed agent configurations alongside Deep Research:\n\n`AntigravityAgentConfig` (`type:\"antigravity\"`, `model`, `max_total_tokens`)` CodeMenderAgentConfig` (`type:\"code-mender\"`, FIND/FIX request & session controls)` DynamicAgentConfig` (`type:\"dynamic\"`)\n**Important boundary**: SDK type definitions do not guarantee account entitlement, nor does logging into `agy` locally automatically authorize API Managed Agents.\n\nSimilarly, the [Self-Hosted Environments docs](https://github.com/google-gemini/gemini-api-cli/tree/2030ff1/docs/self-hosted) and [Agent Substrate example (`ate-gemini`)](https://github.com/google-gemini/gemini-api-cli/tree/2030ff1/docs/self-hosted/agent-substrate) outline running tool execution on your own Kubernetes/gVisor compute using either `environments connect` (single worker) or `environments poll` + `environments serve` (short-lived lease tokens so sandboxes never hold project API keys). Remember the security division: `ate-gemini` validates component mTLS, while multi-tenant user authentication and ACL enforcement remain your application's responsibility.\n\nWant to stop distributing plaintext `GEMINI_API_KEY` secrets across laptops and containers? In Part 2, we inspect the Keyless OAuth path (`GEMINI_ACCESS_TOKEN` + `--user-project`), troubleshoot `ACCESS_TOKEN_SCOPE_INSUFFICIENT`, ship a safe wrapper (` bin/gapi-adc`), and map Free Tier, Paid Tier 1–3, and Google AI Pro/Ultra boundaries.\n\n`2026-11-15`): Full §4.1 Reels Run & Cost Ledger\nFollowing the `--dry-run` validation above, we executed all 8 §4.1 multimodal steps **live** against project `gde-jimmyliao-redeem` (Paid Tier) inside `tmux` (`2026-11-15 00:20:54` → `00:24:23 Asia/Taipei`) and assembled the final 9:16 video with burned-in bilingual subtitles using local `ffmpeg 8.1`:\n\n`gemini-3.8-flash` (storyboard & QA), `gemini-nano-banana-2.1` (Scene 1 & Scene 2 `768×1376` keyframes with crisp Traditional Chinese + English labels), `gemini-omni-1.2-flash` (`5.03s` 720p video at `$0.3527`), `gemini-3.8-flash-tts` (`9.44s` dual-speaker voiceover), `lyria-3.5` (`159.48s` track), and `gemini-3.5-transcribe` all succeeded on the first call (`Exit 0`).`$0` `agent status` polls`44,934` tokens`4,506` input + `35,407` output + `5,021` thought) for a calculated total of `$0.54853125 USD` (`~$0.5485`)`~$0.705 USD` by skipping redundant video renders on Scenes 2 & 3.`gemini-api music --out bgm.wav` wrote `audio/mpeg` (MP3, `\"extension_mismatch\": true`) instead of uncompressed WAV, and `\"先驗首幀\"` (`\"先验手针\"`—reinforcing why subtitle review matters before publishing.\nFull per-call formulas and verified deliverables are in `experiments/06-live-execution-and-cost-log/cost-and-call-ledger.md` and `examples/reels-storyboard-pipeline/output/final-reel.mp4`.", "url": "https://wpnews.pro/news/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal", "canonical_source": "https://dev.to/jimmyliao/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal-cli-toolbox-36p3", "published_at": "2026-11-15 01:15:23+00:00", "updated_at": "2026-11-15 01:21:30.434103+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models", "ai-products"], "entities": ["Google", "gemini-api CLI", "Antigravity CLI", "gemini-cli", "Claude Code", "Codex", "Google AI Pro", "Jimmy Liao"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal", "markdown": "https://wpnews.pro/news/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal.md", "text": "https://wpnews.pro/news/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal.txt", "jsonld": "https://wpnews.pro/news/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal.jsonld"}}