Doramagic 项目包 · 项目说明书
loom 项目
面向 Agent 的浏览器自动化运行时,提供可复现的 Chromium 会话,内置 replay-equal 哈希链、原生 MCP 工具以及内容寻址的动作存储。
Loom 概览、信任区与 Crate 拓扑
Loom 是一个面向 agent / 自动化测试场景的浏览器录制与确定性回放基础设施,源自 Mentiora code-pipeline 项目,经过 23 轮 GA 驱动硬化后于 v0.9.0(2026-05-04)首次公开发布 资料来源:v0.9.0 Release Notes。其核心承诺是:给定相同的动作序列与种子,多次运行可以产出在 manifest 哈希链层面可比较...
继续阅读本节完整说明和来源证据。
项目概览与设计目标
Loom 是一个面向 agent / 自动化测试场景的浏览器录制与确定性回放基础设施,源自 Mentiora code-pipeline 项目,经过 23 轮 GA 驱动硬化后于 v0.9.0(2026-05-04)首次公开发布 资料来源:v0.9.0 Release Notes。其核心承诺是:给定相同的动作序列与种子,多次运行可以产出在 manifest 哈希链层面可比较的"变化预言机"(cross-run regression oracle),并支持 JSON 清单、gzip tarball、HAR 1.2 等多种导出形态 资料来源:loom-core/src/exporters/exporters.rs:1-24。
设计上 Loom 把"会话生命周期 / 内容存储 / Manifest 写入 / 凭证保险库 / 回放引擎 / 预算执行器"作为 surface-agnostic 的内层,将所有跨 crate 的对外 API 收敛到单一入口 CoreApiFacade,从而避免外部代码绕过内部模块 资料来源:loom-core/src/core_api_facade/core_api_facade.rs:1-25。这与社区中"工具调用 schema 与回放 hash 链必须严格等价"(NFR-DET-01)的诉求一致 资料来源:v0.10.0 Release Notes。
Crate 拓扑与构建层级
Loom 工作区由多个职责单一的 crate 组成。loom-core 是 surface-agnostic 的内核,承担会话、内容、Manifest、Vault、回放、预算、Determinism Harness、Observability、Startup Manager 等子系统,并对外只暴露 core_api_facade 模块 资料来源:loom-core/src/lib.rs:1-58, loom-core/src/core_api_facade/core_api_facade.rs:11-19。loom-host 与 loom-rpc 仅通过 CoreApiFacade 与内核交互,禁止穿透到具体子系统 资料来源:loom-core/src/core_api_facade/core_api_facade.rs:15-25。
graph TD CLI["loom-cli / daemon"] --> RPC["loom-rpc (Unix socket / JSON-RPC)"] MCP["loom-mcp (stdio, JSON-RPC 2.0)"] --> RPC SHIM["loom-shims (CBOR / 0.11 协议)"] --> RPC PY["python-sdk (mentiora-loom)"] --> SHIM TS["@mentiora-ai/loom-sdk"] --> SHIM RPC --> FACADE["CoreApiFacade (loom-core)"] FACADE --> SESSION["session_manager"] FACADE --> MANIFEST["manifest_writer"] FACADE --> REPLAY["replay_engine"] FACADE --> BUDGET["budget_enforcer"] FACADE --> VAULT["vault"] FACADE --> CONTENT["content_store"] FACADE --> HARNESS["determinism_harness"] FACADE --> STARTUP["startup_manager"] CLI -. doctor / postinstall .-> DOCTOR["loom doctor + shim health probe"]
loom-mcp 通过 RpcClient 调用 loom-rpc,并把回包按 MCP 工具结果(text / image)序列化;为兼容 Claude Code/Desktop 的 Zod 校验,结构化 JSON 统一以文本块下发 资料来源:loom-mcp/src/error_mapper/error_mapper.rs:13-25。SDK(Python / TypeScript)面向 Unix socket 与运行中的 loom-daemon 通信,并要求先通过 Homebrew / cargo install / 安装脚本把 CLI、daemon、Chromium 钉好版本 资料来源:python-sdk/README.md:1-15, typescript-sdk/README.md:1-15。
信任区与进程边界
Loom 把进程边界当作第一等信任边界来建模,每个进程拥有独立的信任假设:
| 信任区 | 代表进程 | 主要职责 | 关键约束 |
|---|---|---|---|
| 内核 | loom-core(库形态) | 会话/内容/Manifest/Vault/回放/预算 | pub use core_api_facade::*; 是唯一对外出口 资料来源:loom-core/src/lib.rs:23-25 |
| 守护进程 | loom-daemon | 长驻服务、IPC 端点、reaper | 启动前执行 startup_health_check 与 perform_recovery_sweep 资料来源:loom-core/src/core_api_facade/core_api_facade.rs:21-26 |
| 协议适配 | loom-rpc / loom-mcp / loom-shims | JSON-RPC 2.0、stdio 传输、CBOR Shim 协议 | 工具名 loom.* 前缀、计数奇偶信封、协议 schema 内嵌(v0.11.1 修复) 资料来源:loom-mcp/src/mcp_dispatcher/mod.rs:1-50, v0.11.1 Release Notes |
| 客户端 | Python / TypeScript SDK、loom-cli | 会话句柄、Admin RPC(kill_session / daemon.health) | 通过 Unix socket 与 daemon 通信,要求 daemon 已起 资料来源:python-sdk/README.md:1-15, typescript-sdk/README.md:1-15 |
| 测试替身 | */src/mocks.rs | 不依赖 I/O/时间/随机数的桩实现 | 位于各 crate 内部、#[cfg(any(test, feature = "mock"))] 门控 资料来源:mocks/README.md:1-12, loom-core/src/mocks.rs:1-16 |
凭证侧由 Vault 强制执行:调用方必须显式 threat_model_acknowledged = true 才能获得授权,且仅接受 CredentialType::OAuth2,否则以 VaultRejection / vault_threat_model_missing / vault_credential_type_unsupported 等细分错误码拒绝 资料来源:loom-core/src/vault/impl_local.rs:1-40。该约束与 v0.11.0 "Hardening Sweep" 之后对"凭证/协议/确定性"三方收紧的方向一致 资料来源:v0.11.0 Release Notes。
关键能力面与社区关注点
围绕社区反复出现的"截图能传到 MCP 客户端吗?""文件上传能做到吗?""跨运行 diff 是否真为 0?""Linux 装完能不能跑?"等问题,Loom 把能力面分成五块:
- 协议与 Schema:
loom-mcp在 v0.11.0/v0.11.1 之后将until/timeout_ms等参数纳入内嵌 schema,避免postinstall未生成磁盘 schema 文件时给出错误的schema_violation资料来源:v0.11.1 Release Notes, loom-mcp/src/mcp_dispatcher/mod.rs:1-50。 - 回放与确定性:
ReplayEngine提供collect_content_refs/non_deterministic_refusal/unclean_source_refusal等高层判定,v0.10.1 起跨运行 difffield_diffs=0成为正式契约 资料来源:loom-core/src/replay_engine/mod.rs:1-10, v0.10.1 Release Notes。 - 捕获语义:v0.10.0 引入 readiness-gated capture + per-request 网络条目,但仍需保留 NFR-DET-01 哈希链 资料来源:v0.10.0 Release Notes。
- 跨协议内容分发:v0.9.9 让
web.screenshot/web.navigate的 PNG 通过 MCPimage内容块真正到达消费方,修正了双重 CBOR 编码的 bug 资料来源:v0.9.9 Release Notes, loom-mcp/src/error_mapper/error_mapper.rs:17-25。 - 可观测与自愈:v0.9.1 增
daemon.health({deep: true})Shim 探针;v0.10.1 增 session reaper,用于长驻 daemon 清理僵死会话 资料来源:v0.9.1 Release Notes, v0.10.1 Release Notes。
常见失效模式:Linux 全新安装曾因 chromium binary not_found 与 shim IPC 在 fd 3 上与 Tokio I/O 驱动赛跑,导致 surface_trap 资料来源:v0.9.2 Release Notes;e2e-real-world 计划任务在 ubuntu-latest / macos-latest 偶发失败,需结合 daemon 日志与 per-site 工件排查 资料来源:Issue #179。
See Also
- 主页(Loom 项目主页)
- 核心 API 门面(CoreApiFacade 详解)
- Manifest 写入与哈希链(manifest_writer)
- 回放引擎与跨运行确定性(replay_engine)
- MCP 工具分发(mcp_dispatcher)
- Vault 与威胁模型(vault)
- Python SDK(python-sdk)
- TypeScript SDK(typescript-sdk)
来源:https://github.com/mentiora-ai/loom / 项目说明书
CLI、MCP 工具与多语言 SDK
Loom 在核心(loom-core)之上暴露了三条并行的对外接口:loom CLI 用于本地脚本化与运维操作、MCP 工具集用于代理/IDE 集成、多语言 SDK(目前主要是 typescript-sdk)用于嵌入到下游产品(如 agentic-test-studio)。三者都收敛到底层的 loom-rpc 方法集合与 loom-core 的确定性会话模型,避免出现"行为...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
Loom 在核心(loom-core)之上暴露了三条并行的对外接口:loom CLI 用于本地脚本化与运维操作、MCP 工具集用于代理/IDE 集成、多语言 SDK(目前主要是 typescript-sdk)用于嵌入到下游产品(如 agentic-test-studio)。三者都收敛到底层的 loom-rpc 方法集合与 loom-core 的确定性会话模型,避免出现"行为分叉"。
三条接口在栈中的位置
| 接口 | 进程边界 | 调用对象 | 主要职责 |
|---|---|---|---|
loom CLI | 客户端进程直连 daemon(CBOR-over-IPC) | loom-rpc 方法 | 一次性录制/回放、导出、Vault 运维 |
| MCP 服务器 | stdio 帧 | McpDispatcher → rpc.schemas | 将 RPC 方法动态发布为 tools/resources |
| TypeScript SDK | Node 进程 | 通过 loom-rpc 客户端 | 让代理/测试平台以类型化方式调用 |
flowchart LR
CLI[loom CLI] -->|CBOR/Unix socket| Daemon[loom-daemon]
SDK[typescript-sdk] -->|CBOR/Unix socket| Daemon
MCP[loom mcp<br/>stdio] --> Dispatcher[McpDispatcher]
Dispatcher -->|rpc.schemas| Daemon
Daemon --> Core[loom-core<br/>session + manifest]
Core --> Content[ContentStore + Vault]loom-core 通过 pub use core_api_facade::*; 将模块重新导出,CLI、MCP 与 SDK 都只消费这一层 loom-core/src/lib.rs。
MCP 工具:动态从 RPC schema 生成
MCP 服务器没有写死工具列表。它在每次 tools/list 调用时从 rpc.schemas 拉取 MethodSchema,再用 ToolCache::tool_from_method 转成 MCP Tool loom-mcp/src/tool_cache/tool_cache.rs:
- 命名空间前缀:RPC 方法
action.web.click在 MCP 端被转换为loom.action.web.click;反向mcp_to_rpc_name会剥离loom.前缀,便于把tools/call参数路由回 RPCloom-mcp/src/tool_cache/interface_tests.rs。 - 字段命名:
Tool结构在序列化时强制使用inputSchema(驼峰)以兼容 MCP wire 格式——这由#[serde(rename = "inputSchema")]保证,接口测试明确断言序列化结果包含"inputSchema"。 - 协议版本:MCP 服务器对外公布
MCP_PROTOCOL_VERSION = "2024-11-05"loom-mcp/src/mcp_dispatcher/mcp_dispatcher.rs。
隐式会话与生命周期
McpDispatcher 不要求 MCP 客户端先调用 session.create。它持有一个 implicit_session: Mutex<ImplicitSessionState>:首次 tools/call 命中时按 baseline_options 懒创建,并在会话被 daemon 驱逐后透明重建——重建时复用同一份选项以保持 seed/clock_anchor 不漂移;recreated_count 通过原子计数被 loom.session.info 暴露出来,使下游"确定性钉死"客户端能检测到重建而非默默信任 loom-mcp/src/mcp_dispatcher/mcp_dispatcher.rs。
错误与内容类型
McpContent 仅暴露标准 MCP text 与 image 两类内容块:JSON 负载在构造期被 stringify 进 text 字段,避免早期 {"type":"json",...} 在 Claude Code 等严格 Zod 校验下被拒 loom-mcp/src/error_mapper/error_mapper.rs。ErrorMapper 是 LoomError → ToolResult{ isError: true, content } 的唯一转换点,错误载荷经 McpContent::from_json 序列化,接口测试断言其标签为 "text" 且内嵌 JSON 被正确转义 loom-mcp/src/error_mapper/interface_tests.rs。
资源端(resources/*)
ResourceTracker 在 loom://session/<id>/manifest 与 loom://blob/<sha256> 两个 URI 方案下挂载会话清单与内容存储条目,默认 TTL DEFAULT_TTL = 30s;resources/read 返回形如 { contents: [{ uri, mimeType, text|blob }] } 的 MCP 2024-11-05 兼容结构 loom-mcp/src/resource_tracker/resource_tracker.rs。
安全与可观测性
McpObservability 在请求结束写 mcp_request_end 结构化日志(包含 mcp_method / tool_name / latency_us / error_code),并对凭证类工具做参数级脱敏:cookie 工具的 value 字段被路径级剥离但保留名称以维持审计能力 loom-mcp/src/mcp_observability/mod.rs。
CLI 与 SDK:复用同一条 RPC 路径
CLI 与 TypeScript SDK 都不经过 MCP,而是直接走 loom-rpc 的 CBOR-over-Unix-socket。这一设计的好处是 CLI 脚本与生产 SDK 看到的是同一份契约,避免出现"工具里有、CLI 没有"的偏差。loom-core 暴露的子系统被这三者共享:
- Manifest 与哈希链:
ManifestEntry是带标签的枚举(Header/Action/Audit等),全部用 JCS 序列化以承载NFR-DET-01哈希链;Header 显式记录seed以便 replay 时还原Math.random/Date.nowloom-core/src/manifest_writer/manifest_writer.rs。 - Replay 引擎:含
cookie_replay子模块,提供collect_content_refs/non_deterministic_refusal/unclean_source_refusal三个对外函数loom-core/src/replay_engine/mod.rs。 - 预算与导出:
budget_enforcer强制会话级资源上限,Exporter产出export_json/export_tarball/export_har三种制品loom-core/src/exporters/exporters.rs、loom-core/src/budget_enforcer/mod.rs`。 - Vault 审计:
vault/audit_payloads中的 DTO 仅承载字段名与事件元数据,绝不携带原始 cookie 值,从而让审计条目可以安全进入哈希链 `loom-core/src/vault/audit_payloads.rs。
TypeScript SDK
typescript-sdk/package.json 描述了一个 Node 测试驱动的 SDK:使用 tsx 运行 ESM 测试,tsc 负责类型检查与构建,prepublishOnly/prepack 在发布前强制重新构建;运行时仅依赖 @types/node,核心关键字为 browser / automation / loom typescript-sdk/package.json。它面向的目标是"agentic-test-studio"——即让测试平台以类型安全方式驱动 daemon,而不是再走一次 MCP。
测试与 Mock 约定
每个 crate 的 mock 模块就近放在 <crate>/src/mocks.rs,由 #[cfg(any(test, feature = "mock"))] 守门;启用 mock feature 即可让消费者在测试中替换 ContentStore / Vault / RpcClient 实现,避免去构造一个需要依赖全部 crate 的合成测试 crate mocks/README.md。
常见失败模式
- MCP 工具参数被误拒(v0.11.0 → v0.11.1):daemon 曾经按磁盘上的 per-method schema 文件校验参数,但
postinstall没拷贝这些文件,导致 MCP 调用收到schema_violation: field 'params' expected field_unknown got object。v0.11.1 改为"embedded-first"校验路径修复此回归。 - 截图未达 MCP 客户端(v0.9.9 之前):截图字节被双重
CBOR{data:base64}编码且 MCP 没有 image 内容类型,导致渲染图永远到不了消费方;v0.9.9 后web.screenshot/web.navigate通过标准image内容块返回 base64 PNG。 - Linux 平台 daemon 启动后
surface_trap:v0.9.2 之前 shim 的 IPC socket 与 Tokio I/O 在 fd 3 上竞争,造成所有web.*失败;补丁同时修复了loom doctor报chromium binary not found的问题(#70、#71)。
See Also
- Manifest 写入与哈希链
- Replay 引擎与 Cookie 回放
- Vault 与审计载荷
- MCP 资源端:Session 与 Blob
来源:https://github.com/mentiora-ai/loom / 项目说明书
会话生命周期、清单哈希链与回放引擎
Loom 的核心由三大相互咬合的子系统组成:sessionmanager 负责会话的有限状态机与生命周期治理;manifestwriter 将每一次动作回执(ActionReceipt)追加为 JSONL 形式的清单条目,并以此构建出可被跨运行比较的哈希链;replayengine 则在封闭会话之上提供确定性回放能力,并辅以 exporters 将已关闭会话导出为 JSON...
继续阅读本节完整说明和来源证据。
概述
Loom 的核心由三大相互咬合的子系统组成:session_manager 负责会话的有限状态机与生命周期治理;manifest_writer 将每一次动作回执(ActionReceipt)追加为 JSONL 形式的清单条目,并以此构建出可被跨运行比较的哈希链;replay_engine 则在封闭会话之上提供确定性回放能力,并辅以 exporters 将已关闭会话导出为 JSON manifest、gzipped tarball 或 HAR 1.2 等标准制品。三个子系统共同实现"录制→清单化→可验证回放→可导出回归"的闭环。
资料来源:loom-core/src/lib.rs:3-23
会话生命周期
SessionManager 是会话生命周期 FSM 的所有者。每个会话拥有独立的多线程 tokio 任务与独立的 arena,由 Arc<Notify> 与 Arc<AtomicBool> 协同实现 abort 传播:调用 abort() 时翻转布尔位并触发 notify_one(),宿主函数入口处会检查该布尔位,tokio::select! 则在真实调用与通知之间做竞争。FSM 的状态空间为:
stateDiagram-v2
[*] --> Created
Created --> Active: create()
Active --> Closed: close()
Active --> Aborted: abort()
Active --> Killed: budget breach
Active --> Crashed: panic / fatal
Closed --> [*]
Aborted --> [*]
Killed --> [*]
Crashed --> [*]create() 的同步路径只承担"轻量"职责:ULID 生成、目录创建、WAL 头追加、fsync、任务派发,刻意不触发 WASM、Chromium 或网络动作,从而维持暖创建预算(warm create budget)。同时,create() 会向 BudgetEnforcer 注册一个 Arc<dyn Fn(SessionId, KillReason)> 回调,使预算超支可以从外部中断本会话任务而不引入循环依赖。
在 MCP 层面,每个 MCP 进程会持有一个隐式会话(implicit session),在长期闲置被驱逐后可通过相同的确定性子集参数透明自愈。MCP 通过 recreated_count 计数器暴露隐式会话被透明重建的次数,以便确定性感知的客户端"检测"重建而不是"信任"重建——但该计数器从不被纳入清单/哈希链。
资料来源:loom-core/src/session_manager/session_manager.rs:1-39;loom-mcp/src/mcp_dispatcher/mcp_dispatcher.rs:2-30
清单哈希链
manifest_writer 负责把每一次动作结果追加为 JCS(JSON Canonicalization Scheme)形式的 JSONL 条目(manifest.wal)。清单条目(ManifestEntry)的字段集由 capture profile 与 surface 共同约束,结构上区分"哈希字段"与"blob 引用字段"两类,以避免在哈希链中重复携带大体数据:例如 click 类型的回执只携带 dom_after_hash 而不携带 dom_after_blob_ref;而 navigate 类型的回执反之,携带 blob 引用以支持重放期间再水化。
// receipt_builder/interface_tests.rs 验证两类回执的字段差异
let r = ReceiptBuilder::build_click_receipt(...);
assert!(r.dom_after_hash.is_some());
assert!(r.dom_after_blob_ref.is_none());
let r = ReceiptBuilder::build_navigate_receipt(...);
assert!(r.dom_after_blob_ref.is_some());
assert!(r.dom_after_hash.is_none());
哈希链的角色是"是否发生变化"的真值源:从 0.10.1 起,同一确定页面上同一组动作的两次独立录制,其清单 diff 在 field_diffs=0 上达成等值,回放哈希链由此具备跨运行的回归判定能力(cross-run regression oracle)。
资料来源:loom-core/src/manifest_writer/mod.rs:1-9;loom-core/src/receipt_builder/interface_tests.rs:21-37;loom-core/src/lib.rs:3-9
回放引擎
replay_engine 面向"封闭会话"提供回放:它消费 manifest.wal 中的 ActionReceipt 序列并按 collect_content_refs 汇聚本次回放所需的内容引用(screenshot、DOM 快照等)。其拒绝路径由两个公开函数定义:non_deterministic_refusal 在源回执链上检出非确定性字段时拒绝回放;unclean_source_refusal 在源会话存在未关闭动作或污染 blob 时拒绝。cookie_replay 子模块则专门处理会话 Cookie 的还原策略,避免回放命中陈旧认证态。
回放引擎与清单哈希链形成对偶:清单链是"已发生事实"的不可变账本,回放引擎则是"按账本重建事实"的执行器。NFR-DET-01(跨运行确定性)由两者共同保证——清单保证事实链的等价性,回放保证重建路径的等价性。
资料来源:loom-core/src/replay_engine/mod.rs:1-12;loom-core/src/replay_engine/impl_replay.rs:1-4
导出器与跨运行确定性
Exporter 是面向"已关闭会话"的离线制品生成器。它通过 ContentStore::get 读取受内容完整性检查保护的内容 blob,并按三种形态输出:
| 导出形态 | 文件 | 用途 |
|---|---|---|
| JSON manifest | export_json | 输出 {"manifest": {...}, "content_blob_index": [...]} |
| gzipped tarball | export_tarball | manifest.json + cas/<sha256> blob 的归档 |
| HAR 1.2 | export_har | 一条 HAR 条目对应一个 ActionReceipt |
回放哈希链与 loom.session.diff(跨会话 diff 报告:field_diffs / screenshot_diffs / action_count_delta)共同构成跨运行回归判定的两层视图。SessionManager 提供的会话再收割器(reaper)则保证长生命周期的守护进程不会因悬挂会话导致并发上限长期饱和。
资料来源:loom-core/src/exporters/exporters.rs:1-19;loom-mcp/src/mcp_dispatcher/mcp_dispatcher.rs:1-20
常见失败模式
- Schema 校验回归:0.11.0 引入嵌入式优先的 schema 校验时,破坏了
loom.web.navigate对until/timeout_ms的接受路径,使 MCPtools/call误判为schema_violation;0.11.1 修复了该问题。 - Schema 校验回归的另一面:同一参数在
web.wait_for上接受、在web.navigate上拒绝,提示 schema 源在方法间存在不一致。 - 跨运行确定性退化:若
manifest.wal的哈希链被外部工具改写或会话被异常关闭,跨运行 diff 将失去"真值源"地位,应优先调用SessionManager::close()正常收尾。 - 预算超支:当
BudgetEnforcer触发 kill-callback 时,会话进入Killed状态,回执中error.kind="budget_exceeded"。
资料来源:loom-mcp/src/mcp_dispatcher/mcp_dispatcher.rs:2-30;loom-core/src/session_manager/session_manager.rs:1-39
See Also
- 错误映射与
TypedReceipt序列化(loom-mcp/src/error_mapper/error_mapper.rs) - 工具缓存与 schema 注册(
loom-mcp/src/tool_cache/interface_tests.rs) - 内容存储与 blob 引用生命周期(
loom-core/src/content_store/impl_local.rs) - TypeScript SDK(
typescript-sdk/package.json)
安装、Postinstall、Doctor、Vault 与常见故障
本页面向刚装好 Loom 或在生产环境中遇到「装上了但跑不起来」类问题的工程师,覆盖 loom install / loom postinstall 的实际语义、loom doctor 的诊断边界、Vault 凭据网关以及几条历史上真实踩过的坑(release v0.9.2、release v0.11.1)。
继续阅读本节完整说明和来源证据。
安装与 Postinstall
loom postinstall 负责把 daemon、shim、Chromium、per-method schema、macOS 上的 launchd plist 等资源落到正确位置;它是 loom-core 之外、由 CLI 侧驱动的预条件动作,与运行时库是解耦的(运行时库对外只暴露领域模块如 manifest_writer、vault、replay_engine 等,见 loom-core/src/lib.rs:1-25)。
历史上有两个被反复踩过的回归:
- Chromium 没就位(issue #70):0.9.1 之前的 Linux postinstall 表面上
exit 0,但实际二进制没解压好,导致后续loom doctor报chromium binary not found。0.9.2 在 postinstall 内部补齐了下载与权限步骤,并把 doctor 的 chromium 探测当作 sanity check 之一。 - Schema 落盘回归(v0.11.1):0.11.0 把 schema 从「embedded」改为「per-method 文件 + daemon 启动时加载」,但
loom postinstall没有同步把所有 schema 复制到磁盘。结果是loom.web.navigate带until/timeout_ms时被 daemon 报schema_violation: field 'params' expected field_unknown got object,而web.wait_for用同样的参数却能通过——根因就是 daemon 找不到对应 schema 文件。v0.11.1 改回 embedded-first 校验,schema 跟随二进制一起编译,不再依赖 postinstall 的写盘动作。
loom doctor 的诊断能力
loom doctor 是一组静态与动态检查的汇总:
| 检查类别 | 含义 |
|---|---|
| 文件存在性 | Chromium、shim、daemon 二进制、launchd plist |
| 进程健康 | daemon 进程是否在跑(0.9.1 起通过 ShimRequest::Health CBOR 变体做深探针,返回 ShimHealthInf…,由 shim-side handler 填充;见 release v0.9.1) |
| Schema 一致性 | embedded schema 与 daemon 期望一致(v0.11.1 后该检查项不再依赖磁盘文件) |
| Vault 依赖 | Keychain 后端是否就绪(详见下节) |
注意:doctor 的「进程在跑」≠「能正常服务请求」。如果 daemon 启动后 IPC socket 与 Tokio I/O driver 在 fd 3 竞态(0.9.2 之前的 issue #71),所有 web.* 会以 surface_trap 形式被 surface layer 截住——loom doctor 不会自动识别这种「半活」状态,必须配合 daemon.health({deep: true}) 或复现一次 web.navigate 才能暴露。
Vault 与威胁模型
Vault 是凭据生命周期的事实源,其 trait 与实现分别在 loom-core/src/vault/vault.rs 与 loom-core/src/vault/impl_local.rs。LocalVault::grant 强制两道门:
- 凭据类型白名单:当前仅放行
CredentialType::OAuth与CredentialType::Cookie;ApiKey/Saml/Basic仍是保留 slot,会以vault_credential_type_unsupported拒绝(错误上下文里会带allowed_types: ["oauth2_authorization_code_pkce","cookie"],见 vault/impl_local.rs:50-80)。 - 威胁模型确认:调用方必须把
opts.threat_model_acknowledged置为true,否则以vault_threat_model_missing拒绝(见 vault/impl_local.rs:90-130)。
威胁模型文档本身是受测的:单测会校验仓库内的 vault_threat_model.md 至少包含 # Vault Threat Model 标题与 ## Attacker Classes / ## Security Goals / ## Trust Boundaries / ## Abuse Cases 四个固定二级章节,缺一即失败。
flowchart TD
A[grant call] --> B{credential_type in OAuth/Cookie?}
B -- no --> X1[vault_credential_type_unsupported]
B -- yes --> C{threat_model_acknowledged?}
C -- no --> X2[vault_threat_model_missing]
C -- yes --> D[secret exists check]
D --> E[append_audit GrantIssued]
E --> F[(manifest hash chain)]grant 成功后会通过 ManifestWriter::append_audit 把一条 AuditEntry { audit_kind: GrantIssued, … } 追加到与 action receipt 同一条 hash chain 上(见 manifest_writer/manifest_writer.rs:120-160),从而把凭据生命周期与 NFR-DET-01 决定的确定性回放哈希绑定在一起——任何 grant 的审计回放都会落进同样的 chain 校验。
常见故障速查
| 症状 | 版本 / Issue | 根因 |
|---|---|---|
Linux 新装后 loom doctor 报 chromium binary not found | 0.9.2 修复 #70 | postinstall 未把 Chromium 落到正确路径 |
所有 web.* 返回 surface_trap | 0.9.2 修复 #71 | shim IPC socket 与 Tokio I/O driver 在 fd 3 竞态 |
loom.web.navigate 带 until/timeout_ms 被 schema_violation 拒 | 0.11.1 修复 | 0.11.0 改用磁盘 schema 但 postinstall 未落盘 |
Vault grant 报 vault_threat_model_missing | 行为正确 | 调用方未设 threat_model_acknowledged=true |
| GC 误删活跃 blob | 见 content_store/impl_local.rs:1-40 | collect_referenced_blobs 必须解码 receipt_canonical_bytes 才能找到 CAS 引用,否则会把仍在被 manifest 指向的 DOM/screenshot blob 回收掉 |
See Also
来源:https://github.com/mentiora-ai/loom / 项目说明书
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
可能增加新用户试用和生产接入成本。
安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
Pitfall Log / 踩坑日志
项目:mentiora-ai/loom
摘要:发现 8 个潜在踩坑项,其中 1 个为 high/blocking;最高优先级:运行坑 - 来源证据:e2e-real-world: scheduled run failed。
1. 运行坑 · 来源证据:e2e-real-world: scheduled run failed
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个运行相关的待验证问题:e2e-real-world: scheduled run failed
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 证据:community_evidence:github | https://github.com/mentiora-ai/loom/issues/179 | 来源讨论提到 macos 相关条件,需在安装/试用前复核。
2. 配置坑 · 可能修改宿主 AI 配置
- 严重度:medium
- 证据强度:source_linked
- 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
- 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
- 证据:capability.host_targets | https://github.com/mentiora-ai/loom | host_targets=mcp_host, claude_code, claude
3. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 证据:capability.assumptions | https://github.com/mentiora-ai/loom | README/documentation is current enough for a first validation pass.
4. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 证据:evidence.maintainer_signals | https://github.com/mentiora-ai/loom | last_activity_observed missing
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 证据:downstream_validation.risk_items | https://github.com/mentiora-ai/loom | no_demo; severity=medium
6. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 证据:risks.scoring_risks | https://github.com/mentiora-ai/loom | no_demo; severity=medium
7. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 证据:evidence.maintainer_signals | https://github.com/mentiora-ai/loom | issue_or_pr_quality=unknown
8. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 证据:evidence.maintainer_signals | https://github.com/mentiora-ai/loom | release_recency=unknown
来源:Doramagic 发现、验证与编译记录