@chanlerdev/scorel 0.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 (80) hide show
  1. package/README.md +110 -0
  2. package/dist/index.js +6675 -0
  3. package/dist/index.js.map +7 -0
  4. package/docs/CHANGELOG.md +12 -0
  5. package/docs/README.md +116 -0
  6. package/docs/ROADMAP.md +669 -0
  7. package/docs/SHIP.md +242 -0
  8. package/docs/spec/channels.md +156 -0
  9. package/docs/spec/client.md +326 -0
  10. package/docs/spec/daemon.md +408 -0
  11. package/docs/spec/events.md +423 -0
  12. package/docs/spec/extensions.md +255 -0
  13. package/docs/spec/relay.md +391 -0
  14. package/docs/spec/runtime.md +251 -0
  15. package/docs/spec/session.md +380 -0
  16. package/docs/spec/ship/S0001-docs-baseline.md +41 -0
  17. package/docs/spec/ship/S0002-package-skeleton.md +56 -0
  18. package/docs/spec/ship/S0003-protocol-contracts.md +49 -0
  19. package/docs/spec/ship/S0004-session-core.md +50 -0
  20. package/docs/spec/ship/S0005-runtime-loop.md +48 -0
  21. package/docs/spec/ship/S0006-embedded-daemon-client.md +51 -0
  22. package/docs/spec/ship/S0007-cli-alpha.md +49 -0
  23. package/docs/spec/ship/S0008-coding-tools.md +107 -0
  24. package/docs/spec/ship/S0009-code-discovery-tools.md +82 -0
  25. package/docs/spec/ship/S0010-todo-tool-and-cli.md +81 -0
  26. package/docs/spec/ship/S0011-coding-agent-alpha-smoke.md +110 -0
  27. package/docs/spec/ship/S0012-coding-tools-maturity.md +143 -0
  28. package/docs/spec/ship/S0013-local-daemon-protocol.md +57 -0
  29. package/docs/spec/ship/S0014-local-daemon-lifecycle.md +64 -0
  30. package/docs/spec/ship/S0015-local-attach-and-broadcast.md +58 -0
  31. package/docs/spec/ship/S0016-local-daemon-resync-smoke.md +60 -0
  32. package/docs/spec/ship/S0017-grep-files-output-mode.md +49 -0
  33. package/docs/spec/ship/S0018-daemon-entrypoint-smoke.md +48 -0
  34. package/docs/spec/ship/S0019-remote-transport-contract.md +59 -0
  35. package/docs/spec/ship/S0020-remote-websocket-server.md +56 -0
  36. package/docs/spec/ship/S0021-remote-websocket-client-transport.md +55 -0
  37. package/docs/spec/ship/S0022-remote-daemon-cli-lifecycle.md +60 -0
  38. package/docs/spec/ship/S0023-remote-control-e2e-validation.md +66 -0
  39. package/docs/spec/ship/S0024-remote-attach-interactive-stream.md +49 -0
  40. package/docs/spec/ship/S0025-remote-attach-session-event-view.md +57 -0
  41. package/docs/spec/ship/S0026-attach-project-cache-and-dual-seq-reconnect.md +87 -0
  42. package/docs/spec/ship/S0027-session-diagnostics-log.md +77 -0
  43. package/docs/spec/ship/S0028-client-attach-diagnostics-log.md +70 -0
  44. package/docs/spec/ship/S0029-project-index-for-session-lookup.md +119 -0
  45. package/docs/spec/ship/S0030-webui-product-intent.md +73 -0
  46. package/docs/spec/ship/S0031-daemon-projectslug-rule.md +72 -0
  47. package/docs/spec/ship/S0032-daemon-protocol-completion.md +123 -0
  48. package/docs/spec/ship/S0033-webui-skeleton-routing.md +92 -0
  49. package/docs/spec/ship/S0034-webui-device-settings.md +121 -0
  50. package/docs/spec/ship/S0035-webui-device-handshake.md +83 -0
  51. package/docs/spec/ship/S0036-webui-project-session-sync.md +70 -0
  52. package/docs/spec/ship/S0037-webui-chatbox-v1.md +97 -0
  53. package/docs/spec/ship/S0038-webui-cancel-multiclient.md +65 -0
  54. package/docs/spec/ship/S0039-webui-e2e-newchat.md +74 -0
  55. package/docs/spec/ship/S0040-webui-codex-visual-tokens.md +227 -0
  56. package/docs/spec/ship/S0041-webui-markdown-and-tool-block.md +248 -0
  57. package/docs/spec/ship/S0042-webui-streaming-ux-autoscroll.md +130 -0
  58. package/docs/spec/ship/S0043-startup-ergonomics.md +278 -0
  59. package/docs/spec/ship/S0044-webui-chatbox-rebuild.md +556 -0
  60. package/docs/spec/ship/S0045-webui-card-sidebar-and-session-fixes.md +469 -0
  61. package/docs/spec/ship/S0046-webui-empty-composer-and-lazy-session.md +428 -0
  62. package/docs/spec/ship/S0047-webui-project-hover-newchat-and-dynamic-greeting.md +176 -0
  63. package/docs/spec/ship/S0048-device-level-host-project-registry.md +253 -0
  64. package/docs/spec/ship/S0049-webui-add-project-directory-browser.md +217 -0
  65. package/docs/spec/ship/S0050-instruction-snapshot-and-agents-assembly.md +338 -0
  66. package/docs/spec/ship/S0051-harness-item-and-system-reminder.md +190 -0
  67. package/docs/spec/ship/S0052-follow-up-queue-and-dual-loop.md +195 -0
  68. package/docs/spec/ship/S0053-skill-index-and-skill-tool.md +252 -0
  69. package/docs/spec/ship/S0054-webui-running-message-behavior.md +72 -0
  70. package/docs/spec/ship/S0055-webui-composer-acceptance-and-queue-strip.md +68 -0
  71. package/docs/spec/ship/S0056-relay-and-hosted-webui-contract.md +106 -0
  72. package/docs/spec/ship/S0057-relay-service-protocol-skeleton.md +161 -0
  73. package/docs/spec/ship/S0058-host-outbound-relay-and-pair-command.md +138 -0
  74. package/docs/spec/ship/S0059-relay-transport-and-hosted-webui-connector.md +140 -0
  75. package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.md +132 -0
  76. package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.verification.md +90 -0
  77. package/docs/spec/ship/S0061-hosted-defaults-and-cli-command-surface.md +208 -0
  78. package/docs/spec/ship/S0062-npm-package-and-release-workflow.md +166 -0
  79. package/docs/spec/tools.md +173 -0
  80. package/package.json +51 -0
