google-gemini/gemini-cli
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.
- 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/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/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.
- 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().
- The agentic core is GeminiClient.sendMessageStream → Turn.run → GeminiChat.sendMessageStream, yielding typed ServerGeminiStreamEvent values (Content, Thought, ToolCallRequest, Finished, LoopDetected, InvalidStream, AgentExecutionStopped/Blocked, ...).
- 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.
- 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.
- 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/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/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.
- 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.