@pencil-agent/nano-pencil 2.0.0 → 2.0.1

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 (195) hide show
  1. package/README.md +267 -267
  2. package/dist/build-meta.json +3 -3
  3. package/dist/core/export-html/AGENT.md +11 -11
  4. package/dist/core/export-html/template.css +971 -971
  5. package/dist/core/export-html/template.html +54 -54
  6. package/dist/core/mcp/mcp-client.d.ts +3 -1
  7. package/dist/core/mcp/mcp-client.js +6 -6
  8. package/dist/core/mcp/mcp-config.d.ts +3 -3
  9. package/dist/core/mcp/mcp-config.js +1 -1
  10. package/dist/core/mcp/mcp-manager.d.ts +5 -1
  11. package/dist/core/mcp/mcp-manager.js +1 -1
  12. package/dist/core/platform/config/resource-loader.d.ts +2 -0
  13. package/dist/core/platform/config/resource-loader.js +2 -2
  14. package/dist/core/runtime/agent-session.d.ts +12 -0
  15. package/dist/core/runtime/agent-session.js +8 -8
  16. package/dist/core/runtime/sdk.d.ts +8 -0
  17. package/dist/core/runtime/sdk.js +1 -1
  18. package/dist/extensions/builtin/AGENT.md +115 -115
  19. package/dist/extensions/builtin/browser/AGENT.md +17 -17
  20. package/dist/extensions/builtin/browser/agent-workspace/agent_helpers.py +12 -12
  21. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -198
  22. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -341
  23. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -311
  24. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -333
  25. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/atlas/overview.md +70 -70
  26. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -578
  27. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -440
  28. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -110
  29. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -325
  30. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -463
  31. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -360
  32. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -390
  33. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -568
  34. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -323
  35. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -349
  36. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -435
  37. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -506
  38. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -363
  39. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/expedia/automation.md +168 -168
  40. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/groups.md +236 -236
  41. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/pages.md +295 -295
  42. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/framer/editor.md +108 -108
  43. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/fred/scraping.md +493 -493
  44. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/g2/scraping.md +580 -580
  45. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/genius/scraping.md +511 -511
  46. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -65
  47. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/scraping.md +184 -184
  48. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -543
  49. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gmail/compose.md +122 -122
  50. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -461
  51. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -383
  52. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -243
  53. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -473
  54. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -271
  55. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -436
  56. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -1021
  57. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -349
  58. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -109
  59. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -170
  60. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -537
  61. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -120
  62. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/scraping.md +414 -414
  63. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -477
  64. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -478
  65. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -339
  66. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -205
  67. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -472
  68. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -470
  69. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -490
  70. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -478
  71. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -234
  72. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -307
  73. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -421
  74. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/quora/scraping.md +364 -364
  75. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -352
  76. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -124
  77. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -233
  78. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -361
  79. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -36
  80. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -72
  81. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -109
  82. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -137
  83. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -362
  84. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -339
  85. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -435
  86. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/steam/scraping.md +575 -575
  87. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/substack/scraping.md +338 -338
  88. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -52
  89. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -107
  90. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -309
  91. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -88
  92. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -375
  93. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -444
  94. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -306
  95. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/weather/scraping.md +398 -398
  96. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -596
  97. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -356
  98. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -84
  99. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -418
  100. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -433
  101. package/dist/extensions/builtin/browser/browser.md +73 -73
  102. package/dist/extensions/builtin/browser/install.md +142 -142
  103. package/dist/extensions/builtin/browser/interaction-skills/connection.md +48 -48
  104. package/dist/extensions/builtin/browser/interaction-skills/cookies.md +3 -3
  105. package/dist/extensions/builtin/browser/interaction-skills/cross-origin-iframes.md +3 -3
  106. package/dist/extensions/builtin/browser/interaction-skills/dialogs.md +64 -64
  107. package/dist/extensions/builtin/browser/interaction-skills/downloads.md +3 -3
  108. package/dist/extensions/builtin/browser/interaction-skills/drag-and-drop.md +3 -3
  109. package/dist/extensions/builtin/browser/interaction-skills/dropdowns.md +3 -3
  110. package/dist/extensions/builtin/browser/interaction-skills/iframes.md +3 -3
  111. package/dist/extensions/builtin/browser/interaction-skills/network-requests.md +3 -3
  112. package/dist/extensions/builtin/browser/interaction-skills/print-as-pdf.md +3 -3
  113. package/dist/extensions/builtin/browser/interaction-skills/profile-sync.md +90 -90
  114. package/dist/extensions/builtin/browser/interaction-skills/screenshots.md +17 -17
  115. package/dist/extensions/builtin/browser/interaction-skills/scrolling.md +3 -3
  116. package/dist/extensions/builtin/browser/interaction-skills/shadow-dom.md +3 -3
  117. package/dist/extensions/builtin/browser/interaction-skills/tabs.md +69 -69
  118. package/dist/extensions/builtin/browser/interaction-skills/uploads.md +1 -1
  119. package/dist/extensions/builtin/browser/interaction-skills/viewport.md +3 -3
  120. package/dist/extensions/builtin/browser/src/browser_harness/AGENT.md +15 -15
  121. package/dist/extensions/builtin/browser/src/browser_harness/__init__.py +8 -8
  122. package/dist/extensions/builtin/browser/src/browser_harness/_ipc.py +90 -90
  123. package/dist/extensions/builtin/browser/src/browser_harness/admin.py +722 -722
  124. package/dist/extensions/builtin/browser/src/browser_harness/daemon.py +328 -328
  125. package/dist/extensions/builtin/browser/src/browser_harness/helpers.py +396 -396
  126. package/dist/extensions/builtin/browser/src/browser_harness/run.py +103 -103
  127. package/dist/extensions/builtin/discipline/skills/brainstorming/SKILL.md +33 -33
  128. package/dist/extensions/builtin/discipline/skills/executing-plans/SKILL.md +25 -25
  129. package/dist/extensions/builtin/discipline/skills/finishing-development-branch/SKILL.md +25 -25
  130. package/dist/extensions/builtin/discipline/skills/receiving-code-review/SKILL.md +22 -22
  131. package/dist/extensions/builtin/discipline/skills/requesting-code-review/SKILL.md +31 -31
  132. package/dist/extensions/builtin/discipline/skills/systematic-debugging/SKILL.md +28 -28
  133. package/dist/extensions/builtin/discipline/skills/test-driven-development/SKILL.md +32 -32
  134. package/dist/extensions/builtin/discipline/skills/using-git-worktrees/SKILL.md +25 -25
  135. package/dist/extensions/builtin/discipline/skills/verification-before-completion/SKILL.md +27 -27
  136. package/dist/extensions/builtin/discipline/skills/writing-plans/SKILL.md +26 -26
  137. package/dist/extensions/builtin/goal/README.md +67 -67
  138. package/dist/extensions/builtin/grub/README.md +112 -112
  139. package/dist/extensions/builtin/link-world/agent-workspace/README.md +16 -16
  140. package/dist/extensions/builtin/link-world/internet-search/internet-search.md +65 -65
  141. package/dist/extensions/builtin/link-world/link-world-agent.md +82 -82
  142. package/dist/extensions/builtin/link-world/linkworld.md +313 -313
  143. package/dist/extensions/builtin/link-world/network-routing/network-routing.md +67 -67
  144. package/dist/extensions/builtin/loop/README.md +92 -92
  145. package/dist/extensions/builtin/mcp/figma-design.md +68 -68
  146. package/dist/extensions/builtin/mcp/mcp-management.md +85 -85
  147. package/dist/extensions/builtin/recap/AGENT.md +15 -15
  148. package/dist/extensions/builtin/sal/README.md +72 -72
  149. package/dist/extensions/builtin/security-audit/README.md +289 -289
  150. package/dist/extensions/builtin/team/AGENT.md +112 -112
  151. package/dist/extensions/builtin/team/TESTING.md +299 -299
  152. package/dist/extensions/builtin/token-save/README.md +56 -56
  153. package/dist/extensions/optional/AGENT.md +10 -10
  154. package/dist/modes/interactive/interactive-mode.js +36 -36
  155. package/dist/modes/interactive/theme/dark.json +85 -85
  156. package/dist/modes/interactive/theme/light.json +84 -84
  157. package/dist/modes/interactive/theme/theme-schema.json +335 -335
  158. package/dist/modes/interactive/theme/warm.json +81 -81
  159. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.js +3 -2
  160. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.js +2 -1
  161. package/dist/node_modules/@pencil-agent/ai/dist/cli.js +0 -0
  162. package/docs/cc-agent-design.md +1297 -0
  163. package/docs/cc-tui-design.md +1333 -0
  164. package/docs/codex-goal-command-impl.md +1055 -1055
  165. package/docs/codex-goal-vs-grub.md +500 -500
  166. package/docs/custom-provider.md +27 -27
  167. package/docs/extensions.md +27 -27
  168. package/docs/keybindings.md +27 -27
  169. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +250 -250
  170. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +122 -122
  171. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -1222
  172. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/256/236/347/216/260/346/212/245/345/221/212.md" +158 -158
  173. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/257/271/346/257/224/345/210/206/346/236/220.md" +128 -128
  174. package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +320 -320
  175. package/docs/loop-usage-examples.md +214 -214
  176. package/docs/models.md +27 -27
  177. package/docs/nanoPencil-/345/255/246/344/271/240/350/256/241/345/210/222.md +170 -0
  178. package/docs/packages.md +27 -27
  179. package/docs/pi-design-philosophy.md +457 -457
  180. package/docs/planmode.md +1987 -1987
  181. package/docs/prompt-templates.md +27 -27
  182. package/docs/providers.md +27 -27
  183. package/docs/scan-report.md +3820 -0
  184. package/docs/sdk.md +27 -27
  185. package/docs/skills.md +27 -27
  186. package/docs/themes.md +27 -27
  187. package/docs/tui.md +27 -27
  188. package/docs//345/257/271/346/240/207Claude-Code.md +1775 -0
  189. package/docs//351/230/277/351/207/214/345/267/264/345/267/264/350/264/242/346/212/245/345/210/206/346/236/220/344/271/246.md +261 -0
  190. package/package.json +190 -190
  191. package/docs/ACP/345/215/217/350/256/256/351/233/206/346/210/220/345/274/200/345/217/221/346/226/207/346/241/243.md +0 -851
  192. package/docs/SDK-TESTING.md +0 -364
  193. package/docs/mem-core/346/212/200/346/234/257/346/226/207/346/241/243.md +0 -593
  194. package/docs/startup-performance-optimization.md +0 -301
  195. package/docs//350/256/244/347/237/245/345/234/260/345/233/276.md +0 -47
