AI

Gemini CLI Cheat Sheet: Commands, Slash Commands and Flags (PDF)

Gemini CLI still works in October 2026, just not the way most cheat sheets describe it. The free Google sign-in stopped serving on 18 June 2026, the flat settings.json keys that older guides print belong to the old schema, and three defaults trip up anyone who scripts it. An untrusted folder ignores the key in ~/.gemini/.env. A headless run in the default mode quietly skips every edit and still exits 0. And --approval-mode plan can switch itself to YOLO once the model leaves plan mode.

Original content from computingforgeeks.com - post 167354

This Gemini CLI cheat sheet covers the commands, slash commands, flags, exit codes, JSON output, policy files and settings you’ll actually type, plus the fix for each error we hit. Every command shown with output was run on Gemini CLI 0.65.0 on an Ubuntu 26.04 server in October 2026 with a free-tier Gemini API key, and the sandbox section adds a check on macOS.

Check whether Gemini CLI still works for your account

Gemini CLI works today with a Gemini API key, Vertex AI or an existing Code Assist Standard or Enterprise seat. It stopped working for personal Google sign-ins on 18 June 2026, when Google moved free, Google AI Pro and Google AI Ultra users to the closed-source Antigravity CLI. Google’s transition announcement lists the dates, and this is how each account type looks now:

How you sign inStatus in October 2026Where that comes from
Sign in with Google, free personal accountStopped serving on 18 June 2026; Google points you to Antigravity CLIGoogle announcement
Sign in with Google, Google AI Pro or UltraStopped serving on 18 June 2026Google announcement
Free-tier Gemini API key (AI Studio)Works for flash and flash-lite models; the current pro models we tried returned limit: 0Our runs on this page
Paid Gemini API keyStays supportedGoogle announcement
Vertex AI (now Gemini Enterprise Agent Platform)Stays supportedGoogle announcement
Gemini Code Assist Standard or EnterpriseExisting seats keep working; no new purchases since 9 October 2026Google Cloud sunset page

Google’s own pages still disagree on the free tier. The geminicli.com quota page keeps a table with 1,000 requests a day for personal accounts, while its banner says Gemini CLI was replaced by Antigravity CLI for unpaid users on 18 June. Go by the announcement. The same quota page gives an unpaid API key 250 requests a day on Flash models, but not what happens when you ask for more, so we tested it. Flash and flash-lite answered, and every pro model we tried was refused. With GEMINI_CLI_TRUST_WORKSPACE=true exported (the trust section explains why), this is the pro alias on that key, with the stack trace filtered out:

gemini -m pro -p "Reply with one word: ok" 2>&1 | grep -v '^    at '

After the colour warning from our SSH session, you only need the first lines. The model name in the quota error shows -m pro now resolves to the Gemini 3.1 Pro line, and the zero limit means a free key cannot call it at all:

Warning: 256-color support not detected. Using a terminal with at least 256-color support is recommended for a better visual experience.
Error when talking to Gemini API Full report available at: /tmp/gemini-client-error-Turn.run-sendMessageStream-2026-10-21T21-59-32-887Z.json TerminalQuotaError: You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https://ai.dev/rate-limit.
* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 0, model: gemini-3.1-pro
* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 0, model: gemini-3.1-pro
* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_input_token_count, limit: 0, model: gemini-3.1-pro
* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_input_token_count, limit: 0, model: gemini-3.1-pro
Please retry in 9h27.175820413s.

The same zero came back for gemini-3.1-pro-preview and gemini-4-argon, and gemini-2.5-pro answered with This model models/gemini-2.5-pro is no longer available to new users. The free key also ran out of its daily gemini-3.8-flash quota partway through our lab, so plan on flash-lite for long scripted runs. If you need pro models or a quota you can rely on, add billing to the key or move to Vertex AI.

Install Gemini CLI and store the API key

Gemini CLI is an npm package that needs Node.js 20 or newer. Ubuntu 26.04’s own nodejs package is new enough, so the distro packages will do, and ripgrep is worth installing alongside because the search tool falls back to a slower built-in grep without it. python3-pytest is only there for the approval-mode tests later on:

sudo apt update && sudo apt install -y nodejs npm ripgrep git python3-pytest

Install the CLI globally:

sudo npm install -g @google/gemini-cli

The npm install took about seven seconds on our server. Confirm where the binary landed and which release you got:

which gemini; gemini --version

Both lines should come back without an error:

/usr/local/bin/gemini
0.65.0

For macOS, Windows, Homebrew and the browser sign-in flow, the Gemini CLI install guide covers each platform. On a server, put the key in ~/.gemini/.env and lock the file down, because the CLI reads it on every run in a trusted folder. read -rs keeps the key out of your shell history, and the subshell’s umask 077 creates the file as mode 600 in bash and zsh alike:

mkdir -p ~/.gemini && printf 'Gemini API key: ' && read -rs KEY && (umask 077 && printf 'GEMINI_API_KEY=%s\n' "$KEY" > ~/.gemini/.env) && unset KEY

