09-技能-提示模板-主题-包
09 技能、提示模板、主题与包
读这一篇的价值:这四个机制共同决定了“怎么让 Pi 按你的方式工作”,而它们的区别就在于是否需要可执行代码与是否需要分发。选错机制是新手最常见的浪费。
1. 先选对机制
官方在 Quickstart 里给的“最小机制”表,直接拿来当决策树:
| 需求 | 从哪个开始 |
|---|---|
| 给某个目录持久指令 | AGENTS.md(上下文文件) |
从 / 菜单里重用一段提示词 | 提示模板(prompt template) |
| 任务专用指令 + 支撑文件 | 技能(skill) |
| 可执行的工具、命令、事件处理 | 扩展(extension) |
| 自定义终端组件 | TUI(@earendil-works/pi-tui) |
| 接入不支持的模型服务 | 自定义供应商 |
| 安装或分发多个资源 | Pi 包(package) |
一句话概括四者边界:技能 = 知识按需加载;提示模板 = 一段可带参的提示词变成命令;主题 = 终端配色;包 = 前三者的分发容器。
2. 技能(Skills)
技能给 Pi 针对某类工作的专门指令与支撑文件。Pi 启动时只把每个技能的 name + description + 路径放进系统提示词,不加载完整指令;当任务命中时模型才去读 SKILL.md。这是 Pi “上下文按需加载”的主要手段之一。
Pi 实现了 Agent Skills 规范,大多数非法字段只产生警告而不是中止启动。
目录结构
pdf-tools/
├── SKILL.md
├── scripts/
│ └── extract.sh
├── references/
│ └── formats.md
└── assets/
└── template.json
---
name: pdf-tools
description: Extract text and tables from PDF files. Use when reading, converting, or inspecting PDFs.
---
# PDF tools
Read `references/formats.md` before converting a document. Run scripts relative to this skill directory.
description 决定了模型何时考虑加载它:要同时说清“做什么”和“什么时候用”。像“Helps with PDFs”这种描述提供不了路由信息。引用附带文件用相对技能目录的路径(Pi 会告诉模型技能在哪)。
加载与触发
- 模型可能漏加载相关技能,此时用
/skill:name强制加载。命令后跟的参数会作为用户请求追加到已加载指令后:/skill:pdf-tools extract report.pdf。 - frontmatter 里
disable-model-invocation: true使技能只能通过显式命令使用;enableSkillCommands设置控制技能命令是否出现在交互式命令发现里(手动输入的/skill:name仍可用)。 SKILL.md里的 frontmatter 字段:name、description、license、compatibility、metadata、allowed-tools(实验性预批准工具列表)、disable-model-invocation。- 命名:小写字母、数字、连字符,不得有前导/尾部/连续连字符,最多 64 字符;description 最多 1024 字符。Pi 不要求也不告警“声明名与目录名不一致”,但其他实现可能强制,所以保持一致更可携带。
- 格式错误的
SKILL.md与没有 description 的技能不会被加载;名字冲突保留最先发现的,并产生警告。
加载位置
- 用户skills 目录与项目 skills 目录;含
SKILL.md的目录会被递归发现。 - 另外支持 Agent Skills 的位置:
~/.agents/skills/与.agents/skills/。项目的.agents/skills/从工作目录向祖先发现,遇到仓库根就停。 - Pi 接受部分单文件 Markdown 技能,但带
SKILL.md的目录才是可携带形式,应优先用。 - 项目技能可以指示模型跑脚本、改文件:授项目信任前先审阅不熟悉的技能及其支撑文件。
改完技能在活动会话里跑 /reload;排查时看启动诊断与 /skill:name 命令是否出现。
3. 提示模板(Prompt Templates)
把 Markdown 变成可重用的 / 命令,适合“想重用同一段提示词,又不想加可执行行为或大量支撑指令”的场景。
---
description: Review staged git changes
argument-hint: "[focus]"
---
Review the staged changes. Focus on ${1:-correctness, security, and error handling}.
- 文件名就是命令名(上例 →
/review)。description出现在命令补全里;省略时取第一个非空行。 argument-hint可选,用<尖括号>表必填、[方括号]表可选。- 扩展会先通过
input事件拿到原始输入,除非同名扩展命令先处理掉了。
替换语法:
| 语法 | 结果 |
|---|---|
$1、$2 … | 单个位置参数 |
$@ 或 $ARGUMENTS | 所有参数以空格连接 |
${1:-default} | 第一个参数,否则默认值 |
${@:-default} | 所有参数,否则默认值 |
${@:N} | 从第 N 个位置开始的参数 |
${@:N:L} | 从第 N 个位置开始取 L 个参数 |
参数遵循“类似 shell”的引号规则,所以 /review "API compatibility" 提供一个含空格的参数。
加载位置:用户与项目的 prompts 目录;常规 prompts 目录只加载直接的 .md 子文件;设置与包可以选中嵌套 Markdown,包清单能用显式路径与 glob 收窄发现范围。项目模板在授信任后才成为命令。
4. 主题(Themes)
主题控制交互模式与 HTML 导出的颜色。Pi 自带 system、dark、light。
system 主题(默认)
它从终端主题构建 Pi 的颜色,让 Pi 配合终端而不是自带调色板:
- 查询终端的默认前景/背景色与 16 个 ANSI 色;每个 Pi 颜色从某个 ANSI 色取色相(例如 error 取自 red、link 取自 blue),并把亮度设到与背景拉开最小对比:正文在背景上至少保持 4.5:1 的 WCAG 对比度,每个面板同理。
- 终端在明暗之间切换时,Pi 会重新查询并重建主题。
| 终端上报内容 | 结果 |
|---|---|
| 背景 + ANSI 色 | 用终端调色板,并按实际背景摆放 |
| 只有背景 | Pi 自己的色相,按实际背景摆放 |
| 什么都没报 | 用 ANSI 颜色索引与终端默认色,由终端自己渲染(次要文本用 faint,面板无背景色) |
Pi 启动时询问终端颜色,通常几毫秒回答,最多等 100 ms 再显启动头;超时就先用 ANSI 回退方案,颜色稍后到了仍会应用(比如慢速 SSH)。system 是保留名:同名自定义主题会被忽略。
选择主题
/settings → Theme;可以所有终端外观用一个主题,也可以明暗各选一个。保存为 theme 设置:
{ "theme": "dark" }
{ "theme": "light/dark" }
自动模式先存浅色、后存深色。判断终端明暗的顺序:上报的背景/前景色 → 终端的明暗通知 → COLORFGBG 环境变量 → 默认 dark。所以主题名不能含 /。单次运行覆盖用 pi --use-theme light / pi --use-theme light/dark。
自定义主题文件
存为 <agent-dir>/themes/my-theme.json(默认 ~/.pi/agent),把 name 设为 my-theme,改 vars 与 colors,再在 /settings 里选中。用主题名当文件名:只有 <agent-dir>/themes/<name>.json 会被热重载,其他来源改完要 /reload。
| 属性 | 必填 | 作用 |
|---|---|---|
$schema | 否 | 编辑器校验与补全 |
name | 是 | 选择器与设置里的标识;必须唯一、不能含 /、不能是 system |
appearance | 否 | "dark" / "light":主题针对的背景;省略时 Pi 从颜色推断 |
vars | 否 | 可复用颜色值,变量可以引用变量 |
colors | 是 | 把颜色映射到终端 UI 角色(schema 里定义了必填与可选角色) |
export | 否 | 覆盖 HTML 导出的页面与面板背景 |
颜色的六种写法:"#0af" / "#00aaff"(3/6 位 sRGB);"oklch(62% 0.1 200)";"okhsl(250 60% 55%)"(饱和度相对于该色相/亮度下 sRGB 色域允许的最大值,所以值一定在域内且相同饱和度看起来一样鲜艳);39(256 色索引);"primary"(引用 vars);""(终端默认前景/背景)。
Pi 会解析链式变量引用;缺失变量或循环引用使主题无效。有真彩色就用真彩色,OKLCH 会做色域映射到 sRGB,256 色终端做近似。HTML 导出把 OKHSL 转十六进制(CSS 不支持)。颜色与源值不符时,先查终端的真彩色检测与对比度设置。
角色分组(找颜色改哪一块):通用界面 accent/border*/text/muted/dim/success/error/warning;选择与全屏 selectedBg/searchMatch*/scrollbar*;消息 userMessage*/customMessage*/thinkingText;工具执行 toolPendingBg/toolSuccessBg/toolErrorBg/toolTitle/toolOutput;Markdown md*;工具 diff toolDiff*;语法高亮 syntax*;编辑器模式 thinking*/bashMode;HTML 导出 export.pageBg/export.cardBg/export.infoBg。
五个可选颜色会继承:scrollbarTrack←muted、scrollbarThumb←text、searchMatchBg←selectedBg、searchMatchText←text、thinkingMax←thinkingXhigh。省略 export 颜色时,Pi 从 userMessageBg 推导 HTML 页面与面板背景。
项目主题放 .pi/themes/(授信后加载);也可经设置或 Pi 包加载。每个已加载主题名必须唯一,重名会被报告为资源冲突。
5. Pi 包(Packages)
包把扩展、技能、提示模板、主题作为一个整体安装与分发,本质是普通目录或 npm 包,可以带自己的运行时依赖。
安装与管理
pi install npm:@example/pi-tools@1.0.0
pi install git:github.com/example/pi-tools@v1
pi install ./local-package
pi list
pi remove <source>
pi update --extensions
- 个人安装写入
~/.pi/agent/settings.json;加--local/-l写入.pi/settings.json(授项目信任后才会读)。 - 项目包同样在项目信任解决后才安装与加载;包可以执行扩展代码、可能包含指示模型跑程序的技能——安装前审第三方源码,授信前审项目声明。
- 单次试用而不写设置:
pi -e npm:@example/pi-tools。
| 源 | 例子 | 行为 |
|---|---|---|
| npm | npm:@example/pi-tools@1.0.0 | 装在 Pi 的 npm 目录下 |
| git | git:github.com/example/pi-tools@v1 | 克隆并对齐到指定 ref |
| URL | https://github.com/example/pi-tools | 当作 git 源 |
| 本地 | ./pi-tools | 从解析后的路径加载,不拷贝 |
带版本号的 npm 规格会被钉住;git tag 与 commit 也钉住,包更新只对齐已配置的 ref 而不会移动它。相对路径从包含它的那个设置文件解析;文件路径加载一个扩展,目录走常规包发现规则。
创建包
最简包用常规目录:
my-pi-package/
├── package.json
├── extensions/
├── skills/
├── prompts/
└── themes/
没有 pi 清单时,Pi 会从这些目录发现 TS/JS 扩展、技能目录、Markdown 提示词与 JSON 主题。资源在别处或需要过滤时用显式清单:
{
"name": "my-pi-package",
"keywords": ["pi-package"],
"pi": {
"extensions": ["./src/extension.ts"],
"skills": ["./resources/skills"],
"prompts": ["./resources/prompts/*.md"],
"themes": ["./resources/themes/*.json"]
}
}
路径相对于包根;数组支持 glob 与排除。点开头或符号链接的资源根要直接列出(靠 glob 遍历可能发现不到)。pi-package 关键字使 npm 包出现在 Pi 包画廊;pi.image / pi.video 加预览。
依赖声明(容易踩坑)
扩展 import 的运行时包放 dependencies;Pi 在安装 npm 或 git 源时会装包依赖。Pi 向扩展与技能提供这些包:@earendil-works/pi-ai、@earendil-works/pi-agent-core、@earendil-works/pi-coding-agent、@earendil-works/pi-tui、typebox。
规则:
- 上面这些宿主提供的包必须写在
peerDependencies,范围为"*",且不要打包。Pi 对受管 npm 包与用 npm/pnpm/Bun 安装的 git 包会抑制自动 peer 安装。本地包不会被安装或修改,依赖树由作者自负。 - 不要把它们写进
dependencies:物理副本会在编译后的 ESM 里绕过 Pi 的扩展模块映射,造成重复的类、注册表与初始化工作。Pi 检测到这种清单会报扩展警告。 - 作为依赖的其他 Pi 包必须打进发布的 tarball,并通过它们的
node_modules资源路径引用。 - 已安装的包以各自独立的模块根加载:不要指望两个包共享一个依赖实例,也不要指望一个包能解析另一个包未声明的依赖。
选择包内资源
设置里的对象形式可以收窄从包里加载什么:
{
"packages": [
{
"source": "npm:@example/pi-tools",
"extensions": ["extensions/*.ts", "!extensions/legacy.ts"],
"skills": [],
"prompts": ["prompts/review.md"]
}
]
}
每种资源类型:省略属性 = 加载包允许的一切;[] = 一个都不加载;!pattern = 排除 glob 命中;+path / -path = 精确包含/排除单个路径。过滤器只是收窄包清单,不会暴露包本身未声明的资源。
pi config 可以启用/禁用已发现的资源与 Pi 内置扩展:默认从个人配置开始,按 Tab 切作用域,或 pi config --local 直接从项目覆盖开始。
作用域与身份
同一个包可以同时出现在个人与项目设置里:项目条目通常替换个人条目;带 autoload: false 时,项目条目改而作为对个人包的“过滤增量”。身份识别:npm 包按包名、git 包按不含 ref 的仓库 URL、本地包按解析后的绝对路径——这避免同一个包通过等价声明加载两次。
6. 溯源
- 官方
docs/skills.md、docs/prompt-templates.md、docs/themes.md、docs/packages.md、docs/quickstart.md(机制选择表)