Pi Architecture Explained

Pi Architecture Explained — Agent Loop, Tools, TUI and More

Alejandro AO · ~39 min · Deep Dive Document
Video thumbnail — Pi Architecture Explained
⏱ ~39 min 🎤 Alejandro AO 🏷 Pi Agent · Architecture · Agent Loop · Tools · Extensions · TUI · Compaction · Skills

1 The Agent Loop — Pi's Core Design

▶ 0:00

Alejandro opens by explaining that Pi's architecture splits into two main parts: Pi Core (the agent loop itself, also accessible via RPC and SDK) and Pi Interactive (the terminal UI layer). The core is intentionally minimal and built completely from scratch — no external agent framework libraries like OpenAI Agents SDK or Vercel AI SDK.

📝
Init Context
🔄
Transform
🤖
LLM Call
🔧
Tool Calls
💬
Response

2 Context Initialization

▶ 1:51

Every time you send a message, Pi initializes the context by assembling these components in order:

  1. System prompt — hardcoded, ~20 lines. Can be overridden via .pi/SYSTEM.md in your workspace
  2. AGENTS.md files — appended from both ~/.pi/agent/AGENTS.md (global) and the current working directory
  3. Skill descriptions — names and descriptions of all loaded skills (not full content)
  4. Tool descriptions — descriptions of available tools
  5. Message history — previous messages (or a compacted summary if the session was compacted)
  6. Current message — your new prompt
💡 Key point: Skills and tools are described, not loaded in full. Only the names and short descriptions go into the system prompt. The full skill content is loaded on-demand via a read tool call — this is the progressive disclosure pattern.

3 Context Transformation & Compaction Check

▶ 4:10

After initialization, the context goes through a transformation step that checks whether compaction is needed. If the context is too long, Pi compacts it — summarizing the message history via an LLM call and replacing the full history with the summary.

This creates a trade-off: you lose granular history but keep the context window manageable. The full history remains in the JSONL session file — you can always revisit it via /tree.

4 The LLM Call & Tool Loop

▶ 4:47

The assembled context is sent to whatever provider/model the user has selected (OpenAI, Anthropic, Google, Kimi, MiniMax, etc.). The model can respond with:

  • A tool call → the tool executes, its result is appended, and the model is called again
  • A text response → the loop ends, the response is shown to the user

This loop can run hundreds of iterations for complex tasks (e.g., multi-file refactoring) or just a couple for simple queries. There's no hard limit on tool calls per turn — the model decides when it's done.

5 Sessions & Memory — JSONL Storage

▶ 6:52

Sessions are stored at ~/.pi/agent/sessions/, organized by working directory. Each project gets its own subdirectory — so sessions for ~/dashboard and ~/weather-app live in separate folders.

Each session is a single JSONL file (JSON Lines) — one JSON object per line, each representing a message. This format is chosen deliberately:

  • Appending a new message = adding one line (no rewriting the entire file)
  • No array wrapping — easier to update than a JSON array
  • Human-readable — open in any text editor
  • Exportable — trivial to parse, transform, or share

Each message object contains: type (message type), id, parentId, timestamp, and the actual message content (role, text, tool calls, etc.).

6 Tree-Structured Conversation History

▶ 9:46

This is one of Alejandro's favorite Pi design decisions: sessions are stored as trees, not lists. Every message has an id and a parentId — this enables conversation forking.

When you use /tree in Pi, you navigate vertically through the JSONL messages. If you select a previous message and send a new prompt, Pi creates a new child message with the same parent — a fork. Both branches coexist in the same JSONL file.

💡 "It is just a beautiful design." — Alejandro notes that many newer AI agents are migrating to this tree structure instead of flat message lists, because it enables forking, branching, and non-destructive exploration of different approaches.

Alejandro demonstrates this live: he opens /tree, navigates to a previous message, asks Pi to summarize the conversation from that point, and the new message is added as a sibling branch — visible when you re-open /tree.

7 Tools — The Minimalist Set

▶ 15:00

Pi ships with only 4 tools by default:

  1. read — read file contents
  2. bash — execute shell commands
  3. edit — edit files with diffs
  4. write — write files

Two additional tools — grep and find — exist but are disabled by default. They're meant for read-only mode:

pi --tools read,grep,find

This gives you a Pi instance that can only read and search, never write — useful for programmatic/RPC usage where you don't want the agent editing files.

💡 Alejandro's personal setup: He adds web search as the only extra tool on top of the default four. That's his "real minimalist setup" and he finds it sufficient for most tasks.

8 Extensions — Pi's Modularity Layer

▶ 17:40

Extensions are TypeScript packages that modify Pi's behavior. They can:

  • Register new tools — add web search, MCP support, etc.
  • Subscribe to events — hook into tool_call, agent_response, user_message, and other lifecycle events
  • Register commands — add custom /commands
  • Add keyboard shortcuts
  • Add CLI flags
  • Update the system prompt
  • Render custom messages

Pi explicitly does NOT include MCP, web search, sub-agents, or plan mode out of the box. Instead, these are available as extensions — keeping the core minimal while letting users add exactly what they need.

⚠️ Security note: Extensions execute arbitrary code in your system. Alejandro recommends running untrusted packages through Pi itself to review the code before installing.

9 System Prompt Design

▶ 20:15

Pi's default system prompt is remarkably short — about 20 lines. The structure:

  1. "You are Pi, a helpful assistant" — the base identity
  2. Appended sections — from APPEND_SYSTEM.md in .pi/
  3. Skills list — names and descriptions in XML-like markup tags (parsed by the TUI layer)
  4. Current date and working directory

Overriding the system prompt

  • .pi/SYSTEM.md — completely replaces the default prompt
  • .pi/APPEND_SYSTEM.md — appends to the default prompt (non-destructive)
  • --system-prompt "text" — CLI flag override
