# Pi Agent Harness — Socratic Exploration Wiki > A four-package TypeScript monorepo that assembles a self-extensible coding agent: a unified multi-provider LLM layer, a provider-neutral agent loop, a terminal UI library, and the interactive CLI that binds them. What makes it worth studying is the deliberate separation of concerns—each layer is independently publishable and replaceable—and the extension system that lets the agent modify its own tools at runtime. This is a Grok-Wiki source-grounded repository wiki. Use the complete Markdown link when an agent needs the full repo context. ## Context Links - [Complete Markdown wiki](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/llms-full.txt) - [Complete Markdown alias](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234.md) - [Human interactive wiki](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234) - [GitHub repository](https://github.com/earendil-works/pi) ## Repository - Repository: earendil-works/pi - Generated: 2026-05-22T23:31:33.949Z - Updated: 2026-05-22T23:54:42.183Z - Runtime: Claude Code - Format: Socratic Exploration - Pages: 12 ## Pages - [The First Question: Why Is a Simple Script Not Enough?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/01-the-first-question-why-is-a-simple-script-not-enough.md): What problem does pi actually solve, and why does the answer demand four separate packages instead of one? This page traces the repo from its name down to its monorepo shape, asking at every step which assumption would break if the system were simpler. The answer reveals the architectural bet: that provider neutrality, session persistence, and a live extension system are inseparable from any serious coding agent. - [Why Four Packages? Where Does Each Layer End?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/02-why-four-packages-where-does-each-layer-end.md): The repo ships four independently publishable npm packages: pi-ai, pi-agent-core, pi-tui, and pi-coding-agent. Each boundary is a deliberate seam. This page asks: which concerns forced each split, what can cross each boundary, and what would break if two packages were merged? Reading package.json exports, tsconfig.build.json, and the import graph answers these questions concretely. - [BYOK / BYOC: What Does Provider Neutrality Actually Cost?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/03-byok-byoc-what-does-provider-neutrality-actually-cost.md): Pi promises that users bring their own keys and providers. This page probes what that claim requires in practice: how env-api-keys.ts discovers credentials, how the OAuth flow is handled, how the add-llm-provider skill teaches the agent to register new providers at runtime, and what invariants must hold for every provider adapter. The skill file .pi/skills/add-llm-provider.md is the primary non-README evidence. - [The Registry: How Does a New Provider Become Callable?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/04-the-registry-how-does-a-new-provider-become-callable.md): pi-ai uses a runtime registry pattern: providers are registered by API string key, and the agent loop calls them through that registry without knowing which concrete module it will hit. This page traces registerApiProvider, registerBuiltInApiProviders, and the lazy-load pattern in register-builtins.ts that defers heavy provider modules until first use—exposing the tradeoff between startup time and call overhead. - [Nine Providers, One Interface: What Must Every Adapter Guarantee?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/05-nine-providers-one-interface-what-must-every-adapter-guarantee.md): The providers/ directory contains adapters for Anthropic, OpenAI (completions, responses, Codex), Azure OpenAI, Google AI, Google Vertex, Mistral, Amazon Bedrock, Cloudflare, and a faux test provider. This page asks what the common stream/streamSimple contract is, where adapters diverge (Bedrock's Node-only constraint, GitHub Copilot's custom headers, OpenAI prompt-cache specifics), and what the faux provider reveals about testability. - [Streaming All the Way Down: What Happens Between Token and Tool Call?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/06-streaming-all-the-way-down-what-happens-between-token-and-tool-call.md): Every LLM call returns an AsyncIterable of AssistantMessageEvents. This page follows an event from the provider stream through AssistantMessageEventStream (utils/event-stream.ts), into the agent loop's stream function, and up to the TUI renderer. It asks: where is backpressure applied, how are partial tool-call arguments accumulated before validation, and what does the overflow utility guard against? - [The Loop: What Is the Minimal Unit of Agent Work?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/07-the-loop-what-is-the-minimal-unit-of-agent-work.md): packages/agent/src/agent-loop.ts implements the turn-based cycle: add prompt → call LLM → emit events → execute pending tool calls → repeat until stop. This page asks what each AgentEvent type signals, how tool execution mode (sequential vs. parallel) is chosen, and what the difference is between runAgentLoop and runAgentLoopContinue. The test files agent-loop.test.ts and agent.test.ts show which invariants the authors actually enforce. - [AgentSession: What State Must Survive a Model Switch or Session Resume?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/08-agentsession-what-state-must-survive-a-model-switch-or-session-resume.md): AgentSession (core/agent-session.ts) is the shared abstraction across interactive, print, and RPC modes. It owns session persistence, model/thinking-level management, bash execution, and auto-compaction triggers. This page asks: what is serialized to disk, which events drive session persistence, how session branching works, and why AgentSession is deliberately mode-agnostic. - [Compaction: When the Context Window Is the Enemy, What Gets Thrown Away?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/09-compaction-when-the-context-window-is-the-enemy-what-gets-thrown-away.md): As conversations grow, token counts approach the context window limit. The compaction subsystem (core/compaction/) answers: when to compact, which messages to summarize, how branch-level summaries differ from turn-level summaries, and how the agent resumes coherently after a compaction round. The tests agent-session-compaction.test.ts and harness/compaction.test.ts reveal the boundary conditions. - [Built-In Tools: What Can the Agent Actually Do to a Filesystem?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/10-built-in-tools-what-can-the-agent-actually-do-to-a-filesystem.md): The coding agent ships six built-in tools: Read, Write, Edit, Bash, Grep/Find, and Ls. This page asks how each tool definition wraps the underlying operation (tool-definition-wrapper.ts), what file-mutation-queue.ts serializes to prevent concurrent edits, how bash.ts sandboxes commands, and what output-accumulator.ts does to keep large tool results from overflowing the context. The tools/ directory is the system's ground-level action surface. - [pi-tui: Why Build a Terminal UI Library from Scratch?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/11-pi-tui-why-build-a-terminal-ui-library-from-scratch.md): packages/tui implements its own terminal rendering engine with differential output, an undo stack, a kill ring, Emacs-style key bindings, fuzzy search, and inline image display (Kitty/Sixel). This page asks what constraints made off-the-shelf libraries insufficient, how the virtual terminal model in terminal.ts avoids screen-flicker, and what stdin-buffer.ts does to handle raw key events. The regression tests expose the edge cases that forced custom code. - [Three Modes, One AgentSession: What Changes Between Interactive, Print, and RPC?](https://grok-wiki.com/public/wiki/earendil-works-pi-8b87608fc234/pages/12-three-modes-one-agentsession-what-changes-between-interactive-print-and-rpc.md): The coding agent runs in three surface modes: interactive (full TUI), print (stdout-only for scripting), and RPC (JSONL protocol for IDE integration). All three share AgentSession; each adds its own I/O adapter. This page examines rpc-mode.ts and rpc-types.ts to understand the JSONL protocol, contrasts it with interactive-mode.ts component wiring, and asks what the RPC mode reveals about the true API surface of the agent. ## Source Files - `.pi/skills/add-llm-provider.md` - `AGENTS.md` - `package.json` - `packages/agent/package.json` - `packages/agent/src/agent-loop.ts` - `packages/agent/src/agent.ts` - `packages/agent/src/types.ts` - `packages/agent/test/agent-loop.test.ts` - `packages/agent/test/agent.test.ts` - `packages/agent/test/harness/compaction.test.ts` - `packages/ai/package.json` - `packages/ai/src/api-registry.ts` - `packages/ai/src/env-api-keys.ts` - `packages/ai/src/index.ts` - `packages/ai/src/models.ts` - `packages/ai/src/oauth.ts` - `packages/ai/src/providers/amazon-bedrock.ts` - `packages/ai/src/providers/anthropic.ts` - `packages/ai/src/providers/faux.ts` - `packages/ai/src/providers/github-copilot-headers.ts` - `packages/ai/src/providers/openai-prompt-cache.ts` - `packages/ai/src/providers/register-builtins.ts` - `packages/ai/src/providers/transform-messages.ts` - `packages/ai/src/session-resources.ts` - `packages/ai/src/stream.ts` - `packages/ai/src/types.ts` - `packages/ai/src/utils/event-stream.ts` - `packages/ai/src/utils/json-parse.ts` - `packages/ai/src/utils/overflow.ts` - `packages/coding-agent/package.json` - `packages/coding-agent/src/core/agent-session-runtime.ts` - `packages/coding-agent/src/core/agent-session-services.ts` - `packages/coding-agent/src/core/agent-session.ts` - `packages/coding-agent/src/core/auth-guidance.ts` - `packages/coding-agent/src/core/auth-storage.ts` - `packages/coding-agent/src/core/compaction/branch-summarization.ts` - `packages/coding-agent/src/core/compaction/compaction.ts` - `packages/coding-agent/src/core/compaction/utils.ts` - `packages/coding-agent/src/core/index.ts` - `packages/coding-agent/src/core/sdk.ts` - `packages/coding-agent/src/core/session-manager.ts` - `packages/coding-agent/src/core/tools/bash.ts` - `packages/coding-agent/src/core/tools/edit.ts` - `packages/coding-agent/src/core/tools/file-mutation-queue.ts` - `packages/coding-agent/src/core/tools/output-accumulator.ts` - `packages/coding-agent/src/core/tools/tool-definition-wrapper.ts` - `packages/coding-agent/src/main.ts` - `packages/coding-agent/src/modes/index.ts` - `packages/coding-agent/src/modes/interactive/interactive-mode.ts` - `packages/coding-agent/src/modes/print-mode.ts` - `packages/coding-agent/src/modes/rpc/jsonl.ts` - `packages/coding-agent/src/modes/rpc/rpc-mode.ts` - `packages/coding-agent/src/modes/rpc/rpc-types.ts` - `packages/coding-agent/test/suite/agent-session-compaction.test.ts` - `packages/coding-agent/test/suite/agent-session-runtime.test.ts` - `packages/coding-agent/test/tools.test.ts` - `packages/tui/package.json` - `packages/tui/src/kill-ring.ts` - `packages/tui/src/stdin-buffer.ts` - `packages/tui/src/terminal-image.ts` - `packages/tui/src/terminal.ts` - `packages/tui/src/tui.ts` - `packages/tui/test/tui-render.test.ts` - `README.md`