第 9 章:设计哲学——为什么“不做”是特性

# 第 9 章:设计哲学——为什么“不做”是特性

> 决定一个工具上限的,往往是它拒绝做什么。

## 设计思想
Pi 的核心理念是「**极简内核 + 无限可扩展**」。它 deliberately 不在核心中实现诸如子 agent、计划模式、权限弹窗、Todo 管理、后台 Bash 等功能,而是将这些高级能力交给社区通过 **extensions、skills、pi 包** 来提供,或鼓励用户自行构建。这样做的目的是保持主程序轻量、易于审计、安全且能够适配多种工作流,而不被一种“官方的正确方式”所束缚。

## 原理
### 极小的内置工具集
- Pi 仅内置四种基本工具(以及平台特定的补充):
  - `read`:读取文件内容。
  - `write`:创建或覆盖文件。
  - `edit`:精确替换文本(基于完整匹配,避免误改)。
  - `bash`:在所在 shell 中执行命令并返回输出(Windows 上还有 `powershell`)。
- 这些工具已经足以完成文件操作、系统交互、调用其他程序等底层任务;此外还有 `grep` / `find` / `ls` 等只读内置工具可用(例如 `pi --tools read,grep,find,ls -p "Review the code"` 进入纯检查模式)。复杂工作流可以编写成脚本并通过 `bash` 执行,或利用 `read`/`write`/`edit` 逐步构建。

### 通过插件机制实现高级功能
Pi 采用分层的插件体系,使得功能可以按需加载、共享和自定义:

1. **Skills(Agent Skills 标准)**  
   - 每个 skill 是一个自包含的目录,内含 `SKILL.md`(使用说明)以及可选的实现脚本或工具。  
   - 它们遵循统一的格式,agent 能够在用户提及特定关键词时自动加载并呈现使用步骤,或者用户主动通过 `/skill:name` 查询和执行。  
   - 例如:`lark-im` skill 用于发送飞书消息、`lark-base` skill 用于操作多维表格等。

2. **Extensions(TypeScript 扩展)**  
   - 以 TypeScript 编写的模块,导出一个函数接受 `ExtensionAPI`,可注册:
     - 新工具(如 `deploy`、`docker_build`)  
     - 新命令(如 `/stats`、`/todo`)  
     - 键绑定、事件处理器(监听 `tool_call`、`message_sent` 等)  
     - UI 组件(自定义编辑器、状态栏、弹窗、全屏覆盖等)  
   - 扩展在启动时加载;修改后可通过 `/reload` 热重载,无需重启整个程序。  
   - 这使得社区能够实现诸如 **子 agent**、**计划模式**、**权限确认弹窗**、**后台任务**、**Git 自动提交** 等功能,而无需修改 Pi 主源码。

3. **Pi Packages(npm / git 分发)**  
   - 将 skills、extensions、prompt templates、themes 打包成可分发的单元。  
   - 安装命令极其简单:`pi install npm:@foo/pi-tools` 或 `pi install git:github.com/user/repo`。  
   - 包可以声明其包含的资源路径,Pi 会自动将其放入对应的搜索目录(如 `~/.pi/agent/npm/` 或 `~/.pi/agent/git/`),受项目信控制。  
   - 这种机制使得功能的传播像安装普通 npm 包一样便捷,同时又能够进行版本锁定和更新。

4. **主题与个性化**  
   - 内置 `dark`、`light` 两种主题;自定义主题是 **JSON 文件**(定义 `vars`、`colors` 等 token),不是 CSS。
   - 主题文件位于 `~/.pi/agent/themes/*.json`(或项目级 `.pi/themes/`),修改后立即热重载,提供即时的视觉反馈。

### 为什么不在核心中实现这些功能?
- **避免臃肿**:每加入一种特性都会增加代码量、复杂度和潜在的 Bug。核心越小,越易于审计和安全评估。
- **尊重多样性**:不同团队和个人有不同的工作流偏好。有人喜欢计划模式,有人则更倾向于在文件中写 Todo;强行内置一种方式会导致不适用感。
- **社区驱动创新**:通过插件机制,任何人都可以贡献自己的想法而不需要通过主仓库的审核合并流程。这加速了创新的迭代。
- **明确的边界**:核心只负责「读取‑写入‑编辑‑执行命令」,这四种操作是构建任何更高级逻辑的图灵完备基础。所有其它功能都可以在这些基础上通过组合或插件实现,因而没有必要在核心中硬编码。