💡 "Don't try to make it more minimalist" — Alejandro notes the system prompt is already extremely concise. Adding to it (via AGENTS.md or APPEND_SYSTEM.md) is fine, but there's very little to trim.

10 Pi Interactive — CLI Entry Point & TUI

▶ 22:51

Pi Interactive is a separate package from Pi Core. The entry point flows through two files:

  1. client.ts — receives the pi command, sets process title, calls main()
  2. main.ts — parses arguments, resolves config, loads extensions, creates agent session, runs in selected mode (interactive, RPC, or print-to-stdout)

The Terminal UI

The TUI is completely custom-built — it doesn't use Textual, Blessed, or any TUI framework. It's component-based: each component handles its own rendering, inputs, and dynamic updates. Components subscribe to events from the agent core.

The layout: message area on top, input at bottom, status bar with token usage, cost, model info, and current directory.

💡 Pi Core vs Pi Interactive: The core is a headless agent that runs anywhere (SDK, RPC, CLI). The interactive layer adds the TUI, keyboard shortcuts, custom commands, and skill loading — but you could replace it entirely with your own UI.

11 Compaction Mechanics — How Pi Measures Context

▶ 26:58

Alejandro finds Pi's compaction approach elegant in its simplicity. Unlike some agents that estimate tokens by dividing character count by 4, Pi relies on actual LLM response data.

When compaction is checked

  1. When an agent turn ends — after the model finishes all tool calls and returns a response
  2. Before the user sends a prompt — to ensure the context won't overflow

How token count is calculated

If the LLM provider returns context tokens directly → use them. Otherwise, Pi calculates from the response's usage object:

context = usage.input + usage.output + cache.read + cache.write

The compaction prompt

Located in packages/agent/source/harness/compaction/compactions.ts, the summarization prompt creates a structured checkpoint with sections: Goal, Constraints & Preferences, Progress (done / in progress / blocked), Key Decisions, Next Steps, Critical Context. The prompt instructs: "Keep each section concise, preserve exact file paths, function names, and error messages."

12 Skills Workflow — How Pi Loads Skills

▶ 33:00

This is the part Alejandro finds "most interesting." Skills and custom prompts (prompt templates) are handled differently, even though they seem similar:

Custom Prompts (Prompt Templates)

When you type /my-command, the interactive layer intercepts it and replaces it with the full prompt text. Pi Core never sees the slash command — it receives the expanded text directly.

Skills — A Two-Phase Design

Phase 1 (System Prompt): Skill names and descriptions are listed in the system prompt using XML-like markup tags. The LLM knows skills exist but doesn't have their full content.

Phase 2 (Invocation): When you type /skill:my-workflow, the interactive layer intercepts it and sends a structured message to Pi Core containing the skill's name, description, and file location — but NOT the full content. The system prompt includes an instruction: "if a skill is invoked, use the read tool to read it."

So the LLM receives the skill metadata, then uses the read tool to load the actual SKILL.md file from disk, and proceeds to follow its instructions.

💡 Why not just paste the full skill content? Some agents do that. Pi's approach is deliberate — it lets the model use a tool call to load the skill, which means the skill loading appears in the conversation history, can be inspected, and follows the same pattern as any other file read. Other CLIs could implement different mechanisms since this happens at the interactive layer, not in Pi Core.

🎯 Key Takeaways

🔑 Key Takeaways

  • Pi's architecture splits cleanly into Core and Interactive — the core is a headless agent loop (usable via SDK/RPC), the interactive layer adds the TUI and CLI features
  • The agent loop is built from scratch — no OpenAI Agents SDK or similar library. Init context → transform → LLM call → tool loop → response
  • Context = system prompt + AGENTS.md + skill descriptions + tool descriptions + message history + current message
  • Sessions are JSONL files with tree structure — each message has an id and parentId, enabling non-destructive forking via /tree
  • Only 4 default tools: read, bash, edit, write — grep and find exist but are disabled by default (for read-only mode)
  • Extensions are the modularity mechanism — TypeScript packages that register tools, subscribe to events, add commands/shortcuts, and modify the system prompt
  • The system prompt is ~20 lines — intentionally minimal. Override via SYSTEM.md, append via APPEND_SYSTEM.md
  • Compaction uses actual LLM usage data — not character-count estimates. Checked on agent turn end and before user prompts
  • The compaction summary is structured — goal, constraints, progress, key decisions, next steps, critical context
  • Skills use progressive disclosure — descriptions in system prompt, full content loaded via read tool call when invoked
  • The TUI is completely custom-built — component-based, no framework, subscribes to core events
  • Pi Core is educational — Alejandro considers it a great project to study for anyone wanting to build their own coding agent

🔗 Resources & Links

Timestamp Index

▶ 0:00 Introduction — Pi architecture overview
▶ 1:18 Pi Core — the agent loop
▶ 1:51 Context initialization (system prompt, AGENTS.md, skills, tools)
▶ 4:10 Context transformation & compaction check
▶ 4:47 LLM call & tool loop
▶ 6:52 Sessions & memory — JSONL storage
▶ 9:46 Tree-structured conversation history
▶ 11:54 Live demo — /tree and JSONL files
▶ 15:00 Tools — 4 default + 2 disabled (read-only mode)
▶ 17:40 Extensions — TypeScript modularity layer
▶ 20:15 System prompt design (~20 lines)
▶ 22:51 Pi Interactive — CLI entry point & TUI
▶ 26:58 Compaction mechanics
▶ 30:28 Compaction prompt & live demo
▶ 33:00 Skills workflow — progressive disclosure
▶ 38:52 Closing — building your own agent