If you pick “Use Gemini API Key” in the interactive login instead, the CLI saves the key in the system keychain. Our Ubuntu server had no keyring, so it wrote ~/.gemini/gemini-credentials.json with mode 600 and set "security": { "auth": { "selectedType": "gemini-api-key" } } in ~/.gemini/settings.json. With no key at all, a headless run stops with exit code 41 and tells you which variables it looked for:

Please set an Auth method in your /home/josphat/.gemini/settings.json or specify one of the following environment variables before running: GEMINI_API_KEY, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GENAI_USE_GCA

That same exit 41 shows up in one case that has nothing to do with a missing key, which is why the next section matters before you write any script.

Trust the project folder before you script it

Headless runs refuse to start in a folder you have not trusted, and they exit with code 55. This is the check behind the GEMINI_CLI_TRUST_WORKSPACE variable people search for. Before you test it, export the key as a real environment variable, because in an untrusted folder the CLI skips ~/.gemini/.env and you would hit the exit 41 auth error first. Then run gemini -p in a new folder:

mkdir -p ~/scratch && cd ~/scratch && unset GEMINI_CLI_TRUST_WORKSPACE
export GEMINI_API_KEY=$(sed -n 's/^GEMINI_API_KEY=//p' ~/.gemini/.env)
gemini -p "say hi"; echo "exit=$?"

The message names all three ways out:

Gemini CLI is not running in a trusted directory. To proceed, either use `--skip-trust`, set the `GEMINI_CLI_TRUST_WORKSPACE=true` environment variable, or trust this directory in interactive mode. For more details, see https://geminicli.com/docs/cli/trusted-folders/#headless-and-automated-environments
exit=55
  • --skip-trust on the command trusts the folder for that one run
  • export GEMINI_CLI_TRUST_WORKSPACE=true trusts every folder for the shell or CI job
  • running gemini once in the folder and picking “Trust folder” writes it to ~/.gemini/trustedFolders.json

Use the environment variable in CI and the trust dialog on your own machines. Trusting a folder also loads its .gemini/settings.json, the MCP server commands in it and its .gemini/.env, so in CI set it only for repositories you control, never for pull requests from forks. The catch is --skip-trust with a key stored only in ~/.gemini/.env. On a fresh setup, gemini -p "say hi" --skip-trust still exited 41 with the auth error above, while GEMINI_CLI_TRUST_WORKSPACE=true gemini -p ... answered. The source of the release we tested explains it: in an untrusted folder the CLI skips every .gemini/.env file, and the flag only sets the trust variable after that lookup has already run. Plain .env files in the project tree and ~/.env are still read in an untrusted folder, but only for the four auth variables (GEMINI_API_KEY, GOOGLE_API_KEY, GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION). We found that the hard way: a run inside a repository picked up the repository’s own .env and printed Both GOOGLE_API_KEY and GEMINI_API_KEY are set. Using GOOGLE_API_KEY. before failing the trust check.

With the key exported in the same shell, --skip-trust is enough:

gemini --skip-trust -m flash-lite -p "Reply with one word: ok"; echo "exit=$?"

The first line is a colour warning from our SSH session on stderr. After it, the model replies and the exit code is clean:

Warning: 256-color support not detected. Using a terminal with at least 256-color support is recommended for a better visual experience.
ok
exit=0

When you trust a folder in the interactive dialog, the CLI restarts itself and records the path. On our server the file ended up holding one line per trusted folder:

{
  "/home/josphat/demo-app": "TRUST_FOLDER"
}

The dialog also offers “Trust parent folder”, stored as TRUST_PARENT, which covers every project under it. Unless noted, the remaining commands on this page ran with GEMINI_CLI_TRUST_WORKSPACE=true exported, the way a CI job would run them.

Learn the Gemini CLI commands and flags

Gemini CLI has five subcommand groups, and everything else is a flag on the main gemini command. The groups come straight from gemini --help on the release we tested:

CommandWhat it does
geminiStart the interactive terminal UI
gemini "query"Start the UI with a first prompt
gemini -p "query"Headless: answer once, print, exit
gemini -i "query"Run the prompt, then stay in the UI
gemini mcp add | list | remove | enable | disableManage MCP servers
gemini extensions install | list | update | link | new | validate | configManage extensions (also uninstall, enable, disable)
gemini skills list | install | link | enable | disable | uninstallManage agent skills
gemini hooks migrateImport hooks from Claude Code (the only hooks subcommand)
gemini gemma setup | start | stop | status | logsLocal Gemma routing through a LiteRT-LM server

Two things that look like commands are not. gemini update appears on some cheat sheets, including Google’s, but there is no such subcommand. Our run sent the word “update” to the model as a prompt, and it replied by describing the project. --ignore-env from an older release note fails with Unknown arguments: ignore-env, ignoreEnv. The advanced.ignoreLocalEnv setting is the documented way to stop project .env loading. These are the flags that matter day to day:

