20 KiB
Agent Runtime 开发规范
本文是 ClawManager 托管 runtime 的 agent 侧开发规范,适用于 OpenClaw、Hermes,以及后续新增的任意 runtime。开发新 runtime 时,应先满足本文的通用要求,再补充 runtime 自己的启动命令、配置文件和健康检查细节。
相关协议和背景请同时参考:
docs/clawmanager-agent-v2-development-guide.mddocs/clawmanager-agent-v2-contract.mddocs/runtime-agent-integration-guide.mddocs/hermes-lite-pro-agent-development.mddocs/hermes-runtime-agent-development.md
1. 范围和目标
一个托管 runtime 镜像不能只启动业务进程。它必须内置一个常驻 runtime agent,由 agent 在 Pod 内负责:
- Runtime Pod 注册、heartbeat、metrics、gateway 状态上报。
- 接收 ClawManager 下发的 create、delete、drain、restart 等控制指令。
- 管理本 Pod 内多个 gateway 子进程。
- 管理端口池、进程、workspace、UID/GID、资源限制和健康检查。
- 把 ClawManager 注入的 AI Gateway、实例 token、代理信任和 runtime 配置写入每个实例自己的 workspace。
一句话原则:agent 是 Pod 内 gateway 管理器,不是同步启动脚本。
2. 架构约束
每个 Runtime Pod 内只能有一个 runtime agent 控制进程。一个用户实例对应一个 gateway 子进程和一个 workspace。
flowchart LR
CM["ClawManager Backend"]
POD["Runtime Pod"]
AG["runtime-agent"]
GW1["gateway: instance 101"]
GW2["gateway: instance 102"]
WS["/workspaces shared volume"]
CM -- "POST /v1/gateways" --> AG
CM -- "DELETE /v1/gateways/{id}" --> AG
CM -- "POST /v1/drain" --> AG
AG -- "register / heartbeat / metrics / gateways report" --> CM
AG --> GW1
AG --> GW2
GW1 --> WS
GW2 --> WS
浏览器只访问 ClawManager 的 HTTPS 入口。ClawManager 再反代到 Pod 内部 gateway。runtime agent 不应把每个 gateway 的自签 HTTPS 地址直接暴露给前端。
3. 必须遵守的原则
| 原则 | 要求 |
|---|---|
| 异步创建 | POST /v1/gateways 必须快速返回,通常 1 到 3 秒内返回 status=starting,不能阻塞等待业务 gateway 完全启动。 |
| 幂等创建 | 以 instance_id + generation 为主要幂等键,重复请求必须返回同一个 gateway 元数据,不能重复启动进程。 |
| 状态以真实进程为准 | running 只能在进程存在且健康检查通过时上报,不能只读旧缓存。 |
| 端口统一管理 | 端口由 agent 本地分配器加锁分配,启动前检查监听占用,停止后释放。 |
| 配置按 workspace 隔离 | 每个实例的 runtime 配置写入自己的 workspace,不能写全局配置。 |
| 不覆盖用户配置 | 修改 runtime 配置必须做 JSON merge,保留已有字段,数组 append 后去重。 |
| 不写死环境地址 | 不写死外部 IP、域名、CIDR,必须从 env 或 ClawManager 请求中读取。 |
| 内部服务优先 | runtime 内部访问 ClawManager 使用 Kubernetes Service DNS,不使用浏览器访问的外部地址。 |
| 时间必须可信 | token、设备签名、JWT 和 WebSocket 校验依赖时间,agent 必须检测时钟偏移,不能在明显偏移时报告健康。 |
| 安全默认开启 | 控制接口校验 token,路径校验不能越权,命令执行不能拼 shell 字符串。 |
4. Runtime Pod 环境变量
agent 至少支持以下环境变量:
| 变量 | 说明 |
|---|---|
CLAWMANAGER_RUNTIME_TYPE |
runtime 类型,例如 openclaw、hermes。 |
RUNTIME_WORKSPACE_ROOT |
workspace 根目录,默认 /workspaces。 |
RUNTIME_GATEWAY_PORT_START |
gateway 端口起始值,默认 20000。 |
RUNTIME_GATEWAY_PORT_END |
gateway 端口结束值,默认 20099。 |
RUNTIME_AGENT_CONTROL_TOKEN |
ClawManager 调 agent 控制接口使用。 |
RUNTIME_AGENT_REPORT_TOKEN |
agent 上报 ClawManager 使用。 |
CLAWMANAGER_BACKEND_URL |
ClawManager backend 内部地址,推荐 http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001。 |
RUNTIME_AGENT_LISTEN_ADDR |
agent 控制接口监听地址,默认 0.0.0.0:19090。 |
RUNTIME_AGENT_PUBLIC_PORT |
注册给 ClawManager 的 agent 端口,默认 19090。 |
CLAWMANAGER_RUNTIME_IMAGE_REF |
当前 runtime 镜像标识。 |
POD_NAME / POD_NAMESPACE / POD_IP / NODE_NAME |
通过 Downward API 注入的 Pod 身份。 |
CLAWMANAGER_TRUSTED_PROXY_CIDRS |
ClawManager app 或 gateway Pod 的来源网段,供 runtime 的 trusted proxy 配置使用。 |
CLAWMANAGER_CONTROL_UI_ORIGIN |
ClawManager 内部 Control UI origin,默认可由 CLAWMANAGER_BACKEND_URL 推导。 |
要求:
CLAWMANAGER_BACKEND_URL必须是内部服务地址,不能使用https://172.16.1.12:39443这类浏览器外部入口。- 只有对浏览器生成页面 URL 时才使用外部入口。runtime gateway 的信任来源和 LLM base URL 都应使用内部服务 DNS。
- agent 启动时要校验必填 env,缺失时上报
unhealthy,并在/v1/health返回 503。
5. Gateway 创建协议
ClawManager 调用:
POST /v1/gateways
X-ClawManager-Control-Token: ${RUNTIME_AGENT_CONTROL_TOKEN}
Content-Type: application/json
请求字段以 docs/clawmanager-agent-v2-contract.md 为准,当前应支持:
{
"instance_id": 123,
"user_id": 45,
"agent_type": "hermes",
"workspace_path": "/workspaces/hermes/user-45/instance-123",
"port_range": {
"start": 20000,
"end": 20099
},
"uid": 200123,
"gid": 200123,
"cpu_cores": 2,
"memory_mb": 4096,
"disk_quota_mb": 20480,
"generation": 7,
"environment": {
"CLAWMANAGER_LLM_BASE_URL": "http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001/api/v1/gateway/llm",
"CLAWMANAGER_LLM_API_KEY": "instance-token",
"CLAWMANAGER_LLM_MODEL": "[\"auto\"]",
"CLAWMANAGER_LLM_PROVIDER": "openai-compatible",
"CLAWMANAGER_INSTANCE_TOKEN": "instance-token",
"OPENAI_API_KEY": "instance-token"
}
}
成功响应必须快速返回:
{
"gateway_id": "gw-123-7",
"instance_id": 123,
"port": 20017,
"pid": null,
"status": "starting",
"workspace_path": "/workspaces/hermes/user-45/instance-123"
}
创建流程:
- 校验控制 token、
agent_type、instance_id、user_id、generation、workspace_path、端口范围。 - 检查当前 Pod 是否 draining。draining 时返回 409 或 503。
- 按
instance_id + generation查询本地状态。已存在starting或running时直接返回已有元数据。 - 若收到更高 generation,停止并释放同实例旧 generation gateway。
- 加锁分配端口,先标记 reserved。
- 创建 workspace 和 home 目录,设置 owner 为请求中的
uid/gid。 - 写入或合并 runtime 配置。
- 记录 gateway 元数据为
starting。 - 后台启动进程,立即返回。
- 后台健康检查通过后,上报
/api/v1/runtime-agent/gateways/report,状态为running。 - 启动失败或健康检查失败时,上报
error,释放端口,并保留错误信息。
禁止事项:
- 禁止在 HTTP handler 里直接运行前台命令并等待它退出。
- 禁止同一个 create 请求触发多个 gateway 进程。
- 禁止把请求里的任意字符串拼接成 shell 命令。
- 禁止创建不在端口范围内的监听端口。
6. 端口和资源管理
agent 必须实现并发安全的端口分配器:
reserve(instance_id, generation, count) -> port_set
commit(instance_id, generation, port_set)
release(instance_id, generation)
list_used()
要求:
- 分配时持有互斥锁。
- 在锁内检查 agent 内存状态和系统监听端口。
- runtime 如果需要主端口、control 端口、browser 端口或 sidecar 端口,必须一次分配一组端口。
- 启动失败、健康检查失败、DELETE 成功后必须释放端口。
used_slots来自真实starting和健康runninggateway 数量,不能来自旧缓存。
资源隔离要求:
- 每个 gateway 使用独立进程组。
- 业务进程最终以请求里的
uid/gid运行。 - CPU、Memory 使用 cgroup 限制。
- Disk 使用 filesystem quota 或周期扫描加错误上报。
- 删除 gateway 不删除 workspace。
7. Workspace 和配置写入
workspace 固定格式:
/workspaces/{runtime}/user-{user_id}/instance-{instance_id}
agent 必须:
- 对 workspace root 和请求路径执行 realpath。
- 拒绝
..、符号链接逃逸、跨用户或跨实例路径。 - 创建
${workspace}/home,并设置HOME=${workspace}/home。 - 密钥、token、provider 配置文件权限建议
0600。 - owner 设置为该 gateway 的
uid/gid。
runtime 配置必须写在 workspace 内。例如:
| Runtime | 推荐配置路径 |
|---|---|
| OpenClaw | {workspace}/home/.openclaw/openclaw.json |
| Hermes | {workspace}/home/.hermes/hermes.json 或 Hermes 原生配置路径 |
JSON merge 规则:
- 对象字段递归 merge。
- 已存在字段默认保留。
- 平台必须控制的字段可以覆盖,但要在代码中显式列出。
- 数组字段 append 后去重,例如
allowedOrigins。 - 不删除用户已有的未知字段。
- 写入前先生成临时文件,再原子 rename。
8. AI Gateway 和模型凭证注入
ClawManager 会在 POST /v1/gateways 的 environment 字段中下发实例级 LLM 环境变量。agent 必须把这些变量传给 gateway 子进程,并按 runtime 需要写入配置文件。
允许转发给子进程的变量应使用白名单:
CLAWMANAGER_LLM_BASE_URL
CLAWMANAGER_LLM_API_KEY
CLAWMANAGER_LLM_MODEL
CLAWMANAGER_LLM_PROVIDER
CLAWMANAGER_INSTANCE_TOKEN
OPENAI_BASE_URL
OPENAI_API_BASE
OPENAI_API_KEY
OPENAI_MODEL
要求:
CLAWMANAGER_LLM_BASE_URL使用 ClawManager 内部服务 DNS。CLAWMANAGER_LLM_API_KEY和OPENAI_API_KEY使用当前实例 token。- 不能要求用户在 runtime 页面手工填写 OpenAI key。
- 不能把 API key、实例 token、bootstrap token 打到日志。
- 如果
environment里缺少 API key,agent 不应报告 gatewayrunning,应上报error,错误消息明确说明缺少实例 LLM token。
Hermes 落地时应把上述 env 转换成 Hermes 的 provider 配置,推荐语义:
{
"models": {
"providers": {
"auto": {
"type": "openai-compatible",
"baseUrl": "${CLAWMANAGER_LLM_BASE_URL}",
"apiKey": "${CLAWMANAGER_LLM_API_KEY}"
}
},
"primary": "auto/auto"
}
}
如果 Hermes 使用不同配置 schema,也必须满足同样的安全和可用性要求:通过 ClawManager AI Gateway 访问模型,不在镜像内写死厂商 key。
9. 代理信任和浏览器访问
runtime gateway 在 Pod 内部推荐使用 HTTP。浏览器访问链路应为:
Browser HTTPS -> ClawManager HTTPS -> ClawManager backend proxy -> Runtime Pod HTTP gateway
agent 写入 runtime 配置时必须配置:
- Control UI 的
basePath为/api/v1/instances/{instance_id}/proxy。 - 允许的 origin 使用 ClawManager 内部 origin,例如
http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001。 - trusted proxies 使用
CLAWMANAGER_TRUSTED_PROXY_CIDRS或等价 env,不写死100.68.x.x。 - 不使用外部地址
https://172.16.1.12:39443作为 runtime 内部信任来源。
OpenClaw 参考配置:
{
"gateway": {
"auth": {
"mode": "trusted-proxy"
},
"controlUi": {
"allowedOrigins": [
"http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001"
],
"basePath": "/api/v1/instances/123/proxy",
"dangerouslyDisableDeviceAuth": true
},
"trustedProxies": [
"100.68.0.0/16"
]
}
}
说明:
dangerouslyDisableDeviceAuth只能在 ClawManager trusted proxy 模式下使用。- 如果 runtime 不支持 trusted proxy 模式,必须明确实现一种等价机制,保证浏览器通过 ClawManager 代理即可自动进入,不需要用户手工粘贴 gateway token。
- 如果出现
origin not allowed,优先检查allowedOrigins是否使用内部 origin,以及 WebSocket 代理是否正确传递 Origin。 - 如果出现
Proxy headers detected from untrusted address,优先检查 trusted proxies CIDR。
10. 时间同步规范
runtime 侧不能忽略时间问题。以下问题通常与时钟偏移有关:
device signature expired- token 未过期但被拒绝。
- JWT、签名 URL、WebSocket 鉴权异常。
- ClawManager 显示状态和 gateway 实际状态不一致。
agent 必须实现:
- 注册和 heartbeat 响应如果带
server_time,记录本地时间与服务端时间偏移。 - 若偏移超过 30 秒,在日志和 health 中上报
clock_skew_warning。 - 若偏移超过 120 秒,不应报告
ready或 gatewayrunning,应上报unhealthy或error。 - 生成或校验任何带时间的签名时使用 UTC。
- 不在容器里自行修改系统时间。时间同步由 Kubernetes 节点的 NTP、chrony 或宿主机配置负责。
运维要求:
- 所有 Kubernetes 节点必须启用 NTP 或 chrony。
- 发现签名过期类错误时,先比较浏览器机器、ClawManager Pod、runtime Pod、Kubernetes Node 的 UTC 时间。
- agent 健康检查输出应包含当前本地时间、最近服务端时间和估算偏移,便于排查。
11. 状态上报和恢复语义
Runtime Pod 注册 payload 必须包含容量:
{
"runtime_type": "hermes",
"capacity": 100,
"used_slots": 12,
"available_slots": 88,
"state": "ready",
"draining": false
}
Gateway report 每个 gateway 建议包含:
{
"instance_id": 66,
"gateway_id": "gw-66-7",
"gateway_port": 20000,
"gateway_pid": 1234,
"state": "running",
"generation": 7,
"workspace_path": "/workspaces/hermes/user-1/instance-66",
"started_at": "2026-06-03T06:00:00Z",
"updated_at": "2026-06-03T06:00:10Z",
"error_message": ""
}
状态规则:
starting:进程准备中或健康检查尚未通过。running:进程存在、端口监听、HTTP 健康检查通过、必要的代理和 LLM 检查通过。error:启动失败、配置失败、健康检查失败、凭证缺失或端口冲突。stopped:进程已停止,端口已释放。unhealthy:进程存在但健康检查失败。
Pod 重启或升级时:
- agent 启动后先初始化 workspace root、端口池、控制服务和报告客户端。
- 控制服务可用后注册 Runtime Pod。
- 只有初始化完成后才能上报
ready。 - 不要把旧 Pod 的 gateway 当成运行中,除非进程确实存在且健康。
- 收到 SIGTERM 时进入 draining,拒绝新 create,尽量上报最后状态。
- 支持 ClawManager 下发 drain、stop、restart gateway 指令。
12. 健康检查
/v1/health 只有在 agent 能接受控制指令时才返回 2xx。以下情况必须返回 503:
- 必填环境变量缺失。
- workspace root 不可访问。
- 端口池不可用。
- report token 或 control token 缺失。
- 时钟偏移超过健康阈值。
- agent 正在关闭且不再接受请求。
gateway 从 starting 转为 running 前至少校验:
- 端口已监听。
- HTTP
/或 runtime 约定健康端点可访问。 - 代理 base path 配置已写入。
- 使用 ClawManager 内部 Origin 的 Control UI 或 WebSocket 握手不再返回
origin not allowed。 - runtime 如果需要 LLM,使用实例 token 调用 ClawManager AI Gateway 可以返回模型列表或完成一次轻量探测。
健康检查失败时不要上报 running。应上报 error,并带短错误文本。
13. 安全规范
agent 控制接口必须校验:
X-ClawManager-Control-Token。instance_id、user_id、generation类型和值范围。agent_type必须等于当前 Pod runtime type。workspace_path不越权。- 端口只能来自允许范围。
environment只允许白名单 key。
进程启动必须使用 argv 数组,不使用 shell 拼接:
execve(binary, ["hermes", "gateway", "run", "--port", "20017"], env)
禁止:
- 把请求参数拼成
sh -c。 - 日志打印 token、API key、channel secret。
- 允许用户覆盖 agent 自己的控制 token 和上报 token。
- 删除 gateway 时顺手删除 workspace。
- 为了调通临时写死 IP、CIDR 或
allowedOrigins=["*"],除非明确是本地开发环境。
14. Hermes Runtime 开发落地清单
开发 Hermes runtime 时,至少完成以下事项:
| 项目 | 要求 |
|---|---|
| Runtime 类型 | CLAWMANAGER_RUNTIME_TYPE=hermes,注册和上报 payload 中都使用 hermes。 |
| Agent 控制服务 | 监听 0.0.0.0:19090,实现 /v1/health、/v1/gateways、DELETE /v1/gateways/{id}、/v1/drain。 |
| Gateway 启动 | 后台启动 Hermes gateway,使用实例 workspace、端口、UID/GID、HOME。 |
| 配置文件 | 写入 {workspace}/home/.hermes/hermes.json 或 Hermes 原生配置,必须 JSON merge。 |
| AI Gateway | 将 CLAWMANAGER_LLM_* 和 OPENAI_* 注入 Hermes provider 配置。 |
| 代理路径 | Hermes UI 或 WebSocket 必须支持 /api/v1/instances/{instance_id}/proxy base path。 |
| Trusted proxy | 信任 ClawManager 内部 proxy 来源,不信任任意外部来源。 |
| 自动登录 | 浏览器通过 ClawManager proxy 进入时不要求手工粘贴 token 或重复确认自签证书。 |
| 端口组 | 如果 Hermes 除主端口外还有 control/browser/sidecar 端口,按端口组分配。 |
| Skills | skill inventory 和状态上报按 instance_id、workspace_path 分组。 |
| 时间 | 实现 clock skew 检测;偏移过大时不报告 ready/running。 |
| 验收 | 100 个实例并发创建无端口冲突,Pod drain 和重启后状态正确。 |
Hermes 启动命令由 Hermes 项目确定,但 agent 必须保证:
- 命令参数固定且可审计。
- 端口和 workspace 只能来自 agent 校验后的值。
- LLM、proxy、auth 配置在进程启动前已经写入。
POST /v1/gateways返回时进程可以仍在启动,但 metadata 必须已经持久化。
15. 测试和验收
单元测试至少覆盖:
- create gateway 幂等。
- 高 generation 替换低 generation。
- 端口分配并发无冲突。
- 端口被系统占用时跳过。
- workspace path 越权被拒绝。
- JSON merge 保留用户字段,数组去重。
- LLM env 白名单转发。
- 缺少 LLM token 时 gateway 不报告 running。
- trusted proxy 和 allowed origin 配置生成。
- clock skew 阈值判断。
集成测试至少覆盖:
- Runtime Pod 注册为
ready,capacity、used_slots、available_slots 正确。 - 创建 100 个 gateway,端口唯一,状态最终为 running。
- 重复创建同一个
instance_id + generation不重复启动进程。 - ClawManager 反代 WebSocket 不出现
origin not allowed。 - 通过 ClawManager proxy 进入 runtime 不要求手工粘贴 gateway token。
- runtime 内模型调用经过 ClawManager AI Gateway,不出现
No API key found。 - Pod drain 后拒绝新 create,已有 gateway 持续上报,DELETE 后释放端口。
- Pod 重启后不误报旧 gateway running。
上线前 Kubernetes 验证建议:
kubectl -n clawmanager-system get pods -l app.kubernetes.io/component=runtime-agent -o wide
kubectl -n clawmanager-system logs deploy/hermes-runtime --tail=200
kubectl -n clawmanager-system exec deploy/hermes-runtime -- curl -fsS http://127.0.0.1:19090/v1/health
kubectl -n clawmanager-system exec deploy/hermes-runtime -- date -u
kubectl -n clawmanager-system exec deploy/clawmanager-app -- date -u
如果出现认证或签名问题,排查顺序:
- 时间偏移。
- 实例 token 是否下发到
environment。 - runtime 配置文件是否包含 provider 和 API key。
- ClawManager 内部 LLM base URL 是否可达。
- allowed origins 和 trusted proxies 是否使用内部服务地址和 env CIDR。
- gateway 是否真正健康,而不是缓存状态误报。
16. Do / Don't
| Do | Don't |
|---|---|
| 用内部 Kubernetes Service DNS 配置 runtime 到 ClawManager 的访问。 | 写死 172.16.1.12、NodePort、外部 HTTPS 入口。 |
POST /v1/gateways 快速返回 starting,后台拉起进程。 |
在 HTTP 请求里阻塞等待 gateway run 前台进程。 |
按 instance_id + generation 幂等。 |
重试时重复启动多个 gateway。 |
| 上报状态前检查真实进程和健康。 | 只读旧状态文件就上报 running。 |
| JSON merge runtime 配置。 | 覆盖用户的整个配置文件。 |
| 白名单转发 env。 | 把用户请求里的所有 env 原样传给进程。 |
| 使用 trusted proxy 让浏览器通过 ClawManager 自动进入。 | 要求用户手工粘贴 gateway token。 |
| 检测并上报 clock skew。 | 忽略时间,导致 device signature expired 反复出现。 |