Skip to main content

设计哲学与包架构:Minimal Core

Pi 给出的答案是「核心极简,行为由扩展装配」。这跟 Claude Code 那种「核心大而全、扩展只是补丁」的设计路线完全相反。本章先看它最上层的哲学、然后落到 4 个 npm 包的源码目录里,建立后续章节的坐标系。

一句话定位

官方 README 给出的定义是:

Pi is a minimal terminal coding harness. It is designed to stay small at the core while being extended through TypeScript extensions, skills, prompt templates, themes, and pi packages.

关键词是 stay small at the core——核心要小、不能膨胀,所有「工作流级别的能力」都外移到扩展层。这是一个非常有意识的产品决策:默认不内置 MCP、不内置 sub-agent、不内置 plan mode、不内置 to-dos、不内置后台 bash、不内置权限弹窗——这些都可以作为扩展、或者借助容器/tmux 等外部工具实现。

这是 Pi 跟 Claude Code 的第一个根本差异。Claude Code 是一个完整产品:内置 59 个工具、内置权限系统、内置会话管理、内置 hooks、内置插件市场。Pi 把这一切都拆出去,核心只做四件事:加载扩展、跑 agent 循环、读写 session 文件、提供 TUI。

跟其他 Coding Agent 的差异

维度PiClaude CodeOpenCode
核心大小极简,行为由扩展装配大而全,功能内置中等,模块化
MCP不内置(可作扩展)内置内置
Sub-Agent不内置(可作扩展)内置 Coordinator内置
权限系统不内置(靠容器化)内置多层权限内置
Plan Mode不内置内置内置
扩展机制TypeScript 模块 + 生命周期事件 + UIHooks + Skills + PluginsHooks
会话存储JSONL 树形结构,可分支JSONL 线性 + 内部状态JSONL
多 Provider内置统一抽象层主推 Anthropic内置

最值得记住的是安全模型那一行:Pi 没有任何进程级沙箱,文档明确说「这是故意的」。详细分析见第六章。

4 个 npm 包

仓库顶层是 monorepo(pi-mono),核心代码拆成 4 个 npm 包:

包名路径职责
@earendil-works/pi-aipackages/ai统一多 provider LLM API
@earendil-works/pi-agent-corepackages/agentAgent runtime,工具调用 + 状态管理
@earendil-works/pi-coding-agentpackages/coding-agent交互式 coding agent CLI
@earendil-works/pi-tuipackages/tui终端 UI 库,差分渲染

依赖方向是单向的:

pi-ai 是最底层——纯 LLM 适配层,没有任何 agent 概念;pi-agent-core 在它之上引入 agent 循环和工具调用;pi-tui 是独立的 UI 库,被 pi-coding-agent 用来渲染交互界面;最上层的 pi-coding-agent 把前面三者缝合成 CLI 产品。

这种分层的好处是:你只想在自己的应用里嵌入一个对话界面?引 pi-ai。你想搭一个非交互式 agent?引 pi-agent-core。你想直接拿 CLI 用?引 pi-coding-agent。每一层都是独立 npm 包,没有「整套大而全」的强耦合

源码目录导航

packages/coding-agent/ 是大部分用户最关心的包。进入后关键目录是:

packages/coding-agent/
├── docs/ # 文档源文件
├── examples/
│ └── extensions/ # 扩展示例
├── src/
│ ├── cli/ # CLI 入口、命令解析
│ ├── core/
│ │ ├── session-manager.ts # SessionManager(树形)
│ │ ├── messages.ts # 扩展消息类型
│ │ ├── compaction/ # 压缩与分支摘要
│ │ │ ├── compaction.ts
│ │ │ ├── branch-summarization.ts
│ │ │ └── utils.ts
│ │ ├── extensions/ # 扩展运行时 + 类型
│ │ └── ... # 工具、auth、model registry
│ ├── modes/ # 运行模式(interactive / rpc / json / print)
│ └── index.ts # createAgentSession 等 SDK 入口
├── package.json
└── npm-shrinkwrap.json

后续章节会用到的关键文件位置:

功能源文件
SessionManagersrc/core/session-manager.ts
扩展消息类型src/core/messages.ts
自动压缩src/core/compaction/compaction.ts
分支摘要src/core/compaction/branch-summarization.ts
扩展事件类型src/core/extensions/types.ts
自定义 compaction 示例examples/extensions/custom-compaction.ts
自定义 provider 示例examples/extensions/custom-provider-gitlab-duo/
基础消息类型packages/ai/src/types.ts
AgentMessage 联合类型packages/agent/src/types.ts
Provider env 映射packages/ai/src/env-api-keys.ts

为什么是「Minimal Core」

读源码时很容易感觉 Pi 故意「什么都不做」:没有权限弹窗、没有 plan mode、没有内置 to-do——这些 Claude Code 都默认有。但这背后是有意为之的产品判断。

第一,把决策权推给扩展层。 工作流级别的偏好(要不要 plan mode?要不要 to-do?消息队列是 steer 还是 followUp?)本质上是不同团队、不同场景下选择不同。Pi 选择不替你做决定——你要 plan mode,写一个扩展;你要后台 bash,写一个扩展;你要权限弹窗,写一个扩展。

第二,让核心保持可读、可演进。 Claude Code 的 prompts.ts 911 行、main.tsx 785KB 单文件,是「大而全」的代价——任何修改都要触碰核心。Pi 的核心保持极简,意味着扩展可以独立版本化、独立废弃、独立替换,核心不需要承担所有兼容责任

第三,匹配 Pi 自身的安全哲学。 「无沙箱」的设计如果加上内置权限弹窗,会给人「agent 是受控的」错觉,反而危险。把隔离责任彻底推给 OS / 容器 / 虚拟机,让用户清楚意识到这是无保护的进程——这才跟「明确告知无安全边界」的安全模型一致。

这套哲学不是没有代价。Pi 的上手门槛比 Claude Code 高:新用户第一次跑 pi,看到的只是一个最小可用的 CLI;想要 plan mode、想要 to-do、想要 IDE 集成,得自己去装扩展或者写扩展。但 Pi 团队显然认为这个代价是可接受的——他们赌的是核心的稳定性比开箱即用更重要。


下一章进入 Session 设计。Pi 把「会话」这件事做成了 JSONL 树形结构,而不是 Claude Code 那种近似线性的内部状态。这是 Pi 最核心的数据结构创新,也是后续所有能力(分支、回滚、压缩)的基础。