FlagUse
-m, --modelModel or alias: auto, pro, flash, flash-lite or a full model ID
-p, --promptHeadless mode; the text is appended to anything piped on stdin
-i, --prompt-interactiveRun a prompt then keep the session open (not allowed with piped stdin)
-o, --output-formattext, json or stream-json
--approval-modedefault, auto_edit, yolo or plan
-y, --yoloApprove every tool call; cannot be combined with --approval-mode
--policy, --admin-policyLoad extra policy TOML files or folders
--skip-trustTrust the current folder for this run
-s, --sandboxRelaunch the CLI in Docker, Podman or macOS Seatbelt
-r, --resumelatest, a session number or a session ID
--session-id, --session-fileStart a session with your own ID, or load one exported to JSON
--list-sessions, --delete-sessionList or remove saved sessions for this folder
--include-directoriesAdd folders to the workspace
-e, --extensions, -lLimit which extensions load, or list them
--allowed-mcp-server-namesOnly start the named MCP servers
-w, --worktreeStart in a new git worktree (needs experimental.worktrees)
--acpAgent Client Protocol mode for editors; --experimental-acp is deprecated
--raw-outputKeep ANSI escapes from the model; add --accept-raw-output-risk to silence the warning

Some combinations are rejected before any request goes out. Each of these printed the full help text after the message and exited 1:

  • --yolo --approval-mode plan: Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.
  • -r latest --session-id abc: The flags --resume, --session-id, and --session-file are mutually exclusive. Please provide only one.
  • -w feature-x: The --worktree flag is only available when experimental.worktrees is enabled in your settings.

--allowed-tools still parses, but its help text marks it deprecated in favour of the policy engine, which is covered further down. Use a policy file for anything new.

Pick a model with -m

The aliases don’t map to fixed models. Which model flash or auto reaches depends on your account and on server-side flags, so the only reliable answer is the stats.models block of a JSON run. This loop prints it for each alias on our free key:

for m in flash-lite flash pro auto; do printf '%-11s -> ' "$m"; gemini -m $m -p "Reply with one word: ok" -o json 2>/dev/null | jq -r '.stats.models | keys | join(", ")'; done

Three aliases resolved. The pro line is empty because that call failed with the zero quota shown earlier, so the auto result runs straight on after it:

flash-lite  -> gemini-3.5-flash-lite
flash       -> gemini-3.8-flash
pro         -> auto        -> gemini-3.5-flash-lite, gemini-3.8-flash

auto and a run with no -m at all both used two models: flash-lite to route the prompt and gemini-3.8-flash to answer it. Every call also carries the system prompt and tool definitions, so a one-word question cost 9,001 input tokens, which matters when you count requests against a daily quota. When several places set a model, the most specific one wins, and we checked each step:

Set inExampleWins over
-m on the command-m flash-liteeverything below (beat GEMINI_MODEL=gemini-3.8-flash)
GEMINI_MODEL environment variableGEMINI_MODEL=gemini-3.8-flashproject and user settings
Project .gemini/settings.json{"model": {"name": "gemini-2.5-flash"}}user settings
User ~/.gemini/settings.json{"model": {"name": "flash-lite"}}the built-in default (auto)

Inside the interactive UI, /model set flash-lite switches for the session and --persist writes it to settings. Google’s site says Gemini CLI is not tuned for Gemini 4 Argon and sends Argon users to Antigravity, and on a free key the question is moot because Argon returned limit: 0. If you’re choosing between the current flash models, our Gemini 3.8 Flash benchmarks cover speed and quality.

Run Gemini CLI headless in scripts and CI

Headless mode is -p. It prints the answer to stdout, sends warnings to stderr and exits, and anything you pipe in becomes part of the prompt. That makes it a log reader you can drop into a shell pipeline:

printf 'Oct 21 22:40 web01 kernel: EXT4-fs warning: /var is 100%% full\n' | gemini -m flash-lite -p "Which mount point is full? Answer with the path only." 2>/dev/null

Only the answer reaches stdout:

/var

For anything a script has to parse, ask for JSON. The envelope carries the session ID, the response and per-model token counts:

gemini -m flash-lite -p "Reply with one word: ok" -o json

The first line is a terminal warning on stderr from our SSH session, not part of the JSON, so jq never sees it. Read the token counts while you’re here: 9,001 input tokens and 198 thinking tokens to produce one output token:

Warning: 256-color support not detected. Using a terminal with at least 256-color support is recommended for a better visual experience.
{
  "session_id": "af7e02a4-9cc4-486d-9740-efff3f7c97fc",
  "response": "ok",
  "stats": {
    "models": {
      "gemini-3.5-flash-lite": {
        "api": {
          "totalRequests": 1,
          "totalErrors": 0,
          "totalLatencyMs": 2087,
          "errorsByType": {}
        },
        "tokens": {
          "input": 9001,
          "prompt": 9001,
          "candidates": 1,
          "total": 9200,
          "cached": 0,
          "thoughts": 198,
          "tool": 0
        },
        "roles": {
          "main": {
            "totalRequests": 1,
            "totalErrors": 0,
            "totalLatencyMs": 2087,
            "tokens": {
              "input": 9001,
              "prompt": 9001,
              "candidates": 1,
              "total": 9200,
              "cached": 0,
              "thoughts": 198,
              "tool": 0
            }
          }
        }
      }
    },
    "tools": {
      "totalCalls": 0,
      "totalSuccess": 0,
      "totalFail": 0,
      "totalDurationMs": 0,
      "totalDecisions": {
        "accept": 0,
        "reject": 0,
        "modify": 0,
        "auto_accept": 0
      },
      "byName": {}
    },
    "files": {
      "totalLinesAdded": 0,
      "totalLinesRemoved": 0
    }
  }
}

