About gemini-api-cli
gemini-api-cli is a shell CLI for accessing Gemini API resources, media generation, analysis, transcription, agents, and sandboxes. It is intended for terminal, script, and CI use rather than application code, which the README directs to Google GenAI SDKs.
Key features
- 01Shell commands for Gemini API resources
- 02Generate image, audio, and video files
- 03Analyze documents and media
- 04Transcribe recordings
- 05Manage agents and sandboxes
- 06Built-in JSON filtering and dry runs
Use cases
- 01Generate media files from scripts
- 02Analyze local PDFs or recordings
- 03Run Deep Research from a terminal
- 04Manage remote agent workspaces
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ google-gemini/ gemini-skills --skill gemini-api-cliAfter installing, type/gemini-api-cliin Claude Code to confirm it loaded.
Details
From the project READMEThe gemini-api CLI exposes every Gemini API resource as a shell subcommand. Compared to curl: media and transcription commands decode output to disk and print only the file path, -i attaches local files or files/<id> URIs, --jq extracts fields in-process (raw strings by default, no external jq), --dry-run previews redacted HTTP requests offline, and list endpoints auto-paginate with --all (cap pages with --max-pages N; --page-size sets server page size).
CLI vs SDK
CLI for shell work, SDK for application code. Use gemini-api from terminals, scripts, and CI jobs to generate media files, analyze local PDFs or recordings, run Deep Research, and manage agent sandboxes (gemini-api is a stateless Gemini API client, distinct from the interactive @google/gemini-cli coding agent). Use the Google GenAI SDKs (gemini-api-dev, gemini-live-api-dev) when calls live inside application source or need bidirectional Live API WebSockets.
Install and auth
# macOS / Linux (set GEMINI_VERSION=<tag> to pin a release)
curl -fsSL https://raw.githubusercontent.com/google-gemini/gemini-api-cli/main/scripts/install.sh | bash
Credentials resolve in order (first match wins): --api-key / --access-token flags, GEMINI_API_KEY / GEMINI_ACCESS_TOKEN env vars, the OS keychain, then ~/.config/gemini-api/config.yaml.
- Env var (agents and CI):
export GEMINI_API_KEY="..." - Workstation key:
gemini-api configure --api-key "..."saves to the OS keychain. Pass--no-keyringorGEMINI_NO_KEYRING=1on headless Linux to useconfig.yaml;gemini-api auth logoutclears stored keys. - Active auth check:
gemini-api whoami(add-o jsonfor JSON) prints masked credentials and the winning source.
The #1 auth trap: an exported
GEMINI_API_KEYoverrides credentials stored in the keychain orconfig.yaml, billing whichever project that env var belongs to. Checkgemini-api whoamito see which source won, or runenv -u GEMINI_API_KEY gemini-api ...to ignore the env var.
Command structure
gemini-api <intent> [prompt] [flags] # task commands with model and modality presets
gemini-api <resource> <action> [flags] # REST resource groups
Run gemini-api --help to list commands, or <subcommand> --help for flags and examples (--usage dumps a 45 KB KDL spec, so stick to --help to save context).
| Command | Key flags / actions | Default model & behavior |
|---|---|---|
generate [prompt] | -m, -i, --stdin, --system, --previous-interaction-id, --stream=false, --body | gemini-3.8-flash; streams text deltas to stdout |
image [prompt] | -m, -i, --aspect-ratio, --image-size (512..4K), --previous-interaction-id, --out | gemini-nano-banana-2.1; writes image, prints path |
tts [text] | -f, --stdin, --voice (default Kore), --multi-speaker, --language, --out | gemini-3.8-flash-tts; writes 24 kHz WAV, prints path (unstored) |
music [prompt] | -m, -f, --stdin, --out, --body | lyria-3.5; writes audio track, prints path |
video [prompt] | -m, -i, --aspect-ratio, --resolution (360p..4k), --async, --resume, --out | gemini-omni-1.1-flash; polls until done, writes MP4, prints path |
analyze [question] | -i (required, repeatable), --stdin, --system, -m | gemini-3.8-flash; answers over PDFs, media, CSV/text, YouTube URLs (unstored) |
transcribe | -i (required, repeatable), --format (md, text, json, srt), --no-speakers, --no-timestamps, --out | gemini-3.8-flash; writes --out (or ./transcript-*), prints path (unstored) |
agent | run, status, cancel, delete-interaction; create, list, get, delete | Runs models or managed agents; manages custom agent definitions |
files | upload [--wait], list, get, generated-files-list, register, delete | Uploads reusable files/<id> URIs (48h TTL; up to 2 GB, 50 MB PDFs) |
models | (bare), list [--all], get <id> | Bare models prints an offline catalog; list and get query the live API |
environments | create, list, get, delete, files, connect, poll, serve | Remote sandboxes and workspace snapshots (credentials, webhooks, triggers for agent infra) |
Model selection: use gemini-3.8-flash (default), gemini-4-argon (hard reasoning and coding), or gemini-3.5-flash-lite (high throughput); for images, gemini-nano-banana-2.1, gemini-3.1-flash-lite-image, or gemini-3-pro-image. Avoid deprecated gemini-2.5-*, gemini-2.0-*, and gemini-1.5-* models.
Global flags
| Flag | Purpose |
|---|---|
-o, --output-format | pretty (default), json, toon, yaml, table |
-q, --jq | Filter JSON output with a built-in jq expression (--raw-output is true by default) |
--agent-mode | Compact TOON on stdout and structured JSON errors on stderr |
--no-interactive | Disable prompts, TUI forms, and explore |
--dry-run | Validate inputs and preview redacted HTTP requests offline (-o json outputs JSON) |
-d, --debug | Log HTTP request and response details to stderr |
Exit codes: 0 ok, 1 runtime or API error (including failed or incomplete runs), 2 usage or validation error, 3 auth error. See gemini-api --help-global for --server-url, pagination, and auth flags.
Output
Media (image, tts, music, video) and transcribe write files locally and print only the file path on stdout. Adding -o json still writes the file and prints {path, mime_type, size_bytes, response_id, status}.
Streaming and JSON shape: generate and agent run stream plain reply text by default, so -o json alone emits NDJSON events. Pass --stream=false -o json for one JSON object {id, status, steps, usage} (bare --stream=false prints metadata YAML, and --jq or --background disables streaming automatically). Reply text lives under .steps[] model_output (see agent status below) rather than .candidates[]. On paginated list commands, --jq runs per page envelope (.models[]?.name, .agents[]?.id).
Input
-i/--inputattaches media and documents ongenerate,image,video,analyze,transcribe, andagent run(repeatable). Accepts local paths up to ~14 MB (20 MB base64 cap),files/<id>URIs, or YouTube URLs. Upload larger or reused files once withgemini-api files upload <path> --wait.-f/--filereads prompt text from a file onttsandmusic. Piped text needs--stdin: when piping plain text intogenerate,image,video, oranalyze, pass--stdinor piped input gets parsed as a JSON--body.--bodypasses raw Gemini API JSON inline, from@file.json, or via@-(merges with flags; exits 2 on duplicate keys). Use it forresponse_formatschemas,tools(google_search,code_execution,url_context, function declarations),generation_config,environment, orstore.- Don't dump
--schemaraw: it prints ~91 KB of minified JSON and exits before--jqruns. Pipe it tojq:gemini-api generate --schema | jq '."$defs".ModelInteraction.properties | keys'
Media, analysis, and transcription
HERO=$(gemini-api image "Isometric cloud database icon" --aspect-ratio 16:9 --image-size 2K --out ./hero.jpg)
gemini-api image "Add warm sunset lighting" -i "$HERO" --out ./hero-sunset.jpg
gemini-api tts "Alice: Ready to ship? Bob: Checks are green." \
--multi-speaker "Alice=Kore,Bob=Puck" --out ./dialogue.wav
VID_ID=$(gemini-api video "Aerial coastal cliffs at sunrise" --aspect-ratio 16:9 --resolution 1080p --async)
gemini-api video --resume "$VID_ID" --out ./cliffs.mp4
FILE_URI=$(gemini-api files upload ./call.mp4 --wait) # prints files/<id>
gemini-api analyze -i "$FILE_URI" "List action items with owners and timestamps."
gemini-api transcribe -i "$FILE_URI" --format srt --out ./call.srt
Managed agents and sandboxes
deep-research-preview-04-2026anddeep-research-max-preview-04-2026: run with--backgroundand pollagent status.antigravity-preview-09-2026(Linux sandbox with Bash, Python, Node, file ops, and web search): passenvironment("remote") orenvironment_idin--body.
ID boundary: agent status, agent cancel, and agent delete-interaction take a run ID (v1_...). agent create, agent get, agent list, and agent delete manage custom agents only (built-in agents appear in gemini-api models; cap agent list and environments list with --page-size 10).
RUN_ID=$(gemini-api agent run "Compare WebRTC SFU architectures with primary sources." \
--agent deep-research-preview-04-2026 --background --jq '.id')
gemini-api agent status "$RUN_ID" --jq '.status' # queued | in_progress | completed | failed
gemini-api agent status "$RUN_ID" \
--jq '[.steps[]? | select(.type=="model_output") | .content[]? | select(.type=="text") | .text] | join("")'
ENV_ID=$(gemini-api agent run "Benchmark radix sort vs timsort in Python and write results.csv." \
--agent antigravity-preview-09-2026 --body '{"environment": "remote"}' --jq '.environment_id')
gemini-api environments files list -e "$ENV_ID" -r
gemini-api environments files download "$ENV_ID" results.csv --out ./results.csv
gemini-api agent create --id code-reviewer --base-agent antigravity-preview-09-2026 \
--system-instruction "Review diffs for race conditions and auth bugs."
Multi-turn and structured output
Calls store state server-side by default (store is true), so multi-turn chains only need --previous-interaction-id (system_instruction, tools, and generation_config apply per turn; setting store to false disables previous_interaction_id and background):
TURN1=$(gemini-api generate "Propose 2 indexing strategies for time-series logs." --jq '.id')
gemini-api generate "Compare them for write-heavy workloads." --previous-interaction-id "$TURN1"
Combine --stdin with --body for schema-constrained JSON output:
cat build.log | gemini-api generate "Extract unique compiler errors." --stdin --stream=false --body '{
"response_format": {
"type": "text", "mime_type": "application/json",
"schema": {"type": "object", "properties": {"errors": {"type": "array", "items": {"type": "string"}}}, "required": ["errors"]}
},
"store": false
}'
Full CLI reference: aistudio.google.com/docs/cli.md; docs index: llms.txt.