◉ANTIGRAVITY LABJP
Articles/AI Tools
⚙ AI Tools/2026-10-29Intermediate

A 54-Line Front Door for the Days I Can't Decide Between agy and gemini-api

The Gemini API CLI (gemini-api) landed in beta on October 27. Here is a small shell script that sends repo-editing requests to the Antigravity CLI (agy) and read-only requests to gemini-api, including the 14 MB input ceiling, exit codes 0-3, and timeout's 124, all checked with stubs.

Antigravity CLI42agy8Gemini API CLIgemini-api8shell scriptrouting3

I was reading the Gemini API changelog for October 27 when a new line stopped me: a command-line client called gemini-api, in beta.

The names are close, and both call Google models. Should I split work that agy -p already handles into a second command? Or, the other way round, is it wise to let agy, which can touch a repository, handle requests that only need reading? As an indie developer reviewing my own work with nobody else in the room, I wanted the line drawn before I started using either.

One thing up front. What I verified by hand is the branching of a routing script. gemini-api is in beta and I did not pull its binary; I tested with fake commands that record their arguments and return an exit code. Everything I say about gemini-api itself rests on the official documentation.

What the docs say about gemini-api

From the Gemini API CLI guide and the October 27 changelog, only the parts that matter for routing:

  • It is described as a stateless, zero-dependency client that calls Gemini models and managed agents through the Interactions API
  • It is an open-source beta, and breaking changes can land between minor versions. Pin a release in automated environments
  • analyze -i <file> reads PDFs, images, audio, video, CSV and text. Inline input is capped at 14 MB of raw data; beyond that, use files upload. Uploaded files are deleted after 48 hours
  • Exit codes: 0 success, 1 runtime or API error, 2 usage or validation error, 3 authentication or authorization failure
  • generate streams to stdout by default; combine it with -o json or --jq only with --stream=false

On the other side, agy -p is the headless mode: run one prompt and exit. Operations that need approval become soft-denies, and the exit code stays 0 while a notice goes to stderr. I wrote that up in an earlier article.

The line: does it write, or only read?

My first idea was to classify the prompt automatically by keywords such as "fix". That falls apart quickly: "tell me whether this table needs fixing" is a read-only request that would be routed to the side that can edit files. It is easier to trace an incident later if the caller declares intent in one word.

So the front door has three kinds: edit, analyze, ask.

KindGoes toUse it for
editagy -pRequests that read and write files in the repository
analyzegemini-api analyzeRead one file, return just an answer
askgemini-api generateStateless one-off questions

The 54-line script

#!/usr/bin/env bash
# route.sh — 依頼の種類を見て agy と gemini-api を振り分ける小さな玄関
set -uo pipefail
 
LIMIT="${ROUTE_TIMEOUT:-5m}"
INLINE_MAX=$((14 * 1024 * 1024))   # gemini-api の -i は生データ 14MB まで
 
die() { echo "route: $1" >&2; exit "${2:-64}"; }
need() { command -v "$1" >/dev/null 2>&1 || die "$1 が見つかりません" 127; }
 
kind="${1:-}"; [ -n "$kind" ] || die "使い方: route.sh edit|analyze|ask  ..."
shift
 
case "$kind" in
  edit)
    # リポジトリを読み書きさせたい依頼は agy に渡す
    need agy
    [ "$#" -gt 0 ] || die "依頼文がありません"
    timeout "$LIMIT" agy -p "$*"
    rc=$?
    ;;
  analyze)
    # 1 つのファイルを読ませて答えだけ欲しい依頼は gemini-api に渡す
    need gemini-api
    file="${1:-}"; shift || true
    [ -f "$file" ] || die "ファイルがありません: $file"
    [ "$#" -gt 0 ] || die "質問文がありません"
    size=$(wc -c < "$file")
    if [ "$size" -gt "$INLINE_MAX" ]; then
      uri=$(timeout "$LIMIT" gemini-api files upload "$file" --wait) || die "アップロードに失敗しました" 1
      input="$uri"
    else
      input="$file"
    fi
    timeout "$LIMIT" gemini-api analyze -i "$input" --stream=false "$*"
    rc=$?
    ;;
  ask)
    # 状態を持たない単発の質問は gemini-api の generate
    need gemini-api
    [ "$#" -gt 0 ] || die "質問文がありません"
    timeout "$LIMIT" gemini-api generate --stream=false "$*"
    rc=$?
    ;;
  *) die "未知の種類です: $kind" ;;
esac
 
case "$rc" in
  0)   ;;
  124) echo "route: ${LIMIT} で打ち切りました" >&2 ;;
  2)   echo "route: 引数の組み立てが誤っています(終了コード 2)" >&2 ;;
  3)   echo "route: 認証に失敗しました。GEMINI_API_KEY か whoami を確認してください" >&2 ;;
esac
exit "$rc"

Three details matter.

First, the 14 MB line. analyze measures the file and only when it exceeds the ceiling does it call files upload --wait and pass the returned files/<id> to -i. Uploading small files would just pile up temporary files that vanish after 48 hours.

Second, timeout wraps the whole call. A timed-out run exits with timeout's 124, which belongs to neither CLI, so it never collides with the documented 0-3.

Third, exit codes are never swallowed. Only 2 and 3 get a one-line hint, and the original code goes back to the caller.

The branches I actually checked

I put a fake agy and a fake gemini-api at the front of PATH, logged their arguments, and confirmed the following.

CallResult
edit "..."agy -p ... called once, exit 0
analyze on a small fileOnly analyze -i a.txt --stream=false ...
analyze on a ~15 MB filefiles upload big.bin --wait, then -i files/...
Fake CLI returns 3Authentication hint, exit 3
Fake CLI returns 2Usage hint, exit 2
Fake agy sleeping 5 s with ROUTE_TIMEOUT=1sTimeout notice, exit 124
Unknown kind / missing command64 / 127

Caveats and what I have not checked

  • I have not run the real gemini-api. It is a beta, so flag names may change. Check gemini-api --usage before relying on this
  • The official examples include installing with curl ... | bash. I would read the script first, or use a pinned release archive
  • An exit code of 0 from agy includes the soft-deny case. For edit, judge the result by the diff, not by the exit code alone
  • Use a dummy such as YOUR_API_KEY and pass the real key through GEMINI_API_KEY. Never write it into the script

One next step

Writes go to agy, reads go to gemini-api, and when I am unsure, the caller says which in one word. I intend to keep revisiting that line as more beta CLIs appear.

To begin, pull the last five agy -p calls from your shell history and sort them into "asked it to change something" and "only wanted an answer". I'd rather start with that check, because it costs the least rework.

Sources

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⚙ AI Tools2026-10-15
A 50-Line Wrapper That Hands Japanese Proofreading to agy's Headless Mode
Wrap the Antigravity CLI (agy) headless mode in a small proofreading script: how to feed stdin, why exit code 0 can still mean an empty answer, the argument-length ceiling, and a cost estimate that accounts for the January 2027 price change.
⚙ AI Tools2026-09-15
The Day I Stopped Splitting by Skill — Three Questions for Routing Work Between Antigravity CLI and Claude Code
An unattended job sat waiting on an approval prompt for three days without a single error line. Here is how I stopped dividing work between two agent CLIs by capability, and started dividing it by where the approval boundary falls.
⚙ AI Tools2026-09-11
Starting with AGY_CLI_HIDE_LOGO: tuning Antigravity CLI for narrow terminals, screen readers, and recordings
Logo art, your email address, output that swallows the pane, a copy you never asked for. Here are the Antigravity CLI environment variables and settings that quiet the display, grouped by the three situations where they matter.