# NanoClaw 架构图
## 系统概览
```mermaid
flowchart TB
subgraph Platforms["消息平台"]
P1[Discord]
P2[Telegram]
P3[Slack]
P4[GitHub / Linear]
P5[WhatsApp / iMessage / Teams / GChat / Matrix / Webex / Email]
end
subgraph Host["宿主机进程 (Node)"]
direction TB
Bridge["Chat SDK 桥接
(src/channels/chat-sdk-bridge.ts)"]
Router["路由器
(src/router.ts)
platformId + threadId -> messaging_group -> agent_group -> session"]
SessMgr["Session 管理器
(src/session-manager.ts)
创建 inbound.db + outbound.db"]
Runner["容器运行器
(src/container-runner.ts)
OneCLI ensureAgent + 启动"]
Delivery["投递轮询器
(src/delivery.ts)
活跃时 1s / sweep 时 60s"]
Sweep["宿主机 Sweep
(src/host-sweep.ts)
心跳、重试、重复执行"]
Central[("中央库
data/v2.db
agent_groups
messaging_groups
messaging_group_agents
sessions
pending_approvals")]
end
subgraph OneCLI["OneCLI 网关 (0.3.1)"]
Vault["Agent Vault
秘密 + OAuth"]
Approvals["configureManualApproval
-> pending_approvals"]
end
subgraph Session["每个 Session 的容器 (Docker / Apple Container)"]
direction TB
PollLoop["轮询循环
(container/agent-runner)"]
Provider["Agent 提供程序
(claude、opencode、mock;待办: codex)"]
MCP["MCP 工具
send_message, send_file, edit_message,
add_reaction, send_card, ask_user_question,
schedule_task, create_agent,
install_packages, add_mcp_server"]
Skills["容器技能
(container/skills/)"]
InDB[("inbound.db
宿主机写入
偶数 seq
messages_in
destinations
processing_ack")]
OutDB[("outbound.db
容器写入
奇数 seq
messages_out
心跳文件")]
end
subgraph Groups["Agent Group 文件系统 (groups/*)"]
Folder["CLAUDE.md
记忆
每个 group 的技能
container_config"]
end
P1 & P2 & P3 & P4 & P5 --> Bridge
Bridge --> Router
Router --> Central
Router --> SessMgr
SessMgr --> InDB
SessMgr --> Runner
Runner --> OneCLI
Runner --> PollLoop
PollLoop --> InDB
PollLoop --> Provider
Provider --> MCP
Provider --> Skills
MCP --> OutDB
OutDB --> Delivery
Delivery --> Central
Delivery --> Bridge
Bridge --> P1 & P2 & P3 & P4 & P5
Sweep --> InDB
Sweep --> OutDB
Sweep --> Central
Runner -.挂载.-> Folder
MCP -.审批.-> Approvals
Approvals --> Central
Provider -.API 调用.-> Vault
```
## 消息流程 (入站 -> agent -> 出站)
```mermaid
sequenceDiagram
participant P as 平台 (例如 Telegram)
participant B as Chat SDK 桥接
participant R as 路由器
participant SM as Session 管理器
participant IDB as inbound.db
participant C as 容器 (agent-runner)
participant ODB as outbound.db
participant D as 投递轮询器
P->>B: 新消息
B->>R: routeInbound(platformId, threadId, msg)
R->>R: 解析 messaging_group -> agent_group -> session
(agent-shared | shared | per-thread)
R->>SM: 确保 session + DB 存在
R->>IDB: INSERT messages_in (偶数 seq)
R->>C: 唤醒容器 (docker run / 已在运行)
C->>IDB: 轮询 messages_in
C->>C: 格式化 xml, 流式传输到选定的 provider
C->>ODB: INSERT messages_out (奇数 seq)
解析 块
D->>ODB: 1s 轮询(活跃)/ 60s(sweep)
D->>D: hasDestination() 重新验证
D->>B: 通过适配器投递
B->>P: 发送消息 / 编辑 / 反应 / 文件 / 卡片
```
## 命名目的地 + Agent 到 Agent
```mermaid
flowchart LR
subgraph AgentA["Agent Group A (主agent)"]
A_out["输出:
<message to='slack'>...</message>
<message to='browser-agent'>...</message>
<internal>scratchpad</internal>"]
end
subgraph Dests["inbound.db.destinations (每个 agent)"]
D1["slack -> messaging_group 42"]
D2["browser-agent -> agent_group 7
(双向行)"]
D3["github -> messaging_group 13"]
end
subgraph AgentB["Agent Group B (浏览器子agent)"]
B_session["自己的 inbound.db / outbound.db
继承了返回到 A 的目的地"]
end
Slack[Slack 频道]
GitHub[GitHub PR 线程]
A_out -->|解析 + 查找| Dests
D1 -->|投递| Slack
D2 -->|写入 B 的 inbound.db| B_session
D3 -->|投递| GitHub
B_session -.通过 'parent' 回复.-> Dests
```
## 实体模型 + 隔离级别
```mermaid
erDiagram
agent_groups ||--o{ messaging_group_agents : 已连接
messaging_groups ||--o{ messaging_group_agents : 已连接
agent_groups ||--o{ sessions : 运行
messaging_groups ||--o{ sessions : 上下文
agent_groups ||--o{ agent_destinations : 拥有
agent_groups ||--o{ pending_approvals : 请求
agent_groups {
int id
string name
string folder
string agent_provider
json container_config
}
messaging_groups {
int id
string channel_type
string platform_id
string name
bool is_group
string unknown_sender_policy "strict | request_approval | public"
}
users {
string id PK "命名空间 :"
string kind
string display_name
}
user_roles {
string user_id FK
string role "owner | admin"
string agent_group_id FK "null = 全局"
}
agent_group_members {
string user_id FK
string agent_group_id FK
}
user_dms {
string user_id FK
string channel_type
string messaging_group_id FK
}
messaging_group_agents {
int messaging_group_id
int agent_group_id
string session_mode "agent-shared | shared | per-thread"
json trigger_rules
int priority
}
sessions {
int id
int agent_group_id
int messaging_group_id
string sdk_session_id
string status
}
```
### 隔离级别速查表
| 级别 | `session_mode` | 共享内容 | 示例 |
|---|---|---|---|
| 1. 共享 session | `agent-shared` | 工作区 + 记忆 + 对话 | Slack + GitHub webhooks 在同一线程 |
| 2. 相同 agent,独立 session | `shared` / `per-thread` | 仅工作区 + 记忆 | 一个 agent 跨 3 个 Telegram 聊天 |
| 3. 独立的 agent group | (不同的 `agent_group_id`) | 无 | 个人 vs 工作频道 |
## 双库拆分(为什么)
```mermaid
flowchart LR
subgraph Mount["/workspace (挂载到容器中的卷)"]
In[("inbound.db")]
Out[("outbound.db")]
HB["/.heartbeat (文件 touch)"]
end
Host[宿主机进程] -->|"仅写入
(偶数 seq)"| In
Host -->|读取| Out
Container[agent-runner] -->|读取| In
Container -->|"仅写入
(奇数 seq)"| Out
Container -->|每次轮询 touch| HB
HostSweep[宿主机 sweep] -->|stat mtime| HB
HostSweep -->|读取 processing_ack| In
note1["每个文件有且仅有一个写入者。
消除了 SQLite 跨进程写入竞争。
无冲突的 seq 编号。"]
```