google-gemini/gemini-cli
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.
- 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.
- 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.
- 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.
- 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.
- 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().
- 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.
- 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.
- 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.
- 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.
- 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.
- 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)