# Data flow — earendil-works/pi

> Canonical page: https://codevetter.com/unpack/pi/data-flow

# Data flow — earendil-works/pi

Scanned commit 95fbc04997eaee961eb673fa7923e9220609ebd5 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

A prompt enters via CLI args, piped stdin, or the TUI editor; AgentSession wraps it as a user AgentMessage and hands it to Agent.prompt → runAgentLoop. Per turn the loop transforms AgentMessage[] → LLM Message[] (convertToLlm), streams via the model's provider streamFn, executes toolCall content blocks through tools/extensions, and appends ToolResultMessages. AgentSession subscribes to agent events and persists each message_end to the JSONL session file via SessionManager, while the active mode renders events (TUI components, text, or JSON lines). Credentials come from auth.json (locked, 0600) resolved per-request by ModelRuntime; model catalogs come from generated data + models.json + a remote catalog refresh.
- streamAssistantResponse is the LLM boundary: it applies transformContext (AgentMessage[]→AgentMessage[]), convertToLlm (AgentMessage[]→Message[]), normalizeContext, resolves a fresh API key via getApiKey(provider), then calls streamFn(model, llmContext, options) and folds stream events into a final AssistantMessage. — [packages/agent/src/agent-loop.ts#L380-466](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L380-L466)
- runLoop has an outer loop for follow-up messages and an inner loop that alternates: drain steering queue → emit turn_start → prepareRequest hook → stream assistant response → execute tool calls → finishTurn hook → turn_end; the loop ends on agent_end. — [packages/agent/src/agent-loop.ts#L162-320](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L162-L320)
- Tool calls from an assistant message run in parallel by default, sequentially if config.toolExecution or any tool's executionMode requires it; each call goes through prepareToolCall (argument validation via validateToolArguments), execution with progress callbacks, and finalizeExecutedToolCall producing a ToolResultMessage pushed into context. — [packages/agent/src/agent-loop.ts#L505-581](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L505-L581) [packages/agent/src/agent-loop.ts#L583-641](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L583-L641)
- Persistence path: AgentSession subscribes to agent events; on message_end it calls sessionManager.appendMessage(event.message) which appends a SessionMessageEntry to the JSONL file; model changes, thinking-level changes, usage, compaction, labels, and custom entries get their own entry types. — [packages/coding-agent/src/core/agent-session.ts#L921-943](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/agent-session.ts#L921-L943) [packages/coding-agent/src/core/session-manager.ts#L57-160](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/session-manager.ts#L57-L160)
- Agent state is owned by the Agent class: messages/tools arrays with copy-on-assign setters, pendingToolCalls set, steeringQueue and followUpQueue (PendingMessageQueue with 'all' | 'one-at-a-time' drain modes) polled by the loop via getSteeringMessages/getFollowUpMessages. — [packages/agent/src/agent.ts#L142-173](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent.ts#L142-L173) [packages/agent/src/agent.ts#L464-501](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent.ts#L464-L501)
- Credential flow: FileAuthStorageBackend reads/writes ~/.pi/agent/auth.json under a proper-lockfile lock (sync retry loop, async 30s stale timeout), always writing with mode 0600; ModelRuntime composes stored credentials, env vars (env-api-keys.ts), and runtime overrides into provider auth. — [packages/coding-agent/src/core/auth-storage.ts#L25-114](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/auth-storage.ts#L25-L114) [packages/coding-agent/src/core/model-runtime.ts#L67-110](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/model-runtime.ts#L67-L110) [packages/ai/src/env-api-keys.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/src/env-api-keys.ts)
- Model catalog flow: static MODELS catalog (generated) + per-provider dynamic refresh + user models.json + remote catalog provider compose into ModelRuntime; resolveModelScope expands --models/settings enabledModels patterns into ScopedModel list used for selection and Ctrl+P cycling. — [packages/coding-agent/src/core/model-runtime.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/model-runtime.ts) [packages/coding-agent/src/core/model-resolver.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/model-resolver.ts) [packages/coding-agent/src/core/remote-catalog-provider.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/remote-catalog-provider.ts) [packages/ai/src/models.generated.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/src/models.generated.ts)
- Settings are layered: global ~/.pi/agent/settings.json deep-merged with project .pi/settings.json (deepMergeSettings recurses into nested objects); project settings only load when the project is trusted. — [packages/coding-agent/src/core/settings-manager.ts#L165-201](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/settings-manager.ts#L165-L201) [packages/coding-agent/docs/security.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/docs/security.md)
- Context files flow into the system prompt: loadContextFileFromDir checks AGENTS.override.md, AGENTS.md, AGENTS.MD, CLAUDE.md, CLAUDE.MD per directory; loadProjectContextFiles walks ancestors from cwd plus the global agent dir, with git-worktree shadowing handled by findShadowedContextFile. — [packages/coding-agent/src/core/resource-loader.ts#L71-117](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/resource-loader.ts#L71-L117) [packages/coding-agent/src/core/resource-loader.ts#L119-140](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/resource-loader.ts#L119-L140)
- Extension events flow through ExtensionRunner (built on an EventBus): AgentSession emits lifecycle events (session_start, turn_start, message_*, tool_*, context, session_compact, ...) which extension handlers observe or mutate; handler errors route to onError listeners rather than crashing the session. — [packages/coding-agent/src/core/extensions/types.ts#L1349-1424](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/types.ts#L1349-L1424) [packages/coding-agent/src/core/extensions/runner.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/runner.ts) [packages/coding-agent/src/core/event-bus.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/event-bus.ts)
- Output boundaries: interactive mode renders via pi-tui components through InteractiveMode; print mode writes final text or toJsonEvent JSON lines via writeRawStdout (stdout is taken over so extension noise doesn't corrupt the stream); RPC mode serializes responses/events as JSONL on stdout. — [packages/coding-agent/src/modes/print-mode.ts#L108-119](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/modes/print-mode.ts#L108-L119) [packages/coding-agent/src/modes/rpc/rpc-mode.ts#L54-77](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/modes/rpc/rpc-mode.ts#L54-L77) [packages/coding-agent/src/core/output-guard.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/output-guard.ts) [packages/coding-agent/src/modes/json-event.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/modes/json-event.ts)
- Session reload after compaction or /reload rebuilds state from disk: SessionManager.buildSessionProjection folds entries into messages (skipping compacted ranges via firstKeptEntryId), then the agent context is replaced — this is why CompactionEntry stores the full systemMessage snapshot. — [packages/coding-agent/src/core/agent-session.ts#L590-613](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/agent-session.ts#L590-L613) [packages/coding-agent/src/core/session-manager.ts#L91-104](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/session-manager.ts#L91-L104) [packages/coding-agent/src/core/compaction/compaction.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/compaction/compaction.ts)
- Piped stdin and @file arguments are merged into the initial message by buildInitialMessage/processFileArguments (images auto-resized later once the model is known); in RPC mode @file args are rejected because stdin carries the protocol. — [packages/coding-agent/src/main.ts#L210-229](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L210-L229) [packages/coding-agent/src/main.ts#L644-647](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L644-L647) [packages/coding-agent/src/cli/file-processor.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/cli/file-processor.ts) [packages/coding-agent/src/cli/initial-message.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/cli/initial-message.ts)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

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