cd /news/ai-agents/gemini-api-cli-official-guide-part-1… · home › topics › ai-agents › article
[ARTICLE · art-169771] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Gemini API CLI Official Guide (Part 1): Giving Your AI Agent a Stateless Multimodal CLI Toolbox

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.

by read8 min views4 publishedNov 15, 2026

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.

🎬 Video & Bilingual Navigation

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 for the exact scope.

Developers can now adopt a clean two-track architecture:

agy (or Codex / Claude Code) as the Agent Brain & Hostgemini-api as the Stateless Multimodal CLI Toolboxgoogle-gemini/gemini-api-cli) Here, 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.

gemini-api ships as a standalone Go binary. On macOS or Linux, install it using the official installer script:

curl -fsSL https://raw.githubusercontent.com/google-gemini/gemini-api-cli/main/scripts/install.sh | bash
command -v gemini-api
gemini-api --version

On 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:

export PATH="$HOME/.local/bin:$PATH"

Because latest tracks newer releases over time, pin GEMINI_VERSION in CI per the official CLI installation docs.

For standard authentication, use either an environment variable or interactive configuration (choose one; no need to mix both):

export GEMINI_API_KEY="YOUR_API_KEY"
gemini-api configure
gemini-api whoami

Note 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.

AI 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.

First, probing the documentation page itself via curl -sS -I https://aistudio.google.com/docs/cli returns:

content-type: text/markdown; charset=utf-8
x-llms-txt: /llms.txt
link: </llms.txt>; rel="llms-txt", </llms-full.txt>; rel="llms-full-txt"

On the binary side, four introspection flags govern agent self-discovery:

gemini-api --usage                 # Complete KDL command tree
gemini-api generate --schema       # Request body JSON Schema
gemini-api agent run --schema
gemini-api generate "Test prompt" --dry-run -o json

Caveat 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.

Dry-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.

While the CLI supports both JSON and TOON structured output, gemini-api v0.4.6 always emits a JSON request envelope under --dry-run:

{"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}}}

Built-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:

gemini-api generate "Test prompt" --dry-run -o json | jq -r '.request.body.model'

Full dummy-key dry-run traces and HTTP header checks are archived in experiments/02-part1-standard-workflows/sample-dry-runs.md.

Using 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):

cd experiments/02-part1-standard-workflows
gemini-api generate "Test prompt" --dry-run --output-format json
gemini-api analyze -i input.txt "Summarize" --dry-run
gemini-api image "Minimalist cloud database icon" --out /tmp/gapi-test.jpg --dry-run
gemini-api tts "Welcome to the Taiwan developer community" --out voice.wav --dry-run
gemini-api transcribe -i silence.wav --out transcript.md --dry-run
gemini-api video "A cloud above Taipei" --out cloud.mp4 --dry-run

Every subcommand targets POST https://generativelanguage.googleapis.com/v1beta/interactions. Understanding how their JSON bodies differ explains how to wire multimodal pipelines:

Command Default Model ( v0.4.6 ) Key Request Payload Observation
generate gemini-3.8-flash input string,stream:true
analyze gemini-3.8-flash user_input.content array containing text/media + prompt,store:false ,stream:false
image gemini-nano-banana-2.1 response_format:{"type":"image"} ,stream:false
tts gemini-3.8-flash-tts response_format.type:audio ,speech_config:[{"voice":"Kore"}] ,store:false
transcribe gemini-3.5-transcribe audio/wav input,transcription_config.mode.type:verbatim , diarization & word timestamps
video gemini-omni-1.2-flash response_format.type:video ,background:true ,stream:false

File 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:

{
  "generation_config": {"speech_config": [{"voice": "Kore"}]},
  "input": [{"content": [{"text": "Welcome to the Taiwan developer community", "type": "text"}], "type": "user_input"}],
  "model": "gemini-3.8-flash-tts",
  "response_format": {"type": "audio"},
  "store": false,
  "stream": false
}

Output 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.

Our running scenario—"Understand in 15 Seconds Why AI Agents Need a Multimodal CLI Toolbox"—chains these primitives into a version-controlled pipeline:

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. See examples/reels-storyboard-pipeline/run-reels-pipeline.sh and the verbatim trace examples/reels-storyboard-pipeline/dry-run-trace.md.

sample-part1-reels-primitives.sh) Run directly from the workspace root (examples/part1-multimodal-cli/sample-part1-reels-primitives.sh); synthetic fixtures/* validate MIME handling without incurring API charges:

bash <<'PART_SAMPLE'
(
set +x
set -euo pipefail
cd examples/part1-multimodal-cli
unset GEMINI_API_KEY GEMINI_ACCESS_TOKEN GEMINI_ENVIRONMENT_KEY GEMINI_USER_PROJECT
export GEMINI_NO_KEYRING=true
R=../reels-storyboard-pipeline
echo 'Step: offline schema discovery' >&2
gemini-api video --schema --dry-run </dev/null
echo 'Step: storyboard, keyframes, and style continuity (synthetic MIME fixtures)' >&2
gemini-api generate --stream=false --stdin 'Generate a 3-scene storyboard from the brief:' --dry-run < "$R/storyboard-brief.txt"
gemini-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
gemini-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
echo 'Step: video, dual-speaker voiceover, music, and captions' >&2
gemini-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
gemini-api tts --multi-speaker "Host=Kore,CoHost=Puck" -f "$R/dialogue.txt" --out /tmp/part1-voice.wav --dry-run </dev/null
gemini-api music 'Tech short background music' --out /tmp/part1-music.wav --dry-run </dev/null
gemini-api transcribe --format srt -i "$R/fixtures/voiceover-sample.wav" --out /tmp/part1-captions.srt --dry-run </dev/null
echo 'Step: keyframe & storyboard QA' >&2
gemini-api analyze -i "$R/fixtures/scene1-keyframe.png" -i "$R/storyboard.json" 'Check Reels safe-zone and storyboard alignment' --dry-run </dev/null
)
PART_SAMPLE

Beyond direct model primitives, gemini-api can launch server-managed Interactions API agents:

gemini-api agent run "Compare WebRTC SFU architectures" \
  --agent deep-research-preview-04-2026 \
  --background --stream=false --dry-run

Inspecting the upstream source snapshot (2030ff1) under internal/sdk/models/interactions/ reveals several typed agent configurations alongside Deep Research:

AntigravityAgentConfig (type:"antigravity", model, max_total_tokens) CodeMenderAgentConfig (type:"code-mender", FIND/FIX request & session controls) DynamicAgentConfig (type:"dynamic") Important boundary: SDK type definitions do not guarantee account entitlement, nor does logging into agy locally automatically authorize API Managed Agents.

Similarly, the Self-Hosted Environments docs and Agent Substrate example (ate-gemini) 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.

Want 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.

2026-11-15): Full §4.1 Reels Run & Cost Ledger Following 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:

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 polls44,934 tokens4,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. Full 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.

── more in #ai-agents 4 stories · sorted by recency
── more on @google 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/gemini-api-cli-offic…] indexed:0 read:8min 2026-11-15 · —