znlgis 博客

GIS开发与技术分享 — GDAL · GeoServer · PostGIS · QGIS · OpenLayers · Cesium · FreeCAD · NPOI

第十章:Pi 包管理与分发

本章深入讲解 Pi 的包生态系统:从一个包由什么组成、如何安装和管理(pi install / pi list / pi remove / pi update),到如何创建、发布和共享你自己的 Pi 包。读完本章,你将不仅能消费社区 4600+ 包,还能把自己积累的 Extensions、Skills、Prompt Templates 和 Themes 打包分发给团队或社区。

10.1 Pi 包系统概述

第一章提到 Pi 有 4600+ 社区包——这不是夸张的数字,而是截至 2026 年 6 月 npm 上以 pi- 开头的包的实际统计。Pi 包生态之所以如此繁荣,根本原因在于 Mario 把包定义得极其简单:一个 Pi 包就是一个普通的 npm 包或 Git 仓库,其中声明了 Pi 应当从中加载哪些资源

10.1.1 包的组成:四种资源类型

一个 Pi 包可以包含以下四种资源中的任意组合:

资源类型 文件格式 在包中的作用 对应章节
Extensions(扩展) .ts / .js 注册新工具、命令、生命周期钩子、TUI 组件 第九章
Skills(技能) SKILL.md 告诉模型”如何完成某类特定任务”的渐进式文档 第八章
Prompt Templates(提示模板) .md 追加到系统提示末尾的行为约束或风格指南 5.6.4
Themes(主题) .json 定义 TUI 各组件的颜色方案 5.6.5

一个包不需要包含全部四种——它可以只提供一个 Skill,只注册一个 Extension,甚至只带一套主题。包的设计原则是”按需组合”:一个解决特定问题的包,只带解决该问题所需的资源。

10.1.2 安装源:npm 和 Git

Pi 支持两种包安装源:

源类型 格式 适用场景
npm npm:@scope/package-name 或直接 package-name 公开发布的包,社区分享
Git git:github.com/user/repo 私有包、未发布到 npm 的包、开发中的包

两种源的包在功能上完全对等——无论来源是 npm 还是 Git,Pi 都用同一套机制加载其中的 Extension、Skill、Prompt 和 Theme。

10.1.3 配置位置

安装的包会被记录在 settings.jsonpackages 数组中。第五章(5.6.1)已简要介绍过这个字段,这里复习并深化:

{
  "packages": [
    "pi-tool-react@0.2.0",
    "npm:@scope/pi-utils@1.0.0",
    "git:github.com/user/pi-private-tools.git"
  ]
}

packages 数组中的每个条目是一个包引用字符串,Pi 在启动时(或在执行 pi install 后)解析这些引用,下载并加载包中声明的所有资源。

10.1.4 全局 vs 项目级包

和配置的两层体系一致,包也分为全局和项目两级:

层级 配置位置 加载时机 作用范围
全局包 ~/.pi/agent/settings.jsonpackages 每次启动 Pi 所有项目
项目包 .pi/settings.jsonpackages 项目被信任后 当前项目

数组合并规则:项目 packages 追加到全局 packages 之后(与 extensionsskillspromptsthemes 的合并规则一致)。这意味着你在所有项目中都会加载全局包,而在特定项目中可以额外加载项目专属包。

推荐分发策略

  • 全局包:放通用工具——如 pi-tool-shell-safety(Shell 安全检查)、pi-theme-nord(Nord 配色主题)、pi-skill-git-workflow(Git 工作流技能)。
  • 项目包:放项目专属工具——如为某个微服务仓库定制的数据库迁移 Skill、为团队内部框架编写的代码生成 Extension。

10.2 安装包

10.2.1 pi install 基本语法

pi install <包引用>

<包引用> 是一个字符串,支持以下四种格式:

格式 示例 说明
npm 包(简写) pi-tool-react 等同于 npm:pi-tool-react,从 npm registry 安装
npm 包(完整) npm:@scope/pi-utils 显式指定 npm 源,支持 scoped package
npm 包(指定版本) npm:@scope/pi-utils@1.0.0 锁定特定版本
Git 仓库 git:github.com/user/repo 从 Git 仓库克隆安装

10.2.2 npm 包格式详解

npm 是 Pi 包的主要分发渠道。包引用格式遵循标准的 npm 包标识规范:

# 方式 A:简写(无 scope 的包)
pi install pi-tool-react

# 方式 B:完整 npm: 前缀(推荐,语义明确)
pi install npm:pi-tool-react

# 方式 C:带 scope 的包
pi install npm:@myteam/pi-custom-tools

# 方式 D:带 scope + 版本号
pi install npm:@myteam/pi-custom-tools@2.1.0

