AI Research

earendil-works/pi 深度技术研究:从 4 个原子工具到 4 层扩展的代码级解剖

2026-06-05 #pi#earendil#deep-dive#cli-agent#ai-agent

earendil-works/pi 深度技术研究:从 4 个原子工具到 4 层扩展的代码级解剖

本笔记是对 earendil-works/pi 的纵深研究,配合横向对比笔记 pi-agent-vs-claude-code-codex.md 食用。30k 视角放在那一份;这一份只挖实现层:源码文件分布、agent loop 主循环长什么样、4 个原子工具的真实参数与截断策略、系统提示与压缩机制的字符串原文、扩展生命周期事件名一一列举、Session 树的 v1/v2/v3 schema 演进、pi-ai 12 个内建 provider、pi-tui 差分渲染机制等。截至 2026-06-05,主线版本为 v0.78.1

摘要

earendil-works/pi 表面是一个 ~60k stars 的 CLI 编码代理,本质是一套故意保持骨架级最小的 agent harness:核心由 4 个 TypeScript 包构成(ai / agent / coding-agent / tui,分别对应 npm 上的 @earendil-works/pi-ai@earendil-works/pi-agent-core@earendil-works/pi-coding-agent@earendil-works/pi-tui),系统提示控制在 1000 token 以内,工具集只暴露 read / write / edit / bash 四个原子动作,整个低层 agent loop 据中文综述大约 1500 行代码 / 5 个文件silenceper 综述),其余所有”产品功能”——MCP、subagent、plan mode、permission popup、todo list——一律下放给用户用 4 层扩展(skills / prompt templates / extensions / packages)自行组合。本笔记从代码结构层和设计原理层把这套机制拆开:哪几个文件在跑 agent loop、bash 工具是怎么截断输出、edit 是怎么避免并发改文件、Session JSONL 的 V1→V3 schema 怎么自动迁移、扩展事件总线上有哪些可阻断 hook、20+ provider 是怎么 lazy load、ChatGPT Pro / Claude Pro / Copilot 三种订阅 OAuth 怎么挂在同一个抽象层之下、pi-tui 又是用 CSI 2026 同步输出 + 三策略差分渲染做到无闪烁。最后给出与 Claude Code / Codex CLI 在实现机制层(不是产品功能层)的逐项对比。

项目身份与活跃度(精简)

