@tt-a1i/openpi 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +102 -40
  2. package/SETUP.md +22 -6
  3. package/assets/openpi-launch-card-v1.webp +0 -0
  4. package/bin/openpi.js +145 -0
  5. package/extensions/background-terminals/index.ts +30 -2
  6. package/extensions/background-terminals/src/domain.ts +2 -0
  7. package/extensions/background-terminals/src/manager.ts +486 -106
  8. package/extensions/background-terminals/src/output.ts +33 -0
  9. package/extensions/background-terminals/src/prompt.ts +13 -5
  10. package/extensions/background-terminals/src/result-delivery.ts +4 -1
  11. package/extensions/clear-context/index.ts +83 -0
  12. package/extensions/context-pivot/index.ts +16 -6
  13. package/extensions/cron/schedule.ts +7 -1
  14. package/extensions/file-mutation-display/render.ts +17 -257
  15. package/extensions/file-search/src/binaries.ts +57 -41
  16. package/extensions/git-read/index.ts +1 -3
  17. package/extensions/model-info/index.ts +21 -33
  18. package/extensions/model-info/session-metrics.ts +96 -0
  19. package/extensions/plan-mode/bash-policy.ts +54 -9
  20. package/extensions/plan-mode/index.ts +7 -2
  21. package/extensions/post-edit/index.ts +16 -6
  22. package/extensions/sessions/git-stats.ts +258 -72
  23. package/extensions/sessions/index.ts +153 -86
  24. package/extensions/sessions/preview-cache.ts +104 -0
  25. package/extensions/sessions/preview-loader.ts +856 -0
  26. package/extensions/sessions/sessions.ts +43 -4
  27. package/extensions/setup/index.ts +123 -127
  28. package/extensions/shared/activity-status.ts +30 -0
  29. package/extensions/shared/agent-session-page.ts +319 -0
  30. package/extensions/shared/agent-tool-renderer.ts +218 -0
  31. package/extensions/shared/agent-transcript.ts +524 -0
  32. package/extensions/shared/capability-intent.ts +1 -1
  33. package/extensions/shared/child-session.ts +437 -21
  34. package/extensions/shared/result-delivery.ts +34 -0
  35. package/extensions/shared/setup-config.ts +73 -33
  36. package/extensions/shared/setup-episode-state.ts +1 -1
  37. package/extensions/shared/terminal-text.ts +110 -23
  38. package/extensions/shared/text-projection.ts +72 -15
  39. package/extensions/shared/tool-activity.ts +382 -0
  40. package/extensions/shared/tool-surface.ts +29 -2
  41. package/extensions/shared/transcript-viewport.ts +46 -0
  42. package/extensions/shared/web-observer-registry.ts +390 -0
  43. package/extensions/shared/worktree.ts +11 -0
  44. package/extensions/subagents/index.ts +270 -59
  45. package/extensions/subagents/navigation.ts +34 -5
  46. package/extensions/subagents/src/backend.ts +12 -1
  47. package/extensions/subagents/src/backends/pi.ts +375 -66
  48. package/extensions/subagents/src/domain.ts +5 -0
  49. package/extensions/subagents/src/manager.ts +34 -2
  50. package/extensions/subagents/src/prompt.ts +32 -4
  51. package/extensions/subagents/src/result-artifact.ts +4 -0
  52. package/extensions/subagents/src/result-delivery.ts +7 -1
  53. package/extensions/subagents/src/runtime.ts +15 -1
  54. package/extensions/subagents/src/ui/takeover.ts +73 -257
  55. package/extensions/subagents/src/ui/transcript.ts +38 -535
  56. package/extensions/subagents/src/ui/wait-result.ts +103 -15
  57. package/extensions/suggestions/src/ui.ts +10 -4
  58. package/extensions/tasks/index.ts +0 -3
  59. package/extensions/ui-customization/footer.ts +0 -40
  60. package/extensions/ui-customization/index.ts +0 -4
  61. package/extensions/user-input-fold/index.ts +1 -1
  62. package/extensions/web/index.ts +234 -0
  63. package/extensions/workflows/artifacts.ts +137 -47
  64. package/extensions/workflows/completion-projection.ts +457 -0
  65. package/extensions/workflows/coordinator.ts +8 -10
  66. package/extensions/workflows/dashboard.ts +167 -228
  67. package/extensions/workflows/handoff.ts +70 -16
  68. package/extensions/workflows/index.ts +488 -198
  69. package/extensions/workflows/journal.ts +148 -13
  70. package/extensions/workflows/model.ts +74 -4
  71. package/extensions/workflows/navigation.ts +32 -8
  72. package/extensions/workflows/progress-projection.ts +306 -0
  73. package/extensions/workflows/prompt.ts +66 -6
  74. package/extensions/workflows/replay-safety.ts +42 -21
  75. package/extensions/workflows/result-delivery.ts +128 -64
  76. package/extensions/workflows/retention.ts +593 -0
  77. package/extensions/workflows/runner.ts +388 -279
  78. package/extensions/workflows/sandbox-child.cjs +25 -3
  79. package/extensions/workflows/sandbox.ts +62 -8
  80. package/extensions/workflows/serialization.ts +325 -17
  81. package/extensions/workflows/tool-renderer.ts +22 -0
  82. package/extensions/workflows/transcript.ts +149 -0
  83. package/extensions/workspace-cleanup-guard/index.ts +54 -0
  84. package/extensions/workspace-cleanup-guard/workspace-provenance.ts +563 -0
  85. package/package.json +28 -8
  86. package/skills/subagents/REFERENCE.md +189 -0
  87. package/skills/subagents/SKILL.md +1 -1
  88. package/skills/workflows/REFERENCE.md +4 -2
  89. package/web/adapter/pi-adapter.ts +661 -0
  90. package/web/host/browser-launcher.ts +20 -0
  91. package/web/host/static-assets.ts +4 -0
  92. package/web/host/terminal-status.ts +38 -0
  93. package/web/host/web-host.ts +789 -0
  94. package/web/http-dispatcher.ts +125 -0
  95. package/web/protocol/types.ts +462 -0
  96. package/web/runtime/pi-runtime.ts +991 -0
  97. package/web/runtime/types.ts +71 -0
  98. package/web/runtime/web-host-lease.ts +497 -0
  99. package/web/trace.ts +18 -0
  100. package/web/ui/app.js +1398 -0
  101. package/web/ui/index.html +139 -0
  102. package/web/ui/styles.css +598 -0
  103. package/web/vite.config.mjs +34 -0
  104. package/extensions/execution-convergence/active-evidence.ts +0 -129
  105. package/extensions/execution-convergence/index.ts +0 -442
  106. package/extensions/execution-convergence/workspace-provenance.ts +0 -338
  107. package/extensions/setup/intercom-fs-helper.cjs +0 -130
  108. package/extensions/setup/intercom.ts +0 -603
  109. package/extensions/subagents/src/backends/stub.ts +0 -303
package/README.md CHANGED
@@ -1,36 +1,40 @@
1
1
  <p align="center">
2
- <img src="assets/openpi-package.png" alt="OpenPI logo" width="240" />
2
+ <img src="assets/openpi-launch-card-v1.webp" alt="OpenPI — Pi at the core, power on demand. Small Harness. Clean Context. Deep Extensions." width="100%" />
3
3
  </p>
4
4
 
5
- <h1 align="center">OpenPI</h1>
5
+ <p align="center">
6
+ 把后台 Terminal、Pi-native Subagent、可恢复 Workflow 与持续任务装进同一套 <a href="https://pi.dev">Pi</a> 工作台。<br />
7
+ 普通回合零常驻 OpenPI 模型工具;明确需要时,才展开对应能力。
8
+ </p>
6
9
 
7
10
  <p align="center">
8
- <strong>Pi at the core. Power on demand.</strong>
11
+ <strong>Small Harness.</strong> 不替换 Pi Agent loop,普通回合不常驻 OpenPI 模型工具。<br />
12
+ <strong>Clean Context.</strong> 能力按需加载,Subagent 使用独立 Context,不把所有工作塞进主会话。<br />
13
+ <strong>Deep Extensions.</strong> 后台执行、Subagent、Workflow 与持续任务在 Pi 原生生命周期内统一运行和观察。
9
14
  </p>
10
15
 
11
16
  <p align="center">
12
- 默认像 <a href="https://pi.dev">Pi</a> 一样轻;任务需要时,一句话展开后台执行、隔离 Subagent、可恢复 Workflow 与持续任务。<br />
13
- 不替换 Pi,不重写 Agent loop,不让高级能力长期占据每一次对话。
17
+ <strong>不是把一组插件摆在一起,而是让它们共享同一套配置、权限、状态与清理边界。</strong>
14
18
  </p>
