Forge 核心架构与演化协议¶
状态:Accepted Target Architecture
版本:1.0(2026-07-26)
规范源:本文件定义 Forge 的目标产品边界、领域模型和协议。与旧 Forge、Craft、Agent、GUI 文档冲突时,以本文件为准。 实现状态:目标设计,不能据此宣称功能已经落地;公开能力仍以代码和测试为准。
本文使用以下规范词:
- 必须(MUST):违反即破坏协议或产品边界。
- 应该(SHOULD):默认遵循;偏离时必须记录理由。
- 可以(MAY):兼容协议的可选实现。
1. 决策摘要¶
Pulsing 只有一个核心:Actor Runtime。Forge、应用协议、GUI、CLI 和 Python SDK 都建立在它之上。
flowchart TB
subgraph Core["Pulsing Core"]
Actor["Actor Runtime<br/>mailbox · lifecycle · stream · cluster · transport"]
end
subgraph Product["上层产品与协议"]
App["App Protocol<br/>快速声明与部署"]
Forge["Forge<br/>自进化 Agent Runtime"]
end
subgraph Clients["Forge 客户端"]
CLI["CLI / Headless"]
GUI["GUI"]
PySDK["Python SDK"]
API["Remote API"]
end
subgraph Exec["执行后端"]
RustExec["Rust Executors"]
PyExec["Python Worker"]
ActorExec["Actor Workers"]
end
Actor --> App
Actor --> Forge
CLI & GUI & PySDK & API --> Forge
Forge --> RustExec & PyExec & ActorExec
ActorExec --> Actor
核心决策:
- Actor Runtime 是唯一基础设施核心,不知道 Forge、LLM、GUI 或工作区。
- App Protocol 是快捷部署协议,把高级应用声明编译为 Actor Runtime 操作,不形成第二套 Actor 模型。
- Forge 是自进化 Agent Runtime,拥有会话、Agent loop、事件、工具治理、工作区版本、评估与晋升语义。
- Rust Forge 是控制面和规范实现;Python 是 SDK、Provider/Tool 适配器和受控执行后端。
- GUI、CLI、Python SDK 是同一 Forge API 的客户端,不得各自拥有另一套 Agent 状态机。
- 本地优先、按边界 Actor 化;不是每个 Forge 内部对象都必须成为 Actor。
1.1 实现进度¶
截至 2026-07-26,第一条本地垂直链路已经落地:
| 能力 | 状态 |
|---|---|
Rust SessionId / TurnId / CommandId 与版本化 Command/Event |
已实现初版 |
| Session/Turn reducer、单活跃 Turn、连续事件序号 | 已实现 |
command_id 幂等、in-memory EventStore、replay/subscription |
已实现 |
持久 ForgeAgent 对话状态 |
已接入本地 Session |
LocalForgeClient |
已实现 |
| CLI 复用同一个 Forge Session | 已迁移 |
GUI 按 Session 路由事件并通过 CancelTurn 停止 |
已迁移首版 |
| Turn 级取消所有权、Tool/Model 资源登记、shell/UnifiedExec/PTY 进程树回收 | 已实现首版 |
| 文件 EventStore、snapshot/restart recovery | 未实现 |
Python ForgeClient + 默认 ForgeAgent 客户端投影 |
已实现初版 |
| Python Tool/Provider worker protocol | 未实现 |
| Candidate/Evaluation/Promotion/Rollback | 未实现 |
该表只描述实现进度,不降低本文其余不变量。
2. 产品边界与依赖规则¶
2.1 Actor Runtime¶
Actor Runtime 负责:
- Actor 身份、邮箱、生命周期和 supervision;
ask、tell、stream 与背压;- spawn、resolve、placement、集群成员和故障检测;
- Message/Tensor 传输;
- 可观测性和 Rust/Python 绑定。
Actor Runtime 不得依赖:
- Forge Session、Tool 或 Evolution 类型;
- LLM Provider;
- GUI/CLI;
.pulsing工作区产品语义。
2.2 App Protocol¶
App Protocol 负责把用户声明转换为版本化 ApplicationSpec / ActorSpec:
decorator / YAML / CLI
→ validate ApplicationSpec
→ derive ActorSpec + routes + resources
→ spawn / resolve / expose
App Protocol 不得重新实现 mailbox、registry、placement 或 cluster scheduler。对外命名应该使用 App Protocol、ApplicationSpec 或 ServiceSpec,避免与底层 Actor Runtime 混淆。
2.3 Forge¶
Forge 负责:
- 持久
Session、Turn和 Agent loop; - 模型调用的编排协议,但不强绑定某家 Provider;
- Tool registry、capability、审批、sandbox 和执行;
- 工作区 revision、candidate artifact 和审计事件;
- Evaluation、Promotion、Observation 和 Rollback;
- 本地、Python worker 与 Actor worker 的统一执行语义。
Forge 不得把 UI 状态作为执行状态,不得要求集群才能本地运行,也不得把未经评估的“自动修改”称为“演化”。
2.4 依赖方向¶
允许:
client → forge → actor-runtime
app-protocol → actor-runtime
python-sdk → forge binding
python-worker → language-neutral Forge protocol
禁止:
actor-runtime → forge
forge-core → gui
forge-core → concrete CLI
rust control state → Python-only source of truth
gui state → execution ownership
3. Forge 领域模型¶
所有 ID 都是不可复用的 opaque identifier。调用方不得从字符串格式推导语义。
| 对象 | 作用 | 不变量 |
|---|---|---|
Session |
持久 Agent 工作上下文 | 独立事件序列和策略快照 |
Turn |
一次用户目标到最终结果的执行 | 属于一个 Session;默认同 Session 单活跃 Turn |
Event |
已发生事实 | append-only;Session 内单调序号 |
ToolCall |
一次受治理的工具调用 | 有 capability、输入摘要、结果或终止原因 |
WorkspaceRevision |
可验证的工作区状态 | 内容寻址或包含完整 hash manifest |
Candidate |
待评估的不可变变更提案 | 指向 baseline、artifact 和 evolution target |
EvaluationRun |
Candidate 在固定条件下的一次评估 | 输入、环境、结果可审计 |
EvaluationReport |
多个评估运行的归并结论 | 不可变;包含通过条件和证据 |
Promotion |
将 Qualified Candidate 设为活动版本 | 受 policy 和 approval 约束 |
Rollback |
从已晋升版本恢复到已知安全版本 | 产生新事件,不改写历史 |
ClientCursor |
客户端的消费位置 | 只影响投影,不影响执行状态 |
3.1 标识与关联¶
每个命令和事件必须携带以下关联字段中的适用部分:
command_id 是幂等键;correlation_id 串起一次用户操作;causation_id 指向直接导致当前事件的命令或事件。
4. 版本化 Session 协议¶
4.1 Session 状态¶
stateDiagram-v2
[*] --> Active: CreateSession
Active --> Running: StartTurn
Running --> WaitingInput: InputRequired
WaitingInput --> Running: ProvideInput
Running --> WaitingApproval: ApprovalRequired
WaitingApproval --> Running: Grant
WaitingApproval --> Running: Deny and continue
Running --> Active: TurnCompleted
Running --> Cancelling: CancelTurn
Cancelling --> Active: TurnCancelled
Active --> Closed: CloseSession
Closed --> [*]
Session 状态与 Turn 状态必须分开存储。客户端断开、GUI 切换页面或订阅者消失不得改变这两个状态。
4.2 命令¶
协议至少定义:
| 命令 | 语义 |
|---|---|
CreateSession |
创建 Session,并冻结初始 policy/provider/workspace 引用 |
StartTurn |
在 Session 中开始一个 Turn |
CancelTurn |
请求取消指定 Turn |
ProvideInput |
响应结构化用户输入请求 |
ResolveApproval |
批准或拒绝 capability 请求 |
UpdateSessionPolicy |
对后续操作更新策略;不能追溯修改历史 |
CloseSession |
不再接受新 Turn;按策略取消或等待当前 Turn |
GetSessionSnapshot |
获取当前投影和最后事件序号 |
SubscribeEvents |
从指定 after_seq 订阅事件 |
所有改变状态的命令必须包含:
{
"protocol": "forge.session",
"version": {"major": 1, "minor": 0},
"command_id": "opaque",
"session_id": "opaque",
"expected_seq": 42,
"payload": {}
}
expected_seq 用于乐观并发控制;不需要强一致检查的幂等命令可以省略。
4.3 Session 不变量¶
- 默认每个 Session 最多一个 Running/Waiting/Cancelling Turn。
- 同一
command_id重试必须返回等价结果,不能重复产生副作用。 StartTurn被接受后必须先持久化TurnStarted,再发起模型或工具副作用。- 工具调用必须先记录 intent,再 dispatch;完成、失败和取消都必须有终止事件。
CancelTurn是请求,不是假定完成;只有TurnCancelled才表示执行已停止。- 无法立即终止的后端必须标记
cancellation_pending,禁止向客户端报告已停止。 - Session 恢复必须从 snapshot + events 重建,不能依赖 GUI/CLI 内存。
5. 版本化 Event 协议¶
5.1 Event envelope¶
{
"protocol": "forge.event",
"version": {"major": 1, "minor": 0},
"event_id": "opaque",
"session_id": "opaque",
"seq": 43,
"occurred_at": "RFC3339",
"kind": "tool.completed",
"turn_id": "opaque",
"correlation_id": "opaque",
"causation_id": "opaque",
"payload": {},
"redaction": {"class": "public"}
}
5.2 顺序与投递保证¶
- Forge 保证 单 Session 内
seq严格单调且无重复。 - Forge 不保证跨 Session 全局顺序。
- 订阅采用 at-least-once delivery;客户端必须按
event_id或(session_id, seq)去重。 SubscribeEvents(after_seq=N)返回seq > N的历史和实时事件。- 事件持久化后才能对订阅者可见。
- 客户端发现序号缺口时必须重新读取,不得自行猜测缺失状态。
5.3 最小事件集合¶
| 域 | 事件 |
|---|---|
| Session | session.created, session.policy_updated, session.closed |
| Turn | turn.started, turn.output_delta, turn.completed, turn.failed, turn.cancel_requested, turn.cancelled |
| Model | model.requested, model.completed, model.failed, model.usage_recorded |
| Tool | tool.requested, tool.approval_required, tool.started, tool.output_delta, tool.completed, tool.failed, tool.cancelled |
| Workspace | workspace.revision_created, workspace.restored |
| Evolution | candidate.created, candidate.prepared, evaluation.started, evaluation.completed, candidate.qualified, candidate.rejected, promotion.requested, candidate.promoted, candidate.rolled_back |
5.4 兼容性¶
major变化表示破坏兼容;不支持时必须明确拒绝。minor变化只能增加 optional field 或新 event kind。- 客户端必须忽略未知 optional field。
- 投影客户端可以忽略未知 event kind,但必须推进 cursor 并保留原始 envelope。
- 命令处理器不得静默忽略未知命令。
- 持久事件不得原地迁移;升级通过新 projector 或显式 migration event 完成。
5.5 敏感数据¶
事件默认不得保存明文 secret、完整环境变量或未经限制的模型凭据。大输出和二进制内容应进入 artifact store,事件只记录 hash、size、media type 和受控引用。
6. Evolution 协议¶
6.1 什么是演化¶
只有满足以下条件的变更才称为 Evolution:
- 有明确 baseline;
- 产生不可变 candidate;
- 在预先声明的 evaluation suite 上运行;
- 根据 promotion policy 比较 candidate 与 baseline;
- 有独立的批准和原子晋升;
- 晋升后持续观察并可以回滚。
不经过评估的代码、Prompt 或 Tool 修改只是 mutation,不是 evolution。
6.2 Evolution target 风险级别¶
| 级别 | Target | 默认策略 |
|---|---|---|
| L0 | Prompt、Skill 内容、Workflow 配置 | 可自动评估;满足 policy 后可配置自动晋升 |
| L1 | Tool schema、Provider 参数、路由策略 | 需要回归评估;默认人工批准 |
| L2 | 用户工作区代码、依赖和部署配置 | 必须 sandbox + 测试;人工批准 |
| L3 | Forge 或评估器自身代码 | 独立控制器、双重批准、禁止直接原地替换 |
第一阶段必须只支持 L0。L2 稳定后才可以设计 L3 self-hosting。
6.3 Candidate¶
Candidate 创建后必须不可变,至少包含:
candidate_id
target_kind
target_ref
baseline_ref
artifact_ref + content_hash
producer_session_id + producer_turn_id
declared_goal
evaluation_suite_ref + version
promotion_policy_ref + version
risk_level
created_at
任何内容变化都必须产生新 candidate_id,不能覆盖旧 Candidate。
7. Candidate → Evaluation → Promotion → Rollback¶
7.1 状态机¶
stateDiagram-v2
[*] --> Draft: CreateCandidate
Draft --> Prepared: Materialize + validate artifact
Prepared --> Evaluating: StartEvaluation
Evaluating --> Qualified: Policy passed
Evaluating --> Rejected: Policy failed / invalid
Qualified --> AwaitingApproval: Promotion requested
AwaitingApproval --> Promoted: Approved + atomic switch
AwaitingApproval --> Rejected: Denied / expired
Promoted --> Observing: Post-promotion checks
Observing --> Accepted: Observation window passed
Promoted --> RolledBack: Guard triggered / manual rollback
Observing --> RolledBack: Regression detected
Draft --> Archived: Abandon
Prepared --> Archived: Abandon
Rejected --> Archived
Accepted --> Archived: Superseded
RolledBack --> Archived
状态只能通过命令和持久事件转换。状态字段不能被客户端直接修改。
7.2 Evaluation¶
每次 EvaluationRun 必须记录:
- candidate 与 baseline 的不可变引用;
- suite 名称、版本和 hash;
- runner 版本、依赖锁和 sandbox profile;
- 输入数据集或样本版本;
- 随机种子;
- wall time、成本和资源上限;
- 原始结果 artifact;
- 指标、阈值和最终 verdict。
Candidate 与 baseline 应该在等价环境运行。无法重现的外部评价必须标记 non_reproducible,promotion policy 可以禁止其单独触发自动晋升。
7.3 Promotion policy¶
Policy 必须在 Evaluation 开始前冻结,至少定义:
- 必须通过的 hard gates;
- 相对 baseline 的最低提升;
- 允许退化的指标和最大幅度;
- 最大成本、延迟和安全违规;
- 最少运行次数和统计聚合方式;
- 是否允许自动晋升;
- 所需批准角色;
- observation window 和 rollback guards。
评估完成后修改阈值不能让同一份报告变为通过;必须创建新的 Evaluation。
7.4 Promotion¶
Promotion 必须:
- 验证 Candidate 为
Qualified; - 验证 approval、policy、artifact hash 和当前 baseline;
- 使用 compare-and-swap 或等价原子操作切换活动引用;
- 记录旧活动版本,作为 rollback target;
- 发出
candidate.promoted后进入 observation; - 不得直接覆盖 artifact。
7.5 Rollback¶
Rollback 是一次新的受审计操作,不删除 Promotion 历史。它必须:
- 指向明确的已知安全 revision;
- 验证恢复 artifact 的 hash;
- 恢复完整状态,而不是只覆盖旧文件;
- 取消或隔离仍在使用被回滚版本的执行;
- 记录触发原因、操作者和受影响 Session;
- 在恢复失败时进入显式 degraded state,不能报告成功。
7.6 信任边界¶
Evolution Controller、Evaluation policy、artifact verifier 和 rollback implementation 必须位于 Candidate 不能修改的信任边界。
L3 自修改必须通过独立 Forge Controller 或外部 supervisor 完成。正在被 Candidate 替换的 Forge 进程不能自行证明替换成功。
8. Rust 控制面与 Python 执行面¶
8.1 Rust 必须拥有¶
| 能力 | 原因 |
|---|---|
| Session/Turn 状态机 | 唯一执行语义 |
| Event envelope、排序、持久化接口 | 所有客户端一致 |
| Command 幂等和并发控制 | 防止重复副作用 |
| Tool registry 与 capability gate | 安全决策不能由 fallback 绕过 |
| Sandbox policy 解析和 enforcement contract | 跨语言同一策略 |
| Workspace revision manifest 和 hash 验证 | Promotion/Rollback 基础 |
| Candidate/Evaluation/Promotion 状态机 | 演化控制面 |
| Cancellation ownership | GUI/CLI 不得伪造停止 |
8.2 Python 可以拥有¶
| 能力 | 约束 |
|---|---|
| Python SDK | 只能通过 ForgeClient 命令和事件协议改变状态 |
| Model Provider adapter | 返回版本化响应;不得持有 Session 真相 |
| Python Tool adapter | 在声明 capability 和 sandbox profile 后注册 |
| 数据集/Evaluator adapter | 必须输出可审计 EvaluationRun |
| Framework integration | LangChain 等只做映射,不复制 Forge loop |
| 用户扩展 | 默认在 worker 进程;进程内仅用于显式开发模式 |
8.3 绑定协议¶
Rust 类型是规范实现,但协议 schema 必须语言中立。PyO3、本地 direct call 和 Actor RPC 可以使用不同编码,必须保持相同命令、事件和错误语义。
Python callback 抛出的异常必须转换成结构化 Forge error 和终止事件,不能穿过边界后让 Session 留在 Running。
8.4 Python worker¶
生产环境中的 Python Tool/Provider 应运行在可取消、可回收的 worker 边界。Worker 必须:
- 进行 protocol handshake;
- 声明支持的 major/minor 和 capabilities;
- 接受 deadline/cancellation;
- 不直接写 Session/Event store;
- 通过 artifact API 返回大结果;
- 崩溃后由 Forge 记录明确终止事件。
9. 统一客户端模型¶
GUI、CLI、Python SDK 和 Remote API 必须只依赖同一个逻辑接口:
ForgeClient
create_session(...)
start_turn(session_id, input, command_id)
cancel_turn(session_id, turn_id, command_id)
provide_input(...)
resolve_approval(...)
get_snapshot(session_id)
subscribe(session_id, after_seq)
实现可以是:
LocalForgeClient:同进程调用 Rust service;ActorForgeClient:通过 Pulsing ask/tell/stream;RemoteForgeClient:未来的受认证网络接口。
三者必须通过同一 contract test。
9.1 GUI¶
GUI 是事件投影和命令发送器:
- 不创建 detached Agent worker;
- 不把
event_rx当成任务所有权; - 不因切换 tab 改变事件路由;
- Stop 必须发送
CancelTurn,并等待取消完成事件; - 重启后通过 snapshot +
after_seq恢复; - Session/Turn busy 状态来自 Forge 投影。
9.2 CLI¶
CLI 的交互模式和一次性模式都创建或附着 Forge Session。退出终端不等于取消;CLI 必须明确选择 detach、cancel 或 wait。
9.3 Python SDK¶
Python SDK 不再构造独立 HybridForgeRuntime 作为状态所有者。它通过 ForgeClient 操作 Rust Forge,并把 Python Provider/Tool 注册为执行适配器。
当前实现中,pulsing.forge.ForgeAgent 已经是上述客户端投影:Session、Turn、Agent loop、Tool runtime、事件序号与取消所有权都在 Rust。原 Python loop 仅以显式的 LegacyPythonForgeAgent 兼容入口保留,HybridForgeRuntime 仅作为待迁移的混合 Tool adapter;两者不得被默认入口或新代码隐式选择。Python Tool/Provider worker protocol 仍属于 Phase 3,不能把兼容入口的存在误记为该阶段已经完成。
10. 部署模型¶
Forge 默认本地运行,不要求集群:
需要隔离或分布式时:
只有跨故障域、需要独立生命周期或需要远程资源的组件应该 Actor 化。领域值对象和控制面内部 reducer 保持普通 Rust 对象。
11. 持久化、安全与恢复¶
11.1 Stores¶
Forge 通过接口依赖以下 stores:
EventStoreSnapshotStoreArtifactStoreWorkspaceRevisionStoreActiveVersionStore
首个实现可以是本地文件,但必须满足原子写、hash 校验、路径约束和崩溃恢复。GUI 目录或内存 channel 不是 store。
11.2 Capability¶
每个 ToolCall 和 Evolution action 必须绑定 capability。审批决定包含:
审批不能只按工具名无限复用。Python fallback 不得绕过 Rust capability gate。
11.3 恢复¶
进程重启后:
- 加载最近 snapshot;
- replay 后续事件;
- 将没有终止事件的外部调用标记为
unknown; - 查询支持 reconciliation 的执行器;
- 无法确认时安全失败,不自动重复非幂等操作。
12. 错误、重试与取消¶
统一错误至少包含:
错误类别包括 validation、conflict、unsupported_version、permission_denied、sandbox_violation、deadline_exceeded、cancelled、worker_lost、provider_error、storage_error 和 internal。
只有明确标记幂等或携带执行幂等键的操作可以自动重试。模型调用、shell 和外部写操作默认不得静默重试。
取消必须从 Session 传播到模型调用、tool call、Python worker、Actor worker 和子进程。不能终止的资源必须继续显示为 cancelling/unknown,直到 reconciliation 完成。
13. 迁移计划¶
Phase 0:冻结边界¶
- 本文成为目标架构规范源;
- 旧 Forge 文档标记为 Current Tool Runtime;
- Craft/Agent/GUI 文档不再定义独立 Session 语义;
- 建立 protocol compatibility 测试目录。
Phase 1:Rust Session + Event¶
- 在
pulsing-forge实现 Session/Turn reducer; - 实现版本化 Command/Event envelope;
- 本地 EventStore、snapshot、replay;
- ForgeAgent 不再每个 prompt 清空状态;
- 实现真实 cancellation ownership。(首版本地进程与 in-process future 已完成;Python/Actor worker 待后续阶段接入)
Phase 2:统一客户端¶
- CLI 迁移到
LocalForgeClient; - GUI 迁移到 snapshot/subscription;
- Python 暴露
ForgeClient; - 删除 GUI detached worker 和全局 event receiver。
Phase 3:Python 执行适配器¶
- 把 Hybrid routing 决策移入 Rust registry;
- Python-only Tool/Provider 使用 worker protocol;
- Agent 包中的 loop、permission、sandbox 状态迁入 Forge;
pulsing.agent收敛为兼容 API 或参考应用。
Phase 4:L0 Evolution¶
- Candidate、Evaluation、Promotion stores;
- 只支持 Prompt/Skill/Workflow;
- 固定 suite、人工批准、原子 active pointer、完整 rollback;
- GUI 展示 Candidate 与评估证据,但不拥有状态。
Phase 5:代码演化¶
- 支持 L1/L2;
- hermetic evaluator、资源预算和 observation guards;
- L3 必须另立安全设计评审,不自动继承 L2 能力。
14. 验收条件¶
Session/Event¶
- 同一命令重放不会重复启动 Turn 或 Tool;
- GUI 在任意事件点断开后能够无损恢复;
- 同 Session 事件顺序稳定,跨 Session 不做虚假保证;
- Stop 后仍运行的子进程会被测试捕获;
- Rust、Python、GUI、CLI 通过同一协议 contract suite。
Evolution¶
- Candidate 内容修改会得到新 ID;
- Evaluation policy 在运行开始后不可改变;
- baseline 与 candidate 的环境差异可被检测;
- promotion 原子失败时 active version 不改变;
- rollback 恢复完整状态并校验 hash;
- Candidate 无法修改 Controller、policy 或 verifier;
- L0 自动晋升可全程 replay 和审计。
语言边界¶
- 关闭 Python fallback 不影响 Rust 支持工具的语义;
- Python worker 崩溃会产生终止事件,Session 不会永久 Running;
- 不支持的 major version 被明确拒绝;
- 未知 minor event 不会导致 GUI/CLI 崩溃。
15. 非目标¶
- 第一阶段不实现 Forge 自身代码的自动自修改;
- 不要求所有 Forge 部署都使用集群;
- 不把 GUI 布局写入核心协议;
- 不保证跨 Session 全局事件顺序;
- 不承诺任意外部副作用 exactly-once;
- 不用 Python 内存对象作为持久控制状态;
- 不将工作区 overlay copy 称为完整 rollback。
16. 尚待 ADR 决定¶
以下问题不得由实现代码偶然决定:
- EventStore 初始格式和 compaction 策略;
- ArtifactStore 的本地与远程寻址格式;
- Session 是否允许显式并行 Turn;
- Model Provider 的流式协议和 usage 计费模型;
- Evaluation 的统计比较方法;
- L0 自动晋升的默认 policy;
- ActorForgeClient 的命名、租约和故障恢复协议;
- L3 self-hosting 的独立信任根。