9.9 KiB
gori-agent 项目施工指南
本文件供 Coding Agent 在本仓库施工时使用。先理解 Config v3 和实例隔离契约,再做最小、可验证的修改。
1. 项目定位与固定边界
gori-agent 是 Node.js 20+ / TypeScript 项目,通过单个 IM 平台接收请求,并通过官方 Agent Client Protocol(ACP)驱动一个 Coding Agent。
用户 → Platform Adapter → Gateway → AcpSessionManager → AcpWorker → ACP Agent
每个运行实例是一个完整且固定的 Bot:
- 一个 Gateway 进程。
- 一份 Config v3 本地配置。
- 一个
bot.id、workspace、persona。 - 一个 ACP agent。
- 一组直接声明的 skills 与一个 permission policy。
- 一个平台身份。
- 独立 PID、日志和 ACP state。
不要重新引入 Config v1/v2 migration、roles[]、动态 role selection、backends[]、多平台同时启用或单轮 CLI fallback。
2. 实例目录契约
统一实例根:
${GORI_AGENT_ROOT:-$HOME/.gori-agent}/instances/<bot-id>/
├── config.json
├── logs/gori-agent.log
└── state/
├── acp-sessions.json
└── gori-agent.pid
实例目录本身就是该进程的 GORI_AGENT_HOME。约束:
bot.id只允许小写字母、数字和连字符,拒绝/、..等路径穿越。- CLI 加载后必须校验目录名与
config.bot.id相同。 - 实例目录、
logs/、state/为0700。 config.json、PID、state 为0600。- 多实例必须使用不同
gateway.server.port和平台 credentials。 instance init/setup必须交互询问并校验 server host/port;扫描其他 Config v3 的声明端口,冲突时警告,新实例建议下一个未声明端口,已有配置不得静默改端口。- setup 的声明冲突提示不替代实际 bind 检查;
start对缺配置、ID 不匹配、错误权限、占位符、运行 PID、端口冲突 fail closed。
日常入口:
gori-agent instance init <bot-id>
gori-agent instance start <bot-id>
gori-agent instance stop <bot-id>
gori-agent instance restart <bot-id>
gori-agent instance status <bot-id>
gori-agent instance logs <bot-id>
gori-agent instance list
gori-agent instance doctor <bot-id>
保留 start --config、status --config、doctor --config 等用于本地调试,但运行配置不存在时不得回退 example。
3. 核心代码结构
src/config.ts- Config v3 Zod schema、类型、交叉校验和 state 默认路径。
- 只接受
configVersion: 3。
src/server.ts- 组装 fixed Bot、state store、ACP manager、Gateway 和唯一 platform adapter。
- 只挂载所选平台 route。
src/roles/role-registry.ts- 历史路径名保留,但实现是
BotProfileResolver,不是 role registry。 - 加载当前 Bot skills、计算 fingerprint、生成版本化 bootstrap。
- 历史路径名保留,但实现是
src/acp/client.ts- ACP initialize/new/resume/load/prompt/cancel 和 permission request。
src/acp/worker.ts- 直接使用 resolved Bot 的 agent,在
bot.workspace启动。
- 直接使用 resolved Bot 的 agent,在
src/acp/session-manager.ts- 固定 Bot 的 binding、worker pool、恢复、idle sweep、capacity、cancel/reset。
src/core/durable-session-store.ts- state v2,保存 bot/platform identity 和 chat binding。
- 单 writer lock、串行持久化、临时文件、fsync、原子 rename。
src/core/gateway.ts- 入站 allowlist、群 mention、命令、per-chat lock 和回复。
/cancel必须绕过 chat lock。
src/core/command-router.ts/help、/status、/cancel、/new;旧 role 命令返回 retired 提示。
src/platforms/*- Adapter 依赖独立平台 config type,不依赖完整 AppConfig 路径。
src/cli/config-file.ts- fail-closed 加载、example seed 与原子
0600配置写入。
- fail-closed 加载、example seed 与原子
src/cli/instance.ts- 实例目录、PID/log、端口和 lifecycle 管理。
src/cli/doctor.ts- v3、Bot、agent、platform、state、permission 和 placeholder 检查。
src/agents/*、src/core/session-store.ts- legacy compatibility/reference,不是当前运行链路。
dist/- 构建产物;不手改,修改 TypeScript 后运行
npm run build。
- 构建产物;不手改,修改 TypeScript 后运行
4. Config v3 契约
仓库中唯一可提交配置说明是 config.example.json。它含明显占位符,可通过 schema,但不能启动实际 Bot。
顶层:
configVersion 固定 3
bot 固定 Bot、agent、skills、permissions
gateway server、入站 policy、唯一 platform
runtime.acp state 和 ACP 生命周期
4.1 bot
{
"id": "bot-id",
"workspace": "/absolute/path",
"persona": "明确职责、边界和确认点。",
"agent": {
"id": "kimi",
"command": "/absolute/path/to/kimi",
"args": ["acp"],
"env": {}
},
"skills": [],
"permissions": {
"mode": "deny",
"allowedTools": [],
"allowedCommandPatterns": []
}
}
- workspace 必须绝对。
- 一个 Bot 只有一个 agent;不要添加 registry/reference。
- Kimi Code 应使用
args: ["acp"]。 - agent
shell: false,cwd 为 workspace。 - 模型/provider 属于 ACP agent 自己的配置,不写入 gori-agent config。
env不得在模板、日志、diff 中泄漏 token。
4.2 Skills
bot.skills[] 每项直接声明:
{ "id": "skill-id", "file": "/absolute/SKILL.md", "maxBytes": 256000 }
ID 唯一;文件须存在、可读、普通文件且未超限。skill 内容发送给 ACP,也进入 fingerprint;不得放 secret。
4.3 Permissions
deny:默认,拒绝全部 permission request。allowlist:toolCall.name与allowedTools精确匹配;bash/terminal 的 raw command 还要被allowedCommandPatterns完整覆盖。auto:高风险/yolo,只有用户明确授权才能设置。
permission policy 只审批 ACP request,不会注册工具。persona 不是安全边界。请求信息不足时拒绝。命令 regex 应锚定并限制参数,不使用任意 .* 全放行。
4.4 Gateway
gateway.server: host、port、publicBaseUrl。gateway.policy: allowedUsers、allowedChats、requireMentionInGroup。gateway.platform:typediscriminated union,只能是 qq、feishu、wecom、webhook、weixin 之一。- 对象存在即启用,无
enabled字段。
QQ 群 chat ID 为 group:<group_openid>。正式运维 Bot 应配置入口 allowlist。
4.5 Runtime ACP
stateFile为空时为$GORI_AGENT_HOME/state/acp-sessions.json。initializeTimeoutMs: 默认 10000。promptTimeoutMs: 默认 7200000(2 小时)。cancelGraceMs: 默认 5000。idleTimeoutMs: 默认 1800000。sweepIntervalMs: 默认 60000。maxProcesses: 默认 8。
5. Session 与 state v2
Binding key 是当前实例固定的 platform + chatId。不再包含 role。
state v2 header 保存 botId 和 platform。打开时不匹配必须拒绝,不能清空、迁移或覆盖。旧 state v1 也明确拒绝并保留原文件。
Binding 保存 agent ID、workspace、native session ID、Bot fingerprint 和时间戳。fingerprint 包含:
- bootstrap schema version
- Bot ID
- workspace/persona
- agent 定义
- permission policy
- skill 路径和内容 hash
首次消息创建 native session,发送隐藏 bootstrap,成功后保存 binding。重启/idle 后优先 resume,再 fallback load。prompt 失败不重放。
/new 删除当前 chat binding;下一条消息创建新 session。/cancel 不等待 chat lock。
6. 单平台装配
Server 只构造 gateway.platform.type 对应 adapter,只挂载对应 webhook:
- qq webhook 模式 →
/webhook/qq;QQ WebSocket 模式不挂载该 route - feishu →
/webhook/feishu - wecom →
/webhook/wecom - weixin →
/webhook/weixin - webhook →
/webhook/generic
QQ WebSocket 仅在 qq + websocket 模式启动。GET /health 只输出 configVersion、botId、platform 和 aggregate ACP counters,不得输出 credentials 或 native session ID。GET /platforms 返回单 Bot/platform 概览。
7. 配置与实例施工流程
- 读取本文件、
config.example.json和src/config.ts。 - 明确 Bot ID、workspace、persona、平台、skills 和最小 permission policy。
- 确认 ACP agent executable 与 ACP 可用。
- 使用
instance init或 Coding Agent 生成实例config.json;不要把 example 当运行配置。 - 交互确认并严格校验
gateway.server.host/port;对其他实例的声明端口冲突给出警告和建议,但仍由start做实际 bind 检查。 - 写配置必须同目录临时文件 + fsync + atomic rename,最终
0600;目录0700。 - setup 的 secret/token 输入必须不回显;secrets 不在对话、日志、测试输出、diff 中回显。
- 运行
instance doctor,不发送真实平台消息。 - 只有用户明确授权时才启动/停止真实 Bot。
旧仓库本地 config.json、备份和 state 可供人工回退;改造实例时不要删除或覆盖。
8. 测试与验收
行为变化补测试,不削弱测试。配置 schema 变化同步:
src/config.tsconfig.example.json- setup/doctor/instance CLI
- README 和本文件
- config、session、store、Gateway、server 测试
最终运行:
npm run typecheck
npm test
npm run build
git diff --check
bash -n install.sh gori-agent.sh bin/gori-agent
额外检查:
- example 可 parse,doctor 识别 placeholder。
- 不存在的运行配置明确失败。
- tracked diff 无 config、backup、state、log、credentials 或手改 dist。
- 不执行真实平台消息、pull、部署、远程机器修改或 Git mutation,除非用户当次明确授权。
9. 敏感信息与禁止提交
不得提交或粘贴:
- 任何真实
config.json或备份 .env、agent env token/API key- platform credentials
- ACP state、PID、lock、session metadata
- 含真实 chat/user/message ID 或消息正文的日志
.gitignore 已覆盖仓库本地 config.json、备份、日志、dist、node_modules 和 coverage。实例默认在仓库外。安全性按内容判断,不能只依赖文件名。