# 方式 E:版本范围(semver)
pi install npm:pi-tool-react@^1.0.0
pi install npm:pi-tool-react@~1.2.3
pi install npm:pi-tool-react@latest

关于版本号的建议:强烈推荐在包引用中标注版本号。不标版本意味着 Pi 每次解析时都会取 npm 上的最新版——如果包作者发布了 breaking change,你的 Pi 可能在下一次启动时突然行为异常。在生产环境中,锁定精确版本(如 @2.1.0)是最稳妥的做法;在个人实验环境中,可以使用 @latest^ 范围来自动获取补丁更新。

10.2.3 Git 包格式详解

Git 格式让你可以直接从 Git 仓库安装 Pi 包,无需通过 npm 发布。适用于私有仓库、开发中的包、或不想走 npm publish 流程的场景:

# 基本格式:从默认分支安装
pi install git:github.com/user/pi-tools

# 指定分支
pi install git:github.com/user/pi-tools#develop

# 指定标签
pi install git:github.com/user/pi-tools#v1.0.0

# 指定 commit
pi install git:github.com/user/pi-tools#a1b2c3d

# GitLab
pi install git:gitlab.com/user/pi-tools

# Bitbucket
pi install git:bitbucket.org/user/pi-tools

# 自托管 Git(Gitea / Gogs 等)
pi install git:git.mycompany.com/team/pi-tools