15
19
 
16
20
  <p align="center">
17
21
  <a href="https://www.npmjs.com/package/@tt-a1i/openpi"><img alt="npm version" src="https://img.shields.io/npm/v/@tt-a1i/openpi?style=flat-square&color=cb3837"></a>
18
- <a href="https://github.com/tt-a1i/openpi/actions/workflows/ci.yml"><img alt="CI status" src="https://github.com/tt-a1i/openpi/actions/workflows/ci.yml/badge.svg"></a>
22
+ <a href="https://github.com/openpi-dev/openpi/actions/workflows/ci.yml"><img alt="CI status" src="https://github.com/openpi-dev/openpi/actions/workflows/ci.yml/badge.svg"></a>
19
23
  <a href="https://github.com/earendil-works/pi-mono"><img alt="Pi 0.84.1+" src="https://img.shields.io/badge/Pi-0.84.1%2B-2f81f7?style=flat-square"></a>
20
24
  <img alt="Node.js 22.19+" src="https://img.shields.io/badge/Node.js-22.19%2B-3fb950?style=flat-square&logo=nodedotjs&logoColor=white">
21
25
  <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-3fb950?style=flat-square"></a>
22
26
  </p>
23
27
 
28
+ ```bash
29
+ pi install npm:@tt-a1i/openpi
30
+ ```
31
+
24
32
  <p align="center">
25
- <a href="#30-秒开始"><strong>30 秒开始</strong></a> ·
26
- <a href="#默认轻按需强">设计</a> ·
27
- <a href="#openpi-解决什么">解决什么</a> ·
28
- <a href="#能力地图">能力地图</a> ·
29
- <a href="#运行模型">运行模型</a> ·
30
- <a href="#三条执行路径">执行路径</a> ·
31
- <a href="#workflow-不只是并行">Workflow</a> ·
32
- <a href="#安全边界">安全边界</a> ·
33
- <a href="#配置与参考">配置与参考</a>
33
+ <a href="https://openpi-dev.github.io/openpi/"><strong>项目网站</strong></a> ·
34
+ <a href="#30-秒开始"><strong>立即开始</strong></a> ·
35
+ <a href="#默认轻按需强">为什么默认更轻</a> ·
36
+ <a href="#运行模型">看看它怎么工作</a> ·
37
+ <a href="https://github.com/openpi-dev/openpi/issues/22">查看 Benchmark</a>
34
38
  </p>
35
39
 
36
40
  <p align="center">
@@ -77,10 +81,15 @@ OpenPI 会把长期进程放到后台,把独立任务交给隔离 Context 的
77
81
 
78
82
  > [!TIP]
79
83
  > Capability discovery 默认 `explicit`:明确说出能力意图才会加载对应组。英文 `subagent` 与 `workflow` 是保留授权词,单独输入也会加载对应能力。
80
- > 例如 `subagent, workflow` → 同时加载两组;「在后台运行 dev server」→ 后台终端;「用/使用子代理检查」→ Subagent;「用工作流编排」→ Workflow;「用 fd/rg 搜索」或「用 git diff 比较分支」→ 搜索与只读 Git 工具。
81
- > 关键是把意图说清楚(说「用子代理」「后台运行」这类带动作的短语),不需要记住任何工具名。
84
+ > 例如 `subagent, workflow` → 同时加载两组;「在后台运行 dev server」→ 后台终端;「用/使用子代理检查」或句首「子代理了解下项目」→ Subagent;「用工作流编排」→ Workflow;「用 fd/rg 搜索」或「用 git diff 比较分支」→ 搜索与只读 Git 工具。
85
+ > 关键是把意图说清楚(说「用子代理」「子代理检查项目」「后台运行」这类带执行动作的短语),不需要记住任何工具名。仅讨论能力的「子代理是什么」不会加载;否定或条件表达也继续 fail closed。
86
+ > `/plan` 是一个运行时安全例外:进入或恢复 Plan Mode 时会为当前 Session 自动加载 `search` 组,让只读调研直接使用结构化 Git 工具。
82
87
  > 在交互输入框中,保留词 `Subagent` / `Workflow`,以及已被识别的中文能力请求,会使用 Claude Code 风格的薰衣草紫显示;浅色终端自动使用更深的紫色以维持可读性。变色表示提交后会加载对应能力。因为英文名称本身就是授权词,讨论中写出它们也会开闸;条件句和否定句仍保持普通显示,Suggestion 幽灵文字也要在用户接受进输入框后才参与识别。
83
88
 
89
+ Skill 使用 Pi 原生机制:模型根据名称、描述和路径按需用 `read` 读取;用户明确调用时,在输入开头使用 `/skill:code-review 审查这个 PR`(前提是 Pi 已加载该 Skill)。候选补全、正文展开和运行中追加输入均由 Pi 处理。OpenPI 不提供专门的 `$skill` 语法或独立的 Skill 加载通道。
90
+
91
+ Skill 正文通过原生用户消息或工具结果进入正常 Session 历史,压缩也交给 Pi。OpenPI 不另存正文快照,不叠加隐藏正文,也不在压缩后自动补回。压缩后不保证全文仍在模型上下文中;需要时可重新读取或显式调用。普通 `read` 的输出限制和模型总上下文限制仍然适用。设计边界见 [Decision 0002](docs/decisions/0002-native-skill-lifecycle.md)。
92
+
84
93
  > [!IMPORTANT]
85
94
  > 默认安装是安静的:不改主题、不绑定 Provider 或模型、不开启下一步预测,也不执行 post-edit 命令。Capability discovery 默认 `explicit`;只有用户通过 `/openpi-setup` 选择 `adaptive` 后,模型才会常驻看到一个小型发现网关并可自主加载额外能力。
86
95
 
@@ -120,7 +129,6 @@ OpenPI 把成熟 Coding Agent 的工作习惯做成 Pi-native 能力,但不复
120
129
  | 终端工作台 | 自定义 Footer 与任务栏、运行状态、紧凑 Tool Result、Next-action Suggestion、Git / PR 信号 |
121
130
  | 快捷工作流 | `/btw` 旁路提问(TUI)、`/lg` 浏览 Diff(TUI)、`/pr` 查 PR、`/copy-all`、`fd`、`rg`、只读 Git 工具 |
122
131
  | 人类决策 | `ask_user` 草稿与最终复核、parent-only `human_handoff`、Plan Ready 实施门禁 |
123
- | 跨 Session | 可选 parent-only `pi-intercom`;父子通信仍走 Subagent / Workflow 原生通道 |
124
132
  | 统一配置 | `/openpi-setup` 管理 OpenPI 自有模型、并发、Footer、输出密度与 Post-edit 偏好 |
125
133
 
126
134
  OpenPI 采用 [MIT License](LICENSE);第三方来源与保留声明见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
