

假设团队准备给 Coding Agent 增加规划能力。第一种方案是在核心里加入 Plan Mode:新的状态机、只读阶段、审批按钮、计划存储和执行切换都由产品统一维护。第二种方案只允许模型先写 PLAN.md,需要只读时切换 Tool Allowlist,需要执行时再由用户授权。两种方案都能产生计划,却不是同一种产品。
第一种把复杂度交给核心维护者,换来一致体验。第二种把复杂度交给配置、Extension 和操作者,换来可替换性。需要判断的是复杂度被放在哪里、由谁维护、失败时由谁恢复。
Pi 的固定版本把这种取舍写得很直接:核心不内置 MCP、Sub-agent、Plan Mode、Todo、后台 Bash 和逐工具权限弹窗,同时允许用 Extension、Skill、Package、文件、tmux、独立进程或容器补齐。这些需求由外部组合负责,核心不替所有用户规定唯一工作流。
这篇文章只回答一个问题:一项 Agent 能力什么时候应该进入核心,什么时候应该外置?外置之后又会产生什么账单?
一、极简的关键是收窄核心边界


把极简理解成“代码越少越好”,很容易走向两个错误结论:要么把缺少功能当作不成熟,要么把功能少本身当作先进。架构上的极简更严格:核心只承担跨工作流稳定、需要统一生命周期、难以从外部可靠组合的机制。带有明显团队偏好和治理差异的策略,优先留给扩展层。
在 Pi v0.82.1 / b4f2936 的 README 中,这条边界同时出现于两处。一处明确说 Pi 为保持核心精简,不内置 MCP、Sub-agent、Plan Mode、Todo、后台 Bash 和逐工具权限弹窗。另一处又列出 Extension 可以实现自定义 Tool、 Sub-agent、Plan Mode、Permission Gate、Sandbox 和 MCP Server Integration。
所以“不内置”不等于“不支持”。更准确的结构是:
核心提供稳定机制
├─ 模型调用与消息转换
├─ Agent Loop 与 Tool Runtime
├─ Session、事件和基础 UI
└─ Extension / Skill / Package 入口
工作流策略由外部组合
├─ MCP 接入方式
├─ 多 Agent 编排
├─ 规划与审批阶段
├─ Todo 与长期任务状态
├─ 后台进程管理
└─ 权限、隔离和网络策略
这条边界让核心 API 不必同时承诺所有工作流的语义。代价也很明确:没有产品统一承诺的部分,必须由其他人补上。
二、一次“不内置”,会把六种责任一起转移

外置能力经常被描述成“写个 Extension 就行”。但一个功能从核心移到外部,转移的不只是实现代码,还包括至少六种责任。
| 转移对象 | 核心内置时 | 外置后 |
|---|---|---|
| 发现 | 产品 UI 和文档统一暴露 | 用户要知道该装哪个 Package、Skill 或 CLI |
| 权限 | 核心可以统一做阶段和操作授权 | Extension、容器、Shell 与操作者共同承担 |
| 观测 | 事件、日志和 UI 可使用同一状态模型 | tmux、文件、子进程和远程服务各有一套状态 |
| 兼容 | 核心版本与功能一起测试 | 扩展作者要跟随 API、平台和依赖变化 |
| 升级 | 官方迁移和回滚 | 用户要管理 Package 来源、版本与供应链 |
| 恢复 | 核心知道任务状态与生命周期 | 外部进程中断后,恢复协议需要自行设计 |
极简会改变复杂度的所有权。对能够维护 CLI、容器、配置和 Extension 的团队,这种转移可能非常划算。对只想开箱即用、要求统一审计和支持承诺的团队,它可能只是把产品成本变成了集成成本。
因此,决定外置前先写清六项责任:谁负责发现、权限、观测、兼容、升级和恢复。后文每个能力都用这份责任合同判断,不再把“可由扩展实现”当作完成。
三、六类不内置能力,其实是六种不同决策