For long agent runs, -o stream-json prints one JSON event per line as it happens, which is what you want for live logs in CI:

gemini -m flash-lite -p "Reply with one word: ok" -o stream-json

After the same stderr warning, a run opens with init, echoes your prompt, streams message deltas and ends with result. Runs that call tools add tool_use and tool_result events in between:

Warning: 256-color support not detected. Using a terminal with at least 256-color support is recommended for a better visual experience.
{"type":"init","timestamp":"2026-10-21T21:58:49.859Z","session_id":"b68f9ca4-62b4-46dc-aeb5-9d348ac056b6","model":"flash-lite"}
{"type":"message","timestamp":"2026-10-21T21:58:49.861Z","role":"user","content":"Reply with one word: ok"}
{"type":"message","timestamp":"2026-10-21T21:58:51.897Z","role":"assistant","content":"ok","delta":true}
{"type":"result","timestamp":"2026-10-21T21:58:51.938Z","status":"success","stats":{"total_tokens":9425,"input_tokens":9001,"output_tokens":1,"cached":6097,"input":2904,"duration_ms":2080,"tool_calls":0,"models":{"gemini-3.5-flash-lite":{"total_tokens":9425,"input_tokens":9001,"output_tokens":1,"cached":6097,"input":2904}}}}

These are the jq filters we used on that output, and they cover most scripts:

  • jq -r .response for the answer from -o json
  • jq -r '.stats.models | keys | join(", ")' for the models a run used
  • jq -c 'select(.type=="tool_use") | {tool_name, cmd: .parameters.command}' for every tool call in a stream-json log
  • jq -c 'select(.type=="result")' for the final status and token totals

Check the exit code too, because Gemini CLI uses specific codes for its fatal errors. The numbers come from the error classes in the source, and the third column marks the ones we triggered on purpose:

Exit codeMeaningSeen in our runs
0Success, including runs where tools were silently skippedYes
1General failure in text output: API errors such as quota or an unknown model, rejected flag combinationsYes
HTTP status mod 256With -o json or -o stream-json, an API error exits with its HTTP status cut to 8 bits: a 429 quota error exits 173Yes (173)
41Authentication: no key or auth method foundYes
42Input: piped stdin with -i, empty stdin, a reused --session-idYes
44Sandbox: -s with no Docker or PodmanYes
52Config: settings.json that is not valid JSONYes
53Turn limit reachedNo
54Tool execution errorNo
55Folder not trusted in headless modeYes
130Cancelled with Ctrl+CNo

Exit code 0 is the trap. The next section shows a headless run that was asked to fix a bug, changed nothing and still exited 0, so a CI step should check git diff or a test result, never the exit code alone. An empty stdin with no prompt fails fast with No input provided via stdin. Input can be provided by piping data into gemini or using the --prompt option. and exit 42, so a broken pipe in a script errors out instead of waiting.

Control what the agent may do

Approval modes decide which tools run without asking you. In headless mode there is nobody to ask, so a tool that needs your approval is denied. To see what that means in practice, we built a two-file project whose add() function subtracts, and committed it so git checkout could reset it between runs:

mkdir -p ~/demo-app && cd ~/demo-app && git init -q && printf 'def add(a, b):\n    return a - b\n' > calc.py && printf 'from calc import add\n\ndef test_add():\n    assert add(2, 3) == 5\n' > test_calc.py && git add -A && git -c [email protected] -c user.name=josphat commit -qm init && ls

The listing confirms both files are in place:

calc.py
test_calc.py

Each mode then got the same prompt, “Fix the bug in calc.py, then run python3 -m pytest -q to prove it”, with -m flash-lite and no policy files in ~/.gemini/policies/. This is what each one did:

–approval-modeWhat happened headlesscalc.py fixed?Exit
defaultRead both files. Shell call failed: Tool "run_shell_command" not found; a subagent’s edit was blocked: 'replace' is not available to this agentNo0
auto_editEdited the file. Shell call failed the same way, so the test never ranYes, untested0
yoloRead, ran pytest, edited, ran pytest againYes, tested0
planRead both files, wrote a plan, called exit_plan_mode, then edited calc.py and ran pytestYes0

The default row is the one that bites in CI. Nothing changed, nothing was flagged, and the exit code was 0. The plan row is the surprise. Plan mode is documented as read-only, and in the interactive UI leaving it needs your approval, but in headless mode exit_plan_mode approves itself and switches the session to YOLO. The source says so in getAllowApprovalMode(), which returns YOLO when the session is not interactive, and our run used that to edit calc.py and run pytest after the plan step. Never treat -p --approval-mode plan as a safe dry run without the guard below.

