This is an English translation of a Chinese forum post analyzing the architecture of Pi, an agent harness distributed as the @earendil-works/pi-* monorepo (~v0.80.x).
Key points
- Positioning: Pi is a *minimal terminal coding harness* whose core claim is not "most featured coding agent" but "keep the core tiny, let extensions shape workflows." Only four tools ship by default:
read,write,edit,bash. - Deliberate omissions: No MCP, no sub-agents, no permission popups, no plan mode, no built-in todos, no background bash. Each exclusion has a documented alternative (Skills, tmux, containers, custom extensions).
- Delivery modes: Interactive TUI, Print/JSON (
-p/--mode json), RPC (--mode rpc), and SDK viacreateAgentSession()— all sharing oneAgentSessionsemantic core. pi-ai: No UI or coding semantics. Splits into *API dialects* (anthropic-messages,openai-completions,openai-responses,google-generative-ai,bedrock-converse-stream, …) and *providers* (endpoints, model catalogs, auth, OAuth refresh). Key abstractions: serializableContext,Model, unifiedstream/streamSimpleevent flows. Errors are encoded into events and the finalAssistantMessage(stopReason: error|aborted) rather than thrown. Only tool-calling models are supported. API modules are lazy-loaded; the model catalog is generated (models.generated.ts).pi-agent-core: Generic agent loop, tool execution, event stream. Clear type separation: extensibleAgentMessage[]→transformContext→convertToLlm→ vendorMessage[]. Event model (agent_start/turn_start/message_*/tool_execution_*/turn_end/agent_end) is the single source of truth for UI and persistence. Tools run in parallel by default with preflightbeforeToolCallhooks; steering/follow-up message queues are supported. An evolvingAgentHarnessdistinguishes harness config, frozen turn snapshots, persisted session state, and pending writes.pi-tui: Component interface (render(width) → string[]), differential rendering with CSI 2026 synchronized output, overlays, bracketed paste, image protocols.pi-coding-agent: The assembly layer —AgentSession(shared across all modes),SessionManager(JSONL tree), extension loader, tools, compaction, resource loader, model runtime. "Modes are the I/O layer, not the business layer."pi-orchestrator: Experimental, explicitly not a production commitment.
Package layering
Strict downward dependencies, built in order tui → ai → agent → coding-agent → orchestrator:
Session system
Sessions are append-only JSONL files at ~/.pi/agent/sessions/... where id/parentId entries form a tree, not a linear log (v1→v3 migration on load). Entry types include messages, compaction checkpoints, branch_summary, metadata (model_change), and custom entries for extension state. Compaction triggers when contextTokens > contextWindow - reserveTokens (default 16k); branch summarization preserves context when navigating /tree. Compression is a session-layer policy, visible in exports and audits — not hidden provider truncation.
Extensions as first-class citizens
Resource tiers: Extensions (TypeScript modules with lifecycle hooks, registerTool, registerCommand, custom TUI, session entries), Skills (Markdown capability docs the model loads via read), prompt templates, themes, packages, and context files (AGENTS.md/CLAUDE.md). Extensions run with full user privileges — the trust boundary is what you choose to load, not a sandbox interpreter. System prompt assembly layers custom/default prompts, context files (discovered up the directory tree), skill indexes, and appends.
Security and engineering model
Security is layered: OS process permissions, project trust gating local extensions, supply chain hardening (pinned deps, npm-shrinkwrap, --ignore-scripts), and optional container isolation (Gondolin, Docker, OpenShell). Engineering constraints include erasable-TypeScript-only (Node strip-only), no inline dynamic imports, a npm run check gate, faux-provider test suites, and Git discipline for multi-agent parallel development.
Conclusion
The author summarizes Pi in three claims: (1) a layered harness where ai/agent/tui/product each have clean boundaries; (2) minimal core plus first-class extensions instead of kernel feature flags; (3) sessions as an externalized state machine (append-only JSONL tree) shared by CLI, RPC, and SDK. Best suited to users who want deep customization, SDK/RPC embedding, branchable/auditable sessions, and multi-vendor model mixing — not to those expecting a batteries-included agent with built-in MCP, sub-agents, and permission UIs.
> Pi is not an agent that tries to decide how you code — it is a harness that lets you (and your extensions) define how the agent works.