GEMINI LABJP
CLI — As of Jun 18, Gemini CLI and the Gemini Code Assist IDE extensions stop serving AI Pro/Ultra and free individual users; Antigravity CLI is the successorFLASH — The Gemini 3.5 series begins with 3.5 Flash, built for agents and coding with strength on long-horizon tasksDEEPTHINK — Gemini 3 Deep Think is rolling out to Google AI Ultra as the top reasoning mode for math, science, and logicAPP — The Gemini app gains a Daily Brief, a redesigned interface, the Gemini Omni video model, and a personal agent called Gemini SparkDESIGN — A new design language, Neural Expressive, rebuilds the experience for richer visuals and faster switching between modalitiesULTRA — Google AI Ultra bundles top model access, Deep Research, Veo 3 video, and a 1M-token context windowCLI — As of Jun 18, Gemini CLI and the Gemini Code Assist IDE extensions stop serving AI Pro/Ultra and free individual users; Antigravity CLI is the successorFLASH — The Gemini 3.5 series begins with 3.5 Flash, built for agents and coding with strength on long-horizon tasksDEEPTHINK — Gemini 3 Deep Think is rolling out to Google AI Ultra as the top reasoning mode for math, science, and logicAPP — The Gemini app gains a Daily Brief, a redesigned interface, the Gemini Omni video model, and a personal agent called Gemini SparkDESIGN — A new design language, Neural Expressive, rebuilds the experience for richer visuals and faster switching between modalitiesULTRA — Google AI Ultra bundles top model access, Deep Research, Veo 3 video, and a 1M-token context window
Back to Blog

Two Days Before Gemini CLI Goes Dark: How I Inventoried My Automation

Gemini CLIAntigravity CLIMigrationAutomationIndie Developer

On June 18, Gemini CLI and the Code Assist IDE extension stop processing requests for free personal users and for AI Pro / Ultra subscribers. As I write this, there are exactly two days left.

When I first saw the notice, I will admit my stomach tightened a little. I run several sites under Dolice Labs by myself, and Gemini CLI had quietly woven itself into a few corners of that operation. But before I started frantically writing migration scripts, I took one breath at my desk and did something else first. I started by writing down, on paper, where and why I had been calling the CLI at all.

A migration with a fixed deadline is actually easier to stay calm about

Nothing unsettles me more than technical debt with no deadline. The "I should fix this someday" task lingers in the corner of your mind forever, never quite done.

So a migration with a clear June 18 cutoff was, for me, the easier kind. The shape of the work is defined. When the deadline is fixed, what you can reasonably do is limited too. With two days left, the goal is not to build a flawless new system, but to find the spots that will hurt when things stop, and apply the minimum care needed there.

Aim for a perfect migration in two days, and you usually ship something half-finished to production. I try not to get that order wrong.

First, I listed every place the CLI was called

Trying to recall "I think I used it here, and over there" from memory is the most dangerous approach. Memory conveniently drops things. So I searched the whole repository mechanically and surfaced every call site.

# Pull every Gemini CLI / Code Assist invocation out of the automation scripts.
# -n adds line numbers, -r recurses, --include narrows the file types.
grep -rn --include="*.sh" --include="*.mjs" --include="*.py" \
  -E "gemini (generate|chat|code|extensions)|code-assist" . \
  > /tmp/cli_callsites.txt
 
# See how many there are and which files they cluster in.
wc -l /tmp/cli_callsites.txt
cut -d: -f1 /tmp/cli_callsites.txt | sort | uniq -c | sort -rn

When I actually ran it, the call sites were fewer than I remembered, and they clustered in just a handful of scripts. Knowing that alone took a good deal of weight off my shoulders. The vague fear that "everything is hopelessly tangled up with the CLI" is almost always larger than the facts.

The low count was thanks to a small decision past-me had made

Why weren't the calls scattered everywhere? Tracing it back, I landed on a small wrapper function I had written long ago. Instead of hitting the CLI directly all over the place, I had put a thin function like run_gemini() in front of it, and every script only called that.

There was no deep design philosophy at the time. The motivation was closer to laziness: I was tired of typing the command options every single time. Still, because the dependency on an external tool was sealed into one place, the thing I needed to swap out today narrowed down to a single spot.

# The thin wrapper I had been using (callers know only this).
run_gemini() {
  local prompt="$1"
  # Swap only this line for Antigravity CLI, and every caller stays untouched.
  gemini generate --model gemini-3.5-flash --prompt "$prompt"
}

It is during migrations like this that I feel the payoff of hiding external dependencies behind a thin layer. It is not a flashy design, but in indie development I find that "a small bit of groundwork that lets future-me take it easy" is what pays off most.

Always check the behavioral diff before swapping

The path being pointed to is Antigravity CLI. But assuming "it's a similar command, so it should just work" and rewriting the production wrapper outright is, for me, off-limits.

What I always do is line up the old and new outputs side by side. I send the same prompt to both and check whether the length, format, trailing newline, and error behavior of what comes back will break the downstream steps of my automation. Especially when another script is parsing the output, a tiny formatting difference can quietly cascade, and broken results pile up without anyone noticing. That is the scenario I fear most.

I have collected concrete examples of the traps you tend to hit during deprecation and shutdown migrations in How to handle Gemini API model deprecation and migration errors. If you want to follow the steps systematically, as in this case, I'd also point you to Preparing for the personal-tier shutdown of Gemini CLI and Code Assist.

Three things I decide on in a deadline-driven migration

After going through a few of these "migrations with a clock on them," some small rules of my own have settled into place.

First, before rewriting any production script, prepare one fallback that survives a stoppage. If I can temporarily drop the affected automation back to manual operation, a failed migration won't spread its damage.

Second, migrate "one at a time, in order of pain," not "everything at once." There is no need to perfect every repository in two days. I start with whatever hurts most when it stops.

Third, always leave the inventory in writing. This time too, I pasted cli_callsites.txt straight into my working notes. The next time a similar migration comes around, nothing is more dependable than a record left by my past self.

What to do next

If you also have a CLI woven into your automation, run that grep once before you go hunting for a migration target. Just looking at the list of call sites will make "what, by when, and how far" far more concrete than it felt back when it was only anxiety. A migration with a deadline, started calmly from an inventory, is far less frightening than it seems.