Compare commits

...

348 Commits

Author SHA1 Message Date
davidapierce d2b1009e9f Update public workflow trust, readme, and run formatter. 2026-06-22 17:42:11 +00:00
Ramón Medrano Llamas be7ba2c22a fix: resolve workspace publish failures and scheduler event loop starvation (#28063) 2026-06-21 21:27:18 +00:00
Vedant Mahajan c22137ea0a feat: add eval:inventory CLI command and reporting logic (#28009) 2026-06-19 18:01:01 +00:00
Ramón Medrano Llamas 6613e129de fix(ci): append trailing slash to registry url in npmrc (#28038) 2026-06-19 14:54:12 +00:00
Gal Zahavi 93844dfa10 chore(deps): pin dependencies and enforce 14-day update cooldown (#27948) 2026-06-18 23:58:35 +00:00
Gal Zahavi c427d18fea fix(ci): provide fallbacks for package variables in nightly release (#28016) 2026-06-18 21:28:15 +00:00
gemini-cli-robot d5e25b9929 Changelog for v0.48.0-preview.0 (#27999)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-06-18 17:45:57 +00:00
gemini-cli-robot 7ef3b4e1fc chore(release): bump version to 0.49.0-nightly.20260617.g4d3dcdce1 (#28003) 2026-06-18 17:34:42 +00:00
Gal Zahavi 4d3dcdce1f Revert "fix(core-tools): resolve defensive path resolution for at-reference files" (#27992) 2026-06-17 13:23:03 -07:00
luisfelipe-alt f741d03282 fix(core-tools): resolve defensive path resolution for at-reference files (#27943) 2026-06-16 22:05:03 +00:00
Gal Zahavi 926f3d9b95 fix(config): migrate coreTools setting to tools.core (#27947) 2026-06-16 21:34:08 +00:00
Vedant Mahajan 97455e5d43 Add static eval source analyzer (#27631) 2026-06-16 20:08:42 +00:00
amelidev 5624a3b01d fix(cli): handle tmux false positive background detection (#27572)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
2026-06-16 18:34:53 +00:00
sidhantgoyal-droid fbce3e51b6 feat(core): Support GDC air-gapped Service Identity after auth library update (#27956) 2026-06-16 17:48:06 +00:00
Ramón Medrano Llamas 83d7567329 ci: use internal environment for scheduled nightly releases (#27865) (#27939) 2026-06-15 22:58:11 +00:00
jvargassanchez-dot 0f8a157e5e Fix/pending tools and trust overrides (#27854) 2026-06-15 22:24:50 +00:00
Om Patel bca5667fc6 fix(cli): prevent path traversal vulnerabilities during skill install… (#27767) 2026-06-15 15:39:46 +00:00
Cesar Sanchez Coraspe 9e5599c323 fix(core): handle multi-line escaped quotes in stripShellWrapper (#27467)
Co-authored-by: luisfelipe-alt <luisfelipe@google.com>
2026-06-12 19:01:46 +00:00
luisfelipe-alt ba12896a37 fix(core): Ensure zero-quota limits fail fast to prevent retry loop hang (#27698)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-06-12 18:59:21 +00:00
Gal Zahavi 4e10a34be8 ci: update workflow logging and policy configurations (#27853) 2026-06-11 21:38:56 +00:00
Gal Zahavi 1eb8bd418c refactor(core): standardize tool output formatting (#27772) 2026-06-11 21:22:13 +00:00
ruomeng 5d4af9f812 ci(dependabot): enable cooldown period for npm packages (#27743) 2026-06-10 14:07:25 +00:00
gemini-cli-robot 1d2adf7937 chore(release): bump version to 0.48.0-nightly.20260609.g3a13b8eeb (#27779) 2026-06-10 04:45:21 +00:00
Sandy Tao 3a13b8eeb6 Avoid persisting empty resume sessions (#27770) 2026-06-09 22:41:47 +00:00
David Pierce 4523560278 Add documentation and migration commands for Antigravity CLI (#27765)
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
2026-06-09 21:00:26 +00:00
David Pierce f08b4af654 Vertex ai model mapping fix (#27749) 2026-06-09 20:02:50 +00:00
luisfelipe-alt 8e99c26dd8 fix(core): implement atomic update in MCP tool discovery (#27619)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
2026-06-09 18:51:02 +00:00
Gaurav 0567b25a26 chore: remove experimental text from browser agent docs (#27746) 2026-06-08 16:23:21 +00:00
David Pierce f40498db64 update the max amount of times the Antigravity transition banner can be displayed. (#27676) 2026-06-05 14:35:13 +00:00
gemini-cli-robot 4196596f7f Changelog for v0.45.0 (#27642)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-06-03 17:15:26 +00:00
Krish Garg dceb2ea306 fix(policy): add EBUSY fallback and TOML parse recovery (#19919) (#21541)
Signed-off-by: krishdef7 <gargkrish06@gmail.com>
Co-authored-by: Sikandar <ma5161310@gmail.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-06-03 10:12:50 -07:00
David Pierce e4315b36eb Respect backend definitions for 3.5 flash and Update auto mode to use 3.5 flash when the flag is enabled. (#27645) 2026-06-03 15:12:53 +00:00
gemini-cli-robot d2cd12a7cb Changelog for v0.46.0-preview.0 (#27641)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-06-03 03:43:45 +00:00
gemini-cli-robot ae87e208ac chore(release): bump version to 0.47.0-nightly.20260602.gcfcecebe8 (#27644) 2026-06-03 03:43:10 +00:00
Sri Pasumarthi cfcecebe80 fix(ci): use pull_request_target trigger to grant write access on fork PRs (#27637) 2026-06-02 19:42:47 +00:00
Sri Pasumarthi 5110bdf56c chore(ci): add optimized PR size labeler and batch workflows (#27616) 2026-06-02 02:05:33 +00:00
David Pierce 665228e983 Transition to flash GA model when experiment flag is present. (#27570) 2026-06-01 23:36:49 +00:00
Tommaso Sciortino 013914071c Adding quote (#27571) 2026-05-29 13:43:16 -07:00
nirali 211e7d1aec fix(cli): prevent spam loop when preferredEditor is invalid (#25324)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-29 13:43:03 -07:00
gemini-cli-robot b77beba13a Changelog for v0.44.0 (#27569)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-29 19:40:17 +00:00
gemini-cli-robot c82e2b5976 Changelog for v0.45.0-preview.0 (#27495)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-28 17:44:19 +00:00
Tommaso Sciortino bd53951dc8 fix(core): harden PTY resize against native crashes (#27496) 2026-05-28 09:16:24 -07:00
Mukunda Rao Katta 5cac7c10fa fix(cli): ignore unmapped vim normal keys (#27102) 2026-05-27 17:03:00 +00:00
Om Patel 41c9260cae fix(core): prevent blacklist bypass in mcp list (#27377)
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
2026-05-26 22:08:37 +00:00
Tommaso Sciortino 8b56d27901 fix(core): suppress PTY resize EBADF errors (#27461) 2026-05-26 19:43:51 +00:00
Daniel Weis 85563dabe8 fix(core): bypass routing classifiers to prevent orphaned function response errors (#27389) 2026-05-26 16:19:41 +00:00
David Pierce 4a5d5cfc9f Update default auto routing (#27071) 2026-05-26 14:31:07 +00:00
Ramón Medrano Llamas 630ecc21b9 fix(cli): filter internal session context from history during resumption (#27391) 2026-05-24 06:38:53 +00:00
Billy Biggs 3cc7e5b096 Revert "fix(core): prevent SIGHUP kills in PTY environments" (#27401) 2026-05-23 20:52:45 +00:00
gemini-cli-robot a00d03efc6 Changelog for v0.43.0 (#27361)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-22 22:26:32 +00:00
gemini-cli-robot 980a2574df Changelog for v0.44.0-preview.0 (#27360)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-22 22:26:24 +00:00
jvargassanchez-dot 5188601de0 fix(core): force update_topic tool to execute sequentially (#27357) 2026-05-22 20:39:27 +00:00
joshualitt e6f92d66f6 feat(context): Complete simplification work. (#27345) 2026-05-22 18:06:40 +00:00
jvargassanchez-dot d1fa323cfb Feat/a2a expose usage metadata (#27288) 2026-05-22 17:51:39 +00:00
Syed Ayman Quadri ba04e99bea fix(cli): prevent Termux relaunch and resize remount loops (#27110)
Co-authored-by: Spencer <spencertang@google.com>
2026-05-22 06:33:52 +00:00
gemini-cli-robot 6afb109953 chore(release): bump version to 0.45.0-nightly.20260521.g854f811be (#27362) 2026-05-22 01:35:39 +00:00
Coco Sheng 854f811be0 perf: optimize issue triage and lifecycle management (#27346) 2026-05-21 18:42:59 +00:00
Dev Randalpura c4d0e3ca36 fix(ui): added volta to auto update check (#27353) 2026-05-21 18:05:33 +00:00
gemini-cli-robot df1d1119c3 chore/release: bump version to 0.44.0-nightly.20260521.g57c42a5c4 (#27324) 2026-05-21 17:52:43 +00:00
joshualitt 50c2e6764f fix(context): Ensure last message is processed. (#27232) 2026-05-21 15:46:26 +00:00
Coco Sheng 906f8a3151 ci: robust stale issue lifecycle and consolidated triage labels (#27015) 2026-05-20 21:50:19 +00:00
adithya32 64cb88d50e fix(windows): resolve interactive shell arrow-key navigation on Windows (#23505) 2026-05-20 21:41:34 +00:00
tison 96903d50a1 Auto detect pnpm global installation path for macOS and Windows (#22748)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Coco Sheng <cocosheng@google.com>
2026-05-20 21:26:11 +00:00
Coco Sheng 5c4420cc27 fix(core): dynamic fallback routing for exhausted quota models (#27315) 2026-05-20 20:59:33 +00:00
PROTHAM f79d5e059c fix(core): prevent SIGHUP kills in PTY environments (WSL2/Kitty/Alacritty) (#27267) 2026-05-20 20:43:14 +00:00
Coco Sheng d7384c446f fix(core): centralize path validation to prevent crashes from malformed prompts (#27211) 2026-05-20 19:55:57 +00:00
Dev Randalpura e440e02866 fix(core): Added date field for the GCal MCP (#27251) 2026-05-20 18:31:52 +00:00
Hashaam Zahid c854b60f75 fix(scripts): scrub CI env vars in dev to keep interactive mode (#27159) 2026-05-20 17:55:54 +00:00
Coco Sheng 99ae4d8b81 fix(core): generalize MCP compliance fix for tool results (#27045) 2026-05-20 17:31:00 +00:00
Debasish aebdba6565 fix(core): improve Alpine shell compatibility (#26770) 2026-05-20 17:16:22 +00:00
Yuvraj Angad Singh 26f8c0f65e refactor: decouple stored session deletion from ChatRecordingService (#22920) (#27039) 2026-05-20 17:09:17 +00:00
Coco Sheng 29481a1562 fix: robust ripgrep path resolution and 1p hermetic execution support (#27253) 2026-05-20 16:29:00 +00:00
Coco Sheng 2c85f57402 fix(cli): integrate PolicyEngine into ACP session to prevent deadlocks (#23507) (#27252) 2026-05-20 16:16:09 +00:00
Ramón Medrano Llamas 124539b5cc fix(devtools): bundle devtools package to avoid resolution errors (#27250) 2026-05-20 07:14:57 +00:00
gemini-cli-robot ec4910f0bb Changelog for v0.43.0-preview.1 (#27297)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-20 03:49:29 +00:00
Andrea Alberti 57c42a5c40 feat(cli): add Sublime Text and Emacs Client editors, improve error messages and documentation (#21090)
Co-authored-by: Ananth Kini <ananthkini1@gmail.com>
2026-05-19 20:03:25 +00:00
ashishch432 8997488ea6 fix(cli): preserve proxy-agent named exports in ESM bundle (#27145) 2026-05-19 19:41:31 +00:00
kaluchi 6589cdf11b Proposal: deterministic encoding for child-process I/O (#27247) 2026-05-19 19:41:04 +00:00
Dev Randalpura 9de4289287 fix(core): correctly handle nullable array types in MCP tools (#27228) 2026-05-19 18:24:18 +00:00
Coco Sheng 37f3a4c90a fix(core): respect NO_PROXY in global fetch dispatcher (#27216) 2026-05-19 17:56:59 +00:00
Om Patel fcc8c62b8b fix(core): prevent path traversal in custome command file injection (#27234) 2026-05-19 17:37:46 +00:00
Adam Weidman c4758ba820 feat(core): wire AgentSession invocations into agent-tool (#26948) 2026-05-19 16:56:43 +00:00
Ramón Medrano Llamas 96a8d1d069 fix(cli): bundle ink worker-entry.js (#27249) 2026-05-19 16:47:36 +00:00
Dev Randalpura 3494fda2cf fix(core): add exception handling to migrateFromFileStorage (#27229) 2026-05-19 15:10:21 +00:00
Coco Sheng 1a024f30a3 fix: allow configured MCP servers in non-interactive mode (#27215) 2026-05-19 14:44:09 +00:00
Adam Weidman 5650fa90d7 feat(core): add RemoteSessionInvocation (#26937) 2026-05-19 14:17:24 +00:00
Keith Schaab 85566a73f6 fix(a2a-server): Implement default policy loading for parity with CLI (#27073) 2026-05-19 14:09:57 +00:00
Rajesh patel 7478859502 fix(cli): Prevent unmapped keys in Vim Normal mode from inserting text into prompt Input. (#25139)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-19 00:17:55 +00:00
Tirth Naik f09d45d133 fix(core): prevent isBinary false-positive on Windows PTY streams (#26565) 2026-05-18 23:36:23 +00:00
Daniel Weis 792654c88b refactor: decouple auto model description and configuration from releaseChannel (#27227)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-05-18 20:15:55 +00:00
Adam Weidman 6973b963ae feat(core): add LocalSessionInvocation (#26665) 2026-05-18 19:30:21 +00:00
kaluchi dc47aaa2d9 fix(core): prefer pwsh.exe over Windows PowerShell 5.1 (#25859) (#25900)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-18 17:44:05 +00:00
Dev Randalpura 7ff60809ef fix(core): add unit tests for stableStringify (#27212) 2026-05-18 17:23:05 +00:00
joshualitt 055e0f6452 fix(context): Fix snapshot recovery across sessions. (#26939) 2026-05-18 16:44:59 +00:00
Adam Weidman 9d01958cdb feat(skills): add agent-tui and tui-tester skills (#27121) 2026-05-18 15:46:02 +00:00
Adam Weidman 84423e6ea1 fix(core): enforce compile-time exhaustiveness in content-utils (#27207) 2026-05-18 15:16:49 +00:00
Adam Weidman 5611ff40e7 feat(core): add adk.agentSessionSubagentEnabled flag (#26947) 2026-05-17 17:38:34 +00:00
David Pierce 77e65c0db5 fix(core): use hasAccessToPreview for auto model resolution and fix disappearing models (#27112) 2026-05-15 17:26:59 +00:00
Anish Sabharwal b36788eb2a fix(core): add aliases and thinking config for gemini-3.1 models (#27007) 2026-05-15 16:29:15 +00:00
PROTHAM d32c9b77df Fix/web fetch ctrl c abort (#24320)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-15 16:26:03 +00:00
Tommaso Sciortino b213fd68ec security: update dependencies to fix critical and high vulnerabilities (#27077) 2026-05-15 02:01:38 +00:00
sotokisehiro 928a311fb0 fix(core): externalize https-proxy-agent to fix proxy support (#26361) 2026-05-14 22:34:36 +00:00
7. Sun f6494f3862 docs: update sandbox image command (#26774) 2026-05-14 22:08:15 +00:00
Coco Sheng b7f2067dd7 fix(cli): explicitly clear entrypoint when spawning sandbox container (#27059) 2026-05-14 21:50:29 +00:00
Dev Randalpura 7a5a8183bf fix(ui): add ENAMETOOLONG and ENOTDIR to exceptions for file parsing errors (#27069) 2026-05-14 21:23:42 +00:00
Gal Zahavi 0c0d88d90b docs(extensions): clarify env var sanitization policy for MCP and ext… (#22854)
Co-authored-by: Jack Wotherspoon <jackwoth@google.com>
Co-authored-by: Jenna Inouye <jinouye@google.com>
2026-05-14 21:23:38 +00:00
PROTHAM 2151653133 fix(core): resolve EISDIR errors during file processing (#21527) (#27041) 2026-05-14 21:21:57 +00:00
Tommaso Sciortino a6ed2cc5e3 fix(deps): update vulnerable dependencies (#27062) 2026-05-14 21:19:27 +00:00
David Pierce 5159b081bd fix(core): ensure stable admin settings comparison across IPC to prevent restart loop (#27066) 2026-05-14 19:44:03 +00:00
Gal Zahavi 918d6b6085 fix(core): ensure Vertex AI sets hasAccessToPreviewModels and remove aggressive 404 fallback revocation (#27067) 2026-05-14 19:42:09 +00:00
Dev Randalpura 6fee663ddc fix(ui): preserve new line at the end of edit window (#27057) 2026-05-14 18:33:41 +00:00
Coco Sheng 456d1aec74 fix(cli): resolve permission denied in sandbox on NixOS and other distros (#27004) 2026-05-14 17:15:12 +00:00
Coco Sheng e3f2d3e1ef fix(core): respect NO_PROXY for network-based MCP servers (#27012) 2026-05-14 17:11:17 +00:00
Sri Pasumarthi b705505dae fix(acp/auth): prevent conflicting credentials on enterprise gateways and support optional API keys natively (#27021) 2026-05-14 15:38:01 +00:00
Spencer 488d71b8c9 feat(core): expose RAG snippets to local log file for debugging (#27016) 2026-05-14 02:34:12 +00:00
Gal Zahavi 77078b3e8a fix(core): ensure stable fallback for restricted preview models (#26999) 2026-05-13 21:46:41 +00:00
ifitisit 1814c7f358 fix(cli): don't crash when an @-mention captures a non-path blob (#25980) 2026-05-13 21:43:08 +00:00
EMERSON BUSSON 724981baf8 fix(core): throttle shell text output and bound live UI buffer (#26955) 2026-05-13 21:34:32 +00:00
Sandy Tao 7504259d72 chore: clean up launched memory features (#26941)
Co-authored-by: Jenna Inouye <jinouye@google.com>
2026-05-13 21:22:56 +00:00
Coco Sheng 0750b01fe4 fix: add system PATH fallback for ripgrep resolution (#26777) (#26868) 2026-05-13 21:05:37 +00:00
Dev Randalpura 41599ce29f fix(core): made context files append instead of replace (#26950)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-13 19:45:30 +00:00
Tommaso Sciortino 74e9079e5b chore: add execution permission to scripts/review.sh (#27009) 2026-05-13 12:22:00 -07:00
AK 9da30b8831 fix(core): isolate subagent thread context (#26449) 2026-05-13 18:55:17 +00:00
Dev Randalpura 71a2c0264e fix(ui): clamped table column widths (#26991)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-13 18:43:49 +00:00
Sahil Kirad fd01cc03bf fix(core): refresh MCP OAuth token usage after re-auth (#26312)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-13 12:01:27 -07:00
Coco Sheng fc4054446f ci: suppress bot comments during standard triage maintenance (#27006) 2026-05-13 18:43:07 +00:00
Coco Sheng 08abe4542d fix(cli): auto-approve shell redirections in AUTO_EDIT mode (#27003) 2026-05-13 18:28:30 +00:00
Coco Sheng 63b4bbfb5d fix(core): handle EISDIR on virtual drives in memory discovery (#26985) 2026-05-13 17:41:49 +00:00
Coco Sheng 1e7063bb0b fix(cli): allow keychain auth for --list-sessions and non-interactive mode (#26921) 2026-05-13 17:35:21 +00:00
Coco Sheng 297d3a3067 fix(core): preserve OAuth refresh tokens during rotation and retrieval (#26924) 2026-05-13 17:19:05 +00:00
David Pierce 749657cbf9 feat(cli): merge Auto modes into a single Auto mode (#26714) 2026-05-13 16:55:43 +00:00
Adam Weidman 8cda688fe2 feat(core): change agent registration to first-wins and prioritize project (#26953) 2026-05-13 01:33:12 +00:00
gemini-cli-robot 5ee05c775e Changelog for v0.43.0-preview.0 (#26959)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-13 00:01:24 +00:00
mahadevan 31d5947d37 Refactor: Eliminate no-unsafe-return suppressions via strict type validation (#20668)
Signed-off-by: M-DEV-1 <mahadevankizhakkedathu@gmail.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-12 23:45:58 +00:00
gemini-cli-robot 8f03aa320e Changelog for v0.42.0 (#26958)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-12 22:54:14 +00:00
gemini-cli-robot 583839ba46 chore(release): bump version to 0.44.0-nightly.20260512.g022e8baef (#26957) 2026-05-12 22:44:04 +00:00
Tommaso Sciortino 022e8baefc fix(ci): configure git remote with token for authentication (#26949) 2026-05-12 15:15:16 -07:00
Coco Sheng 120dfc724d fix(core): update read_file schema for v1 compatibility (#22183) (#26922) 2026-05-12 21:41:49 +00:00
Dev Randalpura c37b9113d7 fix(ui): fixed line wrap padding for selection lists (#26944) 2026-05-12 21:24:40 +00:00
Christian Gunderman 2334e9b1c4 Incremental refactor repo agent towards skills-based composition (#26717)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-12 20:37:09 +00:00
Tommaso Sciortino f901a4e6b7 fix(ci): replace brittle --no-tag with explicit staging-tmp tag (#26940) 2026-05-12 13:39:54 -07:00
Adam Weidman c987b99394 refactor(core): introduce SubagentState enum for progress (#26934) 2026-05-12 18:58:25 +00:00
Coco Sheng c4973d01da ci: actively triage missing priority labels and intelligently clean up conflicting labels (#26865) 2026-05-12 18:33:55 +00:00
kevinjwang1 27a39b04b0 Enable NumericalRouter when using dynamic model configs (#26929) 2026-05-12 18:06:21 +00:00
Sandy Tao ebe15553a9 Exclude extension context from skill extraction agent (#26879) 2026-05-12 10:45:19 -07:00
Yulong Wu bc730b2c0f fix (telemetry): inject quota_project_id to prevent fallback to default oauth client (#26698)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-12 17:02:15 +00:00
Gal Zahavi 9fe8643552 chore: update checkout action configuration in workflows (#26897) 2026-05-12 16:58:37 +00:00
joshualitt 07792f98cd feat(context): Introduce adaptive token calculator to more accurately calculate content sizes. (#26888) 2026-05-12 15:51:20 +00:00
Coco Sheng 7a9ed4c20a fix: respect explicit model selection after Flash quota exhaustion (#26759) (#26872) 2026-05-12 14:26:50 +00:00
Kuroda Kayn 11a9edc808 fix(cli): restore resume for legacy sessions (#26577)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-12 00:28:47 +00:00
Adam Weidman 24b98ade86 fix(cli): enable adk non-interactive session (#26895) 2026-05-11 23:38:23 +00:00
Eswar809 9f759f97a2 fix(core): ignore .pak and .rpa game archive formats by default (#26884)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-11 21:58:08 +00:00
Franco Pieri 9ff7304391 Allow Enter to select session while in search mode in /resume (#21523)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-11 21:46:00 +00:00
Neil Nair 84fc5cd533 Fix/vscode run current file ts (#22894)
Co-authored-by: Spencer <spencertang@google.com>
2026-05-11 21:21:42 +00:00
Daniel Weis e1b3ce5b36 revert 6b9b778d82 (#26893) 2026-05-11 21:07:54 +00:00
Suhaan Raqeeb Khavas 8e58df72c6 fix: prevent EISDIR crash when customIgnoreFilePaths contains directories (#19868) (#19898)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-11 20:46:08 +00:00
Dev Randalpura c0d5ab1f1e fix(ui): added a gutter width to the input prompt width calculation (#26882) 2026-05-11 20:26:48 +00:00
Coco Sheng 1340c96071 fix(core): handle malformed projects.json in ProjectRegistry (#26885) 2026-05-11 20:19:01 +00:00
Daniel Weis f8198a25d8 fix(routing): Refactor tool turn handling for the conversation history in NumericalClassifierStrategy to prevent 400 Bad Request (#26761) 2026-05-11 20:09:38 +00:00
Coco Sheng 36a7fa089c fix(cli): use static tool name in confirmation prompt to avoid parsing errors (#26866) 2026-05-11 17:45:58 +00:00
Sri Pasumarthi 4739495e39 fix(cli/acp): prevent infinite thought loop in ACP mode by disablig nextSpeakerCheck (#26874) 2026-05-11 17:38:20 +00:00
Aryan Singh ecfaac2dc7 fix(cli): prevent duplicate SessionStart systemMessage render (#25827)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
2026-05-11 16:44:04 +00:00
Daniel Finimundi 7cd228f5af fix(cli): allow installing extensions from ssh repo (#26274)
Signed-off-by: Daniel Finimundi <danielrf@motorola.com>
Co-authored-by: Dev Randalpura <devrandalpura@google.com>
2026-05-11 15:57:52 +00:00
joshualitt 8a3fde4c33 fix(context): Change snapshotter model config. (#26745) 2026-05-11 15:06:55 +00:00
joshualitt 1a894c18ea feat(context): Improvements to the snapshotter. (#26655) 2026-05-08 23:54:44 +00:00
Adam Weidman 54f1e8c6d7 feat(core): add RemoteSubagentProtocol behind AgentProtocol (#25303) 2026-05-08 22:48:17 +00:00
krishdef7 f51391a0f2 fix(mcp): treat GET 404 as 405 in StreamableHTTPClientTransport (#24847)
Co-authored-by: Coco Sheng <cocosheng@google.com>
Co-authored-by: Spencer <spencertang@google.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-08 22:16:08 +00:00
Sri Pasumarthi 1238dcfe91 feat(acp/core): prefix tool call IDs with tool names to support tool rendering in ACP compliant IDEs. (#26676) 2026-05-08 21:21:54 +00:00
Coco Sheng 90e7155971 ci: implement codebase-aware effort level triage (#26666) 2026-05-08 20:48:54 +00:00
JAYADITYA 9d0860bd0f fix(cli): remove noisy theme registration logs from terminal (#25858)
Co-authored-by: Jack Wotherspoon <jackwoth@google.com>
2026-05-08 19:59:33 +00:00
Adam Weidman 014bfeb89b feat(core): add LocalSubagentProtocol behind AgentProtocol (#25302) 2026-05-08 19:28:16 +00:00
Aishanee Shah 5890f50496 fix(core): resolve parallel tool call streaming ID collision (#26646) 2026-05-08 19:14:23 +00:00
Daniel Weis 6b9b778d82 fix: resolve "function response turn must come immediately after function call" error (#26691)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-08 19:01:24 +00:00
Aishanee Shah f86e0ee418 fix(core): throw explicit error on dropped tool responses (#26668) 2026-05-08 18:36:39 +00:00
joshualitt 01635ddb83 fix(context): implement loose boundary policy for gc backstop. (#26594) 2026-05-08 17:36:57 +00:00
Adam Weidman 12c8469b34 refactor(core): agent session protocol changes (#26661) 2026-05-08 17:12:54 +00:00
gemini-cli-robot 43dda31549 Changelog for v0.41.0 (#26670)
Co-authored-by: g-samroberts <158088236+g-samroberts@users.noreply.github.com>
2026-05-08 17:00:48 +00:00
Dev Randalpura dfec94869b fix(ui): added quotes around session id in resume tip (#26669) 2026-05-08 16:55:51 +00:00
Christian Gunderman f42d4e3c16 fix(ci): fix maintainer identification in lifecycle manager (#26706) 2026-05-08 16:48:31 +00:00
ruomeng 838f6f8c18 docs(extensions): refactor releasing guide and add update mechanisms (#26595) 2026-05-08 16:20:22 +00:00
mahadevan 2cad5db770 Feat: Add Machine Hostname to CLI interface (#25637)
Signed-off-by: M-DEV-1 <mahadevankizhakkedathu@gmail.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-08 16:12:35 +00:00
Coco Sheng 3805640530 feat: export session to file and import via flag (#26514) 2026-05-08 15:53:52 +00:00
Tommaso Sciortino 2d10691acb skip broken test (#26705) 2026-05-08 15:47:08 +00:00
gemini-cli-robot 38a9dd18d3 Changelog for v0.42.0-preview.2 (#26597)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
Co-authored-by: Sam Roberts <158088236+g-samroberts@users.noreply.github.com>
2026-05-08 00:53:59 +00:00
AK ebeea7570d fix(core): cache model routing decision in LocalAgentExecutor (#26548) 2026-05-08 00:18:22 +00:00
Br1an c52acebaa2 fix: prevent false command conflicts when launching from home directory (#23069)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-07 22:41:12 +00:00
Sandy Tao 16e345831b fix(cli): hide /memory add subcommand when memoryV2 is enabled (#26605) 2026-05-07 20:48:12 +00:00
Coco Sheng 3a0b19d900 ci: fix json parsing in scheduled triage workflow (#26656) 2026-05-07 20:35:20 +00:00
Dev Randalpura 451bf32c82 fix(ux): fixed issue with transcribed text not showing after releasing space (#26609) 2026-05-07 19:39:03 +00:00
Christopher Thomas 4fd411afe3 docs: add vi mode shortcuts and clarify MCP/custom sandbox setup (#23853)
Co-authored-by: Sam Roberts <158088236+g-samroberts@users.noreply.github.com>
2026-05-07 19:37:51 +00:00
Daniel Weis ac31e80984 fix(routing): fix resolveClassifierModel argument mismatch in ApprovalModeStrategy (#26658)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-07 19:34:14 +00:00
Coco Sheng 49456e4e15 fix(core): preserve system PATH in Git environment to fix ENOENT (#25034) (#26587) 2026-05-07 18:24:49 +00:00
Tommaso Sciortino a809bc7c51 don't wrap args unnecessarily (#26599) 2026-05-06 23:20:47 +00:00
Michael Bleigh 90304b279c refactor(cli): migrate core tools to native ToolDisplay property and fix UI rendering (#25186) 2026-05-06 21:23:26 +00:00
Coco Sheng 4a10751b49 ci: fix Argument list too long in triage workflows (#26603) 2026-05-06 21:10:01 +00:00
gemini-cli-robot 20b5a4cf46 Changelog for v0.42.0-preview.0 (#26537)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-05-06 20:31:17 +00:00
Rhys Sullivan bb4224fdff fix(core): prevent silent hang during OAuth auth on headless Linux (#26571)
Co-authored-by: Jack Wotherspoon <jackwoth@google.com>
2026-05-06 19:47:30 +00:00
Adib234 a38f393af7 fix(cli): improve mcp list UX in untrusted folders (#26457)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-06 19:35:35 +00:00
ruomeng feae856d6e fix(ci): preserve executable bit for mac binaries (#26600) 2026-05-06 19:23:30 +00:00
Christian Van e4242edf61 fix(cli): hide read-only settings scopes (#26249) 2026-05-06 19:03:48 +00:00
Sandy Tao 7fb5146c6b Tighten private Auto Memory patch allowlist (#26535) 2026-05-06 17:32:15 +00:00
joshualitt 897a4d7f83 fix(core): Fix hysteresis in async context management pipelines. (#26452) 2026-05-06 16:37:08 +00:00
Kartik 5155221bbe fix(cli): randomize sandbox container names (#26014) 2026-05-06 16:33:24 +00:00
Keith Schaab 02995ba939 fix(a2a-server): Resolve race condition in tool completion waiting (#26568) 2026-05-06 16:20:22 +00:00
Sri Pasumarthi 97a2bd7507 fix(acp): move tool explanation from thought stream to tool call content (#26554) 2026-05-06 15:42:01 +00:00
cynthialong0-0 80e091a8e1 fix(core): handle invalid custom plans directory gracefully (#26560) 2026-05-06 13:37:59 +00:00
AK 82f6ea5b61 feat(evals): add shell command safety evals (#26528) 2026-05-06 03:31:16 +00:00
cynthialong0-0 469092a72c fix(cli): provide JSON output for AgentExecutionStopped in non-interactive mode (#26504)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-06 00:33:31 +00:00
joshualitt 80d2690540 fix(core): Fix chat corruption bug in context manager. (#26534) 2026-05-05 22:50:01 +00:00
ruomeng e039fcdf2a ci(release): build and attach unsigned macOS binaries to releases (#26462) 2026-05-05 21:59:54 +00:00
Gal Zahavi 3627f4777f fix(core): allow redirection in YOLO and AUTO_EDIT modes without sandboxing (#26542) 2026-05-05 21:26:16 +00:00
Himanshu Kumar d8f2a89865 fix(core): remove unsafe type assertion suppressions in error utils (#19881)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-05-05 19:52:29 +00:00
Abhijit Balaji f29eb9a569 fix(core): reject numeric project IDs in GOOGLE_CLOUD_PROJECT (#24695) (#26532) 2026-05-05 19:50:36 +00:00
Sandy Tao f17cfb2a71 docs: clarify Auto Memory proposes memory updates and skills (#26527) 2026-05-05 19:39:32 +00:00
Aishanee Shah 0218817fe3 feat(core): steer model to use edit tool for surgical edits, fix a typo (#26480) 2026-05-05 19:35:04 +00:00
joshualitt 0803007c8f fix(core): Minor fixes for generalist profile. (#26357) 2026-05-05 19:32:13 +00:00
Coco Sheng f5c0977e96 fix(core): retry on ERR_STREAM_PREMATURE_CLOSE errors (#26519) 2026-05-05 19:19:50 +00:00
Coco Sheng e80d7cc083 feat: allow queuing messages during compression (#24071) (#26506) 2026-05-05 17:52:08 +00:00
Jack Wotherspoon 7cc19c2a1b fix(cli): prevent settings dialog border clipping using maxHeight (#26507) 2026-05-05 16:22:58 +00:00
Keith Schaab 1d72a120fb fix(a2a-server): resolve tool approval race condition and improve status reporting (#26479)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-05 02:47:26 +00:00
Tirth Naik 8f0edcd64f fix(cli): use os.homedir() for home directory warning check (#25890) 2026-05-04 23:24:49 +00:00
Christian Gunderman 04e875c5c8 fix(ci): respect exempt labels when closing stale items (#26475) 2026-05-04 23:00:14 +00:00
gemini-cli-robot a79da4f3a9 Robust Scale-Safe Lifecycle Consolidation (#26355)
Co-authored-by: gemini-cli[bot] <gemini-cli[bot]@users.noreply.github.com>
Co-authored-by: Christian Gunderman <gundermanc@google.com>
2026-05-04 22:07:47 +00:00
Sandy Tao 56809d7069 fix(cli): make SkillInboxDialog fit and scroll in alternate buffer (#26455) 2026-05-04 21:54:13 +00:00
Anjaligarhwal 5dfbb739e5 feat(cli): add /bug-memory command and auto-capture heap snapshot in /bug (#25639) 2026-05-04 21:17:36 +00:00
Christian Gunderman f87072f4e3 feat(bot): add actions spend metric script (#26463) 2026-05-04 21:01:39 +00:00
Adib234 6a3175e973 fix(core): properly format markdown in AskUser tool by unescaping newlines (#26349)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-04 20:59:11 +00:00
Aishanee Shah 4d1ca92a19 fix(core): filter unsupported multimodal types from tool responses (#26352) 2026-05-04 20:31:20 +00:00
Horizon_Architect_07 b6fc583b0c Fix: make Dockerfile self-contained with multi-stage build (#24277)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-05-04 19:51:06 +00:00
Coco Sheng 0d6bd29752 feat(cli): improve /agents refresh logging (#26442) 2026-05-04 19:40:48 +00:00
ANDI FAUZAN HEDIANTORO 78877942ec docs(sdk): add JSDoc to all exported interfaces and types (#26277) 2026-05-04 19:32:47 +00:00
Coco Sheng 493b555646 feat: add ignoreLocalEnv setting and --ignore-env flag (#2493) (#26445) 2026-05-04 19:14:33 +00:00
Adib234 75a8de83fc test(cleanup): fix temporary directory leaks in test suites (#26217) 2026-05-04 19:08:02 +00:00
Sandy Tao a7beb890d0 feat(memory): add Auto Memory inbox flow with canonical-patch contract (#26338) 2026-05-04 19:07:13 +00:00
Coco Sheng 60a6a47d56 feat(voice): add privacy and compliance UX warning for Gemini Live backend (#26454) 2026-05-04 18:32:15 +00:00
Aryan Kumar d313cd7dde fix(core): use close event instead of exit in child_process fallback (#25695)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-04 18:12:21 +00:00
Aryan Singh 77f4be1f3d fix(cli): render LaTeX-style output as Unicode in the TUI (#25802)
Co-authored-by: cynthialong0-0 <82900738+cynthialong0-0@users.noreply.github.com>
2026-05-04 18:05:06 +00:00
Manav Sharma 0da1a2026a fix(cli)#21297: clear skills consent dialog before reload (#26431)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-05-04 17:53:03 +00:00
Coco Sheng 37edd1d4df fix(cli): allow early stdout when config is undefined (#26453) 2026-05-04 17:48:24 +00:00
Sandy Tao 165efa8a38 fix(hooks): preserve non-text parts in fromHookLLMRequest (#26275) 2026-05-04 17:45:52 +00:00
Coco Sheng 790f2cf815 feat: add minimal V8 heap snapshot utility for memory diagnostics (#26440) 2026-05-04 17:42:42 +00:00
Adib234 704be5a418 fix(cli): ensure branch indicator updates in sub-directories and worktrees (#26330) 2026-05-04 17:35:13 +00:00
Sense_wang 9de8c8aadb docs: fix GitHub capitalization in releases guide (#26379) 2026-05-04 17:29:04 +00:00
Dev Randalpura 0657d315fb refactor(UI): created constants file for ThemeDialog (#26446) 2026-05-04 17:28:33 +00:00
Tommaso Sciortino 88bdadc9c6 revert: fix(ci): robust version checking in release verification (#26337) (#26450) 2026-05-04 17:03:22 +00:00
Pyush Sinha 30c324dec7 Enhance React guidelines (#22667)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
2026-05-04 17:01:11 +00:00
AK 40aa7397b6 feat(core): reinforce Inquiry constraints to prevent unauthorized changes (#26310) 2026-05-04 16:37:39 +00:00
Coco Sheng ab48aad213 perf: skip redundant GEMINI.md loading in partialConfig (#26443) 2026-05-04 16:05:24 +00:00
Coco Sheng 4fa2c95c59 docs(sdk): add JSDoc to exported interfaces in packages/sdk/src/types.ts (#26441) 2026-05-04 15:47:14 +00:00
Sri Pasumarthi 4e175527a2 fix(acp): resolve agent mode disconnect and improve mode awareness (#26332) 2026-05-01 23:00:10 +00:00
AK 40b384de2c fix(core): make subagents aware of active approval modes (#23608) 2026-05-01 22:21:38 +00:00
joshualitt de8fdcfa16 Fix bulk of remaining issues with generalist profile (#26073) 2026-05-01 22:04:39 +00:00
Coco Sheng 408afd3c5a fix(core): reset session-scoped state on resumption (#26342) 2026-05-01 21:20:06 +00:00
Aarchi Kumari a93d2a1d1c fix(cli): resolve Ghostty/raw-mode False Cancellation in oauth flow (#25026)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-05-01 21:08:56 +00:00
Harsh Pujari dc5b3114c0 docs(policy-engine): add tool argument keys reference and shell policy cross-links (#25292)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-05-01 20:33:48 +00:00
Sandy Tao 9380e13f6d fix(core): remove "System: Please continue." injection on InvalidStream events (#26340) 2026-05-01 19:45:31 +00:00
gemini-cli[bot] 363854172f Metrics updates (#26348)
Co-authored-by: gemini-cli[bot] <gemini-cli[bot]@users.noreply.github.com>
2026-05-01 19:20:02 +00:00
Adib234 7dea5b47a1 fix(cli): undeprecate --prompt and correct positional query docs (#26329)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-01 19:19:01 +00:00
Coco Sheng 997f461cad fix(cli): prevent Escape from clearing input buffer (#17083) (#26339) 2026-05-01 18:58:55 +00:00
Dev Randalpura b14a29efa2 feat(ui): added wave animation for voice mode (#26284) 2026-05-01 17:56:05 +00:00
AK f496354884 fix(core): discourage unprompted git add . in prompt snippets (#26220) 2026-05-01 17:54:30 +00:00
ruomeng 76d1a73606 fix(cli): enable daemon relaunch in binary and bundle keytar (#26333) 2026-05-01 17:53:56 +00:00
Tommaso Sciortino 8fb1b5aa01 fix(ci): robust version checking in release verification (#26337) 2026-05-01 17:01:46 +00:00
David Pierce 9cb48020e1 fix(cli): respect .env override for GOOGLE_CLOUD_PROJECT (#26288) 2026-05-01 16:49:45 +00:00
Christian Gunderman 8943640a71 fix(ui): fix issue with box edges (#26148) 2026-05-01 16:46:16 +00:00
Zheyuan Lin 7213822e84 fix(cli): insert voice transcription at cursor position instead of ap… (#26287)
Co-authored-by: Zheyuan <zlin252@emory.edu>
2026-05-01 16:41:17 +00:00
Abhijit Balaji d9f273e440 feat(config): enable Gemma 4 models by default via Gemini API (#26307) 2026-05-01 04:14:57 +00:00
AK b3e6c28933 test(evals): add behavioral eval for file creation and write_file tool selection (#26292) 2026-05-01 03:45:56 +00:00
Bryan Morgan 4e81f48646 Remove Star History section from README (#26309) 2026-04-30 21:59:34 -04:00
Bryan Morgan 2e3090b6d9 Add Star History section to README (#26308) 2026-04-30 21:58:45 -04:00
Bryan Morgan c427bd442f Add Star History section to README (#26290) 2026-05-01 01:30:21 +00:00
gemini-cli[bot] caa0466416 # Metrics Integrity & Standardized Reporting (BT-01) (#26240)
Co-authored-by: gemini-cli[bot] <gemini-cli[bot]@users.noreply.github.com>
Co-authored-by: Christian Gunderman <gundermanc@google.com>
2026-04-30 23:11:39 +00:00
Adib234 f497240f7e fix(cli): use resolved sandbox state for auto-update check (#26285) 2026-04-30 22:06:01 +00:00
Christian Gunderman 892c8a720d fix(ci): checkout PR branch instead of main in bot workflow (#26289) 2026-04-30 21:59:06 +00:00
Martin 80e3bb9689 fix(core): silently skip GEMINI.md paths that are directories (EISDIR) (#25662)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-04-30 21:06:56 +00:00
Martin d494195602 feat(extensions): add 'delete' as an alias for /extensions uninstall (#25660)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-04-30 20:50:06 +00:00
Coco Sheng 2f0c7518ad fix: report AgentExecutionBlocked in non-interactive programmatic modes (#26262) 2026-04-30 20:41:35 +00:00
Sahil Kirad a03ec92436 test(acp): add missing coverage for extensions command error paths (#25313)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-04-30 20:31:59 +00:00
gemini-cli-robot e67631132d Changelog for v0.40.0 (#26245)
Co-authored-by: g-samroberts <158088236+g-samroberts@users.noreply.github.com>
2026-04-30 20:29:16 +00:00
Jenna Inouye 778da08ee1 Docs: Update Agent Skills documentation (#22388)
Co-authored-by: Sam Roberts <158088236+g-samroberts@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-04-30 20:25:28 +00:00
Coco Sheng 7125d2cd65 fix(core): ensure tool output cleanup on session deletion for legacy files (#26263) 2026-04-30 20:11:38 +00:00
JunYoung Ka 84616626f5 feat(cli): Add 'list' subcommand to '/commands' (#22324)
Co-authored-by: Coco Sheng <cocosheng@google.com>
Co-authored-by: Spencer <spencertang@google.com>
2026-04-30 19:54:17 +00:00
Dev Randalpura ef040eb392 feat(ui): added microphone and updated placeholder for voice mode (#26270)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-04-30 19:21:54 +00:00
Coco Sheng 8c1e255ac0 fix(cli): prevent informational logs from polluting json output (#26264) 2026-04-30 18:34:25 +00:00
Christian Gunderman 0af13141b2 Fix posting invalid response to a comment (#26266) 2026-04-30 18:22:59 +00:00
Aashir Javed 90895efb29 docs(policy-engine): link to tools reference for tool names and args (#22081)
Co-authored-by: Aashir Javed <Aaxhirrr@users.noreply.github.com>
Co-authored-by: Sam Roberts <158088236+g-samroberts@users.noreply.github.com>
2026-04-30 18:02:18 +00:00
Paolo Menichetti 84875ce911 docs(cli): add skill discovery troubleshooting checklist to tutorial (#26018) 2026-04-30 18:01:41 +00:00
Jack Wotherspoon c94edcd862 fix(cli): do not override GOOGLE_CLOUD_PROJECT in Cloud Shell when using Vertex AI (#24455)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-04-30 17:52:18 +00:00
ruomeng 0f1077076e Skip binary CLI relaunch (#26261) 2026-04-30 17:48:23 +00:00
gemini-cli-robot 9a98b0e56c Changelog for v0.41.0-preview.0 (#26244)
Co-authored-by: g-samroberts <158088236+g-samroberts@users.noreply.github.com>
2026-04-30 17:31:56 +00:00
Dev Randalpura 071e2923bb fix(ui): made shell tool header wrap on Ctrl+O (#26229) 2026-04-30 17:01:47 +00:00
Adib234 487fb219cc fix(cli): use byte length instead of string length for readStdin size limits (#26224) 2026-04-30 14:12:44 +00:00
Coco Sheng d743c6fae6 fix: suppress duplicate extension warnings during startup (#26208) 2026-04-30 14:11:06 +00:00
Coco Sheng a15568e013 fix(cli): refine platform-specific undo/redo and smart bubbling for WSL (#26202) 2026-04-30 14:10:54 +00:00
Sri Pasumarthi 0ccc5ce58f refactor(acp): delegate prompt turn processing logic to GeminiClient (#26222) 2026-04-29 23:58:16 +00:00
Christian Gunderman 1834ad0298 fix(bot): productivity and backlog optimizations (#26236) 2026-04-29 23:18:22 +00:00
Stephen Eckels a2d10b7b99 Allow non-https proxy urls to support container environments (#26234)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2026-04-29 23:12:03 +00:00
Samee Zahid 8cec567064 docs(core): add automated gemma setup guide (#26233)
Co-authored-by: Samee Zahid <sameez@google.com>
2026-04-29 23:08:54 +00:00
gemini-cli[bot] fa1a7c10bd # Fix: Inconsistent Case-Sensitivity in GrepTool (#26235)
Co-authored-by: gemini-cli[bot] <gemini-cli[bot]@users.noreply.github.com>
2026-04-29 22:59:58 +00:00
Abhijit Balaji 49988fc05c fix(agent): prevent exit_plan_mode from being called via shell (#26230) 2026-04-29 22:22:21 +00:00
Martin d6ce310901 fix: correct API key validation logic in handleApiKeySubmit (#25453)
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
2026-04-29 22:06:14 +00:00
lp-peg 2194da2b02 Respect logPrompts flag for logging sensitive fields (#26153)
Co-authored-by: David Pierce <davidapierce@google.com>
Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com>
2026-04-29 21:43:34 +00:00
Christian Gunderman dce13019b9 ci(github-actions): switch to github app token and fix bot self-trigger (#26223) 2026-04-29 20:45:16 +00:00
Adam Weidman 88626f37e3 fix(cli): handle InvalidStream event gracefully without throwing (#26218) 2026-04-29 20:27:53 +00:00
Adam Weidman 3aedbbc067 fix(core): distinguish fallback chains and fix maxAttempts for auto vs explicit model selection (#26163) 2026-04-29 20:23:37 +00:00
Adib234 99235fc59d fix(core): reduce default API timeout to 60s and enable retries for undici timeouts (#26191) 2026-04-29 20:05:45 +00:00
AK 25f422d0e4 test(evals): add EvalMetadata JSDoc annotations to older tests (#26147) 2026-04-29 19:11:51 +00:00
Christian Gunderman 6dec6720de Add the ability to @ mention the gemini robot. (#26207)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-04-29 18:46:33 +00:00
Adib234 3bc56d0ef5 test(core): add regression test for issue for ToolConfirmationResponse (#26194) 2026-04-29 17:51:09 +00:00
Abdul Tawab 011c0f9bc0 feat(cli): add --delete flag to /exit command for session deletion (#19332)
Co-authored-by: David Pierce <davidapierce@google.com>
2026-04-29 17:20:57 +00:00
Adam Weidman 2cf0c75a04 fix(core): add explicit empty log guard in A2A pushMessage (#26198) 2026-04-29 17:06:18 +00:00
Adam Weidman 7ab932c8bf test: fix failures due to antigravity environment leakage (#26162) 2026-04-29 14:51:43 +00:00
Sri Pasumarthi c2e5b28e94 refactor(acp): modularize monolithic acpClient into specialized files (#26143) 2026-04-29 14:51:01 +00:00
Sam Roberts c7d5fcff95 Update documentation workflows with workspace trust (#26150) 2026-04-29 01:00:57 +00:00
Coco Sheng 6d99113936 fix(core): disconnect extension-backed MCP clients in stopExtension (#26136) 2026-04-28 22:46:17 +00:00
Abhi fbd8aaad57 fix(core): add missing oauth fields support in subagent parsing (#26141) 2026-04-28 21:57:30 +00:00
ifitisit 9e7c924f7b docs(cli): point plan-mode session retention to actual /settings labels (#25978)
Co-authored-by: Spencer <spencertang@google.com>
2026-04-28 21:27:42 +00:00
Anas Khalid 4edd7c745c fix(cli): handle DECKPAM keypad Enter sequences in terminal (#26092)
Co-authored-by: Gitanaskhan26 <Gitanaskhan26@users.noreply.github.com>
Co-authored-by: Spencer <spencertang@google.com>
2026-04-28 21:17:31 +00:00
Coco Sheng 12a77da45c fix(cli): pass node arguments via NODE_OPTIONS during relaunch to support SEA (#26130) 2026-04-28 21:15:23 +00:00
gemini-cli-robot 8cfebb9e31 chore(release): bump version to 0.42.0-nightly.20260428.g59b2dea0e (#26142) 2026-04-28 13:28:48 -07:00
Adib234 f8603e990b fix(cli): prevent automatic updates from switching to less stable channels (#26132) 2026-04-28 18:03:08 +00:00
Adib234 59b2dea0e5 fix(cli): preserve Request headers in DevTools activity logger (#26078) 2026-04-28 17:34:45 +00:00
Coco Sheng c841070582 feat(cli): support boolean and number casting for env vars in settings.json (#26118) 2026-04-28 17:32:51 +00:00
Coco Sheng 4b8d5e7624 fix(cli): prevent ACP stdout pollution from SessionEnd hooks (#26125) 2026-04-28 17:29:49 +00:00
gemini-cli-robot 7a3f7c383e Changelog for v0.40.0-preview.3 (#25904)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
Co-authored-by: g-samroberts <samroberts@google.com>
Co-authored-by: Sam Roberts <158088236+g-samroberts@users.noreply.github.com>
2026-04-28 17:23:04 +00:00
Dev Randalpura 8e1cecac06 fix(ux): added error message for ENOTDIR (#26128) 2026-04-28 17:12:51 +00:00
Adib234 b0ffa3b51e fix(core): handle non-string model flags in resolution (#26069)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-04-28 17:11:15 +00:00
Christian Gunderman 58a57b72ae Implement bot that performs time-series metric analysis and suggests repo management improvements (#25945) 2026-04-28 16:49:53 +00:00
David Pierce 54b7586106 Update policy so transient errors are not marked terminal (#26066) 2026-04-28 16:01:27 +00:00
anj-s c17400b830 fix(core): enforce parallel task tracker updates (#24477)
Co-authored-by: anj-s <anjalisridhar@google.com>
2026-04-27 23:17:26 +00:00
Sam Roberts 47bca39eeb (docs) update sandboxing documentation (#25930) 2026-04-27 22:39:22 +00:00
gemini-cli-robot 07506dcd0d Changelog for v0.40.0-preview.2 (#25846)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-04-27 22:11:42 +00:00
Coco Sheng 6cc0b1b136 feat(cli): provide manual session UUID via command line arg (#26060) 2026-04-27 21:05:27 +00:00
Dev Randalpura 820a4e3c92 fix(core): better error message for failed cloudshell-gca auth (#26079) 2026-04-27 21:05:08 +00:00
Coco Sheng 7d08f84305 fix(cli): make MCP ping optional in list command and use configured timeout (#26068) 2026-04-27 20:36:50 +00:00
Adib234 31337b9269 fix(cli): correct alternate buffer warning logic for JetBrains (#26067) 2026-04-27 20:00:01 +00:00
Emily Hedlund b1a50a58af fix(cli): ensure sandbox proxy cleanup and remove handler leaks (#26065) 2026-04-27 19:35:41 +00:00
joshualitt 71f313b51a feat(core): wire up the new ContextManager and AgentChatHistory (#25409) 2026-04-27 18:50:00 +00:00
Dev Randalpura 98aca28985 fix(ui): better error messages for ECONNRESET and ETIMEDOUT (#26059) 2026-04-27 17:17:04 +00:00
Coco Sheng 2de81902c3 test(cli): add unit tests for restore ACP command (#23402) (#26053) 2026-04-27 17:07:14 +00:00
Coco Sheng 1cdfeb6633 fix(cli): provide manual update command when automatic update fails (#26052) 2026-04-27 16:15:04 +00:00
Gaurav Dubey 743518e1b8 fix(cli): add missing response key to custom theme text schema (#25822)
Co-authored-by: Adib234 <30782825+Adib234@users.noreply.github.com>
2026-04-27 15:01:30 +00:00
Sandy Tao 42587de733 feat(memory): persist auto-memory scratchpad for skill extraction (#25873) 2026-04-24 17:21:12 -07:00
gemini-cli-robot a5b030b424 Changelog for v0.39.0 (#25848)
Co-authored-by: gemini-cli-robot <224641728+gemini-cli-robot@users.noreply.github.com>
2026-04-24 22:02:00 +00:00
Abhijit Balaji 2e0641c83b feat(voice): implement real-time voice mode with cloud and local backends (#24174) 2026-04-24 21:29:38 +00:00
Tommaso Sciortino 048bf6e514 fix(cli-ui): revert backspace handling to fix Windows regression (#25941) 2026-04-24 20:30:00 +00:00
Emily Hedlund ed469e492b fix(core): fail closed in YOLO mode when shell parsing fails for restricted rules (#25935) 2026-04-24 19:26:59 +00:00
Spencer cfd7541ad4 fix(cli): allow output redirection for cli commands (#25894) 2026-04-24 18:31:43 +00:00
894 changed files with 71908 additions and 20507 deletions
+17
View File
@@ -0,0 +1,17 @@
# Git history - not needed in build context
.git
# Root node_modules - reinstalled inside container via npm ci
node_modules
# Package-level node_modules - reinstalled inside container
packages/*/node_modules
# Development and IDE files
.github
.vscode
npm-debug.log*
# Misc
.DS_Store
*.tmp
+21 -5
View File
@@ -53,11 +53,27 @@ Gemini CLI project.
overriding values. Refer to `text-buffer.ts` for a canonical example.
- **Logging**: Do not leave `console.log`, `console.warn`, or `console.error` in
the code.
- **State & Effects**: Ensure state initialization is explicit (e.g., use
`undefined` rather than `true` as a default if the state is truly unknown).
Carefully manage `useEffect` dependencies. Prefer a reducer whenever
practical. NEVER disable `react-hooks/exhaustive-deps`; fix the code to
correctly declare dependencies instead.
- **State**: Ensure state initialization is explicit (e.g., use `undefined`
rather than `true` as a default if the state is truly unknown). Prefer a
reducer whenever practical. NEVER disable `react-hooks/exhaustive-deps`; fix
the code to correctly declare dependencies instead. Evaluate all the React
states in a component and ensure that the `useState` calls are necessary and
not cases where values could be derived on render. Ensure there are no stale
closures that are relying on a value from a previous render. React Components
that modify Settings should effectively use the `useSettingsStore` pattern.
Components that configure application Settings (e.g settings.json) are the
only reasonable case for unsaved changes to drive UX; in these cases, the
Settings store should only be written to on save. If the user experience does
not utilize unsaved changes because there is no option to exit without saving
or reverting the unsaved changes, then the component should directly read from
and write to the Settings store without holding pending changes in component
level UI state.
- **Effect**: `useEffect` should not be used to synchronize React states, it
should only be used for genuine side effects that occur outside of React.
Contributors should be able to strongly justify the need for an effect.
Consider whether the effect should instead be inside an event handler, or
whether it is better off being computed on render. Carefully manage
`useEffect` dependencies.
- **Context & Props**: Avoid excessive property drilling. Leverage existing
providers, extend them, or propose a new one if necessary. Only use providers
for properties that are consistent across the entire application.
+5 -1
View File
@@ -3,7 +3,11 @@
"extensionReloading": true,
"modelSteering": true,
"autoMemory": true,
"gemma": true
"topicUpdateNarration": true,
"voiceMode": true,
"adk": {
"agentSessionNoninteractiveEnabled": true
}
},
"general": {
"devtools": true
+330
View File
@@ -0,0 +1,330 @@
---
name: agent-tui
description: >
Main Agents: Do NOT use this skill directly. If you need to test the TUI, invoke the `tui_tester` subagent.
Drive terminal UI (TUI) applications programmatically for testing, automation, and inspection.
Use when: automating CLI/TUI interactions, regression testing terminal apps, or verifying interactive behavior.
Also use when: user asks "what is agent-tui", "what does agent-tui do", "demo agent-tui", "show me agent-tui", "how does agent-tui work", or wants to see it in action.
---
## 🚨 CRITICAL: macOS Daemon Workaround & Gemini CLI Usage 🚨
When using `agent-tui` in this macOS environment, the default background daemonization process crashes, causing `Connection refused (os error 61)` errors.
**You MUST start the daemon manually shielded from TTY hangups before running any `agent-tui` commands.** Using `nohup` is insufficient; you must use `tmux` to provide a fully isolated pseudo-terminal.
To support parallel runs, **only restart the daemon if it is not currently running:**
```bash
# Check if daemon is alive, start it in tmux if it is not
if ! agent-tui sessions >/dev/null 2>&1; then
tmux kill-session -t agent-tui 2>/dev/null || true
agent-tui daemon stop 2>/dev/null || true
rm -f /tmp/agent-tui*
tmux new-session -d -s agent-tui 'agent-tui daemon start --foreground > /tmp/agent-tui-daemon.log 2>&1'
sleep 1
fi
```
### Session ID vs PID (Crucial for Reconnection)
When `agent-tui run` returns JSON, it includes both a `session_id` and a `pid`. The `pid` is purely informational (the OS process ID of the child command). You **do not** use the `pid` to reconnect or issue commands. You must always use the `session_id` (e.g., `--session <id>`).
If the daemon crashes (`os error 61`), the pseudo-terminal is destroyed. Even if the child `pid` survives as an orphan, you cannot reconnect to it. You must restart the daemon using the workaround above and start a completely new session.
### Testing the Gemini CLI
When testing the Gemini CLI with `agent-tui`, there are several strict requirements to ensure deterministic and accurate behavior:
1. **Build Before Running**: `agent-tui` runs the built JS files, not TypeScript. You **MUST** run `npm run build` or `npm run build:all` after making code changes and before launching the CLI with `agent-tui`.
2. **Bypass Trust Modals**: Always pass `GEMINI_CLI_TRUST_WORKSPACE=true` in the environment. If you don't, any new project-level agents or extensions will trigger a full-screen "Acknowledge and Enable" modal. This modal steals focus, swallows automation keystrokes, and causes `agent-tui wait` commands to time out.
3. **Isolated Environments**: If you need to test without real user credentials or existing agents interfering, isolate the global settings using `GEMINI_CLI_HOME=<some-test-dir>`.
4. **Testing State Deltas (e.g., Reloads)**: If you are testing features that report deltas (e.g., `/agents reload` outputting "1 new local subagent"), you **MUST**:
- Start the CLI *first* so it establishes its baseline registry.
- Use a separate shell command (outside of `agent-tui`) to write the new agent `.md`/`.toml` file.
- Use `agent-tui type` and `press` to trigger the `/agents reload` command inside the running session.
- (If you add the files before starting the CLI, they become part of the baseline and won't trigger the delta logic).
```bash
# Example: Standard isolated run (sandboxed config + bypass trust modals)
env GEMINI_CLI_TRUST_WORKSPACE=true GEMINI_CLI_HOME=test-gemini-home agent-tui run -d "$(pwd)" node packages/cli/dist/index.js
```
# Terminal Automation Mastery
## Prerequisites
- **Supported OS**: macOS or Linux (Windows not supported yet).
- **Verify install**:
```bash
agent-tui --version
```
If not installed, use one of:
```bash
# Recommended: one-line install (macOS/Linux)
curl -fsSL https://raw.githubusercontent.com/pproenca/agent-tui/master/install.sh | sh
```
```bash
# Package manager
npm i -g agent-tui
pnpm add -g agent-tui
bun add -g agent-tui
```
```bash
# Build from source
cargo install --git https://github.com/pproenca/agent-tui.git --path cli/crates/agent-tui
```
If you used the install script, ensure `~/.local/bin` is on your PATH.
## Philosophy: Why Terminal Automation Is Different
Terminal UIs are **stateless from the observer's perspective**. Unlike web browsers with a persistent DOM, terminal automation works with a constantly-refreshed character grid. This fundamental difference shapes everything:
| Web Automation | Terminal Automation |
|----------------|---------------------|
| DOM persists across interactions | Screen buffer is redrawn constantly |
| Selectors are stable | Text positions may shift |
| Query once, act many times | Must re-verify before EVERY action |
| Network events signal completion | Must detect visual stability |
**The Core Insight**: agent-tui gives you vision without memory. Each screenshot is a fresh observation. Previous state means nothing after the UI changes. This isn't a limitation—it's the nature of terminal interaction.
## Mental Model: The Feedback Loop
Think of terminal automation as a **closed-loop control system**:
```
┌──────────────────────────────────────────────┐
│ │
▼ │
OBSERVE ──► DECIDE ──► ACT ──► WAIT ──► VERIFY ───┘
│ │
│ │
└─────── NEVER skip ◄────────────────────┘
```
**Each phase is mandatory.** Skipping verification is the #1 cause of flaky automation.
### The "Fresh Eyes" Principle
Every time you need to interact with the UI:
1. **Take a fresh screenshot** — your previous one is now stale
2. **Locate your target visually** — text positions may have changed
3. **Verify the state** — the UI may have changed unexpectedly
4. **Act only when stable** — animations and loading states cause failures
This feels slower, but it's the only reliable approach. Optimistic reuse of stale state causes intermittent failures that are painful to debug.
## Critical Rules (Non-Negotiable)
> **RULE 1: Atomic Execution (No Pipelining)**
> You are FORBIDDEN from chaining commands with `&&` (e.g., `type "x" && press Enter && wait`). Modals or UI updates can intercept your keystrokes. You MUST execute one atomic action, wait, screenshot, and verify before taking the next action in a new turn.
> **RULE 2: Re-snapshot after EVERY action**
> The UI state is invalidated by any change. Always take a fresh screenshot before acting again.
> **RULE 3: Never act on unstable UI**
> If the UI is animating, loading, or transitioning, `wait --stable` first. Acting during transitions because race conditions.
> **RULE 4: Verify before claiming success**
> Use `wait "expected text" --assert` to confirm outcomes. Don't assume an action worked—prove it.
> **RULE 5: Error Recovery**
> If a `wait` command times out, DO NOT blindly restart or kill the session. Execute `screenshot` to visually diagnose what unexpected UI element (modal, error dialog, lost focus) intercepted the flow.
> **RULE 6: Clean up sessions**
> Always end with `agent-tui kill`. Orphaned sessions consume resources and can interfere with future runs.
## Decision Framework
### Which Screenshot Mode?
Use `screenshot --format json` when parsing automation output, or plain `screenshot` for human readable text.
### How to Wait?
```
What are you waiting for?
├─► Specific text to appear
│ └─► `wait "text" --assert` (fails if not found)
├─► Specific text to disappear
│ └─► `wait "text" --gone --assert`
├─► UI to stop changing (animations, loading)
│ └─► `wait --stable`
└─► Multiple conditions
└─► Chain waits sequentially
```
### How to Act?
```
What do you need to do?
├─► Type text into the terminal
│ └─► `type "text"`
├─► Send keyboard shortcuts/navigation
│ └─► `press Ctrl+C` or `press ArrowDown Enter`
```
## Core Workflow
The canonical automation loop:
```bash
# 1. START: Launch the TUI app
agent-tui run <command> [-- args...]
# 2. OBSERVE: Get current UI state
agent-tui screenshot --format json
# 3. DECIDE: Based on text, determine next action
# (This happens in your head/code)
# 4. ACT: Execute the action
agent-tui type "text"
agent-tui press Enter
# 5. WAIT: Synchronize with UI changes
agent-tui wait "Expected" --assert # or wait --stable
# 6. VERIFY: Confirm the outcome (often combined with step 5)
# If verification fails, handle the error
# 7. REPEAT: Go back to step 2 until done
# 8. CLEANUP: Always clean up
agent-tui kill
```
## Anti-Patterns (What NOT to Do)
### ❌ Acting During Animation/Loading
```bash
# WRONG: Acting immediately on dynamic UI
agent-tui run my-app
agent-tui screenshot --format json # UI might still be loading!
agent-tui type "value" # ❌ Might miss the input field
# RIGHT: Wait for stability first
agent-tui run my-app
agent-tui wait --stable # Let UI settle
agent-tui screenshot --format json # Now it's reliable
agent-tui type "value"
```
### ❌ Assuming Success Without Verification
```bash
# WRONG: Assuming the type worked
agent-tui type "value"
agent-tui press Enter
# ...proceed as if success... # ❌ What if it failed silently?
# RIGHT: Verify the outcome
agent-tui type "value"
agent-tui press Enter
agent-tui wait "Success" --assert # ✓ Proves the action worked
```
### ❌ Skipping Cleanup
```bash
# WRONG: Forgetting to kill the session
agent-tui run my-app
# ...do stuff...
# script ends # ❌ Session left running!
# RIGHT: Always clean up
agent-tui run my-app
# ...do stuff...
agent-tui kill # ✓ Clean exit
```
## Before You Start: Clarify Requirements
Before automating any TUI, gather this information:
1. **Command**: What exactly to run? (`my-app --flag` or `npm start`?)
2. **Success criteria**: What text/state indicates success?
3. **Input sequence**: What keystrokes/data to enter, in what order?
4. **Safety**: Is it safe to submit forms, delete data, etc.?
5. **Auth**: Does it need login? Test credentials?
6. **Live preview**: Does the user want to watch? (`agent-tui live start --open`)
If any of these are unclear, ask before running.
## Demo Mode: Showing What agent-tui Can Do
When a user asks what agent-tui is, wants a demo, or asks "show me how it works":
1. **Don't explain—demonstrate.** Actions speak louder than words.
2. **Use the live preview** so they can watch in real-time.
3. **Run `top`**—it's universal and shows dynamic real-time updates.
**Quick demo trigger phrases:**
- "What is agent-tui?" / "What does agent-tui do?"
- "Demo agent-tui" / "Show me agent-tui"
- "How does agent-tui work?" / "See it in action"
## Failure Recovery
| Symptom | Diagnosis | Solution |
|---------|-----------|----------|
| "Text not found" | Stale view or text moved | Re-snapshot, locate text again |
| Wait times out | UI didn't reach expected state | Check screenshot, verify expectations |
| "Daemon not running" | Daemon crashed or not started | `agent-tui daemon start` |
| Unexpected layout | Wrong terminal size | `agent-tui resize --cols 120 --rows 40` |
| Session unresponsive | App crashed or hung | `agent-tui kill`, then re-run |
| Repeated failures | Something fundamentally wrong | Stop after 3-5 attempts, ask user |
## Self-Discovery: Use --help
You don't need to memorize every flag. The CLI is self-documenting:
```bash
agent-tui --help # List all commands
agent-tui run --help # Options for 'run'
agent-tui screenshot --help # Options for 'screenshot'
agent-tui wait --help # Options for 'wait'
```
**When in doubt, ask the CLI.** This skill teaches *when* and *why* to use commands. For exact flags and syntax, `--help` is authoritative.
## Quick Reference
```bash
# Start app
agent-tui run <cmd> [-- args] # Launch TUI under control
# Observe
agent-tui screenshot # Plain text view
agent-tui screenshot --format json # Machine-readable output
# Act
agent-tui press Enter # Press key(s)
agent-tui press Ctrl+C # Keyboard shortcuts
agent-tui type "text" # Type text
# Wait/Verify
agent-tui wait "text" --assert # Wait for text, fail if not found
agent-tui wait "text" --gone --assert # Wait for text to disappear
agent-tui wait --stable # Wait for UI to stop changing
# Manage
agent-tui sessions # List active sessions
agent-tui live start --open # Start live preview
agent-tui kill # End current session
```
+65
View File
@@ -0,0 +1,65 @@
---
name: tui-tester
description: Expert guidance for testing Gemini CLI behavior and visual output using terminal automation.
---
# TUI Tester Skill
This skill provides the operational manual for verifying Gemini CLI behavioral changes and visual output using terminal automation.
## Core Responsibilities
- **Verify Behavior**: Confirm that code changes result in the expected terminal interactions.
- **Visual Validation**: Ensure the TUI renders correctly across different terminal sizes and states.
- **Regression Testing**: Use automation to prevent breaking existing interactive workflows.
## Critical Protocol
When performing TUI testing, you must adhere to these strict rules:
### 1. Initialization
**YOUR ABSOLUTE FIRST ACTION MUST BE:**
Activate the `agent-tui` skill. This provides the underlying tools needed for terminal automation.
### 2. Environment Setup (macOS / Parallel Safe)
Ensure the global daemon is running and the live preview is open:
```bash
if ! agent-tui sessions >/dev/null 2>&1; then
tmux kill-session -t agent-tui 2>/dev/null || true
agent-tui daemon stop 2>/dev/null || true
rm -f /tmp/agent-tui*
tmux new-session -d -s agent-tui 'agent-tui daemon start --foreground > /tmp/agent-tui-daemon.log 2>&1'
sleep 1
fi
agent-tui live start --open
```
### 3. Session Management
- **Session IDs**: Always use the `session_id` returned by `agent-tui run` for subsequent interactions.
- **Atomic Execution**: Execute exactly one command per turn. Do not pipeline actions.
- **The Loop**: Action -> Wait -> Screenshot -> Verify -> Next Action.
### 4. Gemini CLI Specifics
- **Build First**: Always run `npm run build` or `npm run build:all` before testing local changes.
- **Bypass Trust**: Set `GEMINI_CLI_TRUST_WORKSPACE=true` to avoid focus-stealing modals.
- **Isolate Config**: Use `GEMINI_CLI_HOME` to prevent interference with your personal settings.
## Workflow Example
```bash
# Start the CLI
env GEMINI_CLI_TRUST_WORKSPACE=true agent-tui run node packages/cli/dist/index.js
# Wait for the prompt
agent-tui wait "│" --assert
# Send a command
agent-tui type "/help"
agent-tui press Enter
# Verify output
agent-tui wait "Available Commands" --assert
```
## Error Recovery
If a wait times out, take a fresh screenshot to diagnose the state. If you see `os error 61`, restart the daemon using the tmux method.
+1
View File
@@ -1 +1,2 @@
packages/core/src/services/scripts/*.exe
gha-creds-*.json
@@ -14,12 +14,6 @@ outputs:
runs:
using: 'composite'
steps:
- name: 'Print inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Set vars for simplified logic'
id: 'set_vars'
shell: 'bash'
@@ -30,11 +30,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Creates a Pull Request'
if: "inputs.dry-run != 'true'"
env:
@@ -0,0 +1,23 @@
name: 'Download Mac Binaries'
description: 'Downloads the unsigned macOS binaries (x64 and arm64)'
inputs:
path:
description: 'The base path to download the binaries to'
required: true
default: 'dist'
runs:
using: 'composite'
steps:
- name: 'Download macOS arm64 binary'
uses: 'actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806' # ratchet:actions/download-artifact@v4
continue-on-error: true
with:
name: 'gemini-darwin-arm64-unsigned'
path: '${{ inputs.path }}/darwin-arm64'
- name: 'Download macOS x64 binary'
uses: 'actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806' # ratchet:actions/download-artifact@v4
continue-on-error: true
with:
name: 'gemini-darwin-x64-unsigned'
path: '${{ inputs.path }}/darwin-x64'
@@ -27,11 +27,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Prepare Coverage Comment'
id: 'prep_coverage_comment'
shell: 'bash'
+27 -15
View File
@@ -75,12 +75,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: '👤 Configure Git User'
working-directory: '${{ inputs.working-directory }}'
shell: 'bash'
@@ -114,13 +108,14 @@ runs:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
DRY_RUN: '${{ inputs.dry-run }}'
RELEASE_TAG: '${{ inputs.release-tag }}'
GIT_PUSH_TOKEN: '${{ inputs.github-release-token || inputs.github-token }}'
run: |-
set -e
git add package.json package-lock.json packages/*/package.json
git commit -m "chore(release): ${RELEASE_TAG}"
if [[ "${DRY_RUN}" == "false" ]]; then
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}" --follow-tags
git push "https://x-access-token:${GIT_PUSH_TOKEN}@github.com/${{ github.repository }}.git" "HEAD:${BRANCH_NAME}" --follow-tags
else
echo "Dry run enabled. Skipping push."
fi
@@ -172,11 +167,12 @@ runs:
shell: 'bash'
run: |
npm publish \
--ignore-scripts \
--dry-run="${INPUTS_DRY_RUN}" \
--workspace="${INPUTS_CORE_PACKAGE_NAME}" \
--no-tag
--tag staging-tmp
if [[ "${INPUTS_DRY_RUN}" == "false" ]]; then
npm dist-tag rm ${INPUTS_CORE_PACKAGE_NAME} false
npm dist-tag rm ${INPUTS_CORE_PACKAGE_NAME} staging-tmp
fi
- name: '🔗 Install latest core package'
@@ -220,11 +216,12 @@ runs:
shell: 'bash'
run: |
npm publish \
--ignore-scripts \
--dry-run="${INPUTS_DRY_RUN}" \
--workspace="${INPUTS_CLI_PACKAGE_NAME}" \
--no-tag
--tag staging-tmp
if [[ "${INPUTS_DRY_RUN}" == "false" ]]; then
npm dist-tag rm ${INPUTS_CLI_PACKAGE_NAME} false
npm dist-tag rm ${INPUTS_CLI_PACKAGE_NAME} staging-tmp
fi
- name: 'Get a2a-server Token'
@@ -247,11 +244,12 @@ runs:
# Tag staging for initial release
run: |
npm publish \
--ignore-scripts \
--dry-run="${INPUTS_DRY_RUN}" \
--workspace="${INPUTS_A2A_PACKAGE_NAME}" \
--no-tag
--tag staging-tmp
if [[ "${INPUTS_DRY_RUN}" == "false" ]]; then
npm dist-tag rm ${INPUTS_A2A_PACKAGE_NAME} false
npm dist-tag rm ${INPUTS_A2A_PACKAGE_NAME} staging-tmp
fi
- name: '🔬 Verify NPM release by version'
@@ -308,8 +306,21 @@ runs:
fi
rm -rf test-bundle
RELEASE_ASSETS=("gemini-cli-bundle.zip")
# Check for and prepare macOS binaries if they exist
for arch in arm64 x64; do
BINARY_PATH="dist/darwin-${arch}/gemini"
if [[ -f "$BINARY_PATH" ]]; then
chmod +x "$BINARY_PATH"
ZIP_NAME="gemini-darwin-${arch}-unsigned.zip"
zip -j "$ZIP_NAME" "$BINARY_PATH"
RELEASE_ASSETS+=("$ZIP_NAME")
fi
done
gh release create "${INPUTS_RELEASE_TAG}" \
gemini-cli-bundle.zip \
"${RELEASE_ASSETS[@]}" \
--target "${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}" \
--title "Release ${INPUTS_RELEASE_TAG}" \
--notes-start-tag "${INPUTS_PREVIOUS_TAG}" \
@@ -323,7 +334,8 @@ runs:
shell: 'bash'
run: |
echo "Cleaning up release branch ${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}..."
git push origin --delete "${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}"
git push "https://x-access-token:${GIT_PUSH_TOKEN}@github.com/${{ github.repository }}.git" --delete "${STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME}"
env:
GIT_PUSH_TOKEN: '${{ inputs.github-release-token || inputs.github-token }}'
STEPS_RELEASE_BRANCH_OUTPUTS_BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
-5
View File
@@ -18,11 +18,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Checkout'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
with:
-5
View File
@@ -28,11 +28,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Checkout'
uses: 'actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5' # ratchet:actions/checkout@v4
with:
-5
View File
@@ -13,11 +13,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Install system dependencies'
if: "runner.os == 'Linux'"
run: |
+1 -1
View File
@@ -19,6 +19,6 @@ runs:
run: |-
echo ""@google-gemini:registry=https://npm.pkg.github.com"" > ~/.npmrc
echo ""//npm.pkg.github.com/:_authToken=${INPUTS_GITHUB_TOKEN}"" >> ~/.npmrc
echo ""@google:registry=https://wombat-dressing-room.appspot.com"" >> ~/.npmrc
echo ""@google:registry=https://wombat-dressing-room.appspot.com/"" >> ~/.npmrc
env:
INPUTS_GITHUB_TOKEN: '${{ inputs.github-token }}'
@@ -40,12 +40,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
with:
@@ -29,12 +29,6 @@ inputs:
runs:
using: 'composite'
steps:
- name: '📝 Print Inputs'
shell: 'bash'
env:
JSON_INPUTS: '${{ toJSON(inputs) }}'
run: 'echo "$JSON_INPUTS"'
- name: 'setup node'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
+8
View File
@@ -8,6 +8,10 @@ updates:
open-pull-requests-limit: 10
reviewers:
- 'joshualitt'
cooldown:
semver-major-days: 14
semver-minor-days: 14
semver-patch-days: 14
groups:
npm-dependencies:
patterns:
@@ -24,6 +28,10 @@ updates:
open-pull-requests-limit: 10
reviewers:
- 'joshualitt'
cooldown:
semver-major-days: 14
semver-minor-days: 14
semver-patch-days: 14
groups:
actions-dependencies:
patterns:
+278
View File
@@ -0,0 +1,278 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
module.exports = async ({ github, context, core }) => {
const extractJson = (raw) => {
if (!raw || raw === '[]' || raw === '') return [];
try {
// First, try to parse the raw output as JSON.
return JSON.parse(raw);
} catch {
// If that fails, check for a markdown code block.
core.info(
'Direct JSON parsing failed. Trying to extract from a markdown block.',
);
const jsonMatch = raw.match(/```json\s*([\s\S]*?)\s*```/);
if (jsonMatch && jsonMatch[1]) {
try {
return JSON.parse(jsonMatch[1].trim());
} catch (markdownError) {
core.warning(
`Failed to parse extracted JSON from markdown block: ${markdownError.message}`,
);
}
}
// Try to find a raw JSON array in the output.
const jsonArrayMatch = raw.match(
/\[\s*\{\s*"issue_number"[\s\S]*\}\s*\]/,
);
if (jsonArrayMatch) {
try {
return JSON.parse(jsonArrayMatch[0]);
} catch {
const fallbackMatch = raw.match(/(\[\s*\{\s*"issue_number"[\s\S]*)/);
if (fallbackMatch) {
try {
const cleaned = fallbackMatch[0].substring(
0,
fallbackMatch[0].lastIndexOf(']') + 1,
);
return JSON.parse(cleaned);
} catch (fallbackError) {
core.warning(
`Failed to parse extracted JSON using fallback regex: ${fallbackError.message}`,
);
}
}
}
}
}
core.warning('No valid JSON could be extracted from input.');
return [];
};
// Collect all outputs from environment variables
// Prioritize EFFORT results over STANDARD results by processing Effort FIRST
// so that its labels appear first in the merged arrays (and thus win in mutually exclusive logic)
const effortRaw = process.env.LABELS_OUTPUT_EFFORT;
const standardRaw = process.env.LABELS_OUTPUT_STANDARD;
const genericRaw = process.env.LABELS_OUTPUT;
const resultsByIssue = new Map();
const processResults = (results, _sourceName) => {
for (const entry of results) {
const issueNumber = entry.issue_number;
if (!issueNumber) continue;
if (!resultsByIssue.has(issueNumber)) {
resultsByIssue.set(issueNumber, {
issue_number: issueNumber,
labels_to_add: [...(entry.labels_to_add || [])],
labels_to_remove: [...(entry.labels_to_remove || [])],
explanation: entry.explanation || '',
effort_analysis: entry.effort_analysis || '',
});
} else {
const existing = resultsByIssue.get(issueNumber);
// Combine labels
existing.labels_to_add = [
...new Set([
...existing.labels_to_add,
...(entry.labels_to_add || []),
]),
];
existing.labels_to_remove = [
...new Set([
...existing.labels_to_remove,
...(entry.labels_to_remove || []),
]),
];
// Combine explanations (if different)
if (
entry.explanation &&
!existing.explanation.includes(entry.explanation)
) {
existing.explanation = existing.explanation
? `${existing.explanation}\n\n${entry.explanation}`
: entry.explanation;
}
// Take effort analysis if present
if (entry.effort_analysis && !existing.effort_analysis) {
existing.effort_analysis = entry.effort_analysis;
}
}
}
};
// Order matters: Effort first so its labels win in conflict resolution
processResults(extractJson(effortRaw), 'EFFORT');
processResults(extractJson(standardRaw), 'STANDARD');
processResults(extractJson(genericRaw), 'GENERIC');
const finalResults = Array.from(resultsByIssue.values());
core.info(`Aggregated triage results for ${finalResults.length} issues.`);
for (const entry of finalResults) {
const issueNumber = entry.issue_number;
let labelsToAdd = entry.labels_to_add || [];
let labelsToRemove = entry.labels_to_remove || [];
let existingLabels = [];
// Fetch existing labels early
try {
const { data: issueData } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
existingLabels = issueData.labels.map((l) =>
typeof l === 'string' ? l : l.name,
);
} catch (e) {
core.warning(
`Failed to fetch existing labels for #${issueNumber}: ${e.message}`,
);
}
// Programmatic Priority Downgrade Logic
if (labelsToAdd.includes('status/need-information')) {
const targetPriority = labelsToAdd.find((l) => l.startsWith('priority/'));
if (targetPriority) {
let downgradedPriority = null;
if (targetPriority === 'priority/p0')
downgradedPriority = 'priority/p1';
if (targetPriority === 'priority/p1')
downgradedPriority = 'priority/p2';
if (downgradedPriority) {
core.info(
`Programmatically downgrading ${targetPriority} to ${downgradedPriority} due to status/need-information`,
);
labelsToAdd = labelsToAdd.filter((l) => l !== targetPriority);
labelsToAdd.push(downgradedPriority);
}
}
}
labelsToRemove.push('status/need-triage');
if (
labelsToAdd.includes('status/manual-triage') ||
existingLabels.includes('status/manual-triage')
) {
labelsToRemove.push('status/bot-triaged');
labelsToAdd = labelsToAdd.filter((l) => l !== 'status/bot-triaged');
} else {
labelsToAdd.push('status/bot-triaged');
}
// Resolve internal conflicts (e.g., adding P1 and P2)
// We already resolved these by putting Effort first in the combined list
// Resolve external conflicts with existing labels
if (labelsToAdd.some((l) => l.startsWith('area/'))) {
labelsToRemove.push(
...existingLabels.filter((l) => l.startsWith('area/')),
);
}
if (labelsToAdd.some((l) => l.startsWith('priority/'))) {
labelsToRemove.push(
...existingLabels.filter((l) => l.startsWith('priority/')),
);
}
if (labelsToAdd.some((l) => l.startsWith('kind/'))) {
labelsToRemove.push(
...existingLabels.filter((l) => l.startsWith('kind/')),
);
}
// Enforce mutual exclusivity in the TO-ADD list (Architect wins)
const exclusivePrefixes = ['area/', 'priority/', 'kind/'];
for (const prefix of exclusivePrefixes) {
const filtered = labelsToAdd.filter((l) => l.startsWith(prefix));
if (filtered.length > 1) {
const winner = filtered[0]; // First one wins
core.info(
`Issue #${issueNumber} has multiple ${prefix} labels suggested. Keeping "${winner}" and discarding others.`,
);
labelsToAdd = labelsToAdd.filter(
(l) => !l.startsWith(prefix) || l === winner,
);
}
}
// Final deduplication and cleanup
labelsToRemove = [...new Set(labelsToRemove)].filter(
(l) => !labelsToAdd.includes(l) && existingLabels.includes(l),
);
labelsToAdd = [...new Set(labelsToAdd)].filter(
(l) => !existingLabels.includes(l),
);
// Batch label operations
if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: labelsToAdd,
});
core.info(
`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}`,
);
}
if (labelsToRemove.length > 0) {
for (const label of labelsToRemove) {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
name: label,
});
} catch (e) {
if (e.status !== 404)
core.warning(
`Failed to remove label ${label} from #${issueNumber}: ${e.message}`,
);
}
}
core.info(
`Successfully removed labels for #${issueNumber}: ${labelsToRemove.join(', ')}`,
);
}
// Post comment if needed
const needsInfoAdded =
labelsToAdd.includes('status/need-information') &&
!existingLabels.includes('status/need-information');
const hasEffortAnalysis = !!entry.effort_analysis;
if (needsInfoAdded || hasEffortAnalysis) {
let commentBody = '';
if (needsInfoAdded && entry.explanation) commentBody += entry.explanation;
if (hasEffortAnalysis) {
if (commentBody) commentBody += '\n\n';
commentBody += `**Effort Analysis:**\n${entry.effort_analysis}`;
}
if (commentBody) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: commentBody,
});
core.info(`Posted required comment for #${issueNumber}`);
}
}
}
};
+74
View File
@@ -0,0 +1,74 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const fs = require('node:fs');
module.exports = async ({ github, context, core }) => {
let issuesToCleanup = [];
try {
const fileContent = fs.readFileSync('issues_to_cleanup.json', 'utf8');
issuesToCleanup = JSON.parse(fileContent);
} catch (error) {
if (error.code === 'ENOENT') {
core.info('No issues found to clean up.');
return;
}
core.setFailed(`Failed to read issues_to_cleanup.json: ${error.message}`);
return;
}
for (const issue of issuesToCleanup) {
try {
const { data: issueData } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
});
const labels = issueData.labels.map((l) =>
typeof l === 'string' ? l : l.name,
);
if (
labels.includes('status/bot-triaged') &&
labels.includes('status/need-triage')
) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: 'status/need-triage',
});
core.info(
`Successfully removed status/need-triage from #${issue.number}`,
);
}
if (
labels.includes('status/bot-triaged') &&
labels.includes('status/manual-triage')
) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: 'status/bot-triaged',
});
core.info(
`Successfully removed status/bot-triaged from #${issue.number} because it requires manual triage`,
);
}
} catch (error) {
core.warning(
`Failed to clean up labels for #${issue.number}: ${error.message}`,
);
}
}
core.info(
`Cleaned up conflicting labels from ${issuesToCleanup.length} issues.`,
);
};
@@ -0,0 +1,380 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Gemini Scheduled Lifecycle Manager Script
* @param {object} param0
* @param {import('@octokit/rest').Octokit} param0.github
* @param {import('@actions/github/lib/context').Context} param0.context
* @param {import('@actions/core')} param0.core
*/
module.exports = async ({ github, context, core }) => {
const dryRun = process.env.DRY_RUN === 'true';
const owner = context.repo.owner;
const repo = context.repo.repo;
core.info(`Running in ${dryRun ? 'DRY RUN' : 'PRODUCTION'} mode.`);
const STALE_LABEL = 'stale';
const NEED_INFO_LABEL = 'status/need-information';
const EXEMPT_LABELS = [
'pinned',
'security',
'🔒 maintainer only',
'help wanted',
'🗓️ Public Roadmap',
];
const STALE_DAYS = 60;
const CLOSE_DAYS = 14;
const NO_RESPONSE_DAYS = 14;
const now = new Date();
const staleThreshold = new Date(
now.getTime() - STALE_DAYS * 24 * 60 * 60 * 1000,
);
const closeThreshold = new Date(
now.getTime() - CLOSE_DAYS * 24 * 60 * 60 * 1000,
);
const noResponseThreshold = new Date(
now.getTime() - NO_RESPONSE_DAYS * 24 * 60 * 60 * 1000,
);
const maintainerCache = new Map();
async function isMaintainer(user, association) {
if (user?.type === 'Bot') return true;
if (['OWNER', 'MEMBER', 'COLLABORATOR'].includes(association)) return true;
const username = user?.login;
if (!username) return false;
if (maintainerCache.has(username)) {
return maintainerCache.get(username);
}
try {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner,
repo,
username,
});
// Permission can be admin, write, read, none.
// Roles like 'maintain' or 'triage' often map to 'write' or 'read' in the top-level field.
const isM =
['admin', 'write'].includes(data.permission) ||
['admin', 'maintain', 'write'].includes(data.role_name);
maintainerCache.set(username, isM);
return isM;
} catch (err) {
core.warning(
`Could not check permissions for ${username}: ${err.message}`,
);
maintainerCache.set(username, false);
return false;
}
}
async function processItems(query, callback) {
core.info(`Searching: ${query}`);
try {
let items = await github.paginate(
github.rest.search.issuesAndPullRequests,
{
q: query,
per_page: 100,
sort: 'updated',
order: 'asc',
},
);
core.info(`Found ${items.length} items.`);
for (const item of items) {
try {
await callback(item);
} catch (err) {
core.error(`Error processing #${item.number}: ${err.message}`);
}
}
} catch (err) {
core.error(`Search failed: ${err.message}`);
}
}
// 1. Handle No-Response (status/need-information)
// Removal: Check issues updated in the last 48h that have the label
const twoDaysAgo = new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000);
await processItems(
`repo:${owner}/${repo} is:open label:"${NEED_INFO_LABEL}" updated:>${twoDaysAgo.toISOString()}`,
async (item) => {
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: item.number,
sort: 'created',
direction: 'desc',
per_page: 5,
});
// Check if the last comment is from a non-maintainer and not a bot
const lastComment = comments[0];
if (
lastComment &&
lastComment.user?.type !== 'Bot' &&
!(await isMaintainer(lastComment.user, lastComment.author_association))
) {
if (dryRun) {
core.info(
`[DRY RUN] Would remove ${NEED_INFO_LABEL} from #${item.number} due to contributor response.`,
);
} else {
core.info(
`Removing ${NEED_INFO_LABEL} from #${item.number} due to contributor response.`,
);
await github.rest.issues
.removeLabel({
owner,
repo,
issue_number: item.number,
name: NEED_INFO_LABEL,
})
.catch(() => {});
}
}
},
);
// Closure: Check issues with the label that haven't been updated in 14 days
await processItems(
`repo:${owner}/${repo} is:open label:"${NEED_INFO_LABEL}" updated:<${noResponseThreshold.toISOString()}`,
async (item) => {
if (dryRun) {
core.info(
`[DRY RUN] Would close #${item.number} due to no response for ${NO_RESPONSE_DAYS} days.`,
);
} else {
core.info(
`Closing #${item.number} due to no response for ${NO_RESPONSE_DAYS} days.`,
);
await github.rest.issues.createComment({
owner,
repo,
issue_number: item.number,
body: `This item was marked as needing more information and has not received a response in ${NO_RESPONSE_DAYS} days. Closing it for now. If you still face this problem, feel free to reopen with more details. Thank you!`,
});
await github.rest.issues.update({
owner,
repo,
issue_number: item.number,
state: 'closed',
state_reason: 'not_planned',
});
}
},
);
// 2. Handle Stale Mark (60 days inactivity, no stale label)
const exemptQuery = EXEMPT_LABELS.map((l) => `-label:"${l}"`).join(' ');
await processItems(
`repo:${owner}/${repo} is:open -label:"${STALE_LABEL}" ${exemptQuery} updated:<${staleThreshold.toISOString()}`,
async (item) => {
const isBug = item.labels.some((l) =>
(typeof l === 'string' ? l : l.name).toLowerCase().includes('bug'),
);
const bodyText = isBug
? `This bug report has been automatically marked as stale due to ${STALE_DAYS} days of inactivity. Many issues are resolved in newer releases. Please verify if the issue persists in the latest Gemini CLI version. If it does, please leave a comment to keep this open. It will be closed in ${CLOSE_DAYS} days if no further activity occurs. Thank you!`
: `This item has been automatically marked as stale due to ${STALE_DAYS} days of inactivity. It will be closed in ${CLOSE_DAYS} days if no further activity occurs. Thank you!`;
if (dryRun) {
core.info(`[DRY RUN] Would mark #${item.number} as stale.`);
} else {
core.info(`Marking #${item.number} as stale.`);
await github.rest.issues.addLabels({
owner,
repo,
issue_number: item.number,
labels: [STALE_LABEL],
});
await github.rest.issues.createComment({
owner,
repo,
issue_number: item.number,
body: bodyText,
});
}
},
);
// 3. Handle Stale Removal & Close
await processItems(
`repo:${owner}/${repo} is:open label:"${STALE_LABEL}" ${exemptQuery}`,
async (item) => {
// Fetch full timeline to see events and comments
const timeline = await github.paginate(
github.rest.issues.listEventsForTimeline,
{
owner,
repo,
issue_number: item.number,
per_page: 100,
},
);
// Find exactly when the Stale label was added
// We look for the last 'labeled' event for STALE_LABEL
const staleEventIndex = timeline.findLastIndex(
(e) =>
e.event === 'labeled' &&
e.label?.name?.toLowerCase() === STALE_LABEL.toLowerCase(),
);
if (staleEventIndex === -1) return; // Fallback if no event found
const staleEvent = timeline[staleEventIndex];
const eventsAfterStale = timeline.slice(staleEventIndex + 1);
// Check for meaningful activity after the Stale label was applied
const meaningfulEvents = eventsAfterStale.filter((e) => {
const actor = e.actor?.login || '';
const isBot =
actor.includes('[bot]') || actor.includes('github-actions');
if (isBot) return false;
// Explicit whitelist of meaningful events for humans
if (
[
'commented',
'cross-referenced',
'connected',
'reopened',
'assigned',
].includes(e.event)
) {
return true;
}
return false;
});
if (meaningfulEvents.length > 0) {
// Activity detected, remove Stale label
if (dryRun) {
core.info(
`[DRY RUN] Would remove ${STALE_LABEL} from #${item.number} due to meaningful activity (e.g., comment or PR).`,
);
} else {
core.info(
`Removing ${STALE_LABEL} from #${item.number} due to meaningful activity (e.g., comment or PR).`,
);
await github.rest.issues
.removeLabel({
owner,
repo,
issue_number: item.number,
name: STALE_LABEL,
})
.catch(() => {});
}
return;
}
// No meaningful activity. Check if 14 days have passed.
const labeledDate = new Date(staleEvent.created_at);
if (labeledDate > closeThreshold) {
// Has not been 14 days since it was ACTUALLY marked stale
return;
}
if (dryRun) {
core.info(`[DRY RUN] Would close stale item #${item.number}.`);
} else {
core.info(`Closing stale item #${item.number}.`);
await github.rest.issues.createComment({
owner,
repo,
issue_number: item.number,
body: `This item has been closed due to ${CLOSE_DAYS} additional days of inactivity after being marked as stale. If you believe this is still relevant, feel free to comment or reopen. Thank you!`,
});
await github.rest.issues.update({
owner,
repo,
issue_number: item.number,
state: 'closed',
state_reason: 'not_planned',
});
}
},
);
// 4. Handle PR Contribution Policy (Nudge at 7d, Close at 14d)
const PR_NUDGE_DAYS = 7;
const PR_CLOSE_DAYS = 14;
const nudgeThreshold = new Date(
now.getTime() - PR_NUDGE_DAYS * 24 * 60 * 60 * 1000,
);
const prCloseThreshold = new Date(
now.getTime() - PR_CLOSE_DAYS * 24 * 60 * 60 * 1000,
);
// Nudge
await processItems(
`repo:${owner}/${repo} is:open is:pr -label:"help wanted" -label:"🔒 maintainer only" -label:"status/pr-nudge-sent" created:${prCloseThreshold.toISOString()}..${nudgeThreshold.toISOString()}`,
async (pr) => {
if (await isMaintainer(pr.user, pr.author_association)) return;
if (dryRun) {
core.info(
`[DRY RUN] Would nudge PR #${pr.number} for contribution policy.`,
);
} else {
core.info(`Nudging PR #${pr.number} for contribution policy.`);
await github.rest.issues.addLabels({
owner,
repo,
issue_number: pr.number,
labels: ['status/pr-nudge-sent'],
});
await github.rest.issues.createComment({
owner,
repo,
issue_number: pr.number,
body: "Hi there! Thank you for your interest in contributing to Gemini CLI. \n\nTo ensure we maintain high code quality and focus on our prioritized roadmap, we only guarantee review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'. \n\nThis PR will be closed in 7 days if it remains without that designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding.",
});
}
},
);
// Close
await processItems(
`repo:${owner}/${repo} is:open is:pr -label:"help wanted" -label:"🔒 maintainer only" created:<${prCloseThreshold.toISOString()}`,
async (pr) => {
if (await isMaintainer(pr.user, pr.author_association)) return;
if (dryRun) {
core.info(
`[DRY RUN] Would close PR #${pr.number} per contribution policy (no 'help wanted').`,
);
} else {
core.info(
`Closing PR #${pr.number} per contribution policy (no 'help wanted').`,
);
await github.rest.issues.createComment({
owner,
repo,
issue_number: pr.number,
body: "This pull request is being closed as it has been open for 14 days without a 'help wanted' designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding.",
});
await github.rest.pulls.update({
owner,
repo,
pull_number: pr.number,
state: 'closed',
});
}
},
);
};
+99
View File
@@ -0,0 +1,99 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const fs = require('node:fs');
module.exports = async ({ github, context, core }) => {
const query = `
query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
issues(first: 50, states: OPEN, orderBy: {field: UPDATED_AT, direction: DESC}) {
nodes {
id
number
title
body
issueType {
name
}
labels(first: 20) {
nodes {
name
}
}
}
}
}
}
`;
try {
const result = await github.graphql(query, {
owner: context.repo.owner,
repo: context.repo.repo,
});
const issues = result.repository.issues.nodes;
const issuesNeedingAnalysis = [];
let syncedCount = 0;
for (const issue of issues) {
if (issue.issueType === null) {
const labelNames = issue.labels.nodes.map((l) => l.name);
const hasBug = labelNames.includes('kind/bug');
const hasFeature =
labelNames.includes('kind/feature') ||
labelNames.includes('kind/enhancement');
let issueTypeId = null;
if (hasBug) {
issueTypeId = 'IT_kwDOCaSVvs4BR7vP'; // Bug
} else if (hasFeature) {
issueTypeId = 'IT_kwDOCaSVvs4BR7vQ'; // Feature
}
if (issueTypeId) {
await github.graphql(
`
mutation($issueId: ID!, $issueTypeId: ID!) {
updateIssue(input: {id: $issueId, issueTypeId: $issueTypeId}) {
issue {
id
}
}
}
`,
{
issueId: issue.id,
issueTypeId: issueTypeId,
},
);
core.info(`Successfully synced Issue Type for #${issue.number}`);
syncedCount++;
} else {
// Needs analysis to determine kind/type
issuesNeedingAnalysis.push({
number: issue.number,
title: issue.title,
body: issue.body,
});
}
}
}
// Write issues needing analysis to a file so the AI can process them
fs.writeFileSync(
'no_type_issues.json',
JSON.stringify(issuesNeedingAnalysis),
);
core.info(`Synced ${syncedCount} issues from labels.`);
core.info(
`Found ${issuesNeedingAnalysis.length} issues missing both type and kind label to be analyzed.`,
);
} catch (error) {
core.setFailed(`Failed to sync issue types: ${error.message}`);
}
};
@@ -0,0 +1,65 @@
name: 'Build Unsigned Mac Binaries'
on:
workflow_dispatch:
workflow_call:
inputs:
ref:
description: 'The branch, tag, or SHA to build from.'
required: true
type: 'string'
permissions:
contents: 'read'
defaults:
run:
shell: 'bash'
jobs:
build-mac:
name: 'Build Unsigned (${{ matrix.arch }})'
runs-on: 'macos-latest'
strategy:
fail-fast: false
matrix:
arch: ['x64', 'arm64']
steps:
- name: 'Checkout'
uses: 'actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5' # ratchet:actions/checkout@v4
with:
ref: '${{ inputs.ref || github.ref }}'
persist-credentials: false
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
with:
node-version-file: '.nvmrc'
architecture: '${{ matrix.arch }}'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Build Binary'
env:
SKIP_SIGNING: 'true'
run: 'npm run build:binary'
- name: 'Verify Output Exists'
run: |
if [ -f "dist/darwin-${{ matrix.arch }}/gemini" ]; then
echo "Binary found at dist/darwin-${{ matrix.arch }}/gemini"
else
echo "Error: Binary not found in dist/darwin-${{ matrix.arch }}/"
ls -R dist/
exit 1
fi
- name: 'Upload Artifact'
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'gemini-darwin-${{ matrix.arch }}-unsigned'
path: 'dist/darwin-${{ matrix.arch }}/gemini'
retention-days: 14
+5
View File
@@ -148,6 +148,7 @@ jobs:
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
persist-credentials: false
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
@@ -193,6 +194,7 @@ jobs:
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
persist-credentials: false
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
@@ -233,6 +235,7 @@ jobs:
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
persist-credentials: false
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
@@ -314,6 +317,7 @@ jobs:
with:
ref: '${{ needs.parse_run_context.outputs.sha }}'
repository: '${{ needs.parse_run_context.outputs.repository }}'
persist-credentials: false
fetch-depth: 0
- name: 'Set up Node.js 20.x'
@@ -337,6 +341,7 @@ jobs:
if: "${{ steps.check_evals.outputs.should_run == 'true' }}"
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GEMINI_CLI_TRUST_WORKSPACE: true
GEMINI_MODEL: 'gemini-3-pro-preview'
# Only run always passes behavioral tests.
EVAL_SUITE_TYPE: 'behavioral'
+10
View File
@@ -57,6 +57,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 0
@@ -130,6 +131,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Link Checker'
uses: 'lycheeverse/lychee-action@885c65f3dc543b57c898c8099f4e08c8afd178a2' # ratchet: lycheeverse/lychee-action@v2.6.1
with:
@@ -157,6 +160,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -252,6 +257,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -339,6 +346,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
- name: 'Initialize CodeQL'
@@ -363,6 +371,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
fetch-depth: 1
@@ -390,6 +399,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
ref: '${{ github.event.inputs.branch_ref || github.ref }}'
- name: 'Set up Node.js 20.x'
+9 -6
View File
@@ -173,6 +173,7 @@ jobs:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
REPOSITORY: '${{ github.repository }}'
with:
upload_artifacts: 'true'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
@@ -182,12 +183,14 @@ jobs:
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"coreTools": [
"run_shell_command(gh issue list)",
"run_shell_command(gh pr list)",
"run_shell_command(gh search issues)",
"run_shell_command(gh search prs)"
]
"tools": {
"core": [
"run_shell_command(gh issue list)",
"run_shell_command(gh pr list)",
"run_shell_command(gh search issues)",
"run_shell_command(gh search prs)"
]
}
}
prompt: |-
You are a helpful assistant that analyzes community contribution reports.
+3
View File
@@ -43,6 +43,7 @@ jobs:
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.repository }}'
persist-credentials: false
- name: 'Set up Node.js ${{ matrix.node-version }}'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
@@ -86,6 +87,7 @@ jobs:
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.repository }}'
persist-credentials: false
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
@@ -125,6 +127,7 @@ jobs:
with:
ref: '${{ github.event.pull_request.head.sha }}'
repository: '${{ github.repository }}'
persist-credentials: false
- name: 'Set up Node.js 20.x'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions-node@v4
+4
View File
@@ -19,6 +19,7 @@ jobs:
with:
fetch-depth: 0
ref: 'main'
persist-credentials: false
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
@@ -28,7 +29,10 @@ jobs:
- name: 'Run Docs Audit with Gemini'
id: 'run_gemini'
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31'
env:
GEMINI_CLI_TRUST_WORKSPACE: true
with:
upload_artifacts: 'true'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
prompt: |
Activate the 'docs-writer' skill.
+2
View File
@@ -24,6 +24,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Setup Pages'
uses: 'actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b' # ratchet:actions/configure-pages@v5
+2
View File
@@ -38,6 +38,7 @@ jobs:
with:
# Check out the trusted code from main for detection
fetch-depth: 0
persist-credentials: false
- name: 'Detect Steering Changes'
id: 'detect'
@@ -102,6 +103,7 @@ jobs:
# This only runs AFTER manual approval
ref: '${{ github.event.pull_request.head.sha }}'
fetch-depth: 0
persist-credentials: false
- name: 'Remove Approval Notification'
# Run even if other steps fail, to ensure we clean up the "Action Required" message
+5
View File
@@ -46,6 +46,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -66,6 +68,7 @@ jobs:
continue-on-error: true
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GEMINI_CLI_TRUST_WORKSPACE: true
GEMINI_MODEL: '${{ matrix.model }}'
RUN_EVALS: 'true'
EVAL_SUITE_TYPE: "${{ github.event.inputs.suite_type || 'behavioral' }}"
@@ -104,6 +107,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Download Logs'
uses: 'actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806' # ratchet:actions/download-artifact@v4
@@ -48,6 +48,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
@@ -67,6 +69,7 @@ jobs:
REPOSITORY: '${{ github.repository }}'
FIRESTORE_PROJECT: '${{ vars.FIRESTORE_PROJECT }}'
with:
upload_artifacts: 'true'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
@@ -105,10 +108,12 @@ jobs:
}
},
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)",
"run_shell_command(gh issue view)"
],
"tools": {
"core": [
"run_shell_command(echo)",
"run_shell_command(gh issue view)"
]
},
"telemetry": {
"enabled": true,
"target": "gcp"
@@ -90,6 +90,8 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Generate GitHub App Token'
id: 'generate_token'
@@ -134,15 +136,12 @@ jobs:
id: 'gemini_issue_analysis'
env:
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
ISSUE_TITLE: >-
${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.title || github.event.issue.title }}
ISSUE_BODY: >-
${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.body || github.event.issue.body }}
ISSUE_NUMBER: >-
${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.issue_number || inputs.issue_number) || github.event.issue.number }}
REPOSITORY: '${{ github.repository }}'
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
with:
upload_artifacts: 'true'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
@@ -157,17 +156,24 @@ jobs:
"enabled": true,
"target": "gcp"
},
"coreTools": [
"run_shell_command(echo)"
]
"tools": {
"core": []
}
}
prompt: |-
## Role
You are an issue triage assistant. Your role is to analyze a GitHub issue and determine the single most appropriate area/ label based on the definitions provided.
## Issue Context
Title: ${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.title || github.event.issue.title }}
Body:
--- START OF ISSUE BODY ---
${{ github.event_name == 'workflow_dispatch' && steps.get_issue_data.outputs.body || github.event.issue.body }}
--- END OF ISSUE BODY ---
## Steps
1. Review the issue title and body: ${{ env.ISSUE_TITLE }} and ${{ env.ISSUE_BODY }}.
1. Analyze the issue context above.
2. Review the available labels: ${{ env.AVAILABLE_LABELS }}.
3. Select exactly one area/ label that best matches the issue based on Reference 1: Area Definitions.
4. Fallback Logic:
@@ -322,14 +328,41 @@ jobs:
return;
}
const newAreaLabel = labelsToAdd[0];
// Get current labels to resolve conflicts
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const currentLabelNames = currentLabels.map(l => l.name);
const currentAreaLabels = currentLabelNames.filter(name => name.startsWith('area/'));
const labelsToRemove = currentAreaLabels.filter(name => name !== newAreaLabel);
for (const label of labelsToRemove) {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
name: label
});
core.info(`Removed conflicting area label: ${label}`);
} catch (e) {
core.warning(`Failed to remove label ${label}: ${e.message}`);
}
}
// Set labels based on triage result
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: labelsToAdd
labels: [newAreaLabel]
});
core.info(`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}`);
core.info(`Successfully added labels for #${issueNumber}: ${newAreaLabel}`);
- name: 'Post Issue Analysis Failure Comment'
if: |-
+315 -12
View File
@@ -3,27 +3,73 @@ name: '🧠 Gemini CLI Bot: Brain'
on:
schedule:
- cron: '0 0 * * *' # Every 24 hours
issue_comment:
types: ['created']
workflow_dispatch:
inputs:
run_interactive:
description: 'Run interactive flow (requires issue_number)'
type: 'boolean'
default: false
issue_number:
description: 'Issue/PR number to simulate context from'
type: 'string'
required: false
comment_id:
description: 'Specific comment ID to simulate'
type: 'string'
required: false
clear_memory:
description: 'Clear memory (drops learnings from previous runs)'
type: 'boolean'
default: false
enable_prs:
description: 'Enable PRs (automatically promote changes to PRs)'
type: 'boolean'
default: false
concurrency:
group: '${{ github.workflow }}-${{ github.ref }}'
group: '${{ github.workflow }}-${{ github.event.issue.number || github.event.inputs.issue_number || github.ref }}'
cancel-in-progress: true
permissions:
contents: 'write'
issues: 'write'
pull-requests: 'write'
jobs:
brain:
reasoning:
name: 'Brain (Reasoning Layer)'
runs-on: 'ubuntu-latest'
if: "github.repository == 'google-gemini/gemini-cli'"
if: |
github.repository == 'google-gemini/gemini-cli' && (
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_interactive != 'true') ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_interactive == 'true') ||
(github.event_name == 'issue_comment' && github.event.comment.user.login != 'gemini-cli[bot]' && contains(github.event.comment.body, '@gemini-cli') && contains(fromJSON('["COLLABORATOR", "MEMBER", "OWNER"]'), github.event.comment.author_association))
)
# The reasoning phase is strictly readonly.
permissions:
contents: 'read'
issues: 'read'
actions: 'read'
steps:
- name: 'Determine Checkout Ref'
id: 'determine_ref'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ISSUE_NUMBER: '${{ github.event.issue.number || github.event.inputs.issue_number }}'
run: |
REF="${{ github.ref }}"
if [ -n "$ISSUE_NUMBER" ]; then
PR_HEAD=$(gh pr view "$ISSUE_NUMBER" --repo "${{ github.repository }}" --json headRefName --jq .headRefName 2>/dev/null || echo "")
if [ -n "$PR_HEAD" ]; then
REF="$PR_HEAD"
fi
fi
echo "ref=$REF" >> "$GITHUB_OUTPUT"
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ steps.determine_ref.outputs.ref }}'
fetch-depth: 0
persist-credentials: false
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -37,9 +83,266 @@ jobs:
- name: 'Build Gemini CLI'
run: 'npm run bundle'
- name: 'Download Previous Metrics'
- name: 'Download Previous State'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
if [ "${{ github.event.inputs.clear_memory }}" = "true" ]; then
echo "Memory clear requested. Skipping previous state download."
exit 0
fi
# Find the last successful run of this workflow
LAST_RUN_ID=$(gh run list --workflow "${{ github.workflow }}" --status success --limit 1 --json databaseId --jq '.[0].databaseId')
if [ -n "$LAST_RUN_ID" ]; then
echo "Found previous successful run: $LAST_RUN_ID"
# Download brain memory to a temp dir so we can selectively restore only persistent state
mkdir -p .temp_brain_data
gh run download "$LAST_RUN_ID" -n brain-data -D .temp_brain_data || echo "brain-data not found"
# Restore only persistent memory files
cp .temp_brain_data/tools/gemini-cli-bot/lessons-learned.md tools/gemini-cli-bot/lessons-learned.md 2>/dev/null || true
mkdir -p tools/gemini-cli-bot/history/
cp .temp_brain_data/tools/gemini-cli-bot/history/*.csv tools/gemini-cli-bot/history/ 2>/dev/null || true
rm -rf .temp_brain_data
else
echo "No previous successful run found."
fi
- name: 'Collect Current Metrics'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: 'npx tsx tools/gemini-cli-bot/metrics/index.ts'
- name: 'Run Brain Phases'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
GEMINI_MODEL: 'gemini-3-flash-preview'
GEMINI_CLI_HOME: 'tools/gemini-cli-bot'
ENABLE_PRS: "${{ github.event.inputs.enable_prs || 'false' }}"
TRIGGER_ISSUE_NUMBER: '${{ github.event.issue.number || github.event.inputs.issue_number }}'
TRIGGER_COMMENT_ID: '${{ github.event.comment.id || github.event.inputs.comment_id }}'
run: |
PROMPT_PATH="tools/gemini-cli-bot/brain/scheduled.md"
if [ "${{ github.event_name }}" = "issue_comment" ] || [ "${{ github.event.inputs.run_interactive }}" = "true" ]; then
PROMPT_PATH="tools/gemini-cli-bot/brain/interactive.md"
export ENABLE_PRS="true"
fi
touch trigger_context.md
if [ -n "$TRIGGER_ISSUE_NUMBER" ]; then
echo "<untrusted_context>" > trigger_context.md
echo "# Interactive Trigger Context" >> trigger_context.md
echo "You were invoked by a user in issue/PR #$TRIGGER_ISSUE_NUMBER." >> trigger_context.md
if [ -n "$TRIGGER_COMMENT_ID" ]; then
echo "## User Comment" >> trigger_context.md
gh api "repos/${{ github.repository }}/issues/comments/$TRIGGER_COMMENT_ID" -q '.body' >> trigger_context.md 2>/dev/null || gh api "repos/${{ github.repository }}/pulls/comments/$TRIGGER_COMMENT_ID" -q '.body' >> trigger_context.md
echo "" >> trigger_context.md
fi
echo "## Issue/PR Context" >> trigger_context.md
gh issue view "$TRIGGER_ISSUE_NUMBER" >> trigger_context.md 2>/dev/null || gh pr view "$TRIGGER_ISSUE_NUMBER" >> trigger_context.md
echo "</untrusted_context>" >> trigger_context.md
fi
if [ "$ENABLE_PRS" = "true" ]; then
echo "**System Directive**: PR creation is ENABLED for this run. You MUST activate the **'prs' skill** to stage your changes and generate a \`pr-description.md\` file if you are proposing fixes." >> trigger_context.md
echo "**CRITICAL System Directive**: You MUST ONLY propose and implement a **SINGLE** improvement or fix per run. Bundling unrelated changes (e.g., a documentation update and a script fix, or a metrics update and a logic fix) into a single PR is STRICTLY FORBIDDEN and will result in immediate rejection during the critique phase. If you identify multiple issues, pick the most impactful one and ignore the others for now." >> trigger_context.md
else
echo "**System Directive**: PR creation is DISABLED for this run. You MUST NOT stage files or attempt to create a PR description." >> trigger_context.md
fi
echo "" >> trigger_context.md
cat trigger_context.md "$PROMPT_PATH" > combined_prompt.md
node bundle/gemini.js --policy tools/gemini-cli-bot/ci-policy.toml --prompt="$(cat combined_prompt.md)"
if [ -n "$TRIGGER_ISSUE_NUMBER" ] && [ ! -s "issue-comment.md" ] && [ ! -s "pr-comment.md" ]; then
echo "Agent failed to respond. Generating fallback error message."
echo "⚠️ **Gemini CLI Bot failed to generate a response.**" > "issue-comment.md"
echo "" >> "issue-comment.md"
echo "I encountered an error or failed to generate a complete response to your request. You can check the [GitHub Actions Run Log](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details on what went wrong." >> "issue-comment.md"
fi
- name: 'Run Critique Phase'
if: "${{ github.event.inputs.enable_prs == 'true' || github.event_name == 'issue_comment' || github.event.inputs.run_interactive == 'true' }}"
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
GEMINI_MODEL: 'gemini-3-flash-preview'
GEMINI_CLI_HOME: 'tools/gemini-cli-bot'
run: |
if git diff --staged --quiet; then
echo "No changes staged. Skipping critique."
echo "[APPROVED]" > critique_result.txt
else
node bundle/gemini.js --policy tools/gemini-cli-bot/ci-policy.toml --prompt="$(cat tools/gemini-cli-bot/.gemini/skills/critique/SKILL.md)" 2>&1 | tee critique_output.log
if [ "${PIPESTATUS[0]}" -eq 0 ] && grep -q "\[APPROVED\]" critique_output.log && ! grep -q "\[REJECTED\]" critique_output.log; then
echo "[APPROVED]" > critique_result.txt
else
echo "Critique failed, rejected, or did not explicitly approve changes. Skipping PR creation."
echo "[REJECTED]" > critique_result.txt
fi
fi
- name: 'Generate Patch'
if: "${{ github.event.inputs.enable_prs == 'true' || github.event_name == 'issue_comment' || github.event.inputs.run_interactive == 'true' }}"
run: |
touch bot-changes.patch
touch pr-description.md
if [ -f critique_result.txt ] && grep -q "\[APPROVED\]" critique_result.txt && ! grep -q "\[REJECTED\]" critique_result.txt; then
git diff --staged > bot-changes.patch
else
echo "Critique did not approve. Skipping patch generation."
fi
- name: 'Archive Brain Data'
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'brain-data'
path: |
tools/gemini-cli-bot/lessons-learned.md
tools/gemini-cli-bot/history/*.csv
bot-changes.patch
pr-description.md
branch-name.txt
pr-comment.md
pr-number.txt
issue-comment.md
retention-days: 90
publish:
name: 'Publish Artifacts (Archive Layer)'
needs: 'reasoning'
runs-on: 'ubuntu-latest'
if: "github.repository == 'google-gemini/gemini-cli'"
# The publish phase is for archiving artifacts and optionally creating PRs.
permissions:
contents: 'write'
pull-requests: 'write'
actions: 'write'
steps:
- name: 'Generate GitHub App Token 🔑'
id: 'generate_token'
if: "${{ github.event.inputs.enable_prs == 'true' || github.event_name == 'issue_comment' || github.event.inputs.run_interactive == 'true' }}"
uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
owner: '${{ github.repository_owner }}'
repositories: '${{ github.event.repository.name }}'
permission-contents: 'write'
permission-pull-requests: 'write'
permission-issues: 'write'
- name: 'Determine Checkout Ref'
id: 'determine_ref'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
ISSUE_NUMBER: '${{ github.event.issue.number || github.event.inputs.issue_number }}'
run: |
REF="main"
if [ -n "$ISSUE_NUMBER" ]; then
PR_HEAD=$(gh pr view "$ISSUE_NUMBER" --repo "${{ github.repository }}" --json headRefName --jq .headRefName 2>/dev/null || echo "")
if [ -n "$PR_HEAD" ]; then
REF="$PR_HEAD"
fi
fi
echo "ref=$REF" >> "$GITHUB_OUTPUT"
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
ref: '${{ steps.determine_ref.outputs.ref }}'
fetch-depth: 0
persist-credentials: false
- name: 'Download Brain Data'
uses: 'actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093' # ratchet:actions/download-artifact@v4
with:
name: 'metrics-before'
path: 'tools/gemini-cli-bot/history/'
continue-on-error: true
name: 'brain-data'
path: '${{ runner.temp }}/brain-data/'
- name: 'Create or Update PR'
if: "${{ github.event.inputs.enable_prs == 'true' || github.event_name == 'issue_comment' || github.event.inputs.run_interactive == 'true' }}"
env:
GH_TOKEN: '${{ steps.generate_token.outputs.token }}'
FALLBACK_PAT: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
run: |
if [ -s "${{ runner.temp }}/brain-data/bot-changes.patch" ]; then
git config user.name "gemini-cli[bot]"
git config user.email "gemini-cli[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git"
BRANCH_NAME="bot/productivity-updates-$(date +'%Y%m%d%H%M%S')-${{ github.run_id }}"
if [ -f "${{ runner.temp }}/brain-data/branch-name.txt" ]; then
BRANCH_NAME=$(cat "${{ runner.temp }}/brain-data/branch-name.txt")
fi
if [[ ! "$BRANCH_NAME" =~ ^bot/ ]]; then
echo "Error: Branch name '$BRANCH_NAME' does not start with 'bot/'. Safety abort."
exit 1
fi
git checkout -B "$BRANCH_NAME"
git apply "${{ runner.temp }}/brain-data/bot-changes.patch"
git add .
if [ -s "${{ runner.temp }}/brain-data/pr-description.md" ]; then
git commit -F "${{ runner.temp }}/brain-data/pr-description.md"
else
git commit -m "🤖 Gemini Bot Productivity Optimizations"
fi
PR_TITLE="🤖 Gemini Bot Productivity Optimizations"
if [ -s "${{ runner.temp }}/brain-data/pr-description.md" ]; then
PR_TITLE=$(head -n 1 "${{ runner.temp }}/brain-data/pr-description.md")
fi
if ! git push origin "$BRANCH_NAME" --force; then
echo "Push failed. Retrying with FALLBACK_PAT..."
export GH_TOKEN="$FALLBACK_PAT"
git remote set-url origin "https://x-access-token:${FALLBACK_PAT}@github.com/${{ github.repository }}.git"
git push origin "$BRANCH_NAME" --force
fi
if ! gh pr view "$BRANCH_NAME" > /dev/null 2>&1; then
gh pr create --draft --title "$PR_TITLE" --body-file "${{ runner.temp }}/brain-data/pr-description.md" --head "$BRANCH_NAME" --base main || \
gh pr create --draft --title "🤖 Gemini Bot Productivity Optimizations" --body "Automated changes generated by Gemini CLI Bot." --head "$BRANCH_NAME" --base main
else
PR_STATE=$(gh pr view "$BRANCH_NAME" --json state --jq .state)
if [ "$PR_STATE" = "CLOSED" ]; then
NEW_BRANCH_NAME="${BRANCH_NAME}-retry-${{ github.run_id }}"
git checkout -b "$NEW_BRANCH_NAME"
git push origin "$NEW_BRANCH_NAME" --force
gh pr create --draft --title "$PR_TITLE" --body-file "${{ runner.temp }}/brain-data/pr-description.md" --head "$NEW_BRANCH_NAME" --base main || \
gh pr create --draft --title "🤖 Gemini Bot Productivity Optimizations" --body "Automated changes generated by Gemini CLI Bot." --head "$NEW_BRANCH_NAME" --base main
fi
fi
fi
- name: 'Post PR/Issue Comment'
env:
GH_TOKEN: '${{ steps.generate_token.outputs.token }}'
TRIGGER_ISSUE_NUMBER: '${{ github.event.issue.number || github.event.inputs.issue_number }}'
run: |
if [ -s "${{ runner.temp }}/brain-data/issue-comment.md" ] && [ -n "$TRIGGER_ISSUE_NUMBER" ]; then
echo "Posting comment to triggering issue #$TRIGGER_ISSUE_NUMBER"
# Use REST API (gh api) instead of GraphQL (gh issue comment) to ensure robot identity
# while avoiding potential GraphQL-specific authorization hurdles with PATs.
gh api "repos/${{ github.repository }}/issues/$TRIGGER_ISSUE_NUMBER/comments" -F body=@"${{ runner.temp }}/brain-data/issue-comment.md"
fi
if [ -s "${{ runner.temp }}/brain-data/pr-comment.md" ] && [ -f "${{ runner.temp }}/brain-data/pr-number.txt" ]; then
PR_NUM=$(cat "${{ runner.temp }}/brain-data/pr-number.txt")
# Using GitHub App, so author check is no longer valid against gemini-cli-robot
# Skipping author validation here to let the app post.
# Use REST API (gh api) for consistency and robot identity
gh api "repos/${{ github.repository }}/issues/$PR_NUM/comments" -F body=@"${{ runner.temp }}/brain-data/pr-comment.md"
fi
+3 -13
View File
@@ -23,6 +23,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
fetch-depth: 0
- name: 'Setup Node.js'
@@ -34,23 +35,12 @@ jobs:
- name: 'Install dependencies'
run: 'npm ci'
- name: 'Collect Metrics'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: 'npm run metrics'
- name: 'Archive Metrics'
uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4
with:
name: 'metrics-before'
path: 'metrics-before.csv'
- name: 'Run Reflex Processes'
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
if [ -d "tools/gemini-cli-bot/processes/scripts" ] && [ "$(ls -A tools/gemini-cli-bot/processes/scripts)" ]; then
for script in tools/gemini-cli-bot/processes/scripts/*.ts; do
if [ -d "tools/gemini-cli-bot/reflexes/scripts" ] && [ "$(ls -A tools/gemini-cli-bot/reflexes/scripts)" ]; then
for script in tools/gemini-cli-bot/reflexes/scripts/*.ts; do
echo "Running reflex script: $script"
npx tsx "$script"
done
@@ -0,0 +1,47 @@
name: '🔄 Gemini Scheduled Lifecycle Manager'
on:
schedule:
- cron: '30 1 * * *' # Once a day
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode (no changes applied)'
required: false
default: false
type: 'boolean'
concurrency:
group: '${{ github.workflow }}'
cancel-in-progress: true
permissions:
issues: 'write'
pull-requests: 'write'
jobs:
manage-lifecycle:
if: "github.repository == 'google-gemini/gemini-cli'"
runs-on: 'ubuntu-latest'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
- name: 'Checkout repository'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
persist-credentials: false
- name: 'Lifecycle Management'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
env:
DRY_RUN: '${{ inputs.dry_run }}'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |
const script = require('./.github/scripts/gemini-lifecycle-manager.cjs');
await script({github, context, core});
@@ -28,6 +28,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Log in to GitHub Container Registry'
uses: 'docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1' # ratchet:docker/login-action@v3
@@ -47,6 +49,7 @@ jobs:
REPOSITORY: '${{ github.repository }}'
FIRESTORE_PROJECT: '${{ vars.FIRESTORE_PROJECT }}'
with:
upload_artifacts: 'true'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
@@ -85,9 +88,11 @@ jobs:
}
},
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)"
],
"tools": {
"core": [
"run_shell_command(echo)"
]
},
"telemetry": {
"enabled": true,
"target": "gcp"
@@ -1,10 +1,6 @@
name: '📋 Gemini Scheduled Issue Triage'
on:
issues:
types:
- 'opened'
- 'reopened'
schedule:
- cron: '0 * * * *' # Runs every hour
workflow_dispatch:
@@ -23,13 +19,27 @@ permissions:
jobs:
triage-issues:
timeout-minutes: 10
timeout-minutes: 60
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Install Utilities'
run: |
sudo apt-get update
sudo apt-get install -y ripgrep
- name: 'Get Current Version'
id: 'get_version'
run: |
VERSION=$(jq -r .version package.json | cut -d'-' -f1)
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
echo "🚀 Current CLI Version: ${VERSION}"
- name: 'Generate GitHub App Token'
id: 'generate_token'
@@ -47,10 +57,38 @@ jobs:
ISSUE_EVENT: '${{ toJSON(github.event.issue) }}'
run: |
set -euo pipefail
ISSUE_JSON=$(echo "$ISSUE_EVENT" | jq -c '[{number: .number, title: .title, body: .body}]')
echo "issues_to_triage=${ISSUE_JSON}" >> "${GITHUB_OUTPUT}"
echo "$ISSUE_EVENT" | jq -c '[{number: .number, title: .title, body: .body}]' > issues_to_triage.json
echo "has_issues=true" >> "${GITHUB_OUTPUT}"
echo "✅ Found issue #${{ github.event.issue.number }} from event to triage! 🎯"
- name: 'Sync Issue Types'
if: |-
${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
const syncIssueTypes = require('./.github/scripts/sync-issue-types.cjs');
await syncIssueTypes({ github, context, core });
- name: 'Find Issues with Conflicting Labels'
if: |-
${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
GITHUB_REPOSITORY: '${{ github.repository }}'
run: |-
set -euo pipefail
echo '🔍 Fetching open issues to find conflicts...'
# Fetch up to 2000 open issues in one quick GraphQL-backed query
gh issue list --repo "${GITHUB_REPOSITORY}" --search "is:issue is:open" --limit 2000 --json number,title,body,labels > all_open_issues.json
echo '🧹 Filtering issues with multiple area/ or priority/ labels...'
jq -c '[ .[] | select( (.labels | map(select(.name | startswith("area/"))) | length) > 1 or (.labels | map(select(.name | startswith("priority/"))) | length) > 1 ) ] | .[0:50]' all_open_issues.json > conflicting_labels_issues.json
CONFLICT_COUNT=$(jq 'length' conflicting_labels_issues.json)
echo "Found ${CONFLICT_COUNT} issues with conflicting labels (capped at 50 for processing)."
- name: 'Find untriaged issues'
if: |-
${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
@@ -62,25 +100,56 @@ jobs:
set -euo pipefail
echo '🔍 Finding issues missing area labels...'
NO_AREA_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:area/core -label:area/agent -label:area/enterprise -label:area/non-interactive -label:area/security -label:area/platform -label:area/extensions -label:area/documentation -label:area/unknown' --limit 100 --json number,title,body)"
gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:area/core -label:area/agent -label:area/enterprise -label:area/non-interactive -label:area/security -label:area/platform -label:area/extensions -label:area/documentation -label:area/unknown' --limit 50 --json number,title,body,labels > no_area_issues.json
echo '🔍 Finding issues missing kind labels...'
NO_KIND_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:kind/bug -label:kind/enhancement -label:kind/customer-issue -label:kind/question' --limit 100 --json number,title,body)"
gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:kind/bug -label:kind/enhancement -label:kind/customer-issue -label:kind/question' --limit 50 --json number,title,body,labels > no_kind_issues.json
echo '🏷️ Finding issues missing priority labels...'
NO_PRIORITY_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:priority/p0 -label:priority/p1 -label:priority/p2 -label:priority/p3 -label:priority/unknown' --limit 100 --json number,title,body)"
gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:priority/p0 -label:priority/p1 -label:priority/p2 -label:priority/p3 -label:priority/unknown' --limit 50 --json number,title,body,labels > no_priority_issues.json
echo '🔄 Merging and deduplicating issues...'
ISSUES="$(echo "${NO_AREA_ISSUES}" "${NO_KIND_ISSUES}" "${NO_PRIORITY_ISSUES}" | jq -c -s 'add | unique_by(.number)')"
echo '📏 Finding issues missing effort labels...'
gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue -label:effort/small -label:effort/medium -label:effort/large label:area/core,area/extensions,area/site,area/non-interactive' --limit 20 --json number,title,body,labels > no_effort_issues.json
echo '📝 Setting output for GitHub Actions...'
echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
echo '🔄 Merging and deduplicating standard triage issues...'
if [ ! -f conflicting_labels_issues.json ]; then echo "[]" > conflicting_labels_issues.json; fi
jq -c -s 'add | unique_by(.number)' no_area_issues.json no_kind_issues.json no_priority_issues.json conflicting_labels_issues.json > standard_issues_to_triage.json
ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
echo "✅ Found ${ISSUE_COUNT} unique issues to triage! 🎯"
echo '📏 Deduplicating effort issues...'
jq -c -s 'add | unique_by(.number)' no_effort_issues.json > effort_issues_to_triage.json
STANDARD_COUNT="$(jq 'length' standard_issues_to_triage.json)"
EFFORT_COUNT="$(jq 'length' effort_issues_to_triage.json)"
if [ "$STANDARD_COUNT" -gt 0 ] || [ "$EFFORT_COUNT" -gt 0 ]; then
echo "has_issues=true" >> "${GITHUB_OUTPUT}"
echo "has_standard_issues=$([ "$STANDARD_COUNT" -gt 0 ] && echo 'true' || echo 'false')" >> "${GITHUB_OUTPUT}"
echo "has_effort_issues=$([ "$EFFORT_COUNT" -gt 0 ] && echo 'true' || echo 'false')" >> "${GITHUB_OUTPUT}"
else
echo "has_issues=false" >> "${GITHUB_OUTPUT}"
echo "has_standard_issues=false" >> "${GITHUB_OUTPUT}"
echo "has_effort_issues=false" >> "${GITHUB_OUTPUT}"
fi
echo "✅ Found ${STANDARD_COUNT} standard issues and ${EFFORT_COUNT} effort issues to triage! 🎯"
- name: 'Create Gemini CLI Experiments Override'
if: |-
steps.get_issue_from_event.outputs.has_issues == 'true' || steps.find_issues.outputs.has_issues == 'true'
run: |
cat << 'EOF' > gemini_exp.json
{
"flags": [
{
"flagId": 45750526,
"boolValue": false
}
],
"experimentIds": []
}
EOF
- name: 'Get Repository Labels'
id: 'get_labels'
@@ -97,18 +166,21 @@ jobs:
core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
return labelNames;
- name: 'Run Gemini Issue Analysis'
- name: 'Run Standard Triage Analysis'
if: |-
(steps.get_issue_from_event.outputs.issues_to_triage != '' && steps.get_issue_from_event.outputs.issues_to_triage != '[]') ||
(steps.find_issues.outputs.issues_to_triage != '' && steps.find_issues.outputs.issues_to_triage != '[]')
steps.get_issue_from_event.outputs.has_issues == 'true' || steps.find_issues.outputs.has_standard_issues == 'true'
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
id: 'gemini_issue_analysis'
id: 'gemini_standard_issue_analysis'
env:
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
ISSUES_TO_TRIAGE: '${{ steps.get_issue_from_event.outputs.issues_to_triage || steps.find_issues.outputs.issues_to_triage }}'
REPOSITORY: '${{ github.repository }}'
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
CLI_VERSION: '${{ steps.get_version.outputs.version }}'
GEMINI_EXP: 'gemini_exp.json'
GEMINI_STRICT_TELEMETRY_LIMITS: 'true'
GEMINI_MODEL: 'gemini-3-flash-preview'
with:
upload_artifacts: 'true'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
@@ -119,11 +191,14 @@ jobs:
settings: |-
{
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)"
],
"tools": {
"core": [
"run_shell_command(echo)",
"read_file"
]
},
"telemetry": {
"enabled": true,
"enabled": false,
"target": "gcp"
}
}
@@ -136,14 +211,16 @@ jobs:
## Steps
1. You are only able to use the echo command. Review the available labels in the environment variable: "${AVAILABLE_LABELS}".
2. Check environment variable for issues to triage: $ISSUES_TO_TRIAGE (JSON array of issues)
3. Review the issue title, body and any comments provided in the environment variables.
4. Identify the most relevant labels from the existing labels, specifically focusing on area/*, kind/* and priority/*.
1. You are only able to use the echo and read_file commands. Review the available labels in the environment variable: "${AVAILABLE_LABELS}".
2. Use the read_file tool to read the file "standard_issues_to_triage.json" which contains the JSON array of issues to triage (including their current labels).
3. Review the issue title, body, current labels, and any comments provided in the JSON file.
4. Identify the most relevant labels from the existing labels, specifically focusing on area/*, kind/*, and priority/*.
5. Label Policy:
- If the issue already has a kind/ label, do not change it.
- If the issue already has a priority/ label, do not change it.
- If the issue already has an area/ label, do not change it.
- If the issue has exactly ONE priority/ label, do not change it (unless you are explicitly re-evaluating an ambiguous priority).
- If the issue is missing a priority/ label, OR if the issue currently has MULTIPLE priority/ labels, you must evaluate the issue's impact to determine exactly ONE priority level (priority/p0, priority/p1, priority/p2, priority/p3, or priority/unknown) based the guidelines. If you are fixing an issue with multiple priority/ labels, put the correct one in `labels_to_add` and put all the incorrect ones in `labels_to_remove`.
- If the issue has exactly ONE area/ label, do not change it.
- If the issue is missing an area/ label, OR if the issue currently has MULTIPLE area/ labels, select exactly ONE area/ label that best fits the issue. Issues MUST NOT have multiple area/ labels. If you are fixing an issue with multiple area/ labels, put the correct one in `labels_to_add` and put all the incorrect ones in `labels_to_remove`.
- If any of these are missing, select exactly ONE appropriate label for the missing category.
6. Identify other applicable labels based on the issue content, such as status/*, help wanted, good first issue, etc.
7. Give me a single short explanation about why you are selecting each label in the process.
@@ -160,11 +237,12 @@ jobs:
]
```
If an issue cannot be classified, do not include it in the output array.
9. For each issue please check if CLI version is present, this is usually in the output of the /about command and will look like 0.1.5
- Anything more than 6 versions older than the most recent should add the status/need-retesting label
10. If you see that the issue doesn't look like it has sufficient information recommend the status/need-information label and leave a comment politely requesting the relevant information, eg.. if repro steps are missing request for repro steps. if version information is missing request for version information into the explanation section below.
11. If you think an issue might be a Priority/P0 do not apply the priority/p0 label. Instead apply a status/manual-triage label and include a note in your explanation.
12. If you are uncertain about a category, use the area/unknown, kind/question, or priority/unknown labels as appropriate. If you are extremely uncertain, apply the status/manual-triage label.
9. For each issue, carefully check if the CLI version is present. It is usually found under the "### Client information" header, as a bullet point (e.g., "• CLI Version: 0.33.1", "* **CLI Version:** 0.42.0"), or in the output of the `/about` command.
- **Only for issues classified as kind/bug:** If the version is provided but is more than 6 minor versions older than the most recent release (current version is ${{ steps.get_version.outputs.version }}), apply the status/need-information label and leave a comment politely asking the user to verify if the issue persists in the latest version.
10. **Only for issues classified as kind/bug:** If the issue does not have sufficient information, recommend the status/need-information label and leave a comment politely requesting the missing details. For example, if repro steps are missing, ask for them; if the CLI version is completely missing, ask for the version information in the explanation section below. Do not ask for version info if it is already in the issue body. (Check both bullet points and bold text). For features and enhancements, the CLI version is NOT required.
11. If you think an issue is a Priority/P0, you MUST apply the priority/p1 label AND the status/manual-triage label, and include a note in your explanation that it likely requires P0 escalation.
12. If the issue is highly ambiguous, completely lacks a description, or you are torn between two lower priorities (like P2 vs P3), you MUST retain the existing priority label if one is already present. Do not toggle the priority if you do not have enough information to make a definitive change.
13. If you are uncertain about a category, use the area/unknown, kind/question, or priority/unknown labels as appropriate. If you are extremely uncertain, apply the status/manual-triage label.
## Guidelines
@@ -174,10 +252,126 @@ jobs:
- Do not add comments or modify the issue content.
- Do not remove the following labels maintainer, help wanted or good first issue.
- Triage only the current issue.
- Identify only one area/ label.
- Identify exactly ONE area/ label. Do NOT assign multiple area/ labels to a single issue.
- Identify only one kind/ label (Do not apply kind/duplicate or kind/parent-issue)
- Identify only one priority/ label.
- Once you categorize the issue if it needs information bump down the priority by 1 eg.. a p0 would become a p1 a p1 would become a p2. P2 and P3 can stay as is in this scenario.
- Identify exactly ONE priority/ label. Do NOT assign multiple priority/ labels to a single issue.
- **Do not manually downgrade the priority.** Always assign the true priority based on the guidelines. The system will handle downgrades programmatically if information is missing.
- **NEVER mention label names, label removals, or label additions in your `explanation`.** The explanation must be purely written for the user (e.g., "Please provide your CLI version.") without exposing internal triage mechanics (e.g., do NOT say "Removing area/unknown to leave only area/core").
Categorization Guidelines (Priority):
P0 - Urgent Blocking Issues:
- DO NOT APPLY THE priority/p0 LABEL AUTOMATICALLY. Instead apply priority/p1 and status/manual-triage.
- Definition: Critical failures breaking core functionality for a large portion of users. Examples: CLI fails to launch globally, core commands (gemini run) crash on valid input, unhandled promise rejections on boot, critical security vulnerability.
- Note: You must apply priority/p1 and status/manual-triage instead of priority/p0.
P1 - Critical but Workable:
- Definition: Severe issues without a reasonable workaround, significantly degrading the developer experience but not globally blocking. Examples: Specific tools failing consistently (e.g., `web_search` returns 500s), persistent PTY streaming hangs, memory leaks leading to OOM after short use.
P2 - Significant Issues:
- Definition: Affect some workflows but a clear workaround exists, or non-critical bugs. Examples: Theme flickering, confusing error messages, minor UI misalignment, failing to read deeply nested config files correctly.
P3 - Minor/Enhancements:
- Definition: Trivial bugs, typos, documentation requests, or feature requests.
Categorization Guidelines (Kind):
kind/bug: The issue is describing an unexpected behavior or failure in the application.
kind/enhancement: The issue is describing a feature request or an improvement to an existing feature.
kind/question: The issue is asking a question about how to use the CLI or about a specific feature.
Categorization Guidelines (Area):
area/agent: The "brain" of the CLI. Core agent logic, model quality, tool/function calling, memory, web search, generated code quality, sub-agents.
area/core: The fundamental CLI app. UI/UX, installation, OS compatibility, performance, command parsing, theming, flickering.
area/documentation: Website docs, READMEs, inline help text.
area/enterprise: Telemetry, Policy, Quota / Licensing
area/extensions: Gemini CLI extensions capability
area/non-interactive: GitHub Actions, SDK, 3P Integrations, Shell Scripting, Command line automation
area/platform: Platform specific behavior
area/security: Authentication, authorization, privacy, data leaks, credential storage.
- name: 'Stop Telemetry Collector'
if: |-
steps.find_issues.outputs.has_effort_issues == 'true'
run: 'docker rm -f gemini-telemetry-collector || true'
- name: 'Run Effort Triage Analysis'
if: |-
steps.find_issues.outputs.has_effort_issues == 'true'
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
id: 'gemini_effort_issue_analysis'
env:
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
REPOSITORY: '${{ github.repository }}'
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
CLI_VERSION: '${{ steps.get_version.outputs.version }}'
GEMINI_EXP: 'gemini_exp.json'
GEMINI_STRICT_TELEMETRY_LIMITS: 'true'
GEMINI_MODEL: 'gemini-3-flash-preview'
with:
upload_artifacts: 'true'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 30,
"tools": {
"core": [
"run_shell_command(echo)",
"grep_search",
"glob",
"read_file"
]
},
"telemetry": {
"enabled": false,
"target": "gcp"
}
}
prompt: |-
## Role
You are an expert software architect. Analyze the provided GitHub issues and assign the correct `effort/*` label based on the codebase complexity.
## Steps
1. Use the read_file tool to read "effort_issues_to_triage.json".
2. For each issue in the array:
- You must evaluate the architectural complexity to determine the effort level. You MUST NOT guess the root cause. You MUST actively use your codebase search tools (grep_search and glob) to search for keywords from the issue and explore the codebase. You must identify the specific files and components involved before deciding the effort.
3. Output a JSON array of objects, each containing the issue number and the effort label to add, along with an explanation and an effort_analysis field. This effort_analysis must be highly detailed, technical, and empirical. It MUST NOT contain vague guesses (e.g., avoid words like "likely points to" or "possibly"). You must explicitly cite the specific file paths and architectural mechanisms you discovered using your search tools, explain the root cause, and then explicitly state how that complexity maps to the chosen effort level guidelines. For example:
```
[
{
"issue_number": 123,
"labels_to_add": ["effort/small"],
"explanation": "This is a simple logic fix.",
"effort_analysis": "The `vscode-ide-companion` extension indiscriminately tracks active text editors via `vscode.window.onDidChangeActiveTextEditor` in `open-files-manager.ts`. When a user opens `.vscode/settings.json`, its content is sent to the CLI's context. The fix is highly localized to the VS Code companion extension's event listener. It involves adding a simple conditional check to exclude specific configuration files from the active editor tracking logic, which is a trivial logic adjustment with a clear root cause."
}
]
```
## Guidelines
- Output only valid JSON format
- Do not include any explanation or additional text, just the JSON
- Triage only the current issue.
Categorization Guidelines (Effort):
effort/small (1 day or less):
- Trivial Logic & Config: Schema updates (Zod), feature flag toggles, adding missing fields to package.json or settings.json.
- UI/Aesthetic Adjustments: Fixing minor layout bugs in Ink components (e.g., adding flexShrink, correcting padding in a single Box), text color changes.
- Documentation & Strings: Typos, log message updates, CLI argument descriptions.
- Localized Bug Fixes: Single-file logic errors, straightforward promise rejections (e.g., wrapping a known failure in a try/catch), simple regex or string parsing fixes.
effort/medium (2-3 days):
- React/Ink State Management: Debugging useState/useEffect/useReducer bugs, component lifecycle issues (memory leaks in the UI), terminal redraw flickering, or state synchronization between the CLI's internal input buffer and the interactive React components.
- Asynchronous Flow & Integration: Resolving complex Promise chains, ERR_STREAM_PREMATURE_CLOSE, debugging IDE companion extensions (VS Code, Android Studio) or resolving hanging HTTP requests/IPC between the CLI and external plugins, timeouts in non-interactive/ACP modes.
- Tooling & Output Parsers: Modifying how tools parse streaming stdout/stderr buffers, adding new built-in tools that don't require native bindings.
- Cross-Component Refactors: Changes that span across packages/cli and packages/core to pass new data models or telemetry state.
effort/large (3+ days):
- Platform-Specific Complexities (PTY/Signals): Any issue involving node-pty, child_process.spawn, OS-level shell behavior (Windows vs Linux vs macOS), pseudo-terminal exhaustion (ENXIO), raw mode terminal desyncs, or POSIX signal forwarding (SIGINT/SIGTERM).
- Core Architecture & Protocols: Refactoring the Scheduler, Agent-to-Agent (A2A) protocol implementation, low-level MCP (Model Context Protocol) transport mechanisms.
- Performance & Memory: Diagnosing massive disk/memory leaks, severe boot time regressions, high-throughput streaming optimizations (e.g., voice streaming pipelines).
Note: Any bug that is described as intermittent, flickering, difficult to reproduce, platform-specific, or requiring cross-environment setups (e.g., involving the VS Code IDE companion, GCA plugin, or Android Studio) MUST NOT be rated as effort/small because of the increased overhead of testing and reproducing.
Categorization Guidelines (Priority):
P0 - Urgent Blocking Issues:
@@ -216,64 +410,52 @@ jobs:
- This product is designed to use different models eg.. using pro, downgrading to flash etc.
- When users report that they dont expect the model to change those would be categorized as feature requests.
- name: 'Apply Labels to Issues'
- name: 'Apply Triaged Labels'
if: |-
${{ steps.gemini_issue_analysis.outcome == 'success' &&
steps.gemini_issue_analysis.outputs.summary != '[]' }}
always() &&
( (steps.gemini_standard_issue_analysis.outcome == 'success' && steps.gemini_standard_issue_analysis.outputs.summary != '[]' && steps.gemini_standard_issue_analysis.outputs.summary != '') ||
(steps.gemini_effort_issue_analysis.outcome == 'success' && steps.gemini_effort_issue_analysis.outputs.summary != '[]' && steps.gemini_effort_issue_analysis.outputs.summary != '') )
env:
REPOSITORY: '${{ github.repository }}'
LABELS_OUTPUT: '${{ steps.gemini_issue_analysis.outputs.summary }}'
LABELS_OUTPUT_STANDARD: '${{ steps.gemini_standard_issue_analysis.outputs.summary }}'
LABELS_OUTPUT_EFFORT: '${{ steps.gemini_effort_issue_analysis.outputs.summary }}'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
const rawLabels = process.env.LABELS_OUTPUT;
core.info(`Raw labels JSON: ${rawLabels}`);
let parsedLabels;
try {
const jsonMatch = rawLabels.match(/```json\s*([\s\S]*?)\s*```/);
if (!jsonMatch || !jsonMatch[1]) {
throw new Error("Could not find a ```json ... ``` block in the output.");
}
const jsonString = jsonMatch[1].trim();
parsedLabels = JSON.parse(jsonString);
core.info(`Parsed labels JSON: ${JSON.stringify(parsedLabels)}`);
} catch (err) {
core.setFailed(`Failed to parse labels JSON from Gemini output: ${err.message}\nRaw output: ${rawLabels}`);
return;
}
const applyLabels = require('./.github/scripts/apply-issue-labels.cjs');
await applyLabels({ github, context, core });
for (const entry of parsedLabels) {
const issueNumber = entry.issue_number;
if (!issueNumber) {
core.info(`Skipping entry with no issue number: ${JSON.stringify(entry)}`);
continue;
}
- name: 'Sync Issue Types (Post-Analysis)'
if: |-
always() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
const syncIssueTypes = require('./.github/scripts/sync-issue-types.cjs');
await syncIssueTypes({ github, context, core });
const labelsToAdd = entry.labels_to_add || [];
labelsToAdd.push('status/bot-triaged');
- name: 'Find Triaged Issues to Clean Up'
if: |-
always() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token }}'
GITHUB_REPOSITORY: '${{ github.repository }}'
run: |-
set -euo pipefail
echo '🧹 Finding issues that have conflicting status labels...'
gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue label:status/bot-triaged label:status/need-triage' --limit 50 --json number > cleanup_1.json
gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue label:status/bot-triaged label:status/manual-triage' --limit 50 --json number > cleanup_2.json
jq -c -s 'add | unique_by(.number)' cleanup_1.json cleanup_2.json > issues_to_cleanup.json
if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: labelsToAdd
});
const explanation = entry.explanation ? ` - ${entry.explanation}` : '';
core.info(`Successfully added labels for #${issueNumber}: ${labelsToAdd.join(', ')}${explanation}`);
}
if (entry.explanation) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: entry.explanation,
});
}
if ((!entry.labels_to_add || entry.labels_to_add.length === 0) && (!entry.labels_to_remove || entry.labels_to_remove.length === 0)) {
core.info(`No labels to add or remove for #${issueNumber}, leaving as is`);
}
}
- name: 'Clean Up Triage Labels'
if: |-
always() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |-
const cleanupLabels = require('./.github/scripts/cleanup-triage-labels.cjs');
await cleanupLabels({ github, context, core });
@@ -21,6 +21,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Generate GitHub App Token'
id: 'generate_token'
@@ -1,159 +0,0 @@
name: '🔒 Gemini Scheduled Stale Issue Closer'
on:
schedule:
- cron: '0 0 * * 0' # Every Sunday at midnight UTC
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode (no changes applied)'
required: false
default: false
type: 'boolean'
concurrency:
group: '${{ github.workflow }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
jobs:
close-stale-issues:
if: "github.repository == 'google-gemini/gemini-cli'"
runs-on: 'ubuntu-latest'
permissions:
issues: 'write'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
uses: 'actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
permission-issues: 'write'
- name: 'Process Stale Issues'
uses: 'actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b' # ratchet:actions/github-script@v7
env:
DRY_RUN: '${{ inputs.dry_run }}'
with:
github-token: '${{ steps.generate_token.outputs.token }}'
script: |
const dryRun = process.env.DRY_RUN === 'true';
if (dryRun) {
core.info('DRY RUN MODE ENABLED: No changes will be applied.');
}
const batchLabel = 'Stale';
const threeMonthsAgo = new Date();
threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
const tenDaysAgo = new Date();
tenDaysAgo.setDate(tenDaysAgo.getDate() - 10);
core.info(`Cutoff date for creation: ${threeMonthsAgo.toISOString()}`);
core.info(`Cutoff date for updates: ${tenDaysAgo.toISOString()}`);
const query = `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open created:<${threeMonthsAgo.toISOString()}`;
core.info(`Searching with query: ${query}`);
const itemsToCheck = await github.paginate(github.rest.search.issuesAndPullRequests, {
q: query,
sort: 'created',
order: 'asc',
per_page: 100
});
core.info(`Found ${itemsToCheck.length} open issues to check.`);
let processedCount = 0;
for (const issue of itemsToCheck) {
const createdAt = new Date(issue.created_at);
const updatedAt = new Date(issue.updated_at);
const reactionCount = issue.reactions.total_count;
// Basic thresholds
if (reactionCount >= 5) {
continue;
}
// Skip if it has a maintainer, help wanted, or Public Roadmap label
const rawLabels = issue.labels.map((l) => l.name);
const lowercaseLabels = rawLabels.map((l) => l.toLowerCase());
if (
lowercaseLabels.some((l) => l.includes('maintainer')) ||
lowercaseLabels.includes('help wanted') ||
rawLabels.includes('🗓️ Public Roadmap')
) {
continue;
}
let isStale = updatedAt < tenDaysAgo;
// If apparently active, check if it's only bot activity
if (!isStale) {
try {
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
per_page: 100,
sort: 'created',
direction: 'desc'
});
const lastHumanComment = comments.data.find(comment => comment.user.type !== 'Bot');
if (lastHumanComment) {
isStale = new Date(lastHumanComment.created_at) < tenDaysAgo;
} else {
// No human comments. Check if creator is human.
if (issue.user.type !== 'Bot') {
isStale = createdAt < tenDaysAgo;
} else {
isStale = true; // Bot created, only bot comments
}
}
} catch (error) {
core.warning(`Failed to fetch comments for issue #${issue.number}: ${error.message}`);
continue;
}
}
if (isStale) {
processedCount++;
const message = `Closing stale issue #${issue.number}: "${issue.title}" (${issue.html_url})`;
core.info(message);
if (!dryRun) {
// Add label
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [batchLabel]
});
// Add comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: 'Hello! As part of our effort to keep our backlog manageable and focus on the most active issues, we are tidying up older reports.\n\nIt looks like this issue hasn\'t been active for a while, so we are closing it for now. However, if you are still experiencing this bug on the latest stable build, please feel free to comment on this issue or create a new one with updated details.\n\nThank you for your contribution!'
});
// Close issue
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
state_reason: 'not_planned'
});
}
}
}
core.info(`\nTotal issues processed: ${processedCount}`);
@@ -1,254 +0,0 @@
name: 'Gemini Scheduled Stale PR Closer'
on:
schedule:
- cron: '0 2 * * *' # Every day at 2 AM UTC
pull_request:
types: ['opened', 'edited']
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode'
required: false
default: false
type: 'boolean'
jobs:
close-stale-prs:
if: "github.repository == 'google-gemini/gemini-cli'"
runs-on: 'ubuntu-latest'
permissions:
pull-requests: 'write'
issues: 'write'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
env:
APP_ID: '${{ secrets.APP_ID }}'
if: |-
${{ env.APP_ID != '' }}
uses: 'actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
- name: 'Process Stale PRs'
uses: 'actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b' # ratchet:actions/github-script@v7
env:
DRY_RUN: '${{ inputs.dry_run }}'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |
const dryRun = process.env.DRY_RUN === 'true';
const fourteenDaysAgo = new Date();
fourteenDaysAgo.setDate(fourteenDaysAgo.getDate() - 14);
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
// 1. Fetch maintainers for verification
let maintainerLogins = new Set();
const teams = ['gemini-cli-maintainers', 'gemini-cli-askmode-approvers', 'gemini-cli-docs'];
for (const team_slug of teams) {
try {
const members = await github.paginate(github.rest.teams.listMembersInOrg, {
org: context.repo.owner,
team_slug: team_slug
});
for (const m of members) maintainerLogins.add(m.login.toLowerCase());
core.info(`Successfully fetched ${members.length} team members from ${team_slug}`);
} catch (e) {
// Silently skip if permissions are insufficient; we will rely on author_association
core.debug(`Skipped team fetch for ${team_slug}: ${e.message}`);
}
}
const isMaintainer = async (login, assoc) => {
// Reliably identify maintainers using authorAssociation (provided by GitHub)
// and organization membership (if available).
const isTeamMember = maintainerLogins.has(login.toLowerCase());
const isRepoMaintainer = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(assoc);
if (isTeamMember || isRepoMaintainer) return true;
// Fallback: Check if user belongs to the 'google' or 'googlers' orgs (requires permission)
try {
const orgs = ['googlers', 'google'];
for (const org of orgs) {
try {
await github.rest.orgs.checkMembershipForUser({ org: org, username: login });
return true;
} catch (e) {
if (e.status !== 404) throw e;
}
}
} catch (e) {
// Gracefully ignore failures here
}
return false;
};
// 2. Fetch all open PRs
let prs = [];
if (context.eventName === 'pull_request') {
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number
});
prs = [pr];
} else {
prs = await github.paginate(github.rest.pulls.list, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100
});
}
for (const pr of prs) {
const maintainerPr = await isMaintainer(pr.user.login, pr.author_association);
const isBot = pr.user.type === 'Bot' || pr.user.login.endsWith('[bot]');
if (maintainerPr || isBot) continue;
// Helper: Fetch labels and linked issues via GraphQL
const prDetailsQuery = `query($owner:String!, $repo:String!, $number:Int!) {
repository(owner:$owner, name:$repo) {
pullRequest(number:$number) {
closingIssuesReferences(first: 10) {
nodes {
number
labels(first: 20) {
nodes { name }
}
}
}
}
}
}`;
let linkedIssues = [];
try {
const res = await github.graphql(prDetailsQuery, {
owner: context.repo.owner, repo: context.repo.repo, number: pr.number
});
linkedIssues = res.repository.pullRequest.closingIssuesReferences.nodes;
} catch (e) {
core.warning(`GraphQL fetch failed for PR #${pr.number}: ${e.message}`);
}
// Check for mentions in body as fallback (regex)
const body = pr.body || '';
const mentionRegex = /(?:#|https:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/)(\d+)/i;
const matches = body.match(mentionRegex);
if (matches && linkedIssues.length === 0) {
const issueNumber = parseInt(matches[1]);
try {
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber
});
linkedIssues = [{ number: issueNumber, labels: { nodes: issue.labels.map(l => ({ name: l.name })) } }];
} catch (e) {}
}
// 3. Enforcement Logic
const prLabels = pr.labels.map(l => l.name.toLowerCase());
const hasHelpWanted = prLabels.includes('help wanted') ||
linkedIssues.some(issue => issue.labels.nodes.some(l => l.name.toLowerCase() === 'help wanted'));
const hasMaintainerOnly = prLabels.includes('🔒 maintainer only') ||
linkedIssues.some(issue => issue.labels.nodes.some(l => l.name.toLowerCase() === '🔒 maintainer only'));
const hasLinkedIssue = linkedIssues.length > 0;
// Closure Policy: No help-wanted label = Close after 14 days
if (pr.state === 'open' && !hasHelpWanted && !hasMaintainerOnly) {
const prCreatedAt = new Date(pr.created_at);
// We give a 14-day grace period for non-help-wanted PRs to be manually reviewed/labeled by an EM
if (prCreatedAt > fourteenDaysAgo) {
core.info(`PR #${pr.number} is new and lacks 'help wanted'. Giving 14-day grace period for EM review.`);
continue;
}
core.info(`PR #${pr.number} is older than 14 days and lacks 'help wanted' association. Closing.`);
if (!dryRun) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: "Hi there! Thank you for your interest in contributing to Gemini CLI. \n\nTo ensure we maintain high code quality and focus on our prioritized roadmap, we have updated our contribution policy (see [Discussion #17383](https://github.com/google-gemini/gemini-cli/discussions/17383)). \n\n**We only *guarantee* review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'.** All other community pull requests are subject to closure after 14 days if they do not align with our current focus areas. For this reason, we strongly recommend that contributors only submit pull requests against issues explicitly labeled as **'help-wanted'**. \n\nThis pull request is being closed as it has been open for 14 days without a 'help wanted' designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding and for being part of our community!"
});
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
state: 'closed'
});
}
continue;
}
// Also check for linked issue even if it has help wanted (redundant but safe)
if (pr.state === 'open' && !hasLinkedIssue) {
// Already covered by hasHelpWanted check above, but good for future-proofing
continue;
}
// 4. Staleness Check (Scheduled only)
if (pr.state === 'open' && context.eventName !== 'pull_request') {
// Skip PRs that were created less than 30 days ago - they cannot be stale yet
const prCreatedAt = new Date(pr.created_at);
if (prCreatedAt > thirtyDaysAgo) continue;
let lastActivity = new Date(pr.created_at);
try {
const reviews = await github.paginate(github.rest.pulls.listReviews, {
owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number
});
for (const r of reviews) {
if (await isMaintainer(r.user.login, r.author_association)) {
const d = new Date(r.submitted_at || r.updated_at);
if (d > lastActivity) lastActivity = d;
}
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number
});
for (const c of comments) {
if (await isMaintainer(c.user.login, c.author_association)) {
const d = new Date(c.updated_at);
if (d > lastActivity) lastActivity = d;
}
}
} catch (e) {}
if (lastActivity < thirtyDaysAgo) {
const labels = pr.labels.map(l => l.name.toLowerCase());
const isProtected = labels.includes('help wanted') || labels.includes('🔒 maintainer only');
if (isProtected) {
core.info(`PR #${pr.number} is stale but has a protected label. Skipping closure.`);
continue;
}
core.info(`PR #${pr.number} is stale (no maintainer activity for 30+ days). Closing.`);
if (!dryRun) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: "Hi there! Thank you for your contribution. To keep our backlog manageable, we are closing pull requests that haven't seen maintainer activity for 30 days. If you're still working on this, please let us know!"
});
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
state: 'closed'
});
}
}
}
}
@@ -19,6 +19,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5' # ratchet:actions/checkout@v4
with:
persist-credentials: false
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -41,6 +43,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5' # ratchet:actions/checkout@v4
with:
persist-credentials: false
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
+2
View File
@@ -17,6 +17,8 @@ jobs:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Link Checker'
id: 'lychee'
+2
View File
@@ -16,6 +16,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
-33
View File
@@ -1,33 +0,0 @@
name: 'No Response'
# Run as a daily cron at 1:45 AM
on:
schedule:
- cron: '45 1 * * *'
workflow_dispatch:
jobs:
no-response:
runs-on: 'ubuntu-latest'
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
permissions:
issues: 'write'
pull-requests: 'write'
concurrency:
group: '${{ github.workflow }}-no-response'
cancel-in-progress: true
steps:
- uses: 'actions/stale@5bef64f19d7facfb25b37b414482c7164d639639' # ratchet:actions/stale@v9
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
days-before-stale: -1
days-before-close: 14
stale-issue-label: 'status/need-information'
close-issue-message: >-
This issue was marked as needing more information and has not received a response in 14 days.
Closing it for now. If you still face this problem, feel free to reopen with more details. Thank you!
stale-pr-label: 'status/need-information'
close-pr-message: >-
This pull request was marked as needing more information and has had no updates in 14 days.
Closing it for now. You are welcome to reopen with the required info. Thanks for contributing!
+2
View File
@@ -16,6 +16,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5
with:
persist-credentials: false
- name: 'Set up Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -1,133 +0,0 @@
name: '🏷️ PR Contribution Guidelines Notifier'
on:
pull_request:
types:
- 'opened'
jobs:
notify-process-change:
runs-on: 'ubuntu-latest'
if: |-
github.repository == 'google-gemini/gemini-cli' || github.repository == 'google-gemini/maintainers-gemini-cli'
permissions:
pull-requests: 'write'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
env:
APP_ID: '${{ secrets.APP_ID }}'
if: |-
${{ env.APP_ID != '' }}
uses: 'actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ secrets.APP_ID }}'
private-key: '${{ secrets.PRIVATE_KEY }}'
- name: 'Check membership and post comment'
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |-
const org = context.repo.owner;
const repo = context.repo.repo;
const username = context.payload.pull_request.user.login;
const pr_number = context.payload.pull_request.number;
// 1. Check if the PR author is a maintainer
// Check team membership (most reliable for private org members)
let isTeamMember = false;
const teams = ['gemini-cli-maintainers', 'gemini-cli-askmode-approvers', 'gemini-cli-docs'];
for (const team_slug of teams) {
try {
const members = await github.paginate(github.rest.teams.listMembersInOrg, {
org: org,
team_slug: team_slug
});
if (members.some(m => m.login.toLowerCase() === username.toLowerCase())) {
isTeamMember = true;
core.info(`${username} is a member of ${team_slug}. No notification needed.`);
break;
}
} catch (e) {
core.warning(`Failed to fetch team members from ${team_slug}: ${e.message}`);
}
}
if (isTeamMember) return;
// Check author_association from webhook payload
const authorAssociation = context.payload.pull_request.author_association;
const isRepoMaintainer = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(authorAssociation);
if (isRepoMaintainer) {
core.info(`${username} is a maintainer (author_association: ${authorAssociation}). No notification needed.`);
return;
}
// Check if author is a Googler
const isGoogler = async (login) => {
try {
const orgs = ['googlers', 'google'];
for (const org of orgs) {
try {
await github.rest.orgs.checkMembershipForUser({
org: org,
username: login
});
return true;
} catch (e) {
if (e.status !== 404) throw e;
}
}
} catch (e) {
core.warning(`Failed to check org membership for ${login}: ${e.message}`);
}
return false;
};
if (await isGoogler(username)) {
core.info(`${username} is a Googler. No notification needed.`);
return;
}
// 2. Check if the PR is already associated with an issue
const query = `
query($owner:String!, $repo:String!, $number:Int!) {
repository(owner:$owner, name:$repo) {
pullRequest(number:$number) {
closingIssuesReferences(first: 1) {
totalCount
}
}
}
}
`;
const variables = { owner: org, repo: repo, number: pr_number };
const result = await github.graphql(query, variables);
const issueCount = result.repository.pullRequest.closingIssuesReferences.totalCount;
if (issueCount > 0) {
core.info(`PR #${pr_number} is already associated with an issue. No notification needed.`);
return;
}
// 3. Post the notification comment
core.info(`${username} is not a maintainer and PR #${pr_number} has no linked issue. Posting notification.`);
const comment = `
Hi @${username}, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.
We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: [Improving Our Contribution Process & Introducing New Guidelines](https://github.com/google-gemini/gemini-cli/discussions/16706).
Key Update: Starting **January 26, 2026**, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.
Thank you for your understanding and for being a part of our community!
`.trim().replace(/^[ ]+/gm, '');
await github.rest.issues.createComment({
owner: org,
repo: repo,
issue_number: pr_number,
body: comment
});
@@ -0,0 +1,107 @@
name: 'PR Size Labeler (Batch)'
on:
workflow_dispatch:
inputs:
process_all:
description: 'Process all PRs (open and closed) or open only'
required: true
default: 'false'
type: 'choice'
options:
- 'true'
- 'false'
limit:
description: 'Max number of PRs to fetch and check'
required: true
default: '100'
type: 'string'
permissions:
pull-requests: 'write'
jobs:
batch-label:
runs-on: 'ubuntu-latest'
steps:
- name: 'Batch label PRs'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
GH_REPO: '${{ github.repository }}'
run: |
# Determine the state filter
STATE="open"
if [ "${{ github.event.inputs.process_all }}" = "true" ]; then
STATE="all"
fi
LIMIT="${{ github.event.inputs.limit }}"
echo "Batch labeling up to $LIMIT $STATE PRs..."
# 1. Ensure standard premium size labels exist in the repository (self-healing)
gh label create "size/XS" --color "7ee081" --description "XS: <10 lines changed" 2>/dev/null || true
gh label create "size/S" --color "a6d49f" --description "S: 10-49 lines changed" 2>/dev/null || true
gh label create "size/M" --color "f7d070" --description "M: 50-249 lines changed" 2>/dev/null || true
gh label create "size/L" --color "f48c06" --description "L: 250-999 lines changed" 2>/dev/null || true
gh label create "size/XL" --color "dc2f02" --description "XL: >=1000 lines changed" 2>/dev/null || true
# 2. Query PR list with all required fields in ONE call to prevent N+1 queries
PR_LIST=$(gh pr list --state "$STATE" --limit "$LIMIT" --json number,additions,deletions,labels)
if [ -z "$PR_LIST" ] || [ "$PR_LIST" = "[]" ]; then
echo "️ No PRs found matching the criteria."
exit 0
fi
# Parse and iterate over PRs
UPDATED_COUNT=0
SKIPPED_COUNT=0
echo "$PR_LIST" | jq -c '.[]' | while read -r PR_JSON; do
PR_NUMBER=$(echo "$PR_JSON" | jq '.number')
ADDITIONS=$(echo "$PR_JSON" | jq '.additions')
DELETIONS=$(echo "$PR_JSON" | jq '.deletions')
TOTAL=$((ADDITIONS + DELETIONS))
# Calculate target size
if [ $TOTAL -lt 10 ]; then
SIZE="size/XS"
elif [ $TOTAL -lt 50 ]; then
SIZE="size/S"
elif [ $TOTAL -lt 250 ]; then
SIZE="size/M"
elif [ $TOTAL -lt 1000 ]; then
SIZE="size/L"
else
SIZE="size/XL"
fi
# Inspect existing labels to detect discrepancies
EXISTING_LABELS=$(echo "$PR_JSON" | jq -r '.labels[].name' 2>/dev/null || echo "")
LABELS_TO_REMOVE=()
for L in size/XS size/S size/M size/L size/XL; do
if echo "$EXISTING_LABELS" | grep -Fq "$L" && [ "$L" != "$SIZE" ]; then
LABELS_TO_REMOVE+=("--remove-label" "$L")
fi
done
LABEL_TO_ADD=()
if ! echo "$EXISTING_LABELS" | grep -Fq "$SIZE"; then
LABEL_TO_ADD+=("--add-label" "$SIZE")
fi
# Update labels if there's a difference
if [ ${#LABELS_TO_REMOVE[@]} -gt 0 ] || [ ${#LABEL_TO_ADD[@]} -gt 0 ]; then
echo "🔄 PR #$PR_NUMBER (+$ADDITIONS/-$DELETIONS = $TOTAL lines): updating size to $SIZE"
gh pr edit "$PR_NUMBER" "${LABELS_TO_REMOVE[@]}" "${LABEL_TO_ADD[@]}" 2>/dev/null || true
UPDATED_COUNT=$((UPDATED_COUNT + 1))
else
echo "✅ PR #$PR_NUMBER (+$ADDITIONS/-$DELETIONS = $TOTAL lines): already has correct label ($SIZE). Skipping."
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
fi
done
echo "============================================"
echo "🎉 Batch run completed!"
echo "Skipped (already correct): $SKIPPED_COUNT"
echo "Updated: $UPDATED_COUNT"
+120
View File
@@ -0,0 +1,120 @@
name: 'PR Size Labeler'
on:
pull_request_target:
types: ['opened', 'synchronize', 'reopened']
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to label manually (for workflow_dispatch)'
required: false
type: 'string'
permissions:
pull-requests: 'write'
issues: 'write'
jobs:
size-label:
runs-on: 'ubuntu-latest'
steps:
- name: 'Run size labeler'
env:
GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
GH_REPO: '${{ github.repository }}'
run: |
# Determine the target PR number
if [ -n "${{ github.event.pull_request.number }}" ]; then
PR_NUMBER="${{ github.event.pull_request.number }}"
elif [ -n "${{ github.event.inputs.pr_number }}" ]; then
PR_NUMBER="${{ github.event.inputs.pr_number }}"
else
echo "❌ Error: No PR number provided."
exit 1
fi
echo "Checking PR #$PR_NUMBER..."
# 1. Ensure standard premium size labels exist in the repository (self-healing)
# size/XS: Light green (#7ee081)
# size/S: Yellow-green (#a6d49f)
# size/M: Amber/Yellow (#f7d070)
# size/L: Orange (#f48c06)
# size/XL: Red (#dc2f02)
gh label create "size/XS" --color "7ee081" --description "XS: <10 lines changed" 2>/dev/null || true
gh label create "size/S" --color "a6d49f" --description "S: 10-49 lines changed" 2>/dev/null || true
gh label create "size/M" --color "f7d070" --description "M: 50-249 lines changed" 2>/dev/null || true
gh label create "size/L" --color "f48c06" --description "L: 250-999 lines changed" 2>/dev/null || true
gh label create "size/XL" --color "dc2f02" --description "XL: >=1000 lines changed" 2>/dev/null || true
# 2. Fetch PR details in a single efficient API call
PR_DATA=$(gh pr view "$PR_NUMBER" --json additions,deletions,changedFiles,labels)
if [ -z "$PR_DATA" ]; then
echo "❌ Error: Could not fetch PR details."
exit 1
fi
ADDITIONS=$(echo "$PR_DATA" | jq '.additions')
DELETIONS=$(echo "$PR_DATA" | jq '.deletions')
CHANGED_FILES=$(echo "$PR_DATA" | jq '.changedFiles')
TOTAL=$((ADDITIONS + DELETIONS))
echo "PR additions: $ADDITIONS, deletions: $DELETIONS, total changes: $TOTAL, files: $CHANGED_FILES"
# 3. Calculate new size label
if [ $TOTAL -lt 10 ]; then
SIZE="size/XS"
elif [ $TOTAL -lt 50 ]; then
SIZE="size/S"
elif [ $TOTAL -lt 250 ]; then
SIZE="size/M"
elif [ $TOTAL -lt 1000 ]; then
SIZE="size/L"
else
SIZE="size/XL"
fi
# 4. Check existing labels and update only if necessary
EXISTING_LABELS=$(echo "$PR_DATA" | jq -r '.labels[].name' 2>/dev/null || echo "")
LABELS_TO_REMOVE=()
for L in size/XS size/S size/M size/L size/XL; do
if echo "$EXISTING_LABELS" | grep -Fq "$L" && [ "$L" != "$SIZE" ]; then
LABELS_TO_REMOVE+=("--remove-label" "$L")
fi
done
LABEL_TO_ADD=()
if ! echo "$EXISTING_LABELS" | grep -Fq "$SIZE"; then
LABEL_TO_ADD+=("--add-label" "$SIZE")
fi
# Perform a single, highly atomic edit call if changes are needed
if [ ${#LABELS_TO_REMOVE[@]} -gt 0 ] || [ ${#LABEL_TO_ADD[@]} -gt 0 ]; then
echo "Updating labels: removing ${LABELS_TO_REMOVE[*]}, adding $SIZE"
gh pr edit "$PR_NUMBER" "${LABELS_TO_REMOVE[@]}" "${LABEL_TO_ADD[@]}"
else
echo "✅ PR #$PR_NUMBER already has the correct size label ($SIZE)."
fi
# 5. Premium, anti-spam comment logic (updates previous comment to keep thread clean)
COMMENT="📊 PR Size: **$SIZE**
- Lines changed: **$TOTAL**
- Additions: +$ADDITIONS
- Deletions: -$DELETIONS
- Files changed: $CHANGED_FILES"
# Find any existing size labeler comment by the github-actions bot
echo "Searching for existing size comment..."
COMMENT_ID=$(gh api "repos/${{ github.repository }}/issues/$PR_NUMBER/comments" \
--jq '.[] | select(.user.login == "github-actions[bot]" and (.body | startswith("📊 PR Size:"))) | .id' | head -n 1)
if [ -n "$COMMENT_ID" ]; then
echo "Updating existing comment (ID: $COMMENT_ID)..."
gh api "repos/${{ github.repository }}/issues/comments/$COMMENT_ID" -X PATCH -f body="$COMMENT" > /dev/null
else
echo "Creating new comment..."
gh pr comment "$PR_NUMBER" --body "$COMMENT" > /dev/null
fi
echo "🎉 PR size labeling completed successfully."
@@ -44,6 +44,7 @@ jobs:
with:
ref: '${{ github.ref }}'
fetch-depth: 0
persist-credentials: false
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020'
+14
View File
@@ -46,8 +46,15 @@ on:
default: 'prod'
jobs:
build-mac:
if: "github.repository == 'google-gemini/gemini-cli'"
uses: './.github/workflows/build-unsigned-mac-binaries.yml'
with:
ref: '${{ github.event.inputs.ref }}'
release:
if: "github.repository == 'google-gemini/gemini-cli'"
needs: ['build-mac']
runs-on: 'ubuntu-latest'
environment: "${{ github.event.inputs.environment || 'prod' }}"
permissions:
@@ -58,11 +65,13 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
fetch-depth: 0
- name: 'Checkout Release Code'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
path: 'release'
fetch-depth: 0
@@ -83,6 +92,11 @@ jobs:
working-directory: './release'
run: 'npm ci'
- name: 'Download macOS Binaries'
uses: './.github/actions/download-mac-binaries'
with:
path: 'release/dist'
- name: 'Prepare Release Info'
id: 'release_info'
working-directory: './release'
+21 -7
View File
@@ -30,9 +30,16 @@ on:
default: 'prod'
jobs:
build-mac:
if: "github.repository == 'google-gemini/gemini-cli'"
uses: './.github/workflows/build-unsigned-mac-binaries.yml'
with:
ref: '${{ github.event.inputs.ref }}'
release:
if: "github.repository == 'google-gemini/gemini-cli'"
environment: "${{ github.event.inputs.environment || 'prod' }}"
needs: ['build-mac']
environment: "${{ github.event_name == 'schedule' && 'internal' || github.event.inputs.environment || 'prod' }}"
runs-on: 'ubuntu-latest'
permissions:
contents: 'write'
@@ -43,11 +50,13 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
fetch-depth: 0
- name: 'Checkout Release Code'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
path: 'release'
fetch-depth: 0
@@ -62,6 +71,11 @@ jobs:
working-directory: './release'
run: 'npm ci'
- name: 'Download macOS Binaries'
uses: './.github/actions/download-mac-binaries'
with:
path: 'release/dist'
- name: 'Print Inputs'
shell: 'bash'
env:
@@ -131,12 +145,12 @@ jobs:
skip-branch-cleanup: true
force-skip-tests: "${{ github.event_name != 'schedule' && github.event.inputs.force_skip_tests == 'true' }}"
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
npm-registry-publish-url: '${{ vars.NPM_REGISTRY_PUBLISH_URL }}'
npm-registry-url: '${{ vars.NPM_REGISTRY_URL }}'
npm-registry-scope: '${{ vars.NPM_REGISTRY_SCOPE }}'
cli-package-name: '${{ vars.CLI_PACKAGE_NAME }}'
core-package-name: '${{ vars.CORE_PACKAGE_NAME }}'
a2a-package-name: '${{ vars.A2A_PACKAGE_NAME }}'
npm-registry-publish-url: "${{ vars.NPM_REGISTRY_PUBLISH_URL || 'https://registry.npmjs.org/' }}"
npm-registry-url: "${{ vars.NPM_REGISTRY_URL || 'https://registry.npmjs.org/' }}"
npm-registry-scope: "${{ vars.NPM_REGISTRY_SCOPE || '@google' }}"
cli-package-name: "${{ vars.CLI_PACKAGE_NAME || '@google/gemini-cli' }}"
core-package-name: "${{ vars.CORE_PACKAGE_NAME || '@google/gemini-cli-core' }}"
a2a-package-name: "${{ vars.A2A_PACKAGE_NAME || '@google/gemini-cli-a2a-server' }}"
- name: 'Create and Merge Pull Request'
if: "github.event.inputs.environment != 'dev'"
+4
View File
@@ -31,6 +31,7 @@ jobs:
- name: 'Checkout repository'
uses: 'actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5' # ratchet:actions/checkout@v4
with:
persist-credentials: false
# The user-level skills need to be available to the workflow
fetch-depth: 0
ref: 'main'
@@ -70,7 +71,10 @@ jobs:
- name: 'Generate Changelog with Gemini'
if: "steps.validate_version.outputs.CONTINUE == 'true'"
uses: 'google-github-actions/run-gemini-cli@a3bf79042542528e91937b3a3a6fbc4967ee3c31' # ratchet:google-github-actions/run-gemini-cli@v0
env:
GEMINI_CLI_TRUST_WORKSPACE: true
with:
upload_artifacts: 'true'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
prompt: |
Activate the 'docs-changelog' skill.
@@ -17,6 +17,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
fetch-depth: 1
- name: 'Slash Command Dispatch'
@@ -54,6 +54,7 @@ jobs:
with:
ref: '${{ github.event.inputs.ref }}'
fetch-depth: 0
persist-credentials: false
- name: 'Setup Node.js'
uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4
@@ -64,6 +64,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: "${{ github.event.inputs.workflow_ref || 'main' }}"
fetch-depth: 1
@@ -53,12 +53,14 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
fetch-depth: 0
fetch-tags: true
- name: 'Checkout Release Code'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.release_ref }}'
path: 'release'
fetch-depth: 0
+28 -3
View File
@@ -55,6 +55,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
fetch-depth: 0
fetch-tags: true
@@ -171,11 +172,13 @@ jobs:
- name: 'Checkout Ref'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
- name: 'Checkout correct SHA'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ matrix.sha }}'
path: 'release'
fetch-depth: 0
@@ -197,9 +200,15 @@ jobs:
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
working-directory: './release'
build-mac:
if: "github.repository == 'google-gemini/gemini-cli'"
uses: './.github/workflows/build-unsigned-mac-binaries.yml'
with:
ref: '${{ github.event.inputs.ref }}'
publish-preview:
name: 'Publish preview'
needs: ['calculate-versions', 'test']
needs: ['calculate-versions', 'test', 'build-mac']
runs-on: 'ubuntu-latest'
environment: "${{ github.event.inputs.environment || 'prod' }}"
permissions:
@@ -210,11 +219,13 @@ jobs:
- name: 'Checkout Ref'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
- name: 'Checkout correct SHA'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ needs.calculate-versions.outputs.PREVIEW_SHA }}'
path: 'release'
fetch-depth: 0
@@ -229,6 +240,11 @@ jobs:
working-directory: './release'
run: 'npm ci'
- name: 'Download macOS Binaries'
uses: './.github/actions/download-mac-binaries'
with:
path: 'release/dist'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
with:
@@ -266,7 +282,7 @@ jobs:
publish-stable:
name: 'Publish stable'
needs: ['calculate-versions', 'test', 'publish-preview']
needs: ['calculate-versions', 'test', 'publish-preview', 'build-mac']
runs-on: 'ubuntu-latest'
environment: "${{ github.event.inputs.environment || 'prod' }}"
permissions:
@@ -277,11 +293,13 @@ jobs:
- name: 'Checkout Ref'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
- name: 'Checkout correct SHA'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ needs.calculate-versions.outputs.STABLE_SHA }}'
path: 'release'
fetch-depth: 0
@@ -296,6 +314,11 @@ jobs:
working-directory: './release'
run: 'npm ci'
- name: 'Download macOS Binaries'
uses: './.github/actions/download-mac-binaries'
with:
path: 'release/dist'
- name: 'Publish Release'
uses: './.github/actions/publish-release'
with:
@@ -344,6 +367,7 @@ jobs:
- name: 'Checkout Ref'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
- name: 'Setup Node.js'
@@ -379,6 +403,7 @@ jobs:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
DRY_RUN: '${{ github.event.inputs.dry_run }}'
NEEDS_CALCULATE_VERSIONS_OUTPUTS_NEXT_NIGHTLY_VERSION: '${{ needs.calculate-versions.outputs.NEXT_NIGHTLY_VERSION }}'
GIT_PUSH_TOKEN: '${{ secrets.GEMINI_CLI_ROBOT_GITHUB_PAT }}'
run: |-
git add package.json packages/*/package.json
if [ -f package-lock.json ]; then
@@ -387,7 +412,7 @@ jobs:
git commit -m "chore(release): bump version to ${NEEDS_CALCULATE_VERSIONS_OUTPUTS_NEXT_NIGHTLY_VERSION}"
if [[ "${DRY_RUN}" == "false" ]]; then
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}"
git push "https://x-access-token:${GIT_PUSH_TOKEN}@github.com/${{ github.repository }}.git" "HEAD:${BRANCH_NAME}" --follow-tags
else
echo "Dry run enabled. Skipping push."
fi
+2 -1
View File
@@ -52,6 +52,7 @@ jobs:
- name: 'Checkout repository'
uses: 'actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955' # ratchet:actions/checkout@v4
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref }}'
fetch-depth: 0
@@ -192,7 +193,7 @@ jobs:
run: |
echo "ROLLBACK_TAG=$ROLLBACK_TAG_NAME" >> "$GITHUB_OUTPUT"
git tag "$ROLLBACK_TAG_NAME" "${ORIGIN_HASH}"
git push origin --tags
git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" --tags
- name: 'Verify Rollback Tag Added'
if: "${{ github.event.inputs.dry-run == 'false' }}"
+1
View File
@@ -26,6 +26,7 @@ jobs:
- name: 'Checkout'
uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0
- name: 'Push'
+1
View File
@@ -32,6 +32,7 @@ jobs:
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0
persist-credentials: false
- name: 'Install Dependencies'
run: 'npm ci'
- name: 'Build bundle'
-44
View File
@@ -1,44 +0,0 @@
name: 'Mark stale issues and pull requests'
# Run as a daily cron at 1:30 AM
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:
jobs:
stale:
strategy:
fail-fast: false
matrix:
runner:
- 'ubuntu-latest' # GitHub-hosted
runs-on: '${{ matrix.runner }}'
if: |-
${{ github.repository == 'google-gemini/gemini-cli' }}
permissions:
issues: 'write'
pull-requests: 'write'
concurrency:
group: '${{ github.workflow }}-stale'
cancel-in-progress: true
steps:
- uses: 'actions/stale@5bef64f19d7facfb25b37b414482c7164d639639' # ratchet:actions/stale@v9
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
stale-issue-message: >-
This issue has been automatically marked as stale due to 60 days of inactivity.
It will be closed in 14 days if no further activity occurs.
stale-pr-message: >-
This pull request has been automatically marked as stale due to 60 days of inactivity.
It will be closed in 14 days if no further activity occurs.
close-issue-message: >-
This issue has been closed due to 14 additional days of inactivity after being marked as stale.
If you believe this is still relevant, feel free to comment or reopen the issue. Thank you!
close-pr-message: >-
This pull request has been closed due to 14 additional days of inactivity after being marked as stale.
If this is still relevant, you are welcome to reopen or leave a comment. Thanks for contributing!
days-before-stale: 60
days-before-close: 14
exempt-issue-labels: 'pinned,security,🔒 maintainer only,help wanted,🗓️ Public Roadmap'
exempt-pr-labels: 'pinned,security,🔒 maintainer only,help wanted,🗓️ Public Roadmap'
+2
View File
@@ -34,6 +34,8 @@ jobs:
steps:
- name: 'Checkout'
uses: 'actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5' # ratchet:actions/checkout@v4
with:
persist-credentials: false
- name: 'Optimize Windows Performance'
if: "matrix.os == 'windows-latest'"
+2
View File
@@ -44,6 +44,8 @@ jobs:
shell: 'bash'
run: 'echo "${{ toJSON(vars) }}"'
- uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8'
with:
persist-credentials: false
- name: 'Verify release'
uses: './.github/actions/verify-release'
with:
+1 -1
View File
@@ -1 +1 @@
@google:registry=https://wombat-dressing-room.appspot.com
@google:registry=https://wombat-dressing-room.appspot.com/
+1
View File
@@ -23,3 +23,4 @@ Thumbs.db
**/SKILL.md
packages/sdk/test-data/*.json
*.mdx
packages/vscode-ide-companion/NOTICES.txt
+5 -1
View File
@@ -43,9 +43,13 @@
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"name": "CLI: Run Current File",
"runtimeExecutable": "node",
"runtimeArgs": ["--import", "tsx"],
"skipFiles": ["<node_internals>/**"],
"program": "${file}",
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"outFiles": ["${workspaceFolder}/**/*.js"]
},
{
+44 -3
View File
@@ -1,3 +1,44 @@
# ---- Stage 1: Builder ----
FROM docker.io/library/node:20-slim AS builder
# Install git (needed by generate-git-commit-info.js script)
RUN apt-get update && apt-get install -y --no-install-recommends git \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /build
# Copy only package.json files first for better layer caching
# Dependencies only re-install when package files change, not source files
COPY package*.json ./
COPY packages/cli/package*.json ./packages/cli/
COPY packages/core/package*.json ./packages/core/
COPY packages/vscode-ide-companion/package*.json ./packages/vscode-ide-companion/
COPY packages/vscode-ide-companion/scripts/ ./packages/vscode-ide-companion/scripts/
COPY packages/devtools/package*.json ./packages/devtools/
COPY packages/sdk/package*.json ./packages/sdk/
COPY packages/test-utils/package*.json ./packages/test-utils/
COPY packages/a2a-server/package*.json ./packages/a2a-server/
# Use npm ci for consistent, reliable builds (respects package-lock.json)
RUN HUSKY=0 npm ci --ignore-scripts
# Now copy the rest of the source (after install for better caching)
COPY packages/ ./packages/
COPY tsconfig*.json ./
COPY eslint.config.js ./
COPY scripts/ ./scripts/
COPY esbuild.config.js ./
# Pass git commit hash as build arg instead of copying entire .git directory
ARG GIT_COMMIT=unknown
ENV GIT_COMMIT=$GIT_COMMIT
# Build and pack artifacts
RUN HUSKY=0 npm run build && \
npm pack -w packages/core --pack-destination packages/core/dist/ && \
npm pack -w packages/cli --pack-destination packages/cli/dist/
# ---- Stage 2: Runtime ----
FROM docker.io/library/node:20-slim
ARG SANDBOX_NAME="gemini-cli-sandbox"
@@ -40,8 +81,8 @@ ENV PATH=$PATH:/usr/local/share/npm-global/bin
USER node
# install gemini-cli and clean up
COPY packages/cli/dist/google-gemini-cli-*.tgz /tmp/gemini-cli.tgz
COPY packages/core/dist/google-gemini-cli-core-*.tgz /tmp/gemini-core.tgz
COPY --chown=node:node packages/cli/dist/google-gemini-cli-*.tgz /tmp/gemini-cli.tgz
COPY --chown=node:node packages/core/dist/google-gemini-cli-core-*.tgz /tmp/gemini-core.tgz
RUN npm install -g /tmp/gemini-core.tgz \
&& npm install -g /tmp/gemini-cli.tgz \
&& node -e "const fs=require('node:fs'); JSON.parse(fs.readFileSync('/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli/package.json','utf8')); JSON.parse(fs.readFileSync('/usr/local/share/npm-global/lib/node_modules/@google/gemini-cli-core/package.json','utf8'));" \
@@ -50,4 +91,4 @@ RUN npm install -g /tmp/gemini-core.tgz \
&& rm -f /tmp/gemini-{cli,core}.tgz
# default entrypoint when none specified
CMD ["gemini"]
ENTRYPOINT ["/usr/local/share/npm-global/bin/gemini"]
+20
View File
@@ -143,6 +143,16 @@ Integrate Gemini CLI directly into your GitHub workflows with
- **Custom Workflows**: Build automated, scheduled and on-demand workflows
tailored to your team's needs
<!-- prettier-ignore -->
> [!WARNING]
> **Security best practice for public repositories:** Never set
> `GEMINI_CLI_TRUST_WORKSPACE=true` or use `--skip-trust` in CI/CD workflows
> that process untrusted public inputs (like issue titles/bodies or PR comments).
> Doing so can expose dynamically generated runner secrets (such as GCP OIDC
> service account credentials) to prompt injection attacks. See the
> [Trusted Folders documentation](https://www.geminicli.com/docs/cli/trusted-folders)
> for more information.
## 🔐 Authentication Options
Choose the authentication method that best fits your needs:
@@ -395,6 +405,16 @@ for removal instructions.
[Terms & Privacy](https://www.geminicli.com/docs/resources/tos-privacy)
- **Security**: [Security Policy](SECURITY.md)
<p align="left">
<a href="https://www.star-history.com/google-gemini/gemini-cli">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/badge?repo=google-gemini/gemini-cli&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/badge?repo=google-gemini/gemini-cli" />
<img alt="Star History Rank" src="https://api.star-history.com/badge?repo=google-gemini/gemini-cli" />
</picture>
</a>
</p>
---
<p align="center">
+113
View File
@@ -18,6 +18,119 @@ on GitHub.
| [Preview](preview.md) | Experimental features ready for early feedback. |
| [Stable](latest.md) | Stable, recommended for general use. |
## Announcements: v0.45.0 - 2026-06-03
- **Context Simplification:** Completed major architectural work to simplify the
`ContextManager`, improving system robustness and performance
([#27345](https://github.com/google-gemini/gemini-cli/pull/27345) by
@joshualitt).
- **A2A Usage Metadata:** Exposed critical usage metadata in the Agent-to-Agent
(A2A) protocol for better resource tracking
([#27288](https://github.com/google-gemini/gemini-cli/pull/27288) by
@jvargassanchez-dot).
- **Reliability Fixes:** Addressed Termux relaunch loops, PTY resize errors, and
forced sequential execution for topic updates
([#27110](https://github.com/google-gemini/gemini-cli/pull/27110) by @saymanq,
[#27357](https://github.com/google-gemini/gemini-cli/pull/27357) by
@jvargassanchez-dot,
[#27461](https://github.com/google-gemini/gemini-cli/pull/27461) by
@scidomino).
## Announcements: v0.44.0 - 2026-05-27
- **Unified Auto Mode:** Streamlined the automation experience by merging
specialized Auto modes into a single, unified mode
([#26714](https://github.com/google-gemini/gemini-cli/pull/26714) by
@DavidAPierce).
- **New Editor Integrations:** Added native support for Sublime Text and Emacs
Client ([#21090](https://github.com/google-gemini/gemini-cli/pull/21090) by
@alberti42).
- **Enhanced TUI Testing:** Introduced `agent-tui` and `tui-tester` skills for
programmatic testing and automation of terminal UI applications
([#27121](https://github.com/google-gemini/gemini-cli/pull/27121) by
@adamfweidman).
## Announcements: v0.43.0 - 2026-05-22
- **Surgical Code Edits:** Steered Gemini models to prefer the `edit` tool for
surgical modifications, improving speed and precision
([#26480](https://github.com/google-gemini/gemini-cli/pull/26480) by
@aishaneeshah).
- **Session Export and Import:** Added the ability to export sessions to files
and import them via a new flag, facilitating session portability
([#26514](https://github.com/google-gemini/gemini-cli/pull/26514) by
@cocosheng-g).
- **Adaptive Token Estimation:** Introduced an adaptive token calculator for
more accurate content size estimation, enhancing context management efficiency
([#26888](https://github.com/google-gemini/gemini-cli/pull/26888) by
@joshualitt).
## Announcements: v0.42.0 - 2026-05-12
- **Auto Memory Inbox:** Introduced a new inbox flow for Auto Memory with a
canonical-patch contract for seamless skill management
([#26338](https://github.com/google-gemini/gemini-cli/pull/26338) by
@SandyTao520).
- **Gemma 4 by Default:** Enabled Gemma 4 models by default via the Gemini API
for all users
([#26307](https://github.com/google-gemini/gemini-cli/pull/26307) by
@Abhijit-2592).
- **Voice Mode Enhancements:** Added wave animations and privacy/compliance UX
warnings for the Gemini Live backend
([#26284](https://github.com/google-gemini/gemini-cli/pull/26284) by
@devr0306, [#26454](https://github.com/google-gemini/gemini-cli/pull/26454) by
@cocosheng-g).
## Announcements: v0.41.0 - 2026-05-05
- **Real-time Voice Mode:** Implemented real-time voice mode with cloud and
local backends
([#24174](https://github.com/google-gemini/gemini-cli/pull/24174) by
@Abhijit-2592).
- **Secure Environment Loading:** Enforced workspace trust and secured .env
loading in headless mode
([#25814](https://github.com/google-gemini/gemini-cli/pull/25814) by
@ehedlund).
- **Advanced Shell Validation:** Enhanced shell command validation and added
core tools allowlist for improved security
([#25720](https://github.com/google-gemini/gemini-cli/pull/25720) by @galz10).
## Announcements: v0.40.0 - 2026-04-28
- **Offline Search and Themes:** Bundled ripgrep for offline search support and
added GitHub-style colorblind themes
([#25342](https://github.com/google-gemini/gemini-cli/pull/25342) by
@scidomino, [#15504](https://github.com/google-gemini/gemini-cli/pull/15504)
by @Z1xus).
- **Advanced Resource and Memory Management:** Introduced MCP resource tools and
transitioned to a prompt-driven, four-tier memory management system
([#25395](https://github.com/google-gemini/gemini-cli/pull/25395) by
@ruomengz, [#25716](https://github.com/google-gemini/gemini-cli/pull/25716) by
@SandyTao520).
- **UX and Local Models:** Enabled topic update narrations by default and
streamlined Gemma local model setup with `gemini gemma`
([#25586](https://github.com/google-gemini/gemini-cli/pull/25586) by
@gundermanc, [#25498](https://github.com/google-gemini/gemini-cli/pull/25498)
by @Samee24).
## Announcements: v0.39.0 - 2026-04-23
- **Skill Management:** Added a new `/memory` inbox command for reviewing and
patching skills extracted during sessions
([#24544](https://github.com/google-gemini/gemini-cli/pull/24544) by
@SandyTao520, [#25148](https://github.com/google-gemini/gemini-cli/pull/25148)
by @SandyTao520).
- **Improved Transparency:** Plan Mode now requires confirmation for skill
activation and allows plan inspection
([#24946](https://github.com/google-gemini/gemini-cli/pull/24946),
[#25058](https://github.com/google-gemini/gemini-cli/pull/25058) by
@ruomengz).
- **Architecture & Reliability:** Introduced a decoupled `ContextManager`
architecture and resolved several critical memory leaks and PTY exhaustion
issues ([#24752](https://github.com/google-gemini/gemini-cli/pull/24752) by
@joshualitt, [#25079](https://github.com/google-gemini/gemini-cli/pull/25079)
by @spencer426).
## Announcements: v0.38.0 - 2026-04-14
- **Chapters Narrative Flow:** Group agent interactions into "Chapters" based on
+49 -258
View File
@@ -1,6 +1,6 @@
# Latest stable release: v0.38.2
# Latest stable release: v0.45.0
Released: April 17, 2026
Released: June 03, 2026
For most users, our latest stable release is the recommended release. Install
the latest stable version with:
@@ -11,264 +11,55 @@ npm install -g @google/gemini-cli
## Highlights
- **Chapters Narrative Flow:** Introduced tool-based topic grouping ("Chapters")
to provide better session structure and narrative continuity in long-running
tasks.
- **Context Compression Service:** Implemented a dedicated service for advanced
context management, efficiently distilling conversation history to preserve
focus and tokens.
- **Enhanced UI Stability & UX:** Introduced a new "Terminal Buffer" mode to
solve rendering flicker, along with selective topic expansion and improved
tool confirmation layouts.
- **Context-Aware Policy Approvals:** Users can now grant persistent,
context-aware approvals for tools, significantly reducing manual confirmation
overhead for trusted workflows.
- **Background Process Monitoring:** New tools for monitoring and inspecting
background shell processes, providing better visibility into asynchronous
tasks.
- **Context Manager Simplification:** Completed a significant refactoring of the
context management system to improve reliability and architectural clarity.
- **A2A Usage Metadata:** Enhanced the Agent-to-Agent protocol to expose usage
metadata, enabling more transparent resource monitoring.
- **Terminal & PTY Robustness:** Resolved several critical issues related to
terminal interactions, including Termux relaunch loops and PTY resize errors.
- **Routing Optimizations:** Updated default auto-routing and bypassed
classifiers for specific tool responses to prevent orphaned function errors.
- **Tool Execution Control:** Forced the `update_topic` tool to execute
sequentially, ensuring consistent narrative flow in agent interactions.
## What's Changed
- fix(patch): cherry-pick 14b2f35 to release/v0.38.1-pr-24974 to patch version
v0.38.1 and create version 0.38.2 by @gemini-cli-robot in
[#25585](https://github.com/google-gemini/gemini-cli/pull/25585)
- fix(patch): cherry-pick 050c303 to release/v0.38.0-pr-25317 to patch version
v0.38.0 and create version 0.38.1 by @gemini-cli-robot in
[#25466](https://github.com/google-gemini/gemini-cli/pull/25466)
- fix(cli): refresh slash command list after /skills reload by @NTaylorMullen in
[#24454](https://github.com/google-gemini/gemini-cli/pull/24454)
- Update README.md for links. by @g-samroberts in
[#22759](https://github.com/google-gemini/gemini-cli/pull/22759)
- fix(core): ensure complete_task tool calls are recorded in chat history by
@abhipatel12 in
[#24437](https://github.com/google-gemini/gemini-cli/pull/24437)
- feat(policy): explicitly allow web_fetch in plan mode with ask_user by
@Adib234 in [#24456](https://github.com/google-gemini/gemini-cli/pull/24456)
- fix(core): refactor linux sandbox to fix ARG_MAX crashes by @ehedlund in
[#24286](https://github.com/google-gemini/gemini-cli/pull/24286)
- feat(config): add experimental.adk.agentSessionNoninteractiveEnabled setting
by @adamfweidman in
[#24439](https://github.com/google-gemini/gemini-cli/pull/24439)
- Changelog for v0.36.0-preview.8 by @gemini-cli-robot in
[#24453](https://github.com/google-gemini/gemini-cli/pull/24453)
- feat(cli): change default loadingPhrases to 'off' to hide tips by @keithguerin
in [#24342](https://github.com/google-gemini/gemini-cli/pull/24342)
- fix(cli): ensure agent stops when all declinable tools are cancelled by
@NTaylorMullen in
[#24479](https://github.com/google-gemini/gemini-cli/pull/24479)
- fix(core): enhance sandbox usability and fix build error by @galz10 in
[#24460](https://github.com/google-gemini/gemini-cli/pull/24460)
- Terminal Serializer Optimization by @jacob314 in
[#24485](https://github.com/google-gemini/gemini-cli/pull/24485)
- Auto configure memory. by @jacob314 in
[#24474](https://github.com/google-gemini/gemini-cli/pull/24474)
- Unused error variables in catch block are not allowed by @alisa-alisa in
[#24487](https://github.com/google-gemini/gemini-cli/pull/24487)
- feat(core): add background memory service for skill extraction by @SandyTao520
in [#24274](https://github.com/google-gemini/gemini-cli/pull/24274)
- feat: implement high-signal PR regression check for evaluations by
@alisa-alisa in
[#23937](https://github.com/google-gemini/gemini-cli/pull/23937)
- Fix shell output display by @jacob314 in
[#24490](https://github.com/google-gemini/gemini-cli/pull/24490)
- fix(ui): resolve unwanted vertical spacing around various tool output
treatments by @jwhelangoog in
[#24449](https://github.com/google-gemini/gemini-cli/pull/24449)
- revert(cli): bring back input box and footer visibility in copy mode by
@sehoon38 in [#24504](https://github.com/google-gemini/gemini-cli/pull/24504)
- fix(cli): prevent crash in AnsiOutputText when handling non-array data by
@sehoon38 in [#24498](https://github.com/google-gemini/gemini-cli/pull/24498)
- feat(cli): support default values for environment variables by @ruomengz in
[#24469](https://github.com/google-gemini/gemini-cli/pull/24469)
- Implement background process monitoring and inspection tools by @cocosheng-g
in [#23799](https://github.com/google-gemini/gemini-cli/pull/23799)
- docs(browser-agent): update stale browser agent documentation by @gsquared94
in [#24463](https://github.com/google-gemini/gemini-cli/pull/24463)
- fix: enable browser_agent in integration tests and add localhost fixture tests
by @gsquared94 in
[#24523](https://github.com/google-gemini/gemini-cli/pull/24523)
- fix(browser): handle computer-use model detection for analyze_screenshot by
@gsquared94 in
[#24502](https://github.com/google-gemini/gemini-cli/pull/24502)
- feat(core): Land ContextCompressionService by @joshualitt in
[#24483](https://github.com/google-gemini/gemini-cli/pull/24483)
- feat(core): scope subagent workspace directories via AsyncLocalStorage by
@SandyTao520 in
[#24445](https://github.com/google-gemini/gemini-cli/pull/24445)
- Update ink version to 6.6.7 by @jacob314 in
[#24514](https://github.com/google-gemini/gemini-cli/pull/24514)
- fix(acp): handle all InvalidStreamError types gracefully in prompt by @sripasg
in [#24540](https://github.com/google-gemini/gemini-cli/pull/24540)
- Fix crash when vim editor is not found in PATH on Windows by
@Nagajyothi-tammisetti in
[#22423](https://github.com/google-gemini/gemini-cli/pull/22423)
- fix(core): move project memory dir under tmp directory by @SandyTao520 in
[#24542](https://github.com/google-gemini/gemini-cli/pull/24542)
- Enable 'Other' option for yesno question type by @ruomengz in
[#24545](https://github.com/google-gemini/gemini-cli/pull/24545)
- fix(cli): clear stale retry/loading state after cancellation (#21096) by
@Aaxhirrr in [#21960](https://github.com/google-gemini/gemini-cli/pull/21960)
- Changelog for v0.37.0-preview.0 by @gemini-cli-robot in
[#24464](https://github.com/google-gemini/gemini-cli/pull/24464)
- feat(core): implement context-aware persistent policy approvals by @jerop in
[#23257](https://github.com/google-gemini/gemini-cli/pull/23257)
- docs: move agent disabling instructions and update remote agent status by
@jackwotherspoon in
[#24559](https://github.com/google-gemini/gemini-cli/pull/24559)
- feat(cli): migrate nonInteractiveCli to LegacyAgentSession by @adamfweidman in
[#22987](https://github.com/google-gemini/gemini-cli/pull/22987)
- fix(core): unsafe type assertions in Core File System #19712 by
@aniketsaurav18 in
[#19739](https://github.com/google-gemini/gemini-cli/pull/19739)
- fix(ui): hide model quota in /stats and refactor quota display by @danzaharia1
in [#24206](https://github.com/google-gemini/gemini-cli/pull/24206)
- Changelog for v0.36.0 by @gemini-cli-robot in
[#24558](https://github.com/google-gemini/gemini-cli/pull/24558)
- Changelog for v0.37.0-preview.1 by @gemini-cli-robot in
[#24568](https://github.com/google-gemini/gemini-cli/pull/24568)
- docs: add missing .md extensions to internal doc links by @ishaan-arora-1 in
[#24145](https://github.com/google-gemini/gemini-cli/pull/24145)
- fix(ui): fixed table styling by @devr0306 in
[#24565](https://github.com/google-gemini/gemini-cli/pull/24565)
- fix(core): pass includeDirectories to sandbox configuration by @galz10 in
[#24573](https://github.com/google-gemini/gemini-cli/pull/24573)
- feat(ui): enable "TerminalBuffer" mode to solve flicker by @jacob314 in
[#24512](https://github.com/google-gemini/gemini-cli/pull/24512)
- docs: clarify release coordination by @scidomino in
[#24575](https://github.com/google-gemini/gemini-cli/pull/24575)
- fix(core): remove broken PowerShell translation and fix native \_\_write in
Windows sandbox by @scidomino in
[#24571](https://github.com/google-gemini/gemini-cli/pull/24571)
- Add instructions for how to start react in prod and force react to prod mode
by @jacob314 in
[#24590](https://github.com/google-gemini/gemini-cli/pull/24590)
- feat(cli): minimalist sandbox status labels by @galz10 in
[#24582](https://github.com/google-gemini/gemini-cli/pull/24582)
- Feat/browser agent metrics by @kunal-10-cloud in
[#24210](https://github.com/google-gemini/gemini-cli/pull/24210)
- test: fix Windows CI execution and resolve exposed platform failures by
@ehedlund in [#24476](https://github.com/google-gemini/gemini-cli/pull/24476)
- feat(core,cli): prioritize summary for topics (#24608) by @Abhijit-2592 in
[#24609](https://github.com/google-gemini/gemini-cli/pull/24609)
- show color by @jacob314 in
[#24613](https://github.com/google-gemini/gemini-cli/pull/24613)
- feat(cli): enable compact tool output by default (#24509) by @jwhelangoog in
[#24510](https://github.com/google-gemini/gemini-cli/pull/24510)
- fix(core): inject skill system instructions into subagent prompts if activated
by @abhipatel12 in
[#24620](https://github.com/google-gemini/gemini-cli/pull/24620)
- fix(core): improve windows sandbox reliability and fix integration tests by
@ehedlund in [#24480](https://github.com/google-gemini/gemini-cli/pull/24480)
- fix(core): ensure sandbox approvals are correctly persisted and matched for
proactive expansions by @galz10 in
[#24577](https://github.com/google-gemini/gemini-cli/pull/24577)
- feat(cli) Scrollbar for input prompt by @jacob314 in
[#21992](https://github.com/google-gemini/gemini-cli/pull/21992)
- Do not run pr-eval workflow when no steering changes detected by @alisa-alisa
in [#24621](https://github.com/google-gemini/gemini-cli/pull/24621)
- Fix restoration of topic headers. by @gundermanc in
[#24650](https://github.com/google-gemini/gemini-cli/pull/24650)
- feat(core): discourage update topic tool for simple tasks by @Samee24 in
[#24640](https://github.com/google-gemini/gemini-cli/pull/24640)
- fix(core): ensure global temp directory is always in sandbox allowed paths by
@galz10 in [#24638](https://github.com/google-gemini/gemini-cli/pull/24638)
- fix(core): detect uninitialized lines by @jacob314 in
[#24646](https://github.com/google-gemini/gemini-cli/pull/24646)
- docs: update sandboxing documentation and toolSandboxing settings by @galz10
in [#24655](https://github.com/google-gemini/gemini-cli/pull/24655)
- feat(cli): enhance tool confirmation UI and selection layout by @galz10 in
[#24376](https://github.com/google-gemini/gemini-cli/pull/24376)
- feat(acp): add support for `/about` command by @sripasg in
[#24649](https://github.com/google-gemini/gemini-cli/pull/24649)
- feat(cli): add role specific metrics to /stats by @cynthialong0-0 in
[#24659](https://github.com/google-gemini/gemini-cli/pull/24659)
- split context by @jacob314 in
[#24623](https://github.com/google-gemini/gemini-cli/pull/24623)
- fix(cli): remove -S from shebang to fix Windows and BSD execution by
@scidomino in [#24756](https://github.com/google-gemini/gemini-cli/pull/24756)
- Fix issue where topic headers can be posted back to back by @gundermanc in
[#24759](https://github.com/google-gemini/gemini-cli/pull/24759)
- fix(core): handle partial llm_request in BeforeModel hook override by
@krishdef7 in [#22326](https://github.com/google-gemini/gemini-cli/pull/22326)
- fix(ui): improve narration suppression and reduce flicker by @gundermanc in
[#24635](https://github.com/google-gemini/gemini-cli/pull/24635)
- fix(ui): fixed auth race condition causing logo to flicker by @devr0306 in
[#24652](https://github.com/google-gemini/gemini-cli/pull/24652)
- fix(browser): remove premature browser cleanup after subagent invocation by
@gsquared94 in
[#24753](https://github.com/google-gemini/gemini-cli/pull/24753)
- Revert "feat(core,cli): prioritize summary for topics (#24608)" by
@Abhijit-2592 in
[#24777](https://github.com/google-gemini/gemini-cli/pull/24777)
- relax tool sandboxing overrides for plan mode to match defaults. by
@DavidAPierce in
[#24762](https://github.com/google-gemini/gemini-cli/pull/24762)
- fix(cli): respect global environment variable allowlist by @scidomino in
[#24767](https://github.com/google-gemini/gemini-cli/pull/24767)
- fix(cli): ensure skills list outputs to stdout in non-interactive environments
by @spencer426 in
[#24566](https://github.com/google-gemini/gemini-cli/pull/24566)
- Add an eval for and fix unsafe cloning behavior. by @gundermanc in
[#24457](https://github.com/google-gemini/gemini-cli/pull/24457)
- fix(policy): allow complete_task in plan mode by @abhipatel12 in
[#24771](https://github.com/google-gemini/gemini-cli/pull/24771)
- feat(telemetry): add browser agent clearcut metrics by @gsquared94 in
[#24688](https://github.com/google-gemini/gemini-cli/pull/24688)
- feat(cli): support selective topic expansion and click-to-expand by
@Abhijit-2592 in
[#24793](https://github.com/google-gemini/gemini-cli/pull/24793)
- temporarily disable sandbox integration test on windows by @ehedlund in
[#24786](https://github.com/google-gemini/gemini-cli/pull/24786)
- Remove flakey test by @scidomino in
[#24837](https://github.com/google-gemini/gemini-cli/pull/24837)
- Alisa/approve button by @alisa-alisa in
[#24645](https://github.com/google-gemini/gemini-cli/pull/24645)
- feat(hooks): display hook system messages in UI by @mbleigh in
[#24616](https://github.com/google-gemini/gemini-cli/pull/24616)
- fix(core): propagate BeforeModel hook model override end-to-end by @krishdef7
in [#24784](https://github.com/google-gemini/gemini-cli/pull/24784)
- chore: fix formatting for behavioral eval skill reference file by @abhipatel12
in [#24846](https://github.com/google-gemini/gemini-cli/pull/24846)
- fix: use directory junctions on Windows for skill linking by @enjoykumawat in
[#24823](https://github.com/google-gemini/gemini-cli/pull/24823)
- fix(cli): prevent multiple banner increments on remount by @sehoon38 in
[#24843](https://github.com/google-gemini/gemini-cli/pull/24843)
- feat(acp): add /help command by @sripasg in
[#24839](https://github.com/google-gemini/gemini-cli/pull/24839)
- fix(core): remove tmux alternate buffer warning by @jackwotherspoon in
[#24852](https://github.com/google-gemini/gemini-cli/pull/24852)
- Improve sandbox error matching and caching by @DavidAPierce in
[#24550](https://github.com/google-gemini/gemini-cli/pull/24550)
- feat(core): add agent protocol UI types and experimental flag by @mbleigh in
[#24275](https://github.com/google-gemini/gemini-cli/pull/24275)
- feat(core): use experiment flags for default fetch timeouts by @yunaseoul in
[#24261](https://github.com/google-gemini/gemini-cli/pull/24261)
- Revert "fix(ui): improve narration suppression and reduce flicker (#2… by
@gundermanc in
[#24857](https://github.com/google-gemini/gemini-cli/pull/24857)
- refactor(cli): remove duplication in interactive shell awaiting input hint by
@JayadityaGit in
[#24801](https://github.com/google-gemini/gemini-cli/pull/24801)
- refactor(core): make LegacyAgentSession dependencies optional by @mbleigh in
[#24287](https://github.com/google-gemini/gemini-cli/pull/24287)
- Changelog for v0.37.0-preview.2 by @gemini-cli-robot in
[#24848](https://github.com/google-gemini/gemini-cli/pull/24848)
- fix(cli): always show shell command description or actual command by @jacob314
in [#24774](https://github.com/google-gemini/gemini-cli/pull/24774)
- Added flag for ept size and increased default size by @devr0306 in
[#24859](https://github.com/google-gemini/gemini-cli/pull/24859)
- fix(core): dispose Scheduler to prevent McpProgress listener leak by
@Anjaligarhwal in
[#24870](https://github.com/google-gemini/gemini-cli/pull/24870)
- fix(cli): switch default back to terminalBuffer=false and fix regressions
introduced for that mode by @jacob314 in
[#24873](https://github.com/google-gemini/gemini-cli/pull/24873)
- feat(cli): switch to ctrl+g from ctrl-x by @jacob314 in
[#24861](https://github.com/google-gemini/gemini-cli/pull/24861)
- fix: isolate concurrent browser agent instances by @gsquared94 in
[#24794](https://github.com/google-gemini/gemini-cli/pull/24794)
- docs: update MCP server OAuth redirect port documentation by @adamfweidman in
[#24844](https://github.com/google-gemini/gemini-cli/pull/24844)
- chore(release): bump version to 0.45.0-nightly.20260521.g854f811be by
@gemini-cli-robot in
[#27362](https://github.com/google-gemini/gemini-cli/pull/27362)
- fix(cli): prevent Termux relaunch and resize remount loops by @saymanq in
[#27110](https://github.com/google-gemini/gemini-cli/pull/27110)
- Feat/a2a expose usage metadata by @jvargassanchez-dot in
[#27288](https://github.com/google-gemini/gemini-cli/pull/27288)
- feat(context): Complete simplification work. by @joshualitt in
[#27345](https://github.com/google-gemini/gemini-cli/pull/27345)
- fix(core): force update_topic tool to execute sequentially by
@jvargassanchez-dot in
[#27357](https://github.com/google-gemini/gemini-cli/pull/27357)
- Changelog for v0.44.0-preview.0 by @gemini-cli-robot in
[#27360](https://github.com/google-gemini/gemini-cli/pull/27360)
- Changelog for v0.43.0 by @gemini-cli-robot in
[#27361](https://github.com/google-gemini/gemini-cli/pull/27361)
- Revert "fix(core): prevent SIGHUP kills in PTY environments" by @bbiggs in
[#27401](https://github.com/google-gemini/gemini-cli/pull/27401)
- fix(cli): filter internal session context from history during resumption by
@rmedranollamas in
[#27391](https://github.com/google-gemini/gemini-cli/pull/27391)
- Update default auto routing by @DavidAPierce in
[#27071](https://github.com/google-gemini/gemini-cli/pull/27071)
- fix(core): bypass routing classifiers to prevent orphaned function response
errors by @danielweis in
[#27389](https://github.com/google-gemini/gemini-cli/pull/27389)
- fix(core): suppress PTY resize EBADF errors by @scidomino in
[#27461](https://github.com/google-gemini/gemini-cli/pull/27461)
- fix(core): prevent blacklist bypass in mcp list by @ompatel-aiml in
[#27377](https://github.com/google-gemini/gemini-cli/pull/27377)
- fix(cli): ignore unmapped vim normal keys by @MukundaKatta in
[#27102](https://github.com/google-gemini/gemini-cli/pull/27102)
- fix(patch): cherry-pick bd53951 to release/v0.45.0-preview.0-pr-27496 to patch
version v0.45.0-preview.0 and create version 0.45.0-preview.1 by
@gemini-cli-robot in
[#27535](https://github.com/google-gemini/gemini-cli/pull/27535)
**Full Changelog**:
https://github.com/google-gemini/gemini-cli/compare/v0.38.0...v0.38.2
https://github.com/google-gemini/gemini-cli/compare/v0.44.1...v0.45.0
+51 -238
View File
@@ -1,6 +1,6 @@
# Preview release: v0.39.0-preview.0
# Preview release: v0.48.0-preview.0
Released: April 14, 2026
Released: June 17, 2026
Our preview release includes the latest, new, and experimental features. This
release may not be as stable as our [latest weekly release](latest.md).
@@ -13,245 +13,58 @@ npm install -g @google/gemini-cli@preview
## Highlights
- **Refactored Subagents and Unified Tooling:** Consolidate subagent tools into
a single `invoke_subagent` tool, removed legacy wrapping tools, and improved
turn limits for codebase investigator.
- **Advanced Memory and Skill Management:** Introduced `/memory` inbox for
reviewing extracted skills and added skill patching support, enhancing agent
learning and persistence.
- **Expanded Test and Evaluation Infrastructure:** Added memory and CPU
performance integration test harnesses and generalized evaluation
infrastructure for better suite organization.
- **Sandbox and Security Hardening:** Centralized sandbox paths for Linux and
macOS, enforced read-only security for async git worktree resolution, and
optimized Windows sandbox initialization.
- **Enhanced CLI UX and UI Stability:** Improved scroll momentum, added a
`debugRainbow` setting, and resolved various memory leaks and PTY exhaustion
issues for a smoother terminal experience.
- **GDC Service Identity Support**: Added support for GDC air-gapped Service
Identity after a major auth library update.
- **Standardised Tool Outputs**: Standardised tool output formatting to ensure
consistency and readability across different CLI commands.
- **Static Evaluation Analyzer**: Introduced a new static evaluation source
analyzer to improve development and testing.
- **Vulnerability Prevention**: Hardened CLI security by preventing path
traversal vulnerabilities during the installation of Skills.
- **Configuration & Error Hardening**: Migrated the `coreTools` configuration
setting to `tools.core` and ensured zero-quota limits fail fast to prevent
infinite retry loops.
## What's Changed
- refactor(plan): simplify policy priorities and consolidate read-only rules by
@ruomengz in [#24849](https://github.com/google-gemini/gemini-cli/pull/24849)
- feat(test-utils): add memory usage integration test harness by @sripasg in
[#24876](https://github.com/google-gemini/gemini-cli/pull/24876)
- feat(memory): add /memory inbox command for reviewing extracted skills by
@SandyTao520 in
[#24544](https://github.com/google-gemini/gemini-cli/pull/24544)
- chore(release): bump version to 0.39.0-nightly.20260408.e77b22e63 by
- chore(release): bump version to 0.48.0-nightly.20260609.g3a13b8eeb by
@gemini-cli-robot in
[#24939](https://github.com/google-gemini/gemini-cli/pull/24939)
- fix(core): ensure robust sandbox cleanup in all process execution paths by
@ehedlund in [#24763](https://github.com/google-gemini/gemini-cli/pull/24763)
- chore: update ink version to 6.6.8 by @jacob314 in
[#24934](https://github.com/google-gemini/gemini-cli/pull/24934)
- Changelog for v0.38.0-preview.0 by @gemini-cli-robot in
[#24938](https://github.com/google-gemini/gemini-cli/pull/24938)
- chore: ignore conductor directory by @JayadityaGit in
[#22128](https://github.com/google-gemini/gemini-cli/pull/22128)
- Changelog for v0.37.0 by @gemini-cli-robot in
[#24940](https://github.com/google-gemini/gemini-cli/pull/24940)
- feat(plan): require user confirmation for activate_skill in Plan Mode by
@ruomengz in [#24946](https://github.com/google-gemini/gemini-cli/pull/24946)
- feat(test-utils): add CPU performance integration test harness by @sripasg in
[#24951](https://github.com/google-gemini/gemini-cli/pull/24951)
- fix(cli-ui): enable Ctrl+Backspace for word deletion in Windows Terminal by
@dogukanozen in
[#21447](https://github.com/google-gemini/gemini-cli/pull/21447)
- test(sdk): add unit tests for GeminiCliSession by @AdamyaSingh7 in
[#21897](https://github.com/google-gemini/gemini-cli/pull/21897)
- fix(core): resolve windows symlink bypass and stabilize sandbox integration
tests by @ehedlund in
[#24834](https://github.com/google-gemini/gemini-cli/pull/24834)
- fix(cli): restore file path display in edit and write tool confirmations by
@jwhelangoog in
[#24974](https://github.com/google-gemini/gemini-cli/pull/24974)
- feat(core): refine shell tool description display logic by @jwhelangoog in
[#24903](https://github.com/google-gemini/gemini-cli/pull/24903)
- fix(core): dynamic session ID injection to resolve resume bugs by @scidomino
in [#24972](https://github.com/google-gemini/gemini-cli/pull/24972)
- Update ink version to 6.6.9 by @jacob314 in
[#24980](https://github.com/google-gemini/gemini-cli/pull/24980)
- Generalize evals infra to support more types of evals, organization and
queuing of named suites by @gundermanc in
[#24941](https://github.com/google-gemini/gemini-cli/pull/24941)
- fix(cli): optimize startup with lightweight parent process by @sehoon38 in
[#24667](https://github.com/google-gemini/gemini-cli/pull/24667)
- refactor(sandbox): use centralized sandbox paths in macOS Seatbelt
implementation by @ehedlund in
[#24984](https://github.com/google-gemini/gemini-cli/pull/24984)
- feat(cli): refine tool output formatting for compact mode by @jwhelangoog in
[#24677](https://github.com/google-gemini/gemini-cli/pull/24677)
- fix(sdk): skip broken sendStream tests to unblock nightly by @SandyTao520 in
[#25000](https://github.com/google-gemini/gemini-cli/pull/25000)
- refactor(core): use centralized path resolution for Linux sandbox by @ehedlund
in [#24985](https://github.com/google-gemini/gemini-cli/pull/24985)
- Support ctrl+shift+g by @jacob314 in
[#25035](https://github.com/google-gemini/gemini-cli/pull/25035)
- feat(core): refactor subagent tool to unified invoke_subagent tool by
@abhipatel12 in
[#24489](https://github.com/google-gemini/gemini-cli/pull/24489)
- fix(core): add explicit git identity env vars to prevent sandbox checkpointing
error by @mrpmohiburrahman in
[#19775](https://github.com/google-gemini/gemini-cli/pull/19775)
- fix: respect hideContextPercentage when FooterConfigDialog is closed without
changes by @chernistry in
[#24773](https://github.com/google-gemini/gemini-cli/pull/24773)
- fix(cli): suppress unhandled AbortError logs during request cancellation by
@euxaristia in
[#22621](https://github.com/google-gemini/gemini-cli/pull/22621)
- Automated documentation audit by @g-samroberts in
[#24567](https://github.com/google-gemini/gemini-cli/pull/24567)
- feat(cli): implement useAgentStream hook by @mbleigh in
[#24292](https://github.com/google-gemini/gemini-cli/pull/24292)
- refactor(plan) Clean default plan toml by @ruomengz in
[#25037](https://github.com/google-gemini/gemini-cli/pull/25037)
- refactor(core): remove legacy subagent wrapping tools by @abhipatel12 in
[#25053](https://github.com/google-gemini/gemini-cli/pull/25053)
- fix(core): honor retryDelay in RetryInfo for 503 errors by @yunaseoul in
[#25057](https://github.com/google-gemini/gemini-cli/pull/25057)
- fix(core): remediate subagent memory leaks using AbortSignal in MessageBus by
@abhipatel12 in
[#25048](https://github.com/google-gemini/gemini-cli/pull/25048)
- feat(cli): wire up useAgentStream in AppContainer by @mbleigh in
[#24297](https://github.com/google-gemini/gemini-cli/pull/24297)
- feat(core): migrate chat recording to JSONL streaming by @spencer426 in
[#23749](https://github.com/google-gemini/gemini-cli/pull/23749)
- fix(core): clear 5-minute timeouts in oauth flow to prevent memory leaks by
@spencer426 in
[#24968](https://github.com/google-gemini/gemini-cli/pull/24968)
- fix(sandbox): centralize async git worktree resolution and enforce read-only
security by @ehedlund in
[#25040](https://github.com/google-gemini/gemini-cli/pull/25040)
- feat(test): add high-volume shell test and refine perf harness by @sripasg in
[#24983](https://github.com/google-gemini/gemini-cli/pull/24983)
- fix(core): silently handle EPERM when listing dir structure by @scidomino in
[#25066](https://github.com/google-gemini/gemini-cli/pull/25066)
- Changelog for v0.37.1 by @gemini-cli-robot in
[#25055](https://github.com/google-gemini/gemini-cli/pull/25055)
- fix: decode Uint8Array and multi-byte UTF-8 in API error messages by
@kimjune01 in [#23341](https://github.com/google-gemini/gemini-cli/pull/23341)
- Automated documentation audit results by @g-samroberts in
[#22755](https://github.com/google-gemini/gemini-cli/pull/22755)
- debugging(ui): add optional debugRainbow setting by @jacob314 in
[#25088](https://github.com/google-gemini/gemini-cli/pull/25088)
- fix: resolve lifecycle memory leaks by cleaning up listeners and root closures
by @spencer426 in
[#25049](https://github.com/google-gemini/gemini-cli/pull/25049)
- docs(cli): updates f12 description to be more precise by @JayadityaGit in
[#15816](https://github.com/google-gemini/gemini-cli/pull/15816)
- fix(cli): mark /settings as unsafe to run concurrently by @jacob314 in
[#25061](https://github.com/google-gemini/gemini-cli/pull/25061)
- fix(core): remove buffer slice to prevent OOM on large output streams by
@spencer426 in
[#25094](https://github.com/google-gemini/gemini-cli/pull/25094)
- feat(core): persist subagent agentId in tool call records by @abhipatel12 in
[#25092](https://github.com/google-gemini/gemini-cli/pull/25092)
- chore(core): increase codebase investigator turn limits to 50 by @abhipatel12
in [#25125](https://github.com/google-gemini/gemini-cli/pull/25125)
- refactor(core): consolidate execute() arguments into ExecuteOptions by
@mbleigh in [#25101](https://github.com/google-gemini/gemini-cli/pull/25101)
- feat(core): add Strategic Re-evaluation guidance to system prompt by
@aishaneeshah in
[#25062](https://github.com/google-gemini/gemini-cli/pull/25062)
- fix(core): preserve shell execution config fields on update by
@jasonmatthewsuhari in
[#25113](https://github.com/google-gemini/gemini-cli/pull/25113)
- docs: add vi shortcuts and clarify MCP sandbox setup by @chrisjcthomas in
[#21679](https://github.com/google-gemini/gemini-cli/pull/21679)
- fix(cli): pass session id to interactive shell executions by
@jasonmatthewsuhari in
[#25114](https://github.com/google-gemini/gemini-cli/pull/25114)
- fix(cli): resolve text sanitization data loss due to C1 control characters by
@euxaristia in
[#22624](https://github.com/google-gemini/gemini-cli/pull/22624)
- feat(core): add large memory regression test by @cynthialong0-0 in
[#25059](https://github.com/google-gemini/gemini-cli/pull/25059)
- fix(core): resolve PTY exhaustion and orphan MCP subprocess leaks by
@spencer426 in
[#25079](https://github.com/google-gemini/gemini-cli/pull/25079)
- chore(deps): update vulnerable dependencies via npm audit fix by @scidomino in
[#25140](https://github.com/google-gemini/gemini-cli/pull/25140)
- perf(sandbox): optimize Windows sandbox initialization via native ACL
application by @ehedlund in
[#25077](https://github.com/google-gemini/gemini-cli/pull/25077)
- chore: switch from keytar to @github/keytar by @cocosheng-g in
[#25143](https://github.com/google-gemini/gemini-cli/pull/25143)
- fix: improve audio MIME normalization and validation in file reads by
@junaiddshaukat in
[#21636](https://github.com/google-gemini/gemini-cli/pull/21636)
- docs: Update docs-audit to include changes in PR body by @g-samroberts in
[#25153](https://github.com/google-gemini/gemini-cli/pull/25153)
- docs: correct documentation for enforced authentication type by @cocosheng-g
in [#25142](https://github.com/google-gemini/gemini-cli/pull/25142)
- fix(cli): exclude update_topic from confirmation queue count by @Abhijit-2592
in [#24945](https://github.com/google-gemini/gemini-cli/pull/24945)
- Memory fix for trace's streamWrapper. by @anthraxmilkshake in
[#25089](https://github.com/google-gemini/gemini-cli/pull/25089)
- fix(core): fix quota footer for non-auto models and improve display by
@jackwotherspoon in
[#25121](https://github.com/google-gemini/gemini-cli/pull/25121)
- docs(contributing): clarify self-assignment policy for issues by @jmr in
[#23087](https://github.com/google-gemini/gemini-cli/pull/23087)
- feat(core): add skill patching support with /memory inbox integration by
@SandyTao520 in
[#25148](https://github.com/google-gemini/gemini-cli/pull/25148)
- Stop suppressing thoughts and text in model response by @gundermanc in
[#25073](https://github.com/google-gemini/gemini-cli/pull/25073)
- fix(release): prefix git hash in nightly versions to prevent semver
normalization by @SandyTao520 in
[#25304](https://github.com/google-gemini/gemini-cli/pull/25304)
- feat(cli): extract QuotaContext and resolve infinite render loop by @Adib234
in [#24959](https://github.com/google-gemini/gemini-cli/pull/24959)
- refactor(core): extract and centralize sandbox path utilities by @ehedlund in
[#25305](https://github.com/google-gemini/gemini-cli/pull/25305)
- feat(ui): added enhancements to scroll momentum by @devr0306 in
[#24447](https://github.com/google-gemini/gemini-cli/pull/24447)
- fix(core): replace custom binary detection with isbinaryfile to correctly
handle UTF-8 (U+FFFD) by @Anjaligarhwal in
[#25297](https://github.com/google-gemini/gemini-cli/pull/25297)
- feat(agent): implement tool-controlled display protocol (Steps 2-3) by
@mbleigh in [#25134](https://github.com/google-gemini/gemini-cli/pull/25134)
- Stop showing scrollbar unless we are in terminalBuffer mode by @jacob314 in
[#25320](https://github.com/google-gemini/gemini-cli/pull/25320)
- feat: support auth block in MCP servers config in agents by @TanmayVartak in
[#24770](https://github.com/google-gemini/gemini-cli/pull/24770)
- fix(core): expose GEMINI_PLANS_DIR to hook environment by @Adib234 in
[#25296](https://github.com/google-gemini/gemini-cli/pull/25296)
- feat(core): implement silent fallback for Plan Mode model routing by @jerop in
[#25317](https://github.com/google-gemini/gemini-cli/pull/25317)
- fix: correct redirect count increment in fetchJson by @KevinZhao in
[#24896](https://github.com/google-gemini/gemini-cli/pull/24896)
- fix(core): prevent secondary crash in ModelRouterService finally block by
@gundermanc in
[#25333](https://github.com/google-gemini/gemini-cli/pull/25333)
- feat(core): introduce decoupled ContextManager and Sidecar architecture by
@joshualitt in
[#24752](https://github.com/google-gemini/gemini-cli/pull/24752)
- docs(core): update generalist agent documentation by @abhipatel12 in
[#25325](https://github.com/google-gemini/gemini-cli/pull/25325)
- chore(mcp): check MCP error code over brittle string match by @jackwotherspoon
in [#25381](https://github.com/google-gemini/gemini-cli/pull/25381)
- feat(plan): update plan mode prompt to allow showing plan content by @ruomengz
in [#25058](https://github.com/google-gemini/gemini-cli/pull/25058)
- test(core): improve sandbox integration test coverage and fix OS-specific
failures by @ehedlund in
[#25307](https://github.com/google-gemini/gemini-cli/pull/25307)
- fix(core): use debug level for keychain fallback logging by @ehedlund in
[#25398](https://github.com/google-gemini/gemini-cli/pull/25398)
- feat(test): add a performance test in asian language by @cynthialong0-0 in
[#25392](https://github.com/google-gemini/gemini-cli/pull/25392)
- feat(cli): enable mouse clicking for cursor positioning in AskUser multi-line
answers by @Adib234 in
[#24630](https://github.com/google-gemini/gemini-cli/pull/24630)
- fix(core): detect kmscon terminal as supporting true color by @claygeo in
[#25282](https://github.com/google-gemini/gemini-cli/pull/25282)
- ci: add agent session drift check workflow by @adamfweidman in
[#25389](https://github.com/google-gemini/gemini-cli/pull/25389)
- use macos-latest-large runner where applicable. by @scidomino in
[#25413](https://github.com/google-gemini/gemini-cli/pull/25413)
- Changelog for v0.37.2 by @gemini-cli-robot in
[#25336](https://github.com/google-gemini/gemini-cli/pull/25336)
[#27779](https://github.com/google-gemini/gemini-cli/pull/27779)
- ci(dependabot): enable cooldown period for npm packages by @ruomengz in
[#27743](https://github.com/google-gemini/gemini-cli/pull/27743)
- refactor(core): standardize tool output formatting by @galz10 in
[#27772](https://github.com/google-gemini/gemini-cli/pull/27772)
- ci: update workflow logging and policy configurations by @galz10 in
[#27853](https://github.com/google-gemini/gemini-cli/pull/27853)
- fix(core): Ensure zero-quota limits fail fast to prevent retry loop hang by
@luisfelipe-alt in
[#27698](https://github.com/google-gemini/gemini-cli/pull/27698)
- fix(core): handle multi-line escaped quotes in stripShellWrapper by
@sanchezcoraspe in
[#27467](https://github.com/google-gemini/gemini-cli/pull/27467)
- fix(cli): prevent path traversal vulnerabilities during skill install… by
@ompatel-aiml in
[#27767](https://github.com/google-gemini/gemini-cli/pull/27767)
- Fix/pending tools and trust overrides by @jvargassanchez-dot in
[#27854](https://github.com/google-gemini/gemini-cli/pull/27854)
- ci: use internal environment for scheduled nightly releases (#27865) by
@rmedranollamas in
[#27939](https://github.com/google-gemini/gemini-cli/pull/27939)
- feat(core): Support GDC air-gapped Service Identity after auth library update
by @sidhantgoyal-droid in
[#27956](https://github.com/google-gemini/gemini-cli/pull/27956)
- fix(cli): handle tmux false positive background detection by @amelidev in
[#27572](https://github.com/google-gemini/gemini-cli/pull/27572)
- Add static eval source analyzer by @ved015 in
[#27631](https://github.com/google-gemini/gemini-cli/pull/27631)
- fix(config): migrate coreTools setting to tools.core by @galz10 in
[#27947](https://github.com/google-gemini/gemini-cli/pull/27947)
- fix(core-tools): resolve defensive path resolution for at-reference files by
@luisfelipe-alt in
[#27943](https://github.com/google-gemini/gemini-cli/pull/27943)
- Revert "fix(core-tools): resolve defensive path resolution for at-reference
files" by @galz10 in
[#27992](https://github.com/google-gemini/gemini-cli/pull/27992)
**Full Changelog**:
https://github.com/google-gemini/gemini-cli/compare/v0.38.0-preview.0...v0.39.0-preview.0
https://github.com/google-gemini/gemini-cli/compare/v0.47.0-preview.0...v0.48.0-preview.0
+60 -39
View File
@@ -1,9 +1,10 @@
# Auto Memory
Auto Memory is an experimental feature that mines your past Gemini CLI sessions
in the background and turns recurring workflows into reusable
[Agent Skills](./skills.md). You review, accept, or discard each extracted skill
before it becomes available to future sessions.
in the background and proposes durable memory updates and reusable
[Agent Skills](./skills.md). You review each candidate before it becomes
available to future sessions: apply memory updates, promote skills, or discard
anything you do not want.
<!-- prettier-ignore -->
> [!NOTE]
@@ -12,28 +13,32 @@ before it becomes available to future sessions.
## Overview
Every session you run with Gemini CLI is recorded locally as a transcript. Auto
Memory scans those transcripts for procedural patterns that recur across
sessions, then drafts each pattern as a `SKILL.md` file in a project-local
inbox. You inspect the draft, decide whether it captures real expertise, and
promote it to your global or workspace skills directory if you want it.
Memory scans those transcripts for durable facts, preferences, workflow
constraints, and procedural patterns that recur across sessions. It can draft
memory updates as unified diff `.patch` files and draft reusable procedures as
`SKILL.md` files. All candidates are held in a project-local inbox until you
approve or discard them.
You'll use Auto Memory when you want to:
- **Capture team workflows** that you find yourself walking the agent through
more than once.
- **Preserve durable project context** such as repeated verification commands,
local constraints, or personal project notes.
- **Codify hard-won fixes** for project-specific landmines so future sessions
avoid them.
- **Bootstrap a skills library** without writing every `SKILL.md` by hand.
Auto Memory complements—but does not replace—the
[`save_memory` tool](../tools/memory.md), which captures single facts into
`GEMINI.md`. Auto Memory captures multi-step procedures into skills.
Auto Memory complements direct memory-file editing. The agent can still persist
explicit user instructions by editing the appropriate Markdown memory file; Auto
Memory infers candidates from past sessions, writes reviewable patches or skill
drafts, and never applies them without your approval.
## Prerequisites
- Gemini CLI installed and authenticated.
- At least 10 user messages across recent, idle sessions in the project. Auto
Memory ignores active or trivial sessions.
- At least one idle project session with 10 or more user messages. Auto Memory
ignores active, trivial, and sub-agent sessions.
## How to enable Auto Memory
@@ -66,36 +71,45 @@ UI, consume your interactive turns, or surface tool prompts.
been idle for at least three hours and contain at least 10 user messages.
2. **Lock acquisition.** A lock file in the project's memory directory
coordinates across multiple CLI instances so extraction runs at most once at
a time.
3. **Sub-agent extraction.** A specialized sub-agent (named `confucius`)
reviews the session index, reads any sessions that look like they contain
repeated procedural workflows, and drafts new `SKILL.md` files. Its
instructions tell it to default to creating zero skills unless the evidence
is strong, so most runs produce no inbox items.
4. **Patch validation.** If the sub-agent proposes edits to skills outside the
inbox (for example, an existing global skill), it writes a unified diff
`.patch` file. Auto Memory dry-runs each patch and discards any that do not
apply cleanly.
5. **Notification.** When a run produces new skills or patches, Gemini CLI
surfaces an inline message telling you how many items are waiting.
a time. A state file records processed session versions, and extraction is
throttled so short back-to-back CLI launches do not repeatedly scan history.
3. **Candidate extraction.** A background extraction agent reviews the session
index, reads any sessions that look like they contain durable memory or
repeated procedural workflows, and drafts candidates. It defaults to
creating no artifacts unless the evidence is strong, so many runs produce no
inbox items.
4. **Safety boundaries.** Auto Memory writes candidates to a review inbox. It
cannot directly edit active memory files, settings, credentials, or project
`GEMINI.md` files.
5. **Patch validation.** Skill update patches are parsed and dry-run before
they are surfaced. Memory patches are parsed, target-allowlisted, and
applied atomically only when you approve them from the inbox.
6. **Notification.** When a run produces new candidates, Gemini CLI surfaces an
inline message telling you how many items are waiting.
## How to review extracted skills
## How to review extracted items
Use the `/memory inbox` slash command to open the inbox dialog at any time:
**Command:** `/memory inbox`
The dialog lists each draft skill with its name, description, and source
sessions. From there you can:
The dialog groups pending items into new skills, skill updates, and memory
updates. From there you can:
- **Read** the full `SKILL.md` body before deciding.
- **Promote** a skill to your user (`~/.gemini/skills/`) or workspace
(`.gemini/skills/`) directory.
- **Discard** a skill you do not want.
- **Apply** or reject a `.patch` proposal against an existing skill.
- **Review** memory diffs before they touch active files.
- **Apply** or dismiss private and global memory patches. Private patches target
the project memory directory; global patches target only your personal
`~/.gemini/GEMINI.md` file.
Promoted skills become discoverable in the next session and follow the standard
[skill discovery precedence](./skills.md#skill-discovery-tiers).
[skill discovery precedence](./skills.md#skill-discovery-tiers). Applied memory
patches update the underlying memory files and reload memory for the current
session.
## How to disable Auto Memory
@@ -117,19 +131,26 @@ start. Existing inbox items remain on disk; you can either drain them with
## Data and privacy
- Auto Memory only reads session files that already exist locally on your
machine. Nothing is uploaded to Gemini outside the normal API calls the
extraction sub-agent makes during its run.
- The sub-agent is instructed to redact secrets, tokens, and credentials it
encounters and to never copy large tool outputs verbatim.
- Drafted skills live in your project's memory directory until you promote or
discard them. They are not automatically loaded into any session.
machine.
- Auto Memory uses model calls to analyze selected local transcript content
during extraction. No candidates are applied automatically, but transcript
excerpts may be sent to the configured model as part of those calls.
- The extraction agent is instructed to redact secrets, tokens, and credentials
it encounters and to never copy large tool outputs verbatim.
- Drafted skills and memory patches live in your project's memory directory
until you promote, apply, dismiss, or discard them. They are not automatically
loaded into any session.
## Limitations
- The sub-agent runs on a preview Gemini Flash model. Extraction quality depends
on the model's ability to recognize durable patterns versus one-off incidents.
- Auto Memory does not extract skills from the current session. It only
considers sessions that have been idle for three hours or more.
- The extraction agent runs on a preview Gemini Flash model. Extraction quality
depends on the model's ability to recognize durable patterns versus one-off
incidents.
- Auto Memory does not extract memory or skills from the current session. It
only considers sessions that have been idle for three hours or more.
- Project or workspace shared instructions in project `GEMINI.md` files are not
auto-extractable. Auto Memory can propose private project memory, global
personal memory, and skills.
- Inbox items are stored per project. Skills extracted in one workspace are not
visible from another until you promote them to the user-scope skills
directory.
@@ -138,6 +159,6 @@ start. Existing inbox items remain on disk; you can either drain them with
- Learn how skills are discovered and activated in [Agent Skills](./skills.md).
- Explore the [memory management tutorial](./tutorials/memory-management.md) for
the complementary `save_memory` and `GEMINI.md` workflows.
the complementary explicit-memory and `GEMINI.md` workflows.
- Review the experimental settings catalog in
[Settings](./settings.md#experimental).
+2 -1
View File
@@ -9,7 +9,7 @@ and parameters.
| ---------------------------------- | ---------------------------------- | ------------------------------------------------------------ |
| `gemini` | Start interactive REPL | `gemini` |
| `gemini -p "query"` | Query non-interactively | `gemini -p "summarize README.md"` |
| `gemini "query"` | Query and continue interactively | `gemini "explain this project"` |
| gemini "query" | Query and continue interactively | gemini "explain this project" |
| `cat file \| gemini` | Process piped content | `cat logs.txt \| gemini`<br>`Get-Content logs.txt \| gemini` |
| `gemini -i "query"` | Execute and continue interactively | `gemini -i "What is the purpose of this project?"` |
| `gemini -r "latest"` | Continue most recent session | `gemini -r "latest"` |
@@ -33,6 +33,7 @@ These commands are available within the interactive REPL.
| -------------------- | ----------------------------------------------- |
| `/skills reload` | Reload discovered skills from disk |
| `/agents reload` | Reload the agent registry |
| `/commands list` | List available custom slash commands |
| `/commands reload` | Reload custom slash commands |
| `/memory reload` | Reload context files (for example, `GEMINI.md`) |
| `/mcp reload` | Restart and reload MCP servers |
+169 -42
View File
@@ -1,18 +1,21 @@
# Creating Agent Skills
This guide provides an overview of how to create your own Agent Skills to extend
the capabilities of Gemini CLI.
Agent Skills let you extend Gemini CLI with specialized expertise, procedural
workflows, and task-specific resources. This guide walks you through both
automated and manual methods for creating and organizing your skills.
## Getting started: The `skill-creator` skill
## Quickstart: Create a skill with a prompt
The recommended way to create a new skill is to use the built-in `skill-creator`
skill. To use it, ask Gemini CLI to create a new skill for you.
The fastest way to create a new skill is to use the built-in `skill-creator`.
This meta-skill guides you through designing, scaffolding, and validating your
expertise.
**Example prompt:**
Simply ask Gemini CLI to create a skill for you:
> "create a new skill called 'code-reviewer'"
> "Create a new skill called 'code-reviewer' that analyzes local files for
> common errors and style violations."
Gemini CLI will then use the `skill-creator` to generate the skill:
Gemini will then:
1. Generate a new directory for your skill (for example, `my-new-skill/`).
2. Create a `SKILL.md` file with the necessary YAML frontmatter (`name` and
@@ -20,24 +23,116 @@ Gemini CLI will then use the `skill-creator` to generate the skill:
3. Create the standard resource directories: `scripts/`, `references/`, and
`assets/`.
## Manual skill creation
Once created, you can find your new skill in `.gemini/skills/code-reviewer/`.
If you prefer to create skills manually:
## Manual creation
1. **Create a directory** for your skill (for example, `my-new-skill/`).
2. **Create a `SKILL.md` file** inside the new directory.
To add additional resources that support the skill, refer to the skill
structure.
### 1. Create the directory structure
## Skill structure
The first step is to create the necessary folders for your skill and its
scripts.
A skill is a directory containing a `SKILL.md` file at its root.
**macOS/Linux**
### Folder structure
```bash
mkdir -p .gemini/skills/code-reviewer/scripts
```
**Windows (PowerShell)**
```powershell
New-Item -ItemType Directory -Force -Path ".gemini\skills\code-reviewer\scripts"
```
### 2. Define the skill (`SKILL.md`)
The `SKILL.md` file defines the skill's purpose and instructions for the agent.
Create a file at `.gemini/skills/code-reviewer/SKILL.md`.
```markdown
---
name: code-reviewer
description:
Expertise in reviewing code changes for correctness, security, and style. Use
when the user asks to "review" their code or a PR.
---
# Code Reviewer Instructions
You act as a senior software engineer specialized in code quality. When this
skill is active, you MUST:
1. **Analyze**: Review the provided code for logical errors, security
vulnerabilities, and style violations.
2. **Review**: Use the bundled `scripts/review.js` utility to perform an
automated check.
3. **Feedback**: Provide constructive feedback, clearly distinguishing between
critical issues and minor improvements.
```
### 3. Add the tool logic
Skills can bundle resources like scripts to perform deterministic tasks. Create
a file at `.gemini/skills/code-reviewer/scripts/review.js`.
```javascript
// .gemini/skills/code-reviewer/scripts/review.js
const file = process.argv[2];
if (!file) {
console.error('Usage: node review.js <file>');
process.exit(1);
}
console.log(`Reviewing ${file}...`);
// Simple mock review logic
setTimeout(() => {
console.log(`Result: Success (No major issues found in ${file})`);
}, 500);
```
### 4. Test the skill
Gemini CLI automatically discovers skills in the `.gemini/skills` directory.
1. Start a new session and ask a question that triggers the skill's
description: "Can you review index.js"
2. Gemini identifies the request matches the `code-reviewer` description and
asks for permission to activate it.
3. Once you approve, Gemini executes the bundled script:
`node .gemini/skills/code-reviewer/scripts/review.js index.js`
To determine whether your skill has been correctly loaded, run the command:
```bash
/skills
```
### 5. Optional: Share your skill
You can share your skills in several ways depending on your target audience.
- **Workspace skills**: Commit your skill to a `.gemini/skills/` directory in
your project repository.
- **Extensions**: Bundle your skill within a
[Gemini CLI extension](../extensions/writing-extensions.md).
- **Git repositories**: Share the skill directory as a standalone Git repo and
install it using `gemini skills install <url>`.
---
## Core concepts
Now that you've built your first skill, let's explore the core components and
workflows for developing more complex expertise.
### Skill structure
While a `SKILL.md` file is the only required component, we recommend the
following structure for organizing your skill's resources:
following structure for organizing your skill's resources.
```text
my-skill/
@@ -47,34 +142,66 @@ my-skill/
└── assets/ (Optional) Templates and other resources
```
### `SKILL.md` file
When a skill is activated, the model is granted access to this entire directory.
You can instruct the model to use the tools and files found within these
folders.
The `SKILL.md` file is the core of your skill. This file uses YAML frontmatter
for metadata and Markdown for instructions. For example:
### Metadata and triggers
```markdown
---
name: code-reviewer
description:
Use this skill to review code. It supports both local changes and remote Pull
Requests.
---
# Code Reviewer
This skill guides the agent in conducting thorough code reviews.
## Workflow
### 1. Determine Review Target
- **Remote PR**: If the user gives a PR number or URL, target that remote PR.
- **Local Changes**: If changes are local... ...
```
The `SKILL.md` file uses YAML frontmatter for metadata.
- **`name`**: A unique identifier for the skill. This should match the directory
name.
- **`description`**: A description of what the skill does and when Gemini should
use it.
- **Body**: The Markdown body of the file contains the instructions that guide
the agent's behavior when the skill is active.
- **`description`**: **CRITICAL.** This is how Gemini decides when to use the
skill. Be specific about the tasks it handles and the keywords that should
trigger it.
### Discovery tiers
Gemini CLI discovers skills from several locations, following a specific order
of precedence (lowest to highest):
1. **Built-in Skills**: Included with Gemini CLI (pre-approved).
2. **Extension Skills**: Bundled within [extensions](../extensions/).
3. **User Skills**: `~/.gemini/skills/` or the `~/.agents/skills/` alias.
4. **Workspace Skills**: `.gemini/skills/` or the `.agents/skills/` alias.
### Discovery aliases
You can use `.agents/skills` as an alternative to `.gemini/skills`. This alias
is compatible with other AI agent tools following the
[Agent Skills](https://agentskills.io) standard.
## Advanced development
Once you've built a basic skill, you can use specialized scripts and workflows
to streamline your development process.
### Creation scripts
If you are developing a skill and want to use the same scripts the built-in
tools use, you can find them in the core package. These scripts help automate
the initialization, validation, and packaging of skills.
- **Initialize**: `node scripts/init_skill.cjs <name> --path <dir>`
- **Validate**: `node scripts/validate_skill.cjs <path/to/skill>`
- **Package**: `node scripts/package_skill.cjs <path/to/skill>` (Creates a
`.skill` zip file)
### Linking for local development
If you are developing a skill in a separate directory, you can link it to your
user skills directory for testing:
```bash
gemini skills link .
```
## Next steps
- [Skill best practices](./skills-best-practices.md): Learn strategies for
building reliable and effective skills.
- [Agent Skills overview](./skills.md): Deep dive into discovery tiers and the
skill lifecycle.
- [Get started with Agent Skills](./tutorials/skills-getting-started.md): A
quick walkthrough of triggering and using skills.
+1
View File
@@ -34,6 +34,7 @@ separator (`/` or `\`) being converted to a colon (`:`).
> [!TIP]
> After creating or modifying `.toml` command files, run
> `/commands reload` to pick up your changes without restarting the CLI.
> To see all available command files, run `/commands list`.
## TOML file format (v1)
+1 -1
View File
@@ -285,7 +285,7 @@ environment to a blocklist.
<!-- prettier-ignore -->
> [!WARNING]
> Blocklisting with `excludeTools` is less secure than
> allowlisting with `coreTools`, as it relies on blocking known-bad commands,
> allowlisting with `tools.core`, as it relies on blocking known-bad commands,
> and clever users may find ways to bypass simple string-based blocks.
> **Allowlisting is the recommended approach.**
-2
View File
@@ -65,8 +65,6 @@ You can interact with the loaded context files by using the `/memory` command.
being provided to the model.
- **`/memory reload`**: Forces a re-scan and reload of all `GEMINI.md` files
from all configured locations.
- **`/memory add <text>`**: Appends your text to your global
`~/.gemini/GEMINI.md` file. This lets you add persistent memories on the fly.
## Modularize context with imports
+3 -3
View File
@@ -34,11 +34,11 @@ Gemini CLI will use a locally-running **Gemma** model to make routing decisions
reduce costs associated with hosted model usage while offering similar routing
decision latency and quality.
In order to use this feature, the local Gemma model **must** be served behind a
Gemini API and accessible via HTTP at an endpoint configured in `settings.json`.
The easiest way to set this up is using the automated `gemini gemma setup`
command.
For more details on how to configure local model routing, see
[Local Model Routing](../core/local-model-routing.md).
[`gemini gemma` — Local Model Routing Setup](../core/gemma-setup.md).
### Model selection precedence
+2 -2
View File
@@ -138,7 +138,6 @@ These are the only allowed tools:
[`replace`](../tools/file-system.md#6-replace-edit) only allowed for `.md`
files in the `~/.gemini/tmp/<project>/<session-id>/plans/` directory or your
[custom plans directory](#custom-plan-directory-and-policies).
- **Memory:** [`save_memory`](../tools/memory.md)
- **Skills:** [`activate_skill`](../cli/skills.md) (allows loading specialized
instructions and resources in a read-only manner)
@@ -470,7 +469,8 @@ associated plan files and task trackers.
- **Default behavior:** Sessions (and their plans) are retained for **30 days**.
- **Configuration:** You can customize this behavior via the `/settings` command
(search for **Session Retention**) or in your `settings.json` file. See
(search for **Enable Session Cleanup** or **Keep chat history**) or in your
`settings.json` file. See
[session retention](../cli/session-management.md#session-retention) for more
details.
+165 -48
View File
@@ -31,6 +31,53 @@ The benefits of sandboxing include:
- **Safety**: Reduce risk when working with untrusted code or experimental
commands.
## Quickstart
You can enable sandboxing using a command flag, environment variable, or
configuration file.
### Using the command flag
```bash
gemini -s -p "analyze the code structure"
```
### Using an environment variable
**macOS/Linux**
```bash
export GEMINI_SANDBOX=true
gemini -p "run the test suite"
```
**Windows (PowerShell)**
```powershell
$env:GEMINI_SANDBOX="true"
gemini -p "run the test suite"
```
### Configuring via settings.json
```json
{
"tools": {
"sandbox": "docker"
}
}
```
## Configuration
Enable sandboxing using one of the following methods (in order of precedence):
1. **Command flag**: `-s` or `--sandbox`
2. **Environment variable**:
`GEMINI_SANDBOX=true|docker|podman|sandbox-exec|runsc|lxc`
3. **Settings file**: `"sandbox": true` in the `tools` object of your
`settings.json` file (for example, `{"tools": {"sandbox": true}}`).
## Sandboxing methods
Your ideal method of sandboxing may differ depending on your platform and your
@@ -43,12 +90,92 @@ Lightweight, built-in sandboxing using `sandbox-exec`.
**Default profile**: `permissive-open` - restricts writes outside project
directory but allows most other operations.
Built-in profiles (set via `SEATBELT_PROFILE` env var):
- `permissive-open` (default): Write restrictions, network allowed
- `permissive-proxied`: Write restrictions, network via proxy
- `restrictive-open`: Strict restrictions, network allowed
- `restrictive-proxied`: Strict restrictions, network via proxy
- `strict-open`: Read and write restrictions, network allowed
- `strict-proxied`: Read and write restrictions, network via proxy
### 2. Container-based (Docker/Podman)
Cross-platform sandboxing with complete process isolation.
Cross-platform sandboxing with complete process isolation using container
technology. By default, it uses the `ghcr.io/google/gemini-cli:latest` image.
**Note**: Requires building the sandbox image locally or using a published image
from your organization's registry.
**Prerequisites:**
- Docker or Podman must be installed and running on your system.
**How it works (Workspace directory):**
Inside the sandbox container, your current working directory is mounted at the
**exact same absolute path** as it is on your host machine. For example, if you
run the CLI from `/Users/you/project` on your host machine, the sandbox will
mount your local project folder and operate within `/Users/you/project` inside
the container. This allows the AI to seamlessly read and modify your project
files while remaining isolated from the rest of your system.
**Quick setup:**
To enable Docker sandboxing, run Gemini CLI with the sandbox flag and specify
Docker as the provider:
```bash
# Using the environment variable (Recommended)
export GEMINI_SANDBOX=docker
gemini -p "build the project"
# Or configure it permanently in your settings.json
# {"tools": {"sandbox": "docker"}}
```
**Customizing the Sandbox Image:**
If your project requires specific dependencies, you can specify a custom image
name or have Gemini CLI build one for you automatically. You can use any Docker
or Podman image as your sandbox, provided it has standard shell utilities (like
`bash`) available.
**Option A: Using an existing custom image (e.g., Artifact Registry)**
To configure a custom image that is hosted on a registry (or built locally),
update your `settings.json` to use an object for the sandbox configuration, or
set the `GEMINI_SANDBOX_IMAGE` environment variable.
_Example: Configuring via `settings.json`_
```json
{
"tools": {
"sandbox": {
"command": "docker",
"image": "us-central1-docker.pkg.dev/my-project/my-repo/my-custom-sandbox:latest"
}
}
}
```
_Example: Configuring via environment variable_
```bash
export GEMINI_SANDBOX_IMAGE="us-central1-docker.pkg.dev/my-project/my-repo/my-custom-sandbox:latest"
```
**Option B: Building a local custom image automatically**
If you prefer to define your environment as code, you can provide a Dockerfile
and Gemini CLI will build the image automatically.
1. Create a `.gemini/sandbox.Dockerfile` in your project root.
2. Ensure you have the `gh` CLI installed and authenticated (if you are using
the default `ghcr.io/google/gemini-cli` image as a base).
3. Run your command with the `BUILD_SANDBOX` environment variable set:
```bash
BUILD_SANDBOX=1 GEMINI_SANDBOX=docker gemini -p "run my custom build"
```
### 3. Windows Native Sandbox (Windows only)
@@ -188,59 +315,49 @@ This mechanism ensures you don't have to manually re-run commands with more
permissive sandbox settings, while still maintaining control over what the AI
can access.
## Quickstart
### Including files outside the workspace
By default, the sandbox only has access to the current project workspace. If you
need the sandbox to have permission to operate on certain files or directories
from the local file system outside of the project workspace, you can mount them
using the `SANDBOX_MOUNTS` environment variable.
Provide a comma-separated list of mount definitions in the format
`from:to:opts`. If `to` is omitted, it defaults to the same path as `from`. If
`opts` is omitted, it defaults to `ro` (read-only). Note that the `from` path
must be an absolute path.
**Example**:
```bash
# Enable sandboxing with command flag
gemini -s -p "analyze the code structure"
export SANDBOX_MOUNTS="/path/on/host:/path/in/container:rw,/another/path:ro"
```
**Use environment variable**
## Running inside a Docker container
**macOS/Linux**
If you are running Gemini CLI itself from within an official or custom Docker
container and want to enable sandboxing, you must share the host's Docker socket
and ensure your workspace paths align.
1. **Mount the Docker socket**: Map `/var/run/docker.sock` so the CLI can spawn
sibling sandbox containers via the host's Docker daemon.
2. **Align workspace paths**: The path to your workspace inside the container
must exactly match the absolute path on the host. Because the sandbox
container is spawned by the host's Docker daemon, it resolves volume mounts
against the host file system.
**Example**:
```bash
export GEMINI_SANDBOX=true
gemini -p "run the test suite"
docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /absolute/path/on/host/project:/absolute/path/on/host/project \
-w /absolute/path/on/host/project \
-e GEMINI_SANDBOX=docker \
ghcr.io/google/gemini-cli:latest
```
**Windows (PowerShell)**
```powershell
$env:GEMINI_SANDBOX="true"
gemini -p "run the test suite"
```
**Configure in settings.json**
```json
{
"tools": {
"sandbox": "docker"
}
}
```
## Configuration
### Enable sandboxing (in order of precedence)
1. **Command flag**: `-s` or `--sandbox`
2. **Environment variable**:
`GEMINI_SANDBOX=true|docker|podman|sandbox-exec|runsc|lxc`
3. **Settings file**: `"sandbox": true` in the `tools` object of your
`settings.json` file (for example, `{"tools": {"sandbox": true}}`).
### macOS Seatbelt profiles
Built-in profiles (set via `SEATBELT_PROFILE` env var):
- `permissive-open` (default): Write restrictions, network allowed
- `permissive-proxied`: Write restrictions, network via proxy
- `restrictive-open`: Strict restrictions, network allowed
- `restrictive-proxied`: Strict restrictions, network via proxy
- `strict-open`: Read and write restrictions, network allowed
- `strict-proxied`: Read and write restrictions, network via proxy
## Advanced settings
### Custom sandbox flags
@@ -279,7 +396,7 @@ export SANDBOX_FLAGS="--flag1 --flag2=value"
$env:SANDBOX_FLAGS="--flag1 --flag2=value"
```
## Linux UID/GID handling
### Linux UID/GID handling
The sandbox automatically handles user permissions on Linux. Override these
permissions with:
+20 -14
View File
@@ -40,6 +40,7 @@ they appear in the UI.
| Enable Session Cleanup | `general.sessionRetention.enabled` | Enable automatic session cleanup | `true` |
| Keep chat history | `general.sessionRetention.maxAge` | Automatically delete chats older than this time period (e.g., "30d", "7d", "24h", "1w") | `"30d"` |
| Topic & Update Narration | `general.topicUpdateNarration` | Enable the Topic & Update communication model for reduced chattiness and structured progress reporting. | `true` |
| Log RAG Snippets | `general.logRagSnippets` | Log full Code Customization (RAG) retrieved snippets to a local file for debugging. | `false` |
### Output
@@ -158,23 +159,28 @@ they appear in the UI.
| UI Label | Setting | Description | Default |
| --------------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| Auto Configure Max Old Space Size | `advanced.autoConfigureMemory` | Automatically configure Node.js memory limits. Note: Because memory is allocated during the initial process boot, this setting is only read from the global user settings file and ignores workspace-level overrides. | `true` |
| Ignore Local .env | `advanced.ignoreLocalEnv` | Whether to ignore generic .env files in the project directory. | `false` |
### Experimental
| UI Label | Setting | Description | Default |
| ---------------------------------------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| Gemma Models | `experimental.gemma` | Enable access to Gemma 4 models (experimental). | `false` |
| Enable Git Worktrees | `experimental.worktrees` | Enable automated Git worktree management for parallel work. | `false` |
| Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
| Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
| Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` |
| Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` |
| Enable Gemma Model Router | `experimental.gemmaModelRouter.enabled` | Enable the Gemma Model Router (experimental). Requires a local endpoint serving Gemma via the Gemini API using LiteRT-LM shim. | `false` |
| Auto-start LiteRT Server | `experimental.gemmaModelRouter.autoStartServer` | Automatically start the LiteRT-LM server when Gemini CLI starts and the Gemma router is enabled. | `false` |
| Memory v2 | `experimental.memoryV2` | Disable the built-in save_memory tool and let the main agent persist project context by editing markdown files directly with edit/write_file. Route facts across four tiers: team-shared conventions go to project GEMINI.md files, project-specific personal notes go to the per-project private memory folder (MEMORY.md as index + sibling .md files for detail), and cross-project personal preferences go to the global ~/.gemini/GEMINI.md (the only file under ~/.gemini/ that the agent can edit — settings, credentials, etc. remain off-limits). Set to false to fall back to the legacy save_memory tool. | `true` |
| Auto Memory | `experimental.autoMemory` | Automatically extract reusable skills from past sessions in the background. Review results with /memory inbox. | `false` |
| Use the generalist profile to manage agent contexts. | `experimental.generalistProfile` | Suitable for general coding and software development tasks. | `false` |
| Enable Context Management | `experimental.contextManagement` | Enable logic for context management. | `false` |
| UI Label | Setting | Description | Default |
| ---------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| Gemma Models | `experimental.gemma` | Enable access to Gemma 4 models via Gemini API. | `true` |
| Voice Mode | `experimental.voiceMode` | Enable experimental voice dictation and commands (/voice, /voice model). | `false` |
| Voice Activation Mode | `experimental.voice.activationMode` | How to trigger voice recording with the Space key. | `"push-to-talk"` |
| Voice Transcription Backend | `experimental.voice.backend` | The backend to use for voice transcription. Note: When using the Gemini Live backend, voice recordings are sent to Google Cloud for transcription. | `"gemini-live"` |
| Whisper Model | `experimental.voice.whisperModel` | The Whisper model to use for local transcription. | `"ggml-base.en.bin"` |
| Voice Stop Grace Period (ms) | `experimental.voice.stopGracePeriodMs` | How long to wait for final transcription after stopping recording. | `4000` |
| Enable Git Worktrees | `experimental.worktrees` | Enable automated Git worktree management for parallel work. | `false` |
| Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
| Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
| Model Steering | `experimental.modelSteering` | Enable model steering (user hints) to guide the model during tool execution. | `false` |
| Direct Web Fetch | `experimental.directWebFetch` | Enable web fetch behavior that bypasses LLM summarization. | `false` |
| Enable Gemma Model Router | `experimental.gemmaModelRouter.enabled` | Enable the Gemma Model Router (experimental). Requires a local endpoint serving Gemma via the Gemini API using LiteRT-LM shim. | `false` |
| Auto-start LiteRT Server | `experimental.gemmaModelRouter.autoStartServer` | Automatically start the LiteRT-LM server when Gemini CLI starts and the Gemma router is enabled. | `false` |
| Auto Memory | `experimental.autoMemory` | Automatically extract memory patches and skills from past sessions in the background. Every change is written as a unified diff `.patch` file under `<projectMemoryDir>/.inbox/<kind>/` and held for review in /memory inbox; nothing is applied until you approve it. | `false` |
| Use the generalist profile to manage agent contexts. | `experimental.generalistProfile` | Suitable for general coding and software development tasks. | `false` |
| Enable Context Management | `experimental.contextManagement` | Enable logic for context management. | `false` |
### Skills
+78
View File
@@ -0,0 +1,78 @@
# Agent Skill best practices
Create high-quality, reliable Agent Skills by following these established design
principles and patterns.
## Design for discovery
The most important part of a skill is its `description`. This is the only
information the model has before activation.
- **Be specific**: Use keywords that are likely to appear in user prompts (for
example, "audit," "security," "refactor," "migration").
- **Define the trigger**: Clearly state _when_ the skill should be used (for
example, "Use this skill when the user asks to review a PR for performance
regressions").
- **Avoid overlap**: Ensure your skill descriptions are distinct from one
another and from the general capabilities of the model.
## Progressive disclosure
The "context window" is a shared resource. Use a three-level loading system to
manage context efficiently.
1. **Metadata (name + description)**: Always in context (~100 words).
2. **`SKILL.md` body**: Loaded only after the skill triggers (<5k words).
3. **Bundled resources**: Loaded only as needed by the model.
**Best practice**: Keep the `SKILL.md` body focused on core procedural
instructions. Move detailed reference material, schemas, and examples into
separate files in a `references/` directory.
## Degrees of freedom
Match the level of instruction specificity to the task's fragility.
- **High freedom (text-based instructions)**: Use when multiple approaches are
valid or decisions depend heavily on context.
- **Medium freedom (pseudocode or scripts with parameters)**: Use when a
preferred pattern exists but some variation is acceptable.
- **Low freedom (specific scripts, few parameters)**: Use when operations are
fragile and error-prone, or a specific sequence MUST be followed.
## Bundle resources effectively
Leverage the skill's ability to include scripts and assets to extend the agent's
capabilities.
- **Use scripts for deterministic tasks**: If a task can be automated with a
script (for example, running a linter, fetching data from an API), bundle it
in the `scripts/` folder.
- **Agentic ergonomics**: Ensure scripts output LLM-friendly stdout. Suppress
verbose tracebacks and provide clear, concise success/failure messages.
- **Provide templates**: Include common file headers or boilerplate code in the
`assets/` folder to ensure the agent produces consistent output.
## Anatomy of a great skill
A well-structured skill directory organizes its resources into specialized
sub-folders.
```text
my-skill/
├── SKILL.md (Required) Core instructions and metadata
├── scripts/ (Optional) Executable logic (Node.js, Python, etc.)
├── references/ (Optional) Documentation to be loaded as needed
└── assets/ (Optional) Templates and non-executable resources
```
## Security and privacy
Design your skills with security in mind to protect your workspace and data.
- **Avoid hardcoded secrets**: Never include API keys or passwords in your
skill's scripts or documentation.
- **Review third-party skills**: Inspect the `SKILL.md` and scripts of any skill
before installing it from an untrusted source.
- **Limit scope**: Design skills to be as focused as possible to minimize the
potential impact of errors.
+113 -108
View File
@@ -1,112 +1,21 @@
# Agent Skills
Agent Skills allow you to extend Gemini CLI with specialized expertise,
procedural workflows, and task-specific resources. Based on the
Agent Skills let you extend Gemini CLI with specialized expertise, procedural
workflows, and task-specific resources. Based on the
[Agent Skills](https://agentskills.io) open standard, a "skill" is a
self-contained directory that packages instructions and assets into a
discoverable capability.
## Overview
Unlike general context files ([`GEMINI.md`](./gemini-md.md)), which provide
Unlike general context files ([GEMINI.md](./gemini-md.md)), which provide
persistent workspace-wide background, Skills represent **on-demand expertise**.
This allows Gemini to maintain a vast library of specialized capabilities—such
as security auditing, cloud deployments, or codebase migrations—without
cluttering the model's immediate context window.
This lets Gemini CLI maintain a vast library of specialized capabilities—such as
security auditing, cloud deployments, or codebase migrations—without cluttering
the model's immediate context window.
Gemini autonomously decides when to employ a skill based on your request and the
skill's description. When a relevant skill is identified, the model "pulls in"
the full instructions and resources required to complete the task using the
`activate_skill` tool.
## How it works
## Key Benefits
- **Shared Expertise:** Package complex workflows (like a specific team's PR
review process) into a folder that anyone can use.
- **Repeatable Workflows:** Ensure complex multi-step tasks are performed
consistently by providing a procedural framework.
- **Resource Bundling:** Include scripts, templates, or example data alongside
instructions so the agent has everything it needs.
- **Progressive Disclosure:** Only skill metadata (name and description) is
loaded initially. Detailed instructions and resources are only disclosed when
the model explicitly activates the skill, saving context tokens.
## Skill Discovery Tiers
Gemini CLI discovers skills from three primary locations:
1. **Workspace Skills**: Located in `.gemini/skills/` or the `.agents/skills/`
alias. Workspace skills are typically committed to version control and
shared with the team.
2. **User Skills**: Located in `~/.gemini/skills/` or the `~/.agents/skills/`
alias. These are personal skills available across all your workspaces.
3. **Extension Skills**: Skills bundled within installed
[extensions](../extensions/index.md).
**Precedence:** If multiple skills share the same name, higher-precedence
locations override lower ones: **Workspace > User > Extension**.
Within the same tier (user or workspace), the `.agents/skills/` alias takes
precedence over the `.gemini/skills/` directory. This generic alias provides an
intuitive path for managing agent-specific expertise that remains compatible
across different AI agent tools.
## Managing Skills
### In an Interactive Session
Use the `/skills` slash command to view and manage available expertise:
- `/skills list` (default): Shows all discovered skills and their status.
- `/skills link <path>`: Links agent skills from a local directory via symlink.
- `/skills disable <name>`: Prevents a specific skill from being used.
- `/skills enable <name>`: Re-enables a disabled skill.
- `/skills reload`: Refreshes the list of discovered skills from all tiers.
<!-- prettier-ignore -->
> [!NOTE]
> `/skills disable` and `/skills enable` default to the `user` scope. Use
> `--scope workspace` to manage workspace-specific settings.
### From the Terminal
The `gemini skills` command provides management utilities:
```bash
# List all discovered skills
gemini skills list
# Link agent skills from a local directory via symlink
# Discovers skills (SKILL.md or */SKILL.md) and creates symlinks in ~/.gemini/skills
# (or ~/.agents/skills)
gemini skills link /path/to/my-skills-repo
# Link to the workspace scope (.gemini/skills or .agents/skills)
gemini skills link /path/to/my-skills-repo --scope workspace
# Install a skill from a Git repository, local directory, or zipped skill file (.skill)
# Uses the user scope by default (~/.gemini/skills or ~/.agents/skills)
gemini skills install https://github.com/user/repo.git
gemini skills install /path/to/local/skill
gemini skills install /path/to/local/my-expertise.skill
# Install a specific skill from a monorepo or subdirectory using --path
gemini skills install https://github.com/my-org/my-skills.git --path skills/frontend-design
# Install to the workspace scope (.gemini/skills or .agents/skills)
gemini skills install /path/to/skill --scope workspace
# Uninstall a skill by name
gemini skills uninstall my-expertise --scope workspace
# Enable a skill (globally)
gemini skills enable my-expertise
# Disable a skill. Can use --scope to specify workspace or user (defaults to workspace)
gemini skills disable my-expertise --scope workspace
```
## How it Works
The lifecycle of an Agent Skill involves discovery, activation, and conditional
resource access.
1. **Discovery**: At the start of a session, Gemini CLI scans the discovery
tiers and injects the name and description of all enabled skills into the
@@ -123,14 +32,110 @@ gemini skills disable my-expertise --scope workspace
5. **Execution**: The model proceeds with the specialized expertise active. It
is instructed to prioritize the skill's procedural guidance within reason.
### Skill activation
## Discovery tiers
Once a skill is activated (typically by Gemini identifying a task that matches
the skill's description and your approval), its specialized instructions and
resources are loaded into the agent's context. A skill remains active and its
guidance is prioritized for the duration of the session.
Gemini CLI discovers skills from several locations, following a specific order
of precedence (lowest to highest):
## Creating your own skills
1. **Built-in skills**: Standard skills included with Gemini CLI that provide
foundational capabilities.
2. **Extension skills**: Skills bundled within installed
[extensions](../extensions/index.md).
3. **User skills**: Located in `~/.gemini/skills/` or the `~/.agents/skills/`
alias.
4. **Workspace skills**: Located in `.gemini/skills/` or the `.agents/skills/`
alias. Workspace skills are shared with your team via version control.
To create your own skills, see the [Create Agent Skills](./creating-skills.md)
guide.
### Precedence and aliases
If multiple skills share the same name, the version from the higher-precedence
location is used. Within the same tier (user or workspace), the
`.agents/skills/` alias takes precedence over the `.gemini/skills/` directory.
The `.agents/skills/` alias provides an interoperable path for managing
agent-specific expertise that remains compatible across different AI tools.
## Key benefits
Agent Skills provide several advantages for managing specialized knowledge and
complex workflows.
- **Shared expertise**: Package complex workflows (like a specific team's PR
review process) into a folder that anyone can use.
- **Repeatable workflows**: Ensure complex multi-step tasks are performed
consistently by providing a procedural framework.
- **Resource bundling**: Include scripts, templates, or example data alongside
instructions so the agent has everything it needs.
- **Progressive disclosure**: Only skill metadata (name and description) is
loaded initially. Detailed instructions and resources are only disclosed when
the model explicitly activates the skill, saving context tokens.
<!-- prettier-ignore -->
> [!NOTE]
> `/skills disable` and `/skills enable` default to the `user` scope. Use
> `--scope workspace` to manage workspace-specific settings.
To see all available skills in your current session, use the `/skills list`
command.
## Managing skills
You can manage Agent Skills through interactive session commands or directly
from your terminal.
### In an interactive session
Use the `/skills` slash command to view and manage available expertise:
- `/skills list [all] [nodesc]`: Shows discovered skills. Use `all` to include
built-in skills and `nodesc` to hide descriptions.
- `/skills link <path> [--scope user|workspace]`: Links skills from a local
directory.
- `/skills disable <name>`: Prevents a specific skill from being used.
- `/skills enable <name>`: Re-enables a disabled skill.
- `/skills reload` (or `/skills refresh`): Refreshes the list of discovered
skills from all tiers.
### From the terminal
The `gemini skills` command provides management utilities:
```bash
# List all discovered skills. Use --all to include built-in skills.
gemini skills list --all
# Install a skill from a Git repository or local directory.
# Use --consent to skip the security confirmation prompt.
gemini skills install https://github.com/user/repo.git --consent
# Uninstall a skill.
gemini skills uninstall my-skill --scope workspace
```
#### Command options
The skill management commands support several global and command-specific
options.
- `--scope`: Either `user` (global, default) or `workspace` (local to the
project).
- `--path`: The sub-directory within a Git repository containing the skill.
- `--consent`: Acknowledge security risks and skip the interactive confirmation
during installation.
For more details on CLI commands, see the
[CLI reference](./cli-reference.md#skills-management).
## Next steps
Explore these resources to refine your skills and understand the framework
better.
- [Get started with Agent Skills](./tutorials/skills-getting-started.md): A
quick walkthrough of triggering and using skills.
- [Creating Agent Skills](./creating-skills.md): Create your first skill and
bundle custom logic.
- [Using Agent Skills](./using-agent-skills.md): Learn how to leverage built-in
and custom skills.
- [Best practices](./skills-best-practices.md): Learn strategies for building
effective skills.
+10
View File
@@ -117,6 +117,16 @@ the following methods:
These methods will trust the current workspace for the duration of the session
without prompting.
<!-- prettier-ignore -->
> [!WARNING]
> **Never set `GEMINI_CLI_TRUST_WORKSPACE=true` or use `--skip-trust` in CI/CD
> workflows that process untrusted public inputs** (such as GitHub issues, pull
> requests, or comments). Doing so allows a malicious contributor to commit a
> crafted `.gemini/settings.json` file in their pull request, register
> arbitrary tools (including shell execution), and exfiltrate dynamically
> generated runner secrets (such as GCP service account credentials or AWS keys)
> via prompt injection.
For detailed instructions on managing folder trust within CI/CD workflows,
review the
[Gemini CLI trust guidance for GitHub Actions](https://github.com/google-github-actions/run-gemini-cli/blob/main/docs/trust-guidance.md).
+3 -3
View File
@@ -71,8 +71,8 @@ Just tell the agent to remember something.
**Prompt:** `Remember that I prefer using 'const' over 'let' wherever possible.`
The agent will use the `save_memory` tool to store this fact in your global
memory file.
The agent will edit the appropriate memory Markdown file, so the fact is loaded
in future sessions.
**Prompt:** `Save the fact that the staging server IP is 10.0.0.5.`
@@ -125,4 +125,4 @@ immediately. Force a reload with:
`/memory` options.
- Read the technical spec for [Project context](../../cli/gemini-md.md).
- Try the experimental [Auto Memory](../auto-memory.md) feature to extract
reusable skills from your past sessions automatically.
memory updates and reusable skills from your past sessions automatically.
+13
View File
@@ -61,6 +61,19 @@ gemini --list-sessions
gemini --delete-session 1
```
### Scenario: Delete session on exit
If you're doing a one-off task and don't want to leave any session history
behind, use the `--delete` flag when exiting:
```
/exit --delete
```
This removes the current session's conversation history and tool output files
before exiting. It's useful for privacy-sensitive tasks or quick one-off
interactions.
## How to rewind time (Undo mistakes)
Gemini CLI's **Rewind** feature is like `Ctrl+Z` for your workflow.
+121 -73
View File
@@ -1,110 +1,158 @@
# Get started with Agent Skills
Agent Skills extend Gemini CLI with specialized expertise. In this guide, you'll
learn how to create your first skill, bundle custom scripts, and activate them
during a session.
Agent Skills extend Gemini CLI with specialized expertise. In this tutorial,
you'll learn how to create your first skill, bundle custom logic, and activate
it during a session.
## How to create a skill
## Create your first skill
A skill is defined by a directory containing a `SKILL.md` file. Let's create an
**API Auditor** skill that helps you verify if local or remote endpoints are
responding correctly.
A skill is defined by a directory containing a `SKILL.md` file and
subdirectories containing reference materials or scripts used by the skill.
Let's create an **API Auditor** skill that runs a script to help you verify if
local or remote endpoints are responding correctly.
### Create the directory structure
### 1. Create the directory structure
1. Run the following command to create the folders:
The first step is to create the necessary folders for your skill and its
scripts.
**macOS/Linux**
**macOS/Linux**
```bash
mkdir -p .gemini/skills/api-auditor/scripts
```
```bash
mkdir -p .gemini/skills/api-auditor/scripts
```
**Windows (PowerShell)**
**Windows (PowerShell)**
```powershell
New-Item -ItemType Directory -Force -Path ".gemini\skills\api-auditor\scripts"
```
```powershell
New-Item -ItemType Directory -Force -Path ".gemini\skills\api-auditor\scripts"
```
### Create the definition
### 2. Create the definition (`SKILL.md`)
1. Create a file at `.gemini/skills/api-auditor/SKILL.md`. This tells the agent
_when_ to use the skill and _how_ to behave.
The `SKILL.md` file defines the skill's purpose and instructions for the agent.
Create a file at `.gemini/skills/api-auditor/SKILL.md`. This tells the agent
_when_ to use the skill and _how_ to behave.
```markdown
---
name: api-auditor
description:
Expertise in auditing and testing API endpoints. Use when the user asks to
"check", "test", or "audit" a URL or API.
---
```markdown
---
name: api-auditor
description:
Expertise in auditing and testing API endpoints. Use when the user asks to
"check", "test", or "audit" a URL or API.
---
# API Auditor Instructions
# API Auditor Instructions
You act as a QA engineer specialized in API reliability. When this skill is
active, you MUST:
You act as a QA engineer specialized in API reliability. When this skill is
active, you MUST:
1. **Audit**: Use the bundled `scripts/audit.js` utility to check the
status of the provided URL.
2. **Report**: Analyze the output (status codes, latency) and explain any
failures in plain English.
3. **Secure**: Remind the user if they are testing a sensitive endpoint
without an `https://` protocol.
```
1. **Audit**: Use the bundled `scripts/audit.js` utility to check the status of
the provided URL.
2. **Report**: Analyze the output (status codes, latency) and explain any
failures in plain English.
3. **Secure**: Remind the user if they are testing a sensitive endpoint without
an `https://` protocol.
```
### Add the tool logic
### 3. Add the tool logic
Skills can bundle resources like scripts.
Skills can bundle resources like scripts to perform deterministic tasks. Create
a file at `.gemini/skills/api-auditor/scripts/audit.js`. This is the code the
agent will run.
1. Create a file at `.gemini/skills/api-auditor/scripts/audit.js`. This is the
code the agent will run.
```javascript
// .gemini/skills/api-auditor/scripts/audit.js
const url = process.argv[2];
```javascript
// .gemini/skills/api-auditor/scripts/audit.js
const url = process.argv[2];
if (!url) {
console.error('Usage: node audit.js <url>');
process.exit(1);
}
if (!url) {
console.error('Usage: node audit.js <url>');
process.exit(1);
}
console.log(`Auditing ${url}...`);
fetch(url, { method: 'HEAD' })
.then((r) => console.log(`Result: Success (Status ${r.status})`))
.catch((e) => console.error(`Result: Failed (${e.message})`));
```
console.log(`Auditing ${url}...`);
fetch(url, { method: 'HEAD' })
.then((r) => console.log(`Result: Success (Status ${r.status})`))
.catch((e) => console.error(`Result: Failed (${e.message})`));
```
## Verify discovery
## How to verify discovery
Gemini CLI automatically discovers skills in the `.gemini/skills` directory (as
well as the `.agents/skills` alias).
Gemini CLI automatically discovers skills in the `.gemini/skills` directory. You
can also use `.agents/skills` as a more generic alternative. Check that it found
your new skill.
To check if Gemini CLI found your new skill, use the `/skills list` command
within an interactive session:
**Command:** `/skills list`
```bash
/skills list
```
You should see `api-auditor` in the list of available skills.
You should see `api-auditor` in the list of available skills. If you just added
the files, you can run `/skills reload` to refresh the list without restarting
the session.
### If your skill doesn't appear
If `/skills list` doesn't show your skill, check the following:
1. **The folder must be trusted (workspace skills only).** Skills under
`<workspace>/.gemini/skills/` are only loaded when the workspace folder is
marked as trusted. Run `/trust` and restart the session if needed. Skills
under `~/.gemini/skills/` (user scope) are not affected by trust.
2. **Check the path layout.** `SKILL.md` is discovered either at the root of
the skills directory (`.gemini/skills/SKILL.md`) or one directory deep
(`.gemini/skills/<skill-name>/SKILL.md`). The recommended layout uses a
subdirectory per skill so you can bundle scripts and other resources
alongside it. Files nested more than one directory deep are not discovered.
3. **The filename must be exactly `SKILL.md`.** Capitalization matters on
case-sensitive filesystems (Linux, and macOS when configured as such):
`skill.md` or `Skill.md` will be ignored.
4. **Frontmatter must include both `name:` and `description:`, and must be the
first thing in the file.** A `SKILL.md` is silently skipped if either field
is missing, if the delimiters (`---` on their own lines) are absent, or if
any text (an H1 title, a comment, even a blank line) appears before the
opening `---`.
5. **The skill name comes from the `name:` field, not the directory name.** If
your frontmatter says `name: foo`, the skill appears as `foo` in
`/skills list` regardless of what its parent directory is called. The
characters `: \ / < > * ? " |` in the name are replaced with `-`.
## How to use the skill
Now, try it out. Start a new session and ask a question that triggers the
skill's description.
Now that the skill is discovered, you can trigger its activation by asking a
relevant question.
**User:** "Can you audit http://geminicli.com"
1. **Trigger**: Start a new session and ask: "Can you audit https://google.com"
2. **Activation**: Gemini identifies that the request matches the `api-auditor`
description and calls the `activate_skill` tool.
3. **Consent**: You will see a confirmation prompt. Type **y** to approve.
4. **Execution**: Once activated, Gemini uses the `run_shell_command` tool to
execute your bundled script:
`node .gemini/skills/api-auditor/scripts/audit.js https://google.com`
Gemini recognizes the request matches the `api-auditor` description and asks for
permission to activate it.
## Pro tip: Use the skill-creator
**Model:** (After calling `activate_skill`) "I've activated the **api-auditor**
skill. I'll run the audit script now..."
If you don't want to create the files manually, you can use the built-in
`skill-creator` skill. Simply ask Gemini:
Gemini then uses the `run_shell_command` tool to execute your bundled Node
script:
> "Create a new skill called 'api-auditor' that tests if URLs are responding."
`node .gemini/skills/api-auditor/scripts/audit.js http://geminili.com`
The `skill-creator` will handle the directory structure and boilerplate for you.
## Manage skills
You can also manage skills using the `gemini skills` command from your terminal:
- **Install**: `gemini skills install <url-or-path>`
- **Link**: `gemini skills link <path>` (useful for local development)
- **Uninstall**: `gemini skills uninstall <name>`
## Next steps
- Explore the
[Agent Skills Authoring Guide](../../cli/skills.md#creating-a-skill) to learn
about more advanced features.
- Learn how to share skills via [Extensions](../../extensions/index.md).
- [Creating Agent Skills](../creating-skills.md): Detailed guide on advanced
skill features and metadata.
- [Using Agent Skills](../using-agent-skills.md): More ways to discover and
manage your skill library.
- [Skill best practices](../skills-best-practices.md): Learn how to design
reliable and effective expertise.
+89
View File
@@ -0,0 +1,89 @@
# Managing Agent Skills
Agent Skills provide Gemini CLI with specialized expertise on demand. This guide
covers advanced management techniques, including using slash commands, terminal
utilities, and understanding discovery tiers.
## Discovery tiers
Gemini CLI discovers skills from several locations, following a specific order
of precedence (lowest to highest):
1. **Built-in Skills**: Included with Gemini CLI and always available.
2. **Extension Skills**: Bundled within [extensions](../extensions/index.md).
3. **User Skills**: Located in `~/.gemini/skills/` or the `~/.agents/skills/`
alias. These are available across all your projects.
4. **Workspace Skills**: Located in `.gemini/skills/` or the `.agents/skills/`
alias within your current directory. These are project-specific.
> **Tip:** If multiple skills share the same name, the version from the
> higher-precedence location is used.
## In-session management
Use the `/skills` slash command during an interactive session to manage your
available expertise.
- **List skills**: `/skills list` (shows discovered skills).
- Use `/skills list all` to include internal built-in skills.
- Use `/skills list nodesc` to hide descriptions.
- **Reload skills**: `/skills reload` (or `/skills refresh`) to scan for new or
modified skills without restarting the CLI.
- **Toggle status**:
- `/skills disable <name>`: Prevents a skill from being triggered.
- `/skills enable <name>`: Re-enables a disabled skill.
- **Link local skills**: `/skills link <path> [--scope user|workspace]` to
immediately use a skill you are developing.
## Terminal utilities
The `gemini skills` command provides management utilities directly from your
system shell.
### Install a skill
To install a skill from a remote repository or a local `.skill` package:
```bash
gemini skills install https://github.com/user/my-awesome-skill
```
By default, this installs to your **user profile**. Use `--scope workspace` to
install it only for the current project.
### Link for development
If you are developing a skill, use the `link` command to create a reference to
your local directory:
```bash
gemini skills link ./path/to/my-skill
```
### Uninstall a skill
To completely remove an installed or linked skill:
```bash
gemini skills uninstall <name>
```
## Security and consent
Agent Skills can execute scripts and access your files. To protect your
environment:
1. **Installation consent**: When installing from a remote URL, you will be
asked to confirm the source.
2. **Activation consent**: Every time a skill is triggered during a session,
the agent must ask for permission to activate it and gain access to its
resources.
## Next steps
- [Get started with Agent Skills](./tutorials/skills-getting-started.md): A
walkthrough for creating your first skill.
- [Creating Agent Skills](./creating-skills.md): Detailed guide on bundling
scripts and assets.
- [Skill best practices](./skills-best-practices.md): Strategies for building
reliable expertise.
+83
View File
@@ -0,0 +1,83 @@
# `gemini gemma` — Automated Local Model Routing Setup
Local model routing uses a local Gemma 3 1B model running on your machine to
classify and route user requests. It routes simple requests (like file reads) to
Gemini Flash and complex requests (like architecture discussions) to Gemini Pro.
<!-- prettier-ignore -->
> [!NOTE]
> This is an experimental feature currently under active development.
## What is this?
This feature saves cloud API costs by using local inference for task
classification instead of a cloud-based classifier. It adds a few milliseconds
of local latency but can significantly reduce the overall token usage for hosted
models.
## Quick start
```bash
# One command does everything: downloads runtime, pulls model, configures settings, starts server
gemini gemma setup
```
You'll be prompted to accept the Gemma Terms of Use. The model is ~1 GB.
After setup, **just use the CLI normally** — routing happens automatically on
every request.
## Commands
| Command | What it does |
| --------------------- | -------------------------------------------------------------- |
| `gemini gemma setup` | Full install (binary + model + settings + server start) |
| `gemini gemma status` | Health check — shows what's installed and running |
| `gemini gemma start` | Start the LiteRT server (auto-starts on CLI launch by default) |
| `gemini gemma stop` | Stop the LiteRT server |
| `gemini gemma logs` | Tail the server logs to see routing requests live |
| `/gemma` | In-session status check (type it inside the CLI) |
## Verifying it works
1. Run `gemini gemma status` — all checks should show green
2. Open two terminals:
- Terminal 1: `gemini gemma logs` (watch for incoming requests)
- Terminal 2: use the CLI normally
3. You should see classification requests appear in the logs as you interact
with the CLI
4. The `/gemma` slash command inside a session shows a quick status panel
## Setup flags
```bash
gemini gemma setup --port 8080 # custom port
gemini gemma setup --no-start # don't start server after install
gemini gemma setup --force # re-download everything
gemini gemma setup --skip-model # binary only, skip the 1GB model download
```
## How it works under the hood
- Local Gemma classifies each request as "simple" or "complex" (~100ms)
- Simple → Flash, Complex → Pro
- If the local server is down, the CLI silently falls back to the cloud
classifier — no errors, no disruption
## Disabling
Set `enabled: false` in settings or just run `gemini gemma stop` to turn off the
server:
```json
{ "experimental": { "gemmaModelRouter": { "enabled": false } } }
```
## Advanced setup
If you are in an environment where the `gemini gemma setup` command cannot
automatically download binaries (for example, behind a strict corporate
firewall), you can perform the setup manually.
For more information, see the
[Manual Local Model Routing Setup guide](./local-model-routing.md).
+3 -2
View File
@@ -15,8 +15,9 @@ requests sent from `packages/cli`. For a general overview of Gemini CLI, see the
modular GEMINI.md import feature using @file.md syntax.
- **[Policy Engine](../reference/policy-engine.md):** Use the Policy Engine for
fine-grained control over tool execution.
- **[Local Model Routing (experimental)](./local-model-routing.md):** Learn how
to enable use of a local Gemma model for model routing decisions.
- **[Local Model Routing (experimental)](./gemma-setup.md):** Learn how to
enable use of a local Gemma model for model routing decisions using the
automated setup command.
## Role of the core
+14 -7
View File
@@ -1,22 +1,29 @@
# Local Model Routing (experimental)
# Manual Local Model Routing Setup (experimental)
Gemini CLI supports using a local model for
[routing decisions](../cli/model-routing.md). When configured, Gemini CLI will
use a locally-running **Gemma** model to make routing decisions (instead of
sending routing decisions to a hosted model).
<!-- prettier-ignore -->
> [!NOTE]
> This is an experimental feature currently under active development.
<!-- prettier-ignore -->
> [!IMPORTANT]
> **Recommended:** We now provide a fully automated setup command. We recommend
> using the [`gemini gemma` Setup Guide](./gemma-setup.md) instead of following
> these manual steps.
This feature can help reduce costs associated with hosted model usage while
offering similar routing decision latency and quality.
> **Note: Local model routing is currently an experimental feature.**
## Setup
## Manual Setup
Using a Gemma model for routing decisions requires that an implementation of a
Gemma model be running locally on your machine, served behind an HTTP endpoint
and accessed via the Gemini API.
To serve the Gemma model, follow these steps:
and accessed via the Gemini API. If you cannot use the `gemini gemma setup`
command, follow these manual steps:
### Download the LiteRT-LM runtime
+1 -5
View File
@@ -105,7 +105,7 @@ Gemini CLI comes with the following built-in subagents:
slow. You can invoke it explicitly using `@generalist`.
- **Configuration:** Enabled by default.
### Browser Agent (experimental)
### Browser Agent
- **Name:** `browser_agent`
- **Purpose:** Automate web browser tasks — navigating websites, filling forms,
@@ -115,10 +115,6 @@ Gemini CLI comes with the following built-in subagents:
the pricing table from this page," "Click the login button and enter my
credentials."
<!-- prettier-ignore -->
> [!NOTE]
> This is a preview feature currently under active development.
#### Prerequisites
The browser agent requires:
+16
View File
@@ -210,6 +210,22 @@ To update an extension's settings:
gemini extensions config <name> [setting] [--scope <scope>]
```
#### Environment variable sanitization
For security reasons, sensitive environment variables are filtered out and not
passed to extensions or MCP servers by default.
Extensions **will not** inherit the user's full shell environment variables.
They will only have access to:
1. Standard safe variables (e.g., `HOME`, `PATH`, `TMPDIR`).
2. Variables explicitly declared and requested in the `gemini-extension.json`
manifest via the `settings` array (using the `envVar` property).
If your extension requires specific environment variables (like an API key,
custom host, or config path), you **must** declare them in the `settings` array
so the CLI can allowlist them for use within the extension.
### Custom commands
Provide [custom commands](../cli/custom-commands.md) by placing TOML files in a
+57 -23
View File
@@ -1,7 +1,8 @@
# Release extensions
Release Gemini CLI extensions to your users through a Git repository or GitHub
Releases.
Releases. This guide explains how to share your work, list it in the gallery,
and manage updates.
Git repository releases are the simplest approach and offer the most flexibility
for managing development branches. GitHub Releases are more efficient for
@@ -153,29 +154,62 @@ jobs:
release/win32.arm64.my-tool.zip
```
## Migrating an Extension Repository
## Migrate an extension repository
If you need to move your extension to a new repository (for example, from a
personal account to an organization) or rename it, you can use the `migratedTo`
property in your `gemini-extension.json` file to seamlessly transition your
If you move your extension to a new repository or rename it, use the
`migratedTo` property in `gemini-extension.json` to seamlessly transition your
users.
1. **Create the new repository**: Setup your extension in its new location.
2. **Update the old repository**: In your original repository, update the
`gemini-extension.json` file to include the `migratedTo` property, pointing
to the new repository URL, and bump the version number. You can optionally
change the `name` of your extension at this time in the new repository.
```json
{
"name": "my-extension",
"version": "1.1.0",
"migratedTo": "https://github.com/new-owner/new-extension-repo"
}
```
3. **Release the update**: Publish this new version in your old repository.
1. **Create the new repository:** Set up your extension in its new location.
2. **Update the old repository:** In your original repository, update the
`gemini-extension.json` file to include the `migratedTo` property pointing
to the new repository URL, and increment the version number.
```json
{
"name": "my-extension",
"version": "1.1.0",
"migratedTo": "https://github.com/new-owner/new-extension-repo"
}
```
3. **Release the update:** Publish this new version in your old repository.
When users check for updates, Gemini CLI will detect the `migratedTo` field,
verify that the new repository contains a valid extension update, and
automatically update their local installation to track the new source and name
moving forward. All extension settings will automatically migrate to the new
installation.
When users check for updates, Gemini CLI detects the `migratedTo` field,
verifies the new repository, and automatically updates their local installation
to track the new source. All settings migrate automatically.
## How updates work
Gemini CLI automatically checks for extension updates based on the installation
method. Understanding these mechanisms helps you ensure your users always have
the latest version.
### Sync manifest and tags
For GitHub releases, always ensure the `version` in `gemini-extension.json`
matches your GitHub release tag. While the CLI uses tags for update detection,
it displays the manifest version in the UI. Keeping them in sync prevents
confusion.
### Update mechanisms
<details>
<summary>Technical update details</summary>
The CLI uses different strategies depending on the installation type:
- **GitHub releases:** The CLI queries the GitHub API for the latest release
tag. It ignores the `version` field in the manifest for detection.
- **Git clones:** The CLI runs `git ls-remote` to compare the latest remote
commit hash with your local `HEAD`.
- **Local extensions:** The CLI compares the `version` field in the source
directory's manifest with the installed version.
To verify an extension's installation type, inspect the `type` field in the
metadata file at `~/.gemini/extensions/<name>/.gemini-extension-install.json`.
</details>
<!-- prettier-ignore -->
> [!IMPORTANT]
> The `migratedTo` flow requires at least one release on the new repository for
> the CLI to recognize it as a valid update source.
+7
View File
@@ -159,6 +159,13 @@ When a user installs this extension, Gemini CLI will prompt them to enter the
`sensitive` is true) and injected into the MCP server's process as the
`MY_SERVICE_API_KEY` environment variable.
> **Important (Environment Variable Sanitization):** For security reasons,
> sensitive environment variables are filtered out and not passed to extensions
> or MCP servers by default. Extensions will _only_ have access to environment
> variables that are explicitly declared in the `settings` array using the
> `envVar` property, plus a few standard safe variables. Do not expect host
> environment variables to be available otherwise.
## Step 4: Link your extension
Link your extension to your Gemini CLI installation for local development.
+2 -2
View File
@@ -111,8 +111,8 @@ You can also run Gemini CLI using one of the following advanced methods:
directly. This is useful for environments where you only have Docker and want
to run the CLI.
```bash
# Run the published sandbox image
docker run --rm -it us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.1.1
# Run the published sandbox image for a specified CLI version
docker run --rm -it us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.42.0-nightly.20260428.g59b2dea0e
```
- **Using the `--sandbox` flag:** If you have Gemini CLI installed locally
(using the standard installation described above), you can instruct it to run
+29 -1
View File
@@ -154,7 +154,35 @@ and will never be auto-unassigned.
- **Unassign yourself** if you can no longer work on the issue by commenting
`/unassign`, so other contributors can pick it up right away.
### 6. Release automation
### 6. Automatically label PRs by size: `PR Size Labeler`
To help maintainers estimate review effort and keep the PR history clean, this
workflow automatically tags every pull request with a size label representing
the total volume of line changes.
- **Workflow File**: `.github/workflows/pr-size-labeler.yml`
- **When it runs**: Immediately after a pull request is created, synchronized
(new commits pushed), or reopened. It can also be triggered manually via
`workflow_dispatch` with a PR number.
- **What it does**:
- **Calculates total changes**: Summarizes additions and deletions across all
changed files in a single consolidated API request.
- **Applies standard size labels**:
- `size/XS`: < 10 lines changed
- `size/S`: 10-49 lines changed
- `size/M`: 50-249 lines changed
- `size/L`: 250-999 lines changed
- `size/XL`: >= 1000 lines changed
- **Updates size tag atomically**: Adds the new correct size label and removes
any obsolete size labels in one atomic step.
- **Updates/Posts PR size info comment**: Instead of spamming a new comment on
every commit push, it updates the existing size labeler status comment
inline to keep the PR conversation timeline perfectly neat and clean.
- **What you should do**:
- You do not need to take any actions. The workflow runs automatically and
updates the label and comment seamlessly as you push new updates.
### 7. Release automation
This workflow handles the process of packaging and publishing new versions of
Gemini CLI.
+14 -7
View File
@@ -111,6 +111,11 @@ Slash commands provide meta-level control over the CLI itself.
- **Description:** Manage custom slash commands loaded from `.toml` files.
- **Sub-commands:**
- **`list`**:
- **Description:** List available custom command `.toml` files from all
sources (user-level `~/.gemini/commands/`, project-level
`<project>/.gemini/commands/`, and active extensions).
- **Usage:** `/commands list`
- **`reload`**:
- **Description:** Reload custom command definitions from all sources
(user-level `~/.gemini/commands/`, project-level
@@ -260,9 +265,6 @@ Slash commands provide meta-level control over the CLI itself.
- **Description:** Manage the AI's instructional context (hierarchical memory
loaded from `GEMINI.md` files).
- **Sub-commands:**
- **`add`**:
- **Description:** Adds the following text to the AI's memory. Usage:
`/memory add <text to remember>`
- **`list`**:
- **Description:** Lists the paths of the GEMINI.md files in use for
hierarchical memory.
@@ -323,6 +325,11 @@ Slash commands provide meta-level control over the CLI itself.
### `/quit` (or `/exit`)
- **Description:** Exit Gemini CLI.
- **Flags:**
- **`--delete`** _(optional)_: Exit and permanently delete the current
session's history and temporary files (chat recording, tool outputs). Useful
for privacy or one-off tasks where you don't want to leave any traces.
- **Usage:** `/quit --delete` or `/exit --delete`
### `/restore`
@@ -499,12 +506,12 @@ the dedicated [Custom Commands documentation](../cli/custom-commands.md).
These shortcuts apply directly to the input prompt for text manipulation.
- **Undo:**
- **Keyboard shortcut:** Press **Alt+z** or **Cmd+z** to undo the last action
in the input prompt.
- **Keyboard shortcut:** Press **Ctrl+z** (Windows), **Cmd+z** (macOS), or
**Alt+z** (Linux/WSL) to undo the last action in the input prompt.
- **Redo:**
- **Keyboard shortcut:** Press **Shift+Alt+Z** or **Shift+Cmd+Z** to redo the
last undone action in the input prompt.
- **Keyboard shortcut:** Press **Shift+Cmd+Z** (macOS), or **Shift+Alt+Z**
(Linux/WSL) to redo the last undone action in the input prompt.
## At commands (`@`)
+293 -85
View File
@@ -105,9 +105,19 @@ their corresponding top-level category object in your `settings.json` file.
#### `general`
- **`general.preferredEditor`** (string):
- **Description:** The preferred editor to open files in.
- **`general.preferredEditor`** (enum):
- **Description:** The preferred editor to open files in. Must be one of the
built-in supported identifiers. Use /editor in the CLI to pick
interactively, or leave unset to use $VISUAL/$EDITOR.
- **Default:** `undefined`
- **Values:** `"vscode"`, `"vscodium"`, `"windsurf"`, `"cursor"`, `"zed"`,
`"antigravity"`, `"sublimetext"`, `"lapce"`, `"nova"`, `"bbedit"`, `"vim"`,
`"neovim"`, `"emacs"`, `"hx"`, `"emacsclient"`, `"micro"`
- **`general.openEditorInNewWindow`** (boolean):
- **Description:** Open VS Code-family editors in a new window when editing
files.
- **Default:** `false`
- **`general.vimMode`** (boolean):
- **Description:** Enable Vim keybindings
@@ -203,6 +213,11 @@ their corresponding top-level category object in your `settings.json` file.
chattiness and structured progress reporting.
- **Default:** `true`
- **`general.logRagSnippets`** (boolean):
- **Description:** Log full Code Customization (RAG) retrieved snippets to a
local file for debugging.
- **Default:** `false`
#### `output`
- **`output.format`** (enum):
@@ -545,6 +560,24 @@ their corresponding top-level category object in your `settings.json` file.
"model": "gemini-3-flash-preview"
}
},
"gemini-3.1-pro-preview": {
"extends": "chat-base-3",
"modelConfig": {
"model": "gemini-3.1-pro-preview"
}
},
"gemini-3.1-pro-preview-customtools": {
"extends": "chat-base-3",
"modelConfig": {
"model": "gemini-3.1-pro-preview-customtools"
}
},
"gemini-3.1-flash-lite-preview": {
"extends": "chat-base-3",
"modelConfig": {
"model": "gemini-3.1-flash-lite-preview"
}
},
"gemini-2.5-pro": {
"extends": "chat-base-2.5",
"modelConfig": {
@@ -563,6 +596,18 @@ their corresponding top-level category object in your `settings.json` file.
"model": "gemini-2.5-flash-lite"
}
},
"gemini-3.1-flash-lite": {
"extends": "chat-base-3",
"modelConfig": {
"model": "gemini-3.1-flash-lite"
}
},
"gemini-3.5-flash": {
"extends": "chat-base-3",
"modelConfig": {
"model": "gemini-3.5-flash"
}
},
"gemma-4-31b-it": {
"extends": "chat-base-3",
"modelConfig": {
@@ -587,10 +632,16 @@ their corresponding top-level category object in your `settings.json` file.
"model": "gemini-3-flash-preview"
}
},
"gemini-3.5-flash-base": {
"extends": "base",
"modelConfig": {
"model": "gemini-3.5-flash"
}
},
"classifier": {
"extends": "base",
"modelConfig": {
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"generateContentConfig": {
"maxOutputTokens": 1024,
"thinkingConfig": {
@@ -602,7 +653,7 @@ their corresponding top-level category object in your `settings.json` file.
"prompt-completion": {
"extends": "base",
"modelConfig": {
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"generateContentConfig": {
"temperature": 0.3,
"maxOutputTokens": 16000,
@@ -615,7 +666,7 @@ their corresponding top-level category object in your `settings.json` file.
"fast-ack-helper": {
"extends": "base",
"modelConfig": {
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"generateContentConfig": {
"temperature": 0.2,
"maxOutputTokens": 120,
@@ -628,7 +679,7 @@ their corresponding top-level category object in your `settings.json` file.
"edit-corrector": {
"extends": "base",
"modelConfig": {
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"generateContentConfig": {
"thinkingConfig": {
"thinkingBudget": 0
@@ -639,7 +690,7 @@ their corresponding top-level category object in your `settings.json` file.
"summarizer-default": {
"extends": "base",
"modelConfig": {
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"generateContentConfig": {
"maxOutputTokens": 2000
}
@@ -648,7 +699,7 @@ their corresponding top-level category object in your `settings.json` file.
"summarizer-shell": {
"extends": "base",
"modelConfig": {
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"generateContentConfig": {
"maxOutputTokens": 2000
}
@@ -700,6 +751,19 @@ their corresponding top-level category object in your `settings.json` file.
"extends": "gemini-3-flash-base",
"modelConfig": {}
},
"context-snapshotter": {
"extends": "gemini-3-flash-base",
"modelConfig": {
"generateContentConfig": {
"thinkingConfig": {
"thinkingLevel": "HIGH"
},
"temperature": 1,
"topP": 0.95,
"topK": 64
}
}
},
"chat-compression-3-pro": {
"modelConfig": {
"model": "gemini-3-pro-preview"
@@ -712,7 +776,7 @@ their corresponding top-level category object in your `settings.json` file.
},
"chat-compression-3.1-flash-lite": {
"modelConfig": {
"model": "gemini-3.1-flash-lite-preview"
"model": "gemini-3.1-flash-lite"
}
},
"chat-compression-2.5-pro": {
@@ -766,10 +830,10 @@ their corresponding top-level category object in your `settings.json` file.
```json
{
"gemini-3.1-flash-lite-preview": {
"gemini-3.1-flash-lite": {
"tier": "flash-lite",
"family": "gemini-3",
"isPreview": true,
"isPreview": false,
"isVisible": true,
"features": {
"thinking": false,
@@ -816,6 +880,16 @@ their corresponding top-level category object in your `settings.json` file.
"multimodalToolUse": true
}
},
"gemini-3.5-flash": {
"tier": "flash",
"family": "gemini-3",
"isPreview": false,
"isVisible": true,
"features": {
"thinking": false,
"multimodalToolUse": true
}
},
"gemini-2.5-pro": {
"tier": "pro",
"family": "gemini-2.5",
@@ -869,9 +943,10 @@ their corresponding top-level category object in your `settings.json` file.
}
},
"auto": {
"displayName": "Auto",
"tier": "auto",
"isPreview": true,
"isVisible": false,
"isVisible": true,
"features": {
"thinking": true,
"multimodalToolUse": false
@@ -905,26 +980,16 @@ their corresponding top-level category object in your `settings.json` file.
}
},
"auto-gemini-3": {
"displayName": "Auto (Gemini 3)",
"tier": "auto",
"family": "gemini-3",
"isPreview": true,
"isVisible": true,
"dialogDescription": "Let Gemini CLI decide the best model for the task: gemini-3-pro, gemini-3-flash",
"features": {
"thinking": true,
"multimodalToolUse": false
}
"isVisible": false
},
"auto-gemini-2.5": {
"displayName": "Auto (Gemini 2.5)",
"tier": "auto",
"family": "gemini-2.5",
"isPreview": false,
"isVisible": true,
"dialogDescription": "Let Gemini CLI decide the best model for the task: gemini-2.5-pro, gemini-2.5-flash",
"features": {
"thinking": false,
"multimodalToolUse": false
}
"isVisible": false
}
}
```
@@ -977,37 +1042,50 @@ their corresponding top-level category object in your `settings.json` file.
"contexts": [
{
"condition": {
"hasAccessToPreview": false
"hasAccessToPreview": false,
"useGemini3_5Flash": true
},
"target": "gemini-3.5-flash"
},
{
"condition": {
"hasAccessToPreview": false,
"useGemini3_5Flash": false
},
"target": "gemini-2.5-flash"
}
]
},
"gemini-3-pro-preview": {
"default": "gemini-3-pro-preview",
"gemini-3.5-flash": {
"default": "gemini-3.5-flash",
"contexts": [
{
"condition": {
"useGemini3_5Flash": false,
"hasAccessToPreview": false
},
"target": "gemini-2.5-pro"
"target": "gemini-2.5-flash"
},
{
"condition": {
"useGemini3_1": true,
"useCustomTools": true
"useGemini3_5Flash": false
},
"target": "gemini-3.1-pro-preview-customtools"
},
{
"condition": {
"useGemini3_1": true
},
"target": "gemini-3.1-pro-preview"
"target": "gemini-3-flash-preview"
}
]
},
"auto-gemini-3": {
"gemini-2.5-flash": {
"default": "gemini-2.5-flash",
"contexts": [
{
"condition": {
"useGemini3_5Flash": true
},
"target": "gemini-3.5-flash"
}
]
},
"gemini-3-pro-preview": {
"default": "gemini-3-pro-preview",
"contexts": [
{
@@ -1079,23 +1157,18 @@ their corresponding top-level category object in your `settings.json` file.
}
]
},
"auto-gemini-2.5": {
"default": "gemini-2.5-pro"
},
"gemini-3.1-flash-lite-preview": {
"default": "gemini-3.1-flash-lite-preview",
"contexts": [
{
"condition": {
"useGemini3_1FlashLite": false
},
"target": "gemini-2.5-flash-lite"
}
]
"gemini-3.1-flash-lite": {
"default": "gemini-3.1-flash-lite"
},
"flash": {
"default": "gemini-3-flash-preview",
"contexts": [
{
"condition": {
"useGemini3_5Flash": true
},
"target": "gemini-3.5-flash"
},
{
"condition": {
"hasAccessToPreview": false
@@ -1105,15 +1178,34 @@ their corresponding top-level category object in your `settings.json` file.
]
},
"flash-lite": {
"default": "gemini-2.5-flash-lite",
"default": "gemini-3.1-flash-lite"
},
"auto-gemini-3": {
"default": "gemini-3-pro-preview",
"contexts": [
{
"condition": {
"useGemini3_1FlashLite": true
"hasAccessToPreview": false
},
"target": "gemini-3.1-flash-lite-preview"
"target": "gemini-2.5-pro"
},
{
"condition": {
"useGemini3_1": true,
"useCustomTools": true
},
"target": "gemini-3.1-pro-preview-customtools"
},
{
"condition": {
"useGemini3_1": true
},
"target": "gemini-3.1-pro-preview"
}
]
},
"auto-gemini-2.5": {
"default": "gemini-2.5-pro"
}
}
```
@@ -1132,15 +1224,21 @@ their corresponding top-level category object in your `settings.json` file.
"contexts": [
{
"condition": {
"requestedModels": ["auto-gemini-2.5", "gemini-2.5-pro"]
"useGemini3_5Flash": true
},
"target": "gemini-3.5-flash"
},
{
"condition": {
"hasAccessToPreview": false
},
"target": "gemini-2.5-flash"
},
{
"condition": {
"requestedModels": ["auto-gemini-3", "gemini-3-pro-preview"]
"requestedModels": ["gemini-2.5-pro", "auto-gemini-2.5"]
},
"target": "gemini-3-flash-preview"
"target": "gemini-2.5-flash"
}
]
},
@@ -1149,7 +1247,13 @@ their corresponding top-level category object in your `settings.json` file.
"contexts": [
{
"condition": {
"requestedModels": ["auto-gemini-2.5", "gemini-2.5-pro"]
"hasAccessToPreview": false
},
"target": "gemini-2.5-pro"
},
{
"condition": {
"requestedModels": ["gemini-2.5-pro", "auto-gemini-2.5"]
},
"target": "gemini-2.5-pro"
},
@@ -1199,6 +1303,42 @@ their corresponding top-level category object in your `settings.json` file.
{
"model": "gemini-3-flash-preview",
"isLastResort": true,
"maxAttempts": 10,
"actions": {
"terminal": "prompt",
"transient": "prompt",
"not_found": "prompt",
"unknown": "prompt"
},
"stateTransitions": {
"terminal": "terminal",
"transient": "terminal",
"not_found": "terminal",
"unknown": "terminal"
}
}
],
"auto-preview": [
{
"model": "gemini-3-pro-preview",
"maxAttempts": 3,
"actions": {
"terminal": "prompt",
"transient": "silent",
"not_found": "prompt",
"unknown": "prompt"
},
"stateTransitions": {
"terminal": "terminal",
"transient": "sticky_retry",
"not_found": "terminal",
"unknown": "terminal"
}
},
{
"model": "gemini-3-flash-preview",
"isLastResort": true,
"maxAttempts": 10,
"actions": {
"terminal": "prompt",
"transient": "prompt",
@@ -1224,7 +1364,7 @@ their corresponding top-level category object in your `settings.json` file.
},
"stateTransitions": {
"terminal": "terminal",
"transient": "terminal",
"transient": "sticky_retry",
"not_found": "terminal",
"unknown": "terminal"
}
@@ -1232,6 +1372,42 @@ their corresponding top-level category object in your `settings.json` file.
{
"model": "gemini-2.5-flash",
"isLastResort": true,
"maxAttempts": 10,
"actions": {
"terminal": "prompt",
"transient": "prompt",
"not_found": "prompt",
"unknown": "prompt"
},
"stateTransitions": {
"terminal": "terminal",
"transient": "terminal",
"not_found": "terminal",
"unknown": "terminal"
}
}
],
"auto-default": [
{
"model": "gemini-2.5-pro",
"maxAttempts": 3,
"actions": {
"terminal": "prompt",
"transient": "silent",
"not_found": "prompt",
"unknown": "prompt"
},
"stateTransitions": {
"terminal": "terminal",
"transient": "sticky_retry",
"not_found": "terminal",
"unknown": "terminal"
}
},
{
"model": "gemini-2.5-flash",
"isLastResort": true,
"maxAttempts": 10,
"actions": {
"terminal": "prompt",
"transient": "prompt",
@@ -1248,7 +1424,7 @@ their corresponding top-level category object in your `settings.json` file.
],
"lite": [
{
"model": "gemini-2.5-flash-lite",
"model": "flash-lite",
"actions": {
"terminal": "silent",
"transient": "silent",
@@ -1680,6 +1856,12 @@ their corresponding top-level category object in your `settings.json` file.
["DEBUG", "DEBUG_MODE"]
```
- **`advanced.ignoreLocalEnv`** (boolean):
- **Description:** Whether to ignore generic .env files in the project
directory.
- **Default:** `false`
- **Requires restart:** Yes
- **`advanced.bugCommand`** (object):
- **Description:** Configuration for the bug report command.
- **Default:** `undefined`
@@ -1687,10 +1869,38 @@ their corresponding top-level category object in your `settings.json` file.
#### `experimental`
- **`experimental.gemma`** (boolean):
- **Description:** Enable access to Gemma 4 models (experimental).
- **Default:** `false`
- **Description:** Enable access to Gemma 4 models via Gemini API.
- **Default:** `true`
- **Requires restart:** Yes
- **`experimental.voiceMode`** (boolean):
- **Description:** Enable experimental voice dictation and commands (/voice,
/voice model).
- **Default:** `false`
- **`experimental.voice.activationMode`** (enum):
- **Description:** How to trigger voice recording with the Space key.
- **Default:** `"push-to-talk"`
- **Values:** `"push-to-talk"`, `"toggle"`
- **`experimental.voice.backend`** (enum):
- **Description:** The backend to use for voice transcription. Note: When
using the Gemini Live backend, voice recordings are sent to Google Cloud for
transcription.
- **Default:** `"gemini-live"`
- **Values:** `"gemini-live"`, `"whisper"`
- **`experimental.voice.whisperModel`** (enum):
- **Description:** The Whisper model to use for local transcription.
- **Default:** `"ggml-base.en.bin"`
- **Values:** `"ggml-tiny.en.bin"`, `"ggml-base.en.bin"`,
`"ggml-large-v3-turbo-q5_0.bin"`, `"ggml-large-v3-turbo-q8_0.bin"`
- **`experimental.voice.stopGracePeriodMs`** (number):
- **Description:** How long to wait for final transcription after stopping
recording.
- **Default:** `4000`
- **`experimental.adk.agentSessionNoninteractiveEnabled`** (boolean):
- **Description:** Enable non-interactive agent sessions.
- **Default:** `false`
@@ -1702,6 +1912,12 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false`
- **Requires restart:** Yes
- **`experimental.adk.agentSessionSubagentEnabled`** (boolean):
- **Description:** Route subagent invocations through the AgentSession
protocol instead of legacy executors.
- **Default:** `false`
- **Requires restart:** Yes
- **`experimental.enableAgents`** (boolean):
- **Description:** Enable local and remote subagents.
- **Default:** `true`
@@ -1738,13 +1954,6 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false`
- **Requires restart:** Yes
- **`experimental.jitContext`** (boolean):
- **Description:** Enable Just-In-Time (JIT) context loading. Defaults to
true; set to false to opt out and load all GEMINI.md files into the system
instruction up-front.
- **Default:** `true`
- **Requires restart:** Yes
- **`experimental.useOSC52Paste`** (boolean):
- **Description:** Use OSC 52 for pasting. This may be more robust than the
default system when using remote terminal sessions (if your terminal is
@@ -1807,22 +2016,17 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `"gemma3-1b-gpu-custom"`
- **Requires restart:** Yes
- **`experimental.memoryV2`** (boolean):
- **Description:** Disable the built-in save_memory tool and let the main
agent persist project context by editing markdown files directly with
edit/write_file. Route facts across four tiers: team-shared conventions go
to project GEMINI.md files, project-specific personal notes go to the
per-project private memory folder (MEMORY.md as index + sibling .md files
for detail), and cross-project personal preferences go to the global
~/.gemini/GEMINI.md (the only file under ~/.gemini/ that the agent can edit
— settings, credentials, etc. remain off-limits). Set to false to fall back
to the legacy save_memory tool.
- **Default:** `true`
- **`experimental.stressTestProfile`** (boolean):
- **Description:** Significantly lowers token limits to force early garbage
collection and distillation for testing purposes.
- **Default:** `false`
- **Requires restart:** Yes
- **`experimental.autoMemory`** (boolean):
- **Description:** Automatically extract reusable skills from past sessions in
the background. Review results with /memory inbox.
- **Description:** Automatically extract memory patches and skills from past
sessions in the background. Every change is written as a unified diff
`.patch` file under `<projectMemoryDir>/.inbox/<kind>/` and held for review
in /memory inbox; nothing is applied until you approve it.
- **Default:** `false`
- **Requires restart:** Yes
@@ -1831,6 +2035,11 @@ their corresponding top-level category object in your `settings.json` file.
- **Default:** `false`
- **Requires restart:** Yes
- **`experimental.powerUserProfile`** (boolean):
- **Description:** Less cache friendly version of the generalist profile.
- **Default:** `false`
- **Requires restart:** Yes
- **`experimental.contextManagement`** (boolean):
- **Description:** Enable logic for context management.
- **Default:** `false`
@@ -2476,7 +2685,6 @@ for that specific session.
- **Note:** For structured output and scripting, use the
`--output-format json` or `--output-format stream-json` flag.
- **`--prompt <your_prompt>`** (**`-p <your_prompt>`**):
- **Deprecated:** Use positional arguments instead.
- Used to pass a prompt directly to the command. This invokes Gemini CLI in a
non-interactive mode.
- **`--prompt-interactive <your_prompt>`** (**`-i <your_prompt>`**):

Some files were not shown because too many files have changed in this diff Show More