# google-gemini/gemini-cli — codebase unpack

> Canonical page: https://codevetter.com/unpack/gemini-cli

This is a deterministic Repo Unpack scan of google-gemini/gemini-cli — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: d5b3e3accb26000d273abf16e0f1dd83aa5428a9 (2026-09-21)
- Last upstream commit: fix(cli): emit tool_call update prior to request_permission in ACP mode (#29439)
- Generated by codevetter 1.12.0 on 2026-09-22
- 2974 files scanned · 25.0 MB

## Languages

- TypeScript: 2173 files
- Markdown: 170 files
- JavaScript: 72 files
- YAML: 71 files
- JSON: 55 files
- Python: 49 files
- TOML: 24 files
- Shell: 10 files

## Repository structure

- packages/ — 2329 files
- integration-tests/ — 120 files
- tools/ — 117 files
- docs/ — 101 files
- scripts/ — 83 files
- .github/ — 73 files
- evals/ — 47 files
- .gemini/ — 46 files

Probable source entrypoint: `packages/` (inferred from the tree, not upstream docs)

## Package

- package.json: @google/gemini-cli v0.62.0-nightly.20260918.g9450ade79 — 58 declared dependencies

## Structural health signals

Average score 6.2/10 across 96 files; 68 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- d5b3e3accb26 (2026-09-21) fix(cli): emit tool_call update prior to request_permission in ACP mode (#29439)
- 04e39e5dc44f (2026-09-21) fix(core): normalize proxy-agent esbuild interop for environment proxy resolution (#29401)
- cfbcaa8df13e (2026-09-18) fix(core): update auth error documentation link to valid anchor and add fallback (#26140) (#29377)
- e5b668033288 (2026-09-18) fix(vscode-ide-companion): preserve terminal focus when closing diff tabs (#29378)
- 196c772a9701 (2026-09-18) fix(core,cli): improve terminal buffer memory management and format Windows diagnostic paths (#29380)

## Overview

Gemini CLI is Google's open-source terminal agent for the Gemini models: an npm-workspaces monorepo whose main artifact is the `gemini` binary (packages/cli on Ink/React for the TUI, packages/core for the agent loop, tools, policy engine, MCP client, and telemetry). It runs a two-process startup (a lightweight parent that respawns a heavy child with tuned V8 flags), supports interactive and non-interactive/headless modes, an ACP stdio bridge for editors, an A2A HTTP server, an SDK package, and a VS Code companion extension. Its distinctive features are a TOML-driven policy engine gating every tool call, a hook system that can intercept agent/model/tool lifecycle events, and git-checkpointing plus JSONL session recording for rewind/resume.

## System map

The repo is an npm workspaces monorepo (Node >=20, ESM, TypeScript 5.8) with the runtime split between packages/cli (Ink/React TUI, arg parsing, settings, extensions, sandboxing, ACP) and packages/core (agentic loop, tool registry, scheduler, policy engine, hooks, MCP client, telemetry). Secondary packages are a2a-server (Express A2A endpoint), sdk (programmatic sessions), vscode-ide-companion (IDE bridge), devtools (Vite React activity viewer), and test-utils. The shipped binary is produced by esbuild into bundle/gemini.js via the root `bundle` script. Runtime state lives under ~/.gemini (or GEMINI_CLI_HOME) via the Storage class; external integrations include the Gemini API / Code Assist / Vertex AI backends, arbitrary MCP servers, IDE companions over a local server, and git for worktrees/checkpointing.
- The published `gemini` bin is bundle/gemini.js, built by `npm run bundle` which runs esbuild.config.js after generating git-commit info and bundling devtools; per-package `npm run build` uses scripts/build_package.js. — [package.json#L47](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L47) [package.json#L92-94](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L92-L94) [esbuild.config.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/esbuild.config.js) [scripts/build.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/scripts/build.js)
- The true process entrypoint is packages/cli/index.ts run(): unless GEMINI_CLI_NO_RELAUNCH or SANDBOX is set it stays a lightweight parent that spawns `process.execPath` with IPC for admin-settings messages and loops on RELAUNCH_EXIT_CODE; only the child dynamically imports src/gemini.js main(). — [packages/cli/index.ts#L54-163](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/index.ts#L54-L163) [packages/cli/src/utils/processUtils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/processUtils.ts)
- packages/cli/src/gemini.tsx main() is the heavy child orchestrator: patchStdio, unhandled-rejection/uncaught-exception handlers, loadSettings, optional worktree setup (process.chdir), parseArguments (yargs), resolveSessionId, loadCliConfig, refreshAuth, optional sandbox relaunch, then interactive UI or runNonInteractive. — [packages/cli/src/gemini.tsx#L466-1004](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L466-L1004) [packages/cli/src/config/config.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/config.ts)
- packages/core exposes its surface through src/index.ts; the Config class (config.ts, ~4200 lines) is the central god-object implementing McpContext and AgentLoopContext and owning the ToolRegistry, GeminiClient, McpClientManager, PolicyEngine, MessageBus, Storage, and HookSystem. — [packages/core/src/index.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/index.ts) [packages/core/src/config/config.ts#L753-756](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L753-L756)
- Config._initialize() wires the runtime in order: storage, workspace context dirs, PromptRegistry/ResourceRegistry, AgentRegistry, createToolRegistry(), McpClientManager (started non-blockingly unless non-interactive/ACP), skills discovery, HookSystem, MemoryContextManager, and geminiClient.initialize(). — [packages/core/src/config/config.ts#L1450-1564](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L1450-L1564)
- The agentic core is GeminiClient.sendMessageStream → Turn.run → GeminiChat.sendMessageStream, yielding typed ServerGeminiStreamEvent values (Content, Thought, ToolCallRequest, Finished, LoopDetected, InvalidStream, AgentExecutionStopped/Blocked, ...). — [packages/core/src/core/client.ts#L910-1061](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L910-L1061) [packages/core/src/core/turn.ts#L55-74](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/turn.ts#L55-L74) [packages/core/src/core/turn.ts#L270-399](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/turn.ts#L270-L399) [packages/core/src/core/geminiChat.ts#L372](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/geminiChat.ts#L372)
- Model access is abstracted behind the ContentGenerator interface; createContentGenerator() picks FakeContentGenerator (test replay), Code Assist (OAuth/ADC via createCodeAssistContentGenerator wrapped in ModelMappingContentGenerator+LoggingContentGenerator), or @google/genai GoogleGenAI for API-key/Vertex/Gateway auth, with proxy agents, custom headers, and Vertex REP endpoints for us/eu. — [packages/core/src/core/contentGenerator.ts#L39-70](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L39-L70) [packages/core/src/core/contentGenerator.ts#L210-422](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L210-L422) [packages/core/src/code_assist/codeAssist.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/code_assist/codeAssist.ts)
- Cross-layer signaling uses two buses: coreEvents, a process-wide EventEmitter with a CoreEvent enum (UserFeedback, Output, ConsoleLog, ModelChanged, ConsentRequest, ...), and a MessageBus (confirmation-bus) that carries tool-confirmation and policy-update messages to the UI. — [packages/core/src/utils/events.ts#L196-221](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/utils/events.ts#L196-L221) [packages/core/src/confirmation-bus/message-bus.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/confirmation-bus/message-bus.ts) [packages/core/src/scheduler/scheduler.ts#L44-55](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/scheduler.ts#L44-L55)
- Persistent state is rooted at ~/.gemini (GEMINI_DIR, overridable via GEMINI_CLI_HOME or tmpdir on some paths) managed by the Storage class; per-project data is namespaced by a hash of the project root. — [packages/core/src/config/storage.ts#L57-105](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/storage.ts#L57-L105) [packages/core/src/config/storage.ts#L204](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/storage.ts#L204) [packages/cli/index.ts#L26-28](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/index.ts#L26-L28)
- packages/a2a-server is a separate Express app exposing an A2A-protocol agent card ('Gemini SDLC Agent') with bearer/basic auth schemes and pluggable TaskStore (InMemory/GCS/NoOp), reusing core via @google/gemini-cli-core. — [packages/a2a-server/src/http/app.ts#L45-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/a2a-server/src/http/app.ts#L45-L120) [packages/a2a-server/src/index.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/a2a-server/src/index.ts) [packages/a2a-server/src/persistence/gcs.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/a2a-server/src/persistence/gcs.ts)
- packages/sdk re-exports agent/session/tool/skills/fs helpers as a programmatic API, and packages/vscode-ide-companion runs an ide-server plus diff-manager/open-files-manager that the core connects to via IdeClient. — [packages/sdk/src/index.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/sdk/src/index.ts) [packages/sdk/src/session.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/sdk/src/session.ts) [packages/vscode-ide-companion/src/ide-server.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/vscode-ide-companion/src/ide-server.ts) [packages/core/src/ide/ide-client.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/ide/ide-client.ts)
- OS sandboxing is a first-class runtime boundary: the CLI can relaunch itself inside Docker/Podman images or macOS Seatbelt profiles (BUILTIN_SEATBELT_PROFILES/*.sb files) before doing expensive init, and per-command sandboxing is mediated by sandboxManager.prepareCommand in tools. — [packages/cli/src/gemini.tsx#L684-737](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L684-L737) [packages/cli/src/utils/sandbox.ts#L55-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandbox.ts#L55-L120) [packages/cli/src/utils/sandboxUtils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandboxUtils.ts) [packages/core/src/services/sandboxManager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/sandboxManager.ts) [packages/core/src/tools/tool-registry.ts#L404-416](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-registry.ts#L404-L416)

## Feature catalog

User-facing surface is broad: a yargs-driven CLI with subcommands (mcp, extensions, skills, hooks, gemma) plus ~45 built-in slash commands, custom TOML commands, and MCP-prompt commands. The agent can call ~20 built-in tools (file IO, shell, grep/glob/ripgrep, web fetch/search, todos, plan mode, tracker tasks, skills, subagents incl. a browser agent). Auth supports Google OAuth, Gemini API key, Vertex AI, compute ADC, and gateway modes. Features include session resume/checkpointing/rewind, GEMINI.md hierarchical memory, hooks, policies, extensions, skills, ACP editor mode, A2A server, voice mode, IDE integration, worktrees, and multiple output formats (text/json/stream-json).
- CLI flags are defined with yargs in parseArguments: --model, --prompt/-p (headless), --prompt-interactive/-i, --sandbox, --yolo, --approval-mode, --policy, --admin-policy, --acp, --allowed-tools, --allowed-mcp-server-names, --extensions, --resume, --session-id, --session-file, --list-sessions, --delete-session, --include-directories, --output-format, --fake-responses, --record-responses, --raw-output, plus positional query. — [packages/cli/src/config/config.ts#L282-495](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/config.ts#L282-L495)
- Five yargs subcommands are registered alongside the default '$0 [query..]' launcher: mcpCommand, extensionsCommand, skillsCommand, hooksCommand, gemmaCommand. — [packages/cli/src/config/config.ts#L275-282](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/config.ts#L275-L282) [packages/cli/src/commands/mcp.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/commands/mcp.ts) [packages/cli/src/commands/extensions.tsx](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/commands/extensions.tsx) [packages/cli/src/commands/skills.tsx](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/commands/skills.tsx)
- BuiltinCommandLoader registers ~45 slash commands (/about /agents /auth /bug /chat /clear /compress /copy /directory /docs /editor /extensions /help /hooks /ide /init /mcp /memory /model /permissions /plan /policies /privacy /quit /restore /resume /stats /theme /tools /skills /settings /tasks /vim /rewind ...), many gated by config flags such as isAgentsEnabled, isPlanEnabled, isSkillsSupportEnabled, getFolderTrust, or nightly/dev builds. — [packages/cli/src/services/BuiltinCommandLoader.ts#L123-242](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/BuiltinCommandLoader.ts#L123-L242)
- Config.createToolRegistry registers the built-in tool set conditionally via maybeRegister (honoring the coreTools allowlist): UpdateTopic, LS, ReadFile, RipGrep-or-Grep fallback, Glob, ActivateSkill, Edit, WriteFile, WebFetch, ReadMcpResource, ListMcpResources, Shell, background-process tools, WebSearch, AskUser, WriteTodos, Enter/ExitPlanMode, Tracker* tools, and AgentTool. — [packages/core/src/config/config.ts#L3932-4087](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L3932-L4087) [packages/core/src/tools/tool-names.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-names.ts)
- Six AuthType values are supported (oauth-personal LOGIN_WITH_GOOGLE, gemini-api-key, vertex-ai, legacy cloud-shell, compute-default-credentials, gateway); getAuthTypeFromEnv auto-detects via GOOGLE_GENAI_USE_GCA, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GEMINI_BASE_URL, GEMINI_API_KEY, CLOUD_SHELL/GEMINI_CLI_USE_COMPUTE_ADC. — [packages/core/src/core/contentGenerator.ts#L63-100](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L63-L100)
- Sessions are recorded as JSONL files named session-<ts>-<id>.jsonl under the project's temp 'chats' dir; they can be resumed via --resume/--session-id, imported via --session-file (filtering to user/gemini messages), listed via --list-sessions, and deleted via --delete-session. — [packages/cli/src/gemini.tsx#L336-407](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L336-L407) [packages/cli/src/gemini.tsx#L799-826](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L799-L826) [packages/core/src/services/chatRecordingService.ts#L28-40](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/chatRecordingService.ts#L28-L40)
- Custom slash commands are user-defined TOML files (required 'prompt', optional 'description' per TomlCommandDefSchema) scanned from user, project, and extension command dirs by FileCommandLoader, with !{...} shell injection and @file injection prompt processors that can require confirmation. — [packages/cli/src/services/FileCommandLoader.ts#L55-90](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/FileCommandLoader.ts#L55-L90) [packages/cli/src/services/prompt-processors/shellProcessor.ts#L24-53](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/prompt-processors/shellProcessor.ts#L24-L53) [docs/cli/custom-commands.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/cli/custom-commands.md)
- MCP servers from settings/extensions are connected by McpClientManager during Config._initialize; MCP prompts become slash commands via McpPromptLoader and MCP tools enter the ToolRegistry as DiscoveredMCPTool instances. — [packages/core/src/config/config.ts#L1506-1531](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L1506-L1531) [packages/core/src/tools/mcp-client-manager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/mcp-client-manager.ts) [packages/core/src/tools/mcp-tool.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/mcp-tool.ts) [packages/cli/src/services/McpPromptLoader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/McpPromptLoader.ts)
- An extension system (ExtensionManager) installs/loads extensions from git clones or GitHub releases, hydrates variables, manages consent and per-extension settings/env files, contributes MCP servers, commands, agents, skills, hooks, themes, and TOML policies, and enforces admin allowlists and integrity checks. — [packages/cli/src/config/extension-manager.ts#L1-110](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extension-manager.ts#L1-L110) [packages/cli/src/config/extensions/github.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extensions/github.ts) [packages/cli/src/config/extensions/consent.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extensions/consent.ts) [docs/extensions/index.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/extensions/index.md)
- A hook system (HookSystem/HookRegistry/HookRunner/HookAggregator/HookPlanner) fires lifecycle events — SessionStart/End, Before/AfterAgent, Before/AfterModel, BeforeToolSelection, Before/AfterTool — whose outputs can inject context, block/stop execution, synthesize model responses, or modify tool/config. — [packages/core/src/hooks/hookSystem.ts#L38-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/hooks/hookSystem.ts#L38-L120) [packages/core/src/hooks/hookRegistry.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/hooks/hookRegistry.ts) [packages/cli/src/gemini.tsx#L937-958](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L937-L958) [docs/hooks/index.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/hooks/index.md)
- Subagents are a feature: AgentRegistry loads local agent definitions (built-ins include CodebaseInvestigatorAgent, CliHelpAgent, GeneralistAgent, BrowserAgentDefinition) plus remote A2A agents, exposes them through AgentTool, and supports hot reload with new/updated/deleted summaries. — [packages/core/src/agents/registry.ts#L50-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/registry.ts#L50-L120) [packages/core/src/agents/agent-tool.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/agent-tool.ts) [packages/core/src/agents/codebase-investigator.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/codebase-investigator.ts) [docs/core/subagents.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/core/subagents.md)
- ACP mode (--acp) runs the CLI as an Agent Client Protocol stdio server via runAcpClient with session management, RPC dispatch, and a filesystem bridge for editor clients such as Zed. — [packages/cli/src/acp/acpStdioTransport.ts#L15](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/acp/acpStdioTransport.ts#L15) [packages/cli/src/acp/acpSessionManager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/acp/acpSessionManager.ts) [packages/cli/src/acp/acpFileSystemService.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/acp/acpFileSystemService.ts) [docs/cli/acp-mode.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/cli/acp-mode.md) [packages/cli/src/gemini.tsx#L874-876](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L874-L876)
- Headless mode supports three output formats — TEXT (ANSI-stripped via stripAnsi unless --raw-output), JSON (JsonFormatter with stats), and STREAM_JSON (StreamJsonFormatter emitting INIT/MESSAGE/TOOL_USE/TOOL_RESULT/ERROR/RESULT events). — [packages/cli/src/nonInteractiveCli.ts#L65-72](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L65-L72) [packages/cli/src/nonInteractiveCli.ts#L118-121](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L118-L121) [packages/cli/src/nonInteractiveCli.ts#L252-260](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L252-L260) [docs/cli/headless.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/cli/headless.md)
- Hierarchical memory loads GEMINI.md-style context files discovered upward/downward from the project (memoryDiscovery), surfaced through MemoryContextManager and the /memory command, with a memoryTool letting the model save facts. — [packages/core/src/utils/memoryDiscovery.ts#L248-458](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/utils/memoryDiscovery.ts#L248-L458) [packages/core/src/config/memory.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/memory.ts) [packages/core/src/tools/memoryTool.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/memoryTool.ts) [docs/cli/gemini-md.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/cli/gemini-md.md)
- Additional user-facing features include git worktree startup (--worktree via setupWorktree which chdirs before config load), checkpointing/rewind via GitService, a local Gemma model router (LiteRtServerManager, user-scope-only binary path), voice mode transcription providers, and IDE context sharing with the VS Code companion. — [packages/cli/src/gemini.tsx#L496-505](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L496-L505) [packages/cli/src/gemini.tsx#L848-863](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L848-L863) [packages/core/src/config/config.ts#L3835](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L3835) [packages/core/src/voice/transcriptionFactory.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/voice/transcriptionFactory.ts) [packages/cli/src/utils/worktreeSetup.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/worktreeSetup.ts) [docs/cli/git-worktrees.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/cli/git-worktrees.md)

## Data flow

Input enters via argv/stdin, is merged with layered settings.json files (system → user → workspace, plus remote admin controls over IPC), then Config becomes the single state owner for the session. A prompt flows through slash-command and @-file processors into Part[] arrays, into GeminiClient.sendMessageStream → Turn → GeminiChat → ContentGenerator → the Gemini/Code Assist/Vertex HTTP stream. Streamed chunks become typed events; ToolCallRequest events are drained into the Scheduler which runs policy checks, user confirmation over the MessageBus, hooks, then the ToolExecutor; tool results are appended as functionResponse parts and recorded into chat history plus the JSONL session file, looping until a Finished/Stopped event. Output exits via coreEvents.Output/TextOutput/StreamJsonFormatter or the Ink UI.
- Settings data flow: loadSettings() reads layered settings.json (system path /etc/gemini-cli or OS equivalents, user ~/.gemini/settings.json, workspace .gemini/settings.json), interpolates env vars (resolveEnvVarsInObject), merges with customDeepMerge per schema mergeStrategy, and validates against the generated settingsSchema. — [packages/cli/src/config/settings.ts#L82-117](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/settings.ts#L82-L117) [packages/cli/src/config/settingsSchema.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/settingsSchema.ts) [packages/cli/src/utils/envVarResolver.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/envVarResolver.ts) [packages/cli/src/utils/deepMerge.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/deepMerge.ts)
- Remote admin/enterprise controls flow over Node IPC: the parent process forwards {type:'admin-settings'} messages to the child, which calls config.setRemoteAdminSettings; the child pushes 'admin-settings-update' back after refreshAuth fetches CCPA admin settings. — [packages/cli/index.ts#L63-87](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/index.ts#L63-L87) [packages/cli/src/gemini.tsx#L1057-1088](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L1057-L1088) [packages/cli/src/gemini.tsx#L669-679](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L669-L679)
- Prompt ingress in headless mode: stdin (readStdin) is prepended to --prompt input, SessionStart hook context is wrapped in <hook_context> tags and prepended, then slash commands (isSlashCommand → handleSlashCommand) or @-commands (handleAtCommand) convert text into Part[] before entering the loop. — [packages/cli/src/gemini.tsx#L927-966](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L927-L966) [packages/cli/src/nonInteractiveCli.ts#L262-311](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L262-L311) [packages/cli/src/ui/hooks/atCommandProcessor.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/hooks/atCommandProcessor.ts) [packages/cli/src/nonInteractiveCliCommands.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCliCommands.ts)
- Per turn, GeminiClient.sendMessageStream resets turn state, runs BeforeAgent hooks (can stop/block/inject additionalContext), then delegates to Turn.run which streams GeminiChat responses; GeminiChat wraps the API call in retryWithBackoff and raises InvalidStreamError for empty/malformed/safety-blocked streams. — [packages/core/src/core/client.ts#L910-970](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L910-L970) [packages/core/src/core/turn.ts#L270-320](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/turn.ts#L270-L320) [packages/core/src/core/geminiChat.ts#L311-337](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/geminiChat.ts#L311-L337) [packages/core/src/core/geminiChat.ts#L1113](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/geminiChat.ts#L1113) [packages/core/src/core/geminiChat.ts#L1576-1602](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/geminiChat.ts#L1576-L1602)
- Tool-call data flow: resp.functionCalls become ToolCallRequestInfo via Turn.handlePendingFunctionCall → ToolCallRequest events; the consumer collects them and calls Scheduler.schedule, which runs checkPolicy/policy engine, resolveConfirmation over the MessageBus, BeforeTool hooks (evaluateBeforeToolHook), ToolModificationHandler, then ToolExecutor, producing CompletedToolCall with ToolCallResponseInfo. — [packages/core/src/core/turn.ts#L380-387](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/turn.ts#L380-L387) [packages/cli/src/nonInteractiveCli.ts#L482-545](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L482-L545) [packages/core/src/scheduler/scheduler.ts#L95-130](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/scheduler.ts#L95-L130) [packages/core/src/scheduler/confirmation.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/confirmation.ts) [packages/core/src/scheduler/tool-executor.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/tool-executor.ts)
- Tool responses re-enter the model loop as functionResponse parts appended to currentMessages; recordCompletedToolCalls persists metadata into GeminiChat history and recordToolCallInteractions logs telemetry before the next sendMessageStream iteration, bounded by getMaxSessionTurns(). — [packages/cli/src/nonInteractiveCli.ts#L488-544](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L488-L544) [packages/cli/src/nonInteractiveCli.ts#L311-332](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L311-L332) [packages/core/src/core/client.ts#L79](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L79)
- Policy decisions are computed by a tiered TOML rule engine: directories ordered Default → Extension → Workspace → User → Admin map to priority tiers 1-5 with fractional offsets for flags like --allowed-tools, coreTools, and trusted/allowed MCP servers; rules yield PolicyDecision allow/ask_user/deny consumed by the scheduler. — [packages/core/src/policy/config.ts#L66-110](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/config.ts#L66-L110) [packages/core/src/policy/policy-engine.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/policy-engine.ts) [packages/core/src/policy/toml-loader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/toml-loader.ts) [packages/core/src/scheduler/policy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/policy.ts)
- Session persistence is an append-only JSONL transcript: ConversationRecord header line followed by MessageRecord/MetadataUpdateRecord/RewindRecord lines written to ~/.gemini/tmp/<projectHash>/chats/session-*.jsonl by ChatRecordingService, with ENOSPC graceful degradation. — [packages/core/src/services/chatRecordingService.ts#L28-98](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/chatRecordingService.ts#L28-L98) [packages/cli/src/gemini.tsx#L371-391](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L371-L391)
- The system prompt is assembled by getCoreSystemPrompt(config, userMemory) via a PromptProvider, combining environment context (getDirectoryContextString), GEMINI.md memory, and model-family-specific tool declarations resolved per model in tools/definitions. — [packages/core/src/core/prompts.ts#L23-31](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/prompts.ts#L23-L31) [packages/core/src/core/client.ts#L1077-1078](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L1077-L1078) [packages/core/src/utils/environmentContext.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/utils/environmentContext.ts) [packages/core/src/tools/definitions/resolver.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/definitions/resolver.ts) [packages/core/src/tools/definitions/model-family-sets](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/definitions/model-family-sets)
- Context-window management: token counts are estimated per request (calculateRequestTokenCount, tokenLimit) and ChatCompressionService compresses history (emitting ChatCompressed events); LoopDetectionService watches for repetitive turns and yields LoopDetected; ContextManager/AgentHistoryProvider/ToolOutputMaskingService manage what history the model sees. — [packages/core/src/core/client.ts#L97-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L97-L120) [packages/core/src/context/chatCompressionService.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/context/chatCompressionService.ts) [packages/core/src/services/loopDetectionService.ts#L133](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/loopDetectionService.ts#L133) [packages/core/src/core/tokenLimits.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/tokenLimits.ts)
- Output egress is centralized through patchStdio + coreEvents: initializeOutputListenersAndFlush drains backlogged Output/ConsoleLog/UserFeedback events to stdout/stderr, forcing stdout payloads to stderr when outputFormat is 'json' so machine output stays parseable; ConsolePatcher reroutes console.* into the same bus for the UI. — [packages/cli/src/gemini.tsx#L1006-1055](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L1006-L1055) [packages/cli/src/ui/utils/ConsolePatcher.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/utils/ConsolePatcher.ts) [packages/cli/src/nonInteractiveCli.ts#L85-103](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L85-L103)
- IDE context flows in from the vscode-ide-companion over a local connection managed by IdeClient into ideContextStore; GeminiClient diffs lastSentIdeContext vs current (forceFullIdeContext flag) to inject file/selection context into requests. (inferred) — [packages/core/src/ide/ide-client.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/ide/ide-client.ts) [packages/core/src/ide/ideContext.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/ide/ideContext.ts) [packages/core/src/core/client.ts#L104-105](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L104-L105) [packages/vscode-ide-companion/src/ide-server.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/vscode-ide-companion/src/ide-server.ts)

## Behavior traces

Traced three flows end-to-end. (1) Startup: parent spawn → settings → args → session resolution → partial config → auth → optional sandbox relaunch → full config init → interactive Ink UI or headless loop. (2) Headless agentic turn: input normalization → hooks → GeminiClient stream → Turn/GeminiChat → tool requests → Scheduler (policy→confirm→hooks→execute) → responses fed back until Finished. (3) Session persistence/resume: JSONL transcript written per message/tool call and rehydrated via SessionSelector or imported from file.
- Startup trace (parent): `gemini` bin → packages/cli/index.ts run() → getMemoryNodeArgs() reads ~/.gemini/settings.json for advanced.autoConfigureMemory → getSpawnConfig() → spawn child node with same args + IPC channel → forward admin-settings → on child close, exit with code unless code === RELAUNCH_EXIT_CODE, then respawn. — [packages/cli/index.ts#L20-116](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/index.ts#L20-L116) [packages/cli/src/utils/processUtils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/processUtils.ts) [packages/cli/src/utils/relaunch.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/relaunch.ts)
- Startup trace (child): gemini.tsx main() → setupAdminControlsListener → patchStdio → setupUnhandledRejectionHandler/setupSignalHandlers → SlashCommandConflictHandler.start → loadSettings → optional setupWorktree → parseArguments → resolveSessionId → ConsolePatcher.patch → loadCliConfig (partial, skipExtensions) → validateAuthMethod/validateNonInteractiveAuth → partialConfig.refreshAuth → remote admin settings propagation. — [packages/cli/src/gemini.tsx#L466-682](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L466-L682) [packages/cli/src/config/auth.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/auth.ts) [packages/cli/src/validateNonInterActiveAuth.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/validateNonInterActiveAuth.ts)
- Startup trace (sandbox hop): if SANDBOX env is unset and not a subcommand, loadSandboxConfig decides; when configured, piped stdin is read and injected into argv as --prompt, then relaunchOnExitCode(start_sandbox(...)) re-executes the CLI inside Docker/Podman/Seatbelt and the outer process exits SUCCESS. — [packages/cli/src/gemini.tsx#L684-737](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L684-L737) [packages/cli/src/utils/sandbox.ts#L55-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandbox.ts#L55-L120) [packages/cli/src/config/sandboxConfig.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/sandboxConfig.ts)
- Startup trace (post-sandbox): full loadCliConfig → config.storage.initialize → createPolicyUpdater(policyEngine, messageBus, storage) → registerCleanup(SessionEnd hook + ConsolePatcher) → flag handlers (--list-extensions/--list-sessions/--delete-session exit early) → setRawMode → setupTerminalAndTheme → initializeApp(config, settings) which auths, connects IdeClient, validates theme, counts GEMINI.md files → startInteractiveUI dynamically imports interactiveCli.js (React/Ink lazy-loaded). — [packages/cli/src/gemini.tsx#L742-922](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L742-L922) [packages/cli/src/core/initializer.ts#L19-50](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/core/initializer.ts#L19-L50) [packages/cli/src/config/policy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/policy.ts) [packages/cli/src/interactiveCli.tsx](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/interactiveCli.tsx)
- Headless turn trace: runNonInteractive → promptIdContext.run → ConsolePatcher + TextOutput + Ctrl+C readline keypress abort → new Scheduler({context: config, messageBus}) → optional geminiClient.resumeChat → handleSlashCommand/handleAtCommand → loop: geminiClient.sendMessageStream(parts, signal, prompt_id) → for-await events → collect ToolCallRequest → scheduler.schedule → completedToolCalls → append responseParts to history → next iteration until no tool calls / Finished / stopped. — [packages/cli/src/nonInteractiveCli.ts#L72-180](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L72-L180) [packages/cli/src/nonInteractiveCli.ts#L234-332](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L234-L332) [packages/cli/src/nonInteractiveCli.ts#L482-545](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L482-L545)
- Model-stream trace inside core: sendMessageStream → fireBeforeAgentHookSafe (may yield AgentExecutionStopped/Blocked or inject <hook_context>) → processTurn loop → Turn.run → chat.sendMessageStream(modelConfigKey, req, prompt_id, signal, role) → retryWithBackoff around apiCall → per-chunk parse: thought parts → Thought events, text → Content, functionCalls → ToolCallRequest, finishReason → Finished(+citations), citations tracked across chunks. — [packages/core/src/core/client.ts#L930-971](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L930-L971) [packages/core/src/core/turn.ts#L270-399](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/turn.ts#L270-L399) [packages/core/src/core/geminiChat.ts#L480-725](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/geminiChat.ts#L480-L725)
- Tool-execution trace inside Scheduler: schedule() enqueues SchedulerQueueItem → SchedulerStateManager tracks call lifecycle (validating → awaiting approval → executing → success/error) → checkPolicy consults PolicyEngine (deny short-circuits) → resolveConfirmation publishes ToolConfirmationRequest on the MessageBus for UI approval → evaluateBeforeToolHook may block/modify → ToolExecutor runs the ToolInvocation → ToolCallEvent telemetry logged → CompletedToolCall resolved. (inferred) — [packages/core/src/scheduler/scheduler.ts#L57-130](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/scheduler.ts#L57-L130) [packages/core/src/scheduler/state-manager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/state-manager.ts) [packages/core/src/scheduler/policy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/policy.ts) [packages/core/src/scheduler/confirmation.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/confirmation.ts) [packages/core/src/scheduler/hook-utils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/hook-utils.ts) [packages/core/src/scheduler/tool-executor.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/tool-executor.ts)
- Shell tool trace: model calls run_shell_command → ShellToolInvocation → command parsing via initializeShellParsers/getCommandRoots/stripShellWrapper/detectCommandSubstitution → policy check on root commands → confirmation showing command+roots → ShellExecutionService.execute prefers node-pty (getPty) with childProcessFallback → streamed ShellOutputEvents, live output buffer trimmed at 100k chars, background commands wrapped with EXIT-trap PID capture. — [packages/core/src/tools/shell.ts#L102-140](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/shell.ts#L102-L140) [packages/core/src/utils/shell-utils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/utils/shell-utils.ts) [packages/core/src/services/shellExecutionService.ts#L431-475](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/shellExecutionService.ts#L431-L475)
- Session resume trace: --resume → SessionSelector(storage).resolveSession picks or lists JSONL transcripts → ResumedSessionData {conversation, filePath} → in headless mode geminiClient.resumeChat(convertSessionToClientHistory(messages)) rehydrates GeminiChat history; --session-file instead imports an external record, filters to user/gemini messages, mints a new sessionId, and writes a fresh session-*.jsonl. — [packages/cli/src/gemini.tsx#L319-444](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L319-L444) [packages/cli/src/nonInteractiveCli.ts#L242-250](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L242-L250) [packages/core/src/core/client.ts#L339-343](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L339-L343) [packages/cli/src/utils/sessionUtils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sessionUtils.ts)
- AfterAgent continuation trace: when hooks are enabled and no pending tools, fireAfterAgentHookSafe runs; a blocking decision yields AgentExecutionBlocked, decrements hookState.activeCalls, then recursively calls sendMessageStream with the hook's reason as the new request and stopHookActive=true — an internal agentic continuation invisible to the UI loop. — [packages/core/src/core/client.ts#L973-1058](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts#L973-L1058)
- Interactive UI trace: startInteractiveUI → interactiveCli.js → Ink renders AppContainer (~2900 lines) → useGeminiStream hook drives geminiClient.sendMessageStream and owns Scheduler wiring plus slashCommandProcessor for / commands inside the TUI. — [packages/cli/src/gemini.tsx#L446-464](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L446-L464) [packages/cli/src/ui/AppContainer.tsx](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/AppContainer.tsx) [packages/cli/src/ui/hooks/useGeminiStream.ts#L1773](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/hooks/useGeminiStream.ts#L1773) [packages/cli/src/ui/hooks/slashCommandProcessor.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/hooks/slashCommandProcessor.ts)

## Testing signals

Testing is heavy and layered: Vitest 3.2 with colocated *.test.ts(x) unit tests across every package (a large share of scanned TS files are tests), an integration-tests/ workspace running the real built binary (optionally under docker/podman sandbox) with recorded .responses fixtures, evals/ behavioral evals gated behind RUN_EVALS with an llm-judge, plus perf-tests/ and memory-tests/ with baseline updating. CI (ci.yml) enforces lint (eslint+actionlint+shellcheck+yamllint+prettier+sensitive-keywords+action pinning), build, typecheck, per-workspace test:ci, bundle smoke (`node ./bundle/gemini.js --version`), generated-settings-doc freshness, and lockfile checks. Husky+lint-staged run prettier/eslint on commit.
- Unit tests are colocated Vitest files next to sources (e.g. client.test.ts, scheduler.test.ts, extension-manager*.test.ts, App.test.tsx); vitest.config.ts per package; `npm run test` runs --workspaces plus a sea/sea-launch.test.js binary-launch check, and posttest runs a full build. — [package.json#L48-52](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L48-L52) [packages/cli/vitest.config.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/vitest.config.ts) [sea/sea-launch.test.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/sea/sea-launch.test.js) [packages/core/src/core/client.test.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.test.ts)
- integration-tests/ is a separate vitest root (52+ *.test.ts files) with testTimeout 300000, retry 2, 8-16 threads, globalSetup.ts, GEMINI_TEST_TYPE=integration, and *.responses replay fixtures for browser-agent/hooks/context-compression flows; sandbox variants selected via GEMINI_SANDBOX=none|docker|podman. — [integration-tests/vitest.config.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/integration-tests/vitest.config.ts) [integration-tests/globalSetup.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/integration-tests/globalSetup.ts) [package.json#L55-64](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L55-L64) [integration-tests/hooks-system.before-agent.responses](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/integration-tests/hooks-system.before-agent.responses)
- Fake/recorded model backends are first-class test hooks: --fake-responses/--fake-responses-non-strict load FakeContentGenerator from a file and --record-responses wraps the real generator in RecordingContentGenerator — this is how the .responses fixtures are produced and replayed. — [packages/core/src/core/contentGenerator.ts#L215-228](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L215-L228) [packages/core/src/core/contentGenerator.ts#L417-419](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L417-L419) [packages/core/src/core/fakeContentGenerator.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/fakeContentGenerator.ts) [packages/core/src/core/recordingContentGenerator.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/recordingContentGenerator.ts) [packages/cli/src/config/config.ts#L474-489](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/config.ts#L474-L489)
- evals/ contains ~30 *.eval.ts behavioral evals (answer-vs-act, plan_mode, prompt_injection_mcp, memory_persistence, model_steering, sandbox_recovery, ...) driven by an llm-judge.ts; only 'always_passing' run by default, all evals need RUN_EVALS=1. — [evals/llm-judge.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/evals/llm-judge.ts) [evals/vitest.config.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/evals/vitest.config.ts) [package.json#L53-54](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L53-L54) [evals/prompt_injection_mcp.eval.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/evals/prompt_injection_mcp.eval.ts) [docs/behavioral-evals.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/behavioral-evals.md)
- perf-tests/ and memory-tests/ are dedicated vitest roots with baseline files updated via UPDATE_PERF_BASELINES/UPDATE_MEMORY_BASELINES env flags, plus memory-nightly.yml and perf-nightly.yml scheduled workflows. — [package.json#L59-62](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L59-L62) [.github/workflows/perf-nightly.yml](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/perf-nightly.yml) [.github/workflows/memory-nightly.yml](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/memory-nightly.yml)
- CI runs a lint battery beyond eslint: scripts/lint.js --setup/--eslint/--actionlint/--shellcheck/--yamllint/--prettier/--sensitive-keywords/--check-github-actions-pinning, then build, typecheck, settings-doc regeneration check (docs:settings --check), and lockfile integrity. — [.github/workflows/ci.yml#L89-125](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/ci.yml#L89-L125) [scripts/lint.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/scripts/lint.js)
- CI test matrix splits jobs by workspace: `npm run test:ci --workspace @google/gemini-cli` on one runner and core+a2a-server+vscode-ide-companion+test-utils (with coverage disabled) on another, followed by bundle verification `node ./bundle/gemini.js --version`. — [.github/workflows/ci.yml#L188-201](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/ci.yml#L188-L201) [.github/workflows/ci.yml#L279-292](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/ci.yml#L279-L292)
- A deflake harness exists (scripts/deflake.js + deflake.yml workflow + RUN_FLAKY_INTEGRATION flag) specifically to rerun integration suites, signalling acknowledged flaky e2e coverage. — [package.json#L24-26](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L24-L26) [package.json#L57](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L57) [.github/workflows/deflake.yml](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/deflake.yml)
- Test infrastructure deps include msw (HTTP mocking), mock-fs/memfs (fs virtualization), react-devtools-core, and a dedicated @google/gemini-cli-test-utils workspace; ink is replaced with a fork (@jrichman/ink) via npm overrides to make TUI testable. — [package.json#L81-91](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L81-L91) [package.json#L130-152](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L130-L152) [packages/test-utils/package.json](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/test-utils/package.json)
- eslint-plugin-headers enforces the Google Apache license header on source files, and lint-staged runs prettier+eslint --fix on commit via husky hooks. — [package.json#L126](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L126) [package.json#L172-183](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L172-L183) [packages/cli/index.ts#L1-6](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/index.ts#L1-L6)
- Coverage gaps visible from the file tree: packages/devtools client has few colocated tests, scripts/ has a separate vitest config, and several heavy paths (sandbox.ts 1431 lines, AppContainer.tsx 2869 lines) have limited direct unit coverage relative to size — integration tests carry much of that weight. (inferred) — [packages/cli/src/utils/sandbox.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandbox.ts) [packages/cli/src/ui/AppContainer.tsx](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/AppContainer.tsx) [packages/cli/vitest.config.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/vitest.config.ts)

## Risk map

The riskiest surfaces are the ones that execute or fetch code: ShellTool + ShellExecutionService (model-generated commands on the host, mitigated by policy/confirmation/sandbox), the sandbox relaunch path itself (exec/spawn of docker, podman, sandbox-exec), extension installation (git clone / GitHub release downloads, consent-gated), the toolDiscoveryCommand (arbitrary configured command whose stdout is parsed into tools), custom-command shell injection (!{...} processors), and the a2a-server which ships hardcoded demo credentials. Config.ts is a 4200-line god object and the two-process relaunch + ConsolePatcher/stdio interception are fragile coupling hotspots. Credential storage (OAuth via keychain/file fallback, apiKeyCredentialStorage, MCP oauth-token-storage) is sensitive file IO outside the repo.
- a2a-server customUserBuilder authenticates with literal hardcoded values — Bearer 'valid-token' and Basic 'admin:password' — which would accept those credentials on any deployed instance of this Express app. — [packages/a2a-server/src/http/app.ts#L96-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/a2a-server/src/http/app.ts#L96-L120)
- ShellTool executes model-generated shell commands; mitigations are layered (shell-utils root-command parsing for policy matching, PolicyDecision gating, user confirmation details of type 'exec', optional sandboxing via sandboxManager, untrusted-context tracking for build/test commands) but the blast radius is the user's shell. — [packages/core/src/tools/shell.ts#L37-66](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/shell.ts#L37-L66) [packages/core/src/services/shellExecutionService.ts#L441-475](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/shellExecutionService.ts#L441-L475) [packages/core/src/utils/untrustedContextTracker.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/utils/untrustedContextTracker.ts) [packages/core/src/scheduler/policy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/policy.ts)
- The sandbox path spawns external binaries (docker/podman/sandbox-exec) and rewrites argv/stdin; sandbox.ts uses exec/execSync/spawnSync heavily and manages temp seatbelt profile files — a failure here can strand processes or silently run unsandboxed if config detection misfires. (inferred) — [packages/cli/src/utils/sandbox.ts#L7-20](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandbox.ts#L7-L20) [packages/cli/src/utils/sandbox.ts#L55-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandbox.ts#L55-L120) [packages/cli/src/utils/sandboxUtils.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/utils/sandboxUtils.ts) [packages/cli/src/gemini.tsx#L684-737](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L684-L737)
- ToolRegistry.discoverAndRegisterToolsFromCommand spawns a user-configured toolDiscoveryCommand via spawn and JSON.parses its stdout into FunctionDeclarations; DiscoveredTool invocations then spawn toolCallCommand piping params as JSON on stdin — arbitrary local command execution is a designed-in extension surface. — [packages/core/src/tools/tool-registry.ts#L376-539](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-registry.ts#L376-L539) [packages/core/src/tools/tool-registry.ts#L77-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-registry.ts#L77-L120)
- Custom TOML commands support !{...} shell injection executed through ShellProcessor, which throws ConfirmationRequiredError to force user approval — a prompt-file → shell-exec path that depends on the confirmation gate not being bypassed. — [packages/cli/src/services/prompt-processors/shellProcessor.ts#L24-53](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/prompt-processors/shellProcessor.ts#L24-L53) [packages/cli/src/services/FileCommandLoader.ts#L25-35](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/FileCommandLoader.ts#L25-L35)
- Extension installs fetch remote code (cloneFromGit/downloadFromGitHubRelease) and extensions can contribute MCP servers, hooks, policies, and commands — supply-chain risk is gated by maybeRequestConsentOrFail, admin allowlists (applyAdminAllowlist), ExtensionIntegrityManager, and folder trust. — [packages/cli/src/config/extension-manager.ts#L21-24](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extension-manager.ts#L21-L24) [packages/cli/src/config/extension-manager.ts#L44-64](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extension-manager.ts#L44-L64) [packages/cli/src/config/extensions/consent.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extensions/consent.ts) [packages/core/src/config/extensions/integrity.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/extensions/integrity.ts)
- Config (packages/core/src/config/config.ts, 4205 lines) concentrates ~200 getters plus lifecycle (auth refresh, tool registry, MCP startup, hooks, extensions) — edits here have the largest blast radius and the file already carries patches like minified-class-name normalization in maybeRegister. — [packages/core/src/config/config.ts#L753](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L753) [packages/core/src/config/config.ts#L3939-3964](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L3939-L3964)
- The uncaught-exception handler deliberately swallows specific node-pty errors ('Cannot resize a pty that has already exited', EBADF from node-pty stacks) — pragmatic, but any genuinely new fatal error signature matching those strings will also be suppressed. — [packages/cli/src/gemini.tsx#L225-248](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L225-L248)
- Secrets handling spans multiple stores: OAuth creds via oauth2.ts, GEMINI_API_KEY persisted in apiKeyCredentialStorage (keytar on supported platforms, with a documented Linux Secret-Service hang avoided by early return for OAuth/ADC), MCP tokens via keychain/hybrid/file storage — file-permission and keychain-availability edge cases are the sensitive surface. — [packages/core/src/core/apiKeyCredentialStorage.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/apiKeyCredentialStorage.ts) [packages/core/src/code_assist/oauth2.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/code_assist/oauth2.ts) [packages/core/src/mcp/token-storage/keychain-token-storage.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/mcp/token-storage/keychain-token-storage.ts) [packages/core/src/mcp/token-storage/hybrid-token-storage.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/mcp/token-storage/hybrid-token-storage.ts) [packages/core/src/core/contentGenerator.ts#L164-172](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L164-L172)
- stdio is globally intercepted (patchStdio + ConsolePatcher redirecting console.* into coreEvents) and stdin is toggled into raw mode at multiple layers; ordering bugs here caused real issues — the code comments cite silent keystroke loss when stdin listeners drop to zero. — [packages/cli/src/gemini.tsx#L477-481](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L477-L481) [packages/cli/src/gemini.tsx#L828-838](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L828-L838) [packages/cli/src/gemini.tsx#L903-911](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L903-L911) [packages/cli/src/ui/utils/ConsolePatcher.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/utils/ConsolePatcher.ts)
- MCP servers are spawned/connected from settings and extension manifests with OAuth flows (mcp-oauth-provider) and token storage; allowedMcpServerNames and admin policies constrain them, but a malicious or compromised MCP server can inject tool descriptions, prompts (McpPromptLoader), and resources into the model context — flagged by the prompt_injection_mcp eval. (inferred) — [packages/core/src/tools/mcp-client-manager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/mcp-client-manager.ts) [packages/core/src/mcp/mcp-oauth-provider.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/mcp/mcp-oauth-provider.ts) [packages/cli/src/services/McpPromptLoader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/McpPromptLoader.ts) [evals/prompt_injection_mcp.eval.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/evals/prompt_injection_mcp.eval.ts)
- --raw-output disables ANSI sanitization of model output in TEXT mode; the code itself warns this 'may contain harmful ANSI sequences (e.g. for phishing or command injection)' and requires --accept-raw-output-risk to suppress the warning. — [packages/cli/src/nonInteractiveCli.ts#L210-218](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L210-L218) [packages/cli/src/nonInteractiveCli.ts#L340-343](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/nonInteractiveCli.ts#L340-L343)
- Workspace-trust is a security boundary: trustedFolders.json gates folder trust, untrusted folders restrict which extensions/commands/hooks load (FileCommandLoader checks isTrustedFolder; LiteRt binaryPath/autoStartServer are deliberately user-scope-only to prevent workspace configs executing arbitrary binaries). — [packages/cli/src/config/trustedFolders.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/trustedFolders.ts) [packages/cli/src/services/FileCommandLoader.ts#L75-81](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/FileCommandLoader.ts#L75-L81) [packages/cli/src/gemini.tsx#L852-861](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L852-L861)

## Extension points

Almost every subsystem is a plug-in point: ICommandLoader implementations feed CommandService; ToolRegistry.registerTool plus the discovery-command and MCP paths add tools; AgentRegistry loads local .md/agent definitions and remote A2A agents; the policy engine loads TOML rule dirs per tier; hooks subscribe to named lifecycle events; extensions bundle all of the above via gemini-extension.json; skills are discovered by SkillManager and activated via ActivateSkillTool; ContentGenerator is a factory interface; and the policy engine, themes, and model-config service all accept externally supplied entries.
- Slash commands plug in through the ICommandLoader interface — BuiltinCommandLoader (hardcoded), FileCommandLoader (TOML in ~/.gemini/commands, project, extension dirs), McpPromptLoader (MCP prompts), SkillCommandLoader — merged by CommandService.create with SlashCommandResolver de-duplicating conflicts by renaming losers. — [packages/cli/src/services/types.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/types.ts) [packages/cli/src/services/CommandService.ts#L44-82](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/CommandService.ts#L44-L82) [packages/cli/src/services/BuiltinCommandLoader.ts#L73](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/BuiltinCommandLoader.ts#L73) [packages/cli/src/services/SlashCommandResolver.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/SlashCommandResolver.ts) [packages/cli/src/services/SkillCommandLoader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/SkillCommandLoader.ts)
- New core tools are added by implementing AnyDeclarativeTool/BaseDeclarativeTool (build() → ToolInvocation with getDescription/shouldConfirmExecute/execute) and registering in Config.createToolRegistry's maybeRegister list, which automatically respects the coreTools allowlist. — [packages/core/src/tools/tools.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tools.ts) [packages/core/src/config/config.ts#L3939-4087](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L3939-L4087) [packages/core/src/tools/tool-registry.ts#L287-314](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-registry.ts#L287-L314)
- Tools can be added without recompiling via settings toolDiscoveryCommand (JSON function declarations on stdout) + toolCallCommand (JSON params on stdin), executed through the optional sandboxManager — a command-protocol plugin surface. — [packages/core/src/tools/tool-registry.ts#L376-533](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-registry.ts#L376-L533)
- MCP servers are the main third-party extension surface: configured in settings/extensions, connected by McpClientManager, their tools appear as DiscoveredMCPTool (MCP_TOOL_PREFIX), prompts become slash commands, and resources are exposed via ReadMcpResourceTool/ListMcpResourcesTool through registries. — [packages/core/src/tools/mcp-client-manager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/mcp-client-manager.ts) [packages/core/src/tools/mcp-tool.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/mcp-tool.ts) [packages/cli/src/services/McpPromptLoader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/McpPromptLoader.ts) [packages/core/src/config/config.ts#L1511-1515](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L1511-L1515)
- Extensions are defined by a gemini-extension.json manifest (EXTENSIONS_CONFIG_FILENAME) and can contribute MCP servers, context files, custom commands, agents, skills, hooks, themes, and TOML policies; ExtensionManager handles install/enable/disable/update and variable hydration (${extensionPath} etc.). — [packages/cli/src/config/extension-manager.ts#L64-83](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extension-manager.ts#L64-L83) [packages/cli/src/config/extensions/variables.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extensions/variables.ts) [docs/extensions/reference.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/extensions/reference.md) [docs/extensions/writing-extensions.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/extensions/writing-extensions.md)
- The policy engine accepts user rules from multiple TOML directories per tier (default core policies in packages/core/src/policy/policies/*.toml — yolo.toml, read-only.toml, plan.toml, agents.toml etc. — plus --policy paths, workspace, user, and --admin-policy dirs) and dynamic rules pushed over the MessageBus via UpdatePolicy messages. — [packages/core/src/policy/config.ts#L44](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/config.ts#L44) [packages/core/src/policy/policies](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/policies) [packages/core/src/policy/toml-loader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/toml-loader.ts) [packages/cli/src/config/policy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/policy.ts) [packages/core/src/confirmation-bus/types.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/confirmation-bus/types.ts)
- Hooks are user/extension-supplied handlers for HookEventName lifecycle events (SessionStart/End, Before/AfterAgent, Before/AfterModel, BeforeToolSelection, Before/AfterTool) executed by HookRunner and aggregated by HookAggregator, capable of injecting context, modifying model calls, or blocking execution. — [packages/core/src/hooks/types.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/hooks/types.ts) [packages/core/src/hooks/hookSystem.ts#L38-120](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/hooks/hookSystem.ts#L38-L120) [packages/core/src/hooks/hookRunner.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/hooks/hookRunner.ts) [docs/hooks/reference.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/hooks/reference.md)
- Subagents plug in via AgentDefinition objects loaded by loadAgentsFromDirectory (project/user/extension dirs) or built in code; kind:'remote' agents are A2A-protocol endpoints resolved through A2AClientManager with pluggable auth via A2AAuthProviderFactory. — [packages/core/src/agents/registry.ts#L17-34](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/registry.ts#L17-L34) [packages/core/src/agents/agentLoader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/agentLoader.ts) [packages/core/src/agents/a2a-client-manager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/a2a-client-manager.ts) [packages/core/src/agents/auth-provider/factory.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/agents/auth-provider/factory.ts) [docs/core/remote-agents.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/core/remote-agents.md)
- Skills are markdown-based packages discovered by SkillManager from user/project/extension dirs (loadSkillsFromDir), gated by admin settings and folder trust, exposed to the model through ActivateSkillTool whose schema is re-registered with the discovered skill enum. — [packages/core/src/skills/skillManager.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/skills/skillManager.ts) [packages/core/src/skills/skillLoader.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/skills/skillLoader.ts) [packages/core/src/config/config.ts#L1533-1551](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L1533-L1551) [docs/cli/creating-skills.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/cli/creating-skills.md)
- Model selection is extensible: ModelConfigService resolves per-alias model configs, routing/routingStrategy.ts plus availability policyHelpers decide model per request, handleFallback switches models on quota errors, and ModelMappingContentGenerator remaps names for Code Assist (CCPA_AI_MODEL_MAPPINGS). (inferred) — [packages/core/src/services/modelConfigService.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/modelConfigService.ts) [packages/core/src/routing/routingStrategy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/routing/routingStrategy.ts) [packages/core/src/availability/policyHelpers.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/availability/policyHelpers.ts) [packages/core/src/fallback/handler.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/fallback/handler.ts) [packages/core/src/core/modelMappingContentGenerator.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/modelMappingContentGenerator.ts)
- ContentGenerator is a decorated factory: Fake/Recording/Logging/ModelMapping wrappers compose around either the Code Assist server client or @google/genai — new providers slot in by extending createContentGenerator's authType switch. — [packages/core/src/core/contentGenerator.ts#L210-422](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/contentGenerator.ts#L210-L422) [packages/core/src/core/loggingContentGenerator.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/loggingContentGenerator.ts)
- Tool declarations shown to the model are model-family aware: tools/definitions/coreTools.ts + resolver.ts + model-family-sets produce per-model FunctionDeclarations so tool schemas can be swapped per Gemini version without touching tool implementations. — [packages/core/src/tools/definitions/coreTools.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/definitions/coreTools.ts) [packages/core/src/tools/definitions/resolver.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/definitions/resolver.ts) [packages/core/src/tools/definitions/modelFamilyService.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/definitions/modelFamilyService.ts) [packages/core/src/tools/tool-registry.ts#L663-725](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/tools/tool-registry.ts#L663-L725)

## Contributor handoff

An agent editing this repo should treat packages/core and packages/cli as separate layers (core must not import cli), keep the Config god-object edits minimal, route all tool gating through the PolicyEngine/MessageBus rather than ad-hoc checks, and always run the colocated vitest file plus typecheck before considering a change done. Build is `npm run bundle` (esbuild → bundle/gemini.js); quick dev loop is `npm run start` / `npm start -- -p '...'` after build. Conventions: ESM with .js import specifiers for .ts files, Apache license header enforced by eslint, debugLogger instead of console.*, proper-lockfile/proper JSONL append for session files. Traps: two-process relaunch means env changes need GEMINI_CLI_NO_RELAUNCH=1 to debug the real process; posttest triggers a full build; Ink is a forked package via npm overrides.
- Read-first files for any agentic-loop change: packages/core/src/core/client.ts (GeminiClient), turn.ts (event types Turn/GeminiEventType), geminiChat.ts (stream+retry), scheduler/scheduler.ts (tool execution), config/config.ts (wiring). CLI-side entry: packages/cli/index.ts then src/gemini.tsx main(). — [packages/core/src/core/client.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/client.ts) [packages/core/src/core/turn.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/core/turn.ts) [packages/core/src/scheduler/scheduler.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/scheduler.ts) [packages/cli/src/gemini.tsx](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx)
- Build/dev commands: `npm run bundle` produces bundle/gemini.js (esbuild, includes generated git commit info and devtools bundle); `npm run start` runs scripts/start.js with NODE_ENV=development; `npm run build` builds packages only. — [package.json#L20-47](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L20-L47) [esbuild.config.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/esbuild.config.js) [scripts/start.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/scripts/start.js) [scripts/build.js](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/scripts/build.js)
- Test commands: `npm run test:ci --workspace @google/gemini-cli-core` for core unit tests; `npm run test:integration:sandbox:none` for e2e without sandbox; `npm run typecheck` across workspaces; `npm run preflight` = clean+ci+format+build+lint+typecheck+test:ci (slow, full gate). — [package.json#L48-72](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L48-L72) [.github/workflows/ci.yml#L188-194](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/ci.yml#L188-L194) [CONTRIBUTING.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/CONTRIBUTING.md)
- Imports must use ESM `.js` specifiers referencing the compiled names (e.g. './utils/cleanup.js'), the repo is "type":"module" everywhere, and every file needs the SPDX Apache header enforced by eslint-plugin-headers. — [package.json#L7](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L7) [packages/cli/src/gemini.tsx#L43-101](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L43-L101) [package.json#L126](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L126)
- Logging convention: never use console.log/console.error in library paths — ConsolePatcher intercepts them; use debugLogger (debug/error/warn) for diagnostics and coreEvents.emitFeedback for user-facing messages so headless JSON output stays clean. — [packages/cli/src/ui/utils/ConsolePatcher.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/ui/utils/ConsolePatcher.ts) [packages/cli/src/gemini.tsx#L583-592](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L583-L592) [packages/core/src/utils/events.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/utils/events.ts)
- Tool-approval changes must go through the PolicyEngine + MessageBus confirmation flow (checkPolicy → resolveConfirmation → MessageBusType.ToolConfirmationRequest); bypassing it (e.g. auto-executing in a new tool) defeats --approval-mode/--yolo/plan-mode semantics and enterprise admin policies. — [packages/core/src/scheduler/scheduler.ts#L10-13](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/scheduler.ts#L10-L13) [packages/core/src/scheduler/policy.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/scheduler/policy.ts) [packages/core/src/confirmation-bus/types.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/confirmation-bus/types.ts) [packages/core/src/policy/policy-engine.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/policy/policy-engine.ts)
- Safe edit boundaries: new tools go in packages/core/src/tools/ + registration in config.ts createToolRegistry; new slash commands in packages/cli/src/ui/commands/ + BuiltinCommandLoader; new settings keys in settingsSchema.ts (docs regenerated via npm run docs:settings, which CI verifies with --check). — [packages/core/src/config/config.ts#L3966-4087](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L3966-L4087) [packages/cli/src/services/BuiltinCommandLoader.ts#L123-240](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/services/BuiltinCommandLoader.ts#L123-L240) [packages/cli/src/config/settingsSchema.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/settingsSchema.ts) [package.json#L32-34](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L32-L34) [.github/workflows/ci.yml#L116-119](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/ci.yml#L116-L119)
- Debugging trap: the CLI double-forks — the visible process is a thin parent; to debug or test the real logic run with GEMINI_CLI_NO_RELAUNCH=1 (or `npm run debug` which uses --inspect-brk), otherwise breakpoints attach to the wrong process and stdin/stdio patching differs. — [packages/cli/index.ts#L54-56](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/index.ts#L54-L56) [packages/cli/src/gemini.tsx#L138-140](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L138-L140) [package.json#L23](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L23)
- Trap: `npm test` at the root runs a build afterwards (posttest → npm run build) and the prepare script runs `husky && npm run bundle`, so npm install/test are not side-effect-free; the package-lock is guarded by check:lockfile in CI. — [package.json#L52](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L52) [package.json#L73](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L73) [package.json#L77](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L77) [.github/workflows/ci.yml#L89](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/.github/workflows/ci.yml#L89)
- Layering rule: packages/cli depends on @google/gemini-cli-core (file:../core) and everything cross-layer is exported through packages/core/src/index.ts; a2a-server and sdk also consume core only through that barrel — new core APIs must be re-exported there to be usable. — [packages/cli/package.json#L34](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/package.json#L34) [packages/core/src/index.ts](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/index.ts) [packages/a2a-server/src/http/app.ts#L29-35](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/a2a-server/src/http/app.ts#L29-L35) [packages/sdk/package.json](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/sdk/package.json)
- Ink is pinned to a fork (@jrichman/ink@6.6.9) via npm overrides with wrap-ansi/cliui pinned too — do not upgrade ink casually; TUI tests rely on the fork's behavior (react-devtools-core in devDeps). — [package.json#L81-86](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L81-L86) [package.json#L143](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/package.json#L143)
- Session transcript writes must remain append-only JSONL with proper record shapes (MessageRecord/$set/$rewindTo/$partial metadata guards in chatRecordingService); --resume and rewind depend on parsing these exact line types. — [packages/core/src/services/chatRecordingService.ts#L76-98](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/services/chatRecordingService.ts#L76-L98) [packages/cli/src/gemini.tsx#L336-407](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L336-L407)
- Enterprise/admin settings arrive via parent→child IPC and CCPA fetch in refreshAuth; features must consult admin flags (e.g. getAdminBlockedMcpServersMessage, adminSkillsEnabled, applyAdminAllowlist) rather than only user settings, or enterprise controls are bypassed. — [packages/cli/src/gemini.tsx#L669-679](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/gemini.tsx#L669-L679) [packages/cli/src/config/extension-manager.ts#L55-56](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/cli/src/config/extension-manager.ts#L55-L56) [packages/core/src/config/config.ts#L1534-1550](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/packages/core/src/config/config.ts#L1534-L1550) [docs/admin/enterprise-controls.md](https://github.com/google-gemini/gemini-cli/blob/d5b3e3accb26000d273abf16e0f1dd83aa5428a9/docs/admin/enterprise-controls.md)

Source repository: https://github.com/google-gemini/gemini-cli
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/gemini-cli.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