Pi 把多个“不做”并列在 Philosophy 中,但它们的理由并不完全相同。不能用一句“外部工具已经解决”概括全部。
1. MCP:标准接入能力是否属于默认核心
固定版本的立场是核心不内置 MCP,优先使用带 README 的 CLI,或者由 Extension 增加 MCP 支持。这里能够确认的是 Pi 的产品边界,不能推导 MCP 协议没有价值,也不能推导所有 MCP Host 都会把全部工具永久塞进上下文。
CLI 路线适合已有成熟命令行、输出可检查、需要管道组合的本地工程。MCP 或正式 API Tool 更适合远程 SaaS、跨语言生态、结构化发现和企业系统。究竟选择哪一条,取决于发现、认证、Schema、远程复用和治理要求。这里保留一条边界: Pi 把 MCP 视为可替换接入策略,而不是 Agent Kernel 的必要组成。
2. Sub-agent:启动进程与调度系统不是一回事
Pi 不提供唯一的内置 Sub-agent Tool,但固定文档给出 tmux、独立 Pi 实例、Extension 和第三方 Package 等组合路线。这些路线足以证明“可以组合多个 Agent”,却不自动提供任务所有权、取消传播、工作区隔离、结果协议和独立验收。
把 Sub-agent 外置,核心避免绑定一种编排模型。操作者则必须自己回答:谁能改哪个文件、迟到结果是否可接受、一个子任务失败后主任务如何恢复。能启动多个进程,不能证明已经具备生产调度器。
3. Plan Mode:状态文件与阶段策略不是同一个对象
把计划写入 PLAN.md 有实际优势:可见、可编辑、可 Diff、可跨 Session,也能进入 Git。固定文档还允许用 Tool Allowlist 形成只读探索阶段。但文件只表示“计划是什么”,不会天然保证“规划时禁止写入”“执行前必须批准”“切换后使用哪套权限”。
所以计划文件与 Plan Mode 的关系是:
PLAN.md = 可持久化状态
只读 Tool Profile = 动作边界
Owner Approval = 阶段门
执行 Profile = 下一阶段能力
核心不内置 Plan Mode,意味着团队可以自由组合这四项。也意味着阶段切换和审批一致性不再由产品兜底。
4. Todo:可见清单与调度状态不是一回事
TODO.md 适合单 Agent、中小任务和仓库中心工作流,因为它可以被人编辑、被版本控制、被后续 Session 读取。但当任务涉及依赖、并发、租约、重试和取消时,一份 Markdown 清单没有事务语义。
同时存在多份真相才是风险:文件写“步骤二进行中”,子进程已完成步骤三,用户以为任务准备发布,而 Gate 仍绑定旧产物。规模变大后,结构化任务系统承担状态一致性职责。
5. 后台 Bash:tmux 解决运行,不自动解决任务语义
Pi 建议把后台进程交给 tmux。tmux 确实已经处理 Session、Pane、断开重连、输出观察和人工接管,核心无需重复实现一个终端复用器。但 Agent 任务仍需要进程命名、PID 或 Pane 归属、退出状态、日志截断、端口冲突、清理和恢复规则。
tmux 解决“进程继续跑”。Harness 仍要解决“这个进程属于哪个 Attempt、完成后怎样进入下一状态、取消后如何确认副作用停止”。外置减少核心代码,不会自动得到 Durable Workflow。
6. 权限弹窗:不弹窗不等于没有安全问题
固定版本没有逐工具权限弹窗,并建议使用容器或由 Extension 构造适合环境的确认流。这里必须区分 Project Trust、 Tool Gate、操作系统隔离、网络策略、Secret 隔离和人工审批。它们控制的是不同风险。
权限弹窗不是完整安全边界:被批准的构建命令仍可能执行恶意依赖。它仍能阻止明显越权写入和未经批准的外部动作。把权限策略外置,更适合能够自行设计容器、路径和网络边界的用户,不适合把默认安全责任完全交给普通操作者的产品。
四、哪些能力应该进入核心:四项准入测试

