- 人工智能
- AI 应用
- 交互助手
- AI Agent
【免费下载链接】ironclaw
IronClaw is an Agent OS focused on privacy, security and extensibility
本文围绕 IronClaw 开源仓库的设计文档 target-architecture/families/events.md 展开,结合
crates/events/家族四个 crate 的源码与测试,完整讲解其"证据、派生视图、传输流"三层架构:生产者如何写入脱敏事件与审计信封,ironclaw_event_store如何以 fail-closed 策略选择持久化后端,ironclaw_event_projections如何在不持有写端口的前提下重放折叠只读模型,以及ironclaw_event_streams如何在传输无关的前提下完成授权、准入与脱敏校验。读完本文,你将掌握这套四阶段单向证据管线的分层规则、每个 crate 的公开接口与关键实现、生产环境后端选择与安全边界,并能在自己的 Agent 系统中复刻同样的"可重建、不可篡改、绝不成为权威"的事件设计。
IronClaw 是一个以隐私、安全与可扩展性为核心的 Agent OS。在其 Reborn 架构中,crates/events/家族承担了整个系统的"发生了什么"的可追溯记录职责:它既不是屏幕当前显示的内容,也不是某个业务主体(线程、触发器、记忆文档)的类型化记录,而是跨越内核、循环、领域与产品各层的横向事实流。整个家族严格按"证据 → 存储 → 投影 → 流"四个阶段单向推进,任何反向的依赖箭头或写入路径都被视为设计缺陷。
一、家族定位:四阶段单向证据管线
crates/events/的定位可以用一句话概括:它是系统"发生过什么"的记录,与"屏幕此刻显示什么"在结构上严格分离。原设计文档将这条链路描述为一条深度为四级的单向管道:
crates/events/ ├── ironclaw_event_log 证据词汇与日志 trait(无存储驱动) ├── ironclaw_event_store 持久化后端与 fail-closed 配置校验 ├── ironclaw_event_projections 重放派生的只读读模型 └── ironclaw_event_streams 准入校验的流式投递一条事件从产生到被订阅者消费,恰好经过四个阶段:
- 某个生产者发出一个已脱敏的事件或审计信封;
ironclaw_event_log的 trait 接纳它;ironclaw_event_store选择一个持久化后端,在单调游标(monotonic cursor)下追加该条目;ironclaw_event_projections按需将日志折叠(fold)为限定作用域、仅元数据的读模型;ironclaw_event_streams对这些投影进行授权与准入,提供实时或重放订阅——它只读取投递领域(outbound)的推送候选,从不真正发送。
家族有一条铁律:没有任何东西反向运行。投影不能修改它折叠出来的日志;流不能凭空发明未通过重放得到的状态;只有ironclaw_event_store可以写入持久化日志,且家族中没有任何 crate 可以"决定权威"(decide authority)。
从源码结构看,这条单向性不只是文档约定,而是被依赖关系写死的结构性事实:ironclaw_event_projections只依赖ironclaw_event_log与中性的权威词汇 crate,没有任何可写后端;ironclaw_event_streams只依赖ironclaw_event_projections、权威词汇(含 turn 词汇)以及ironclaw_outbound的唯一一个只读方法。家族根目录的 AGENTS.md 将这条法律明确为三条:"projections never write authority;streams never invent state;only the store isolates drivers"(投影永不写权威;流永不发明状态;只有存储隔离驱动),并补充了家族准入清单——脱敏证据词汇与日志 trait、持久化后端选择与 fail-closed 配置校验、重放派生读模型、准入校验的流投递,恰好这四个阶段,别无其他。
二、边界:与 substrates、domains、product 的分工
设计文档用三个对比精确刻画了这个家族的独特位置。
vssubstrates/(底层机制 vs 时间性记录):文件系统、libsql 运行时、密钥、网络、安全等 substrate crate 提供的是"无时间概念"的机制——隔离、连接准入、加密、出口加固。events/是在这些机制之上构建的时间性证据记录:ironclaw_event_store通过存储织物(storage fabric)打开持久化后端,并把每一次追加都路由经过它。substrate 没有历史;events/就是历史本身,它与 substrate 的唯一依赖就是它所追加的存储织物。
vsdomains/(主体记录 vs 横切事实流):领域 crate 为某个主体(线程、触发器、记忆文档)拥有类型化的记录文法;events/拥有的是跨切面的事实流,它不是某个主体——它没有线程记录、没有触发器记录,只有"某事发生了"或"做出了某个审计相关决策"的脱敏形态。领域建模"这个事物此刻是什么",events/建模"发生了什么、可重放、与由哪个领域引起无关"。
vsproduct/(投影 vs 产品视图):ironclaw_event_projections产出的是仅元数据、重放派生、作用域校验的读模型,没有写端口,也没有自己的物化存储;ironclaw_assistant负责把这些投影组装成用户可见的视图,并拥有展示与命令语义。投影对"屏幕如何渲染"或"用户下一步能做什么"没有任何意见,依赖方向只允许从 product 指向 events,绝不反向。
家族内部的三契约分离是承重设计:证据(log)、投影(projections)、流(streams)是三个独立契约,分别拆成独立 crate:
ironclaw_event_log是纯词汇与 trait,没有任何存储驱动——所有只需要记录事实的生产者因此完全不需要编译任何数据库或 TLS 依赖;ironclaw_event_store是第二个独立 crate,纯粹为了隔离驱动依赖锥(driver cone)并承载 fail-closed 的后端选择策略;它依赖ironclaw_event_log,绝不反向;ironclaw_event_projections是第三个独立 crate,因为它必须可证明不写入——它只依赖证据词汇与中性权威词汇,绝不依赖任何存储驱动;ironclaw_event_streams是第四个独立 crate,因为只有它被信任读取投递领域(outbound)的推送候选,家族中其他 crate 都不得持有该依赖。
三、归属清单:什么属于这里,什么永远不属于
设计文档给出了一份严格的"准入/禁入"清单,这也是架构评审的直接依据。
属于这里(Belongs):
- 脱敏的事件与审计词汇、无驱动的追加日志 trait;
- 持久化后端选择与 fail-closed 生产配置校验;
- 重放派生、作用域与游标受限、无物化存储的读模型;
- 传输无关的订阅授权、准入控制,以及在任何数据跨过线路之前的脱敏校验。
永远不属于这里(Never belongs):
- SSE、WebSocket、Webhook 框架或任何具体传输——那是产品家族(
ironclaw_webui等)的职责; - 产品视图组装、命令处理或展示逻辑;
- 第二个写入权威——任何投影或流都不得写回持久化日志,也不得发明未通过重放得到的状态;"清理持久化行"不是这个家族提供的概念;
- 存储驱动(在 store 之外)——
ironclaw_event_store是唯一被允许携带数据库/TLS 驱动锥的 crate; - 供应商名称;
- 原始密钥、原始主机路径、原始工具输入/输出、审批理由、调用指纹(invocation fingerprint)、租约(lease)材料——以任何持久化或流式形态都不允许。
家族根 AGENTS.md 还补充了领域记录文法(domain record grammar)属于crates/domains/,本家族只拥有横切事实流。
四、依赖方向:从叶子到出口的单向图
原设计文档给出了完整的依赖图,这也是架构测试实际校验的对象:
ironclaw_event_log 只依赖中性权威词汇 crate(家族的叶子) ironclaw_event_store 依赖 event_log + ironclaw_common + 存储织物 crate + 权威词汇 ironclaw_event_projections 依赖 event_log + 权威词汇(别无其他) ironclaw_event_streams 依赖 event_projections + 权威词汇(含 turn 词汇)+ outbound 领域(仅一个只读方法)家族之外只有两个入口:
- 所有生产者/读者通过
ironclaw_event_log的 trait 与ironclaw_event_projections的服务进入,从不直接解析持久化行; - 唯一的组装层例外:组合根(composition root,
crates/app/ironclaw_composition)调用ironclaw_event_store的后端选择工厂,构造出分发给所有人的持久化日志句柄。
家族从不依赖内核、循环、扩展或产品家族。AGENTS.md 指出:14 个工作区 crate 在 Cargo.toml 中声明ironclaw_event_log = ...(可用grep -rl '^ironclaw_event_log = ' --include=Cargo.toml crates验证),覆盖内核/循环/领域/产品各层的生产者。
这些规则由crates/app/ironclaw_architecture_tests中的架构测试强制执行(运行cargo test -p ironclaw_architecture_tests),包括:
- 层矩阵:每个 crate 声明
[package.metadata.ironclaw] layer = "substrates",矩阵禁止命名 kernel/loop/product/app; - 每 crate 拒绝规则:投影不得命名
ironclaw_event_store或ironclaw_filesystem("投影永不写"由链接权限强制);流不得命名ironclaw_event_log、ironclaw_event_store或ironclaw_filesystem(它只能通过投影触及证据); - 驱动隔离:只有被授权 crate 能链接 Postgres 等持久化驱动,且
ironclaw_event_store只能在私有后端模块体内提及驱动名; - 同层边:恰好固定五条事件族边——
event_store → {event_log, filesystem}、event_projections → event_log、event_streams → {event_projections, outbound},新增或过期的同层边都会导致测试失败; - watch 与 push 是两个决策:流授权订阅独立于 outbound 是否授权推送,写入 outbound 的路径永远是缺陷。
五、安全与权威模型:脱敏在源头,投影永不成为第二真相源
这个家族继承了内核外围托付的持久化审计/事件追加与重放游标职责,并贯彻一条总规则:投影是可重建的,且永不拥有权威。设计文档将其拆成三个"何时安全":
- 证据只有在
ironclaw_event_log的构造函数里完成源头脱敏后才安全持久化; - 只有经过
ironclaw_event_projections的作用域校验 + 仅元数据折叠后才安全投影——该 crate 没有任何写端口,因此结构上就不可能成为第二真相源; - 只有经过
ironclaw_event_streams独立授权后才安全投递——watch 与 push 永远是两个决策,绝不是一个:订阅者对被投影的读权限,绝不意味着投递资格。
crates/events/AGENTS.md还指出本家族不提供"清理持久化行"的概念,因为"第二个写入权威"在这个家族中没有位置。
六、ironclaw_event_log:脱敏词汇与追加日志 trait
ironclaw_event_log是整个家族的叶子与中性契约,其 crate 文档(src/lib.rs)明确它定义了"每个 Reborn 系统服务 crate 用来记录可观测运行时/进程迁移与控制面审计的小型脱敏词汇",加上宿主运行时、调度器、进程管理器与审批解析器用来暴露可重放作用域流的持久化追加日志基座。它没有任何存储驱动,公开表面如下:
EventSink/AuditSink(尽力而为):trait 文档(src/sink.rs)明确"一次 sink 失败不得改变运行时或控制面结果"——返回Result只是让实现可以把诊断交给独立的观察者,绝不是让尽力而为的调用方短路周围的工作流。运行时关键路径的生产者必须显式要求NonBlockingEventSink,防止异步专用 sink 被接进绝不能等待的路径。DurableEventLog/DurableAuditLog(显式错误):追加失败必须传播;read_after_cursor受两层权威门控——调用方必须先验证请求的EventStreamKey与消费者被授权的流匹配,然后由实现(而非调用方)强制ReadScope,使项目级/线程级消费者无法拿到同流内其他项目/线程的记录。DurableEventLog还要求实现提供append_batch(默认按条追加,可被合并覆盖)与原子化的head_cursor(PR #3931 引入,用于区分"重放"与"实时"边界,杜绝竞态)。- 游标词汇:
EventCursor(单调、serde(transparent)包装u64)、EventStreamKey(按(tenant, user, agent)分区)、ReadScope(在流内进一步限定 project/mission/thread/process,Some字段是收紧而非宽松默认,ReadScope::any()仅限测试与管理聚合路径)、EventLogEntry<T>与EventReplay<T>(src/cursor.rs)。 - 错误词汇:
EventError提供Serialize、Sink、DurableLog、ReplayGap { requested, earliest }与InvalidReplayRequest(src/error.rs)——显式的重放缺口错误是游标设计的核心:游标早于最早保留条目时返回ReplayGap,传输层据此请求快照/重建,而不是静默丢数据。 - 内存引用实现:
InMemoryDurableEventLog、InMemoryDurableAuditLog、InMemoryEventSink、InMemoryAuditSink,用于测试与参考循环;生产后端在ironclaw_event_store中,依赖这些 trait 而非把驱动拉回本 crate。
6.1 脱敏不变量:构造即脱敏
RuntimeEvent是脱敏后的运行时事件载荷,字段保持pub以方便进程内检视,但在每一次 I/O 边界都强制执行脱敏不变量:typed 失败构造函数与with_error_summary在构造时应用净化;自定义Serialize/Deserialize在进出线路时重跑净化器,因此即使进程内调用方直接拼字段,也无法把原始错误文本、路径或 token 形状的秘密走私过任何serde_json::to_*或持久化append路径(src/runtime_event.rs)。
具体的脱敏规则(来自源码常量与函数):
error_kind只接受lower_snake_case标识符(可带.或:分隔),整体不超过 64 字节、每段不超过 24 字节,任何形似路径、JWT、base64 token、API key、数字前缀、前导下划线的值都被折叠为稳定的UNCLASSIFIED_ERROR_KIND = "Unclassified";error_summary由宿主编写且有界(512 字节上限),不安全的非空摘要被折叠为固定安全显示标记(如"the tool failure details were redacted"、"can't access your workspace file");duration_ms被钳制到MAX_RUNTIME_EVENT_DURATION_MS(24 小时,即 86_400_000 ms),保证可观测元数据有界;- hook 相关字段(
hook_id、hook_point、hook_trust_class、hook_decision、hook_failure_category、hook_failure_disposition)与恢复字段(recovery_stage/class/disposition)全部使用闭合词汇标签并通过对应净化器。
RuntimeEventKind是闭合枚举(serde(rename_all = "snake_case")),共 21 种事件种类:DispatchRequested、RuntimeSelected、DispatchSucceeded、DispatchFailed、CapabilityActivityRequested/Succeeded/Failed、ModelStarted/Completed/Failed、AssistantReplyFinalized、LoopCompleted/Cancelled/Failed、ProcessStarted/Completed/Failed/Killed、HookDispatched、HookDecisionEmitted、HookFailed、FailureRecovered。值得注意的是,审批相关的事件种类被刻意缺席——审批解析是控制面关注点,以AuditEnvelope+AuditStage::ApprovalResolved的形式记录。
6.2 安全审计词汇:无载荷的设计
src/security_audit.rs 定义了SecurityAuditSink/SecurityAuditEvent等安全审计原语,其核心不变量是无自由文本 String 载荷:事件只记录哪个边界(SecurityBoundary:LeakDetector、NoExposureGuard、CredentialChannel、AuthContinuation、HookDeny、McpDirectLease)、什么决策(SecurityDecision:Blocked、Allowed、ScopeMismatch、ReplayRejected)、一个'static原因代码(如leak_redact_failed、no_exposure_block_header)、可选 capability id 与作用域、以及时间戳。原因代码按"指标名"约定:小写、snake_case、永不用户派生、永不 PII、永不秘密。该 crate 还提供TracingSecurityAuditSink与NoopSecurityAuditSink等实现。
七、ironclaw_event_store:fail-closed 后端选择与驱动隔离锥
ironclaw_event_store是"生产组合侧"的持久化后端:它拥有后端选择配置类型、fail-closed 的生产配置校验,以及实现ironclaw_event_logtrait 的具体持久化日志适配器(src/lib.rs)。它同时是家族中唯一被允许携带数据库/TLS 驱动锥的 crate——隔离在这里,意味着家族其他生产者与消费者永远不用编译这段依赖。
7.1 后端选择配置
RebornEventStoreConfig枚举定义了五类后端:
| 变体 | 说明 |
|---|---|
InMemory | 内存引用后端,仅显式本地/测试 profile 合法;生产直接拒绝 |
Jsonl { root, accept_single_node_durable } | 单节点持久 JSONL 后端;生产必须显式接受单节点持久模式,防止成为隐式内存式回退 |
Postgres { url, tls_options } | 通过 URL 打开PostgresRootFilesystem,走统一文件系统分发织物 |
PostgresPool { pool } | 复用已打开的连接池(托管生产用它避免为事件日志再开一个独立池) |
Libsql { path_or_url, auth_token } | 本地路径或远程 URL 打开LibSqlRootFilesystem |
LibsqlFilesystem { filesystem, path_or_url } | 复用已打开的 libSQL 文件系统(path_or_url仅保留用于生产持久性/传输策略校验) |
7.2 fail-closed 校验:生产没有隐式回退
RebornProfile(Standalone/Test/Production)控制哪些回退合法。build_reborn_event_stores(profile, config)在Production下会拒绝:
InMemory→ProductionInMemoryDisabled;Jsonl未显式accept_single_node_durable→ProductionJsonlRequiresAcceptance;- libSQL
http://明文 URL →ProductionLibsqlClearTextDisabled;裸词(无 scheme 无路径语法,如events.db或db.example.com,可能是远端主机名拼写错误或 CWD 相对文件)→ProductionLibsqlAmbiguousTarget(fail closed); - 远端 Postgres 明文(
sslmode=disable)→RemotePostgresClearTextDisabled,除非显式allow_remote_cleartext: true;默认Prefer在远端会被强制升级为Require。
libSQL 目标的分类逻辑(classify_libsql_target)是大小写不敏感的——HTTPS://、LibSQL://的大小写变体不会落入本地文件分支,从而避免"以 URL 命名的节点本地 SQLite 文件"这类静默事故。Postgres 的本地/远端判定基于解析后的Config::get_hosts()/get_hostaddrs()(而非原始字符串),因此hostaddr=关键字形式、postgresql:///db?host=...查询参数形式、混合 socket+TCP 主机列表都被正确归类(源码中的回归测试覆盖了这些边界)。连接池默认DEFAULT_POSTGRES_POOL_MAX_SIZE = 8(从 2 提升,避免单轮读突发在事件存储/触发器仓库/结果读取共用池时自排队),并配有 30 秒的 checkout/create/recycle 超时,把池饱和从"永久卡死"转化为可重试错误。
7.3 文件系统后端与路径布局
src/durable_log.rs 中的FilesystemDurableEventLog/FilesystemDurableAuditLog把持久化日志路由经过ScopedFilesystem的统一append/tail平面,而不是直接说 SQL。路径布局为:
/events/<kind>/<tenant>/<user>/<agent>其中<kind>为runtime或audit,<agent>在无代理 id 时回退为_none。路径组件直接来自已校验的EventStreamKeyid(已被ironclaw_host_api约束到安全字母表)。游标语义:append返回的游标其u64即底层挂载的单调SeqNo;read_after_cursor按有界tail页推进并在 Rust 侧应用ReadScope过滤,next_cursor会越过尾部被过滤的记录,避免下次重放重复扫描;若after > 0而 tail 为空,则回退探测after - 1来区分"已追平 head"与"外部未来游标",后者返回ReplayGap。append_batch按流路径分组、每路径一次多行写入,一轮突发通常共享同一流从而折叠为一次往返。该 crate 还提供CoalescingEventSink(高频生产者的合并 sink,见 src/coalescing_sink.rs)。
为什么单独成 crate:它是家族中唯一允许携带数据库/TLS 驱动锥的 crate(Postgres 驱动仅出现在私有postgres_backed模块体内,架构测试会逐文件扫描),且其公开表面不暴露任何后端特定错误类型——错误被脱敏并后端泛化。
八、ironclaw_event_projections:重放派生的只读读模型
ironclaw_event_projections是读模型边界:上层 Reborn 层应消费这些 DTO,而不是直接解析持久化事件/审计行。crate 文档(src/lib.rs)明确"第一个实现是对DurableEventLog的重放派生,因此独立于具体 JSONL/PostgreSQL/libSQL 适配器"。
8.1 服务与游标词汇
EventProjectionService/AuditProjectionServicetrait 分别提供snapshot与updates两个方法;实现为ReplayEventProjectionService/ReplayAuditProjectionService(后者包装Arc<dyn DurableAuditLog>)。ProjectionScope由stream: EventStreamKey(选择(tenant, user, agent)分区)+read_scope: ReadScope(在分区内收紧,阻止产品调用方观察相邻项目/线程/进程记录)组成。ProjectionCursor是作用域绑定的:每个游标携带其铸造时的ProjectionScope。因为持久化流按(tenant, user, agent)分区而 project/mission/thread/process 过滤发生在读过滤器内部,线程 B 返回的游标其运行时值可能落在线程 A 的共享流内;在错误作用域下重放会静默跳过早期记录,因此作用域不匹配的游标恢复一律返回ProjectionError::RebaseRequired——消费者必须请求全新快照,而不是假设丢失条目被静默跳过。- 硬性分页边界:
MAX_PROJECTION_PAGE_LIMIT = 1_000(请求超限在读取前即被拒绝为InvalidRequest);运行态折叠有STATE_REPLAY_PAGE_LIMIT = 256的页大小与STATE_REPLAY_MAX_EVENTS = 100_000的硬上限,超过则表面RebaseRequired,绝不静默返回部分运行态视图。
8.2 读模型 DTO
ProjectionSnapshot:timeline: ThreadTimeline、runs: Vec<RunStatusProjection>、capability_activities、next_cursor、truncated;ProjectionReplay(updates返回):updates: Vec<TimelineEntry>、capability_activity_transitions、runs、capability_activities、next_cursor、truncated;ThreadTimeline/TimelineEntry:线程时间线条目,含kind: TimelineEntryKind(闭合枚举,映射自RuntimeEventKind)、invocation_id、capability_id、provider、runtime、process_id、output_bytes、error_kind,以及闭合词汇的 hook/恢复元数据;RunStatusProjection:RunProjectionStatus(Running/Completed/Cancelled/Failed/Killed)、last_cursor、updated_at;CapabilityActivityProjection:CapabilityActivityStatus(Started/Running/Completed/Failed/Killed)、first_cursor/last_cursor、error_detail(来自RuntimeEvent.error_summary且重放时重跑净化器);- 审计侧:
AuditProjectionSnapshot/AuditProjectionReplay/AuditProjectionEntry(stage、correlation_id、approval_request_id、action_kind、decision_kind、result_status等)以及MemoryAuditProjectionMetadata(记忆领域审计的可选元数据,如relative_path_hash、byte_count、chunk_count、protected_path_class、reason_code、severity、finding_count)。
8.3 有界内存折叠与 checkpoint
snapshot()的runs始终反映当前作用域流的流头(fold_runtime_to_head逐页增量折叠,内存O(scoped invocations)与流长无关),而不仅仅是被分页的时间线页——否则limit=1的快照会把已终结运行的Running状态悄悄发给消费者(PR #3212 评审反馈)。updates()通过fold_runtime_prefix只为"本页触及的调用"折叠前缀(O(touched.len()))。RuntimeProjectionCheckpointCache为每个作用域缓存折叠进度,把重复轮询从全量重放降为增量推进。
为什么单独成 crate:投影折叠与流订阅完全隔离,投影失败永远不会触及实时订阅;投影与存储驱动完全隔离,使"投影永不写权威"由 crate 被允许链接什么来强制,而非仅靠代码碰巧不写。
九、ironclaw_event_streams:传输无关的流管理器
ironclaw_event_streams是家族的投递腿:传输无关的流管理器,负责授权、准入控制、有界 live/replay 缝合、滞后与重建处理,以及只读的 outbound 推送候选查找——它从不发送(src/lib.rs)。SSE、WebSocket 或任何通道特定帧在此一律不存在。
9.1 EventStreamManager 与注入协作者
EventStreamManager::new(src/manager.rs)接受六个注入协作者,全部以 trait 对象泛型装配:
| 协作者 | 类型 | 职责 |
|---|---|---|
projection | Arc<dyn EventProjectionService> | 快照/更新来源 |
access_policy | Arc<dyn ProjectionAccessPolicy> | actor/scope/view/target 授权检查 |
admission_policy | Arc<dyn ProjectionStreamAdmissionPolicy> | 订阅准入与配额 |
update_source | Arc<dyn ProjectionUpdateSource> | live 更新源 |
redaction_validator | Arc<dyn ProjectionRedactionValidator> | 投递前脱敏复检 |
outbound_store | Arc<dyn OutboundStateStorePort> | outbound 领域只读推送候选查找 |
fetch_snapshot/subscribe等公开方法都会先执行authorize(...)(actor/scope/view/target 授权检查),随后才返回快照、重放或 live 投递。ironclaw_outbound的依赖是单一只读方法,且按设计只读——写入 outbound 的路径在这个家族永远是缺陷。
9.2 RAII 准入许可与默认配额
src/admission.rs 定义ProjectionStreamAdmissionPolicy与ProjectionStreamAdmissionPermit。许可持有AdmissionRelease,其Drop实现自动释放槽位——被遗弃的订阅总是释放它的配额。默认限额(ProjectionStreamLimits::default):
per_tenant: 64 # 每租户最多并发订阅 per_actor: 16 # 每 actor 最多并发订阅 per_scope: 8 # 每作用域最多并发订阅 global: 512 # 全局并发上限任一维度超限即返回AdmissionDenied。AllowAllProjectionAccessPolicy作为默认授权策略存在(生产会注入真实策略)。
9.3 投递前脱敏复检
src/redaction.rs 的NoExposureProjectionRedactionValidator把信封序列化为字符串后扫描 11 个哨兵标记:RAW_PROMPT_SENTINEL、TOOL_INPUT_SENTINEL、TOOL_OUTPUT_SENTINEL、SECRET_SENTINEL、HOST_PATH_SENTINEL、RAW_RUNTIME_OUTPUT_SENTINEL、BACKEND_DIAGNOSTIC_SENTINEL、RAW_PROVIDER_ERROR_SENTINEL、INVOCATION_FINGERPRINT_SENTINEL、APPROVAL_REASON_SENTINEL、LEASE_MATERIAL_SENTINEL——任何命中都返回ProjectionStreamError::Redaction,即任何跨向订阅者的值,在原始提示词、工具输入/输出、秘密、主机路径、提供商错误、调用指纹、审批理由、租约材料或后端诊断上均失败关闭。ProjectionValidationCache(1024 条目有界集)缓存已验证信封,避免对稳定快照反复序列化扫描。
为什么单独成 crate:证据/投影/流的三契约分离是常设设计不变量,本 crate 是它的投递腿——家族中唯一被信任读取投递状态的成员,因此另外三个 crate 可以在完全不考虑投递语义的情况下被推理与依赖。
十、家族治理:AGENTS.md 与架构测试
家族根 AGENTS.md 是家族的"治理法律",除三定律与准入清单外还规定了:
- 每个 crate 的指南都必须复述自己那份法律切片(拥有什么、绝不可持久化或暴露什么、以及自身依赖中哪一个是有意例外);
- 这条家族法律只有家族根能单独表述:单向管线"证据 → 存储 → 投影 → 流",任何指向该顺序的依赖箭头永远错误,无论单 crate 的局部规则如何允许;
- 规则由
crates/app/ironclaw_architecture_tests的架构测试强制执行(cargo test -p ironclaw_architecture_tests),包括层矩阵、每 crate 拒绝规则、驱动隔离与同层边清单(详见第四节)。
原设计文档还注明:家族 AGENTS.md 的"每 crate 携带指南"要求于 2026-08-05 修订为"每条事实一个权威归属地",遵循 guidance-conventions.md——每 crate 一个AGENTS.md或CLAUDE.md作为唯一权威文件,第二个文件只做指针。设计记录、处置、迁移约束与未决决策分别沉淀在 PROPOSAL.md(§6.3 每 crate 处置、§8 依赖模型)、CHECKLIST.md 与 PLAN.md;冻结的契约见 contracts/events.md 与 contracts/events-projections.md。
十一、落地建议与验证入口
在生产组合中,事件与审计日志的构造路径是:组合根调用ironclaw_event_store::build_reborn_event_stores(profile, config)(或build_reborn_event_stores_from_root_filesystem复用既有RootFilesystem),得到RebornEventStores { events, audit }两个Arc<dyn DurableEventLog>/Arc<dyn DurableAuditLog>句柄,再注入给家族内外所有消费者。选择后端时注意:
- 本地单机开发:
Jsonl(需在生产显式accept_single_node_durable: true)或本地 libSQL 绝对/相对路径; - 托管生产:
PostgresPool/LibsqlFilesystem复用 substrate 既有连接,避免为事件日志开第二池;远端 Postgres 必须满足sslmode=require(默认Prefer会被强制升级),远端 libSQL 必须https://或libsql://; - 测试:
InMemory或显式非生产 profile。
验证这套管线行为的测试入口包括:ironclaw_event_log/tests/durable_log_contract.rs(游标/重放契约)、ironclaw_event_store/tests/profile_contract.rs与durable_event_store_contract.rs(fail-closed 配置与持久化后端契约)、ironclaw_event_projections/tests/replay_projection_contract.rs(重放折叠契约)、ironclaw_event_streams/tests/event_stream_manager_contract.rs(授权、准入、脱敏与订阅契约)。
十二、关键要点
- 四阶段单向管线是铁律:证据 → 存储 → 投影 → 流,反向依赖箭头永远错误;只有
ironclaw_event_store写持久化日志。 - 脱敏发生在源头:
ironclaw_event_log构造即脱敏,Serialize/Deserialize在每条线路复检;ironclaw_event_streams投递前以 11 个哨兵再次失败关闭。 - 投影可重建、永不权威:
ironclaw_event_projections无物化存储、无写端口,作用域不匹配的游标恢复强制RebaseRequired。 - watch 与 push 是两个决策:订阅授权独立于投递授权,outbound 依赖是唯一只读方法。
- 驱动锥隔离是结构性事实:只有 store 携带数据库/TLS 驱动,投影与流按链接权限就不可能写权威。
- 游标是压缩友好的:重放只按游标推进,后端可压缩存储而不破坏消费者恢复位置,早于最早保留条目的游标显式返回
ReplayGap。
这套设计把"发生了什么"从"屏幕显示什么"中彻底分离,用依赖图、架构测试与源头脱敏三重手段把安全边界变成可证明的结构事实,是构建可审计、可重放、隐私安全的 Agent 运行时值得直接借鉴的模板。
- 人工智能
- AI 应用
- 交互助手
- AI Agent
【免费下载链接】ironclaw
IronClaw is an Agent OS focused on privacy, security and extensibility
相关推荐
IronClaw 事件子系统(crates/events)架构解析:脱敏证据日志、投影读模型与传输无关订阅流的单向管道
IronClaw 事件子系统(crates/events)架构解析:脱敏证据日志、投影读模型与传输无关订阅流的单向管道 导读 本文聚焦 IronClaw(面向隐
人工智能AI 应用交互助手AI AgentIronClaw 事件系统架构指南:Durable Events、Projection 与 Transport Streams 的可重放治理规则
IronClaw 事件系统架构指南:Durable Events、Projection 与 Transport Streams 的可重放治理规则 导读 Iron
人工智能AI 应用交互助手AI AgentIronClaw 事件投影(Event Projections):只读、元数据级、可重放的读模型边界深度解析
IronClaw 事件投影(Event Projections):只读、元数据级、可重放的读模型边界深度解析 IronClaw 的 ironclaw_event
人工智能AI 应用交互助手AI Agent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考