# gori-agent 项目施工指南 本文件供 Coding Agent 在本仓库施工时使用。先理解 Config v3 和实例隔离契约,再做最小、可验证的修改。 ## 1. 项目定位与固定边界 `gori-agent` 是 Node.js 20+ / TypeScript 项目,通过单个 IM 平台接收请求,并通过官方 Agent Client Protocol(ACP)驱动一个 Coding Agent。 ```text 用户 → 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. 实例目录契约 统一实例根: ```text ${GORI_AGENT_ROOT:-$HOME/.gori-agent}/instances// ├── 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。 日常入口: ```bash gori-agent instance init gori-agent instance start gori-agent instance stop gori-agent instance restart gori-agent instance status gori-agent instance logs gori-agent instance list gori-agent instance doctor ``` 保留 `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` 启动。 - `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` 配置写入。 - `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`。 ## 4. Config v3 契约 仓库中唯一可提交配置说明是 `config.example.json`。它含明显占位符,可通过 schema,但不能启动实际 Bot。 顶层: ```text configVersion 固定 3 bot 固定 Bot、agent、skills、permissions gateway server、入站 policy、唯一 platform runtime.acp state 和 ACP 生命周期 ``` ### 4.1 `bot` ```json { "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[]` 每项直接声明: ```json { "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`: `type` discriminated union,只能是 qq、feishu、wecom、webhook、weixin 之一。 - 对象存在即启用,无 `enabled` 字段。 QQ 群 chat ID 为 `group:`。正式运维 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. 配置与实例施工流程 1. 读取本文件、`config.example.json` 和 `src/config.ts`。 2. 明确 Bot ID、workspace、persona、平台、skills 和最小 permission policy。 3. 确认 ACP agent executable 与 ACP 可用。 4. 使用 `instance init` 或 Coding Agent 生成实例 `config.json`;不要把 example 当运行配置。 5. 交互确认并严格校验 `gateway.server.host/port`;对其他实例的声明端口冲突给出警告和建议,但仍由 `start` 做实际 bind 检查。 6. 写配置必须同目录临时文件 + fsync + atomic rename,最终 `0600`;目录 `0700`。 7. setup 的 secret/token 输入必须不回显;secrets 不在对话、日志、测试输出、diff 中回显。 8. 运行 `instance doctor`,不发送真实平台消息。 9. 只有用户明确授权时才启动/停止真实 Bot。 旧仓库本地 `config.json`、备份和 state 可供人工回退;改造实例时不要删除或覆盖。 ## 8. 测试与验收 行为变化补测试,不削弱测试。配置 schema 变化同步: - `src/config.ts` - `config.example.json` - setup/doctor/instance CLI - README 和本文件 - config、session、store、Gateway、server 测试 最终运行: ```bash 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。实例默认在仓库外。安全性按内容判断,不能只依赖文件名。