@@ -1,457 +1,457 @@
1
- # Pi Agent 核心设计哲学
2
-
3
- > nanoPencil 的骨架与灵魂来源。本文件不是怀旧考古——它是活的约束。
4
- > 每一个架构决策、每一次 PR、每一行代码,都应能回溯到这里的某条原则。
5
-
6
- ---
7
-
8
- ## 一、血统
9
-
10
- **上游**: [pi](https://github.com/earendil-works/pi) (`@earendil-works/pi-coding-agent`)
11
- **作者**: Armin Ronacher(Flask 作者)、Mario Zechner(badlogic)、Roland Wachtler
12
- **Stars**: 61k+(截至 2026-06)
13
- **许可证**: MIT
14
-
15
- nanoPencil 从 pi 分叉,在其骨架上叠加了**记忆系统**(mem-core)和**人格进化**(soul-core)两层。
16
- 但骨架本身的设计哲学——极简核心、终端原生、扩展驱动、会话即状态——是不可动摇的地基。
17
-
18
- ---
19
-
20
- ## 二、六大核心原则
21
-
22
- ### 原则 1:极简核心(Minimal Core)
23
-
24
- > "pi's core is minimal. If your feature does not belong in the core, it should be an extension.
25
- > PRs that bloat the core will likely be rejected."
26
- > — pi CONTRIBUTING.md
27
-
28
- **含义**:
29
- - 核心只做三件事:agent loop、工具调用、状态管理
30
- - 其他一切——记忆、人格、权限门禁、安全审计、多 agent——都是扩展
31
- - 如果一个功能可以用扩展实现,它就不该进核心
32
- - 核心代码量是约束指标,不是成就指标
33
-
34
- **违反信号**:
35
- - 核心目录新增了"可选"依赖
36
- - 核心代码出现了 `if (featureEnabled)` 分支
37
- - 核心包体积持续增长但功能没有本质变化
38
-
39
- **纳米铅笔的实践**:
40
- - `mem-core` 和 `soul-core` 是独立包,不污染 `agent-core`
41
- - 扩展系统(`core/extensions-host/`)是核心的一部分,但具体扩展(`extensions/builtin/`)不是
42
- - 2.0 重构把上帝类拆成控制器,是为了让核心更小更清晰,不是更大
43
-
44
- ---
45
-
46
- ### 原则 2:终端原生(Terminal Native)
47
-
48
- > pi 是纯 TUI,不依赖 Electron/浏览器。差分渲染、键盘快捷键、树状会话导航。
49
-
50
- **含义**:
51
- - 终端是第一公民,不是 GUI 的降级版
52
- - 差分渲染(differential rendering)实现流畅的 TUI 体验
53
- - 键盘快捷键是核心交互方式,不是可选功能
54
- - 所有用户交互必须在 80x24 的终端中可用
55
-
56
- **设计约束**:
57
- - 不能假设用户有鼠标
58
- - 不能假设终端支持图片(但可以通过扩展支持)
59
- - 不能假设终端宽度超过 80 列
60
- - 启动时间必须是亚秒级
61
-
62
- **纳米铅笔的实践**:
63
- - `@pencil-agent/tui` 包提供终端 UI 组件
64
- - 交互模式(`modes/interactive/`)是纯终端实现
65
- - 打印模式(`modes/print/`)支持无 TUI 的管道使用
66
-
67
- ---
68
-
69
- ### 原则 3:扩展驱动(Extension-Driven)
70
-
71
- > Extensions are TypeScript modules that extend pi's behavior. They can subscribe to
72
- > lifecycle events, register custom tools callable by the LLM, add commands, and more.
73
- > — pi docs/extensions.md
74
-
75
- **含义**:
76
- - 扩展是一等公民,不是二等插件
77
- - 扩展可以做任何核心能做的事:注册工具、拦截事件、注入上下文、自定义 UI
78
- - 扩展是 TypeScript 模块,不是配置文件
79
- - 扩展可以热重载(`/reload`)
80
-
81
- **扩展能力矩阵**:
82
-
83
- | 能力 | API | 说明 |
84
- |------|-----|------|
85
- | 自定义工具 | `pi.registerTool()` | LLM 可调用的工具 |
86
- | 事件拦截 | `pi.on("tool_call", ...)` | 拦截/修改工具调用 |
87
- | 上下文注入 | `pi.on("before_agent_start", ...)` | 注入额外上下文 |
88
- | 用户交互 | `ctx.ui.select/confirm/input` | 扩展与用户对话 |
89
- | 自定义 UI | `ctx.ui.custom()` | 完整 TUI 组件 |
90
- | 自定义命令 | `pi.registerCommand()` | 注册 `/mycommand` |
91
- | 会话持久化 | `pi.appendEntry()` | 存储跨重启的状态 |
92
- | 自定义渲染 | 渲染钩子 | 控制工具调用/结果的显示 |
93
-
94
- **扩展生命周期**:
95
- ```
96
- session_start → before_agent_start → user_message →
97
- tool_call → tool_execution_start → tool_execution_end →
98
- after_agent_end → session_shutdown
99
- ```
100
-
101
- **纳米铅笔的实践**:
102
- - 4 级扩展加载器:内置 → 配置 → npm → 路径
103
- - `@pencil-agent/extension-sdk` 定义工具和生命周期契约
104
- - `core/extensions-host/` 是扩展运行时
105
- - `extensions/builtin/` 包含内置扩展(soul、plan、teach 等)
106
-
107
- ---
108
-
109
- ### 原则 4:会话即状态(Session as State)
110
-
111
- > Sessions auto-save to `~/.pi/agent/sessions/`, organized by working directory.
112
- > Each session is a JSONL file with a tree structure.
113
- > — pi docs/sessions.md
114
-
115
- **含义**:
116
- - 会话不是临时对话,是持久化的状态树
117
- - JSONL 格式:每行一个 JSON 条目,append-only
118
- - 树状结构:每个条目有 `id` 和 `parentId`,当前叶子是活跃分支
119
- - 支持分支(fork)、导航(tree)、压缩(compact)
120
-
121
- **会话操作**:
122
-
123
- | 操作 | 命令 | 语义 |
124
- |------|------|------|
125
- | 继续 | `pi -c` | 恢复最近会话 |
126
- | 浏览 | `pi -r` | 交互式选择历史会话 |
127
- | 新建 | `/new` | 开始新会话 |
128
- | 分支 | `/fork` | 从历史点创建新分支 |
129
- | 克隆 | `/clone` | 复制当前分支到新会话 |
130
- | 压缩 | `/compact` | 摘要旧上下文 |
131
- | 导出 | `/export` | 导出为 HTML |
132
- | 分享 | `/share` | 上传为 GitHub gist |
133
-
134
- **树状结构示例**:
135
- ```
136
- ├─ user: "Hello, can you help..."
137
- │ └─ assistant: "Of course! I can..."
138
- │ ├─ user: "Let's try approach A..."
139
- │ │ └─ assistant: "For approach A..."
140
- │ │ └─ user: "That worked..." ← active
141
- │ └─ user: "Actually, approach B..."
142
- │ └─ assistant: "For approach B..."
143
- ```
144
-
145
- **纳米铅笔的实践**:
146
- - `core/session/session-manager.ts` 实现 JSONL 持久化
147
- - `SessionTreeController` 管理会话树导航
148
- - `CompactionController` 管理上下文压缩
149
- - 会话数据与记忆系统(mem-core)分离但可互操作
150
-
151
- ---
152
-
153
- ### 原则 5:Agent Harness 生命周期(AgentHarness Lifecycle)
154
-
155
- > `AgentHarness` is the orchestration layer above the low-level agent loop.
156
- > It owns session persistence, runtime configuration, resource resolution,
157
- > operation locking, and extension-facing mutation semantics.
158
- > — pi docs/agent-harness.md
159
-
160
- **这是 pi 最精妙的设计,也是最容易被忽视的设计。**
161
-
162
- #### 四类状态分离
163
-
164
- | 类别 | 含义 | 可变时机 |
165
- |------|------|----------|
166
- | **Harness Config** | 运行时配置(模型、thinking level、工具、资源) | 任何时候,立即生效,影响下一个 turn |
167
- | **Turn Snapshot** | 一次 LLM turn 的具体状态 | turn 开始时快照,turn 期间不变 |
168
- | **Session** | 持久化的会话条目 | 只在 save point 写入 |
169
- | **Pending Writes** | 排队中的会话写入 | 在 save point/operation 结束时刷新 |
170
-
171
- **为什么这样分**:
172
- - Harness Config 是"你想用什么",Turn Snapshot 是"这次实际用什么"
173
- - 分离保证了:在 turn 执行期间修改配置不会破坏当前请求
174
- - Pending Writes 保证了:扩展在 turn 期间写的条目不会丢失,也不会破坏顺序
175
-
176
- #### 操作阶段
177
-
178
- ```typescript
179
- type AgentHarnessPhase = "idle" | "turn" | "compaction" | "branch_summary" | "retry";
180
- ```
181
-
182
- **规则**:
183
- - 结构性操作(prompt、compact、navigateTree)必须在 `idle` 阶段
184
- - 结构性操作会同步设置 phase,然后才 await
185
- - 非 idle 时发起结构性操作 → 拒绝(`AgentHarnessError` code `"busy"`)
186
- - steer、followUp、nextTurn、abort 在 turn 期间允许
187
-
188
- #### Save Point 语义
189
-
190
- Save point 发生在 assistant turn 和 tool-result 消息完成后:
191
-
192
- 1. 刷新 pending session writes
193
- 2. 创建新的 turn snapshot(如果 low-level loop 可能继续)
194
- 3. 应用最新的 context/model/thinking-level/stream-options/session-id
195
-
196
- **关键洞察**:
197
- - Provider transport reading 已经被 `AssistantMessageStream` 解耦
198
- - Harness 可以直接 await listeners/hooks 的 settlement,不需要额外的异步事件队列
199
- - 这保证了 transcript/session 顺序的确定性
200
-
201
- #### 错误处理分层
202
-
203
- | 层级 | 策略 | 原因 |
204
- |------|------|------|
205
- | 低层能力(ExecutionEnv、shell) | `Result<TValue, TError>` | 预期失败必须被包含,不能抛 |
206
- | 高层编排(Session、AgentHarness) | throw | 裸 Result 容易被忽略 |
207
- | 公共 Harness 失败 | `AgentHarnessError` | 子系统错误保留为 `cause` |
208
-
209
- **纳米铅笔的实践**:
210
- - `core/runtime/agent-session.ts` 是 Harness 的本地实现
211
- - `ModelController`、`CompactionController` 等是 Harness 语义的控制器化
212
- - save point 语义在 compaction 和 model switch 中体现
213
-
214
- ---
215
-
216
- ### 原则 6:代码质量即纪律(Code Quality as Discipline)
217
-
218
- > "You must understand your code. If you cannot explain what your changes do
219
- > and how they interact with the rest of the system, your PR will be closed."
220
- > — pi CONTRIBUTING.md
221
-
222
- **这是 pi 最严厉的原则,也是最值得传承的原则。**
223
-
224
- #### 铁律清单
225
-
226
- | 规则 | 原因 | 违反后果 |
227
- |------|------|----------|
228
- | **不用 `any`** | 类型安全是最后防线 | PR 关闭 |
229
- | **不用内联 import** | 依赖关系必须在文件顶部可见 | PR 关闭 |
230
- | **不降级代码修类型错误** | 升级依赖,不是削弱代码 | PR 关闭 |
231
- | **不硬编码按键** | 走 `DEFAULT_*_KEYBINDINGS` 配置 | PR 关闭 |
232
- | **不直接改生成文件** | 改生成脚本,重新生成 | PR 关闭 |
233
- | **不假设外部 API 类型** | 检查 `node_modules` | PR 关闭 |
234
- | **单行 helper 只有一个调用点** | 内联它 | 代码审查 |
235
- | **不保留向后兼容** | 除非用户明确要求 | 设计决策 |
236
- | **不删除看似有意的功能** | 先问 | PR 关闭 |
237
-
238
- #### 可擦除 TypeScript 语法
239
-
240
- pi 要求在根配置管辖的代码中使用 Node strip-only mode 兼容的语法:
241
-
242
- **禁止**:
243
- - 参数属性(`constructor(private x: number)`)
244
- - `enum`
245
- - `namespace` / `module`
246
- - `import =`
247
- - `export =`
248
- - 其他需要 JS emit 的构造
249
-
250
- **替代**:
251
- - 显式字段 + 构造函数赋值
252
- - `const` 对象代替 `enum`
253
- - 标准 ESM import/export
254
-
255
- #### Git 纪律
256
-
257
- **多 session 并行修改同一仓库时的生存规则**:
258
-
259
- | 操作 | 规则 | 原因 |
260
- |------|------|------|
261
- | 暂存 | `git add <path1> <path2>` | 永远不用 `git add -A` / `git add .` |
262
- | 提交前 | `git status` 验证 | 确保只暂存自己的文件 |
263
- | 提交消息 | `{feat,fix,docs}[(scope)]: message` | 简洁、信息丰富 |
264
- | 冲突 | 只解决自己修改的文件 | 不碰别人的文件 |
265
- | 永远不运行 | `git reset --hard`, `git checkout .`, `git clean -fd`, `git stash`, `git add -A`, `git add .`, `git commit --no-verify` | 毁灭其他 session 的工作 |
266
-
267
- #### 依赖安全
268
-
269
- | 实践 | 命令 | 原因 |
270
- |------|------|------|
271
- | 安装 | `npm install --ignore-scripts` | 不运行生命周期脚本 |
272
- | CI | `npm ci --ignore-scripts` | 同上 |
273
- | 直接依赖 | 精确版本锁定 | 防止供应链攻击 |
274
- | lockfile 变更 | 受保护 | pre-commit 阻止意外 lockfile 提交 |
275
- | 新生命周期脚本依赖 | 需要审查 + 显式白名单 | 安全门禁 |
276
-
277
- **纳米铅笔的实践**:
278
- - 遵循 `no any`、`no inline imports` 等规则
279
- - 提交消息使用 conventional format
280
- - DIP 协议(文档同构)是纳米铅笔自己的增量
281
-
282
- ---
283
-
284
- ## 三、架构拓扑(从 pi 继承)
285
-
286
- ### 包结构
287
-
288
- ```
289
- pi-mono/
290
- ├── packages/
291
- │ ├── ai/ # 统一多 provider LLM API
292
- │ ├── agent/ # Agent runtime + tool calling + state management
293
- │ ├── coding-agent/ # 交互式编码 agent CLI
294
- │ └── tui/ # 终端 UI 差分渲染库
295
- ```
296
-
297
- **映射到纳米铅笔**:
298
-
299
- | pi 包 | 纳米铅笔位置 | 职责 |
300
- |-------|-------------|------|
301
- | `@earendil-works/pi-ai` | `core/lib/ai/` | 统一多 provider LLM API |
302
- | `@earendil-works/pi-agent-core` | `core/lib/agent-core/` | Agent runtime、tool calling、状态管理 |
303
- | `@earendil-works/pi-coding-agent` | `core/` + `modes/` | 编码 agent CLI、会话、扩展 |
304
- | `@earendil-works/pi-tui` | `core/lib/tui/` | 终端 UI 差分渲染 |
305
-
306
- ### 数据流
307
-
308
- ```
309
- 用户输入
310
-
311
- AgentHarness (编排层)
312
-
313
- Agent Loop (状态机)
314
-
315
- StreamFn → LLM Provider
316
-
317
- Tool Orchestration (工具编排)
318
-
319
- Session Persistence (会话持久化)
320
-
321
- Extension Hooks (扩展钩子)
322
-
323
- TUI Rendering (终端渲染)
324
- ```
325
-
326
- ---
327
-
328
- ## 四、与上游的分叉点
329
-
330
- ### 纳米铅笔新增的能力
331
-
332
- | 能力 | 上游状态 | 纳米铅笔实现 | 设计决策 |
333
- |------|----------|-------------|----------|
334
- | **持久记忆** | 无 | `packages/mem-core/` | 独立包,不进核心 |
335
- | **人格进化** | 无 | `packages/soul-core/` | Big Five 向量 + 编码风格 |
336
- | **Persona 切换** | 无 | `core/persona/` | 多人格管理 |
337
- | **中文支持** | 英文 | i18n + DashScope provider | 本地化 |
338
- | **Teach 扩展** | 无 | `extensions/builtin/teach/` | 引导式知识教学 |
339
- | **DIP 协议** | 无 | `CLAUDE.md` 体系 | 文档同构约束 |
340
-
341
- ### 不可分叉的(必须保留的)
342
-
343
- | 设计 | 原因 |
344
- |------|------|
345
- | 极简核心 | 这是 pi 的存在理由 |
346
- | Agent Harness 生命周期 | 状态分离 + save point 语义是正确性的基础 |
347
- | 会话树结构 | JSONL + tree 是状态管理的核心 |
348
- | 扩展即一等公民 | 扩展能力矩阵决定了系统的可扩展性 |
349
- | 代码质量纪律 | 这是工程品味的底线 |
350
- | 终端原生 | 这是用户群体的共识 |
351
-
352
- ### 可以分叉的(纳米铅笔自己的增量)
353
-
354
- | 设计 | 原因 |
355
- |------|------|
356
- | 记忆系统 | 上游明确没有,这是增量 |
357
- | 人格系统 | 上游明确没有,这是增量 |
358
- | DIP 文档协议 | 纳米铅笔自己的工程实践 |
359
- | 中文支持 | 本地化需求 |
360
-
361
- ---
362
-
363
- ## 五、违反哲学的反模式
364
-
365
- ### 反模式 1:核心膨胀
366
-
367
- ```typescript
368
- // ❌ 在 agent-core 里加记忆功能
369
- import { MemCore } from "../mem-core/index.js";
370
- if (options.enableMemory) { ... }
371
-
372
- // ✅ 记忆是扩展
373
- // extensions/builtin/memory/index.ts
374
- pi.on("before_agent_start", async (event, ctx) => {
375
- const memories = await memCore.retrieve(ctx.messages);
376
- ctx.injectContext(memories);
377
- });
378
- ```
379
-
380
- ### 反模式 2:绕过 Harness
381
-
382
- ```typescript
383
- // ❌ 直接写会话,不经过 save point
384
- session.entries.push(newEntry);
385
- session.save();
386
-
387
- // ✅ 通过 pending writes 机制
388
- harness.appendEntry(newEntry);
389
- // 在 save point 自动刷新
390
- ```
391
-
392
- ### 反模式 3:类型降级
393
-
394
- ```typescript
395
- // ❌ 用 any 修类型错误
396
- const result: any = await someFunction();
397
-
398
- // ✅ 升级依赖或修正类型
399
- const result: ProperType = await someFunction();
400
- ```
401
-
402
- ### 反模式 4:内联 import
403
-
404
- ```typescript
405
- // ❌ 动态 import
406
- const { something } = await import("./module.js");
407
-
408
- // ✅ 顶层 import
409
- import { something } from "./module.js";
410
- ```
411
-
412
- ### 反模式 5:硬编码配置
413
-
414
- ```typescript
415
- // ❌ 硬编码按键
416
- if (key === "ctrl+x") { ... }
417
-
418
- // ✅ 走配置
419
- if (matchesKey(key, DEFAULT_EDITOR_KEYBINDINGS.save)) { ... }
420
- ```
421
-
422
- ---
423
-
424
- ## 六、哲学的检验标准
425
-
426
- 在做任何架构决策之前,问自己:
427
-
428
- 1. **这个功能能在扩展里实现吗?** 如果能,它就不该进核心。
429
- 2. **这个改动破坏了 Harness 的状态分离吗?** 如果破坏了,重新设计。
430
- 3. **这个代码能用 Result 而不是 throw 吗?** 如果是低层能力,用 Result。
431
- 4. **这个类型是 any 吗?** 如果是,停下来,找到正确的类型。
432
- 5. **这个 import 是内联的吗?** 如果是,移到文件顶部。
433
- 6. **这个配置是硬编码的吗?** 如果是,提取到默认配置。
434
- 7. **这个 PR 能解释清楚吗?** 如果不能,重新理解你的代码。
435
-
436
- ---
437
-
438
- ## 七、致后来者
439
-
440
- pi 的设计哲学不是文档,是纪律。
441
-
442
- 纪律的意思是:即使没有人在看,你也遵守。即使赶 deadline,你也遵守。即使"这次只是个小改动",你也遵守。
443
-
444
- 因为每一次妥协都会累积。每一次 `any` 都会让类型系统少保护一个角落。每一次内联 import 都会让依赖关系多一个隐藏的节点。每一次核心膨胀都会让扩展的空间少一分。
445
-
446
- pi 用 61k stars 证明了:极简核心 + 扩展驱动 + 代码纪律 = 可持续的开源项目。
447
-
448
- 我们继承了这个骨架。记忆和灵魂是我们加的血肉。但骨架不能断。
449
-
450
- ---
451
-
452
- **最后一条**:
453
-
454
- > "Using AI to write code is fine. Submitting AI-generated slop without understanding it is not."
455
- > — pi CONTRIBUTING.md
456
-
457
- 理解你写的每一行代码。这不是建议,是准入条件。
1
+ # Pi Agent 核心设计哲学
2
+
3
+ > nanoPencil 的骨架与灵魂来源。本文件不是怀旧考古——它是活的约束。
4
+ > 每一个架构决策、每一次 PR、每一行代码,都应能回溯到这里的某条原则。
5
+
6
+ ---
7
+
8
+ ## 一、血统
9
+
10
+ **上游**: [pi](https://github.com/earendil-works/pi) (`@earendil-works/pi-coding-agent`)
11
+ **作者**: Armin Ronacher(Flask 作者)、Mario Zechner(badlogic)、Roland Wachtler
12
+ **Stars**: 61k+(截至 2026-06)
13
+ **许可证**: MIT
14
+
15
+ nanoPencil 从 pi 分叉,在其骨架上叠加了**记忆系统**(mem-core)和**人格进化**(soul-core)两层。
16
+ 但骨架本身的设计哲学——极简核心、终端原生、扩展驱动、会话即状态——是不可动摇的地基。
17
+
18
+ ---
19
+
20
+ ## 二、六大核心原则
21
+
22
+ ### 原则 1:极简核心(Minimal Core)
23
+
24
+ > "pi's core is minimal. If your feature does not belong in the core, it should be an extension.
25
+ > PRs that bloat the core will likely be rejected."
26
+ > — pi CONTRIBUTING.md
27
+
28
+ **含义**:
29
+ - 核心只做三件事:agent loop、工具调用、状态管理
30
+ - 其他一切——记忆、人格、权限门禁、安全审计、多 agent——都是扩展
31
+ - 如果一个功能可以用扩展实现,它就不该进核心
32
+ - 核心代码量是约束指标,不是成就指标
33
+
34
+ **违反信号**:
35
+ - 核心目录新增了"可选"依赖
36
+ - 核心代码出现了 `if (featureEnabled)` 分支
37
+ - 核心包体积持续增长但功能没有本质变化
38
+
39
+ **纳米铅笔的实践**:
40
+ - `mem-core` 和 `soul-core` 是独立包,不污染 `agent-core`
41
+ - 扩展系统(`core/extensions-host/`)是核心的一部分,但具体扩展(`extensions/builtin/`)不是
42
+ - 2.0 重构把上帝类拆成控制器,是为了让核心更小更清晰,不是更大
43
+
44
+ ---
45
+
46
+ ### 原则 2:终端原生(Terminal Native)
47
+
48
+ > pi 是纯 TUI,不依赖 Electron/浏览器。差分渲染、键盘快捷键、树状会话导航。
49
+
50
+ **含义**:
51
+ - 终端是第一公民,不是 GUI 的降级版
52
+ - 差分渲染(differential rendering)实现流畅的 TUI 体验
53
+ - 键盘快捷键是核心交互方式,不是可选功能
54
+ - 所有用户交互必须在 80x24 的终端中可用
55
+
56
+ **设计约束**:
57
+ - 不能假设用户有鼠标
58
+ - 不能假设终端支持图片(但可以通过扩展支持)
59
+ - 不能假设终端宽度超过 80 列
60
+ - 启动时间必须是亚秒级
61
+
62
+ **纳米铅笔的实践**:
63
+ - `@pencil-agent/tui` 包提供终端 UI 组件
64
+ - 交互模式(`modes/interactive/`)是纯终端实现
65
+ - 打印模式(`modes/print/`)支持无 TUI 的管道使用
66
+
67
+ ---
68
+
69
+ ### 原则 3:扩展驱动(Extension-Driven)
70
+
71
+ > Extensions are TypeScript modules that extend pi's behavior. They can subscribe to
72
+ > lifecycle events, register custom tools callable by the LLM, add commands, and more.
73
+ > — pi docs/extensions.md
74
+
75
+ **含义**:
76
+ - 扩展是一等公民,不是二等插件
77
+ - 扩展可以做任何核心能做的事:注册工具、拦截事件、注入上下文、自定义 UI
78
+ - 扩展是 TypeScript 模块,不是配置文件
79
+ - 扩展可以热重载(`/reload`)
80
+
81
+ **扩展能力矩阵**:
82
+
83
+ | 能力 | API | 说明 |
84
+ |------|-----|------|
85
+ | 自定义工具 | `pi.registerTool()` | LLM 可调用的工具 |
86
+ | 事件拦截 | `pi.on("tool_call", ...)` | 拦截/修改工具调用 |
87
+ | 上下文注入 | `pi.on("before_agent_start", ...)` | 注入额外上下文 |
88
+ | 用户交互 | `ctx.ui.select/confirm/input` | 扩展与用户对话 |
89
+ | 自定义 UI | `ctx.ui.custom()` | 完整 TUI 组件 |
90
+ | 自定义命令 | `pi.registerCommand()` | 注册 `/mycommand` |
91
+ | 会话持久化 | `pi.appendEntry()` | 存储跨重启的状态 |
92
+ | 自定义渲染 | 渲染钩子 | 控制工具调用/结果的显示 |
93
+
94
+ **扩展生命周期**:
95
+ ```
96
+ session_start → before_agent_start → user_message →
97
+ tool_call → tool_execution_start → tool_execution_end →
98
+ after_agent_end → session_shutdown
99
+ ```
100
+
101
+ **纳米铅笔的实践**:
102
+ - 4 级扩展加载器:内置 → 配置 → npm → 路径
103
+ - `@pencil-agent/extension-sdk` 定义工具和生命周期契约
104
+ - `core/extensions-host/` 是扩展运行时
105
+ - `extensions/builtin/` 包含内置扩展(soul、plan、teach 等)
106
+
107
+ ---
108
+
109
+ ### 原则 4:会话即状态(Session as State)
110
+
111
+ > Sessions auto-save to `~/.pi/agent/sessions/`, organized by working directory.
112
+ > Each session is a JSONL file with a tree structure.
113
+ > — pi docs/sessions.md
114
+
115
+ **含义**:
116
+ - 会话不是临时对话,是持久化的状态树
117
+ - JSONL 格式:每行一个 JSON 条目,append-only
118
+ - 树状结构:每个条目有 `id` 和 `parentId`,当前叶子是活跃分支
119
+ - 支持分支(fork)、导航(tree)、压缩(compact)
120
+
121
+ **会话操作**:
122
+
123
+ | 操作 | 命令 | 语义 |
124
+ |------|------|------|
125
+ | 继续 | `pi -c` | 恢复最近会话 |
126
+ | 浏览 | `pi -r` | 交互式选择历史会话 |
127
+ | 新建 | `/new` | 开始新会话 |
128
+ | 分支 | `/fork` | 从历史点创建新分支 |
129
+ | 克隆 | `/clone` | 复制当前分支到新会话 |
130
+ | 压缩 | `/compact` | 摘要旧上下文 |
131
+ | 导出 | `/export` | 导出为 HTML |
132
+ | 分享 | `/share` | 上传为 GitHub gist |
133
+
134
+ **树状结构示例**:
135
+ ```
136
+ ├─ user: "Hello, can you help..."
137
+ │ └─ assistant: "Of course! I can..."
138
+ │ ├─ user: "Let's try approach A..."
139
+ │ │ └─ assistant: "For approach A..."
140
+ │ │ └─ user: "That worked..." ← active
141
+ │ └─ user: "Actually, approach B..."
142
+ │ └─ assistant: "For approach B..."
143
+ ```
144
+
145
+ **纳米铅笔的实践**:
146
+ - `core/session/session-manager.ts` 实现 JSONL 持久化
147
+ - `SessionTreeController` 管理会话树导航
148
+ - `CompactionController` 管理上下文压缩
149
+ - 会话数据与记忆系统(mem-core)分离但可互操作
150
+
151
+ ---
152
+
153
+ ### 原则 5:Agent Harness 生命周期(AgentHarness Lifecycle)
154
+
155
+ > `AgentHarness` is the orchestration layer above the low-level agent loop.
156
+ > It owns session persistence, runtime configuration, resource resolution,
157
+ > operation locking, and extension-facing mutation semantics.
158
+ > — pi docs/agent-harness.md
159
+
160
+ **这是 pi 最精妙的设计,也是最容易被忽视的设计。**
161
+
162
+ #### 四类状态分离
163
+
164
+ | 类别 | 含义 | 可变时机 |
165
+ |------|------|----------|
166
+ | **Harness Config** | 运行时配置(模型、thinking level、工具、资源) | 任何时候,立即生效,影响下一个 turn |
167
+ | **Turn Snapshot** | 一次 LLM turn 的具体状态 | turn 开始时快照,turn 期间不变 |
168
+ | **Session** | 持久化的会话条目 | 只在 save point 写入 |
169
+ | **Pending Writes** | 排队中的会话写入 | 在 save point/operation 结束时刷新 |
170
+
171
+ **为什么这样分**:
172
+ - Harness Config 是"你想用什么",Turn Snapshot 是"这次实际用什么"
173
+ - 分离保证了:在 turn 执行期间修改配置不会破坏当前请求
174
+ - Pending Writes 保证了:扩展在 turn 期间写的条目不会丢失,也不会破坏顺序
175
+
176
+ #### 操作阶段
177
+
178
+ ```typescript
179
+ type AgentHarnessPhase = "idle" | "turn" | "compaction" | "branch_summary" | "retry";
180
+ ```
181
+
182
+ **规则**:
183
+ - 结构性操作(prompt、compact、navigateTree)必须在 `idle` 阶段
184
+ - 结构性操作会同步设置 phase,然后才 await
185
+ - 非 idle 时发起结构性操作 → 拒绝(`AgentHarnessError` code `"busy"`)
186
+ - steer、followUp、nextTurn、abort 在 turn 期间允许
187
+
188
+ #### Save Point 语义
189
+
190
+ Save point 发生在 assistant turn 和 tool-result 消息完成后:
191
+
192
+ 1. 刷新 pending session writes
193
+ 2. 创建新的 turn snapshot(如果 low-level loop 可能继续)
194
+ 3. 应用最新的 context/model/thinking-level/stream-options/session-id
195
+
196
+ **关键洞察**:
197
+ - Provider transport reading 已经被 `AssistantMessageStream` 解耦
198
+ - Harness 可以直接 await listeners/hooks 的 settlement,不需要额外的异步事件队列
199
+ - 这保证了 transcript/session 顺序的确定性
200
+
201
+ #### 错误处理分层
202
+
203
+ | 层级 | 策略 | 原因 |
204
+ |------|------|------|
205
+ | 低层能力(ExecutionEnv、shell) | `Result<TValue, TError>` | 预期失败必须被包含,不能抛 |
206
+ | 高层编排(Session、AgentHarness) | throw | 裸 Result 容易被忽略 |
207
+ | 公共 Harness 失败 | `AgentHarnessError` | 子系统错误保留为 `cause` |
208
+
209
+ **纳米铅笔的实践**:
210
+ - `core/runtime/agent-session.ts` 是 Harness 的本地实现
211
+ - `ModelController`、`CompactionController` 等是 Harness 语义的控制器化
212
+ - save point 语义在 compaction 和 model switch 中体现
213
+
214
+ ---
215
+
216
+ ### 原则 6:代码质量即纪律(Code Quality as Discipline)
217
+
218
+ > "You must understand your code. If you cannot explain what your changes do
219
+ > and how they interact with the rest of the system, your PR will be closed."
220
+ > — pi CONTRIBUTING.md
221
+
222
+ **这是 pi 最严厉的原则,也是最值得传承的原则。**
223
+
224
+ #### 铁律清单
225
+
226
+ | 规则 | 原因 | 违反后果 |
227
+ |------|------|----------|
228
+ | **不用 `any`** | 类型安全是最后防线 | PR 关闭 |
229
+ | **不用内联 import** | 依赖关系必须在文件顶部可见 | PR 关闭 |
230
+ | **不降级代码修类型错误** | 升级依赖,不是削弱代码 | PR 关闭 |
231
+ | **不硬编码按键** | 走 `DEFAULT_*_KEYBINDINGS` 配置 | PR 关闭 |
232
+ | **不直接改生成文件** | 改生成脚本,重新生成 | PR 关闭 |
233
+ | **不假设外部 API 类型** | 检查 `node_modules` | PR 关闭 |
234
+ | **单行 helper 只有一个调用点** | 内联它 | 代码审查 |
235
+ | **不保留向后兼容** | 除非用户明确要求 | 设计决策 |
236
+ | **不删除看似有意的功能** | 先问 | PR 关闭 |
237
+
238
+ #### 可擦除 TypeScript 语法
239
+
240
+ pi 要求在根配置管辖的代码中使用 Node strip-only mode 兼容的语法:
241
+
242
+ **禁止**:
243
+ - 参数属性(`constructor(private x: number)`)
244
+ - `enum`
245
+ - `namespace` / `module`
246
+ - `import =`
247
+ - `export =`
248
+ - 其他需要 JS emit 的构造
249
+
250
+ **替代**:
251
+ - 显式字段 + 构造函数赋值
252
+ - `const` 对象代替 `enum`
253
+ - 标准 ESM import/export
254
+
255
+ #### Git 纪律
256
+
257
+ **多 session 并行修改同一仓库时的生存规则**:
258
+
259
+ | 操作 | 规则 | 原因 |
260
+ |------|------|------|
261
+ | 暂存 | `git add <path1> <path2>` | 永远不用 `git add -A` / `git add .` |
262
+ | 提交前 | `git status` 验证 | 确保只暂存自己的文件 |
263
+ | 提交消息 | `{feat,fix,docs}[(scope)]: message` | 简洁、信息丰富 |
264
+ | 冲突 | 只解决自己修改的文件 | 不碰别人的文件 |
265
+ | 永远不运行 | `git reset --hard`, `git checkout .`, `git clean -fd`, `git stash`, `git add -A`, `git add .`, `git commit --no-verify` | 毁灭其他 session 的工作 |
266
+
267
+ #### 依赖安全
268
+
269
+ | 实践 | 命令 | 原因 |
270
+ |------|------|------|
271
+ | 安装 | `npm install --ignore-scripts` | 不运行生命周期脚本 |
272
+ | CI | `npm ci --ignore-scripts` | 同上 |
273
+ | 直接依赖 | 精确版本锁定 | 防止供应链攻击 |
274
+ | lockfile 变更 | 受保护 | pre-commit 阻止意外 lockfile 提交 |
275
+ | 新生命周期脚本依赖 | 需要审查 + 显式白名单 | 安全门禁 |
276
+
277
+ **纳米铅笔的实践**:
278
+ - 遵循 `no any`、`no inline imports` 等规则
279
+ - 提交消息使用 conventional format
280
+ - DIP 协议(文档同构)是纳米铅笔自己的增量
281
+
282
+ ---
283
+
284
+ ## 三、架构拓扑(从 pi 继承)
285
+
286
+ ### 包结构
287
+
288
+ ```
289
+ pi-mono/
290
+ ├── packages/
291
+ │ ├── ai/ # 统一多 provider LLM API
292
+ │ ├── agent/ # Agent runtime + tool calling + state management
293
+ │ ├── coding-agent/ # 交互式编码 agent CLI
294
+ │ └── tui/ # 终端 UI 差分渲染库
295
+ ```
296
+
297
+ **映射到纳米铅笔**:
298
+
299
+ | pi 包 | 纳米铅笔位置 | 职责 |
300
+ |-------|-------------|------|
301
+ | `@earendil-works/pi-ai` | `core/lib/ai/` | 统一多 provider LLM API |
302
+ | `@earendil-works/pi-agent-core` | `core/lib/agent-core/` | Agent runtime、tool calling、状态管理 |
303
+ | `@earendil-works/pi-coding-agent` | `core/` + `modes/` | 编码 agent CLI、会话、扩展 |
304
+ | `@earendil-works/pi-tui` | `core/lib/tui/` | 终端 UI 差分渲染 |
305
+
306
+ ### 数据流
307
+
308
+ ```
309
+ 用户输入
310
+
311
+ AgentHarness (编排层)
312
+
313
+ Agent Loop (状态机)
314
+
315
+ StreamFn → LLM Provider
316
+
317
+ Tool Orchestration (工具编排)
318
+
319
+ Session Persistence (会话持久化)
320
+
321
+ Extension Hooks (扩展钩子)
322
+
323
+ TUI Rendering (终端渲染)
324
+ ```
325
+
326
+ ---
327
+
328
+ ## 四、与上游的分叉点
329
+
330
+ ### 纳米铅笔新增的能力
331
+
332
+ | 能力 | 上游状态 | 纳米铅笔实现 | 设计决策 |
333
+ |------|----------|-------------|----------|
334
+ | **持久记忆** | 无 | `packages/mem-core/` | 独立包,不进核心 |
335
+ | **人格进化** | 无 | `packages/soul-core/` | Big Five 向量 + 编码风格 |
336
+ | **Persona 切换** | 无 | `core/persona/` | 多人格管理 |
337
+ | **中文支持** | 英文 | i18n + DashScope provider | 本地化 |
338
+ | **Teach 扩展** | 无 | `extensions/builtin/teach/` | 引导式知识教学 |
339
+ | **DIP 协议** | 无 | `CLAUDE.md` 体系 | 文档同构约束 |
340
+
341
+ ### 不可分叉的(必须保留的)
342
+
343
+ | 设计 | 原因 |
344
+ |------|------|
345
+ | 极简核心 | 这是 pi 的存在理由 |
346
+ | Agent Harness 生命周期 | 状态分离 + save point 语义是正确性的基础 |
347
+ | 会话树结构 | JSONL + tree 是状态管理的核心 |
348
+ | 扩展即一等公民 | 扩展能力矩阵决定了系统的可扩展性 |
349
+ | 代码质量纪律 | 这是工程品味的底线 |
350
+ | 终端原生 | 这是用户群体的共识 |
351
+
352
+ ### 可以分叉的(纳米铅笔自己的增量)
353
+
354
+ | 设计 | 原因 |
355
+ |------|------|
356
+ | 记忆系统 | 上游明确没有,这是增量 |
357
+ | 人格系统 | 上游明确没有,这是增量 |
358
+ | DIP 文档协议 | 纳米铅笔自己的工程实践 |
359
+ | 中文支持 | 本地化需求 |
360
+
361
+ ---
362
+
363
+ ## 五、违反哲学的反模式
364
+
365
+ ### 反模式 1:核心膨胀
366
+
367
+ ```typescript
368
+ // ❌ 在 agent-core 里加记忆功能
369
+ import { MemCore } from "../mem-core/index.js";
370
+ if (options.enableMemory) { ... }
371
+
372
+ // ✅ 记忆是扩展
373
+ // extensions/builtin/memory/index.ts
374
+ pi.on("before_agent_start", async (event, ctx) => {
375
+ const memories = await memCore.retrieve(ctx.messages);
376
+ ctx.injectContext(memories);
377
+ });
378
+ ```
379
+
380
+ ### 反模式 2:绕过 Harness
381
+
382
+ ```typescript
383
+ // ❌ 直接写会话,不经过 save point
384
+ session.entries.push(newEntry);
385
+ session.save();
386
+
387
+ // ✅ 通过 pending writes 机制
388
+ harness.appendEntry(newEntry);
389
+ // 在 save point 自动刷新
390
+ ```
391
+
392
+ ### 反模式 3:类型降级
393
+
394
+ ```typescript
395
+ // ❌ 用 any 修类型错误
396
+ const result: any = await someFunction();
397
+
398
+ // ✅ 升级依赖或修正类型
399
+ const result: ProperType = await someFunction();
400
+ ```
401
+
402
+ ### 反模式 4:内联 import
403
+
404
+ ```typescript
405
+ // ❌ 动态 import
406
+ const { something } = await import("./module.js");
407
+
408
+ // ✅ 顶层 import
409
+ import { something } from "./module.js";
410
+ ```
411
+
412
+ ### 反模式 5:硬编码配置
413
+
414
+ ```typescript
415
+ // ❌ 硬编码按键
416
+ if (key === "ctrl+x") { ... }
417
+
418
+ // ✅ 走配置
419
+ if (matchesKey(key, DEFAULT_EDITOR_KEYBINDINGS.save)) { ... }
420
+ ```
421
+
422
+ ---
423
+
424
+ ## 六、哲学的检验标准
425
+
426
+ 在做任何架构决策之前,问自己:
427
+
428
+ 1. **这个功能能在扩展里实现吗?** 如果能,它就不该进核心。
429
+ 2. **这个改动破坏了 Harness 的状态分离吗?** 如果破坏了,重新设计。
430
+ 3. **这个代码能用 Result 而不是 throw 吗?** 如果是低层能力,用 Result。
431
+ 4. **这个类型是 any 吗?** 如果是,停下来,找到正确的类型。
432
+ 5. **这个 import 是内联的吗?** 如果是,移到文件顶部。
433
+ 6. **这个配置是硬编码的吗?** 如果是,提取到默认配置。
434
+ 7. **这个 PR 能解释清楚吗?** 如果不能,重新理解你的代码。
435
+
436
+ ---
437
+
438
+ ## 七、致后来者
439
+
440
+ pi 的设计哲学不是文档,是纪律。
441
+
442
+ 纪律的意思是:即使没有人在看,你也遵守。即使赶 deadline,你也遵守。即使"这次只是个小改动",你也遵守。
443
+
444
+ 因为每一次妥协都会累积。每一次 `any` 都会让类型系统少保护一个角落。每一次内联 import 都会让依赖关系多一个隐藏的节点。每一次核心膨胀都会让扩展的空间少一分。
445
+
446
+ pi 用 61k stars 证明了:极简核心 + 扩展驱动 + 代码纪律 = 可持续的开源项目。
447
+
448
+ 我们继承了这个骨架。记忆和灵魂是我们加的血肉。但骨架不能断。
449
+
450
+ ---
451
+
452
+ **最后一条**:
453
+
454
+ > "Using AI to write code is fine. Submitting AI-generated slop without understanding it is not."
455
+ > — pi CONTRIBUTING.md
456
+
457
+ 理解你写的每一行代码。这不是建议,是准入条件。