开发者体验与生产安全经常被写成同一套 bootstrap:如果状态不存在就创建,字段缺失就补齐,版本不一致就自动升级。它在本地很方便,进入生产后却意味着应用进程可以悄悄改变身份、策略和权限。
Agent Foundation 的 Runtime 选择了另一条路:同一个小型 facade 提供一致的 Agent 调用形状,但 local 与 production 的 bootstrap 权限完全不同。
开发者可以在本地首次创建 project-private sealed state;生产环境只能验证 adopter 已经预建的身份、Variant、Registration、namespace、preset lineage 与 credential mapping。验证不通过就失败,Runtime 不代建、不修补。
查看 Agent Foundation 项目总览 · 打开本文交互图
一条普通 Agent 能理解的黄金路径
面向普通开发者的调用顺序很小:
turn = runtime.before_model(...) answer = host_agent(turn) plan = runtime.after_model(turn, answer=answer) result = runtime.validate_outcome(turn, outcome=answer)
before_model 读取受限 Context;after_model 只进入 representation planning;validate_outcome 返回 validated_no_write。新 facade 没有 record_outcome,也不会在一次普通模型调用之后悄悄写 Memory、Relation、ReviewDecision 或 Graph。
真正的治理动作必须走显式方法,例如后续版本提供的 Memory 或 Observation governance workflow。
Local bootstrap 为什么可以创建
本地目标是让开发者无需 Secret、PostgreSQL、外部 Graph 或 MCP 就能跑通一条真实 Runtime 路径。但“可以创建”不等于“随便创建几张 SQLite 表”。
首次初始化采用:
- 跨进程锁,避免两个进程同时初始化同一目录;
- sibling staging directory,在目标目录旁完整构建候选状态;
- 整目录原子发布,避免进程中断留下半套状态;
- sealed manifest 与 fingerprints,绑定 identity、package defaults、Profile、Blueprint、Variant、Registration 和 route;
- project-private immutable Variant,防止多个项目共享一份会漂移的本地身份。
只有完整候选通过内部一致性检查后,目标目录才会出现。
Local 首次初始化可以形成密封状态;精确重开与 production bootstrap 都只能验证。所有回执均经公共 Runtime façade 返回。
精确重开比“自动修复”更重要
第二次打开同一个 state_dir 时,Runtime 重新核对 manifest 与 live SQLite lineage。只要 identity、package defaults、Registration、Profile、Blueprint、Variant 或 route 发生漂移,就 fail closed。
它不会:
- 根据当前代码重新编译并覆盖旧状态;
- 替换不匹配的 Variant;
- 在原目录补一项新 policy pack;
- 重新 seal 一个已经漂移的目录;
- 把失败包装成“已自动升级”。
精确重开成功时,configuration_writes_performed=false。这条诊断很重要:它证明“成功打开”不是又执行了一轮配置修复。
Production bootstrap 为什么只能验证
生产身份与权限应由 adopter 的部署和安全控制面负责,而不是由业务请求第一次触发时临时生成。
因此 production bootstrap 要求:
- adopter-owned credential;
- secret-free descriptor;
- 精确
mapping_revision; - 已存在且可重读的 Registration、namespace 与 preset lineage;
- 实际 principal 的 scopes 与冻结合同完全匹配。
Runtime 只调用 Foundation 公共 API 验证这些事实。它不创建 production Variant,不修复 Registration,不改变 scope,也不会因为 descriptor “看起来合理”就接受请求体自报身份。
身份验证失败与可选 Context retrieval degraded 也被明确区分。前者阻止 Runtime 打开;后者可以返回受限降级结果,但不能伪装成健康权威。
为什么要分三类副作用
一个单一的 writes_performed 很容易误导。
Local 首次 bootstrap 确实会写配置文件和 SQLite;如果只看“没有语义写”,就可能把初始化描述成完全零写。相反,after_model 和 validate_outcome 应当在三类副作用上都保持 false。
因此 receipt 分别报告:
semantic_authority_writes_performed;configuration_writes_performed;operational_writes_performed。
首次 local initialization 会报告 configuration/operational writes;精确 reopen 不再报告配置写;模型后的 planning 与 outcome validation 三类均为 false。
这让“零写规划”“本地初始化”和“生产权威写入”不再混成一个模糊指标。
personal-safe 为什么必须精确解析
Runtime 没有新造一套类似但不同的默认策略。personal-safe 精确解析到既有 personal-autonomous lineage,并冻结对应 package defaults 与 identity。
Local 可以为当前项目创建 private immutable Variant;production 只能验证 adopter 已预建且完全匹配的 Variant。若 sealed state 缺少后续版本要求的新 Policy Pack,系统要求使用新的 state_dir,不会对旧目录静默升级。
这是兼容性边界:相同名称必须指向相同合同,旧密封状态也不能因为 package 更新获得新的策略含义。
实际验证到哪里
AF-C02 的验收覆盖:
- focused safety tests;
- AF-C01、client 与 app compatibility;
- 完整 backend/SDK 回归;
- mypy、Ruff、compileall 与 whitespace gate;
- clean wheel、fresh install 和 local 首次初始化;
- exact reopen 零配置写;
- production bootstrap 缺失或不匹配身份时 fail closed。
这证明的是受限 developer preview 的 bootstrap 机制。它不证明 production IAM、TLS、Secret custody/rotation、HA/DR、服务重启恢复或发布流程已经完成。
开发者便利不应成为生产写权限
很多平台把 production bootstrap 做成 local bootstrap 加几个环境变量。这样一来,开发者便利路径也把“创建身份、选择策略、修复权限”的能力带进了生产进程。
我的判断是:API 形状可以一致,authority 不应一致。 Local 环境可以在受限目录内创建可丢弃的密封状态;production 环境只能验证外部控制面已经完成的配置。把两者分开,开发者仍然有一条短黄金路径,而生产系统不会因为第一次请求或一次升级悄悄改变自己的身份。