Git 包引用的 URL 部分直接传给 git clone,因此任何 git clone 能识别的 URL 格式都可以用(包括 https://git@ssh:// 等)。上一节示例省略了协议前缀——Pi 会自动补全 https://。如果需要显式指定协议:

pi install git:https://github.com/user/pi-tools.git
pi install git:git@github.com:user/pi-tools.git

分支/标签/commit 的 # 语法在所有 Git 平台上通用,Pi 内部将其映射为 git clone --branchgit checkout

10.2.4 安装流程详解

当你执行 pi install npm:@scope/pi-tools@1.0.0 时,Pi 内部依次执行以下步骤:

  1. 解析包引用:将字符串解析为 { type: "npm", name: "@scope/pi-tools", version: "1.0.0" } 结构。
  2. 下载包
    • npm 包:通过 npm pack 或直接 npm install 到 Pi 的内部缓存目录(~/.pi/packages/)。
    • Git 包:通过 git clone 到同一缓存目录。
  3. 读取 package.json 中的 pi 字段:这是 Pi 包的核心声明——它告诉 Pi 这个包里有哪些 Skills、Extensions、Prompts、Themes。详见 10.4
  4. 注册资源:将 Skills 路径加入 Skills 索引(Pi 启动时加载),将 Extensions 路径加入 Extension 加载列表,将 Prompt 和 Theme 路径加入对应的资源池。
  5. 更新配置:在 settings.jsonpackages 数组中追加该包引用字符串(如果使用 --no-save 参数则跳过)。
  6. 输出安装摘要:在 TUI 中显示安装了哪些资源(如 “✓ 已加载 2 个 Skills,1 个 Extension”)。

安装过程中的 package.json 查找逻辑:Pi 会在包的根目录下寻找 package.json,如果找不到,或者找到了但其中没有 pi 字段,Pi 会给出警告并跳过该包——因为没有 pi 字段的声明,Pi 不知道该包提供了什么资源。

10.2.5 安装参数

# 保存到全局配置(默认行为)
pi install npm:pi-tool-react

# 保存到项目配置
pi install npm:pi-tool-react --project
pi install npm:pi-tool-react -p

# 仅临时使用,不写入 settings.json
pi install npm:pi-tool-react --no-save

# 强制重新下载(即使缓存中已有相同版本)
pi install npm:pi-tool-react --force

# 安装但不自动启用(仅下载,不加载资源)
pi install npm:pi-tool-react --no-enable

--no-save 适合测试新包——不想因为试用就把包永久写进配置。--force 适合包的本地开发迭代——你改了包的代码,想确认 Pi 加载的是最新版本而非缓存。


10.3 管理包

10.3.1 pi list:查看已安装包

pi list

输出示例:

已安装的 Pi 包:

  全局包(~/.pi/agent/settings.json):
  ┌──────────────────────────────────┬──────────┬──────────────────────────────────┐
  │ 包名                              │ 版本     │ 源                               │
  ├──────────────────────────────────┼──────────┼──────────────────────────────────┤
  │ pi-tool-react                    │ 0.2.0    │ npm registry                     │
  │ npm:@scope/pi-utils              │ 1.0.0    │ npm registry                     │
  │ git:github.com/user/pi-private   │ a1b2c3d  │ GitHub (main)                    │
  └──────────────────────────────────┴──────────┴──────────────────────────────────┘

  项目包(./.pi/settings.json):
  ┌──────────────────────────────────┬──────────┬──────────────────────────────────┐
  │ 包名                              │ 版本     │ 源                               │
  ├──────────────────────────────────┼──────────┼──────────────────────────────────┤
  │ pi-skill-db-migration            │ 1.2.0    │ npm registry                     │
  └──────────────────────────────────┴──────────┴──────────────────────────────────┘

  合计:4 个包

对于 Git 包,”版本”列显示的是当前 checkout 的 commit 短哈希和分支名。

10.3.2 pi remove:卸载包

# 卸载包
pi remove npm:pi-tool-react

# 同时清理缓存
pi remove npm:pi-tool-react --purge

pi remove 做了三件事:

  1. settings.jsonpackages 数组中删除该包引用。
  2. 从 Pi 的资源索引中注销该包提供的所有 Skills、Extensions、Prompts、Themes。
  3. 默认保留缓存(~/.pi/packages/ 中的下载文件),以便将来重新安装时无需再次下载。--purge 参数会额外删除缓存。

10.3.3 pi update:更新包

# 更新 Pi 本身
pi update

# 更新 Pi 和所有已安装包到最新版本
pi update --all

# 仅更新已安装的包(不更新 Pi 本身)
pi update --packages

# 更新指定包
pi update npm:pi-tool-react

pi update --all 是推荐的日常维护命令——每周运行一次即可保持整个 Pi 生态处于最新状态。更新时的具体行为:

更新对象 检查内容 更新方式
Pi 本身 npm registry 上 @earendil-works/pi-coding-agent 的最新版本 npm install -g @earendil-works/pi-coding-agent@latest
npm 包 每个包在 npm registry 上的最新版本(或满足 semver 范围的最新版本) 重新下载并替换缓存
Git 包 远程仓库的最新 commit(当前 checkout 分支的 HEAD) git pull(若本地有未提交修改则警告并跳过)

Git 包的更新策略:Pi 不会强制覆盖本地修改——如果你在 ~/.pi/packages/ 中对 Git 包做了手动修改(例如调试),pi update 会跳过该包并给出警告,提示先处理本地修改后再更新。

版本锁定与更新:如果你在包引用中指定了精确版本(@1.0.0),pi update --all 不会将其升级——它会保持你锁定的版本。只有当你使用范围版本(@^1.0.0)、@latest 或未指定版本时,才会拉取最新匹配版本。


10.4 创建可分发包

创建一个 Pi 包的本质是:创建一个包含 package.json(其中有 pi 字段)的 npm 包或 Git 仓库。如果包中还有 .ts/.js 扩展文件、SKILL.md 技能文件、.md 提示模板或 .json 主题文件,在 pi 字段中声明它们的路径即可。

10.4.1 package.json 中的 pi 字段

pi 字段是 Pi 识别一个 npm 包是否为 Pi 包的标志。如果 package.json 中没有这个字段,Pi 会认为这个包不提供任何 Pi 资源(即使它恰好包含技能文件),从而跳过加载。

pi 字段的结构:

{
  "name": "pi-tool-my-awesome-pack",
  "version": "1.0.0",
  "description": "一个描述",
  "pi": {
    "extensions": ["./extensions/hello.ts"],
    "skills": ["./skills/code-review/SKILL.md"],
    "prompts": ["./prompts/coding-style.md"],
    "themes": ["./themes/ocean.json"]
  }
}

10.4.2 pi.extensions:扩展路径

一个字符串数组,指向包内的 TypeScript 或 JavaScript 扩展文件。Pi 在加载包时会按顺序将这些文件作为 Extension 加载——与你在 settings.jsonextensions 数组中声明本地扩展的行为完全一致。

"pi": {
  "extensions": [
    "./extensions/danger-detector.ts",
    "./extensions/git-utils.ts"
  ]
}

路径是相对于包根目录的。每个 .ts / .js 文件必须导出一个默认函数,接收 ExtensionAPI 对象并在其上注册工具、命令或事件监听器。具体 API 参见第九章:Extensions 扩展开发

10.4.3 pi.skills:技能路径

一个字符串数组,指向包内的 SKILL.md 技能文件。每个路径通常指向一个目录——Pi 会加载该目录下的 SKILL.md 文件(目录名即为技能名)。

"pi": {
  "skills": [
    "./skills/git-workflow",
    "./skills/api-design"
  ]
}

上述配置意味着包内存在以下文件结构:

pi-tool-my-awesome-pack/
├── skills/
│   ├── git-workflow/
│   │   └── SKILL.md
│   └── api-design/
│       └── SKILL.md
├── ...
└── package.json

技能文件遵循 agentskills.io 标准。Pi 在启动时只加载技能名称和一句话摘要,完整内容在 Agent 首次使用时才按需加载(渐进式披露)。详细技能编写规范见第八章:Skills 技能系统

10.4.4 pi.prompts:提示模板路径

一个字符串数组,指向包内的 Markdown 提示模板文件。这些文件的内容会被追加到系统提示的末尾(在所有 Skills 之后、对话历史之前)。

"pi": {
  "prompts": [
    "./prompts/react-patterns.md",
    "./prompts/testing-guidelines.md"
  ]
}

提示模板用于注入”始终在线”的行为约束或风格指南,而不是像 Skills 那样按需加载。例如:

  • react-patterns.md:”> 始终使用函数组件和 Hooks。避免 class 组件。状态管理优先使用 useState 和 useReducer。”
  • testing-guidelines.md:”> 为所有导出的工具函数编写单元测试。测试文件与源文件同目录,后缀 .test.ts。”

10.4.5 pi.themes:主题路径

一个字符串数组,指向包内的 JSON 主题文件。

"pi": {
  "themes": [
    "./themes/ocean.json",
    "./themes/forest.json"
  ]
}

加载后,用户可以在 settings.jsontheme 字段中通过主题名引用这些主题。例如,如果 ocean.json 中定义了 "name": "ocean",用户就可以设置 "theme": "ocean"

10.4.6 完整 package.json 示例

以下是一个真实可用的 Pi 包 package.json 完整示例。这个假想的包名为 pi-tool-frontend-kit,集成了 React 开发中常用的扩展、技能、提示模板和主题:

{
  "name": "pi-tool-frontend-kit",
  "version": "1.2.0",
  "description": "Pi package with tools, skills, prompts and theme for React frontend development",
  "keywords": ["pi", "pi-package", "react", "frontend"],
  "author": "Your Name <you@example.com>",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/your-org/pi-tool-frontend-kit"
  },
  "pi": {
    "extensions": [
      "./extensions/component-scaffolder.ts",
      "./extensions/css-linter.ts"
    ],
    "skills": [
      "./skills/react-component",
      "./skills/state-management",
      "./skills/api-integration"
    ],
    "prompts": [
      "./prompts/react-conventions.md",
      "./prompts/a11y-checklist.md"
    ],
    "themes": [
      "./themes/ocean-breeze.json"
    ]
  },
  "dependencies": {
    "typebox": "^0.32.0"
  },
  "peerDependencies": {
    "@earendil-works/pi-coding-agent": ">=0.70.0"
  },
  "files": [
    "extensions/",
    "skills/",
    "prompts/",
    "themes/",
    "package.json",
    "README.md"
  ]
}