Policy files fix both rows: an allow rule for the auto_edit row and a deny rule for the plan row, and auto_edit with a scoped allow rule is the combination we’d run in CI. Rules are TOML files in ~/.gemini/policies/, each one matching a tool (and optionally a command prefix) to allow, deny or ask_user, and ask_user counts as deny in headless runs. Create a rule that lets CI run the test suite and nothing else on the shell:

mkdir -p ~/.gemini/policies && vim ~/.gemini/policies/ci.toml

Add this rule. interactive = false limits it to headless runs, so your own sessions still ask, and modes = ["autoEdit"] keeps it out of plan mode. Our first version had no modes line, and plan-mode runs then executed pytest too, because a user rule outranks the built-in plan-mode denies:

[[rule]]
toolName = "run_shell_command"
commandPrefix = "python3 -m pytest"
decision = "allow"
priority = 100
interactive = false
modes = ["autoEdit"]

Rerun the auto_edit prompt and list the tool calls from the stream-json log:

gemini -m flash-lite --approval-mode auto_edit -p "Fix the bug in calc.py, then run python3 -m pytest -q to prove it" -o stream-json > /tmp/policy2.ndjson
jq -c 'select(.type=="tool_use") | {tool_name, cmd:.parameters.command}' /tmp/policy2.ndjson

Now pytest runs twice, once to see the failure and once after the edit:

{"tool_name":"update_topic","cmd":null}
{"tool_name":"read_file","cmd":null}
{"tool_name":"read_file","cmd":null}
{"tool_name":"run_shell_command","cmd":"python3 -m pytest -q"}
{"tool_name":"update_topic","cmd":null}
{"tool_name":"replace","cmd":null}
{"tool_name":"update_topic","cmd":null}
{"tool_name":"run_shell_command","cmd":"python3 -m pytest -q"}
{"tool_name":"update_topic","cmd":null}

The two pytest results in the log read 1 failed in 0.01s and then 1 passed in 0.01s, and git diff --stat showed one line changed in calc.py. To keep headless plan mode read-only, deny exit_plan_mode outside the interactive UI:

vim ~/.gemini/policies/plan-guard.toml

A deny rule with no argument pattern removes the tool from the model’s tool list completely, so it can’t even try:

[[rule]]
toolName = "exit_plan_mode"
decision = "deny"
priority = 900
interactive = false
denyMessage = "Headless runs stay in plan mode."

With both files in place, the same plan-mode prompt read the two files, wrote its plan and stopped: no exit_plan_mode, no shell call, and calc.py unchanged. The plan itself still gets written, under ~/.gemini/tmp/<project>/<session>/plans/. Inside the UI, /policies list shows how your files rank against the built-in ones. User rules land in the 4.x tier, above every default:

ℹ Active Policies
  ### Normal Mode Policies
  1. DENY tool: exit_plan_mode [Priority: 4.9] [Source: User: plan-guard.toml]
  2. DENY tool: ask_user [Priority: 1.999] [Source: Default: non-interactive.toml]
  3. ALLOW tool: invoke_agent [Priority: 1.05] [Source: Default: agents.toml]

The scoped test rule sits further down, at the top of the Auto Edit section:

  ### Auto Edit Mode Policies (combined with normal mode policies)
  1. ALLOW tool: run_shell_command (args match: \"command\":\"python3\ \-m\ pytest(?:[\s"]|\\")) [Priority: 4.1] [Source: User: ci.toml]
  2. ALLOW tool: replace [Priority: 1.015] [Source: Default: write.toml]

The full list runs to more than 50 rules across the four modes, including the YOLO block that allows *. The policy engine reference documents every field, from argsPattern and commandRegex to admin policies in /etc/gemini-cli/policies. If you want the theory behind tool calls, agent loops and memory that these rules are guarding, An Illustrated Guide to AI Agents (paid link) by Jay Alammar and Maarten Grootendorst (O’Reilly, October 2026) explains them with diagrams instead of marketing. It’s the book we’d hand someone before they let any agent loose in CI.

Use slash commands and shortcuts in the interactive UI

Slash commands only exist inside the UI. Typing /help there printed this set on our server, and the table keeps the ones you’ll reach for, with their subcommands:

Slash commandWhat it does
/about, /bug, /bug-memoryVersion info; file a bug; capture a V8 heap snapshot for a bug report
/auth signin | signoutChange the auth method or clear cached credentials
/clearClear the screen and start a new session (Ctrl+L only clears the screen)
/compressReplace the context with a summary
/resume save | resume | delete | list | shareCheckpoints and the session browser; /chat is the same command
/rewindJump back to an earlier message and restart from there
/export-sessionWrite the session to JSON for --session-file
/model set <name> [--persist]Switch model; /model manage opens the dialog
/stats session | model | toolsToken, latency and tool counts
/memory show | reload | list | inboxGEMINI.md context and skills learned from past sessions
/initWrite a GEMINI.md for the project
/mcp list | desc | schema | auth | reloadInspect and reload MCP servers
/tools, /tools descList built-in tools
/policies listShow active policy rules by mode
/permissions trust [path]Change folder trust
/plan, /plan copySwitch to plan mode; copy the approved plan
/directory add | showAdd folders to the workspace
/skills, /extensions, /hooks, /agentsManage skills, extensions, hooks and subagents
/commands list | reloadList or reload custom TOML commands
/settings, /theme, /vim, /editor, /footerSettings UI and display options
/copyCopy the last answer or code block
/setup-github, /terminal-setup, /ideGitHub Actions, multiline keys, IDE integration
/quitExit

