docs: add source code learning roadmap

This commit is contained in:
2026-05-13 03:08:45 +00:00
parent 38bb076ac6
commit a8d90d2980

192
docs/learning-roadmap.md Normal file
View File

@@ -0,0 +1,192 @@
# NanoClaw 源码学习路线图
## 前置知识
阅读源码前,确保理解以下核心概念:
- **两层运行时**Host 进程用 Node/pnpmContainer 进程用 Bun。两者不共享代码不共享模块。
- **唯一的 IO 界面**Host 和 Container 之间没有 IPC、没有 stdin pipe。两个 SQLite 文件是唯一的通讯界面:
- `inbound.db` — Host 写Container 读
- `outbound.db` — Container 写Host 读
- **seq 奇偶规则**Host 使用偶数 seqContainer 使用奇数 seq避免双方同时写同一个 DB 时的冲突。
- **实体模型**`users → messaging_groups → agent_groups → sessions`,中间通过 `messaging_group_agents` 多对多连接。
- **会话不等于代理组**:一个 agent group 可以有多个 session比如不同线程每个 session 有自己独立的 `inbound.db` + `outbound.db`
> 建议:先快速浏览 `docs/architecture.md` 和 `docs/architecture-diagram.md`,建立一个心智模型再开始。
---
## 第一层:全局鸟瞰(先读文档)
| 顺序 | 文件 | 解决什么问题 |
|------|------|-------------|
| 1 | `docs/architecture.md` | 整个系统的架构全貌,消息怎么流转 |
| 2 | `docs/architecture-diagram.md` | 消息从进到出的可视化链路 |
| 3 | `docs/db.md` | 三层 DB 模型central + inbound + outbound |
| 4 | `docs/db-central.md` | 中央库 `data/v2.db` 每一张表的职责和字段 |
| 5 | `docs/db-session.md` | 会话库的 schema + seq 奇偶分配机制 + cross-mount 不变式 |
| 6 | `docs/build-and-runtime.md` | 为什么 Host 用 NodeContainer 用 Bun两套锁文件互不干扰 |
---
## 第二层:主循环 — 消息从进到出的主干链路
这是整个系统的脊椎。按调用顺序读,每个文件不必求甚解,但要理解数据流向。
| 顺序 | 文件 | 在链路中的角色 |
|------|------|---------------|
| 7 | `src/index.ts` | 程序入口:初始化 DB、运行迁移、启动所有 channel adapter、启动 poll sweep、启动 CLI socket server |
| 8 | `src/router.ts` | 入站路由:收到消息 → 解析 messaging group → 解析 agent group → 权限门检查 → 创建/查找 session → 写 `inbound.db` → 唤醒容器 |
| 9 | `src/session-manager.ts` | 会话生命周期:管理 session 目录、打开/关闭 DB、心跳检测、跨 mount 的 `journal_mode=DELETE` 不变式 |
| 10 | `src/delivery.ts` | 出站投递:轮询 `outbound.db` → 通过 channel adapter 发送消息 → 处理系统动作(审批、调度等) |
| 11 | `src/host-sweep.ts` | 后台清扫60 秒周期 — `processing_ack` 同步、僵死容器检测、到期消息唤醒、定时任务触发 |
> **到这里你应该能回答:一条用户消息从发出来到 agent 回复,经历了哪些步骤。**
---
## 第三层:容器侧 — Agent 在里面干什么
理解 Host 怎么把消息交给容器之后,钻进去看容器内部。
| 顺序 | 文件 | 在链路中的角色 |
|------|------|---------------|
| 12 | `container/agent-runner/src/index.ts` | 容器入口:加载 `/workspace/agent/container.json`、构建 MCP server 配置、创建 provider、进入 poll loop |
| 13 | `container/agent-runner/src/poll-loop.ts` | 核心大循环:读 `inbound.db` → 调 providerClaude/OpenCode→ 格式化输出 → 写 `outbound.db` |
| 14 | `container/agent-runner/src/providers/factory.ts` | Provider 工厂:根据 `container.json` 中的 `agent_provider` 字段选择 Claude 或 OpenCode |
| 15 | `container/agent-runner/src/providers/claude.ts` | Claude Agent SDK 的具体对接实现 |
| 16 | `container/agent-runner/src/formatter.ts` | 出站消息格式化:按目标 channel 类型做内容适配 |
| 17 | `container/agent-runner/src/mcp-tools/index.ts` | MCP 工具注册入口agent 能调用的所有工具列表 |
---
## 第四层:带着问题深入子系统
以下问题按系统层次组织,每个问题后面标注了需要读的关键文件。带着问题去读比按文件线性读高效得多。
---
### 全局架构
#### Q1: 一条用户消息从 Slack 发出,到 agent 回复出现在聊天框里,完整路径是什么?
> 追踪:`src/router.ts` → `src/session-manager.ts` → `container/agent-runner/src/poll-loop.ts` → `src/delivery.ts`。动手画一张时序图,标注每个环节读/写了哪个数据库。
#### Q2: 为什么 Host 用 NodeContainer 用 Bun两套运行时之间的"协议"是什么?
> `docs/build-and-runtime.md` + `src/container-runner.ts`
#### Q3: `inbound.db` 和 `outbound.db` 为什么各只能有一个 writer`journal_mode=DELETE` 为什么是必须的?
> `docs/db-session.md` + `src/session-manager.ts` 中的注释块
---
### 路由与会话
#### Q4: 一个 messaging group比如 Slack 频道)怎么决定路由到哪个 agent group没匹配上怎么办
> `src/router.ts` 的 `routeInbound()` + `src/db/messaging-groups.ts`
#### Q5: Session 什么时候创建?`agent-shared`、`shared`、per-thread 三种隔离模式的区别是什么?
> `docs/isolation-model.md` + `src/session-manager.ts`
#### Q6: 容器 idle 后被 kill用户再发消息时怎么被唤醒`on_wake` 消息为什么不会被旧容器偷走?
> `src/container-runner.ts` 的 `killContainer()` + `src/container-restart.ts`
---
### 权限与安全
#### Q7: 用户身份怎么确定owner / admin / member 三级的权限检查在哪张表、哪段代码里完成?
> `src/modules/permissions/access.ts` + `src/modules/permissions/db/user-roles.ts`
#### Q8: 陌生人在群里 @bot系统怎么决定是忽略、审批、还是直接响应
> `src/modules/permissions/sender-approval.ts` + `src/router.ts` 中的 access gate 回调
#### Q9: Agent 在容器里能用 `ncl` 命令吗?能查其他 agent group 的数据吗?`cli_scope` 在哪里被检查?
> `src/cli/dispatch.ts` + `src/command-gate.ts` + `src/db/migrations/015-cli-scope.ts`
---
### 容器生命周期
#### Q10: 启动 agent 容器时 mount 了哪些东西?`/workspace`、session DB、CLAUDE.md、skills 分别从哪里来?
> `src/container-runner.ts` 的 mount 参数 + `src/group-init.ts`
#### Q11: Agent 的 system prompt 是怎么拼出来的CLAUDE.md + 全局指令 + container config 各自贡献了什么?
> `src/claude-md-compose.ts` + `container/agent-runner/src/index.ts`
#### Q12: 容器心跳怎么检测?进程活着但 poll loop 卡死了host 怎么发现?
> `src/host-sweep.ts` + `src/session-manager.ts` 中 `.heartbeat` 文件的逻辑
---
### 出站投递与系统动作
#### Q13: Agent 回复消息后delivery.ts 怎么知道用哪个 channel adapter 发送?重试和失败怎么处理?
> `src/delivery.ts` + `src/channels/adapter.ts`
#### Q14: Agent 发起 `install_packages` 或 `add_mcp_server`,从发出请求到容器重建完成,完整的审批-执行链路是什么?
> `container/agent-runner/src/mcp-tools/self-mod.ts` → `src/modules/self-mod/request.ts` → `src/modules/approvals/primitive.ts` → `src/modules/self-mod/apply.ts`
#### Q15: 定时任务cron怎么实现Agent 在容器里能创建吗?触发时谁写消息进 `inbound.db`
> `src/modules/scheduling/recurrence.ts` + `src/modules/scheduling/db.ts` + `src/host-sweep.ts` 中 recurrence 处理
---
### 数据模型
#### Q16: 中央库 `data/v2.db` 有哪些表?它们之间的外键关系是怎样的?
> `src/db/schema.ts` + `docs/db-central.md`。建议自己画一张 ER 图。
#### Q17: DB 迁移怎么组织?我要加一张表或一个字段该改哪些文件?
> `src/db/migrations/index.ts` + 任意一个 `src/db/migrations/0XX-*.ts`
---
### Provider 与 MCP
#### Q18: Claude Agent SDK、OpenCode、Ollama 三个 provider 怎么抽象成统一接口?切换 provider 改什么?
> `container/agent-runner/src/providers/factory.ts` + `container/agent-runner/src/providers/types.ts`
#### Q19: 容器里的 MCP server 怎么启动内置工具core、agents、self-mod 等)和外部 MCP server 有什么不同?
> `container/agent-runner/src/mcp-tools/server.ts` + `container/agent-runner/src/index.ts` 中的 MCP 构建逻辑
---
### Channel 适配器
#### Q20: 如果要加一个新的 channel比如钉钉需要实现什么接口、改哪些文件
> `src/channels/adapter.ts`(接口定义)+ `src/channels/channel-registry.ts`(注册表)+ `src/channels/chat-sdk-bridge.ts`(如果用 Chat SDK 模式)
#### Q21: Chat SDK bridge 是什么?为什么 Discord/Slack/Telegram 等共用它?
> `src/channels/chat-sdk-bridge.ts`
---
## 建议的阅读策略
1. **先跑通主干**第一层→第二层Q1不求甚解但要能画出消息的完整流转路径
2. **再读容器侧**(第三层),理解 agent 内部怎么调 Claude、怎么写回结果
3. **挑一个子系统深入**(第四层),根据你最关心的方向:
- 关注**多租户/权限** → Q7, Q8, Q9
- 关注**容器/部署** → Q6, Q10, Q11, Q12
- 关注**扩展新 provider/channel** → Q18, Q19, Q20, Q21
- 关注**运维/稳定性** → Q2, Q3, Q5, Q14, Q15
4. **最后回到文档**,通读 `docs/api-details.md``docs/agent-runner-details.md`
---
## 关键文件速查表
| 想了解... | 先读这个文件 |
|-----------|-------------|
| 整体启动流程 | `src/index.ts` |
| 消息怎么进来 | `src/router.ts` |
| 消息怎么出去 | `src/delivery.ts` |
| Session 怎么管理 | `src/session-manager.ts` |
| 容器怎么启动/杀死 | `src/container-runner.ts` |
| Agent 的主循环 | `container/agent-runner/src/poll-loop.ts` |
| Agent 能调用哪些工具 | `container/agent-runner/src/mcp-tools/index.ts` |
| 权限检查入口 | `src/modules/permissions/access.ts` |
| ncl CLI 怎么工作 | `src/cli/dispatch.ts` |
| DB 有哪些表 | `src/db/schema.ts` |
| 审批流程 | `src/modules/approvals/primitive.ts` |
| 自我修改如何实现 | `src/modules/self-mod/apply.ts` |