【Loom】核心架构与设计原理深度解析:让 Coding Agent 像交付工程师一样工作的本地 MCP 状态机
引子
2026 年的 Coding Agent 赛道正在经历一次静悄悄的范式转移:从「让模型答得更好」转向「让模型稳定交付」。
Claude Code、Codex、OpenCode、Gemini CLI……每一个 Agent 都有自己的 prompt、自己的 hook、自己的 settings.json。我们写 .claude/CLAUDE.md 时心里清楚:这份知识只活在那个 Agent 的会话里。换一个 Agent、换一个项目、换一个 session,所有上下文都得从零重建。
更糟的是「交付」二字本身的重量——一个真实业务需求往往要穿过澄清、规划、任务拆分、编码、验证、修复、部署、复盘这八个环节。任何一个环节出错,整条交付链就垮了。Agent 在「写代码」环节很强,但在「跨环节状态管理」上几乎一片空白。
valkor-ai/loom(⭐1.1k,Apache-2.0)正是冲着这条空白而来的——它把自己定位为 「Loop Engineering for Agentic Software Delivery」:
一个本地 MCP 交付状态机,把交付链路上的所有中间产物(澄清记录、规划契约、架构工件、任务计划、执行结果、修复记录、部署配置)变成可恢复、可移交、可验证的状态。Agent 不再靠「记忆」记住自己走到哪一步,而是每次都问 Loom:「下一步该写什么?」
下面这张图是 Loom 在仓库根目录自带的示意图,浓缩了整套哲学:
1 | Delivery State Machine |
整个项目用 Rust 写状态机 + Python 写检索算法,通过 MCP 协议与三个主流 Agent(Codex、Claude Code、OpenCode)对话。今天我们就把它拆开,从架构、机制、状态机、域分派、知识层一路拆到 Rust 源码。
项目定位与核心价值
仓库统计:
| 字段 | 值 |
|---|---|
| 全名 | valkor-ai/loom |
| ⭐ Stars | 1,132 |
| 主语言 | Rust(94%) + Python(算法) |
| License | Apache-2.0 |
| 仓库大小 | 8.4 MB |
| 最后推送 | 2026-09-29 |
| 形态 | 本地 MCP 服务 + 三个 Agent 插件 + Python 算法 worker |
一句话定义:Loom 是一个本地 MCP 交付状态机,把 Coding Agent 的「从需求到部署」拆成 22 个可路由动作、5 个领域分派器、4 个执行批次,所有中间产物持久化到 .loom/,让任何 Agent 都能在断点续跑、跨 Agent 移交、长流程回溯上保持一致。
能力矩阵(8 个第一性能力):
| 能力 | 实现位置 | 关键抽象 |
|---|---|---|
| 交付状态持久化 | core/transition.rs::TransitionStore | FileTransitionStore + OperationLease |
| 域分派 | core/domain_dispatcher.rs::DomainDispatcher | 5 个 trait 实现 |
| 路由动作 | core/route_action.rs::RouteActionKind | 22 个 enum 变体 |
| 下一动作协议 | core/next_action.rs::LoomMcpNextAction | 7 个 tagged union 变体 |
| 知识检索 | python/algorithms/{bm25,tfidf,analyzer,worker}.py | BM25 + TF-IDF + 多进程 worker |
| MCP 服务 | mcp-server/server.rs | rmcp SDK + ToolRegistry |
| 验证 | verification/lib.rs + execution/vsefm.rs | VSEFM 验证 + 修复循环 |
| 部署 | execution/browser.rs + deploy/ | 浏览器运行时 + Compose 拓扑 |
与传统 Agent 框架的根本差异:
| 维度 | LangChain / LangGraph | Claude Code / Codex | Loom |
|---|---|---|---|
| 状态位置 | 内存 + callback | 会话内 prompt | .loom/ 文件 + OperationLease |
| Agent 切换 | 需重写 | 完全不兼容 | @loom / /loom 同套接口 |
| 知识复用 | 无标准方案 | CLAUDE.md / AGENTS.md | 知识源注册 + BM25 检索 |
| 跨 session | 仅短期记忆 | 重新提示 | delivery state 可恢复 |
| 修复机制 | 异常吞掉 | 重试或人工 | RepairAction 自动路由 |
| 验证 | 无 | 无 | VSEFM 全链路验证 |
整体架构
Loom 不是单一可执行文件,而是一个 Rust workspace + 一个 Python 算法包 + 三个 Agent 插件 + 一个 MCP server的多层栈:
flowchart TB
subgraph A["三个 Coding Agent"]
CC[Claude Code]
CDX[Codex CLI]
OC[OpenCode]
end
subgraph B["Agent 插件层"]
CCPlugin[claude-code-plugin]
CDXPlugin[codex-plugin]
OCPlugin[opencode-plugin]
end
subgraph C["MCP Server 进程"]
Server[mcp-server/server.rs]
ToolReg[ToolRegistry<br/>loom.plan / loom.continue /<br/>loom.read / loom.write /<br/>loom.submit / loom.review /<br/>loom.deploy / loom.knowledge.*]
end
subgraph D["Domain Dispatch 层"]
Brainstorm[brainstorm/<br/>澄清 + 知识询问]
Planning[planning/<br/>仓库上下文 + 技术基线 +<br/>规划契约 + 架构工件]
Execution[execution/<br/>任务计划 + 任务执行 +<br/>评审 + 修复]
Verification[verification/<br/>VSEFM 验证 + 修复]
Repair[repair/<br/>任务/任务计划/架构修复]
end
subgraph E["核心运行时 core/"]
TE[TransitionEngine]
TS[TransitionStore<br/>FileTransitionStore]
OL[OperationLease<br/>并发互斥]
RS[RouteAction<br/>22 个动作]
NA[LoomMcpNextAction<br/>7 个 tagged union]
AC[AgentContract<br/>59KB 契约表]
ST[state/<br/>lifecycle_store + paths]
end
subgraph F["算法层 src/python/algorithms"]
BM25[bm25.py]
TFIDF[tfidf.py]
Analyzer[analyzer.py]
Worker[worker.py<br/>独立进程入口]
end
subgraph G["持久化 .loom/"]
Status[project_status.json]
Delivery[deliveries/*/index.json]
Phase[deliveries/*/phases/*/]
Lease[leases/*.json]
KB[knowledge/<br/>index + 倒排]
end
A --> B --> C
C --> D
D --> E
E --> G
D -.远程调用.-> F
F --> G
classDef agent fill:#fef3c7,stroke:#f59e0b
classDef server fill:#dbeafe,stroke:#3b82f6
classDef domain fill:#fce7f3,stroke:#ec4899
classDef core fill:#dcfce7,stroke:#16a34a
classDef algo fill:#ede9fe,stroke:#7c3aed
classDef persist fill:#fee2e2,stroke:#ef4444
class CC,CDX,OC,CCPlugin,CDXPlugin,OCPlugin agent
class Server,ToolReg server
class Brainstorm,Planning,Execution,Verification,Repair domain
class TE,TS,OL,RS,NA,AC,ST core
class BM25,TFIDF,Analyzer,Worker algo
class Status,Delivery,Phase,Lease,KB persist整个栈有 6 层(Agent → 插件 → MCP Server → Domain Dispatch → Core Runtime → 持久化),加上一个横切的 Python 算法进程。下面我们逐层深入。
4 个 Cargo Crate 的边界
Loom 的 Rust 工作区只有 4 个 crate:
1 | # src/rust/Cargo.toml(workspace) |
主体逻辑都放在 src/rust/ 下的内部 crate,每个 domain 一个 crate:
1 | src/rust/ |
这是 Loom 的关键架构决策:域 = crate。每个域自治,可独立测试、独立编译、独立演进。core/ 是所有域共享的最小内核(依赖只指向 contracts/ 和 state/,从不反向依赖任何 domain)。
状态机一:22 个 RouteActionKind
Loom 的状态机不是「节点 + 边」的图模型,而是**「动作路由 + 上下文投影」的偏序集**。整个交付流程被编码成 22 个 RouteActionKind 枚举值,分布在 5 个域、4 个执行批次里:
1 | // src/rust/core/route_action.rs:1-30 |
每个动作都映射到一个域 + 一个批次:
1 | // src/rust/core/route_action.rs:50-90 |
这个 22 × 5 × 4 的笛卡尔矩阵就是 Loom 状态机的全部。下面这张图把它们摊开来看:
flowchart LR
subgraph B7["批次 7 — 澄清"]
BS[BrainstormStart]
BC[BrainstormClarification]
BCO[BrainstormConfirmation]
end
subgraph B8["批次 8 — 基线构建"]
TCR[TechnicalBaselineRequest]
RCR[RepositoryContextRequest]
PCC[PlanningContractCreate]
AAC[ArchitectureArtifactContract]
TG[TaskplanGeneration]
end
subgraph B9["批次 9 — 执行评审"]
REV[Review]
ER[ExecutionRepair]
NUD[NeedsUserDecision]
MR[ManualReview]
end
subgraph B10["批次 10 — 验证"]
VO[VsefmOnboarding]
VV[VsefmVerification]
VRG[VsefmResultGate]
VR[VsefmRepair]
end
subgraph B5["批次 5 — 局部修复"]
TRR[TaskResultRepair]
TPR[TaskplanRepair]
AAR[ArchitectureArtifactRepair]
end
subgraph END["终止"]
CNP[ContinueToNextPhase]
D[Done]
end
BS --> BC --> BCO --> TCR
BCO --> RCR
TCR --> PCC --> AAC --> TG --> REV
REV --> ER --> REV
REV --> NUD --> MR
REV --> VO --> VV --> VRG --> VR --> REV
REV --> CNP --> D
REV --> TRR --> REV
REV --> TPR --> REV
REV --> AAR --> REV
classDef user_gate fill:#fef3c7,stroke:#f59e0b
classDef domain_brainstorm fill:#fce7f3,stroke:#ec4899
classDef domain_planning fill:#dbeafe,stroke:#3b82f6
classDef domain_execution fill:#dcfce7,stroke:#16a34a
classDef domain_verification fill:#ede9fe,stroke:#7c3aed
classDef domain_repair fill:#fee2e2,stroke:#ef4444
classDef terminal fill:#f3f4f6,stroke:#6b7280
class BS,BC,BCO,NUD,MR user_gate
class TCR,RCR,PCC,AAC,TG domain_planning
class REV,ER,CNP domain_execution
class VO,VV,VRG,VR domain_verification
class TRR,TPR,AAR domain_repair
class D terminal核心观察:
Brainstorm*是唯一需要用户参与(is_user_gate())的入口三件套(澄清 + 知识询问 + 确认)Review是唯一的「返回中心」——所有修复动作(执行/任务/架构/VSEFM)修完都回到 Review,而不是回到上一步VsefmResultGate是验证关卡——通过则ContinueToNextPhase,失败则VsefmRepair回到 Review 循环Done是终态,但只有Review通过验证后才能进
这种**「中心辐条 + 修复回环」**设计把状态机变成一个有界的偏序集:永远从 BrainstormStart 开始,永远在 Done 终止,中间的修复回环不会无限循环(因为批次号 5/9/10 的修复都有穷尽规则)。
状态机二:TransitionEngine 主循环
状态机的真正「驱动器」是 core/transition.rs::TransitionEngine<S, D>——一个泛型结构,S 是 TransitionStore,D 是 DomainDispatcher。这意味着:
- S 可以是
FileTransitionStore(生产)、InMemoryTransitionStore(测试)、RedisTransitionStore(将来分布式) - D 可以是任意实现了
DomainDispatchertrait 的域分派器
1 | // src/rust/core/transition.rs:88-100 |
主循环伪代码(综合 transition.rs、domain_dispatcher.rs、agent_contract.rs):
sequenceDiagram
participant Agent as Coding Agent
participant MCP as loom.continue
participant TE as TransitionEngine
participant TS as TransitionStore
participant DD as DomainDispatcher
participant FS as .loom/ files
Agent->>MCP: loom.continue
MCP->>TE: continue_current(ctx)
TE->>TS: load_status(project_root)
TS->>FS: read .loom/project_status.json
FS-->>TS: ProjectStatus
alt active_delivery_id is None
TE-->>MCP: Done 或 Blocked(loom.plan)
MCP-->>Agent: "No active delivery"
else has active_delivery
TE->>TS: load_delivery_index(delivery_id)
TE->>TS: read_operation_lease(delivery_id)
TE->>TE: current_phase + pending_action
alt has pending RouteAction
TE->>DD: dispatch_route_action(...)
DD->>FS: write artifact / read state
DD-->>TE: LoomMcpActionResult
else needs next action
TE->>TE: contract_for_phase → next action
TE-->>MCP: WriteArtifactNext / ExecuteTaskNext
end
end
MCP-->>Agent: LoomMcpNextAction JSON
Agent->>Agent: 写产物 / 执行任务
Agent->>MCP: loom.submit(artifact)
MCP->>TE: submit_artifact
TE->>TS: commit_delivery_state
TE-->>Agent: next RouteAction关键设计哲学:
- 每次 continue 都从磁盘读
project_status.json—— 不靠内存缓存,避免 stale 状态 - OperationLease 是并发互斥令牌 —— 同一 delivery_id 同一时间只能有一个 Agent 在写
- Dispatch 是同步阻塞调用 —— 但 dispatcher 内部可以异步(BM25 检索是子进程 RPC)
- 提交产物 = 触发下一次路由 —— submit 不是「结束」,而是「进入下一节点」
下面看实际的 core/transition.rs 主循环简化版(只展示主干):
1 | // src/rust/core/transition.rs(精简后) |
Domain Dispatch 层:5 个分派器
core/domain_dispatcher.rs 定义了 trait,每个域都实现自己的分派器:
1 | // src/rust/core/domain_dispatcher.rs(完整源文件) |
这个默认实现是 Loom 的优雅之处:每个域的 dispatcher 都用 UnimplementedDomainDispatcher 作为兜底,当某个 action 落到「未实现」的域时,返回的失败对象里精确告诉你:
code=not_implemented_for_batchtarget_batch= 哪个批次domain= 哪个域recovery_tool= 建议用哪个工具恢复
例如:
1 | [ArchitectureArtifactContract] requires the architecture domain handler. |
Agent 拿到这个失败码,不用看文档就知道:「哦,这个动作得切到 architecture 分派器」。
真实分派器例子:ArchitectureDomainDispatcher
1 | // src/rust/architecture/lib.rs(精简) |
5 个真实分派器 + 默认兜底 的组合让 Loom 的状态机具有**「部分实现也是合法状态」** 的特性——你只实现 BrainstormDispatcher 和 ExecutionDispatcher,剩下的批次返回明确错误而不是 panic。这是大型状态机的关键工程纪律。
协议层:LoomMcpNextAction 7 种 Next 动作
core/next_action.rs 定义了 MCP 返回给 Agent 的「下一步该做什么」——它是 7 个 tagged union:
1 | // src/rust/core/next_action.rs(精简) |
每个变体里都带精确的字段组——告诉 Agent 「读哪几个 group、写哪个文件、用哪个 tool 提交」:
1 |
|
关键洞察:Agent 收到的不是一个「宽泛的 prompt」,而是**「只读这几个字段、只写这一个文件、用这个 tool 提交」**的精确指令。这把 context window 的噪声降到最低——Agent 不用读整本契约,只读需要的字段组。
core/agent_contract.rs(59KB 巨型契约表)就是这些字段组的来源:每个 action_kind 对应一组 read_groups、一组 write_targets、一个 submit_tool、一组「为什么这个动作存在」的文档注释。Loom 把「知识」从 LLM 提示里抽出来,做成机器可读的查表。
持久化层:FileTransitionStore
所有状态都序列化到 .loom/<project>/ 目录下。state/lifecycle_store.rs 里的 FileTransitionStore 是默认实现:
1 | .loom/ |
TransitionStore trait 提供 8 个方法,下面是核心几个:
1 | // src/rust/core/transition.rs(精简) |
核心哲学:写永远原子、读永远重读。commit_delivery_state 默认实现是「先写 delivery_index,再 apply_delivery_index 到 status,再写 status」——三步走。如果中间崩溃,最坏的后果是 status 短暂落后,下一次 commit 自动追上。
更精巧的是 OperationLease——这是单机版的乐观锁:
1 | // src/rust/core/operation_lease.rs(精简) |
关键设计:
holder是 Agent ID(Claude Code / Codex / OpenCode),多 Agent 不会互相覆盖expires_at防死锁——进程崩溃 lease 自动过期revision单调递增——CAS 风格更新,防止 stale write
下面是完整的状态机生命周期(从 init 到 Done):
sequenceDiagram
participant U as User
participant A as Coding Agent
participant L as Loom MCP
participant FS as .loom/
U->>A: @loom build 访客登记系统
A->>L: loom.plan
L->>FS: 初始化 project_status.json
L->>L: route → BrainstormStart
L-->>A: LoomMcpNextAction::WriteArtifact(Clarification)
A->>U: 问需求澄清问题
U-->>A: 回答
A->>L: loom.write + loom.submit
L->>FS: 写 clarification_state.json
L->>L: route → TechnicalBaselineRequest
L-->>A: WriteArtifact(baseline)
A->>A: 扫描仓库 + 写技术基线
A->>L: loom.submit
L->>L: route → PlanningContractCreate
L-->>A: WriteArtifact(plan_contract)
A->>L: loom.submit
L->>L: route → ArchitectureArtifactContract
L-->>A: WriteArtifact(arch_candidate)
A->>L: loom.submit
L->>L: route → TaskplanGeneration
L-->>A: WriteArtifact(task_plan)
A->>L: loom.submit
L->>L: route → ContinueExecution
L-->>A: ExecuteTask(task_id=1)
A->>A: 写代码 + 跑测试
A->>L: loom.submit(TaskResult)
L->>L: route → Review
L-->>A: WriteArtifact(review)
A->>L: loom.submit
L->>L: route → VsefmVerification
L-->>A: RunVsefmVerification
A->>L: loom.submit
L->>L: route → ContinueToNextPhase → Done
L-->>A: LoomMcpActionResult::Done知识层:BM25 + Python 算法 worker
Loom 的知识层是一个Rust 调 Python 的子进程 RPC 架构:
flowchart LR
subgraph Rust["Rust 进程 mcp-server"]
KS[knowledge/search.rs]
AC[algorithm-client/<br/>lib.rs]
end
subgraph IPC["stdin/stdout JSON-RPC"]
PROTO[算法请求/响应]
end
subgraph Py["Python 进程 algorithms/worker.py"]
WR[Worker 主循环]
BM25[bm25.py]
TFIDF[tfidf.py]
AZ[analyzer.py]
end
subgraph Persist["知识索引 .loom/knowledge/"]
INV[倒排索引]
META[元数据]
SEM[语义包<br/>semantic packs]
end
KS --> AC
AC <-->|JSON-RPC| PROTO
PROTO <--> WR
WR --> BM25
WR --> TFIDF
WR --> AZ
BM25 --> INV
TFIDF --> META
AZ --> SEM为什么用 Python 而不是 Rust 实现算法?因为:
- BM25 / TF-IDF 在 Python 生态有成熟的科学计算库(numpy、scikit-learn 的 rank_bm25)
- 算法可以热更新——Loom 在多个 Agent 进程间共享同一份算法进程,重启算法不需要重启 MCP server
- 隔离算法崩溃——Python 进程崩溃不会带垮 Rust 状态机
下面是 algorithm-client/lib.rs 调 Python 的 RPC 客户端骨架:
1 | // src/rust/algorithm-client/lib.rs(精简) |
Python worker 是个简单的 stdin/stdout RPC 服务:
1 | # src/python/algorithms/worker.py(精简) |
注意 generate_semantics 里的「断点续跑」语义——索引构建可能中途崩溃,worker 记住每个 batch_index,下次 resume 时从下一个 batch 开始。这是长任务的工程纪律:算法不能因为进程重启就重头跑。
验证层:VSEFM(Verification, Self-Evaluation, Feedback, Mutation)
execution/vsefm.rs(188KB 巨型文件)是 Loom 的全链路验证系统——名字缩写揭示了它的设计:
1 | V — Verification(断言检查) |
VSEFM 不是「跑一遍测试」这么简单,而是一个多层断言 + 自评 + 反馈 + 自动修复的循环:
flowchart TB
subgraph VERIFY["VSEFM 主循环"]
V[Verification<br/>断言检查]
SE[Self-Evaluation<br/>自评打分]
RG[ResultGate<br/>结果闸]
REP[Repair<br/>修复变异]
end
subgraph Assert["断言层(按权重)"]
A1[L1 — 语法<br/>linter]
A2[L2 — 类型<br/>tsc/mypy]
A3[L3 — 单元测试<br/>pytest/jest]
A4[L4 — 集成测试<br/>contract test]
A5[L5 — 业务规则<br/>semantic check]
end
subgraph Repair["修复变异(按严重度)"]
R1[minor —<br/>自动重格式化]
R2[major —<br/>重写该函数]
R3[blocker —<br/>回滚 Phase]
end
V --> A1 --> A2 --> A3 --> A4 --> A5
A5 --> SE
SE --> RG
RG -->|通过| ContinueToNextPhase
RG -->|失败| REP
REP --> R1 --> V
REP --> R2 --> V
REP --> R3 --> BackReview
BackReview[回到 Review 阶段] --> V
classDef pass fill:#dcfce7,stroke:#16a34a
classDef fail fill:#fee2e2,stroke:#ef4444
classDef neutral fill:#dbeafe,stroke:#3b82f6
class ContinueToNextPhase pass
class R1,R2,V,SE,RG,A1,A2,A3,A4,A5 neutral
class R3,BackReview fail关键设计:
- 5 层断言按权重——L1 失败不阻塞(自动 reformat),L5 失败必阻塞
- 修复变异 3 档——minor / major / blocker,越严重越回退到更早阶段
- 结果闸——所有断言通过且自评分数达标才放行
- 修复回环有界——VSEFM 修复 3 次不通过 → NeedsUserDecision,让人类介入
MCP Server 层:8 个 Tool
mcp-server/tool_registry.rs 注册了 8 个对外暴露的工具:
1 | // src/rust/mcp-server/tool_registry.rs(精简) |
这 12 个工具覆盖完整生命周期:
| 工具 | 何时调用 | 输入 | 输出 |
|---|---|---|---|
loom.initProject | 首次启动 | project_root | ProjectStatus v1 |
loom.plan | 开始新交付 | request_text + requirement_files | BrainstormStart |
loom.read | 读契约/产物 | request_ref + group_ids | 只读字段组 |
loom.write | 写产物 | artifact_kind + content | write receipt |
loom.submit | 提交产物 | request_ref + artifact | next RouteAction |
loom.continue | 恢复 / 推进 | project_root | 下一动作 |
loom.review | 强制评审 | delivery_id | review 工件 |
loom.deploy | 本地部署预览 | delivery_id | Compose 拓扑 + 日志 |
loom.knowledge.add | 注册知识源 | name + paths | source_id |
loom.knowledge.build | 构建索引 | source_id | doc_count |
loom.knowledge.search | 检索 | query + top_k | hits |
每个工具的 handler 都是很薄的 wrapper——做参数校验 + 调 TransitionEngine + 序列化结果。核心逻辑都在 core/ 里。
协议层:三个 Coding Agent 的适配
三个 Agent 的插件入口都指向同一套 MCP 协议,只是命令前缀不同:
| Agent | 命令前缀 | 配置文件 |
|---|---|---|
| Claude Code | /loom <subcmd> | .claude/plugins/loom.json |
| Codex CLI | @loom <subcmd> | .codex/plugins/loom.toml |
| OpenCode | /loom <subcmd> | .opencode/plugins/loom.json |
安装器 install.sh 检测本地已有哪个 Agent,把对应插件写到 ~/.config/<agent>/plugins/:
1 | # install.sh(精简) |
这意味着一个核心洞察:Loom 不是另一个 Agent,它是 Agent 之间的协议层。Claude Code 用户和 Codex 用户跑同一份 .loom/ 状态——跨 Agent 移交成为一等公民。
与同类项目对比
| 维度 | LangGraph | Claude Code | Loom |
|---|---|---|---|
| 状态持久化 | 内存 callback | 会话内 prompt | .loom/ 文件 + lease |
| 跨 Agent 兼容 | 否 | 否 | 是(3 个 Agent) |
| 知识检索 | 无标准方案 | CLAUDE.md | 注册源 + BM25 + 语义 |
| 修复机制 | 异常吞掉 | 重试或人工 | 22 个动作路由 + 自动 repair |
| 验证 | 无 | 无 | VSEFM 5 层断言 + 修复变异 |
| 部署 | 无 | 无 | 本地 Compose 预览 |
| 跨 session 续跑 | 短期记忆 | 重新提示 | delivery state 可恢复 |
| 学习曲线 | 低 | 零 | 中(需要理解状态机) |
| License | MIT | 闭源 | Apache-2.0 |
核心差异:
- LangGraph 是「图执行引擎」——节点 + 边 + 检查点。但图是「业务层」的,不涉及交付流程本身
- Claude Code 是「单 Agent CLI」——把 prompt 优化到极致,但不持久化交付状态
- Loom 是「交付协议层」——状态机 + 契约 + 知识 + 验证 + 修复,专门解决「跨 Agent、跨 session、跨项目」的一致性问题
和 planning-with-files / Loop Engineering 主题的差异:
planning-with-files用「文件当 RAM」——所有状态写在 3 个 markdown 文件里- Loom 用「JSON 当 schema」——所有状态结构化 + 带 schema 校验
两种哲学各有所长:文件更适合人眼审阅,JSON 更适合机器处理。Loom 选择 JSON 是因为它的受众是 Agent(机器),而不是人。
优缺点分析
架构简洁性 vs 性能 / 复杂度
| 维度 | 优势 | 劣势 |
|---|---|---|
| 架构简洁性 | ✅ 22 个 enum + 5 个 trait 实现,比写「节点 + 边」的图状态机更短 | ⚠️ 仓库 8.4 MB、18 个内部 crate,新人需 1-2 天才能理清边界 |
| 可扩展性 | ✅ 新增 action 只改 4 处:enum、target_batch、domain、dispatcher | ⚠️ 每个域 dispatcher 是手写 if/else 链,没有自动路由表 |
| 易用性 | ✅ 三个 Agent 同一套命令,跨 Agent 无缝 | ⚠️ 安装需要 Rust + Python + Docker,门槛比 pip install 高 |
| 性能 | ✅ Rust 状态机 + 操作 lease 并发安全 | ⚠️ 每次 continue 都读 .loom/ 文件,磁盘 IO 比内存 callback 重 |
| 复杂度 | ✅ 22 动作 × 5 域 × 4 批次是有限状态机,可形式化验证 | ⚠️ VSEFM 188KB、agent_contract 60KB、task_plan 380KB——核心文件巨型 |
| 维护性 | ✅ 域 = crate,跨域依赖只指向 core | ⚠️ Python 算法 worker 是独立进程,IPC 调试比纯 Rust 麻烦 |
实际使用中的取舍
适合用 Loom 的场景:
- 多人 / 多 Agent 协作同一项目(每个 Agent 跑独立 session)
- 长交付流程(澄清 → 部署)需要中断 / 续跑
- 强合规场景(每次决策都要审计)
- 复杂业务规则需要知识源支撑(产品手册 / 领域规范)
不太适合的场景:
- 一次性快速脚本(3 行 prompt 写完就完)
- 纯研究 / 探索性任务(不需要交付流程)
- 单 Agent 单 session 的小项目(CLAUDE.md 就够了)
实践:从零跑通一个 Loom 交付
下面是一段真实可执行的 Loom 使用流程——从安装到完成一个简单交付:
1. 安装 Loom
1 | # macOS / Linux |
安装器会检测 Rust 工具链、Docker、Python,编译 Rust MCP server,下载算法包,配置 Agent 插件。
2. 注册知识源
在 coding agent 里输入:
1 | @loom knowledge add --name product-rules ~/Documents/product-rules |
输出:
1 | [OK] Source 'product-rules' registered with 23 paths |
3. 启动交付
1 | @loom build 一个访客登记 REST API,支持微信扫码签到 |
Agent 收到 loom.plan 工具的返回,进入 BrainstormStart 状态机:
flowchart LR
A[loom.plan] --> B[BrainstormStart]
B --> C[BrainstormClarification<br/>问 5 个澄清问题]
C --> D[BrainstormConfirmation<br/>让用户确认摘要]
D --> E[TechnicalBaselineRequest]
E --> F[PlanningContractCreate]
F --> G[ArchitectureArtifactContract]
G --> H[TaskplanGeneration]
H --> I[ContinueExecution<br/>执行第一个任务]
I --> J[Review]
J --> K[VsefmVerification]
K --> L[ContinueToNextPhase]
L --> M[Done]4. 中断与续跑
任何时刻关闭 Agent、关闭电脑,下次打开 Agent 继续:
1 | @loom continue |
loom.continue 从 .loom/project_status.json 读 active delivery_id,从 deliveries/<id>/index.json 读当前阶段,从 leases/<id>.json 检查 lease 是否过期,路由到下一个动作。
5. 切换 Agent
同一项目,把 Codex 换成 Claude Code:
1 | /loom continue # Claude Code 重新打开 |
Claude Code 加载 .codex/plugins/loom.toml 的等价配置 .claude/plugins/loom.json,从同一份 .loom/ 状态读出来。零数据迁移。
6. 本地部署预览
1 | @loom deploy |
Loom 调 Docker Compose 起本地预览环境,输出:
1 | [OK] Topology generated: .loom/deliveries/<id>/deploy/compose.yml |
趋势与总结
4 个趋势判断
1. 「Loop Engineering」会成为 2026 H2 Coding Agent 的新基础设施类别
2026 H1 是「Prompt Engineering」——把 prompt 写得更好。2026 H2 是「Loop Engineering」——把交付流程跑得更稳。Loom 是这条赛道的早期定义者,22 个动作 + 5 个域 + VSEFM 验证给后来者立了标杆。未来 6 个月可能出现:「Loop as Code」(声明式定义交付循环)、「Loop Trace」(把整个交付过程做成 OpenTelemetry span)、「Loop Marketplace」(共享行业专用 loop)。
2. 「Agent × Provider × Loop」会成为 Coding Agent 三件套
2025 H2 主流 Agent 是「裸 LLM + tools」(Claude Code 雏形)。2026 H1 是「Agent + Provider」(claude-code-router 雏形)。2026 H2 是「Agent + Provider + Loop」——在 Provider 之上叠加 Loop,把交付流程变成可路由、可验证、可恢复的状态机。Loom 的 22 个动作是这条路线的最小可行集。
3. 「状态机优先」会取代「prompt 优先」
传统 Agent 框架(LangChain / LlamaIndex / CrewAI)走 prompt 路线——把流程塞进 prompt,让 LLM 自己推理。Loom 走状态机路线——把流程抽出来做 enum + dispatcher,让 Agent 只负责「填表」。后者更稳定、更可验证、更易调试。这与 promptfoo / RagaAI 等可观测性项目正交——那些是「观测 prompt 行为」,Loom 是「让 prompt 行为可重放」。
4. 「跨 Agent 协议」会出现行业标准
Claude Code / Codex / OpenCode 都有自己的 .md 配置和 hook,但没有跨 Agent 的状态交换协议。Loom 的 .loom/ 是个事实标准雏形。如果未来出现「Agent State Transfer Protocol」(ASTP),它的 v0.1 大概率会参考 Loom 的 ProjectStatus + DeliveryIndex + OperationLease 三件套。
工程经验提炼
读完 Loom 的源码,有 5 条经验值得记下:
- 枚举值是状态机的最佳载体——22 个
RouteActionKind比「节点 + 边」的 JSON 配置文件更紧凑、更可验证、更易编译期优化 - Trait 默认实现 = 部分实现的合法化——
UnimplementedDomainDispatcher让单个域 dispatcher 只关心自己的 action,其他返回明确错误 - Lease 模式比锁轻量——
OperationLease用文件 + 过期时间实现单机并发安全,无需重启进程 - 写产物 = 触发路由——
submit不是「结束」而是「进入下一节点」,这让 Agent 不靠记忆记住进度 - 算法 worker 用独立进程——Python 算法崩溃不会带垮 Rust 状态机,重启算法不需要重启 MCP server
一句话总结
valkor-ai/loom 用 Rust 状态机 + Python 算法 + 12 个 MCP 工具,把 Coding Agent 的「从需求到部署」拆成 22 个可路由动作 × 5 个域分派器 × VSEFM 验证 × OperationLease 并发,让 Claude Code / Codex / OpenCode 三个 Agent 共享同一份 .loom/ 交付状态。它是 2026 H2「Loop Engineering」赛道的开山之作,填补了 Coding Agent 在「跨 Agent、跨 session、跨项目一致性」上的关键空白。
附录:关键资源
| 资源 | 链接 |
|---|---|
| GitHub 仓库 | https://github.com/valkor-ai/loom |
| 技术报告 | Loomline-v0.pdf(仓库 docs/) |
| 官网 | https://www.valkorai.com/ |
| 安装脚本 | curl -fsSL https://github.com/valkor-ai/loom/releases/latest/download/install.sh | bash -s -- --agent <codex|claude-code|opencode|all> |
| Discord | https://discord.gg/Yr7UjwbYPC |
| License | Apache-2.0 |
| 核心模块 | core/(状态机) + mcp-server/(协议) + src/python/algorithms/(算法) |
| 关键抽象 | RouteActionKind(22 个) + DomainDispatcher(5 个 trait) + LoomMcpNextAction(7 个 tagged union) + TransitionStore(持久化) + VSEFM(5 层验证) |
| Agent 适配 | Claude Code / Codex CLI / OpenCode(同一套 MCP) |
| 算法实现 | BM25 + TF-IDF + 多进程 worker |