详细身份见对比笔记,这一节只列与代码结构相关的少量事实。

  • 仓库earendil-works/pi(旧名 badlogic/pi-mono,2026-04 随 Mario Zechner 加入 Earendil PBC 后整体迁移;GitHub 已对旧 URL 做 transfer-redirect)
  • License:MIT
  • 主语言:TypeScript(93.5%)
  • 最新版本:v0.78.1(2026-06-04,226 个 release)
  • stars / forks / open issues:≈59.9k / ≈7.2k / 45(GitHub 仓库主页
  • monorepo 包packages/{ai, agent, coding-agent, tui} 4 个;这是 GitHub 上的目录名,对应 npm 包名分别为 @earendil-works/pi-ai / pi-agent-core / pi-coding-agent / pi-tui。坐落在 earendil-works 组织下的姊妹仓库还有 gondolin(microvm 沙箱)、pi-chat(IM 集成)、pi-review(评审扩展)、pi-tutorial(教程模式)、absurd(Postgres durable workflow 实验)等共 10 个仓(组织页)。

设计哲学:”Primitives, not products” 深度解读

pi.dev 主页的官方定调:*”Pi is a minimal terminal coding harness… Rather than shipping with pre-built features, Pi emphasizes letting users build what they need. The philosophy centers on providing ‘primitives, not features’.”*(pi.dev)—— 注意 pi.dev 主页用的是 “primitives, not features”,而 README 里更常见的措辞是 “primitives, not products”,社区中文综述则把它泛化成”五个 No”:

No MCP / No sub-agents / No plan mode / No permission popups / No bloated system prompts(CSDN 深度解读 by 程超)。

把这个哲学翻译成具体的代码取舍,可以归纳为四点:

  1. 核心包尺寸的硬约束 — 中文社区按文件数粗算 packages/agent/src/ 大约 5 个文件 / 1.5k LoC 就跑完整个 agent loop(agent-loop.ts / agent.ts / proxy.ts / types.ts / index.ts,仓库当前主分支与社区描述相符),任何额外功能都得放进上层包或扩展(silenceper 综述)。
  2. Token 预算的硬约束 — 系统提示 < 1000 token;对照 Claude Code 的 10k+,这是个两个量级的差距。代价是模型必须自己掌握编辑/搜索的常识,pi 不教,pi 只暴露工具(CSDN)。
  3. 责任倒置(trust the model) — 不内置 plan mode / sub-agent / todo 不是因为没需求,而是因为把这些做成内核会强迫一种工作流。pi 的态度是”把 4 个原子动作交给现代 LLM,让模型自己决定怎么组合”,需要 plan/subagent 的时候用扩展(仓库 examples/extensions/plan-mode/examples/extensions/subagent/ 是官方示例)就好。
  4. 责任倒置(trust the user) — 对应”不做权限弹窗”。官方 README 直说:”Pi runs with the permissions of its launching user/process—there’s no built-in access control. For stricter isolation, the documentation recommends containerization using OpenShell, Gondolin extensions, or Docker approaches.”(README)这让 pi 在企业落地时有明显短板,但保持了 harness 层的纯净。

社区把这条路线和 Claude Code/Codex 形成的对照称为”fat harness vs thin harness“。与之对应,社区已经出现明显的”补完”型分叉项目,Oh-My-Pi(omp) 是其中代表:保留 pi 的 4 工具内核,但默认装齐 subagent / MCP / 权限层等”成品功能”(SegmentFault:Pi 极简 vs Oh-My-Pi 全能)。

4 包架构

packages/ai — 统一 LLM provider 层(@earendil-works/pi-ai

依赖关系最底层,纯抽象 LLM 协议,不知道什么是 agent,也不依赖 tui。核心源文件(packages/ai/src):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
api-registry.ts          # 注册/查找/卸载 ApiProvider
bedrock-provider.ts # AWS Bedrock 单独走 Node-only 入口
cli.ts
env-api-keys.ts
image-models.generated.ts / image-models.ts / images-api-registry.ts / images.ts
index.ts
models.generated.ts / models.ts
oauth.ts # 仅是 re-export 自 utils/oauth/index.ts
session-resources.ts
stream.ts # 统一 stream() / complete() 入口
types.ts
providers/ # 12 个 provider 实现 + 3 个 utility
amazon-bedrock.ts
anthropic.ts
azure-openai-responses.ts
cloudflare.ts
faux.ts # 测试用伪 provider
github-copilot-headers.ts
google-shared.ts / google.ts / google-vertex.ts
mistral.ts
openai-codex-responses.ts
openai-completions.ts
openai-prompt-cache.ts
openai-responses-shared.ts / openai-responses.ts
register-builtins.ts # lazy 注册全部 builtin
simple-options.ts
transform-messages.ts

注意:providers/ 里的文件数比 README 宣传的 “20+ providers” 少。原因是一个文件可以服务多个 provider——例如 openai-completions.ts 同时承担 Ollama / vLLM / LM Studio / DeepSeek / xAI / Groq / Together / OpenRouter / Hugging Face 等所有”OpenAI Completions 兼容”的提供商,靠 ~/.pi/agent/models.jsonapi: "openai-completions" + 不同 baseUrl 区分(docs/custom-provider.md 思路 + docs/models.md 显式)。register-builtins.ts 用动态 import() lazy 加载每个 provider 模块,并把 stream / streamSimple 两套接口都注册到中央 registry,这样 clearApiProviders() + resetApiProviders() 可以做到运行时换 provider 不重启进程(register-builtins.ts)。

packages/agent — Agent 运行时(@earendil-works/pi-agent-core

中层,依赖 pi-ai,不依赖 coding-agenttui。核心源文件(packages/agent/src):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
types.ts          # AgentMessage / AgentTool / AgentEvent / AgentLoopConfig 定义
agent-loop.ts # agentLoop() / agentLoopContinue() 低层循环
agent.ts # Agent 类(高层,状态管理 + 事件总线 + steer/followUp 队列)
proxy.ts # 代理与 transport
node.ts # Node.js 入口
index.ts
harness/ # 二级抽象:把 prompt/skills/compaction/session 都包好
agent-harness.ts
messages.ts
prompt-templates.ts
skills.ts
system-prompt.ts
types.ts
compaction/ env/ session/ utils/

关键设计:把”低层循环”与”高层有状态 Agent”切开。agentLoop() 是纯函数风格的 EventStream 生成器,没有持久状态;Agent 类包一层,管 transcript / streaming flag / pendingToolCalls / errorMessages / steer 队列 / followUp 队列。文档明确:”Agent owns the current transcript, emits lifecycle events, executes tools, and exposes queueing APIs for steering and follow-up messages.”(agent.ts 摘要)。

harness/ 这一层是 coding-agent 走 SDK 路径时使用的”半成品 harness”,把 system prompt 构造、skills 加载、compaction 触发、session manager 整合在一起;如果你只是用 Agent + agentLoop(),可以完全绕过 harness 层。

packages/coding-agent — 交互式 CLI 与高层 SDK(@earendil-works/pi-coding-agent

依赖 pi-agent-corepi-tuipi-ai,是用户实际跑的旗舰包。源码文件分布(packages/coding-agent/src):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
src/
cli.ts main.ts index.ts config.ts
migrations.ts package-manager-cli.ts
bun/ cli/ modes/ utils/
core/
agent-session.ts # 这是 CLI 用的核心 session 类
agent-session-runtime.ts # 多 session 切换/fork/clone
agent-session-services.ts
auth-guidance.ts auth-storage.ts
bash-executor.ts # bash 工具底层
defaults.ts diagnostics.ts
event-bus.ts # 极薄的 EventEmitter wrap
exec.ts http-dispatcher.ts
footer-data-provider.ts
keybindings.ts messages.ts
model-registry.ts model-resolver.ts
output-guard.ts
package-manager.ts
prompt-templates.ts # 加载 .md 模板 + $1/$@ 替换
provider-attribution.ts provider-display-names.ts
resolve-config-value.ts
resource-loader.ts # 喂 skills / prompts / themes / extensions
sdk.ts # createAgentSession 高层工厂
session-cwd.ts session-manager.ts
settings-manager.ts
skills.ts # progressive disclosure 实现
slash-commands.ts source-info.ts
system-prompt.ts # 默认 prompt 模板与 guidelines 拼接
telemetry.ts timings.ts
compaction/
branch-summarization.ts compaction.ts utils.ts index.ts
export-html/
extensions/
index.ts loader.ts runner.ts types.ts wrapper.ts
tools/
bash.ts edit.ts edit-diff.ts file-mutation-queue.ts
find.ts grep.ts ls.ts
output-accumulator.ts path-utils.ts
read.ts render-utils.ts
tool-definition-wrapper.ts truncate.ts write.ts
index.ts

注意四件事:

  1. 工具不止 4 个。除了广告里宣传的 read / write / edit / bash 外,仓库 tools/ 目录下其实还实现了 find / grep / ls 三个”helper 工具”。SDK 文档把它们也列出来了:*”Enable or disable built-in tools (read, bash, edit, write, grep, find, ls) or create custom tools”*(docs/sdk.md)。但它们默认不暴露给 LLM——coding-agent 默认只把 4 个原子工具塞进 system prompt 与 tool-call schema;find/grep/ls 主要给 SDK 集成方与扩展开发者用,模型可以调用 bash 自行 rg / find / ls(system prompt 里有专门一句 “Use bash for file operations like ls, rg, find” 引导模型走 bash 而非内建工具,见下文)。
  2. edit-diff.tsfile-mutation-queue.ts 是为了让 edit 安全可重放file-mutation-queue 给所有写文件操作排队,避免同一会话里多个 tool call 并发写同一文件出现 race。
  3. extensions/ 目录是分层的loader.ts 负责发现 + 加载、runner.ts 负责事件分发、wrapper.ts 负责把 ExtensionAPI 适配到 Agent,types.ts 是公开 API 类型。
  4. compaction/export-html/ 单独分包,配合 docs/compaction.md 与 docs/session-format.md 共同把”上下文管理”与”分享”做成可独立替换的子系统。

packages/tui — 终端 UI 库(@earendil-works/pi-tui

最底层与 pi-ai 平级、可被独立使用的包。源文件清单(packages/tui/src):

1
2
3
4
5
6
autocomplete.ts editor-component.ts fuzzy.ts index.ts
keybindings.ts keys.ts kill-ring.ts
native-modifiers.ts stdin-buffer.ts
terminal-image.ts terminal.ts tui.ts
undo-stack.ts utils.ts word-navigation.ts
components/ # 内建组件库

设计目标在 README 里说得很直接:*”a lightweight framework for building flicker-free interactive CLI applications using differential rendering and synchronized output.”* 关键能力包括 three-strategy 差分渲染、CSI 2026 synchronized output(让多行更新看起来像一次原子提交,从而消除闪烁)、Kitty/iTerm2 行内图像协议、IME 光标定位(CJK)、>10 行粘贴自动转占位符标签。

4 包依赖箭头

1
2
3
4
5
6
7
                tui

| (可选;agent-core 不依赖 tui)
|
ai ← agent ← coding-agent
↑ ↑
└── 也可独立用 ────┘

四个包都可以独立安装与使用。具体的:pi-ai 可以单独做 LLM proxy 库;pi-agent-core 可以嵌入 Web/Desktop 应用;pi-coding-agent 同时暴露 CLI 二进制与 SDK 入口;pi-tui 也是独立 npm 包。

agent loop 与 4 个原子工具

启动一次 pi 命令到第一次 token 输出

main.tscli.tsagent-session.tsagent.tsagent-loop.ts 串起来,发生顺序大致如下(综合 main.tsagent-session.tsagent-loop.ts 的官方/AI 摘要):

  1. parseArgs() 解析 CLI flags → SessionCreateOptions
  2. readPipedStdin() 检测 stdin 是否被管道喂入。
  3. createSessionManager() 决定是新建 / resume / fork / --no-session,并打开/创建 JSONL 文件。
  4. createAgentSessionServices() 装配 model-registry、settings、auth、resource-loader(加载全局/项目两层 settings + extensions + skills + prompts + themes)。
  5. system-prompt.ts:buildSystemPrompt() 拼接:默认 prompt 头 + tool 列表 + guidelines + 项目 context 文件(AGENTS.md / CLAUDE.md)+ skills 索引 + 当前日期 + cwd。
  6. 选择 mode:InteractiveMode / runPrintMode / runRpcMode / JSON 模式(按 stdin/--mode 决定)。
  7. 实例化 AgentSession(运行模式都共享同一个),订阅 agent events,把每个 event 转写成 SessionManager 里的 entry 并 append 到 JSONL。
  8. 用户敲入第一条消息 → Agent.prompt(messages)agentLoop() 把 messages 通过 convertToLlmMessages() 转成 LLM 协议消息 → 调用 pi-aistream() → 模型首 token 通过 EventStream 流回 → UI 渲染。

_runAgentPrompt 主循环(伪代码)

agent-session.ts 的核心方法是 _runAgentPrompt,根据 WebFetch 摘要 还原的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
async _runAgentPrompt(messages) {
await this.agent.prompt(messages);
while (await this._handlePostAgentRun()) {
await this.agent.continue();
}
this._flushPendingBashMessages();
}

async _handlePostAgentRun(): Promise<boolean> {
// 1) 自动重试:检测 rate limit / overload / 5xx,指数退避
if (isRetryableError(this.lastError)) {
await sleep(backoff());
return true;
}

// 2) 压缩:两种触发
if (contextOverflow()) { // 已经超窗
await this._compact();
return true; // 压缩完自动重试
}
if (contextThresholdReached()) { // 接近窗口
await this._compact();
return false; // 仅压缩,不重试
}

// 3) 队列消息:steer / followUp
if (this.queuedMessages.length > 0) {
return true;
}

return false;
}

而下层 agent-loop.tsrunLoop()双层循环架构:外层处理 follow-up 消息、内层处理 tool call + steer 消息(agent-loop.ts 摘要)。每次 LLM 调用前都会 validate context ends with appropriate message roles,避免 tool_use/tool_result 配对错乱。

4 个原子工具的真实 schema 与截断策略

read — 文本/图像读取(read.ts

  • 参数path(相对/绝对都行)、可选 offset(1-indexed 行号)、可选 limit
  • 默认上限2000 行 或 4 KB(哪个先到先截)。
  • 图像:JPG / PNG / GIF / WebP;自动 resize 到 ≤ 2000×2000;非 vision 模型会拿到一段 “image omitted” 的文字说明(避免把 base64 灌爆 context)。
  • 特殊截断分支:源码注释里特意写道 *”First line alone exceeds the byte limit. Point the model at a bash fallback.”*——遇到一行就超 4 KB 的怪文件,直接劝模型改用 bash + head/sed
  • 可插拔后端:通过 ReadOperations 接口可委派到 SSH / 容器 / 远程 VM;gondolin 扩展正是用这个钩子把所有 read 路由进 microvm。

write — 文件创建/覆盖(write.ts

  • 参数path(兼容 file_path 别名,处理不同模型的 schema 漂移)、content
  • 行为:创建文件;父目录自动 mkdir -p;存在则覆盖。
  • **WriteHighlightCache**:每次渲染时增量做语法高亮,避免大文件被反复全量高亮。
  • 并发安全:经过 file-mutation-queue 排队,与 edit 互斥。
  • AbortSignal 处理:每次 await 后再检 signal.aborted,避免半写状态。

edit — 精确文本替换(edit.ts

  • 参数path + 一个 edits 数组,每个元素 { oldText, newText }。是精确字符串替换,不是 unified diff、不是 patch、不是 line-number 偏移。
  • 预处理:BOM 剥离 + 行尾归一化(回写时还原原始 CRLF/LF)。
  • 重叠校验:拒绝 oldText 互相 overlap 的 edits。
  • diff 输出:执行结果同时返回两种 diff —— 给用户 UI 看的”展示型 diff” + 给 LLM 后续 reasoning 用的 unified patch;并返回首个改动行号供编辑器跳转。
  • Live preview:用户输入未提交时就能在 TUI 里预览将要应用的改动。
  • edit-diff.ts 单独承担 diff 生成;**file-mutation-queue.ts** 防并发。

设计取舍很明显:edit 不做 fuzzy 匹配、不做 line-number、不做 patch。这把”上下文是否准确”的责任彻底压给模型——它必须先 read 拿到精确字符串。这种简单接口反过来逼 LLM 用更可靠的工作流(先 read 再 edit),并大幅降低工具执行失败率,是 pi 哲学的代表性体现。

bash — Shell 执行(bash.ts + bash-executor.ts

  • 参数command(字符串)、可选 timeout 秒数。
  • 流式输出stdout + stderr 实时回传;UI 节流到 每 100ms 刷一次
  • 截断50 行 或 1 MB(先到先截)。截断时全量内容写 temp 文件,路径通过 fullOutputPath 字段返回,模型可以在下一轮用 read 把 temp 文件内容拿回。
  • Sanitize:剥 ANSI、把二进制乱码替换成可见字符、归一换行符;输出 buffer 上限 DEFAULT_MAX_BYTES * 2
  • AbortSignal:被取消时 cancelled: true + exitCode: undefined,与正常退出区分;底层走 process tree kill。
  • BashOperations 接口:把”实际执行”抽到 interface 层,允许扩展把整个 bash 路由到 SSH / Docker / Gondolin microvm。
  • **BashSpawnHook**:扩展可以在每个命令真正 spawn 前拦截并改写(典型用法:在 git push 前再确认一次)。

设计哲学层的特别说明:bash 是 pi 的真正逃生舱。模型如果发现 4 个工具不够用(要重命名、要 grep、要 build),就直接 bash。这把”工具列表庞大”的复杂度从核心搬到LLM 的常识——这也是 pi 把 system prompt 控制在 < 1k token 的根本前提。

与 Claude Code / Codex 工具集对照(实现层)

工具 pi Claude Code Codex CLI
读取文件 read(2000 行 / 4 KB) Read 内建
创建/覆盖 write Write 内建
编辑 edit(多个 oldText/newText) Edit(含 Multi-Edit,类似机制) apply_patch(unified diff)
Shell bash(50 行 / 1 MB) Bash(含 BashOutputKillBash 子工具) shell(带 local_shell 类型)
搜索 让 LLM 直接 bash rg/grep/find;内建 grep/find 仅 SDK 用 一等公民工具 GrepGlob 自带
Web 不内建(需 pi-web-access 扩展) WebSearchWebFetch 扩展
Plan 不内建(示例扩展 plan-mode/ 一等公民 不内建
Subagent 不内建(示例扩展 subagent/ 一等公民(多 subagent 并行 + 仲裁) 不内建

apply_patch vs edit 的差别值得单独点出:Codex 把”让模型生成 diff”这个负担显式化,对应能力较强的模型上下文消耗更小;pi 把这个负担留给”模型自己组装 oldText/newText”,简单但容易漏字符串。

系统提示与上下文管理

默认系统提示原文

packages/coding-agent/src/core/system-prompt.ts 的默认 prompt 模板(WebFetch 抓取的 verbatim 字符串):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
You are an expert coding assistant operating inside pi, a coding agent harness.
You help users by reading files, executing commands, editing code, and writing
new files.

Available tools:
${toolsList}

In addition to the tools above, you may have access to other custom tools
depending on the project.

Guidelines:
${guidelines}

Pi documentation (read only when the user asks about pi itself, its SDK,
extensions, themes, skills, or TUI):
- Main documentation: ${readmePath}
- Additional docs: ${docsPath}
- Examples: ${examplesPath} (extensions, custom tools, SDK)
- When reading pi docs or examples, resolve docs/... under Additional docs and
examples/... under Examples, not the current working directory
- When asked about: extensions (docs/extensions.md, examples/extensions/),
themes (docs/themes.md), skills (docs/skills.md), prompt templates
(docs/prompt-templates.md), TUI components (docs/tui.md), keybindings
(docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers
(docs/custom-provider.md), adding models (docs/models.md), pi packages
(docs/packages.md)
- When working on pi topics, read the docs and examples, and follow .md
cross-references before implementing
- Always read pi .md files completely and follow links to related docs
(e.g., tui.md for TUI API details)

变量填充:

  • ${toolsList} — 形如 - read: <snippet> 的 4 行(可被 --exclude-tools/-xt 减成 3 行甚至更少)。

  • ${guidelines} — 默认包含 3 条:

    1. *”Use bash for file operations like ls, rg, find”*(仅当 bash 可用时拼入;这是把”搜索/列目录”显式劝退到 bash 的关键句)
    2. “Be concise in your responses”
    3. “Show file paths clearly when working with files”
    • 用户通过 promptGuidelines / .pi/SYSTEM.md / 自定义 prompt 追加的内容。
  • 末尾自动追加AGENTS.mdCLAUDE.md 内容(项目级 context 文件)+ skills 索引(仅 name + description,不含正文)+ Today's date is YYYY-MM-DD + Current working directory: /path/to/cwd

Token 预算实测:以默认 4 工具 + 3 guidelines + 没有项目 AGENTS.md 时,整个 system prompt 大约 400–600 token 区间,远低于 1000 token 上限。即便在所有 27 个 docs 路径都列出来的扩展 reference 段,也不会超 1k——因为这一段只是路径清单,模型按需 read 即可。

Compaction(自动压缩)

core/compaction/compaction.ts + utils.ts 实现两套机制(docs/compaction.md):

Compaction(沿主线压缩)

  • 触发:上下文 token 超过 windowSize - reserveTokens(默认 reserveTokens = 16384)。

  • 算法:从最新消息往前回溯,累加 token,直到 keepRecentTokens默认 20000)。把更老的消息提取出来,序列化成文本(每条 tool_result 上限 2000 字符),喂一个独立 LLM 调用做摘要,写回成 CompactionEntry 添加到 session 末尾。

  • SUMMARIZATION_SYSTEM_PROMPT verbatim(compaction/utils.ts):

    1
    2
    3
    4
    5
    6
    You are a context summarization assistant. Your task is to read a conversation
    between a user and an AI coding assistant, then produce a structured summary
    following the exact format specified.

    Do NOT continue the conversation. Do NOT respond to any questions in the
    conversation. ONLY output the structured summary.

    注意 issue #5401 指出这里硬编码了 “AI coding assistant”,对非编码会话不够通用——这是当前的 known limitation。

  • 结构化输出:摘要格式固定为 markdown 章节 goal / progress / decisions / critical context,并把 file operations 累计到 details.fileOperations(这样多次压缩之后还能追溯哪些文件被改过)。

  • Split-turn 处理:单个 turn 自身就超预算时生成两份摘要再合并,避免消息丢失。

Branch Summarization(切分支时压缩)

  • 触发:用户在 /tree 里跳到一个不同分支时。
  • 算法:找当前活跃叶子与目标节点的最近公共祖先,把”被放弃的那一支”的所有 entries 收集起来生成 BranchSummaryEntry,附在新分支起点,让模型继续工作时仍能感知”被丢弃的那条思路”。

可定制点

两个 hook:

  • session_before_compact(扩展可阻断或替换 compaction,例如换更便宜的摘要模型)
  • session_before_tree(同样可在 branch summary 前拦截)

reserveTokens / keepRecentTokens 可在 ~/.pi/agent/settings.json 里调(docs/settings.md)。

上下文窗口耗尽时的回退

_handlePostAgentRun 的代码路径里压缩失败/不足时:

  1. 触发自动重试(指数退避,可配置 maxAttempts)。
  2. 如果是 contextOverflow(已超窗),压缩成功后自动重试return true)。
  3. 如果是 contextThresholdReached(接近超窗),压缩后不重试return false)——等用户下一条消息再继续。
  4. 模型切换:modelChange 事件会跳过 overflow 检查(因为换模型可能换 window size),让用户手动决定是否压缩。

4 层扩展系统(重点章节)

pi 的扩展是分四层的洋葱模型,从外到内:”Skills(知识层)→ Prompt Templates(提示工程层)→ Extensions(运行时代码层)→ Packages(分发层)“。这一节把每一层的机制单独剖一遍,再讨论它们互相的边界与组合关系。

4.1 Skills — 按需加载的知识包(progressive disclosure)

数据形态

每个 skill 是一个目录,必含 SKILL.md,frontmatter 强制要求 name(≤64 字符、小写字母/数字/连字符、不能首尾连字符也不能连续连字符)+ description(≤1024 字符)。可选字段含 licensedisable-model-invocation(设 true 后只允许 /skill:name 显式触发,不进 system prompt)(docs/skills.md)。

支持目录树嵌套;.gitignore / .ignore / .fdignore 都被尊重。Symlink 会用 canonical 路径去重。

Progressive Disclosure 的具体机制

core/skills.ts 的逻辑(综合 skills.ts 摘要 + docs/skills.md):

  1. 启动时扫描loadSkills() 从 4 处加载——
    • ~/.pi/agent/skills/(用户级)
    • <cwd>/.pi/skills/(项目级)
    • npm package 内的 skills/ 目录(来自 package.jsonpi.skills
    • CLI --skill 参数显式指定的路径
  2. 进 system prompt 的只是索引formatSkillsForPrompt() 把所有 skill 的 name + description 打包成 XML 风格列表附在 system prompt 末尾(可能形如 <skills><skill name="..." description="..."/>...</skills>),不含 SKILL.md 正文
  3. 匹配后才加载正文:模型如果决定使用某个 skill,会用 read 工具去读对应 SKILL.md 的完整内容;或者用户手动 /skill:name 触发。这样”100 个 skills”在静态状态下的 token cost 还是可控(每个 skill 大约 50–100 token 的索引开销)。

Skills 与 Claude Code Skills / MCP 的对应关系

  • Claude Code Skills:完全对标。pi 文档明确说 “Following the Agent Skills standard”,即遵循同一份 Anthropic-skills-spec。一个细微差异:pi 允许 name 与目录名不一致(在多工具共享 skills 目录时方便)。
  • MCP:MCP 是协议层(外部进程提供工具/资源),Skills 是知识包(喂 prompt 文本 + 触发模型调用既有工具)。pi 不内建 MCP。社区 pi-mcp-adapter(≈99K 月下载)通过 extension 把 MCP 桥接到 pi(pi.dev/packages)。

4.2 Prompt Templates — /cmd 斜杠命令

prompt-templates.ts + docs/prompt-templates.md 的关键点:

  • 形态:每个模板是一个 .md 文件(可选 YAML frontmatter,含 description / argument-hint),文件名决定命令名(review.md/review)。
  • 加载位置~/.pi/agent/prompts/ / <cwd>/.pi/prompts/ / npm package 内 prompts/ / settings.json resourceLoader / CLI --promptprompts/ 默认非递归,需要子目录得在 settings 显式开。
  • 参数替换:bash 风格——$1 $2 位置参数、$@/$ARGUMENTS 全部参数 join、${@:N} ${@:N:L} 切片。
  • 防注入:源码注释明确——*”Argument values containing patterns like $1, $@ are NOT recursively substituted.”* 用户传的参数不会被二次展开成另一个占位符。

4.3 Extensions — TypeScript 运行时模块

这是 pi 扩展系统里”代码量最大、能力最强”的一层。文件分布 src/core/extensions/: index.ts / loader.ts / runner.ts / types.ts / wrapper.ts

加载位置

自动发现:

  • ~/.pi/agent/extensions/*.ts(全局)
  • <cwd>/.pi/extensions/*.ts(项目级)
  • settings.jsonresourceLoader.extensions: [npm:..., git:..., ./local]

ExtensionAPI 能力清单

来自 core/extensions/types.ts + docs/extensions.md + examples/extensions/README.md

1
2
3
4
5
6
7
8
interface ExtensionAPI {
on(event, handler); // 订阅事件(见下)
registerTool(def); // 注册新工具,参数用 TypeBox schema
registerCommand(name, handler); // 注册 /command
registerKeybinding(...); // 注册键盘快捷键
registerProvider(...); // 注册自定义 LLM provider 或覆盖内建
appendEntry(...); // 持久化扩展自己的状态到 session JSONL
}

生命周期事件清单(从 types.ts 摘要 + docs 还原)

按出现顺序:

阶段 事件名 可阻断/可改写
Session session_start
Session session_before_switch / session_before_fork / session_before_compact / session_before_tree 可 cancel
Session session_shutdown
Agent before_agent_start 可改 system prompt / 工具集
Agent agent_start / agent_end
Turn turn_start / turn_end
Message message_start / message_update(流式)/ message_end
Tool tool_call(参数已就绪、未执行) 可阻断(→ permission gate)
Tool tool_execution_start / tool_execution_end
Tool tool_result 可改写返回值
模型/思考 model_select / thinking_level_select
输入 input 可改写或拦截(→ input transform)
队列 queue_update(steer/followUp 队列变化)

tool_calltool_result 的可阻断/可改写性是 pi 扩展能做”权限门 / 路径保护 / 输出 sanitize”的关键。例子见 examples/extensions/permission-gate.tsprotected-paths.tstool-override.ts

ctx.ui 与 RPC 模式协议

事件 handler 收到的 ctx 提供 UI 原语:

  • ctx.ui.notify(text, level) — 火-忘式
  • ctx.ui.select(options) / confirm(text) / input(prompt) / editor() — 阻塞式 dialog
  • ctx.ui.custom(component) — 用 pi-tui 组件渲染任意 UI
  • ctx.mode"interactive" | "rpc" | "json" | "print",扩展可据此降级(v0.78.1 才稳定下来,release notes
  • ctx.getSystemPromptOptions() — 拿原始 system prompt 选项做检查

RPC 模式下 ctx.ui.* 走的是文档化 JSON 协议(docs/rpc.md),父进程实现这些方法即可在外部 UI(Web / 桌面)里弹出 select / confirm / input。

60+ 个示例扩展的概貌

examples/extensions/9 个子目录 + 70+ 单文件扩展。挑能反映扩展系统能力边界的几个:

  • plan-mode/ — Claude Code 风 plan mode:bash allowlist(cat/grep/ls/pwd 等)+ 模型用 Plan: header 列出步骤 + 完成时打 [DONE:n],进度组件展示。/plan --plan Ctrl+Alt+P 三种触发(plan-mode/README)。
  • subagent/ — 委派任务给隔离 subagent,每个跑独立进程独立 context window;最大 8 任务、并发 4。内置 4 个角色:Scout(Haiku,快速侦察)/ Planner(Sonnet)/ Reviewer(Sonnet)/ Worker(全权)Ctrl+C 可中断子 agent 进程(subagent/README)。
  • gondolin/ — 把所有内建工具路由进 microvm;auth 留宿主、tools 进 VM。
  • sandbox/ — OS 级沙箱(Linux Landlock / macOS Seatbelt / Docker),按项目配置。
  • doom-overlay/ — DOOM 在 35 FPS 跑在 overlay 里。仪式性的”看 pi-tui 多能整活”展示。
  • dynamic-resources/ — 用 resource discovery API 动态加载 skills/prompts/themes。
  • custom-provider-anthropic / custom-provider-gitlab-duo / with-deps — 自定义 provider 的样板(前者带 OAuth)。
  • 单文件(>60 个)覆盖 permission-gate.ts / protected-paths.ts / git-checkpoint.ts / git-merge-and-resolve.ts / github-issue-autocomplete.ts / ssh.ts / interactive-shell.ts / structured-output.ts / todo.ts / preset.ts / questionnaire.ts / handoff.ts / pirate.ts / snake.ts / tic-tac-toe.ts / space-invaders.ts

一个隐蔽的设计点:例子里有完整 snake / tic-tac-toe / space-invaders 三个游戏,是 Mario 故意展示”扩展系统的表达力”——证明你可以在 agent harness 里嵌任意交互 UI。这种”博物馆式过度展示”在 Claude Code/Codex 里基本看不到。

4.4 Packages — 分发层

package.json 声明(docs/packages.md

1
2
3
4
5
6
7
8
9
{
"keywords": ["pi-package"],
"pi": {
"extensions": ["./extensions"],
"skills": ["./skills"],
"prompts": ["./prompts"],
"themes": ["./themes"]
}
}

或者直接放约定目录(extensions/ / skills/ / prompts/ / themes/)即可被 auto-discover。

安装来源 4 种 + 命令对应

1
2
3
4
5
pi install npm:@foo/bar@1.0.0           # → ~/.pi/agent/npm/<scope>__<name>/
pi install git:github.com/user/repo@v1 # → .pi/git/...
pi install https://github.com/user/repo # 同上
pi install ./relative/path # local 链接
pi -e npm:@foo/bar # 一次性、本会话临时

管理:pi list / pi update / pi update <pkg> / pi remove。版本走的就是 npm semver / git tag。

安全模型(明确推卸责任)

文档原文:*”Pi packages run with full system access. Extensions execute arbitrary code, and skills can instruct the model to perform any action including running executables.”* 责任明确推到用户——审计自己装的代码。这是 pi 与 Claude Code/Codex 的”权限弹窗 + 文件白名单”路线最大的哲学分歧。

注:v0.78.1 引入了”安装目录权限收紧”——extension 安装目录改成私有 directory,至少避免他人写入;但运行时权限仍然等同进程

与 Claude Code / MCP / Plugins 的对应

概念 pi Claude Code
知识包 Skills(SKILL.md Skills(同标准)
Slash 命令 Prompt Templates Slash Commands
运行时代码 Extensions(TS) Hooks(pre/post)+ MCP server
协议工具 不原生(需 pi-mcp-adapter MCP 一等公民
分发 Packages(npm/git/local) npm + Anthropic registry

简化说法:pi 用一种统一机制(Extensions)覆盖了 Claude Code 的 Hooks + MCP + 部分 Skills,代价是用户自己写更多 TS 代码;好处是边界清楚(一切都是同一种 API),不需要在 hook / mcp / skill 之间纠结边界。

Session 树

V3 schema 与 JSONL 格式

docs/session-format.md + session-manager.ts

每个 session 文件是 JSONL,每行一个 JSON 对象,含 type 字段。文件首行是 header(含 schema version、id、timestamp、cwd),其后是 entries。所有 entry 都有 id + parentId,”current position” 是被指向的活跃 leaf。

Schema 演进

  • V1:纯线性序列(旧版 pi-mono 早期)。
  • V2:引入 tree(parentId)。
  • V3:引入 unified custom roles(让扩展持久化的 entry 可以同时进/不进 LLM 上下文)。

migrations.ts 在打开旧文件时自动升级 schema。

Entry 类型枚举(综合 docs + session-manager.ts)

类型 含义
SessionMessageEntry 一次对话 turn 的消息载荷(AgentMessage
CompactionEntry 压缩生成的摘要(含累计 file operations)
BranchSummaryEntry 切分支时被丢弃路径的摘要
CustomEntry 扩展持久化的非 LLM 状态(不进上下文)
CustomMessageEntry 扩展持久化的 LLM 上下文(进上下文)
ModelChangeEntry / ThinkingLevelChangeEntry 配置变更
LabelEntry 用户给某个 entry 打书签
SessionInfoEntry display name 等元信息

buildSessionContext() 的还原逻辑

session-manager.ts 把”从 JSONL 还原 LLM 输入”做成一个明确函数:

“buildSessionContext() walks from the current leaf to the root, producing the message list for the LLM” —— 中间遇到 CompactionEntry 时会用摘要 替换 它对应的原始消息段,遇到 BranchSummaryEntry 时会把摘要插入分支起点。

/tree /fork /clone /share /export 怎么做

  • /tree — 用 pi-tui 渲染整棵树,方向键导航、Ctrl+←/→ 折叠/展开。选中 user 消息会把它拷进编辑器(resubmit 模式);选中 assistant 消息则保留空 editor 续写。这就是树编辑的核心 UX。
  • /fork — 把当前节点为根的子树拷到一个新文件,原文件不动。AgentSessionRuntime.fork() 实现,支持 before / at 两种锚点。
  • /clone — 复制活跃分支到新文件,但不切到新文件。
  • /share — 把当前 session 上传成 GitHub gist 并生成可访问的 HTML 链接(实际工具是 badlogic/pi-share-hf)。
  • /export [file] — 渲染独立 HTML(包含 markdown / 代码高亮 / tool result 折叠等),用 core/export-html/ 下的代码生成。注意 v0.78.1 修了一次 HTML 导出 XSS(URL sanitization),见 release notes

与 HuggingFace 数据集的衔接

仓库 README 里说:”Public OSS session data helps improve coding agents with real-world tasks, tool use, failures, and fixes instead of toy benchmarks.”(README

机制:用户 /share 后,配套工具 badlogic/pi-share-hf 把 session 上传到 HF 数据集 badlogicgames/pi-mono(沿用旧 owner,没改名)。这是 pi 想做”非 toy benchmark”的诚意所在。

隐私 / 数据治理

文档里没有自动脱敏。export-html 与 share 都包含完整的 tool input/output。XSS 修复是 v0.78.1 才有的(针对导出 HTML 时 URL 不被转义)。这意味着如果 session 里调用过含 API key 的命令,share/export 时 key 会跟着走。这是当前已知的硬限制,生产场景下应配合扩展手动 sanitize

pi-ai:统一 provider 层

接口形态

pi-ai README 摘要:聚焦 tool-calling capable models;统一接口 stream()complete();Streaming event 类型有 text_delta / thinking_delta / toolcall_delta;用 TypeBox schema 做工具签名 + 自动校验;支持跨 provider handoff(中途切模型保留上下文);图像 I/O;thinking/reasoning blocks;OAuth;context 序列化。

Provider 总览

packages/ai/src/providers/ 下源文件:

文件 服务
anthropic.ts Anthropic Messages
openai-completions.ts OpenAI Chat Completions + 任意 OpenAI 兼容(DeepSeek / xAI / Groq / Together / OpenRouter / Mistral 兼容入口 / Hugging Face Inference / Ollama / vLLM / LM Studio)
openai-responses.ts + openai-responses-shared.ts OpenAI Responses API
openai-codex-responses.ts OpenAI Codex 通道(订阅 OAuth)
azure-openai-responses.ts Azure OpenAI Responses
mistral.ts Mistral 原生 API
google.ts + google-shared.ts Google Gemini Generative AI
google-vertex.ts Google Vertex AI
amazon-bedrock.ts AWS Bedrock
cloudflare.ts Cloudflare AI Gateway / Workers AI
github-copilot-headers.ts GitHub Copilot OAuth headers 处理
openai-prompt-cache.ts OpenAI prompt caching 优化
transform-messages.ts provider 共用消息转换
simple-options.ts 简化配置入口
register-builtins.ts lazy 注册全部
faux.ts 测试 mock

宣传里的”20+ providers”靠两个机制凑齐:**(a)** 一个 openai-completions.ts 文件覆盖任意 OpenAI 兼容服务;**(b)** 用户在 ~/.pi/agent/models.json 里配 baseUrl + api 类型注册自定义 provider。v0.78 系列陆续新增了 Ant Ling、NVIDIA NIM、MiniMax-M3、xAI、Moonshot Kimi 等(v0.78.0 / v0.78.1 release notes)。

三种订阅 OAuth

packages/ai/src/oauth.tsexport * from "./utils/oauth/index.ts" 的 re-export(oauth.ts),实际逻辑在 utils 子目录。从 docs/providers.md + release notes 整合:

  • ChatGPT Plus/Pro(OpenAI Codex 通道) — 走 openai-codex-responses.ts,2025 年 OpenAI 把 Codex CLI 的订阅认证开放后接入。v0.77.0 起加 device-code flow 支持 headlessv0.77.0 release notes)。
  • Claude Pro/Max — 走 Anthropic 的 OAuth flow,token 到期自动 refresh。
  • GitHub Copilotgithub-copilot-headers.ts 管 token;浏览器登录后 token 写 ~/.pi/agent/auth.json,过期前主动 refresh。

token 都存 ~/.pi/agent/auth.json,文件权限 0600。CLI flag > auth.json > env > 自定义 provider key 是优先级(docs/providers.md)。

值得注意:配置 value 支持动态值——!command 执行 shell 命令并缓存 stdout、$VAR / ${VAR} 环境变量插值、$$ / $! 字面转义。这让 secret 管理可以挂到 1Password CLI / vault 等工具。

与 LiteLLM / OpenRouter 的差异

对比项 pi-ai LiteLLM OpenRouter
形态 npm 库(嵌入) Python 库 + 独立 proxy server 云服务
协议归一 Anthropic / OpenAI / Google 三套并行,不强制翻译成 OpenAI 全部翻译成 OpenAI 格式 全部翻译成 OpenAI 格式
Tool calling 一等公民、TypeBox schema 一等公民 一等公民
Thinking blocks 一等公民 间接支持 间接支持
订阅 OAuth ChatGPT/Claude/Copilot 三家 不主打 不支持
跨 provider handoff 一等公民 不主打 N/A

最大差异:pi-ai 不把所有 provider 翻译成 OpenAI 而是保留各自原生协议——这是 thinking blocks / prompt cache / tool calling 在不同模型上能拿到最佳性能的前提。这也是它能直接接 ChatGPT/Claude/Copilot 三家订阅 OAuth 而不是只支持 API key 的根本原因。

pi-tui:差分渲染终端 UI

三策略差分渲染 + CSI 2026

pi-tui README 概述:

  • Three-strategy 渲染:每帧只更新变化区域;具体策略有 “整行重写 / 行内 cursor 移动后局部重写 / 不变” 三档(具体阈值未在 README 公开,由实测结果驱动)。
  • CSI 2026 同步输出(synchronized output):把多行 update 包在 \x1B[?2026h\x1B[?2026l 里,让 terminal 把整批 update 当成一次原子提交,消除高速刷新时的局部撕裂。这是 pi-tui 不用 Ink/React-style 双缓冲也能无闪烁的关键。
  • truncateToWidth() / visibleWidth() 在保留 ANSI escape 的同时计算可见宽度——对接全角字符 / emoji / 颜色码必须做这步。
  • Kitty / iTerm2 行内图像协议terminal-image.ts 自动探测协议,不支持就 fallback 到文本。
  • IME 光标定位Editor 组件给硬件光标定位,让 macOS / Windows / Linux 的 CJK IME 浮窗出现在正确位置。
  • `>10 行粘贴 自动转占位符**:避免黏贴一大段日志时卡渲染。

与 Ink / Textual / Bubble Tea 的关系

pi-tui 完全独立——没有用 React / blessed / Ink,也不用 Charm 的 Bubble Tea(Go 系)或 Python 的 Textual。它就是一个手写的 TypeScript TUI 库。设计理念偏向”以 component class 为单位,每个组件实现 render() 返回字符串数组” + 主循环做 diff,与 Bubble Tea 的 Elm-style 比更命令式、与 Ink 的 React-style 比更轻量。

兼容性

  • tmux / screen / 远程 ssh:基本兼容(OSC 8 hyperlinks v0.78.0 起在 tmux 内也能用,release notes)。
  • Windows:v0.77 修过 MSYS2 启动兼容;issue #5394 还在跟踪 WezTerm(Windows)下 footer thinking-level 文字截断的 bug。
  • Termux(Android):有专门 docs(docs/termux.md)。

生态:官方 / 社区扩展清单

官方仓库内(earendil-works 组织)

仓库 类型 说明
earendil-works/pi 主仓 monorepo
earendil-works/gondolin microvm 沙箱 QEMU/krun + JS 控制 VFS + 可编程出站策略 + 凭据占位注入
earendil-works/pi-chat 扩展 Discord/Telegram 集成,每个 channel 独立 Gondolin VM
earendil-works/pi-review 扩展 /review /end-review 命令;支持 PR/branch/commit/folder 4 种 review 输入
earendil-works/pi-tutorial 扩展 实验性教程模式
earendil-works/absurd 实验 纯 Postgres 的 durable execution workflow(与 pi 路线相关但独立)
earendil-works/website 站点 pi.dev

社区扩展(由 pi.dev/packages 月下载量排序,截至 2026-05–06)

月下载 功能
context-mode ≈121.5K “MCP 插件,节省 ~98% context window”(沙箱执行 + 知识库搜索)
pi-subagents ≈103.2K 任务委派给 subagent,支持并行 + 交互澄清
pi-mcp-adapter ≈99.2K 把 Model Context Protocol 桥接进 pi
pi-web-access ≈84.7K web 搜索 + URL 抓取 + GitHub clone + PDF 提取 + 视频分析
rpiv-ask-user-question ≈52.4K 结构化问卷工具,让模型按 typed schema 提问
rpiv-todo ≈33.2K 持久 TODO 列表
pi-lens ≈21K 实时代码反馈(LSP/linter)

数据来源:pi.dev/packages + TheAIEra 综述。社区还提到 OthmanAdi/planning-with-files(plan 自动执行 + attestation)、w-winter/pi-rewind-hook(基于 git ref 回滚)、dnouri/pi-coding-agent(Emacs 前端)等。

据中文综述(BAAI2048ai.net)社区已经出现”补完”型 fork——**Oh-My-Pi (omp)**:保留 pi 的 4 工具内核,把 subagent / MCP / 权限层做成默认开。这是 pi 哲学激起的典型反弹。

未来与商业化

路线图(从 issues + release 节奏推断)

最近 1–2 个月的 issue 标签集中在三处(issue list):

  1. provider 修复(高频)maxTokens 映射错误(#5331)、zai thinking 参数错误(#5330)、Vertex GCP metadata server 支持(#5323)、新 provider 申请(#5363)。这反映 pi-ai 的”统一 + 模型无关”承诺会随每个新 provider 引入回归压力。
  2. 可观测/可集成Expose when Pi is waiting on user input for host integrations(#5329)、Allow custom OAuth callback page rendering(#5372)。说明 RPC 模式被越来越多 host 应用集成,他们要更细的 hook。
  3. 跨平台/SDK 路径:#5350 报告 SDK 自定义工具拿到的是 host OS 解析后的路径,Windows host 接 Linux 远程文件工具会断裂——这是 pi 跨 OS 路径处理一致性的硬骨头。

possibly-openclaw-clanker label(出现在 #5350)暗示 pi 团队对来自 fork(OpenClaw 是 pi 的下游)的”机器人式 issue”有专门标注——这本身揭示了一件事:pi 的下游已经形成一定规模的二次开发生态,团队需要专门 triage

Earendil 的商业化方向(推测)

公开信号:

  • 组织页 tagline “Bearer of Light” + Tolkien 的 Eärendil(迷雾之海上指引航道的星)暗示主理人偏向”基础设施 / 工具”路线,不是产品向。
  • 主理人 Armin Ronacher(Flask 之父,Sentry 出身)公开发文《I’ve sold out》解释加入 PBC 的动机(changchen.me 中文解读),核心是希望把”基础设施级 AI 工具”做成可持续的 PBC 而非传统 VC 公司。
  • gondolin(microvm)+ absurd(durable workflow)+ pi-chat(Discord/Telegram) 三块在做”可托管的 agent 执行环境”——典型的 SaaS 雏形。
  • 截至 2026-06,没有公开的商业产品页 / 价格表 / SaaS 入口

合理推测路线图:先靠开源建生态、靠 PBC 拿与 VC 不同的资金(行善让利的 LP 圈),后续可能围绕 “managed Gondolin sandbox + pi-chat / pi-review 等扩展”做 SaaS。但这是推测,不是公开声明

Mario Zechner 的设计 rationale

直接英文一手资料(如 Mario 的个人博客 / Twitter 长文)截至本笔记发稿在公开搜索里没有完整命中。中文社区综述(CSDN by 程超silenceperBAAI)转述的几条要点:

  • “做 pi 的起因是对 Claude Code 频繁 update / 行为漂移的不满”——希望有一个”我能完全掌控、产品行为不会被官方一夜改掉”的 harness。
  • “现代 LLM 已经足够聪明,不需要 fat prompt 来教它做事;4 个原子动作 + bash 兜底足够解 90% 编码任务”。
  • “MCP 太烧 token——Chrome DevTools MCP 一上线就吃 18K context,对单用户 agent 是无谓开销”。
  • “subagent 是底层 primitive 而非应用——你要 subagent 自己 spawn pi.exec() 即可”。

这些表述是中文综述的翻译/转述,不是 Mario 的原话引用。如果以后能找到他的英文一手贴,应替换本节。

已知局限与社区抱怨

综合 issue list 与社区评测(2048ai.netCSDNSegmentFault):

  1. 学习曲线陡 — “blank canvas” 风格让初学者无所适从;要先知道自己想要什么扩展。
  2. 没有内置权限 / 沙箱 — 默认 YOLO 模式;要安全得自己上 Gondolin / Docker。社区批”过于宽松”,主理人立场是”传统 permission popup 是 security theater”。
  3. TUI 美学被批 ugly / unintuitive — 相比 Cursor / Claude Desktop GUI 不够”漂亮”,主理人立场是”TUI 的 simplicity 与透明度匹配 pi 哲学”。
  4. 社区扩展质量参差 — 部分 PR 含 AI 生成代码,仓库已强化 audit;issue #5350possibly-openclaw-clanker label 是这个问题的具象化。
  5. 依赖冲突 / Build 失败protobuf / numpy 等版本不兼容偶发;force-pushed git 仓库的扩展更新失败(PR #961,旧仓 URL)。
  6. non-coding 场景不通用SUMMARIZATION_SYSTEM_PROMPT 硬编码 “AI coding assistant”,做非编码任务时摘要策略不太合适(#5401)。

与 Claude Code / Codex CLI 的实现机制对比

这一节不重复对比笔记的”产品功能”层对照;只看实现机制层面的差异。

实现机制 pi Claude Code Codex CLI
语言 / runtime TypeScript(Node + 可选 Bun) TypeScript(Node) Rust 核心 + Node CLI 包装
主仓代码量级 4 包 / pi-agent ~1.5k LoC 内核 + ~数万 LoC 上层 闭源 codex-rs/ Rust + codex-cli/ + mcp-server/
Agent loop 形态 EventStream + 双层 loop(follow-up 外、tool 内) 闭源 Tokio 异步 + Ratatui TUI
默认工具数 4(read/write/edit/bash) ~10+(含 Read/Write/Edit/MultiEdit/Bash/BashOutput/KillBash/Grep/Glob/Web*/Plan/SubAgent) ~5+(含 shell/local_shell/apply_patch/…)
编辑机制 多个 oldText/newText 精确替换 同源思路(Edit / MultiEdit) apply_patch unified diff
Bash 输出截断 50 行 / 1MB,超时 + 全量 temp 文件 类似(具体阈值闭源) 同档(具体闭源)
System prompt token 预算 < 1000 10k+(含 plan/skill/MCP 描述) 中等(不含 MCP 时较小)
上下文压缩 自动 + 可阻断 hook 自动 + skills/AGENTS.md 长记忆 session resumption
扩展机制 TypeScript 模块(同时承担 hook + tool + UI + provider) Skills / Hooks / MCP 三套 MCP(client+server 双向)+ 命令白名单
沙箱 不内建(OpenShell / Gondolin / Docker 三选一) plan mode + permission prompt OS 级:macOS Seatbelt、Linux Landlock+seccomp、Windows WSL2
订阅认证 ChatGPT Pro / Claude Pro / Copilot 三家 OAuth 同时 仅 Claude(自家) 仅 ChatGPT(自家)
Session 形态 JSONL 树(v1/v2/v3 自动迁移)+ /tree /fork /clone /share 文件级 memory session resumption + prompt 库
TUI 实现 自有 pi-tui(差分渲染 + CSI 2026) 闭源 Ratatui(Rust)
Skills 实现 progressive disclosure(只放 name+desc 进 system prompt) 同思路 N/A

实现层最关键的三处差异

  1. System prompt 预算差两个量级(pi <1k vs Claude Code 10k+)—— 决定了 pi 必须把”工具足够正交、模型必须懂常识”作为前提。
  2. Edit 接口:pi 的”多对 oldText/newText” vs Codex 的 apply_patch unified diff vs Claude Code 的 Edit/MultiEdit。三者背后是”让模型负担 vs 让工具负担”的不同选择。
  3. 扩展的统一性:pi 用一个 ExtensionAPI 同时覆盖 hook / tool / UI / provider;Claude Code 把 Skills / Hooks / MCP 切成三套独立机制;Codex 把 MCP 推到中心、其余靠白名单。pi 的统一性让边界清楚,但代价是新手要写 TS。

不确定性

  1. <1000 token 的实测值不在仓库 docs 里。这个数字来自中文社区综述(CSDN / silenceper);本笔记沿用,但若用 tiktoken 真测一次,结果可能在 600–1000 区间漂动,且会随项目 AGENTS.md 是否存在剧烈波动。
  2. agent loop “5 个文件 / 1.5k LoC” 是中文综述的描述。仓库当前 packages/agent/src/ 实际有 agent-loop.ts / agent.ts / proxy.ts / types.ts / node.ts / index.ts 6 个文件 + harness/ 子目录,LoC 也未实测;本笔记把这条标为社区描述、不当作精确事实。
  3. SUMMARIZATION_SYSTEM_PROMPT 我抓到了 verbatim,但 issue #5401 暗示后续可能改名/重写——本笔记引用的是 v0.78.1 当前版。
  4. Mario Zechner 的英文一手 blog/Twitter 长文 没有命中。中文转述算二手。如果用户能给到原始链接(personal blog / Twitter thread),应替换。
  5. Earendil PBC 的商业化方向 完全是从仓库结构推测,不是官方声明。SaaS / 托管沙箱仅是合理猜测。
  6. pi-share-hf 的现状:HuggingFace 数据集 badlogicgames/pi-mono 还在用旧 owner / 旧名,更新节奏与新仓 release 节奏是否同步未确认。
  7. OAuth 三家 token refresh 的具体参数(refresh window / retry policy)需要去看 packages/ai/src/utils/oauth/ 子目录,本笔记没抓到该层源码。
  8. pi-tui 的”three-strategy 渲染”具体三档阈值 README 没披露,本笔记按”全行重写 / 局部 cursor 移动 / 不变”做了合理还原,但不是源码字面意义。
  9. 社区扩展月下载量 来自 pi.dev/packages 当前快照,会随时间变化。
  10. OpenClaw 的实际下游影响:搜索结果反复出现 “pi 下游 OpenClaw 在 2 个月内拿到 210k stars” 的说法,本笔记未独立验证 OpenClaw 仓库当前的真实 stars / 与 pi 的代码继承关系。把 possibly-openclaw-clanker label 视为 pi 团队对该下游的客观存在的反应即可。

后续行动

  • tiktoken 实测 v0.78.1 的默认 system prompt token 数(带/不带 AGENTS.md 两组)。
  • 在本机跑一次 wc -l packages/agent/src/**.ts 验证 1.5k LoC 的说法。
  • gondolin 在本机搭起来,跑 5 条 bash 命令验证凭据隔离 + VFS 控制的实用强度。
  • 单独追:packages/ai/src/utils/oauth/ 三家 OAuth refresh 的具体参数。
  • pi-mcp-adapter 在本仓装一次,对照 Claude Code MCP 一等公民,量化 token 消耗差异。
  • 跟 issue #5401 的修复——若 SUMMARIZATION 走向”按场景分支”,对长程非编码任务表现可能改善。
  • 跟 v0.79.x 的 release notes,看 sandbox / 权限层是否会”软化为内建可选”——这关系到 pi 哲学是否在企业落地压力下让步。
  • 找 Mario Zechner 的英文一手 blog/Twitter,替换中文综述转述。

来源

仓库与官方 docs

关键源码文件

示例扩展

Release Notes & Issues

Earendil 姊妹仓库

第三方综述与社区

评论
分享