@@ -147,7 +155,7 @@ OpenPI 采用 [MIT License](LICENSE);第三方来源与保留声明见 [THIRD_
147
155
  跨回合工作项 → Tasks
148
156
  持续自主目标 → Goal
149
157
  同一 Session 的阶段切换 → Context Pivot
150
- 真正跨顶层 Session → pi-intercom(可选)
158
+ 真正跨顶层 Session → 独立 pi-intercom package(按需安装)
151
159
  ```
152
160
 
153
161
  ---
@@ -266,7 +274,7 @@ return agent("Synthesize the verified findings", {
266
274
  | `pipeline()` | 每个 item 完成上阶段后立即进入下一阶段;多阶段 fan-out 的默认选择 |
267
275
  | `parallel()` | 并发 barrier;只在下一阶段确实需要全部结果时使用 |
268
276
 
269
- Workflow 默认并发 8 个 Agent,单次最多 128 次调用;可配置到 64 和 1024。前台运行可实时查看,后台运行完成后自动回传;`/workflows` 展示阶段、Agent、Transcript、Graph、用量与产物。
277
+ Workflow 默认并发 8 个 Agent,单次最多 128 次调用;可配置到 64 和 1024。前台运行可实时查看,后台运行完成后自动回传;`/workflows` 展示阶段、Agent、Transcript、Graph、用量与产物。每个 Child Provider turn 必须在 45 秒内产生模型可见的 thinking、text、tool call 或完成事件,并在持续输出时按进展续期;空 stream start 与 transport heartbeat 不算进展。用户显式配置了更宽的 Pi `httpIdleTimeoutMs` 时沿用该上限。超时会 abort 当前 Child、保留已有 Transcript/usage/evidence,并让 sibling 与后续阶段继续结算。
270
278
 
271
279
  ---
272
280
 
@@ -302,13 +310,29 @@ OpenPI 把一次调用拆成可以审计的生命周期,而不是把“进程
302
310
 
303
311
  ### Explicit Acceptance
304
312
 
305
- 可选 `acceptance: { criteria: [...] }` 要求同一个 Agent 返回 evidence ledger。条件缺失、格式错误或被拒绝时,调用返回 `ok: false`,但原始输出与 ledger 仍保留。OpenPI 不会暗中再启动 reviewer、Shell 或额外 Judge 模型。
313
+ 可选 `acceptance: { criteria: [...] }` 要求同一个 Agent 返回 evidence ledger。支持 1–32 条验收条件;`description` 为人类可读说明(1–500 字符),可选的 `requiredEvidence` 为字符串数组(至多 16 个标签,每项至多 120 字符),子 Agent 必须在 `acceptance.criteria[].evidence` 中返回完全匹配的标签:
314
+
315
+ ```js
316
+ acceptance: {
317
+ criteria: [
318
+ {
319
+ id: "tests",
320
+ description: "Focused tests pass.",
321
+ requiredEvidence: ["test-command"],
322
+ },
323
+ ],
324
+ }
325
+ ```
326
+
327
+ 条件缺失、格式错误或被拒绝时,调用返回 `ok: false`,但原始输出与 ledger 仍保留。OpenPI 不会暗中再启动 reviewer、Shell 或额外 Judge 模型。
328
+
329
+ 未设置 `requiredEvidence` 的 criterion 是对 `description` 的自我声明,不是有证据约束的验收门禁;需要 evidence-backed gate 时,必须声明所需证据标签。
306
330
 
307
331
  ### Worktree Handoff
308
332
 
309
333
  Workflow 在清理隔离 checkout 前原子保存有界 Handoff Manifest:tracked binary patch、stat、branch/HEAD、untracked/ignored 清单与 cleanup receipt。状态不明就保留现场,不自动 merge、apply 或强删。
310
334
 
311
- 设计细节见 [`docs/design/WORKFLOW_INVOCATION_GRAPH.md`](docs/design/WORKFLOW_INVOCATION_GRAPH.md)。
335
+ 设计细节见 [Workflow invocation graph](https://github.com/openpi-dev/openpi/blob/main/docs/design/WORKFLOW_INVOCATION_GRAPH.md)。
312
336
 
313
337
  ---
314
338
 
@@ -318,7 +342,7 @@ Workflow 在清理隔离 checkout 前原子保存有界 Handoff Manifest:track
318
342
  | ------------- | --------------------------------------- | ------------------------------------------------------------------- |
319
343
  | Tasks | `tasks_add` / `tasks_update` / `/tasks` | 逐项同步当前批次工作意图并刷新完整快照;不推断完成、不执行工作 |
320
344
  | Goal | `/goal <目标>` | 驱动一个持续到终态的自主目标;完成前要求证据审计 |
321
- | Plan Mode | `/plan [目标]` | 只读调研;`plan_ready` 后才准备可编辑的实施 Prompt,不自动执行 |
345
+ | Plan Mode | `/plan [目标]` | 自动加载结构化搜索/Git 做只读调研;`plan_ready` 后才准备实施 Prompt |
322
346
  | Context Pivot | `/context-pivot <下一阶段>` | Context 超过约 30K Tokens 且任务换阶段时,用自包含 Brief 替换旧噪音 |
323
347
  | Sessions | `/sessions` | 搜索、预览并通过 Pi 安全生命周期切换 Session |
324
348
  | Human Input | `ask_user` / `human_handoff` | 收集经复核的决策,或等待只有用户能完成的外部操作 |
@@ -342,8 +366,8 @@ Footer 使用一套 Codicon 线性图标:`` 模型、`` context、``
342
366
  - 默认把高频的模型与 context 放在最左侧,把项目定位信息归到右侧,并以当前目录作为最右锚点;支持 `powerline`、`powerline-mono`、`compact`,也支持自定义多行布局;
343
367
  - 终端变窄时按优先级隐藏次要指标,不机械截断尾部;
344
368
  - Subagent 与 Workflow 活动时自动出现,空闲时不占空间;
345
- - Bash、Write/Edit 与 Subagent 结果可独立选择 `full` 或 `compact`;普通 `read`、`grep`、`find`、`ls` 以及 compact Bash/Write/Edit 默认显示一行语义活动摘要,包含目标、状态与关键规模;Nerd Font 可为读取、终端、编辑、搜索和目录动作显示 Codex 风格线框图标,未安装时动词与全部信息仍保持可读;
346
- - 折叠内容用 Pi 的 `app.tools.expand` 快捷键临时展开(默认 `Ctrl+O`),展开后直接恢复 Pi 原生参数、输出、错误、diff、耗时与 full-output 证据;
369
+ - Bash、Write/Edit 与 Subagent 结果可独立选择 `full` 或 `compact`,默认均为 `compact`;普通 `read`、`grep`、`find`、`ls` 以及 compact Bash/Write/Edit 默认显示一行语义活动摘要,包含目标、状态与关键规模;Nerd Font 可为读取、终端、编辑、搜索和目录动作显示 Codex 风格线框图标,未安装时动词与全部信息仍保持可读;
370
+ - 折叠内容用 Pi 的 `app.tools.expand` 快捷键临时展开(默认 `Ctrl+O`),展开后直接恢复 Pi 原生参数、输出、错误、diff、耗时与 full-output 证据;进入 Direct Subagent 或 Workflow child 详情页时会继承父会话的当前展开状态,详情页内切换只影响该页,不改变父会话;
347
371
  - Git 状态本地刷新;只有显式运行 `/pr` 才查询 GitHub PR。
348
372
 
349
373
  `fd` 与 `rg` 是结构化模型工具,不拼接 Shell。它们默认遵守 `.gitignore`,支持 Glob、类型、Smart Case、固定字符串与上下文。`git_show`、`git_diff`、`git_log` 以结构化参数提供只读提交、差异和历史检查,并禁用仓库配置的 external diff/textconv。两类工具的输出均限制为 50 KiB / 2000 行,完整截断内容最多私有保存 10 MiB,并在 Session Shutdown 时清理。
@@ -369,7 +393,7 @@ macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下
369
393
  | 用户配置 | 单一受限 typed tool 写入;不散落扩展私有配置入口 |
370
394
  | 模型消费 | Suggestion 默认关闭;adaptive 仅在显式开启后允许模型自主加载能力 |
371
395
 
372
- 可选的 [pi-intercom](https://github.com/nicobailon/pi-intercom) 只在顶层 Pi Session 加载。它使用进程级身份,而 OpenPI Child 是同一进程内的并发 Session;Child Resource Loader 会移除 pi-intercom 扩展与 Skill,避免身份串线。Replay 也不会复用其调用。
396
+ 独立的 [pi-intercom](https://github.com/nicobailon/pi-intercom) package 只适合顶层 Pi Session。它使用进程级身份,而 OpenPI Child 是同一进程内的并发 Session;Child Resource Loader 会从 npm、Git 和 local package source 中精确移除 pi-intercom 扩展与 Skill,避免身份串线,同时保留普通同名项目资源。Replay 也不会复用其调用。
373
397
 
374
398
  ---
375
399
 
@@ -384,6 +408,8 @@ macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下
384
408
 
385
409
  无参数时,OpenPI 展示当前状态并引导修改;带自然语言时只改指定项:
386
410
 
411
+ <!-- config-contract: capabilities.discovery suggestions.enabled suggestions.model workflows.concurrency workflows.maxAgentCalls ui.showHeader ui.customFooter ui.footerStyle ui.footerLines ui.subagentResultDisplay ui.bashToolDisplay ui.fileMutationDisplay postEdit.command subagents.roleModels -->
412
+
387
413
  ```text
388
414
  /openpi-setup 开启下一步预测,选择 Registry 里的轻量模型,minimal 推理
389
415
  /openpi-setup 让模型在合适时自主发现并采用 OpenPI 能力
@@ -396,7 +422,9 @@ macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下
396
422
 
397
423
  配置保存在 `~/.pi/agent/my-pi-setup.json`,与包代码分离,升级不会覆盖。
398
424
 
399
- 一次 `/openpi-setup` episode 最多成功写入一次;成功后配置工具立即隐藏。若随后还要修改另一项,请重新执行 `/openpi-setup <自然语言请求>`,不要让模型重调已隐藏工具,也不要绕过入口直接编辑配置文件。
425
+ Footer 布局以 `footerLines` 作为唯一持久化格式。旧版 `footerItems` 会在读取时迁移,但迁移后的配置不保证能被旧版 OpenPI 正确解释,因此不承诺配置文件的降级兼容性。
426
+
427
+ 一次 `/openpi-setup` episode 最多成功写入一次;成功后配置工具立即隐藏。若本轮没有成功写入,Runtime 会追加一条可见、持久且进入后续模型上下文的关闭凭据,明确 writer 已隐藏,后续修改必须重新执行 `/openpi-setup <自然语言请求>`。writer 只有在 OpenPI 能验证当前激活的是包自身定义时才可用;重复或来源不匹配会显式 fail closed,不会发布假的 setup-active 状态。不要让模型重调已隐藏工具,也不要绕过入口直接编辑配置文件。
400
428
 
401
429
  <details>
402
430
  <summary><strong>默认值</strong></summary>
@@ -408,10 +436,9 @@ macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下
408
436
  | Workflow 并发 / 总调用 | 8 / 128;硬上限 64 / 1024 |
409
437
  | 大型 Header | 关闭 |
410
438
  | Dashboard Footer | 开启;单行 `plain` |
411
- | Subagent / Bash / Write/Edit | `full` / `compact` / `compact` |
439
+ | Subagent / Bash / Write/Edit | `compact` / `compact` / `compact` |
412
440
  | Post-edit 命令 | 关闭;单条命令最多 500 字符 |
413
441
  | 内置角色模型 | 全部继承父模型 |
414
- | pi-intercom | 不静默安装;由用户明确选择 |
415
442
  | 主题 | 保留用户现有选择 |
416
443
 
417
444
  </details>
@@ -421,7 +448,7 @@ macOS/Linux arm64 与 x64 缺少二进制时,OpenPI 会从官方 Release 下
421
448
  - Pi `0.84.1` 或更新版本;
422
449
  - Node.js `22.19.0` 或更新版本;
423
450
  - npm 安装:`pi install npm:@tt-a1i/openpi`;
424
- - GitHub 安装:`pi install git:github.com/tt-a1i/openpi`。
451
+ - GitHub 安装:`pi install git:github.com/openpi-dev/openpi`。
425
452
 
426
453
  #### 开发运行时:区分 npm 与当前源码
427
454
 
@@ -440,7 +467,7 @@ pi list
440
467
  **2. 开发时让 Pi 直接加载当前 checkout**
441
468
 
442
469
  ```bash
443
- git clone https://github.com/tt-a1i/openpi.git ~/work/openpi
470
+ git clone https://github.com/openpi-dev/openpi.git ~/work/openpi
444
471
  cd ~/work/openpi
445
472
  bun install --frozen-lockfile
446
473
 
@@ -486,21 +513,45 @@ bun run test
486
513
 
487
514
  Host SDK 与 TypeBox 按 Pi Package 契约声明为 Peer Dependencies;仓库开发依赖不随包重复提供。
488
515
 
489
- ### 可选:顶层 Pi Session 通信
516
+ ### 独立可选:顶层 Pi Session 通信
490
517
 
491
- 运行 `/openpi-setup`,在原生确认框中选择安装;也可手动执行:
518
+ [pi-intercom](https://github.com/nicobailon/pi-intercom) 是独立维护的 Pi package。OpenPI 不探测、推荐、安装或配置它;需要跨顶层 Session 通信时,请先审查其独立仓库,再通过 Pi 原生 package 命令按需安装:
492
519
 
493
520
  ```bash
494
521
  pi install npm:pi-intercom
495
522
  ```
496
523
 
497
- 新私有配置默认 `confirmSend: true`、`inboundTrigger: "replies"`;已有配置绝不重写。安装失败不显示成功,也不写配置;安装后需 `/reload`。跨顶层 Session pi-intercom,父子委派继续使用 `subagent_*` 与 Workflow 原生结果通道。
524
+ 安装、配置和升级均由 Pi pi-intercom 自身负责;OpenPI 不写入或迁移已有 intercom 偏好。跨顶层 Session 可使用 pi-intercom,OpenPI 父子委派继续使用 `subagent_*` 与 Workflow 原生结果通道。
525
+
526
+ ### 独立 Web 工作台
527
+
528
+ Web runtime 不嵌入交互式终端 Session。它由独立进程创建自己的 Pi `AgentSessionRuntime`、独立 `~/.pi/agent/web-sessions` 持久化目录和生命周期;浏览器发送消息、新建 Session 或切换工作区,不会写入或切换任何已经运行的终端 Pi Session,Web Session 也不会出现在终端的默认 Session 列表中。在侧栏选择 Session 会把它激活为 Web 进程的当前 Pi Session;Prompt 只会投递到请求时仍匹配的活动 Web Session。独立的只读历史浏览不属于首版范围。
529
+
530
+ 同一 Pi agent 目录一次只允许一个 Web Host 持有该 Session/元数据目录。第二个 `openpi web` 会明确拒绝启动;正常关停会先排空共享目录变更再释放租约,进程崩溃后仅在确认原 owner 的 PID 与进程启动身份不再匹配时恢复。一个 Host 可在侧栏管理多个工作区,因此不需要为每个仓库启动一个进程。
531
+
532
+ Host 仅监听 loopback。启动链接中的高熵 token 属于本次 Web Host 进程,浏览器会从 URL fragment 取出后保存到当前标签页的 `sessionStorage`,并立即清除地址栏 fragment;关闭 Host 后该 token 失效。这不是远程身份或长期登录机制。
533
+
534
+ 发布包提供 `openpi` 可执行文件。需要同时使用终端扩展和 Web 时,安装同一版本的 Pi package 与 CLI:
535
+
536
+ ```bash
537
+ pi install npm:@tt-a1i/openpi
538
+ npm install --global @tt-a1i/openpi
539
+ openpi web # 使用当前目录启动 Web
540
+ openpi web /path/to/repo # 指定初始工作区
541
+ ```
542
+
543
+ 两处应保持同一 OpenPI 版本。Pi 的 managed package 与全局 CLI 即使位于不同物理路径,同一 Web 进程内也通过带版本的共享 registry 按 Pi `SessionManager` 身份连接 capability 投影;它不保存第二份状态,也不兼容任意混装版本。
544
+
545
+ 已经在 Pi 中安装 OpenPI 时,也可以直接执行 `/web`。它通过 Pi 官方的交互式终端 seam 暂停当前 TUI,运行当前 package 内完全相同的 `openpi web` 子进程,并在 `Ctrl+C` 停止 Web 后恢复原来的终端 Session。运行期间终端只归 Web 子进程使用;父 Pi 不读取按键,也不会把当前 Session id、消息、上下文或工作目录传给浏览器。Web 会恢复它自己的已有 Session 和工作区;没有可用项时,由用户在浏览器中添加或选择,不会把启动 `/web` 时的终端目录自动注册为 Web 工作区。选择前的内部引导态不暴露 Session、不绑定 extension 生命周期,也不接受 Prompt 或模型变更。选择工作区后发送第一条消息会先创建真实 Web Session,再向它投递。
546
+
547
+ Pi 当前只原生分派 `install`、`remove`、`update`、`list`、`config` 和 `auth` 等固定子命令,package 不能注册新的顶层子命令。因此 Web 入口是独立 CLI 的 `openpi web`,不是会被 Pi 当成初始 Prompt 的 `pi open`。Web 进程仍沿用 Pi 的 Provider、模型、凭据、Settings、Trust、Session 格式和 extension 资源加载,不引入第二套 Provider 或 Session 存储。
498
548
 
499
549
  ### 命令速查
500
550
 
501
551
  | 命令 | 作用 |
502
552
  | -------------------------- | ---------------------------------------------- |
503
- | `/openpi-setup [自然语言]` | 查看或修改统一配置;可选择安装 pi-intercom |
553
+ | `/openpi-setup [自然语言]` | 查看或修改 OpenPI 自有配置 |
554
+ | `/web` | 前台运行独立 Web 工作台;`Ctrl+C` 后返回 Pi |
504
555
  | `/ps` | 查看、跟踪与终止后台终端 |
505
556
  | `/subagents` / `/btw` | 管理 Subagent / 在旁路 Context 中提问;仅 TUI |
506
557
  | `/workflows` | 查看阶段、Agent、Graph 与产物;可停止运行 |
@@ -515,9 +566,9 @@ pi install npm:pi-intercom
515
566
  <details>
516
567
  <summary><strong>模型工具速查</strong></summary>
517
568
 
518
- Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 OpenPI 模型工具,首轮保持 Pi 原生 `read`、`bash`、`edit`、`write`。用户明确要求结构化搜索、Subagent、Workflow、后台进程或 Session Goal/Tasks 时,OpenPI 在 `before_agent_start` 直接加载对应能力组;明确询问 OpenPI capabilities/tools/features 时显示 `openpi_load_tools`。可通过 `/openpi-setup` 显式选择 `adaptive`:此时只让小型 `openpi_load_tools` 网关常驻,模型可在判断任务确实受益时自主加载一个能力组。该选择也授权模型启动该组内的昂贵工作,因此不作为默认值。条件句(例如 “If you delegate…”)不会被当成显式委派意图。能力组在当前 Session 内单调保持,避免反复增删工具破坏缓存。Delegate 一经加载便一次性开放完整、稳定的 Subagent 工具族;资源不存在时由工具执行层明确返回空状态或 fail-closed,而不再按实例生命周期改变模型接口。其他组内管理工具仍只在资源成功创建或状态确实存在后出现。Mode / Setup / Context 工具独立跟随实时状态显示和隐藏。Background、Subagent 与 Workflow 的 Skill 文件仍随包发布,但只在对应能力触发后提示读取,不常驻普通系统 Prompt。
569
+ Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 OpenPI 模型工具,首轮保持 Pi 原生 `read`、`bash`、`edit`、`write`。用户明确要求结构化搜索、Subagent、Workflow、后台进程或 Session Goal/Tasks 时,OpenPI 在 `before_agent_start` 直接加载对应能力组;明确询问 OpenPI capabilities/tools/features 时显示 `openpi_load_tools`。可通过 `/openpi-setup` 显式选择 `adaptive`:此时只让小型 `openpi_load_tools` 网关常驻,模型可在判断任务确实受益时自主加载一个能力组。该选择也授权模型启动该组内的昂贵工作,因此不作为默认值。句首「子代理了解下项目」这类带执行动作的表达会加载 Delegate;「子代理是什么」这类讨论、否定表达和条件句(例如 “If you delegate…”)不会被当成显式委派意图。能力组在当前 Session 内单调保持,避免反复增删工具破坏缓存。Delegate 一经加载便一次性开放完整、稳定的 Subagent 工具族;资源不存在时由工具执行层明确返回空状态或 fail-closed,而不再按实例生命周期改变模型接口。其他组内管理工具仍只在资源成功创建或状态确实存在后出现。Mode / Setup / Context 工具独立跟随实时状态显示和隐藏。Background、Subagent 与 Workflow 的 Skill 文件仍随包发布,但只在对应能力触发后提示读取,不常驻普通系统 Prompt。
519
570
 
520
- 普通产品默认采用 Pi-native execution:保留 Pi 原生完整历史、工具输出上限、Session compaction、显式 Bash timeout 与 provider loop,不再额外做固定事务投影、成功 Bash 二次裁剪、测试 timeout 改写、重复失败硬拦或恢复/轨迹提示。OpenPI 只保留独立的工作区安全边界:阻止未授权删除 pre-existing 路径,并从实际文件状态识别本轮通过原生写入、文字重定向或 literal `mkdir -p` 创建的 scratch,避免误拦其清理。旧执行策略仅保留为受 benchmark root 门控的实验 profile,不会进入普通 Session。
571
+ 普通产品采用 Pi-native execution:保留 Pi 原生完整历史、工具输出上限、Session compaction、显式 Bash timeout 与 provider loop,不额外做固定事务投影、成功 Bash 二次裁剪、测试 timeout 改写、重复失败硬拦或恢复/轨迹提示。OpenPI 只保留一层工作区清理护栏:源码中可识别的 `rm` 只有在整条命令是直接、可静态验证的 literal `rm`,且目标都是工作区内相对路径时,才会进入 provenance 与确认流程;可识别的复合、嵌套或动态 target `rm` 会 fail closed,并提示改用独立的 literal `rm` 重试。单条 standalone 普通命令中可静态识别的 bare、single-quoted double-quoted 参数、Bash comment,以及独占输入的单个非展开 heredoc 中的 `rm` 文本不受影响;复合命令、已知 command forwarder 和带后续命令的 heredoc 会保守阻止 source-visible `rm`,可拆成独立命令重试。Guard 会从实际文件状态识别本轮通过原生写入、文字重定向或 literal `mkdir -p` 创建的 scratch,避免误拦其清理;它不是任意程序文件系统行为的 sandbox,也不承诺识别运行时生成的命令名或其他程序内部的文件系统行为。
521
572
 
522
573
  | 工具 | 用途 | 可见时机 |
523
574
  | -------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------------------------- |
@@ -567,7 +618,11 @@ Subagent 是一项可继续对话的自包含委派;Workflow 是多阶段编
567
618
  <details>
568
619
  <summary><strong>Plan Mode 为什么允许 git log,却拒绝 npm install?</strong></summary>
569
620
 
570
- Plan Mode 不猜“任意 Shell 是否只读”,只放行由已知安全零件组成的命令。窄白名单内的 Git / GitHub 查询可以通过;Shell 元字符、未知 flag、安装、写入和无法证明的形式全部拒绝。
621
+ Plan Mode 不猜“任意 Shell 是否只读”,只放行由已知安全零件组成的命令。不会生成 diff 的窄白名单 Git / GitHub 查询(例如原始 `git log`、`git status`、`git blame`)可以通过;Shell 元字符、未知 flag、安装、写入和无法证明的形式全部拒绝。
622
+
623
+ 进入或恢复 Plan Mode 时,OpenPI 会为当前 Session 加载 `search` 组。差异检查使用结构化 `git_diff` / `git_show`,历史浏览使用 `git_log`;前两者固定传入 `--no-ext-diff --no-textconv --no-color`。原始 Bash `git diff`、`git show`、`git whatchanged`,以及 `git log -p`、`--stat`、`--name-only`、`-L` 等会生成 diff 的形式会被拒绝,避免仓库的 `diff.external` 或 textconv driver 执行外部程序。
624
+
625
+ 这项保证精确覆盖 Git diff driver 边界,并不宣称任意 hostile Git 配置都无副作用;其余允许的 Git 调研命令仍位于 Pi 已有的项目 Trust 边界内。
571
626
 
572
627
  </details>
573
628
 
@@ -600,6 +655,7 @@ extensions/
600
655
  ├── context-pivot/ # 定向 Compaction
601
656
  ├── plan-mode/ + cron/ # 批准门禁与 Session 定时 Prompt
602
657
  ├── ask-user/ # Reviewed input 与 Human Handoff
658
+ ├── workspace-cleanup-guard/ # pre-existing 文件删除保护
603
659
  ├── file-search/ # fd / rg 与安全二进制获取
604
660
  ├── git-read/ # 只读 git show / diff / log
605
661
  ├── sessions/ # Session 搜索与切换
@@ -607,12 +663,18 @@ extensions/
607
663
  ├── ui-customization/ # Header、Footer、Terminal title
608
664
  └── shared/ # Child policy、配置、Worktree、终端清洗
609
665
 
666
+ bin/openpi.js # 独立 Web CLI 入口
667
+ web/ # Web Host、Pi Runtime Adapter、协议与浏览器 UI
610
668
  skills/ # Background terminal、Subagent 与 Workflow 指南
611
669
  themes/ # github-dark-default
612
670
  ```
613
671
 
672
+ Web 日常开发、前后端边界、Vite HMR 和后端自动重启说明见 [`docs/development/OPENPI_WEB_DEVELOPMENT.md`](docs/development/OPENPI_WEB_DEVELOPMENT.md)。正式运行仍使用 `openpi web [workspace]`;Vite 只用于本地 UI 开发。
673
+
614
674
  开发工具链使用 Bun `1.3.14` 管理依赖和脚本,Biome 负责 TypeScript / JavaScript / JSON 格式与基础 lint;产品运行时仍是 Node,测试仍由 `node:test` 与 Vitest 执行:
615
675
 
676
+ 根目录的 `tsconfig.json` 是所有 extension 的唯一 TypeScript 项目配置;不要在 extension 目录中添加局部 `tsconfig.json`。单独类型检查使用根目录的 `bun run typecheck`,完整校验执行:
677
+
616
678
  ```bash
617
679
  bun install --frozen-lockfile
618
680
  bun run check
@@ -621,7 +683,7 @@ bun run test
621
683
 
622
684
  npm 仍用于发布包的 `pack` / clean-install 验证,因为用户通过 npm Registry 安装 OpenPI。
623
685
 
624
- 测试覆盖进程树终止与竞态、Subagent 生命周期与工具边界、Workflow Sandbox / Ledger / Graph / Replay / Acceptance、Worktree 数据保全、Session 状态恢复、配置迁移和 TUI 渲染。设计记录见 [`docs/design/`](docs/design/),问题请提交到 [GitHub Issues](https://github.com/tt-a1i/openpi/issues)。
686
+ 测试覆盖进程树终止与竞态、Subagent 生命周期与工具边界、Workflow Sandbox / Ledger / Graph / Replay / Acceptance、Worktree 数据保全、Session 状态恢复、配置迁移和 TUI 渲染。设计记录见 [docs/design/](https://github.com/openpi-dev/openpi/tree/main/docs/design/),问题请提交到 [GitHub Issues](https://github.com/openpi-dev/openpi/issues)。
625
687
 
626
688
  ---
627
689
 
@@ -629,6 +691,6 @@ npm 仍用于发布包的 `pack` / clean-install 验证,因为用户通过 npm
629
691
 
630
692
  本项目最初基于 [davis7dotsh/my-pi-setup](https://github.com/davis7dotsh/my-pi-setup) 演进,现作为独立发行版维护。感谢原作者提供起点。
631
693
 
632
- `extensions/sessions/` 改编自 [jayshah5696/pi-agent-extensions](https://github.com/jayshah5696/pi-agent-extensions)。可选的顶层 Session 通信由 [pi-intercom](https://github.com/nicobailon/pi-intercom) 提供。完整第三方说明见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
694
+ `extensions/sessions/` 改编自 [jayshah5696/pi-agent-extensions](https://github.com/jayshah5696/pi-agent-extensions)。独立可选的顶层 Session 通信 package 见 [pi-intercom](https://github.com/nicobailon/pi-intercom)。完整第三方说明见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
633
695
 
634
696
  本项目以 MIT 许可证发布(见 [`LICENSE`](LICENSE));`THIRD_PARTY_NOTICES.md` 记录第三方来源与各自许可。
package/SETUP.md CHANGED
@@ -9,14 +9,16 @@ pi install npm:@tt-a1i/openpi
9
9
  To inspect the current source before loading it, install directly from GitHub instead:
10
10
 
11
11
  ```sh
12
- pi install git:github.com/tt-a1i/openpi
12
+ pi install git:github.com/openpi-dev/openpi
13
13
  ```
14
14
 
15
15
  Pi installs the package dependencies automatically. Restart Pi or run `/reload` after installation.
16
16
 
17
17
  ## fd, rg, and read-only git tools
18
18
 
19
- The `file-search` extension registers `fd` and `rg` as model tools, and `git-read` registers `git_show`, `git_diff`, and `git_log` (read-only git inspection). They stay outside an ordinary parent turn until the user explicitly asks to use `fd`/`rg`/git history, or structured file search, or the model loads the `search` group through `openpi_load_tools`. The gateway is shown after an explicit OpenPI-capability request, or remains visible when the user opts into adaptive discovery; child sessions may still receive these tools through the reviewed child-safe allowlist (the read-only git tools let reviewer/advisor subagents inspect diffs, which a bash-free tool boundary otherwise excludes). No setup is normally needed: at startup `fd`/`rg` silently use a system-installed binary (`fd`/`fdfind` and `rg`) when available, or an existing binary in the agent's private managed bin directory (`~/.pi/agent/bin`). Only when neither exists does it download an official release binary (macOS/Linux, arm64/x64, over HTTPS) into that directory — a persistent cache that survives package updates — and show a one-time notification. If your platform is unsupported, install `fd` and `rg` with your package manager and restart Pi. The git tools require a system `git`.
19
+ The `file-search` extension registers `fd` and `rg` as model tools, and `git-read` registers `git_show`, `git_diff`, and `git_log` (read-only git inspection). They stay outside an ordinary parent turn until the user explicitly asks to use `fd`/`rg`/git history, or structured file search, or the model loads the `search` group through `openpi_load_tools`. Entering or restoring Plan Mode is a runtime-safety exception: it loads `search` for that Session so diff investigation can use the structured Git boundary. The gateway is shown after an explicit OpenPI-capability request, or remains visible when the user opts into adaptive discovery; child sessions may still receive these tools through the reviewed child-safe allowlist (the read-only git tools let reviewer/advisor subagents inspect diffs, which a bash-free tool boundary otherwise excludes). No setup is normally needed: at startup `fd`/`rg` silently use a system-installed binary (`fd`/`fdfind` and `rg`) when available, or an existing binary in the agent's private managed bin directory (`~/.pi/agent/bin`). Only when neither exists does it download an official release binary (macOS/Linux, arm64/x64, over HTTPS) into that directory — a persistent cache that survives package updates — and show a one-time notification. If your platform is unsupported, install `fd` and `rg` with your package manager and restart Pi. The git tools require a system `git`.
20
+
21
+ While Plan Mode is active, raw Bash `git diff`, `git show`, and `git whatchanged` are refused, as are diff-generating `git log` options such as `-p`, `--stat`, `--name-only`, and `-L`. Use `git_log` to find commits and `git_diff` / `git_show` to inspect changes; the latter commands always pass `--no-ext-diff --no-textconv --no-color`, so repository-configured `diff.external` and textconv drivers are not executed. This guarantee is scoped to the Git diff-driver boundary rather than every possible hostile Git configuration; the remaining allowlisted Git investigation commands still run inside Pi's existing project Trust boundary.
20
22
 
21
23
  ## Theme
22
24
 
@@ -32,7 +34,7 @@ Pi will load the extensions and theme the next time it starts. OpenPI's Backgrou
32
34
 
33
35
  ## Configure this package
34
36
 
35
- Use the single canonical package-owned command. `/my-pi-setup` remains a compatibility alias. With no arguments, when optional pi-intercom is absent, the interactive TUI first offers a reviewed global installation; declining changes nothing. Acceptance installs the fixed `npm:pi-intercom` source through Pi's package manager. A new private config receives `confirmSend: true` and `inboundTrigger: "replies"`; an existing preference file is never rewritten and must already define both fields. Package download failure writes no config, while uncertain activation retains the safe new config. Setup asks for `/reload` instead of loading a new broker into the running Session. The current model then explains the remaining configurable areas and uses `ask_user`: first run initializes them; later runs explain the saved state and ask whether to keep it, change one area, or review everything. With arguments, it treats the rest as a targeted natural-language request. Persist still goes through the typed `configure_my_pi_setup` tool, which is exposed only while that `/openpi-setup` episode is in flight and is hidden again afterward. One successful apply completes the episode; a later configuration change starts a new one with `/openpi-setup <request>` rather than reusing the hidden tool:
37
+ Use the single canonical package-owned command. `/my-pi-setup` remains a compatibility alias. With no arguments, the current model explains the configurable areas and uses `ask_user`: first run initializes them; later runs explain the saved state and ask whether to keep it, change one area, or review everything. With arguments, it treats the rest as a targeted natural-language request. Persist still goes through the typed `configure_my_pi_setup` tool. The writer stays hidden while a busy Session queues the setup request, becomes active only when that exact request is delivered to the model, and is hidden again afterward. One successful apply completes the episode. If the run settles without a successful apply, OpenPI appends a visible, durable closure receipt to the Session and later model context; it says that the writer is hidden and re-entry requires `/openpi-setup <request>`. OpenPI also verifies that the active writer belongs to the package source before announcing an active setup episode; duplicate or mismatched sources fail closed without injecting the setup request. A later configuration change starts a new episode with `/openpi-setup <request>` rather than reusing the hidden tool:
36
38
 
37
39
  ```text
38
40
  /openpi-setup
@@ -54,7 +56,21 @@ Use the single canonical package-owned command. `/my-pi-setup` remains a compati
54
56
  /openpi-setup 清除 explorer 的模型,让它继承父模型
55
57
  ```
56
58
 
57
- Capability discovery defaults to `explicit`, preserving the zero-resident OpenPI tool surface until the user asks for a capability. The case-insensitive English words `subagent` and `workflow` are reserved authorization words: entering either word is sufficient to load its capability group, and the interactive editor shows it in Claude Code-style lavender before submission, with a darker purple fallback for light themes. This makes discussion that contains either English word an intentional opt-in tradeoff; conditional and negated clauses remain inert, while Chinese capability names still require a recognized action request. `adaptive` is an explicit opt-in that keeps only `openpi_load_tools` visible and allows the model to load a useful group on its own; because this can start Subagents, Workflows, or background processes, normal permission and configured concurrency/call limits still apply. Changing the setting updates the current Session immediately, while already loaded groups remain stable for that Session. Accepted Suggestion text is classified only after it becomes real editor input. The visual feedback and runtime activation share one fail-closed intent classifier. Next-action suggestions default to off. Run `/openpi-setup` to explicitly choose an available model and reasoning level. After a fully settled main-agent run, one suggestion may appear as dim inline text on the first row of an empty editor; reserved cells at the row end keep CJK IME preedit from overwriting it. `Right` accepts it into the editor without submitting, while any other editor input dismisses it. Suggestions are ephemeral and never enter session history or model context. Workflows default to 8 concurrent agents and 128 total agent calls per run; configurable hard maxima are 64 and 1024. The large decorative header defaults off and the custom dashboard footer defaults on with a one-line plain layout (`model context |flex| git pr cwd`; `thinking`, `cache`, `cost`, and `throughput` remain opt-in metrics). Footer presets are `powerline`, `powerline-mono`, and `compact`; style can also be set independently to `plain`, `powerline`, or `powerline-mono`. Custom layouts use a 2D `footerLines` array with at most one `flex` per row for left/right alignment. Nerd Font affects powerline separator glyphs (``) and adds Codex-style outline icons to compact read, terminal, edit, search, and directory activity rows; all accompanying text remains readable without it. Footer metrics use one Codicon outline family (`` model, `` context, and `` directory) plus `⎇` for the branch. A Nerd Font containing Codicons renders them as designed; without one, the text labels remain readable even if an icon falls back to an empty box. Footer changes apply immediately in the active TUI session. Subagent results default to the existing full display; compact mode shows only bounded status rows and keeps raw child reports behind `app.tools.expand` (`Ctrl+O` by default). Ordinary `read`, `grep`, `find`, and `ls` operations render as one-line semantic activity summaries. Bash and Write/Edit default to the same activity-row projection, showing the target, running/success/failure state, and useful line or diff counts without replaying stdout or previews. Select full independently for Bash or Write/Edit to keep Pi's native rendering expanded. `app.tools.expand` temporarily restores the native arguments, output, errors, diff, timing, images, truncation notices, and full-output metadata; it never changes Session history or model context. An optional post-edit command is off by default: set one (for example `npm run format`, maximum 500 characters) and it runs once in the background after each interactive-TUI turn with successful Write/Edit operations, with failures reported as a notification. It deliberately does not guess whether arbitrary Bash commands changed files. Built-in Agent roles `explorer`, `implementer`, `reviewer`, and `advisor` are shared by `subagent_spawn.agent_type` and Workflow `agent(..., { agent_type })`; all inherit the parent model by default. `/openpi-setup` may assign a currently available Registry model to any subset; clearing one returns it to inheritance and omitted roles stay unchanged. Model precedence is explicit call > selected role-file model > setup assignment > parent inheritance; effort is explicit call > selected role > parent. A trusted project `.pi/agents/<role>.md` overrides global `~/.pi/agent/agents/<role>.md`, which overrides the complete built-in role definition; overrides are diagnosed. Role-model changes apply to the next spawn or Workflow agent call without reload. Configuration is stored privately at `~/.pi/agent/my-pi-setup.json`.
59
+ Capability discovery defaults to `explicit`, preserving the zero-resident OpenPI tool surface until the user asks for a capability. The case-insensitive English words `subagent` and `workflow` are reserved authorization words: entering either word is sufficient to load its capability group, and the interactive editor shows it in Claude Code-style lavender before submission, with a darker purple fallback for light themes. This makes discussion that contains either English word an intentional opt-in tradeoff; conditional and negated clauses remain inert, while Chinese capability names still require a recognized action request. `adaptive` is an explicit opt-in that keeps only `openpi_load_tools` visible and allows the model to load a useful group on its own; because this can start Subagents, Workflows, or background processes, normal permission and configured concurrency/call limits still apply. Changing the setting updates the current Session immediately, while already loaded groups remain stable for that Session. Accepted Suggestion text is classified only after it becomes real editor input. The visual feedback and runtime activation share one fail-closed intent classifier. Next-action suggestions default to off. Run `/openpi-setup` to explicitly choose an available model and reasoning level. After a fully settled main-agent run, one suggestion may appear as dim inline text on the first row of an empty editor; reserved cells at the row end keep CJK IME preedit from overwriting it. `Right` accepts it into the editor without submitting, while any other editor input dismisses it. Suggestions are ephemeral and never enter session history or model context. Workflows default to 8 concurrent agents and 128 total agent calls per run; configurable hard maxima are 64 and 1024. The large decorative header defaults off and the custom dashboard footer defaults on with a one-line plain layout (`model context |flex| git pr cwd`; `thinking`, `cache`, `cost`, and `throughput` remain opt-in metrics). Footer presets are `powerline`, `powerline-mono`, and `compact`; style can also be set independently to `plain`, `powerline`, or `powerline-mono`. Custom layouts use a 2D `footerLines` array with at most one `flex` per row for left/right alignment. Nerd Font affects powerline separator glyphs (``) and adds Codex-style outline icons to compact read, terminal, edit, search, and directory activity rows; all accompanying text remains readable without it. Footer metrics use one Codicon outline family (`` model, `` context, and `` directory) plus `⎇` for the branch. A Nerd Font containing Codicons renders them as designed; without one, the text labels remain readable even if an icon falls back to an empty box. Footer changes apply immediately in the active TUI session. Subagent results default to a compact status summary; full mode remains available as a per-user setting, and `app.tools.expand` (`Ctrl+O` by default) reveals the available child report. Ordinary `read`, `grep`, `find`, and `ls` operations render as one-line semantic activity summaries. Bash and Write/Edit default to the same activity-row projection, showing the target, running/success/failure state, and useful line or diff counts without replaying stdout or previews. Select full independently for Bash or Write/Edit to keep Pi's native rendering expanded. `app.tools.expand` temporarily restores the native arguments, output, errors, diff, timing, images, truncation notices, and full-output metadata; it never changes Session history or model context. An optional post-edit command is off by default: set one (for example `npm run format`, maximum 500 characters) and it runs once in the background after each interactive-TUI turn with successful Write/Edit operations, with failures reported as a notification. It deliberately does not guess whether arbitrary Bash commands changed files. Built-in Agent roles `explorer`, `implementer`, `reviewer`, and `advisor` are shared by `subagent_spawn.agent_type` and Workflow `agent(..., { agent_type })`; all inherit the parent model by default. `/openpi-setup` may assign a currently available Registry model to any subset; clearing one returns it to inheritance and omitted roles stay unchanged. Model precedence is explicit call > selected role-file model > setup assignment > parent inheritance; effort is explicit call > selected role > parent. A trusted project `.pi/agents/<role>.md` overrides global `~/.pi/agent/agents/<role>.md`, which overrides the complete built-in role definition; overrides are diagnosed. Role-model changes apply to the next spawn or Workflow agent call without reload. Configuration is stored privately at `~/.pi/agent/my-pi-setup.json`.
60
+
61
+ Legacy `footerItems` is accepted and migrated at the input boundary, but new setup writes persist only canonical `footerLines`. Configurations written by this version are not guaranteed to retain their Footer layout when read by an older OpenPI version.
62
+
63
+ <!-- config-contract: capabilities.discovery suggestions.enabled suggestions.model workflows.concurrency workflows.maxAgentCalls ui.showHeader ui.customFooter ui.footerStyle ui.footerLines ui.subagentResultDisplay ui.bashToolDisplay ui.fileMutationDisplay postEdit.command subagents.roleModels -->
64
+
65
+ ## Optional cross-session communication
66
+
67
+ [pi-intercom](https://github.com/nicobailon/pi-intercom) is an independently maintained Pi package for communication between top-level Sessions. OpenPI does not detect, recommend, install, configure, migrate, or remove it. If you need that capability, review its repository and install it through Pi's native package command:
68
+
69
+ ```sh
70
+ pi install npm:pi-intercom
71
+ ```
72
+
73
+ OpenPI Direct Subagents and Workflow children use their native parent/child result channels instead. To preserve process-level identity isolation, their Resource Loader excludes pi-intercom extensions and Skills installed from npm, Git, or local package sources without excluding ordinary project resources that merely share the same directory name.
58
74
 
59
75
  ## Session Goal and Tasks
60
76
 
@@ -71,6 +87,6 @@ Session Tasks remain advisory multi-item work intent and do not determine Goal c
71
87
  - `/sessions` searches and previews project sessions before switching.
72
88
  - `/tasks` inspects branch-scoped advisory work items.
73
89
  - `/goal ...` controls the persistent autonomous session objective.
74
- - `/context-pivot <next phase>` deliberately compacts a long current session into a next-phase brief. It requires at least 30,000 context tokens and is rejected below that; use the separate `/handoff` skill when work should move to a genuinely new session.
90
+ - `/context-pivot <next phase>` deliberately compacts a long current session into a next-phase brief. It requires at least 30,000 context tokens and is rejected below that; use `/sessions` to browse or switch sessions, or install the optional `pi-intercom` package for communication between top-level sessions.
75
91
  - `/cron every <5m> <prompt>`, `/cron in <30s> <prompt>`, `/cron list`, and `/cron remove <id>` schedule a prompt for this session. Jobs are in-memory and session-scoped (cleared on shutdown), fire only while the session is idle, and use a duration grammar (`30s`/`5m`/`2h`, minimum 30s) rather than crontab fields, because the scheduler polls about every 30 seconds. Jobs due in the same poll are delivered as one triggered turn while retaining each job's id and recurrence metadata; if that atomic delivery fails, every due job remains pending for retry.
76
- - `/plan [objective]` explores read-only before changing anything: while armed it blocks `edit`, `write`, mutating Bash, `subagent_send`, `workflow`, and `bg_start`, while read/grep/find/ls/fd/rg and verified read-only Git/GitHub commands stay available. It permits `subagent_spawn`, but the harness narrows every newly spawned planning child to investigation-only tools; agent types can narrow that list further, never widen it. The model must submit the complete plan through parent-only `plan_ready`; the write gate stays closed until `/plan` prepares an editable implementation prompt for the current or a fresh Session. `/plan off` cancels.
92
+ - `/plan [objective]` explores read-only before changing anything and automatically loads the `search` capability for the current Session. While armed it blocks `edit`, `write`, mutating Bash, raw Git diff-rendering commands, `subagent_send`, `workflow`, and `bg_start`; read/grep/find/ls/fd/rg, `git_log`/`git_diff`/`git_show`, and verified non-diff Git/GitHub Bash commands stay available. It permits `subagent_spawn`, but the harness narrows every newly spawned planning child to investigation-only tools; agent types can narrow that list further, never widen it. The model must submit the complete plan through parent-only `plan_ready`; the write gate stays closed until `/plan` prepares an editable implementation prompt for the current or a fresh Session. `/plan off` cancels.
package/bin/openpi.js ADDED
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { resolve } from "node:path";
4
+ import { createJiti } from "jiti";
5
+
6
+ function printHelp() {
7
+ console.log(`OpenPI Web Workbench
8
+
9
+ Usage:
10
+ openpi web [workspace]
11
+ openpi [workspace] Alias for openpi web [workspace]
12
+
13
+ Options:
14
+ --port <number> Bind a specific loopback port (development)
15
+ --no-open Do not open a browser (development)
16
+
17
+ Starts an isolated local Web runtime. Browser conversations and session changes
18
+ never enter an interactive terminal Pi session.`);
19
+ }
20
+
21
+ const args = process.argv.slice(2);
22
+ if (args.includes("--help") || args.includes("-h")) {
23
+ printHelp();
24
+ process.exit(0);
25
+ }
26
+ const command = args[0] === "web" ? args.slice(1) : args;
27
+ const noOpen = command.includes("--no-open");
28
+ const noWorkspace = command.includes("--no-workspace");
29
+ const portIndex = command.indexOf("--port");
30
+ const portText = portIndex >= 0 ? command[portIndex + 1] : undefined;
31
+ const workspaceArgs = [];
32
+ for (let index = 0; index < command.length; index++) {
33
+ const value = command[index];
34
+ if (value === "--no-open") continue;
35
+ if (value === "--no-workspace") continue;
36
+ if (value === "--port") {
37
+ index++;
38
+ continue;
39
+ }
40
+ workspaceArgs.push(value);
41
+ }
42
+ const configuredPort = portText ?? process.env.OPENPI_WEB_PORT;
43
+ const port = configuredPort === undefined ? undefined : Number(configuredPort);
44
+ if (portIndex >= 0 && (!portText || portText.startsWith("--"))) {
45
+ console.error("--port requires a value");
46
+ process.exit(1);
47
+ }
48
+ if (port !== undefined && (!Number.isInteger(port) || port < 0 || port > 65535)) {
49
+ console.error("--port must be an integer between 0 and 65535");
50
+ process.exit(1);
51
+ }
52
+ if (workspaceArgs.length > 1) {
53
+ console.error("Usage: openpi web [workspace]");
54
+ process.exit(1);
55
+ }
56
+ if (noWorkspace && workspaceArgs.length > 0) {
57
+ console.error("--no-workspace cannot be combined with a workspace");
58
+ process.exit(1);
59
+ }
60
+
61
+ let host;
62
+ let runtime;
63
+ let stopping;
64
+ const stop = () => {
65
+ stopping ??= host?.stop() ?? runtime?.dispose() ?? Promise.resolve();
66
+ return stopping;
67
+ };
68
+
69
+ try {
70
+ const jiti = createJiti(import.meta.url);
71
+ const [browserModule, hostModule, runtimeModule, statusModule, traceModule] =
72
+ await Promise.all([
73
+ jiti.import("../web/host/browser-launcher.ts"),
74
+ jiti.import("../web/host/web-host.ts"),
75
+ jiti.import("../web/runtime/pi-runtime.ts"),
76
+ jiti.import("../web/host/terminal-status.ts"),
77
+ jiti.import("../web/trace.ts"),
78
+ ]);
79
+ const { openBrowser } = browserModule;
80
+ const { WebHost } = hostModule;
81
+ const { PiWebRuntime } = runtimeModule;
82
+ const { formatWebReadyScreen } = statusModule;
83
+ const { traceWeb } = traceModule;
84
+ runtime = noWorkspace
85
+ ? await PiWebRuntime.createWithoutWorkspace()
86
+ : await PiWebRuntime.create(resolve(workspaceArgs[0] ?? process.cwd()));
87
+ host = new WebHost({
88
+ runtime,
89
+ ...(port === undefined ? {} : { port }),
90
+ ...(process.env.OPENPI_WEB_TOKEN
91
+ ? { token: process.env.OPENPI_WEB_TOKEN }
92
+ : {}),
93
+ ...(process.env.OPENPI_WEB_ALLOWED_ORIGIN
94
+ ? { allowedOrigins: [process.env.OPENPI_WEB_ALLOWED_ORIGIN] }
95
+ : {}),
96
+ });
97
+ await host.start();
98
+ traceWeb("web_started", {
99
+ ...(runtime.workspaceSelected === true ? { cwd: runtime.cwd } : {}),
100
+ origin: host.origin,
101
+ });
102
+ const opened = noOpen ? false : await openBrowser(host.url);
103
+ if (noWorkspace) {
104
+ console.log(
105
+ formatWebReadyScreen({
106
+ origin: host.origin,
107
+ url: host.url,
108
+ opened,
109
+ }),
110
+ );
111
+ } else {
112
+ console.log(`OpenPI Web Workbench is running at ${host.origin}`);
113
+ if (!opened) console.log(`Open this URL in a browser: ${host.url}`);
114
+ }
115
+
116
+ for (const signal of ["SIGINT", "SIGTERM"]) {
117
+ process.once(signal, () => {
118
+ void stop().then(
119
+ () => process.exit(0),
120
+ (error) => {
121
+ console.error(
122
+ `Failed to stop OpenPI Web Workbench: ${error instanceof Error ? error.message : String(error)}`,
123
+ );
124
+ process.exit(1);
125
+ },
126
+ );
127
+ });
128
+ }
129
+ } catch (error) {
130
+ let cleanupError;
131
+ try {
132
+ await stop();
133
+ } catch (caught) {
134
+ cleanupError = caught;
135
+ }
136
+ console.error(
137
+ `Failed to start OpenPI Web Workbench: ${error instanceof Error ? error.message : String(error)}`,
138
+ );
139
+ if (cleanupError) {
140
+ console.error(
141
+ `Failed to clean up OpenPI Web Workbench: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`,
142
+ );
143
+ }
144
+ process.exit(1);
145
+ }