Two prefixes do most of the work. @path pulls a file or folder into the prompt. Our @calc.py question ran the ReadManyFiles tool and got back the correct answer, that the function returns the difference of the two arguments. Typing ! on an empty prompt switches the input to shell mode. That is how !git log --oneline runs in bash. Shell mode stays on after that command until you press Esc. We typed /stats model while it was still on, and bash got it:

│ x  Shell Command /stats model                                                                                                                  │
│                                                                                                                                                │
│ Command exited with code 127.                                                                                                                  │
│                                                                                                                                                │
│ /usr/bin/bash: line 2: /stats: No such file or directory                                                                                       │

Watch the status line under the prompt, which reads shell mode enabled (esc to disable) while every line goes to bash. The shortcuts /help lists are short enough to learn in a day:

  • Shift+Tab cycles the approval mode (/help calls it auto-accepting edits), and Ctrl+Y toggles YOLO
  • Ctrl+L clears the screen and keeps the conversation
  • Ctrl+G opens the input in your external editor
  • Ctrl+P and Ctrl+N cycle prompt history
  • Esc cancels a running operation; press it twice to clear the input
  • F9 enters selection mode for copying text
  • Ctrl+Enter adds a new line, Ctrl+C quits

Custom keybindings go in ~/.gemini/keybindings.json, and Google’s keyboard shortcuts page has the full list, including the vim-mode motions.

Write settings.json the current way

Settings are nested objects now, grouped under keys such as model, ui, general, tools and security. Old guides, including the previous version of this page, still show flat keys like "theme" and "vimMode" at the top level. Open the user settings file:

vim ~/.gemini/settings.json

This is the file as the CLI left it on our server after we set the model and theme, chose API key auth in the UI and removed a test MCP server, which is why mcpServers is empty:

{
  "model": {
    "name": "flash-lite"
  },
  "ui": {
    "theme": "GitHub"
  },
  "mcpServers": {},
  "security": {
    "auth": {
      "selectedType": "gemini-api-key"
    }
  }
}

The model setting took effect on the next run, which reported gemini-3.5-flash-lite in stats.models. Mistakes in this file fail in four different ways, and only one of them stops the run:

What we put in settings.jsonWhat the CLI did
A trailing comma (invalid JSON)Error in /home/josphat/demo-app/.gemini/settings.json: Expected double-quoted property name in JSON at position 37 (line 1 column 38), exit 52
"vimMode": "yes" under generalPrinted Error in: general.vimMode Expected boolean, received string, then answered the prompt, exit 0
Old flat "model": "gemini-2.5-flash-lite"Printed Error in: model Expected object, received string, then answered the prompt anyway
Old flat "theme" and "vimMode" onlyNo message at all

The last row is the one to fix on purpose, because an outdated file loads without a word. Settings merge in this order, with later ones winning:

  1. built-in defaults
  2. system defaults file (/etc/gemini-cli/system-defaults.json on Linux)
  3. user file ~/.gemini/settings.json
  4. project file .gemini/settings.json (only in a trusted folder)
  5. system override file (/etc/gemini-cli/settings.json)
  6. environment variables, then command-line flags

Our model tests matched that order for the user file, project file, GEMINI_MODEL and -m. The system file paths come from the configuration reference, which also lists every key. Inside the UI, /settings edits the same file without the typo risk.

Resume sessions and name them for CI

Every run is saved as a session for the folder it ran in, headless runs included, so a busy CI box collects them fast. List them:

gemini --list-sessions

Ours had 25 after about 25 minutes of testing, each labelled with its first prompt and a UUID. These are the first three lines:

Available sessions for this project (25):
  1. Reply with exactly: ok (22 minutes ago) [feed183d-2ae5-49e3-a537-13552bc4c0c0]
  2. Reply with one word: ok (21 minutes ago) [533e1be9-fe2a-46dc-b993-f2feda1b1d2c]
  3. Reply with one word: ok (18 minutes ago) [1e3ee0f0-0b21-483f-906b-680defc22f41]

For pipelines, give the session your own ID so a later step can pick it up. Start one with a fact the next step has to remember:

gemini -m flash-lite --session-id nightly-ci-001 -p "Remember the codeword: tangerine. Reply with: noted" 2>/dev/null

It answers with the one word we asked for:

noted

A later step resumes that exact session by its ID. -r latest also worked for us, but on a shared runner another job’s session can become the latest one:

gemini -m flash-lite -r nightly-ci-001 -p "What was the codeword? One word." 2>/dev/null; echo "exit=$?"

The resumed run still had the first one’s context:

tangerine
exit=0

