【Pi Coding Agent】我的个性化配置
背景
为何使用起 Pi Coding Agent:
- 主要原因:近几个月很多公益站的 gpt 模型没有了,想要低成本使用没有降智的 gpt 越来越难(还是想白嫖为主🤣)。
- 与此同时,很多公益站都上了国模,主要还是以 flash 为主的模型,比如 deepseek-v4-flash、deepseek-v4.1-flash、glm-5.3-flash,当然也有 glm-5.3,kimi-k3 等大参数模型,但是限制于额度或者是稳定性,一般都不太能顺畅使用。
- 这些 flash 模型在 Codex 或者 Claude Code 上面表现不佳,我猜测原因还是现在这两个功能越来越庞大,并且与自家模型绑定了一些功能(比如 cache_control 和 prompt_cache_key),导致启动时上下文占用很多,并且默认注册的工具也多,一些特殊用法在自家模型上表现正常,在别的模型上则不能正常发挥作用甚至影响模型发挥。
- 平时水 L 站多了,自然早已耳闻 pi 的大名,以简洁著名,能个性化打造自己的 coding agent,并且有了稳定版本,而且还在积极推进,没有那么多 breaking change,所以没怎么考虑就选择了这个了。
- 目标:能够在一些没有那么复杂的场景下使用 Pi Coding Agent + 国模来代替 gpt,达到最低成本 vibe coding。
我写的插件
以下插件基本都是边 Pi Coding Agent+flash 国模开发,边完善的,也是体会到了奥特曼他们用 gpt 开发 codex 的过程,确实以这种方式,开发了也能用起来,用起来的时候也能发现又哪些不足,然后又继续演进,互相成就。
目前基本能用阶段,因为我开发这些插件的过程,就是在用这些插件了,但是估计还得慢慢优化。
watchdog(自动发继续)
解决明明输出还没有结束,但是 api 的流式输出就是完成了,只有发继续才能接着输出。会注册一个工具到主 agent。
因为我默认开启这个插件,如果没有问题,也会发一次给 llm 确认一下,没法知道任务是不是真的完成了,如果人不在屏幕面前,所以下面的截图是正常情况下的。
更多了解可以见文章:【Pi Coding Agent】watchdog自动发继续插件 | GreenHatHGのBlog
subagent
其实 subagent 有时候还是有必要的,我在用 flash 模型的时候发现有些结论并不对,如果你单独拿出这条结论重新开个对话用同样的 flash 模型再确认一次,这次就对了。所以你可以手动复制粘贴一下结论给在新的对话确定一下,或者是叫主 agent 启用 subagent 再去确认一下结论(这里有个坑就是主 agent 给 subagent 的描述,会不会把 subagent 也引导歪了,这是另外一个话题了)。
基于 tmux+Pi Coding Agent 本身,等于是用 tmux 启动另外一个 Pi Coding Agent,基于文件交流。
基于 tmux 好处是可以随时使用 tmux 命令连接上去看 subagent 干了什么,也能提前结束,重新发送别的内容,其实就是跟用 Pi Coding Agent 一样,不用管什么 subagent 不 subagent 的。但是 subagent 不注册 subagent 工具,也就是不能嵌套启用 subagent。
另外 subagent 是一个 Pi Coding Agent 实例的话,也可以用到上面提到的 watchdog 插件,来帮助你自动发继续,确定 subagent 是真的完成了。大家都知道,公益站提供的 llm 很多时候都不稳定,用在 subagent 上是个很痛苦的事情,subagent 可能一直断流,需要靠主 agent 来监控和重试,可能现在很多 harness 框架处理的比较好了,在早期版本,subagent 很不完善。
总共有三种模式,所以会注册三个工具到主 agent,advisor用的最多,其次是websearch,最后是普通的:
- 普通 subagent 模式:system prompt,tools 和主 agent 基本一样。
- websearch 专用:system prompt 改为用于专门搜索,加载 pi-web-access 插件,同时限制 tools 列表。
- advisor 模式:用于 flash 模型询问高级模型,system prompt 改为 advisor 模式专用,同时限制 tools 列表。
以 advisor 模式举例,总共5个部分,如图里面的圆圈:
- 代表模型调用 advisor 工具,然后 subagent 插件会输出一些常用的命令,用于快速复制粘执行,比如 kill 掉这个 subagent、连接到 tmux 上面看这个 subagent 的输出等等。
- 主 agent 给 subagent 写的任务详细说明,点击可以展开查看。
- 主 agent 等待 subagent 完成,超时 1800s,如果 subagent 完成了,会通知这个命令,主 agent 就会接着执行。
- subagent 任务完成后,会将结果写到文件中,点击可以展开查看。
- 主 agent 查看结果文件。
简单加了个 subagent 的状态,先凑合用,ui 和操作并不是很完美😅
默认情况下展示 agent 的状态,左边是 agent 的名字,右边则是最后一行输出:
点击可以展开,查看更多的状态行:
展开后还可以点击具体一个 subagent,这时候弹出一个悬浮窗,其实就是连接上了 tmux 的窗口,可以实时预览 subagent 的输出。
subagent 一执行结束,tmux 就不能连接上去查看,想要事后看到 subagent 做了些什么,只能是通过读 Pi Coding Agent 的 jsonl 文件,里面记录了 subagent 当时做了些什么,可以下载个专门解析 jsonl 的工具,也可以使用 pi --session 命令恢复。
bash guard(命令拦截)
我在用 flash 模型的过程中,发现 flash 用 bash 会执行一些很宽泛的命令,比如 find ~,或者是 grep 没加关键过滤条件或者是条件太广泛,返回 40 kb 的结果。所以我搞了个插件,专门拦截一些广泛的命令还有大搜索结果返回,主要是下面几种情况:
- 针对搜索的命令:find、rg、grep、find、tree、ls -R、ps 等命令:
- 命令返回限制在 8KB,如果超过了就将完整输出保存在磁盘,返回给 llm 超额的错误提示、修正的意见、磁盘文件路径、按 error/warning 关键字提取的关键行、头和尾的预览等等。
- 拦截一些搜索范围很大的命令:如果扫描的目录是
$HOME、/ 或者系统目录(/etc、/var、/usr 这些),会拒绝运行,然后返回给 llm 建议。 - 搜索命令如果没设超时参数或者设得比 300 秒大,则修改参数为300,如果设置比 300 小,则不修改,避免 llm 无脑设置一个很大的超时。
- 针对真的需要查看很多内容的命令:比如 git diff、pnpm build、pytest、sed 等,限制在 30kb,如果超过了就将完整输出保存在磁盘,返回给 llm 磁盘文件路径以及怎么用 read/grep 工具按需读取的建议。
- Pi Coding Agent 的 bash 工具默认限制 50kb 返回,这个未修改。
1 和 2 是利用静态代码去做命令识别,所以只能覆盖常见情况,并且可能有一些误杀的情况,比如确实是得输出这么多,但是被拦截了,llm 还得多次读取,反而增加了开销。还得随着使用次数增多,根据拦截的结果进一步优化静态代码。
此外还有两个额外的功能:
- 只读命令模式:用于 advisor subagent,避免 advisor 执行修改命令,比如写、删、装依赖、联网搜索等。毕竟设计 advisor 的目的是咨询,而不是让 advisor 重新深度调查一次。
- 注入 bash guard 拦截和正确使用 rg、head 等命令的说明,会自动当作用户消息发出去,只会发一次。(这个说明可能不太完善,并且后续看看添加到system prompt是不是会更好点):
1
[BASH OUTPUT DISCIPLINE]\nAn extension guards shell output. Search/listing/dump commands (e.g. `rg`, recursive `grep`, `find`, `ls -R`, `env`, `ps`, `git log`) are capped at 8.0KB; other commands are capped at 30.0KB. Above the cap, the result is replaced with a short preview, the error/warning lines, and a path to the full output. Guarded results are marked `[BASH OUTPUT GUARD]`. Treat it as a nudge to rewrite the command, or to read the file, not as a failure.\n\nBound output before you run:\n- Content search: use the `grep` tool (`limit` caps matches; it respects .gitignore). In bash, `rg -l` lists matching files only, `-c` counts per file, `-m 5` caps matches per file. Never scan a huge tree unbounded.\n- Read files: use the `read` tool with offset/limit. For spot checks use `sed -n '1,80p' <file>` or `head -n 80 <file>` — not `cat`.\n- Logs/lists: `tail -n 50`, `git log --oneline -n 20`, `git diff --stat`, `ls | head`.\n- Aggregate first: `| wc -l`, `| sort | uniq -c`, `-q`/`--quiet`/`-s`. Write big output to a file, then read/grep it selectively.\n\nSearch commands (`find`, recursive `grep`, `rg`, `du`, `tree`) are capped at 5 minutes (300 seconds) automatically; scans rooted at `$HOME`, `/`, or a system directory like `/etc` are blocked before they run. Everything else runs with no timeout guard — pass an explicit `timeout` for anything that can hang (log follow, foreground servers).
plan mode(计划模式)
这个我有两个实现,主要是用第一个实现比较多,也最简单,目前用着还行。其实就是在~/.pi/agent/prompts/discuss.md写入1
2
3
4
5---
description: 先讨论方案与影响,待用户确认后再开始执行修改
argument-hint: "<task>"
---
先讨论,再执行:$@%
比如你在 tui 里面输入/discuss 帮我看看怎么修复这个错误:xxx,其实就等于发先讨论,再执行:帮我看看怎么修复这个错误:xxx。这个我在 flash 模型用着都还行,没有遇到过什么情况,也很简单。
第二种则是类似 Codex 那种,我是通过插件实现的,实现的逻辑:如果使用了/plan,那么就动态注册一个submit_plan工具,并且在 plan 阶段只给使用只读命令和只能写.md文件。
还会给 llm 发送一条消息说,你已经在 plan 模式,你应该怎么做,什么是不能做的:1
"[PLAN MODE]\nYou are in plan mode.\n\nUntil the plan is approved:\n- write/edit may only modify .md/.mdx files inside the working directory (cwd). All other writes are blocked.\n- bash is for read-only exploration. File mutations, redirects, installs, git write operations, sed -i, and tee may be blocked by a best-effort guard.\n- Explore the codebase, then write the complete plan to a markdown file and call submit_plan with its path.\n- The plan must include context, approach, files to modify, implementation steps, and verification.\n- A blocked tool call is not an error to retry: it means plan mode forbids it.\n- If non-markdown changes are needed before approval, ask the user to run /plan to exit plan mode. Do not attempt those writes.\n\nAfter a revision request, update the same plan file and submit it again. After approval, implement the approved plan."
submit_plan的工具效果则是类似这种:
其实就是使用代码弹框给你选择,然后帮你自动发消息给 llm,比如你选择了 revise,就会出现这个:
然后你输入你的反馈,等于发送一条给消息给 llm(只是举例,实际不俗这样):用户对你的计划有修改要求:xxx,请修改计划文件balabala。
如果你选择了 approve,那么就会放开各种命令操作,可以写、修改各种文件了,也会发送一条消息给 llm 说不在 plan 模式了,可以随便改了。
当然你也可以不用注册工具,通过/plan off之类的命令手动关闭 plan 模式,从而放开各种命令操作(目前没实现)。
我觉得这个 plan 模式还挺费劲,真不如我的/discuss🤣。并且/plan最好在开头就使用,因为会注册工具,避免缓存失效,当然注册了后就不会撤消了。
tool token est(输出tool result大概开销)
这个很简单,只是打印一下 tool result 预估占用的上下文而已,使用 openai_o200k_base 标准,差不多是 gpt-4o 那时候的计算方法。纯本地,不会影响上下文。
metrics(打印耗时)
这个也很简单,是我在人家的项目maplezzk-pi-extensions/packages/pi-metrics上修改的,多加了一个当前时间和自开始会话以来占用了多少时间。纯本地,不会影响上下文。
这个也会在流式输出的时候,添加个计时,能看到这一轮跑了多久:
goal 模式
这个还在跑 beta 版本中,目前要用的情况是,让 flash 模型用 Python + graphviz 画状态机的时候,画的图很一般,我是打算让模型多轮修复,一直达到我发给它的效果。
使用 /goal的时候,会注册一个submit_verdict工具,等于是把这次结果写一下,然后插件会写到状态文件,提供给下一轮的 llm 参考(如果对这个结果文件有依赖的话,还得看看如果 llm 不主动调用的话,是不是还得反复提醒一下):
目前想到有三个点:
- 有轮数上限,可以指定,默认是 5 次
- 每一轮都是单独的一轮:
- 所以这一轮的 llm 不会被上一轮的 llm 影响。
- 每一轮完成后都会提交 Git(单独的 goal 分支,不会影响到当前的分支情况),新的一轮查看 git 提交可以知道前面的做了什么。
- 只会记录状态和用户最初的要求到文件中,这种不会影响到 llm 的上下文。
- 每一轮其实就是一次 Pi Coding Agent 的对话,没有主 agent,subagent 什么的,跟你每次重新开对话,然后复制粘贴 prompt 的效果差不多。所以自然也可以用前面那些插件,比如 watchdog,advisor 等,每轮的历史对话也可以在 jsonl 中找到。
我的工作区
沙盒
这个东西首先得看自己的需求是什么,我的需求是:
- 大部分文件是可读的,除了一些特殊的文件,比如 ssh 密钥这些不能泄露的东西。
- 只有当前工作区是可写的,以及一些特殊白名单可写,保证误删最小化。
- 不做极端的防范,因为根据 pi 作者的观点,在本地电脑上的限制 ai 很多都可以绕过去。
我用的是 mba m1,权衡了一下,我选择 macos 自带的沙盒,当然也可以选择 docker,但是我为了开发体验,没有用这个,用本地的工具链方便点。但是我用的是一个 GitHub 项目 enclave,这个项目在 macos 上跑的时候最终也是基于 macos 自带的沙盒,但是多提供了一个功能 unboxexec_allowed_commands,等于写在里面的命令,都不走沙盒,适用于一些特别的工具,需要权限多,仅靠沙盒的规则满足不了放行的需求,或者是配置起来特别繁琐。
可以看作者的文章:claude-sandbox: Yet another sandboxing tool for Claude Code on macOS - DEV Community
具体我的配置 ~/.config/enclave/config.toml 是1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66sandbox_profile = '''
(version 1)
(allow default)
(deny file-read*
(subpath "/Users/jooooody/.ssh")
(subpath "/Users/jooooody/.gnupg")
(subpath "/Users/jooooody/Library/Keychains")
(subpath "/Users/jooooody/.aws")
(subpath "/Users/jooooody/.azure")
(subpath "/Users/jooooody/.config/gcloud")
(subpath "/Users/jooooody/.kube")
(subpath "/Users/jooooody/.docker/config.json")
(subpath "/Users/jooooody/.config/gh")
(literal "/Users/jooooody/.git-credentials")
(literal "/Users/jooooody/.netrc")
(literal "/Users/jooooody/.npmrc")
(literal "/Users/jooooody/.pypirc")
(literal "/Users/jooooody/.cargo/credentials")
(literal "/Users/jooooody/.cargo/credentials.toml")
(literal "/Users/jooooody/.gem/credentials")
(subpath "/Users/jooooody/.pip/pip.conf")
(subpath "/Users/jooooody/.config/openai")
(subpath "/Users/jooooody/.anthropic")
(literal "/Users/jooooody/.zsh_history")
(literal "/Users/jooooody/.bash_history")
(literal "/Users/jooooody/.python_history")
(literal "/Users/jooooody/.node_repl_history")
(literal "/Users/jooooody/.mysql_history")
(literal "/Users/jooooody/.psql_history")
)
(deny file-write*)
(allow file-write*
(literal "/Users/jooooody/.tmux.conf")
(literal "/Users/jooooody/.zshrc")
(subpath (param "WORKDIR"))
(subpath "/tmp")
(subpath "/private/tmp")
(subpath "/Users/jooooody/Library/Caches")
(subpath "/var/folders")
(subpath "/private/var/folders")
(subpath "/Users/jooooody/.pi/")
(subpath "/Users/jooooody/.npm")
(subpath "/Users/jooooody/Library/pnpm/")
(literal "/dev/null")
(literal "/dev/stdout")
(literal "/dev/stderr")
(literal "/dev/dtracehelper")
(literal "/dev/ptmx")
(regex #"^/dev/tty*")
)
'''
unboxexec_allowed_commands = [
"^playwright-cli",
"^mmdc",
"^git",
"^/bin/ps"
]
这套规则能跑,但不是很完美,可能有些地方还是会被误限制,或者某些地方能泄露什么东西,如果有发现漏洞麻烦发一下,我更完善一下。🫡
kitty+tmux
我之前使用 Codex 或者 Claude code 的时候,用的是 cli,编排用的是 ensoai,效果是下面这种:
主要是三个区域:
- 左边第一个区域负责管理多个项目和多个 Git worktree 分支,这样就能快速在不同的项目和不同的 git worktree 上并行开发。
- 中间第二个区域则是 agent 区域,代表着不同的项目不同的 worktree 可以启动多个不同的 agent,包括 codex,claude code,pi 等等,方便同时跑多个 agent 完成不同的任务。
- 右边第三个区域则是用浏览器或者别的东西快速打开当前目录,比如我经常用 vscode 打开后查看、跳转、调试代码和管理 Git。
后来我发现在 kitty 的渲染效果会比在 ensoai 好很多,并且 Pi Coding Agent 在 ensoai 的渲染好像有时候有点问题,不太记得是什么问题了,有可能是得改 Pi Coding Agent 的什么配置才行。总之就是想在 kitty 使用 cli,之前在 ensoai 使用 codex 也是凑合用,倒是没啥问题。现在使用了 Pi Coding Agent,正好有这个契机了迁移到 kitty(省流:折腾心犯了😅)。
根据之前的习惯,还是想把功能拆分为多工作区多 wortktree 多 agent 的方案,同时配一下快速打开 vscode 的功能。
目前实现的效果如下,很多代码属于耦合在一起的状态,包括耦合了我的自己实现的插件,因为得获取状态。只是能跑起来阶段,但是在 Pi Coding Agent 跑起来是没有问题,也许会有些状态同步的小 bug。后续我想先搞这套方案支持配置 ssh,然后看心情支持 codex 和 cc,毕竟那两个如果我要用我可以先凑合回到 ensoai。
ssh 的功能对我来说比较关键,因为现在经常要挂着 agent 跑,电脑又只能一直开着,而且我又是经常移动电脑,所以不太方便,如果有vps就方便多了。但是前提是得先把本地电脑这一套搞好,然后再支持一下配置到 ssh。
- 圆圈 1 的部分则是 kitty 自带的功能,多个 tab,代表不同的工作区。
- 按快捷键 alt+数字键 / 鼠标点击可以快速切换,alt+t 可以创建一个 tab,alt+w 可以关闭当前 tab。
- 每个 tab 名字固定是当前项目的名字。
- 名字前面还有
⌛️1、✅1的图标,代表有多少个 Pi Coding Agent 正在工作(比如在请求,执行 tool 等等,空闲不显示),如果是完成了但是还没有查看,则是显示的完成 emoji。比如3个正在运行,2个待查看,则显示两个emoji:⌛️3✅2。
- 圆圈 2 则是跑的 Pi Coding Agent,跑在 byobu 上(基于 tmux),这里不使用任何分屏,所以只会显示一个 Pi Coding Agent,当然也可以分屏,用 kitty 或者 tmux 自带的应该,就是状态显示不知道有没有问题,因为我的是 mba,屏幕小,所以没有分屏习惯。
- 圆圈 3 则是 byobu 的状态栏,当前图片显示有三个程序已经启动了
- tab 命名的规则是命令行名字@分支名字,也就是启动的cli 名字 @ 当前 Git 分支或者 worktree 名字。如果当前项目不是 git 项目,那么就没有@分支名字。
- ctrl+b+数字键 / 鼠标点击可以切换 tab,ctrl+b+c 可以创建一个新的 tab,新 tab 的目录是执行快捷键的 tab 对应的目录。
- 同样也有 emoji,代表正在执行Pi Coding Agent,还是 Pi Coding Agent 完成了待查看。
设计了一个快捷键 ctrl+b+p 启动一个悬浮窗口,可以管理所有 Pi Coding Agent 的窗口。
- 圆圈 1:是哪个工作区,tmux 的会话名是什么
- 圆圈 2: 具体每个 tmux tab 的情况
- 圆圈 3: 这种一般是 subagent,因为没有 kitty tab 对应,也没有 tmux 关联(subagent用的是专属 tmux socket)。如果有 tmux,但是不小心关闭了 kitty tab,点击后可以自动创建一个 kitty tab 打开。
通知我则是用的 kitty 自带的通知,如果哪个完成了,macos 的程序栏的 kitty 会有状态变更,并且你不点击的话,会时不时跳一下。应该是可以触发声音,不过我还没有怎么用过,我看 kitty 可以配置通知要不要开声音。
然后点击进去还有个🔔的状态,代表这个工作区的 Pi Coding Agent 完成了,发出来的通知,然后根据完成状态可以定位到是哪个 Pi Coding Agent。
其他
- 查看所有历史记录:
Dwsy/pi-session-manager。 - 查看实际上发送的请求内容:本地部署一个
bestruirui/octopus网关。 - 按上下键快速选择上次发送的内容:
oipsanthony/pi-command-history,不知道新版本是不是自带了这个功能 - 上下文占用查看:
diegopetrucci/pi-context-inspector - 添加模型和自动拉取模型的信息:
palmtom/pi-models - 使用 gpt 模型,修改一下请求的 header 为 codex,不知道修改有没有什么作用:
rays1d/pi-custom-header - 本地计算发送第一条 system 消息的时候,上下文是多少,哪些工具占用了:
npm:pi-token-burden



