@@ -0,0 +1,338 @@
1
+ # S0050 — Instruction Snapshot And AGENTS.md Assembly
2
+
3
+ ## Goal
4
+
5
+ 把 Scorel 当前 `systemPrompt = undefined` 的 runtime 路径升级为正式的 harness input assembly:
6
+
7
+ - session 初始化时发现并装配 `AGENTS.md`
8
+ - 生成一份冻结的 `instruction_snapshot`
9
+ - 将其作为一等 PersistentEvent 写入 session JSONL
10
+ - 后续 turn 从 snapshot 派生 provider-level `systemPrompt`
11
+ - 当前 session 内 system prompt 不因磁盘文件变动而漂移
12
+
13
+ 本 spec 只定义 **instruction snapshot 与 runtime 接线**。不在本轮引入 GUI、HTTP API、自动刷新 snapshot 或 `<system-reminder>` 扩展语义。
14
+
15
+ ## Why Now
16
+
17
+ 当前 `M7` 已被定义为 Agent Runtime Quality。现状存在一个明确缺口:
18
+
19
+ - `packages/core/src/runtime/index.ts` 已支持 `executeTurn(context, systemPrompt, options)`
20
+ - `packages/core/src/provider/pi-ai.ts` 已支持把 `systemPrompt` 作为独立 provider 字段传给 pi-ai
21
+ - 但 `packages/daemon/src/index.ts` 仍以 `undefined` 调用 runtime
22
+
23
+ 结果是:
24
+
25
+ - `AGENTS.md` 尚未进入真实产品主链路
26
+ - session 恢复、clone、branch、审计都无法回答“这个会话当时到底吃了哪份 instruction set”
27
+ - 未来 memory / workspace summary / runtime guidance 没有稳定挂点
28
+
29
+ 在继续做 `<system-reminder>`、diagnostics、eval 之前,必须先把 session-scoped instruction snapshot 模型锁定。
30
+
31
+ ## Scope
32
+
33
+ ### 1. AGENTS.md Discovery
34
+
35
+ V1 discovery 规则固定如下:
36
+
37
+ - 发现基准是 session 初始化时的当前 `cwd`
38
+ - 从 `cwd` 逐级向上查找 project-scope `AGENTS.md`
39
+ - 如果 `cwd` 在 Git repository 内,project walk 在最近的 Git root 停止
40
+ - 如果 `cwd` 不在 Git repository 内,project walk 在用户 home `~` 前停止;不把 home 自身作为 project scope 读取
41
+ - 额外读取 `~/.scorel/AGENTS.md` 作为用户级全局源
42
+ - 所有命中的 `AGENTS.md` **全部加载**,不是只取最近一个
43
+ - discovery 结果在 session 初始化时冻结;当前 session 后续不动态重算
44
+
45
+ 优先级模型:
46
+
47
+ - 高层目录先发现,低层目录后发现
48
+ - 更接近当前 `cwd` 的文件优先级更高
49
+ - 用户级全局源独立于 project walk;它不是 project-scope parent
50
+ - 当前 V1 只支持 `AGENTS.md`
51
+ - 不支持:
52
+ - `AGENTS.override.md`
53
+ - `SCOREL.md`
54
+ - `scrolls.md`
55
+ - fallback filenames
56
+ - include/import 展开
57
+
58
+ ### 2. First-Class `instruction_snapshot` PersistentEvent
59
+
60
+ 协议新增一等 PersistentEvent:
61
+
62
+ ```typescript
63
+ interface InstructionSnapshotEvent extends PersistentEventBase {
64
+ type: "instruction_snapshot";
65
+ snapshot: InstructionSnapshot;
66
+ }
67
+ ```
68
+
69
+ 它的语义是:
70
+
71
+ - 记录一个 session 初始化时冻结下来的 instruction assembly 结果
72
+ - 用于 resume、clone、branch、audit、diagnostics 和 runtime system prompt 派生
73
+ - 不直接作为普通 message 进入 LLM context
74
+
75
+ V1 规则:
76
+
77
+ - 一个 session 默认只追加一条 `instruction_snapshot`
78
+ - 追加时机是:
79
+ - 首次 user message 持久化前或紧邻其前
80
+ - 保证该 snapshot 在 JSONL 中先于首个 user turn 出现
81
+ - 不支持 session 中途自动刷新 snapshot
82
+
83
+ ### 3. Structured Snapshot Schema
84
+
85
+ `instruction_snapshot` 不存一段无结构大字符串,而存结构化 section。
86
+
87
+ V1 section 顺序固定为:
88
+
89
+ 1. `baseline`
90
+ 2. `agents`
91
+ 3. `memory`
92
+ 4. `workspace`
93
+ 5. `environment`
94
+ 6. `time`
95
+
96
+ 建议协议形态:
97
+
98
+ ```typescript
99
+ type InstructionSectionKind =
100
+ | "baseline"
101
+ | "agents"
102
+ | "memory"
103
+ | "workspace"
104
+ | "environment"
105
+ | "time";
106
+
107
+ interface InstructionSource {
108
+ sourceType: "builtin" | "agents_md" | "memory";
109
+ path?: string;
110
+ scope?: "global_user" | "project";
111
+ priority?: number;
112
+ content?: string;
113
+ }
114
+
115
+ interface InstructionSection {
116
+ kind: InstructionSectionKind;
117
+ frozenAt: number;
118
+ sources?: InstructionSource[];
119
+ renderedBlock: string;
120
+ data?: Record<string, unknown>;
121
+ }
122
+
123
+ interface InstructionSnapshot {
124
+ version: 1;
125
+ cwd: string;
126
+ sections: InstructionSection[];
127
+ }
128
+ ```
129
+
130
+ V1 约束:
131
+
132
+ - 所有 section 以固定顺序写入 snapshot
133
+ - 每个 section 至少保留 `kind`、`frozenAt`、`renderedBlock`
134
+ - `agents` section 必须保留来源块:
135
+ - `path`
136
+ - `scope`
137
+ - `priority`
138
+ - `content`
139
+ - `memory`、`workspace`、`environment`、`time` 即使当下内容很轻,也必须进入结构化 schema,而不是以后再另起另一套快照模型
140
+
141
+ ### 4. Section Meaning
142
+
143
+ #### `baseline`
144
+
145
+ Scorel 自带的静态系统提示词,不来自用户文件。
146
+
147
+ 包括但不限于:
148
+
149
+ - agent/product identity
150
+ - 输出与安全高层原则
151
+ - 工具使用的高层纪律
152
+ - `<system-reminder>` 解释性声明
153
+
154
+ 这里冻结的是 **baseline prompt block**,不是未来所有实现细节的不可变版本数据库。
155
+
156
+ #### `agents`
157
+
158
+ `AGENTS.md` discovery 与装配结果。
159
+
160
+ 要求:
161
+
162
+ - 以带来源分块的形式保存
163
+ - `renderedBlock` 是最终进入 provider-level system prompt 的 AGENTS block
164
+ - 当前 V1 不做 include/import 扩展
165
+
166
+ #### `memory`
167
+
168
+ 进入 system prompt 的 memory block。
169
+
170
+ V1 可以先接入最小来源,甚至为空 block,但 schema 必须预留该 section。后续 memory specs 只能扩展其来源,不应再改变 snapshot 总模型。
171
+
172
+ #### `workspace`
173
+
174
+ 工作区结构摘要,而不是全量目录树。
175
+
176
+ V1 建议只包含:
177
+
178
+ - `cwd`
179
+ - repo root / workspace root(如可得)
180
+ - monorepo/workspace 摘要
181
+ - 关键顶层模块/目录摘要
182
+
183
+ 不要把 `find .` 或大体量树结构塞进该 section。
184
+
185
+ #### `environment`
186
+
187
+ 运行环境摘要,例如:
188
+
189
+ - platform
190
+ - shell
191
+ - OS version
192
+ - git/worktree 约束
193
+ - 其他需要稳定告知 agent 的运行环境信息
194
+
195
+ #### `time`
196
+
197
+ 时间快照,例如:
198
+
199
+ - session start timestamp
200
+ - local timezone
201
+ - human-readable date string
202
+
203
+ V1 明确接受它在长会话中会 stale,因为当前产品选择就是 session 初始化后冻结 prompt。
204
+
205
+ ### 5. Runtime Integration
206
+
207
+ `instruction_snapshot` 的正确用途不是进入 `buildContext()` 普通消息流,而是:
208
+
209
+ 1. session 初始化时生成并 append 到 JSONL
210
+ 2. daemon/lane 在内存中持有这份 snapshot
211
+ 3. 每次 `runtime.executeTurn()` 前,把 snapshot sections 渲染为 provider-level `systemPrompt`
212
+ 4. 通过已有独立参数传给 runtime/provider
213
+
214
+ 也就是:
215
+
216
+ ```text
217
+ instruction_snapshot -> renderSystemPrompt(snapshot) -> executeTurn(context, systemPrompt, ...)
218
+ ```
219
+
220
+ 不允许:
221
+
222
+ - 把最终 provider-level system prompt 当普通 `message` / `custom_message` 塞进 `buildContext()`
223
+ - 依赖 `role = "system"` message 让 pi-ai 推导 system prompt
224
+
225
+ 原因是当前 `packages/core/src/provider/pi-ai.ts` 会把 `role === "system"` 的 ScorelMessage 降成 provider `user` message,而不是 provider-level `systemPrompt`。
226
+
227
+ ### 6. Session / Resume / Clone / Branch Semantics
228
+
229
+ V1 规则:
230
+
231
+ - loadSession 时必须能读出 `instruction_snapshot`
232
+ - 恢复当前 session 时继续使用这条 snapshot
233
+ - clone 成新 session 时:
234
+ - 默认复制源 session 的 snapshot 作为新 session 的初始 snapshot
235
+ - 不重新从磁盘发现 `AGENTS.md`
236
+ - 同一 session 内 branch 到旧 event 时:
237
+ - 继续使用本 session 既有 snapshot
238
+ - 不追加新的 `instruction_snapshot`
239
+ - branch 只改变 conversation tree 的 leaf,不改变 harness input world
240
+
241
+ 理由:
242
+
243
+ - clone 是复制已有 session 状态到新 session,不是按当前磁盘环境重新初始化 prompt world
244
+ - branch 是同一 session 内的 conversation-tree 分叉,更不应该重新发现磁盘指令
245
+
246
+ ## Explicitly Not In Scope
247
+
248
+ - `<system-reminder>` 新注入来源与 merge 语义扩展
249
+ - memory 检索/召回策略本身
250
+ - GUI 或 WebUI 对 snapshot 的可视化
251
+ - 自动刷新 snapshot、cache invalidation 后追加新 snapshot
252
+ - `AGENTS.override.md`
253
+ - `SCOREL.md` / `scrolls.md`
254
+ - fallback filenames
255
+ - include/import 语法
256
+ - 基于目标文件路径的动态重算
257
+ - 让 `instruction_snapshot` 进入普通 LLM context message history
258
+ - 重写当前完整 EventTypeHandler/convertToLlm 架构;本 spec 只要求新事件具备明确 skip/display 行为
259
+
260
+ ## Required Tests
261
+
262
+ ### Protocol
263
+
264
+ - 新增 `instruction_snapshot` 到 PersistentEvent union。
265
+ - `instruction_snapshot` round-trip 持久化与解析通过。
266
+
267
+ ### Session Core
268
+
269
+ - session JSONL 可在 header 后追加 `instruction_snapshot` 再追加普通消息。
270
+ - `buildContext()` 不把 `instruction_snapshot` 当普通 message 带进消息历史。
271
+ - loadSession / append 对该事件类型通过校验。
272
+
273
+ ### AGENTS.md Discovery
274
+
275
+ - project walk 从 `cwd` 到最近 Git root;无 Git root 时到 home 前停止。
276
+ - `~/.scorel/AGENTS.md` 作为用户级全局源进入 snapshot。
277
+ - 近处文件优先级高于远处文件。
278
+ - 当前 session 初始化后,即使磁盘上 `AGENTS.md` 改变,后续 turn 仍使用原 snapshot。
279
+
280
+ ### Snapshot Shape
281
+
282
+ - snapshot 含固定 section 顺序:
283
+ - baseline
284
+ - agents
285
+ - memory
286
+ - workspace
287
+ - environment
288
+ - time
289
+ - `agents` section 保留带来源的 source blocks。
290
+ - `workspace` section 是摘要而不是全量树。
291
+
292
+ ### Runtime Integration
293
+
294
+ - 首个 turn 之前若无 snapshot,daemon 会先生成并 append snapshot,再调用 runtime。
295
+ - 后续 turn 复用同一 snapshot 渲染的 system prompt。
296
+ - `packages/daemon/src/index.ts` 不再以 `undefined` 调用 runtime。
297
+ - pi-ai request payload 能看到 provider-level `systemPrompt`。
298
+
299
+ ### Resume / Clone / Branch
300
+
301
+ - reload 现有 session 后仍能读取并使用相同 snapshot。
302
+ - clone 后新 session 继承源 session snapshot,而不是重新做磁盘 discovery。
303
+ - branch 到同一 session 的旧 event 时不生成新 snapshot。
304
+
305
+ ## Likely Files
306
+
307
+ ```text
308
+ packages/protocol/src/events.ts
309
+ packages/protocol/src/index.test.ts
310
+ packages/core/src/session/index.ts
311
+ packages/core/src/session/session.test.ts
312
+ packages/core/src/runtime/index.ts
313
+ packages/core/src/provider/pi-ai.ts
314
+ packages/core/src/provider/pi-ai.test.ts
315
+ packages/daemon/src/index.ts
316
+ packages/daemon/src/index.test.ts
317
+ packages/daemon/src/projects/sessions.ts
318
+ docs/spec/session.md
319
+ docs/spec/events.md
320
+ docs/spec/runtime.md
321
+ ```
322
+
323
+ ## Risks And Boundaries
324
+
325
+ - 如果把完整最终 provider prompt 冻结到 JSONL,会把 baseline wording、tool contract wording 和 runtime baseline 一起版本化,兼容边界过重;V1 只冻结结构化 snapshot 与其 rendered blocks。
326
+ - `time` section 会 stale,这是产品明确接受的冻结代价,不算 bug。
327
+ - `memory` section 当前即使实现很轻,也必须占住结构化位置,避免后续再改 snapshot 总模型。
328
+ - 现有 `buildContext()` 仍是 M1 风格“只收 message”的实现;本 spec 不强迫一次性重构为完整 EventTypeHandler 架构,但要求 `instruction_snapshot` 能在现有边界下被稳定跳过。
329
+
330
+ ## Done When
331
+
332
+ - session 首次进入主链路时会 append 一条 `instruction_snapshot`
333
+ - snapshot 使用固定 section schema,包含 `baseline / agents / memory / workspace / environment / time`
334
+ - `AGENTS.md` project discovery 从 `cwd` 到最近 Git root 或 home 前停止,并包含 `~/.scorel/AGENTS.md`
335
+ - 当前 session 内 system prompt 由 snapshot 派生且保持冻结
336
+ - runtime 不再以 `undefined` 调用 provider-level `systemPrompt`
337
+ - 自动测试与 typecheck 通过
338
+ - 完成后 commit:`S0050: feat: add instruction snapshot and agents assembly`
@@ -0,0 +1,190 @@
1
+ # S0051 — Harness Item And System Reminder Conversion
2
+
3
+ ## Goal
4
+
5
+ 把 Scorel 的 runtime guidance 从 ad-hoc message 拼接升级为正式的 `harness_item` 事件模型:
6
+
7
+ - 用一等 PersistentEvent 表达 harness 注入项
8
+ - 用 `<system-reminder>` 作为进入 LLM message stream 的统一 envelope
9
+ - 区分 item 的真实来源和 LLM 传输形式
10
+ - 支持 steer 这类当前 turn 引导输入
11
+ - 为后续 follow-up queue、Skill listing/delta、memory、hook 等注入建立共用管道
12
+
13
+ 本 spec 只做 `harness_item` 事件、LM/display conversion 和 system-reminder 格式。Queue 双 loop 与 Skill index 不在本轮实现。
14
+
15
+ ## Why Now
16
+
17
+ S0050 只解决 provider-level `systemPrompt` 的冻结和装配。M7 还需要一条独立管道,把“不是普通用户消息、但模型必须看到”的 runtime guidance 放进 LLM context。
18
+
19
+ 这些信息包括:
20
+
21
+ - 用户运行中 steer 的引导
22
+ - Skill listing / Skill delta
23
+ - memory 或 hook 产生的上下文
24
+ - runtime notice、date change、attachment metadata
25
+
26
+ 如果这些内容直接伪装成普通 user message,UI、审计和 replay 都会混乱。如果把它们放进 provider system prompt,又会破坏 session-scoped snapshot 的冻结语义。因此需要 `harness_item`。
27
+
28
+ ## Scope
29
+
30
+ ### 1. Protocol Event
31
+
32
+ 新增一等 PersistentEvent:
33
+
34
+ ```typescript
35
+ type HarnessItemKind =
36
+ | "attachment"
37
+ | "skill_listing"
38
+ | "skill_delta"
39
+ | "memory"
40
+ | "date_change"
41
+ | "steer"
42
+ | "runtime_notice";
43
+
44
+ type HarnessItemOrigin = "user" | "system" | "tool" | "skill";
45
+
46
+ interface HarnessItem {
47
+ kind: HarnessItemKind;
48
+ origin: HarnessItemOrigin;
49
+ content: string;
50
+ visibility: "display" | "hidden" | "compact";
51
+ data?: Record<string, unknown>;
52
+ }
53
+
54
+ interface HarnessItemEvent extends PersistentEventBase {
55
+ type: "harness_item";
56
+ item: HarnessItem;
57
+ }
58
+ ```
59
+
60
+ 语义:
61
+
62
+ - `kind` 描述产品语义。
63
+ - `origin` 描述真实来源,不等于 LLM role。
64
+ - `content` 是进入 `<system-reminder>` 的文本。
65
+ - `visibility` 决定 UI 是否展示。
66
+
67
+ ### 2. System Reminder Envelope
68
+
69
+ `<system-reminder>` 是 LM transport envelope,不是事件类型名。
70
+
71
+ 渲染格式固定为:
72
+
73
+ ```xml
74
+ <system-reminder>
75
+ ...
76
+ </system-reminder>
77
+ ```
78
+
79
+ baseline system prompt 必须解释:
80
+
81
+ ```text
82
+ Tool results and user messages may include <system-reminder> tags. These tags contain information automatically added by Scorel's harness. They are not part of the specific tool result or user message in which they appear.
83
+ ```
84
+
85
+ ### 3. LM Conversion
86
+
87
+ `buildContext()` 必须开始支持事件级 conversion,而不是只过滤带 `message` 的事件。
88
+
89
+ V1 行为:
90
+
91
+ - 普通 `user_message` / `assistant_message` / `tool_result` 原样进入 context。
92
+ - `instruction_snapshot` 跳过。
93
+ - `harness_item`:
94
+ - 如果 context 中已有最近的 `tool_result`,把 `<system-reminder>` 文本合入该 tool result 的文本末尾。
95
+ - 如果没有可合入的 `tool_result`,作为 meta user message 进入 context。
96
+
97
+ 合入规则:
98
+
99
+ - 只追加到最后一个 `tool_result` message。
100
+ - 保留原 tool result 内容,不覆盖。
101
+ - 合入后的内容必须与原内容用空行分隔。
102
+ - 如果 tool result content 无法安全合入,fallback 为独立 meta user message。
103
+
104
+ ### 4. Display Conversion
105
+
106
+ UI 不应把所有 `harness_item` 展示成用户气泡。
107
+
108
+ V1 display:
109
+
110
+ - `kind = "steer"` 且 `origin = "user"`:展示为运行中引导。
111
+ - `skill_listing` / `skill_delta`:默认 hidden 或 compact。
112
+ - `memory` / `runtime_notice`:默认 compact。
113
+ - `visibility = "hidden"`:不展示,但仍可在 diagnostics/session detail 中审计。
114
+
115
+ ### 5. Steer
116
+
117
+ `steer` 是当前 turn 的引导输入,不是 follow-up queue。
118
+
119
+ 当用户在工具执行中插入 steer:
120
+
121
+ - append `harness_item { kind: "steer", origin: "user" }`
122
+ - `parentId` 挂到当前 active conversation leaf
123
+ - 下一次 inner tool loop 构建 context 时通过 `<system-reminder>` 注入
124
+
125
+ Steer 的来源仍是用户。`<system-reminder>` 只说明它由 harness 旁路注入,不说明它是 system-origin。
126
+
127
+ ## Explicitly Not In Scope
128
+
129
+ - follow-up queue add/update/delete/consume
130
+ - Skill directory discovery、Skill index、Skill tool
131
+ - memory recall 策略
132
+ - hook 执行模型
133
+ - UI 完整设计
134
+ - compact / rewind / branch 完整 handler 架构重写
135
+
136
+ ## Required Tests
137
+
138
+ ### Protocol
139
+
140
+ - `harness_item` 加入 PersistentEvent union。
141
+ - round-trip parse / serialize 通过。
142
+ - `origin` 和 `kind` 非法值会失败。
143
+
144
+ ### Session Core
145
+
146
+ - `buildContext()` 会跳过 `instruction_snapshot`。
147
+ - `harness_item` 在无 tool result 时变成 meta user message。
148
+ - `harness_item` 在已有 tool result 时合入最后一个 tool result。
149
+ - `steer` 的 `origin = "user"` 被保留到 event payload。
150
+
151
+ ### Display
152
+
153
+ - `steer` 不渲染成普通用户气泡。
154
+ - hidden harness item 不进入普通 transcript。
155
+
156
+ ### Runtime
157
+
158
+ - daemon 可以在当前 active leaf 后 append steer harness item。
159
+ - 下一次 runtime context 包含对应 `<system-reminder>`。
160
+
161
+ ## Likely Files
162
+
163
+ ```text
164
+ packages/protocol/src/events.ts
165
+ packages/protocol/src/index.test.ts
166
+ packages/core/src/session/index.ts
167
+ packages/core/src/session/session.test.ts
168
+ packages/daemon/src/index.ts
169
+ packages/daemon/src/index.test.ts
170
+ apps/webui/lib/events/*
171
+ docs/spec/events.md
172
+ docs/spec/session.md
173
+ docs/spec/runtime.md
174
+ ```
175
+
176
+ ## Risks And Boundaries
177
+
178
+ - 事件名不能叫 `system_reminder`,否则会混淆来源;`steer` 是 user-origin。
179
+ - 不要把 harness item 放进 provider-level `systemPrompt`。
180
+ - 不要把 display 逻辑和 LM conversion 混在一起。
181
+ - V1 可以保留轻量 hardcoded conversion,但 public spec 必须按 handler/converter 语义描述,避免继续扩散 M1-only `buildContext()`。
182
+
183
+ ## Done When
184
+
185
+ - `harness_item` 事件可以持久化、恢复、replay。
186
+ - `buildContext()` 能把 harness item 转成 `<system-reminder>` meta user message 或合入 tool result。
187
+ - steer 可以作为 user-origin harness item 注入当前 turn。
188
+ - UI/display 不把 harness item 误显示为普通用户输入。
189
+ - 自动测试与 typecheck 通过。
190
+ - 完成后 commit:`S0051: feat: add harness item system reminders`