IDs are single use. Running --session-id nightly-ci-001 a second time stops with Error starting session: Session ID "nightly-ci-001" already exists. Use --resume to resume it, or provide a different ID. and exit 42, so put the build number in the ID. A few more session commands round it out:

  • gemini --delete-session 1 removes one (ours printed Deleted session 1: Reply with exactly: ok (22 minutes ago))
  • /export-session plus gemini --session-file <file> moves a session between machines
  • transcripts live in ~/.gemini/tmp/<project>/chats/ as JSONL
  • general.sessionRetention.maxAge sets how long they are kept (30 days by default)

Clear old sessions on shared runners, because the transcripts hold your prompts and the tool output that came back.

Add MCP servers, custom commands and GEMINI.md

gemini mcp add writes to the project’s .gemini/settings.json unless you pass --scope user. Add the filesystem server for the current project:

gemini mcp add fs npx -y @modelcontextprotocol/server-filesystem /home/josphat/demo-app

It confirms the scope and transport:

MCP server "fs" added to project settings. (stdio)

Our first gemini mcp list showed ✗ fs: ... (stdio) - Disconnected, most likely because npx was still fetching the package, and the same server read ✓ ... - Connected on the next list, so don’t debug a red cross on the first run. Remote servers take --transport http:

gemini mcp add --scope user --transport http docs https://example.com/mcp
gemini mcp list
gemini mcp remove --scope user docs

The list shows both scopes together, with the placeholder URL failing to connect as expected:

MCP server "docs" added to user settings. (http)
Configured MCP servers:

✗ docs: https://example.com/mcp (http) - Disconnected
✓ fs: npx -y @modelcontextprotocol/server-filesystem /home/josphat/demo-app (stdio) - Connected
Server "docs" removed from user settings.

gemini mcp disable and enable are in the help text but did not work on the release we tested: both returned Error: Server 'fs' not found. Use 'gemini mcp' to see available servers. for project and user servers alike. Use /mcp in the UI, --allowed-mcp-server-names on the command line, or remove the server.

Custom slash commands are TOML files. A file at ~/.gemini/commands/git/commit.toml becomes /git:commit, and !{...} runs a shell command and pastes its output into the prompt:

mkdir -p ~/.gemini/commands/git && vim ~/.gemini/commands/git/commit.toml

Add the description and prompt:

description = "Write a commit message for the staged diff"
prompt = """
Write a one-line conventional commit message for this diff:
!{git diff --staged}
"""

It showed up in /help as /git:commit with its description. Put files in .gemini/commands/ to share them with the repository instead. Project rules go in GEMINI.md at the repository root. We added two lines to ours (tests run with python3 -m pytest -q, never edit test files to make a test pass). A headless question about running the tests came back as `python3 -m pytest -q`. /memory list shows which GEMINI.md files are loaded.

Run the agent’s tools in a sandbox

-s relaunches Gemini CLI itself inside a container on Linux, or under Seatbelt on macOS, so the tools it runs can’t reach the rest of your machine. On a Linux box with neither Docker nor Podman it fails straight away with exit 44:

GEMINI_SANDBOX is true but failed to determine command for sandbox; install docker or podman or specify command in GEMINI_SANDBOX

Ubuntu’s docker.io package fixes that, plus a docker group membership for your user:

sudo apt install -y docker.io && sudo usermod -aG docker $USER

The group change only applies to new logins. After that, the first sandboxed run pulled Google’s sandbox image from us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox, tagged with the CLI version (1.67 GB), in under a minute. It then failed the trust check inside the container, even though the folder was trusted on the host and GEMINI_CLI_TRUST_WORKSPACE=true was exported: the variable isn’t passed into the container. Pass the flag instead, because command-line arguments do go through:

sg docker -c 'gemini -s --skip-trust -m flash-lite -p "Run uname -a and head -2 /etc/os-release, show the raw output" --approval-mode yolo' 2>&1 | grep -v 256-color

We ran it through sg docker because the new docker group membership was not active in that login yet. The tools ran in a Debian 12 container that shares the host kernel and mounts the project at the same path, as user node:

YOLO mode is enabled. All tool calls will be automatically approved.
YOLO mode is enabled. All tool calls will be automatically approved.
Linux sandbox-0.65.0-ac1257ff8271 7.0.0-15-generic #15-Ubuntu SMP PREEMPT_DYNAMIC Wed Apr 22 16:06:43 UTC 2026 x86_64 GNU/Linux
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"

That run took 15.6 seconds once the image was cached. SANDBOX_ENV=GEMINI_CLI_TRUST_WORKSPACE=true also works, and GEMINI_SANDBOX=podman picks Podman. On macOS, -s uses Seatbelt with the permissive-open profile by default. In our test on a Mac, a YOLO run asked to touch one file in the project and one in the home folder relayed this from the shell tool (home path shortened):

inside-ok
touch: ~/outside.txt: Operation not permitted