几个关键点:

  • keywords 中包含 "pi""pi-package":方便在 npm 上被搜索到。社区约定所有 Pi 相关的包都在 keywords 中带上这两个标签。
  • peerDependencies 声明 Pi 版本要求:如果你的包依赖了特定版本的 Extension API,通过此字段声明兼容的 Pi 版本范围,npm 会在安装时给出提示。
  • dependencies 中声明 typebox:如果你的 Extension 注册了自定义工具,通常需要使用 TypeBox 来定义工具参数 schema。第九章会详细讲解。
  • files 字段精确控制发布内容:npm publish 默认会包含 .gitignore 忽略之外的所有文件。显式声明 files 可以避免意外将测试文件、开发配置等发布到 npm。

10.5 包资源加载机制

理解 Pi 如何发现和加载包中的资源,对于调试包相关问题(”装了但没生效”)至关重要。

10.5.1 加载顺序和优先级

Pi 的资源加载严格按照以下顺序进行:

1. 内置工具和命令(read / write / edit / bash / grep / find / ls)
2. 全局 settings.json 中声明的 Extensions / Skills / Prompts / Themes
3. 全局 settings.json 中 packages 数组的每个包
4. 项目 .pi/settings.json 中声明的 Extensions / Skills / Prompts / Themes
5. 项目 .pi/settings.json 中 packages 数组的每个包
6. CLI -e 参数临时加载的 Extensions

这个顺序的意义:后加载的可以覆盖先加载的。例如,你可以在全局安装一个 pi-theme-dark 包,然后在项目中通过本地 themes 数组覆盖其中某个主题。同样,项目包中的 Skill 可以覆盖全局包中同名的 Skill(通过 Skill 名称匹配)。

10.5.2 冲突解决

当两个包声明了同名的资源时,Pi 使用以下规则解决冲突:

资源类型 冲突检测依据 解决规则
Extension 文件名(不含路径前缀) 后加载的覆盖先加载的
Skill 技能目录名(skills/<name>/SKILL.md 中的 <name> 后加载的覆盖先加载的
Prompt 文件名 全部加载(追加,不覆盖)
Theme 主题 JSON 中的 name 字段 后加载的覆盖先加载的

Skill 覆盖是特性,不是 Bug:如果一个项目包声明了一个与全局包同名的 Skill,项目包的版本会”阴影”(shadow)全局包的版本。这允许团队在特定项目中定制一个通用 Skill 的行为,而不影响其他项目。Pi 在启动日志中会明确标注被覆盖的 Skill(⚠ skill "code-review" 已被 /path/to/project-skill/SKILL.md 覆盖)。

Prompt 不覆盖:因为 Prompt Templates 是追加到系统提示末尾的文本块,多个来源的 Prompts 应该全部生效——全局和项目的行为约束同时起作用。如果两个包有同名的 Prompt 文件,两者的内容都会被注入。

10.5.3 资源发现机制

Pi 在启动时会触发一个内部的 resources_discover 事件,该事件的流程如下:

  1. 扫描 settings.json 的 packages 数组,解析每个包引用。
  2. 对于每个包
    • 检查缓存目录中是否已有该包。没有则下载(npm install 或 git clone)。
    • 读取包的 package.json,提取 pi 字段。
    • 验证 pi 字段中声明的每个路径是否存在。不存在的路径会给出警告但不阻塞启动。
    • 将资源路径登记到对应索引中。
  3. 对于本地声明的 Extensions / Skills / Prompts / Themes:解析路径(展开 ~、解析相对路径),验证文件存在性,登记到索引。
  4. 构建最终的资源表:合并所有来源,按优先级解决冲突。
  5. 按需加载 Skills:Skills 在启动时只加载名称和摘要(从 SKILL.md 的 front matter 或首段提取),完整内容在 Agent 首次使用时才按需加载(渐进式披露)。
  6. 执行 Extensions:导入每个 Extension 的默认导出函数,传入 ExtensionAPI 对象,完成工具注册和事件监听。

整个加载过程会输出详细日志(可通过 --debug/debug 命令查看)。如果你安装了包但 Skills 或 Extensions 没有生效,建议先用 pi --debug 启动,查看日志中是否有路径解析错误或冲突覆盖警告。


10.6 发布到 npm

npm 是 Pi 包生态的主要分发渠道。将你的 Pi 包发布到 npm 上,全世界的 Pi 用户都可以通过 pi install npm:your-package 安装它。

10.6.1 发布前的检查清单

npm publish 之前,请逐项确认:

  • package.jsonname 字段以 pi- 开头(社区约定,见 10.9.1)。
  • package.json 中已正确设置 version(初始版本建议 0.1.0,遵循 semver)。
  • pi 字段存在且所有路径指向实际存在的文件。
  • keywords 中包含 "pi""pi-package"
  • files 字段(或 .npmignore)正确配置,排除测试、开发配置等不需要发布的内容。
  • peerDependencies 中声明了对 @earendil-works/pi-coding-agent 的版本要求。
  • 在本地用 pi install ./path/to/your-package --no-savenpm link 测试过,确认包能正常加载。
  • README.md 中包含:包的用途、安装方式(pi install npm:your-package)、提供的资源列表(Skills / Extensions / Prompts / Themes)。

10.6.2 npm publish 流程

# 1. 确保你在包根目录
cd /path/to/pi-tool-my-pack

# 2. 登录 npm(如果尚未登录)
npm login

# 3. 检查哪些文件会被发布
npm pack --dry-run

# 4. 发布
npm publish

# 5. 验证
npm view pi-tool-my-pack

scope 包的发布:如果你的包使用了 scope(如 @myteam/pi-tools),首次发布时需要加上 --access public(scope 包默认是私有的):

npm publish --access public

10.6.3 版本管理

遵循语义化版本(Semantic Versioning / semver):

版本变化 示例 何时使用
补丁版本(Patch) 1.0.01.0.1 Bug 修复,不影响 API
次版本(Minor) 1.0.01.1.0 新增 Skill / Extension / Theme,向后兼容
主版本(Major) 1.0.02.0.0 不兼容的 API 变更,重命名 Skill,改变工具参数

便捷命令:

npm version patch   # 1.0.0 → 1.0.1,自动 git tag
npm version minor   # 1.0.0 → 1.1.0
npm version major   # 1.0.0 → 2.0.0

npm version 命令会自动更新 package.json 中的版本号并创建 git tag,但不会自动 push。需要手动执行 git push --follow-tags

10.6.4 发布注意事项

  1. 不要发布包含 API Key 或凭证的文件。检查 files 字段和 .npmignore,确保 auth.json.envcredentials.json 等敏感文件不会被打包。
  2. Extension 中不要硬编码绝对路径。使用 Extension API 提供的路径解析函数获取配置文件、数据库等持久化资源的位置。
  3. 测试你的包在”干净环境”中是否可用。在另一个目录中执行 pi install npm:your-package --no-save,确认能正常加载和使用。
  4. 发布后更新 CHANGELOG。在 GitHub Release 中简述该版本的变更内容,让用户知道升级能得到什么。
  5. 遵循 npm 的最佳实践main 字段指向入口文件(如果你的包也是可编程使用的库),types 字段指向类型声明文件(如果你的包提供了 TypeScript 类型)。

10.7 从 Git 仓库安装

Git 源为 Pi 包的私有分发和开发中迭代提供了灵活性——你不需要发布到 npm 就能让团队成员使用你的包。

10.7.1 GitHub / GitLab / Bitbucket 支持

Pi 对三大 Git 托管平台提供原生支持:

# GitHub
pi install git:github.com/user/pi-tools
pi install git:github.com/user/pi-tools#develop
pi install git:github.com/user/pi-tools#v1.0.0

# GitLab
pi install git:gitlab.com/user/pi-tools

# Bitbucket
pi install git:bitbucket.org/user/pi-tools

Pi 内部会为每个平台自动补全正确的 git clone URL。对于 GitHub,完整的克隆命令等价于:

git clone https://github.com/user/pi-tools.git ~/.pi/packages/git-github.com-user-pi-tools/

10.7.2 私有仓库配置

安装私有仓库的 Pi 包需要认证。根据你的 Git 托管平台和认证方式,有以下几种方案:

方案 A:SSH 密钥(推荐)

为你的机器配置 SSH 密钥并将其添加到 GitHub / GitLab 账户中:

# 1. 生成 SSH 密钥(如果还没有)
ssh-keygen -t ed25519 -C "your-email@example.com"

# 2. 将公钥添加到 GitHub / GitLab
cat ~/.ssh/id_ed25519.pub

# 3. 测试 SSH 连接
ssh -T git@github.com

# 4. 使用 SSH 格式的 URL 安装
pi install git:git@github.com:your-org/pi-private-tools.git

Pi 执行 git clone 时会自动使用系统的 SSH 配置。

方案 B:HTTPS + Personal Access Token

如果你无法使用 SSH,可以通过 Personal Access Token 进行 HTTPS 认证:

# GitHub: 在 https://github.com/settings/tokens 生成 token
pi install git:https://<your-token>@github.com/your-org/pi-private-tools.git

# GitLab: 在 https://gitlab.com/-/profile/personal_access_tokens 生成 token
pi install git:https://oauth2:<your-token>@gitlab.com/your-org/pi-private-tools.git

安全警告:将 Token 直接写入包引用字符串意味着它会被明文记录在 settings.json 中。更安全的做法是使用 Git 的 credential helper:

# 配置 Git credential helper
git config --global credential.helper store

# 首次克隆时手动输入用户名和 Token
git clone https://github.com/your-org/pi-private-tools.git
# 输入用户名和 Token,Git 会记住

# 之后 Pi 的 git clone 也会复用这个凭证
pi install git:https://github.com/your-org/pi-private-tools.git

方案 C:自托管 Git 的 SSH 配置

如果你的组织使用自托管的 Git 服务(如 Gitea、Gogs、GitLab CE),在 ~/.ssh/config 中配置好主机别名和密钥:

# ~/.ssh/config
Host git.mycompany.com
    HostName git.mycompany.com
    User git
    IdentityFile ~/.ssh/mycompany_rsa

然后使用对应的 URL 安装:

pi install git:git@git.mycompany.com:team/pi-tools.git

10.7.3 SSH 认证故障排查

如果 pi install git:... 报错 Permission denied (publickey)

  1. 确认 SSH 密钥已添加到 Git 平台:登录 GitHub → Settings → SSH and GPG Keys,确认密钥在列表中。
  2. 确认 SSH agent 正在运行且密钥已加载
    eval $(ssh-agent -s)
    ssh-add ~/.ssh/id_ed25519
    
  3. 测试 SSH 连接ssh -T git@github.com。正常应输出 “Hi ! You've successfully authenticated..."
  4. 确认 Git URL 格式正确:SSH URL 应以 git@ 开头(git@github.com:user/repo.git),而非 https://

10.8 Pi 配置中的包管理

10.8.1 settings.jsonpackages 数组

packages 字段已在第五章(5.6.1)中介绍过。这里从”包管理”的角度补充一些细节:

{
  "packages": [
    "pi-tool-react@0.2.0",
    "npm:@scope/pi-utils@1.0.0",
    "git:github.com/your-org/pi-private-tools.git#v2.0.0"
  ]
}

手动编辑 vs pi install 命令:你可以直接手动编辑 settings.jsonpackages 数组中添加包引用——Pi 在下次启动时会自动检测到新增条目并下载。但推荐使用 pi install 命令,因为它会:

  • 立即解析包引用并下载
  • 验证包格式和内容
  • 给出即时的加载结果反馈
  • 避免手动写错格式

数组的维护:当你添加或删除包时,注意数组中条目的 JSON 语法要求——每个字符串后要有逗号(除了最后一项),字符串要双引号包裹。

10.8.2 项目级 .pi/settings.json 配置

项目级包配置与全局配置的格式完全一致,但语义不同——它只对当前项目生效:

// 项目根目录/.pi/settings.json
{
  "packages": [
    "pi-skill-project-conventions@0.1.0",
    "git:github.com/my-team/pi-internal-tools.git"
  ]
}

项目信任机制的作用:如第五章所述,Pi 默认不会自动加载项目级配置——你需要在使用该项目的 Pi 时确认信任。一旦信任,项目级 packages 会被追加到全局 packages 之后。

10.8.3 全局 ~/.pi/agent/settings.json 配置

全局 settings.json 中的 packages 定义了所有项目中都可用的包:

{
  "packages": [
    "pi-tool-shell-safety@1.0.0",
    "pi-theme-nord@0.5.0",
    "pi-skill-git-workflow@1.2.0"
  ]
}

全局包的管理原则

  • 保持全局包列表精简——只装你在每个项目中都会用到的通用包。
  • 项目专有工具放在项目级 packages 中。
  • 定期执行 pi list 检查全局包列表,移除不再使用的包。

10.9 最佳实践

10.9.1 包命名规范

社区约定 Pi 包的命名遵循以下规范:

类别 命名格式 示例
通用工具 pi-tool-<功能>pi-<功能> pi-tool-shell-safetypi-git-helper
技能 pi-skill-<技能名> pi-skill-git-workflowpi-skill-api-design
主题 pi-theme-<主题名> pi-theme-nordpi-theme-solarized
语言/框架专用 pi-<语言>-<功能> pi-react-component-genpi-python-linter
组织内部 @<组织>/pi-<功能> @mycompany/pi-internal-tools

为什么命名重要:npm 是一个扁平的命名空间——所有无 scope 的包共享 package-name。以 pi- 开头能:

  • 让用户在 npm 上搜索 pi- 时找到你的包(Pi 生态的社区 4600+ 包几乎全部以 pi- 开头)。
  • pi list 输出中自然地排列在一起。
  • 向潜在用户传达”这是一个 Pi 生态的包”。

10.9.2 包版本管理

在生产环境中,对包版本的管理建议如下:

  1. 全局包使用精确版本"pi-tool-shell-safety@1.0.0" 而非 "pi-tool-shell-safety"。这样 pi update --all 不会意外升级全局包——升级全局包可能影响你所有项目的 Pi 行为。
  2. 项目包可以适当宽松:如果项目包的 API 稳定、作者有良好的向后兼容记录,可以使用 @^1.0.0 自动获取补丁和次版本更新。
  3. Git 包使用 tag 锁定git:github.com/user/repo#v1.0.0 而非 git:github.com/user/repo#main。主分支随时可能合并 breaking change。
  4. 在团队中统一版本:在团队的 AGENTS.md 或项目文档中明确写出当前使用的各个包及其版本。新成员加入时,执行 pi install 即可获得一致的包环境。

10.9.3 团队共享

将 Pi 包作为团队知识资产共享的方式:

  1. 发布到 npm(公开或组织 scope):适合已经稳定、被多个项目使用的包。
  2. 通过私有 Git 仓库共享:适合仍在快速迭代的包、或包含组织敏感信息的包(如内部工具集、数据库 schema 变更 Skill)。
  3. 在项目仓库中内嵌 .pi/ 目录:如果某个包的资源量很小(就一个 Skill 文件和一个 Extension),直接放在项目 .pi/ 目录下比发布成一个独立的包更简单。

推荐的分发策略

资源量 稳定性 建议
1-2 个 Skill 或 1 个 Extension 项目专属 放在项目 .pi/ 目录
3+ 个资源、多个项目共用 稳定 发布为 npm 包
3+ 个资源、仍在迭代 不稳定 通过私有 Git 仓库共享,用 tag 或分支分流
大型工具集(10+ 个资源) 稳定 发布为组织 scope 下的 npm 包:@your-org/pi-kit

10.9.4 安全注意事项

包系统引入了新的安全考量——你安装的包中的 Extension 代码会在你的机器上以 Pi 进程的权限运行。以下是几条关键的防护措施:

  1. 审查包的来源
    • 安装前查看包的 npm 页面:下载量、最后发布时间、GitHub 仓库的 stars 和活跃度。
    • 阅读包的 README.md 了解其功能范围。如果包声称只提供一个 Skill 但其 package.json 声明了多个 Extensions,保持警惕。
    • 查看包的 GitHub Issues 区,了解是否有安全问题被报告。
  2. 审查 Extensions 代码
    • Extension 是 TypeScript/JavaScript 代码,拥有和 Pi 进程同等的文件系统权限。安装包后,尽快阅读其 Extensions 源码(~/.pi/packages/<package>/extensions/)。
    • 重点关注:Extension 是否调用了 bash 工具、是否监听和修改了 tool_call 事件、是否注册了网络请求相关的工具。
  3. 使用 Git 的 commit/tag 而非动态分支
    • git:github.com/user/repo#v1.0.0 指向一个不可变的 tag——你审查过一次代码后,这个 tag 的代码不会变。
    • git:github.com/user/repo#main 是可变的——你审查过的代码可能在下一次 pi update 后被替换为包含恶意代码的新版本。
  4. 最小权限原则
    • 只安装你真正需要的包。不要因为”看起来有用”而安装一个你实际上不会用到的包。
    • 对于不需要读写文件的包(如纯主题包),Pi 默认的 YOLO 模式风险较低——主题没有可执行代码。
    • 对于包含 Extensions 的包,这些 Extensions 可以执行任意 shell 命令、读写任意文件——在”完全可信”的项目之外使用它们时,请通过 Docker 容器或 Gondolin 微 VM 运行 Pi(见第十二章:容器化与安全沙箱)。
  5. CI/CD 中的包管理
    • 在 CI 流水线中使用的包,尽量锁定精确版本。
    • 在 CI 中运行 pi list 并对比期望的包列表,确保没有意外引入或遗漏的包。
    • 考虑在 CI 流水线中加入 npm audit 步骤,检测包依赖中的已知漏洞(Pi 包本身是 npm 包,其依赖链也受 npm audit 覆盖)。

10.10 本章小结

本章完整覆盖了 Pi 包生态系统的方方面面:

  • 包系统概述:一个 Pi 包是在 package.json 中声明了 pi 字段的普通 npm 包或 Git 仓库,可包含 Extensions、Skills、Prompts、Themes 四种资源。安装源为 npm 和 Git,配置在 settings.jsonpackages 数组中,分全局和项目两级。
  • 安装包pi install <引用> 支持 npm 包(含 scope、版本号、semver 范围)和 Git 仓库(含分支/tag/commit)两种格式。安装流程依次为下载、读取 pi 字段、注册资源、更新配置。
  • 管理包pi list 列出已安装包,pi remove 卸载并注销资源,pi update 更新 Pi 本体(pi update)、同时更新所有包(pi update --all)、或只更新指定包。
  • 创建可分发包:核心是在 package.json 中添加 pi 字段,声明 extensionsskillspromptsthemes 的路径。本章提供了一个包含全部四种资源的完整 package.json 示例。
  • 资源加载机制:资源按固定的优先级顺序加载——内置工具 → 全局资源 → 全局包 → 项目资源 → 项目包 → CLI -e 扩展。同名 Skills 和 Extensions 后加载的覆盖先加载的,Prompt Templates 则全部追加不覆盖。Skills 采用渐进式披露——启动时仅加载名称和摘要。
  • 发布到 npm:遵循 npm publish 标准流程,推荐版本号遵循 semver,keywords 中包含 "pi""pi-package"
  • 从 Git 仓库安装:支持 GitHub / GitLab / Bitbucket 和自托管 Git。私有仓库可通过 SSH 密钥、HTTPS Personal Access Token 或 Git credential helper 认证。
  • 配置中的包管理:全局 packages 放通用工具,项目 packages 放专属工具。手动编辑和 pi install 命令两种方式均可,推荐后者。
  • 最佳实践:包命名以 pi- 开头、锁定精确版本、按资源量和稳定性选择分发策略(项目内嵌 / npm 发布 / 私有 Git)、安装前审查包来源和 Extensions 代码、在 CI 中锁定版本。

下一章:第十一章:SDK 嵌入与 RPC 模式 将讲解如何通过 SDK 将 Pi 的 Agent 能力嵌入到自己的 Node.js 应用中,以及通过 RPC 协议与非 Node.js 程序集成。


提示:如果你在包管理中遇到问题——包安装了但不生效、Skill 没有出现、Extension 报错——先用 pi --debug 启动 Pi 并检查启动日志中与 packages 相关的输出。九成问题可以通过日志中的路径解析错误或冲突覆盖警告定位。