第三版以来又用了快一个月。第一次安装 Pi 的佬友可以先看前三版,这篇继续记录第三版之后的变化。
前三版
Pi 从零安装到入门配置:Windows 实战教程
Pi Windows 工作流第二版:从第一版配置升级到现在有哪些改变?
Pi Windows 工作流第三版:继续迭代
你也可以直接把四篇文章交给agent让它配置好
本版:编写于 2026 年 9 月 5 日,Pi 0.85.0。
这次改动主要来自三件事:Pi 有了原生 PowerShell 工具;我换了一套上下文压缩方案;插件更新后,原有配置和本地扩展的部分需要对应调整。
项目 |
第三版 |
当前状态 |
|---|
终端工具 |
通过 bash 工具和 shell 配置使用 PowerShell |
主会话和常规子代理显式使用原生 powershell 工具 |
上下文 |
原生自动压缩、pi-ultra-compact、context-mode |
关闭原生自动压缩,移除 ultra-compact,改用 Magic Context;保留 context-mode |
中文界面 |
pi-di18n 接管部分内置工具显示 |
移除 pi-di18n,使用 rpiv-i18n 翻译接入它的扩展界面 |
模型选择 |
Plan 角色写死模型,后台组件各自配置 |
Plan 角色已继承模型,Historian 用本地扩展同步;普通角色仍有固定供应商配置,下面一起说明如何改成跟随 |
MCP |
Context7、DeepWiki 提前连接 |
两者改为按需连接,工具是否直接暴露另行配置 |
通知 |
新增的通知插件 |
新增 @pi-unipi/notify,使用 Windows 桌面通知 |
本地扩展 |
plan-subagent-ceiling |
保留原扩展,新增 magic-context-model-sync 同步 Historian 的模型选择 |
下面只展开说说上述这些影响工作流使用方式的变化。其他未提及就是没有改变。
原生 PowerShell:主会话、子代理、Plan 和权限一起调整
Pi 0.84.2 加入 defaultTools,0.84.3 加入可选的原生 powershell 工具。这两项合起来,可以让模型看到的工具名和实际使用的终端一致。
之前需要反复告诉模型:虽然工具叫 Bash,这里要按 PowerShell 的变量、引号和路径规则执行。现在主会话直接使用下面这份工具列表。
settings.json 中的当前终端配置
{
"shellPath": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
"defaultTools": [
"read",
"powershell",
"edit",
"write",
"grep",
"find",
"ls"
]
}
这里起工具选择作用的是 defaultTools,不能只改 shellPath。原生 PowerShell 工具优先找 pwsh.exe,没有时才回退到 Windows PowerShell。Pi 在 Windows 上默认仍选择 Bash,需要自己显式启用 PowerShell。
另外,编辑器里的 !、!! 仍走 Bash 入口。defaultTools 也只选择内置工具。
常规子代理也要改自己的工具列表。 主会话启用了 PowerShell,不会覆盖角色配置里已经写死的 tools。我在 settings.json.subagents.agentOverrides 里同步调整了普通角色,下面以 scout 和 worker 为例:
常规子代理的 PowerShell 工具配置摘录
{
"subagents": {
"agentOverrides": {
"scout": {
"tools": ["read", "grep", "find", "ls", "powershell", "contact_supervisor"]
},
"worker": {
"tools": ["read", "grep", "find", "ls", "powershell", "edit", "write", "contact_supervisor"]
}
}
}
}
其他常规角色也使用 powershell。这里仅摘录工具字段,合并时保留原有的思考等级、上下文继承等配置;模型如何跟随供应商切换,放到后面的模型一节统一说。
Plan 的工具选择单独配置。 我在 ~/.pi/agent/pi-plan-mode.json 的 defaultPlanTools 中加入 powershell,原有读工具、subagent、FFF 和 MCP 条目继续保留,当前文件也仍保留 bash。Plan 会对有效的 bash/powershell 工具应用有限命令策略,普通会话能执行的脚本不一定能通过 Plan 检查。
这里的 safeSubcommands 要按当前版本理解:命中自定义信任前缀后,Plan 会跳过整条命令的解析检查,无法起到只读保证。三个 plan-* 专用角色仍只保留 read/grep/find/ls。
权限插件也要认识新工具名。
权限继续使用 @gotgenes/pi-permission-system,在它的配置里补充:
{
"shellTools": {
"powershell": {
"commandArgument": "command"
}
}
}
把这段合并到 ~/.pi/agent/extensions/pi-permission-system/config.json,原有 permission 规则保留。
因为命令规则写在 permission.bash 下。shellTools 告诉插件:名为 powershell 的工具也携带 shell 命令,命令正文在 command 参数里,要送进现有命令检查链路。只换工具名、不补这个映射,插件会把它当普通扩展工具处理。
终端规则仍按 PowerShell 7 和 UTF-8 编写,避免在原生工具外再套一层 Bash 或 cmd。普通角色即使没有 edit/write,也可能通过 PowerShell 写入文件;我自己的协作规则继续要求子代理只回传证据,由主线程修改文件。
Magic Context:安装、配置和日常更新
前情提要 Pi 有没有压缩插件推荐?
虽然 OpenAI 那边引入了新的上下文压缩方式,但是 Pi 这边还没有跟进,观望一下。
我对上下文的需求是长会话里的整理和回读:旧调查可以从当前上下文移出,需要时还能找回原始消息;不需要把每次任务都积累成跨会话长期记忆。
第三版的组合是原生自动压缩、pi-ultra-compact 和 context-mode。现在移除了 pi-ultra-compact,安装 @cortexkit/pi-magic-context。
现在三个组件这样分工:
context-mode 继续负责大段工具结果的外部索引和检索。
- Magic Context 给消息打标签,通过
ctx_reduce 排队移出不再需要的内容,Historian 在后台整理旧对话,需要原文时通过 ctx_expand 回读。
- Pi 原生自动压缩关闭,由 Magic Context 管理这条自动整理路径。
首次安装,向导和手动安装二选一。
在 PowerShell 7 中运行官方向导:
npx @cortexkit/magic-context@latest setup --harness pi
--harness pi 明确指定 Pi,避免同时装了其他宿主时选错目标。向导会注册 Pi 扩展、创建 Magic Context 配置,并询问 Historian、Dreamer、Sidekick 和 embedding 的模型选择。先在 Pi 里配置好可用的供应商和模型,再按自己的需要选择;我只保留会话整理,后面会关闭长期记忆等功能。
如果不需要向导,也可以直接安装 Pi 包:
pi install npm:@cortexkit/pi-magic-context
这条会把扩展加入 Pi 的 packages,但不会替你创建 magic-context.jsonc,需要自行准备。上面两个命令是两条安装路径,不用连续执行。
记得移除你的其他记忆或上下文管理插件避免冲突,例如我的:
pi remove npm:pi-ultra-compact
压缩开关分别配置。 Pi 的原生自动压缩关闭,Magic Context 自己的压缩开启。
在 ~/.pi/agent/settings.json 关闭 Pi 原生压缩配置,让 Magic Context 接管。
Pi 的压缩配置
{
"compaction": {
"enabled": false,
"reserveTokens": 65536,
"keepRecentTokens": 24000
}
}
Magic Context 当前配置摘录
{
"enabled": true,
"auto_update": true,
"language": "zh",
"cache_ttl": "5m",
"execute_threshold_percentage": 65,
"history_budget_percentage": 0.18,
"protected_tags": 24,
"compaction": {
"enabled": true
},
"smart_drops": false,
"caveman_text_compression": {
"enabled": false
},
"dreamer": {
"disable": true
},
"memory": {
"enabled": false
},
"todowrite": {
"enabled": false
},
"sidekick": {
"disable": true
},
"embedding": {
"provider": "off"
}
}
这份文件在 ~/.config/cortexkit/magic-context.jsonc,不在 .pi 目录里。项目自己的 .cortexkit/magic-context.jsonc 还能覆盖用户配置。
这里关闭了长期记忆、embedding、Dreamer、Sidekick 和 Magic Context 自带 Todo。任务列表继续由现有 rpiv-todo 负责。
Historian 的模型字段和跟随主会话的办法放到下一节,手动安装时也要补上那部分。上面的内容作参考。
日常更新 :
命令 |
更新范围 |
|---|
pi update npm:@cortexkit/pi-magic-context |
只更新 Magic Context 的 Pi 扩展 |
pi update --extensions |
更新扩展包 |
pi update |
只更新 Pi 本体 |
pi update --all |
更新 Pi 本体和扩展包 |
虽然配置虽然写着 auto_update: true,但是现在 magic-context 只支持 OpenCode 插件侧的自动更新检查,不负责升级 Pi 包。Pi 这边仍使用第一条定向更新命令。
日常可以按下面的顺序操作:
- 正常结束当前任务和后台子代理,退出使用同一 Magic Context 数据库的会话。
- 在 PowerShell 中定向更新扩展。
- 用官方
doctor 检查安装、配置和依赖状态,阅读输出后再决定是否需要处理问题。
- 回到项目目录重新启动 Pi,用
/ctx-status 查看本次会话状态,再按下一节同步 Historian 模型。
第 2、3 步的命令是:
pi update npm:@cortexkit/pi-magic-context
npx @cortexkit/magic-context@latest doctor --harness pi
注意两个包名不同:@cortexkit/magic-context 是提供 setup、doctor 的统一 CLI,@cortexkit/pi-magic-context 才是 Pi 加载的扩展。npx ...@latest doctor 使用新版诊断 CLI,不等于把 Pi 插件也更新了。
doctor 也不完全是只读命令,可能迁移旧配置位置,所以先备份。日常更新不需要顺手加 --force 或 --clear。
Magic Context 默认把数据放在 ~/.local/share/cortexkit/magic-context/。如果设置了 MAGIC_CONTEXT_STORAGE_DIR 等路径覆盖,就备份实际使用的目录。同一份数据库可能被 Pi、OpenCode 或 OMP 共用,混合版本进程可能阻止迁移,因此跨版本更新后建议完整退出重启。
多供应商切换:子代理继承,Historian 同步
我经常会在不同供应商(中转)之间切换。同一个模型名在不同供应商下是不同的 provider/model,主会话切换以后,后台组件如果仍写死 A/...,就不会自动跟着走。
Pi 0.84.3 增加了 /thinking 选择器。通过 /model 和 /thinking 做的临时选择保持在当前会话,按 Ctrl+S 才保存为启动默认。模型跟随要以当前父会话的选择为准,就不能只盯着 settings.json 中的默认值。
于是乎为了解决上述问题,现在我的工作流里存在两种情况:一种是类似 pi-subagents 原生支持继承父会话模型直接改成继承父会话模型;一种是类似 Magic Context 的 Historian 需要读取独立配置,需要自己编写本地扩展同步。
Plan 角色已经改成继承。 三个专用角色仍保存在 ~/.pi/agent/agents/,共同使用 model: inherit:
角色 |
当前模型设置 |
思考等级 |
工具 |
|---|
plan-scout |
inherit |
low |
read, grep, find, ls |
plan-researcher |
inherit |
medium |
read, grep, find, ls |
plan-reviewer |
inherit |
medium |
read, grep, find, ls |
inherit 选择的是启动子代理时父会话正在使用的供应商和模型。角色的 low/medium 思考分工继续保留,plan-researcher 的 timeoutMs: 900000、空 extensions 和 inheritSkills: false 也没有放开。
常规角色也需要去掉固定供应商,应删除 subagents.defaultModel 的固定值,把各角色的 model 改为 inherit,并删除旧的固定 fallbackModels,否则失败回退时仍可能回到原供应商。下面是补齐跟随行为的配置示例:
普通角色跟随父会话的模型配置
{
"subagents": {
"agentOverrides": {
"delegate": { "model": "inherit", "thinking": "low" },
"scout": { "model": "inherit", "thinking": "low" },
"context-builder": { "model": "inherit", "thinking": "low" },
"researcher": { "model": "inherit", "thinking": "low" },
"planner": { "model": "inherit", "thinking": "medium" },
"worker": { "model": "inherit", "thinking": "medium" },
"reviewer": { "model": "inherit", "thinking": "medium" },
"oracle": { "model": "inherit", "thinking": "medium" }
}
}
}
这段只覆盖模型和思考字段,前面配置好的 tools、inheritProjectContext 等字段保留。单次子代理调用若显式传入模型,仍会覆盖继承设置;已经运行的子代理也不会因为父会话切模型而中途换模型。
如果想只跟随供应商,但让各角色继续使用不同型号,当前插件还支持 subagents.agentOverridesByProvider,按父会话的供应商匹配角色配置。它和“所有角色直接 inherit”是两种选择。
Historian 通过本地扩展同步。 它的配置在 ~/.config/cortexkit/magic-context.jsonc,我的配置是:
{
"historian": {
"pi": {
"model": "a/gpt-6-astra",
"thinking_level": "xhigh"
}
}
}
这里需要填写 Pi 中已经配置且可用的 provider/model。为避免每次切换都手动修改,我新增了 ~/.pi/agent/extensions/magic-context-model-sync/index.ts:
magic-context-model-sync/index.ts
import { readFile, writeFile } from "node:fs/promises";
import { createRequire } from "node:module";
import { homedir } from "node:os";
import { join } from "node:path";
import { getAgentDir, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
type Model = { provider: string; id: string };
type MagicContextConfig = {
historian?: {
pi?: {
model?: unknown;
thinking_level?: unknown;
fallback_models?: unknown;
[key: string]: unknown;
};
[key: string]: unknown;
};
[key: string]: unknown;
};
const configPath = join(
process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"),
"cortexkit",
"magic-context.jsonc",
);
const requireFromAgentPackages = createRequire(join(getAgentDir(), "npm", "package.json"));
const { parse, stringify } = requireFromAgentPackages("comment-json") as {
parse: <T>(source: string) => T;
stringify: (value: unknown, replacer: null, space: number) => string;
};
function modelKey(model: Model): string {
return `${model.provider}/${model.id}`;
}
async function syncHistorianModel(model: Model, thinkingLevel: string | undefined): Promise<boolean> {
const source = await readFile(configPath, "utf8");
const config = parse<MagicContextConfig>(source);
const historian = config.historian ?? (config.historian = {});
const pi = historian.pi ?? (historian.pi = {});
const nextModel = modelKey(model);
const changed = pi.model !== nextModel
|| pi.thinking_level !== thinkingLevel
|| "fallback_models" in pi;
if (!changed) return false;
pi.model = nextModel;
if (thinkingLevel) pi.thinking_level = thinkingLevel;
else delete pi.thinking_level;
delete pi.fallback_models;
await writeFile(configPath, `${stringify(config, null, 2)}\n`, "utf8");
return true;
}
export default function magicContextModelSync(pi: ExtensionAPI) {
pi.on("model_select", async (event, ctx) => {
try {
if (await syncHistorianModel(event.model, ctx.thinkingLevel)) {
ctx.ui.notify(
`Magic Context Historian 已同步至 ${modelKey(event.model)};执行 /sync-magic-model 可立即重载。`,
"info",
);
}
} catch (error) {
ctx.ui.notify(
`无法同步 Magic Context Historian:${error instanceof Error ? error.message : String(error)}`,
"warning",
);
}
});
pi.registerCommand("sync-magic-model", {
description: "Sync Magic Context Historian with the current Pi model and reload",
handler: async (_args, ctx: ExtensionContext) => {
if (!ctx.model) {
ctx.ui.notify("当前没有已选模型,未同步 Magic Context Historian。", "warning");
return;
}
try {
await syncHistorianModel(ctx.model, ctx.thinkingLevel);
await ctx.reload();
} catch (error) {
ctx.ui.notify(
`无法同步 Magic Context Historian:${error instanceof Error ? error.message : String(error)}`,
"error",
);
}
},
});
}
- 收到
model_select 时,把完整的供应商、模型 ID 和当时的思考等级写入 historian.pi。
- 删除旧的
fallback_models,避免后台继续沿用另一套固定供应商。
- 提供
/sync-magic-model,手动同步当前选择并 reload。
日常操作就是先在 Pi 里选好供应商、模型和思考等级,再执行 /sync-magic-model。只切模型会自动写文件,不会自动 reload;只调思考等级时也用这条命令同步。
这个扩展只同步 Historian,不会重写 settings.json.subagents,所以普通角色的继承配置仍要单独完成。它写的是全局文件,多开会话时后一次写入会影响后续读取这份配置的会话;项目若另有 Magic Context 模型覆盖,也要避免把它固定在旧供应商上。
MCP 减少无必要的提前启动
我用的 MCP 如下:
服务 |
当前生命周期 |
工具暴露方式 |
|---|
context-mode |
eager |
direct |
sequential-thinking |
eager |
direct |
mcp-server-time |
eager |
direct |
shrimp-task-manager |
eager |
direct |
context7-1 |
lazy |
只直接暴露 resolve-library-id、query-docs |
mcp-deepwiki |
lazy |
direct |
playwright |
lazy |
通过 adapter 代理调用 |
chrome-devtools-mcp |
lazy |
通过 adapter 代理调用 |
相较第三版,Context7 和 DeepWiki 从 eager 改成 lazy,避免每次启动就连接暂时不用的文档服务。全局 directTools 为 false,再按服务覆盖。lazy 表示按需连接,directTools 决定工具如何暴露给模型。
Context7 当前配置片段
{
"protocolVersion": "auto",
"lifecycle": "lazy",
"directTools": [
"resolve-library-id",
"query-docs"
]
}
界面、汉化和桌面通知
Pi 本体这一个月增加了几项日常操作:
版本 |
与日常使用有关的更新 |
|---|
0.84.2 |
全屏对话全文搜索;单独点击展开思考块和工具结果 |
0.84.3 |
调整 Windows/WSL 的部分默认快捷键 |
0.84.4 |
新增 fullscreenCopyOnSelect,可关闭拖选后自动复制;关闭后 Ctrl+X 优先复制选区 |
0.85.0 |
上翻后可点击 Jump to latest message 回到最新消息;优化长对话搜索的缓存、索引和高亮处理 |
我的 tuiMode: fullscreen、自动滚动条和 Markdown 配置继续保留,没有显式关闭 fullscreenCopyOnSelect。
快捷键继续以自己的 keybindings.json 为准。我的文件保留第三版的编辑器移动和换行绑定,另外显式设置了:
{
"tui.altScreen.searchPrevious": "shift+enter"
}
汉化从 pi-di18n 换成 rpiv-i18n。
第三版为了避免内置工具重复注册,把 read/edit/write/bash 留给 pi-di18n,tool-display 只接管搜索工具。现在因为 pi-di18n 作者维护不及时,我已经放弃了汉化,移除 pi-di18n。
rpiv-i18n 提供 /languages,统一切换接入其 SDK 的扩展界面语言;它不会把整个 Pi、所有内置工具或发给模型的提示词都翻译成中文。
我现在的语言设置是:
{
"locale": "zh"
}
文件在 ~/.config/rpiv-i18n/locale.json。这样能保留问答、Todo 等已接入扩展的中文界面,同时不再依赖 pi-di18n 覆盖内置工具显示。
显示层的其他分工继续沿用:
- Pi 负责全屏布局、滚动、搜索和内置显示。
pi-zentui 负责编辑器、用户消息和 Starship Footer;当前图标模式是 ascii,主题为 codex-graphite。
pi-tool-display 仍只启用 grep/find/ls 的内置工具覆盖,read/bash/edit/write 保持 false。
pi-markdown-preview 保留独立预览能力。
补齐桌面通知能力
顺便我还新增了插件 @pi-unipi/notify 补齐桌面通知能力。长任务结束、模型需要我回答问题,或者权限插件正在等确认时,我希望在切到其他窗口后仍能收到提醒。
它支持原生桌面、Gotify、Telegram 和 ntfy。我现在只开启原生桌面通知,另外三个渠道关闭,通知的模型摘要 recap 也关闭。
当前通知配置摘录
{
"native": {
"enabled": true,
"suppressWhenFocused": true
},
"events": {
"agent_end": {
"enabled": true,
"platforms": []
},
"agent_settled": {
"enabled": true,
"platforms": []
},
"ask_user_prompt": {
"enabled": true,
"platforms": []
},
"permission_request": {
"enabled": true,
"platforms": []
}
},
"recap": {
"enabled": false
}
}
配置位置是 ~/.unipi/config/notify/config.json,可以通过 /unipi:notify-settings 调整。suppressWhenFocused 用来抑制 Pi 窗口处于焦点时的原生通知,空 platforms 则使用已启用的渠道。
插件已经接入 rpiv-ask-user-question 的提问事件和权限插件的确认事件。agent_end 表示一次 agent run 结束,agent_settled 才表示重试、压缩和排队续跑结束后的稳定状态。我当前两项都开着,不能把每条结束通知都理解成整项任务已经完成。
其他工作流、MCP 错误等事件开关也已开启,但跨插件事件需要对应发送方配合。
当前插件版本一览
当前插件版本一览
包 |
已安装版本 |
|---|
pi-mcp-adapter |
2.32.1 |
pi-until-done |
0.3.1 |
@narumitw/pi-plan-mode |
0.56.0 |
@juicesharp/rpiv-advisor |
2.9.0 |
pi-simplify |
0.2.3 |
pi-markdown-preview |
0.16.0 |
@juicesharp/rpiv-ask-user-question |
2.9.0 |
@juicesharp/rpiv-i18n |
2.9.0 |
pi-rewind |
0.5.0 |
@gotgenes/pi-permission-system |
31.1.1 |
pi-wtf |
0.2.4 |
@ff-labs/pi-fff |
0.10.6 |
pi-web-access |
0.28.0 |
@juicesharp/rpiv-todo |
2.9.0 |
pi-zentui |
0.22.3 |
pi-subagents |
0.65.1 |
pi-tool-display |
0.5.0 |
@narumitw/pi-lsp |
0.49.6 |
@cortexkit/pi-magic-context |
0.41.3 |
@pi-unipi/notify |
2.16.0 |
AGENTS.md 更新
我的最新 AGENTS.md
AGENTS.md.txt (17.1 KB)

主要差异是适配 pi 支持原生 PowerShell 那在提示词里的约束可以删去一些(但是必要的还是要保留),然后就是改善说废话,还有试图解决静态检查时候召唤子agent无限循环检查和非得给你写测试脚本的毛病,把功能改动约束在主流程里面解决,要求所有功能改动必须在检查前完成,检查只检查代码格式问题,配合 LSP 可以解决。