Google documents stricter profiles through SEATBELT_PROFILE (restrictive-open, strict-open and their -proxied variants). Our strict-open attempt crashed node with ERR_INVALID_PACKAGE_CONFIG because our npm prefix sat outside the paths that profile allows, so test a strict profile against your own install path before you rely on it. Pair -s with YOLO and the agent can run anything inside the project, which is the only setup where we’d use YOLO at all.

Map Gemini CLI flags to Antigravity CLI

Antigravity CLI (agy) is where Google sent personal accounts, and its flags look similar but are not the same. The biggest difference for scripts is that agy has no --yolo. This mapping comes from Google’s Antigravity headless docs rather than our lab, so treat it as a starting point:

Gemini CLIAntigravity CLI (agy)
gemini -p "..."agy -p "..." (also --print)
-o json | stream-json--output-format json | stream-json (different envelope: conversation_id, status, usage)
--yolo or --approval-mode yolo--dangerously-skip-permissions
Policy TOML in ~/.gemini/policies/permissions.allow rules such as command(git) in ~/.gemini/antigravity-cli/settings.json
-r latest--continue or -c
-m flash--model <slug> from agy models, plus --effort low|medium|high
Headless tool needing approval: denied, exit 0Soft-denied with a notice on stderr, exit 0

Both CLIs read GEMINI.md. Our Antigravity CLI cheat sheet covers agy in depth, and the Antigravity CLI install guide handles the keyring errors on headless Linux. If you’re weighing other terminal agents too, the Claude Code cheat sheet, Codex CLI commands and OpenCode reference were tested the same way.

Fix the Gemini CLI errors you will hit

These are the messages our lab produced, with the cause we confirmed for each. Search this page for the first few words of yours.

Error: “Gemini CLI is not running in a trusted directory”

A headless run in an untrusted folder exits 55. Add --skip-trust, export GEMINI_CLI_TRUST_WORKSPACE=true, or open gemini once in the folder and pick “Trust folder”. Inside a -s sandbox only --skip-trust or SANDBOX_ENV gets through.

Error: “Please set an Auth method in your ~/.gemini/settings.json”

Exit 41 means no usable key. Check GEMINI_API_KEY first. If the key is in ~/.gemini/.env and the folder isn’t trusted, the CLI skips that file, and --skip-trust does not change that, so export the variable or trust the folder.

Error: “Ripgrep is not available. Falling back to GrepTool.”

We removed ripgrep from the server and this line appeared on stderr; the search still worked through the slower built-in grep. Installing the distro package (sudo apt install ripgrep, which puts rg in /usr/bin) made it go away. The npm package ships no rg of its own, and the source only accepts a system rg whose real path sits under /usr/bin, /bin, /usr/local/bin, /usr/sbin, /sbin or the macOS Homebrew folders (/opt/homebrew/bin, /opt/homebrew/Cellar, /usr/local/Cellar). A copy in ~/.cargo/bin, Linuxbrew or the Nix store is ignored and you get the same message, so install it from the distro, or from Homebrew on a Mac.

Error: “Quota exceeded for metric … limit: 0”

A limit of 0 means your key’s tier can’t use that model at all, which on our free key covered every current pro model we tried. Switch to -m flash or -m flash-lite, or enable billing. A non-zero limit with Please retry in ... is a rate limit that clears on its own.

Error: “You have exhausted your daily quota on this model.”

Free keys have a daily request cap per model, which our key hit on gemini-3.8-flash during testing. Google’s rate-limit docs say daily quotas reset at midnight Pacific time; until then, move to another model with -m.

Error: “This model models/gemini-2.5-pro is no longer available to new users”

Google retired the 2.5 Pro model for new keys and suggests gemini-3.1-pro-preview instead, which needs a paid key. Drop old model IDs from scripts and settings.json and use the aliases.

Error: “Server ‘fs’ not found” from gemini mcp disable

The enable and disable subcommands didn’t find any configured server in our tests. Use gemini mcp remove, or start the CLI with --allowed-mcp-server-names listing the servers you want.

Error: “/usr/bin/bash: line 2: /stats: No such file or directory”

Shell mode was still on, so the slash command went to bash. Press Esc until the status line no longer says shell mode enabled, then retype the command. For setup problems before any of this, the install guide has the platform-specific fixes.

Keep reading

Ollama Models Cheat Sheet: Best Models by VRAM, Tested (PDF) AI Ollama Models Cheat Sheet: Best Models by VRAM, Tested (PDF) Open Source LLM Comparison Table (2026) AI Open Source LLM Comparison Table (2026) OpenCode CLI Cheat Sheet: Commands, Sessions and Fixes (PDF) AI OpenCode CLI Cheat Sheet: Commands, Sessions and Fixes (PDF) Best Weather Stations for Home Assistant: Ecowitt, Tempest, Davis Automation Best Weather Stations for Home Assistant: Ecowitt, Tempest, Davis Best Water Leak Sensors and Auto Shutoff Valves for Home Assistant Automation Best Water Leak Sensors and Auto Shutoff Valves for Home Assistant Setup GitLab Runner on Rocky Linux 10 / Ubuntu 24.04 Automation Setup GitLab Runner on Rocky Linux 10 / Ubuntu 24.04

Leave a Comment

Press ESC to close