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

> Source: <https://dev.to/jimmyliao/gemini-api-cli-official-guide-part-1-giving-your-ai-agent-a-stateless-multimodal-cli-toolbox-36p3>
> Published: 2026-11-15 01:15:23+00:00

**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**

- ▶️
**70-second Walkthrough Video (YouTube 16:9)**: [https://youtu.be/Rb5ij419w2Y](https://youtu.be/Rb5ij419w2Y)
- ⚡
**13-second Highlight (YouTube Shorts 9:16)**: [https://youtube.com/shorts/82-Z_Jq-ezQ](https://youtube.com/shorts/82-Z_Jq-ezQ)
- 📱
**Facebook Reel (9:16)**: [https://www.facebook.com/reel/1484807533581243/](https://www.facebook.com/reel/1484807533581243/)
- 🇹🇼
**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)

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

Developers can now adopt a clean **two-track architecture**:

`agy` (or Codex / Claude Code) as the Agent Brain & Host`gemini-api` as the Stateless Multimodal CLI Toolbox`google-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](https://aistudio.google.com/docs/cli#install).

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"
# OR interactive OS Keychain storage:
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/`](https://github.com/google-gemini/gemini-api-cli/tree/2030ff1/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](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.

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