Tobatsu 2.0 · 方案

Agent 自助自定义 Runtime

内部 Agent 通过 API 改一份 Dockerfile,系统自动构建 + 验证 + 上线;模板按名字引用,新任务自动用当前版本。

2026-06-20 · cc + codex 收敛 · 最小方案,不做完备平台

目标 + 前提

目标:一个模板缺依赖时,Agent 自己就能改 runtime——改 Dockerfile → 平台自动建 + 验证 → 候选 → 测试 → 升正式。没人手敲镜像、没人手改仓库。

前提(owner 定):用户都是信得过的内部 Agent。不做精细权限、不做 typed validation、不做依赖结构化模型。先把"能自助改 runtime 并自动构建"跑通。

模型:Runtime 是数据库里的 Dockerfile

现成 vs 要做(第一手核过)

好消息:下半截基本都在,只缺"Dockerfile 进库 + 接口 + 自动触发"。

✓ 已现成(不用动)

要做(四块)

数据模型(就加 1 张表)

runtime_dockerfile_revisions

id · runtime_id(稳定ID) · name(稳定名字) · revision(内部递增,模板不引用) · dockerfile_content(完整文本) · parent_runtime_id(从谁分叉) · base_revision_id · content_sha256 · smoke_command(可空,Agent 自带的一条附加验证) · created_by/at

最新版 = 同 runtime_id 下 revision 最大那行;回滚 = 再插一条复制旧内容。一张表够,revision 行本身就是历史。

image_build_requests 三个可空字段:runtime_dockerfile_revision_id / runtime_name / log_path。老的 commit-only 构建请求照常工作。

接口(7 个,开放给可信 Agent)

接口干什么
GET /runtimes列出所有 runtime + 最新版 + 构建状态 + 当前 active/canary
GET /runtimes/{name}读一个 runtime 的 Dockerfile、父、构建状态
POST /runtimes分叉:从某 base 拷一份成新 runtime,立即建
PUT /runtimes/{name}/dockerfile主入口:改 Dockerfile → 插新版 → 同事务建 → 自动 CI
POST /runtimes/{name}/pull-base拉最新 base(Agent 自己合好的 Dockerfile,不做自动 merge)
POST /runtime-profiles/{id}/set-canary候选设成 canary(测试环境优先解析它)
POST /runtime-profiles/{id}/promote-active验过升正式(旧 active 归档)

自动触发 CI(你最强调的)

1API 写入新 Dockerfile revision。
2同一个事务写入构建请求(指向这条 revision)。← 这就是"改了自动触发",不靠人手点。
3轮询服务认领 → 从 DB 读 Dockerfile 写临时文件 → 调现有构建脚本(传 RUNTIME_DOCKERFILE_PATH + 可选 smoke command)。
4构建脚本:现有 identity/doctor smoke + 可选的 Agent 自带 smoke(如 fc-match Montserrat)→ 注册候选 profile。
5候选 → set-canary → _test 验 → promote-active。

只让构建输入从"仓库固定 Dockerfile"变成"DB 里这条 Dockerfile",其余复用现有链路。

Mai 第一个用(走分叉,不动 base)

分叉把影响圈在 Mai,不让 MB/别的模板跟着换镜像。等字体确认是全平台通用,再合进 base。

明确砍掉(不做)

内部可信 Agent 直接改 Dockerfile,API 保存 + 触发 CI。先把闭环跑通。

风险(已知,owner 接受)


源:codex 最简稿 /tmp/codex-runtime-customization-plan.md + cc 代码核实。— 待 owner 拍 → 进入实现清单(DB migration → seed base → API → CI → Mai 首用)。