## 用法
### 查看与管理已安装的插件
- **交互式**:`/settings` → Extensions / Skills 选项列出当前已加载的扩展和技能,可启用/禁用。
- **命令行**:
  ```bash
  pi list                  # 显示已安装的 pi 包(npm/git)
  pi config                # 交互式切换扩展、skill、prompt、theme 的启用状态
  pi update --extensions   # 更新所有通过 pi 包安装的 skills/extensions
  ```

### 安装社区提供的功能
```bash
# 示例:安装一个提供飞书消息能力的 skill 包
pi install npm:@foo/pi-lark-skills
# 然后可以使用 /skill:lark-im 发送消息,或让 agent 自动在提及“发消息”时建议使用该 skill
```

### 开发自己的插件
1. **创建 Skill**  
   - 新建目录 `~/.pi/agent/skills/my-helper/`  
   - 放入 `SKILL.md`,说明该 skill 在何时使用以及步骤。  
   - 如需自动化,可在此目录添加脚本(如 `install.sh`、`run.sh`)并在 `SKILL.md` 中记录调用方式。  
   - 保存后,使用 `/skill:my-helper` 查看说明;如需 agent 自动加载,则在 `SKILL.md` 中按照规范编写触发关键词。

2. **编写 Extension**(以 TypeScript 为例)  
   - 新建文件 `~/.pi/agent/extensions/hello.ts`(官方 API 签名):
     ```ts
     import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";

     export default function (pi: ExtensionAPI) {
       pi.registerCommand("hello", {
         description: "Say hello",
         handler: async (args, ctx) => {
           ctx.ui.notify(`Hello ${args || "world"}!`, "info");
         },
       });
     }
     ```
   - 测试:`pi -e ./hello.ts` 临时加载;或保存后 `/reload`,即可使用 `/hello`。
   - 更高级的示例可见官方仓库的 `examples/extensions/` 目录。

3. **制作并分发 Pi Package**  
   - 在项目根目录的 `package.json` 中加入 `pi` 字段:
     ```json
     {
       "name": "my-pi-utils",
       "version": "1.0.0",
       "keywords": ["pi-package"],
       "pi": {
         "extensions": ["./extensions"],
         "skills": ["./skills"],
         "prompts": ["./prompts"],
         "themes": ["./themes"]
       }
     }
     ```
   - 发布到 npm(`npm publish`,包带 `pi-package` keyword 便于检索);用户随后可通过 `pi install npm:my-pi-utils` 安装。

### 项目级与全局插件的区别
- **全局插件**:放在 `~/.pi/agent/` 下的目录(如 `extensions/`, `skills/`),对所有项目都可用,只要用户没有在项目级禁用它们。
- **项目级插件**:放在项目内的 `.pi/` 目录(如 `.pi/extensions/`, `.pi/skills/`)。这些插件只有在该项目被标记为 **可信**(`~/.pi/agent/trust.json` 中有记录或用户手动通过 `/trust` 标记)时才会加载,以防止恶意代码在未授权的项目中自动运行。
- 此机制确保了在共享或开源项目中插件不会意外执行,同时又允许在受信的私有项目中使用强大的自动化功能。

### 与传统 IDE 的对比
- 传统 IDE 往往内置调试器、Git 客户端、终端、插件市场等功能,导致启动慢且难以精准裁剪。  
- Pi 则把这些能力外化为插件:你想要 Git,就安装一个提供 `git` 命令的 extension;想要 Todo 列表,就用一个 skill 或自行编写一个 extension 维护 `TODO.md`。  
- 这样做虽然需要用户自行选择和组装功能,却获得了完全匹配个人工作流的定制化体验,并且 core 始终保持快速和可预测。

## 小结
Pi 的哲学不是“一体化”,而是“**提供最小但完整的基础,让能力的边界由社区和用户自行划定**”。通过极简内核与灵活的插件体系(skills、extensions、pi packages、themes),它实现了:
- **轻量**:核心代码少,启动快,易于审计。  
- **可扩展**:几乎无限的功能可以通过插件添加。  
- **安全可控**:项目级信任机制防止未授权代码自动运行。  
- **工作流自由**:用户可以根据自己的偏好构建或选择所需的工具链,而不是被迫接受一套预设的功能集。  
这种设计使得 Pi 能够在从个人实验到企业级自动化的各种场景中都保持适用性和活力。