Pi Windows 工作流第四版:工作流变化之原生 PowerShell、上下文压缩更换和插件协作

xk128 2026-09-05 20:03 1


第三版以来又用了快一个月。第一次安装 Pi 的佬友可以先看前三版,这篇继续记录第三版之后的变化。




前三版

Pi 从零安装到入门配置:Windows 实战教程


Pi Windows 工作流第二版:从第一版配置升级到现在有哪些改变?


Pi Windows 工作流第三版:继续迭代


你也可以直接把四篇文章交给agent让它配置好




本版:编写于 2026 年 9 月 5 日,Pi 0.85.0



这次改动主要来自三件事:Pi 有了原生 PowerShell 工具;我换了一套上下文压缩方案;插件更新后,原有配置和本地扩展的部分需要对应调整。
















































项目 第三版 当前状态
终端工具 通过 bash 工具和 shell 配置使用 PowerShell 主会话和常规子代理显式使用原生 powershell 工具
上下文 原生自动压缩、pi-ultra-compactcontext-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 加入 defaultTools0.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.jsondefaultPlanTools 中加入 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-compactcontext-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 这边仍使用第一条定向更新命令。


日常可以按下面的顺序操作:



  1. 正常结束当前任务和后台子代理,退出使用同一 Magic Context 数据库的会话。

  2. 在 PowerShell 中定向更新扩展。

  3. 用官方 doctor 检查安装、配置和依赖状态,阅读输出后再决定是否需要处理问题。

  4. 回到项目目录重新启动 Pi,用 /ctx-status 查看本次会话状态,再按下一节同步 Historian 模型。


第 2、3 步的命令是:


pi update npm:@cortexkit/pi-magic-context
npx @cortexkit/magic-context@latest doctor --harness pi

注意两个包名不同:@cortexkit/magic-context 是提供 setupdoctor 的统一 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-researchertimeoutMs: 900000、空 extensionsinheritSkills: 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" }
}
}
}


这段只覆盖模型和思考字段,前面配置好的 toolsinheritProjectContext 等字段保留。单次子代理调用若显式传入模型,仍会覆盖继承设置;已经运行的子代理也不会因为父会话切模型而中途换模型。


如果想只跟随供应商,但让各角色继续使用不同型号,当前插件还支持 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",
);
}
},
});
}



  1. 收到 model_select 时,把完整的供应商、模型 ID 和当时的思考等级写入 historian.pi

  2. 删除旧的 fallback_models,避免后台继续沿用另一套固定供应商。

  3. 提供 /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-idquery-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 可以解决。

最新回复 (4)
  • 一摩尔氚 09-05 20:25
    1

    捉。

    如此好的教程贴只能给你抓到我的集合贴里面了

  • 1571379055 09-05 20:27
    2

    佬,关注啦,很有用的教程

  • 土豆哪里去挖 09-05 20:38
    3

    这个教程真不错^-^下次我照着给我的pi试一下这一套

  • Aprils148 09-05 20:40
    4

    感謝分享,最近用pi覺得真心不錯

* 帖子来源Linux.do
返回