Before Gemini CLI Shuts Down (June 18): Audit Every Hidden Dependency Before Moving to Antigravity CLI
When Gemini CLI shuts down on June 18, the things that actually break are not in your terminal—they're the gemini calls buried in CI, git hooks, and cron. Here's how to surface every reference, validate with a dry run, and design a rollback before you cut over.
On June 18, Gemini CLI and the Gemini Code Assist IDE extension stop serving requests for free individual users and AI Pro / Ultra subscribers, consolidating into the Go-based Antigravity CLI. If all you do is retype gemini in your terminal, that's a few minutes of work.
What gave me a cold sweat while auditing my own app-operations automation was finding the string gemini buried in places I had forgotten about: GitHub Actions workflows, a git hook that runs before each commit, a cron job firing at midnight, package.json scripts, a Makefile target. None of those are visible from the terminal. On deadline day they can fail silently—sometimes without even producing an error that tells you the shutdown was the cause.
This article is not about "how to rename the command." It's the practical procedure for getting your replacement coverage to zero misses, switching over without stopping production automation, and rolling back instantly if something goes wrong. It pays off most for anyone running several repositories and automated pipelines in parallel. As an indie developer juggling exactly that, I've felt how much this inventory step matters.
Why "it works in my terminal" doesn't mean the migration is done
CLI migrations go wrong when three things line up.
First, the call sites are scattered. The interactive gemini you type is the tip of the iceberg; most invocations are non-interactive (pipes, subcommands) called mechanically. Second, failures happen quietly. If a CI step swallows the exit code with || true, or a cron job sends stderr nowhere, nobody notices for a while after the cutoff. Third, more than the name drifts. If the new CLI changed the config location, environment variable names, or where it reads credentials, then even after you swap in antigravity you land in "the command is found but auth fails."
So the first move in a migration isn't replacement—it's an inventory. List out where, how, and under whose permissionsgemini is being called before you touch anything.
First, surface every reference mechanically
Start by pulling out gemini references across both your repositories and your operational environment. Cast a wide net—include comments and string literals—and let a human triage afterward. Over-detection is safer than a miss.
#!/usr/bin/env bash# audit-gemini.sh — surface dependencies on the gemini CLI across the board# Usage: ./audit-gemini.sh /path/to/repo1 /path/to/repo2 ...set -euo pipefailREPORT="gemini-audit-$(date +%Y%m%d-%H%M).md"echo "# Gemini CLI dependency audit $(date)" > "$REPORT"scan_dir() { local root="$1" echo -e "\n## $root" >> "$REPORT" # 1) Calls inside source/config files (exclude .git and node_modules) echo -e "\n### In-file references" >> "$REPORT" grep -rInE '\bgemini\b' "$root" \ --include='*.sh' --include='*.yml' --include='*.yaml' \ --include='*.json' --include='*.toml' --include='Makefile' \ --include='*.mjs' --include='*.ts' --include='*.js' \ 2>/dev/null | grep -v '/node_modules/' | grep -v '/.git/' \ >> "$REPORT" || echo "(none)" >> "$REPORT" # 2) git hooks (untracked, so check them separately) echo -e "\n### git hooks" >> "$REPORT" if [ -d "$root/.git/hooks" ]; then grep -rIn 'gemini' "$root/.git/hooks" 2>/dev/null \ | grep -v '\.sample:' >> "$REPORT" || echo "(none)" >> "$REPORT" fi}for target in "$@"; do scan_dir "$target"done# 3) The user's cron (often lurks outside any repo)echo -e "\n## crontab (current user)" >> "$REPORT"crontab -l 2>/dev/null | grep -n 'gemini' >> "$REPORT" || echo "(none)" >> "$REPORT"# 4) Any old binary still on PATHecho -e "\n## gemini binary on PATH" >> "$REPORT"command -v gemini >> "$REPORT" 2>/dev/null || echo "(not on PATH)" >> "$REPORT"echo "✅ Report written: $REPORT"
The key to this script is that it looks in places that aren't tracked. .git/hooks and crontab -l will never show up in git grep. My own cold sweat came from exactly that—a formatting-check call I had tucked into a pre-push hook. Read the resulting Markdown top to bottom and tag each line as "interactive" or "automation"; that ordering decides what to dry-run first.
References hiding in package.json scripts are worth confirming as dependencies too.
# Pull out just the scripts section and check itnode -e "const p=require('./package.json'); console.log(JSON.stringify(p.scripts||{}, null, 2))" \ | grep -n 'gemini' || echo "no gemini references in scripts"
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Surface every gemini call hiding in CI, git hooks, and cron—the ones you can't see from your terminal—with a single audit script
✦Avoid the classic trap where you renamed the command but the auth and config paths drifted, by sequencing your dry run correctly
✦Apply a cutover procedure that keeps production automation running, with rollback wired up before you flip the switch
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Once the inventory is done, confirm the behavioral diff in one place before replacing anything. The binary name changes from gemini to antigravity, but what actually bites you in a migration isn't the name—it's everything around it. At a minimum, verify these four against the real new CLI before any bulk replace:
The launch command name (gemini → antigravity) and whether non-interactive subcommands/flags are spelled the same as before
The config search path (does the new CLI read the old CLI's home-directory config, or look somewhere else?)
Where credentials come from (did env var names or the auth flow change?)
The meaning of exit codes (does success = 0 / failure = non-zero still match? Your CI pass/fail logic depends on this)
The rule is to verify in a throwaway directory, starting with read-only, low-impact operations. Running a production script first makes it hard to isolate the cause when it fails with side effects mixed in.
# Minimal checks in an isolated dry-run directoryTMP="$(mktemp -d)"; cd "$TMP"echo "console.log('hello')" > sample.js# Is the new CLI on PATH, can we read a version? (start with zero-side-effect checks)antigravity --version || { echo "❌ antigravity not found. Install it first"; exit 1; }# Read help to confirm the real subcommand/flag surface# NOTE: always confirm exact subcommand names against the official migration notesantigravity --help | head -40echo "Once verified, proceed to replacing the production scripts"; cd - >/dev/null
Reading the --help output plainly is the shortcut here. I once assumed "the flags must be the same as the old CLI," ran a bulk sed, and a one-character difference in a non-interactive flag turned CI red. Don't guess spellings—look at the real surface before any mechanical replace.
Rewrite CI workflows while making failures visible
Calls inside CI are a chance to make failures visible at the same time you replace them. The number-one reason last-minute automation dies quietly is swallowed errors.
# After — replace the command and surface failure as a job failure- name: Generate code summary run: | set -euo pipefail antigravity summarize ./src > summary.txt # For the first few days only, continue-on-error gives you a "fail but don't block" observation window continue-on-error: true
Two points. One: drop || true and add set -euo pipefail so you can judge whether it's actually working from the exit code. Two: for just the first few days after migrating, add continue-on-error: true to create an observation mode—"don't halt the pipeline on failure, but leave it in the logs and status." That way a missed replacement or auth drift shows up on your dashboard before it takes production down with it. Once the window passes, remove continue-on-error and return it to a required step.
The worst thing you can do in a migration is "swap everything to the new CLI and pray." To keep production automation running, prepare the way back before you move forward.
What works in practice is consolidating calls behind one thin wrapper. Instead of each script invoking antigravity directly, route them through an intermediary like ai-cli and switch the real implementation inside the wrapper.
#!/usr/bin/env bash# ai-cli — a thin wrapper for the migration window; switch the impl with one env varset -euo pipefail# AI_CLI_IMPL=antigravity (default) / gemini (for emergency rollback)IMPL="${AI_CLI_IMPL:-antigravity}"if ! command -v "$IMPL" >/dev/null 2>&1; then echo "❌ '$IMPL' not found (check AI_CLI_IMPL)" >&2 exit 127fiexec "$IMPL" "$@"
Replace each call site with ai-cli ... and, if antigravity does something unexpected, you can revert instantly just by setting AI_CLI_IMPL=gemini (until June 18, or for as long as the old binary remains locally). Because the switch point is consolidated in one place, you don't have to re-sed every script.
Of course, after June 18 the gemini side stops accepting requests, so this is insurance for "if the new CLI breaks on migration day, keep the old behavior alive just long enough to isolate the cause." The permanent fix is closing out every missed replacement and auth drift during the observation window. Keep the wrapper around and the same defense works the next time a CLI changes.
Don't make post-migration verification a manual checklist
If you finish the cutover on "probably fine" and the next thing to run is a midnight cron job, you won't learn about the failure until morning. Mechanize the verification too.
#!/usr/bin/env bash# verify-migration.sh — machine-judge whether the migration is completeset -uo pipefailFAIL=0echo "== 1. Remaining references to the old binary =="if grep -rInE '\bgemini\b' . \ --include='*.sh' --include='*.yml' --include='*.yaml' \ --include='*.json' --include='Makefile' 2>/dev/null \ | grep -v '/node_modules/' | grep -v 'ai-cli' | grep -q .; then echo "⚠️ gemini references still remain (see above)"; FAIL=1else echo "✅ no direct references"fiecho "== 2. Does the new CLI respond? =="if antigravity --version >/dev/null 2>&1; then echo "✅ antigravity responds"; else echo "❌ antigravity does not respond"; FAIL=1; fiecho "== 3. Can we run through the wrapper? =="if AI_CLI_IMPL=antigravity ./ai-cli --version >/dev/null 2>&1; then echo "✅ via ai-cli OK"; else echo "❌ wrapper failed"; FAIL=1; fi[ "$FAIL" -eq 0 ] && echo "🎉 migration verification PASS" || { echo "🛑 there are incomplete items"; exit 1; }
Wire this verification into your migration branch's CI as one step and block the merge on exit 1, and you erase the human error of "forgetting to verify" entirely. The same hazard—a broken result getting frozen at the edge—shows up in web delivery too; the idea is shared with designing so a broken result never gets cached. Make failure observable, prevent it from being frozen, and keep a way back. Push hard enough and CLI migration and cache design arrive at the same principle.
The order that worked for me as a solo developer
The order that actually went smoothly for me was five steps: (1) surface all references with the audit script, (2) dry-run in an isolated directory to confirm the old/new diff, (3) consolidate calls behind the wrapper, (4) replace inside CI in observation mode, (5) wire the verification script into CI. It took about half a day, but only a tenth of that was the actual replacing—the rest was time spent making "where is it being called" visible. Put the other way: once the visibility is done, the migration stops being scary.
With days left on the clock, there's exactly one concrete step to take now. Run the audit-gemini.sh above against every repository you touch and your current user's crontab, and get the list of where gemini is buried out in front of you. Replacement can come after. As long as you can see it, June 18 passes by quietly.
If the migration is also a prompt to redesign how your agents run on a schedule, notes on implementing scheduled background agents make a solid foundation. Thanks for reading—I hope it helps anyone juggling several automations the way I am.
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.