设计自己的 Harness 时,不应机械复制“不要 MCP”或“只用四个 Tool”。更稳妥的方法是让每项候选能力通过四项测试。
测试一:它是不是跨工作流稳定机制
消息转换、Tool Call 生命周期、Session 身份和事件顺序通常跨工作流存在。用不用 MCP、怎样规划、是否启动 Sub-agent 则高度依赖团队。越接近稳定机制,越适合核心。越接近偏好策略,越适合外置。
测试二:它是否需要统一生命周期
如果能力必须与任务版本、取消、重试、幂等和恢复共享状态,只放在松散脚本里会产生双重真相。此时即使 UI 可以外置,核心也应提供最小状态契约和事件接口。
测试三:外部组合是否真的可靠
“可以用 Shell 拼起来”只证明可调用,不证明错误传播、跨平台行为、输出上限和恢复语义可靠。若团队每次都要重复实现同一套脆弱胶水,外置成本可能已经高于核心抽象成本。
测试四:默认开启的风险是否可接受
进入核心通常意味着更容易被默认使用。远程 Tool、后台进程和高权限 Shell 需要清楚的权限与审计边界。无法提供安全默认值时,保持显式安装和显式授权可能更合理。
四项测试可以形成一张决策表:
| 结论 | 适合位置 | 典型条件 |
|---|---|---|
| 稳定、共享生命周期、外部组合脆弱、风险可控 | 核心机制 | Session ID、Tool 生命周期、事件与取消协议 |
| 需要执行权限和事件 Hook,但工作流有差异 | Extension | 自定义 Tool、Permission Gate、MCP Adapter |
| 主要提供知识、步骤和按需说明 | Skill / README | CLI 使用方法、项目流程、检查清单 |
| 主要保存人机可见状态 | 文件 | PLAN、TODO、交接记录,但不冒充事务系统 |
| 已有成熟运行与隔离系统 | 外部工具 | tmux、容器、Git、CI |
| 跨团队远程复用且需独立治理 | 独立服务 | 企业 API、MCP Server、Durable Workflow |
五、极简 Harness 的收益必须和代价成对出现

Pi 这条路线的真实收益是控制力。默认核心较窄,用户更容易看到模型收到了什么、哪些能力来自 Extension、状态存在哪里,也更容易替换某一层而不接受完整产品工作流。对研究 Harness、嵌入自有产品、已有成熟 CLI 和平台治理的团队,这种透明度很有价值。
对应代价是组合责任。扩展越自由,来源、版本、权限和兼容越分散。外部状态越多,恢复与审计越难统一。默认保护越少,操作者越需要理解终端、依赖和隔离风险。较弱模型也可能更依赖专用 Tool 与结构化反馈,不能因为强模型能熟练使用 Bash,就把四 Tool 路线当成普遍最优。
本文没有运行极简与产品型 Harness 的受控对照,无法给出成功率、Token、速度、维护工时或安全收益数字。作者早期博客中的历史数字和个人体验只能解释动机,不能当作本文环境的实测结果。
六、最终产物:一份复杂度归属合同

团队决定不内置某项功能时,不能只写一句“以后用 Extension”。至少应留下以下合同:
capability: plan-and-approval
core_mechanism:
- task_version
- tool_profile
- owner_gate
external_strategy:
state: PLAN.md
implementation: project_extension
responsibility:
discovery: platform_team
permission: security_team
observability: extension_events
compatibility: extension_owner
recovery: workflow_owner
fallback:
disable_extension: true
preserve_plan_file: true
evidence_required:
- read_only_stage_test
- approval_bypass_test
- stale_plan_rejection
这份合同用于防止“外置”变成无人负责。每次把能力移出核心,都应明确谁提供发现、权限、观测、兼容、升级和恢复。否则核心看起来很小,系统复杂度只是散落到了没人维护的角落。
Pi 的极简主义提供了一组具体追问:这项能力为什么必须进入核心?如果不进入,逃生口在哪里?复杂度会转移给谁?失败后谁能证明状态仍然可信?
四个问题都有答案时,极简是一项可验收的架构选择。没有答案时,团队只是把产品缺口转移给使用者。
参考资料与证据边界
- Pi Coding Agent README,固定 Tag
v0.82.1:https://github.com/earendil-works/pi/blob/v0.82.1/packages/coding-agent/README.md - Pi Extension examples,固定 Tag
v0.82.1:https://github.com/earendil-works/pi/tree/v0.82.1/packages/coding-agent/examples/extensions - Mario Zechner,What I learned building an opinionated and minimal coding agent:https://mariozechner.at/posts/2025-11-30-pi-coding-agent/
固定 Tag 用于证明 Pi 当时明确列出的“不内置”能力与替代路线。作者博客只用于解释设计动机。内置/外置决策表、复杂度转移账单和 YAML 合同是本文作者综合,不是 Pi 官方协议。本文未运行极简与产品型 Harness 的受控比较,真实效果幅度未知。