Files
gori-agent/AGENTS.md
T
2026-08-17 00:49:29 +08:00

10 KiB
Raw Blame History

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。
  • init / setup 必须交互询问并校验 server host/port;扫描其他 Config v3 的声明端口,冲突时警告,新实例建议下一个未声明端口,已有配置不得静默改端口。
  • setup <bot-id> 只重配已有实例:校验目录/config/PID,运行中或 foreign PID 拒绝,固定 Bot ID,保留 agent/skills/permissions/policy/runtime/secrets/publicBaseUrl,确认写入后运行 doctor。
  • setup 的声明冲突提示不替代实际 bind 检查;start 对缺配置、ID 不匹配、错误权限、占位符、运行 PID、端口冲突 fail closed。
  • start 只 spawn 构建后的内部 dist/cli/instance-runner.js <config-path>;PID identity 必须精确匹配 Node executable、runner 和唯一 config 参数。

公开入口仅有:

gori-agent init <bot-id>
gori-agent setup <bot-id>
gori-agent start <bot-id>
gori-agent stop <bot-id>
gori-agent restart <bot-id>
gori-agent status <bot-id>
gori-agent logs <bot-id>
gori-agent doctor <bot-id>
gori-agent list

不兼容旧 instance 前缀;不公开 debug 命令、--config 或 --json。

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/instance-runner.ts
    • 非公开进程入口;加载单实例配置、启动 server,并处理 SIGINT/SIGTERM 优雅关闭。
  • 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。

顶层:

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: type discriminated 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. 配置与实例施工流程

  1. 读取本文件、config.example.json 和 src/config.ts。
  2. 明确 Bot ID、workspace、persona、平台、skills 和最小 permission policy。
  3. 确认 ACP agent executable 与 ACP 可用。
  4. 使用 gori-agent init <bot-id> 或 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. 运行 gori-agent doctor <bot-id>,不发送真实平台消息。
  9. 只有用户明确授权时才启动/停止真实 Bot。

旧仓库本地 config.json、备份和 state 可供人工回退;改造实例时不要删除或覆盖。

8. 测试与验收

行为变化补测试,不削弱测试。配置 schema 变化同步:

  • src/config.ts
  • config.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。实例默认在仓库外。安全性按内容判断,不能只依赖文件名。