◉ANTIGRAVITY LABJP
Articles/Antigravity Basics
◉ Antigravity Basics/2026-06-14Intermediate

A Compatibility Shim That Bridges Old Scripts to agy Before Gemini CLI Shuts Down

Ahead of the June 18 Gemini CLI shutdown, instead of rewriting every gemini call scattered across cron and CI at once, a thin compatibility shim can bridge them to the Antigravity CLI (agy). Here is the approach with working shell scripts.

Antigravity CLI42Gemini CLI13Migration9Shell ScriptCI11

The real headache was that the command name gemini is scattered across cron, CI, Makefiles, and old notes—and I could not honestly account for every place it gets called from. Trying to replace them all on shutdown day, a few always slip through and fail quietly at 3 a.m. As an indie developer running an automated publishing pipeline, that "one that slipped through" goes unnoticed until the next morning.

So before rewriting every call site directly, I slipped in a thin compatibility shim that keeps the name gemini but routes the body to agy (the Antigravity CLI). That decoupled me from the deadline and let me move call sites over one at a time, calmly.

Why a shim instead of a one-shot replace

What is genuinely scary about migrating from gemini to agy is not the command disappearing—it is not holding a correct, complete list of every caller. grep only finds what is inside the repo; crontab, systemd timers, and scripts on another machine all escape it.

A shim absorbs that uncertainty over time. It keeps the old name while delegating to the new implementation, separating the migration deadline (June 18) from your own deadline to fix every caller. As long as you secure name compatibility before the command goes away, you can move the internals at your own pace.

Build the flag mapping table first

Before writing the shim, map only the flags you actually use. There is no need to cover every flag—porting ones you never call buys nothing. My pipeline used just these four.

  • -p / --prompt (prompt string) → agy run -p
  • -m / --model (model selection) → agy run -m
  • --json (machine-readable output) → agy run --format json
  • -f / --file (input file) → agy run --input

What matters here is the output-format difference. The old CLI's --json and the new CLI's --format json can differ in key names and nesting. If anything downstream parses it, look at the real output once right after routing through the shim and confirm your jq paths still work. Skip this and you get the worst failure: the command succeeds while the downstream silently grabs nothing.

The compatibility shim itself (drop-in replacement)

Prepare an executable named gemini placed at the front of PATH. It is a thin layer that parses the arguments and re-passes them to agy.

#!/usr/bin/env bash
# /usr/local/bin/gemini  ← place under the old command name, first on PATH
# Role: a compatibility shim that bridges old gemini calls to agy run
set -euo pipefail
 
# Resolve the real agy (fail loudly if missing)
AGY="$(command -v agy || true)"
if [ -z "$AGY" ]; then
  echo "gemini-shim: agy not found. Please install the Antigravity CLI." >&2
  exit 127
fi
 
args=()
while [ $# -gt 0 ]; do
  case "$1" in
    -p|--prompt) args+=( -p "$2" ); shift 2 ;;
    -m|--model)  args+=( -m "$2" ); shift 2 ;;
    -f|--file)   args+=( --input "$2" ); shift 2 ;;
    --json)      args+=( --format json ); shift ;;
    -h|--help)
      echo "gemini-shim → agy run compatibility layer. Unknown flags pass through." >&2
      shift ;;
    *)           args+=( "$1" ); shift ;;   # pass unknown args through as-is
  esac
done
 
# Make migration visible: log shim-routed calls to surface remaining callers
echo "$(date -Iseconds) shim-call: $*" >> "${HOME}/.gemini-shim.log"
 
exec "$AGY" run "${args[@]}"

The exec replacement passes the exit code and signals straight through to agy. Inserting another process in between can make CI misjudge the exit code or fail to deliver the timeout signal.

Use the log as a map of "remaining callers"

The hidden star of this shim is the last log line. By recording shim-routed calls, just a few days of operation naturally collects "where gemini actually gets called from." Even a crontab or another script grep never found will leave a footprint in the log the moment it runs.

# Tally the actual callers of gemini over the past week into a to-migrate list
sort "${HOME}/.gemini-shim.log" | awk '{$1=""; print}' | sort | uniq -c | sort -rn

Looking at this tally, I noticed an old backup cron that did not exist anywhere in the repo. It was a caller static grep would never have found. Once you can measure migration progress by "how many callers remain," the pre-deadline anxiety drops a lot.

Judging when to remove the shim

The shim is a bridge, not a destination. Once the tally hits zero for several days straight, you can conclude every caller has moved to calling agy directly.

# If there have been zero shim-routed calls in the past 3 days, it is a removal candidate
RECENT=$(awk -v cut="$(date -d '3 days ago' -Iseconds)" '$1 > cut' "${HOME}/.gemini-shim.log" | wc -l)
[ "$RECENT" -eq 0 ] && echo "No shim-routed calls → you can remove /usr/local/bin/gemini"

Migration is only complete when removal is included. Leave the shim in place and the call sites you should have fixed get preserved "because they still work," leaving you with permanent double maintenance. I deliberately set a deadline and pulled it out.

The first thing to do is write down just four or five flags you actually use and run the shim above within that scope. You do not need perfect compatibility. If you reach a state where "as long as the name lives, the body can move later" before the June 18 shutdown, you are freed from a deadline-driven migration. I hope this helps anyone with an automation-script migration coming up.

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

◉ Antigravity2026-10-26
When the Agent Stops Answering From Your Attachment After /compact, One Canary File Tells You Why
After compacting a long Antigravity CLI session, replies stopped reflecting the file you attached. A one-line canary file separates a version issue from how you attached it.
◉ Antigravity2026-09-17
Wait or Pay When the Baseline Runs Out: Deciding Credit Overages Per Task
When your baseline quota is exhausted, one setting decides whether you wait for the refresh or spend purchased credits. Here is how I split attended work from unattended runs, and the small gate I put in front of the jobs nobody is watching.
◉ Antigravity2026-08-20
Count What Writes Outside Your Workspace Before You Upgrade to CLI 1.1.14
Antigravity CLI 1.1.14 makes paths outside the workspace read-only by default. If your source assets and delivery targets live outside the repository, it is worth knowing what breaks before you upgrade. Here is a script that inventories your write targets, and the two ways it quietly undercounts them.