# Boardware Genius Backend

这是 `Boardware Genius` 的后端服务仓库；当前技术命令和包名仍沿用 `nanobot`，但产品品牌按 `Boardware Genius` 表述：

- `nanobot web`：单用户 FastAPI 后端，供独立前端或 `/docs` 调试使用
- `nanobot gateway`：常驻 worker，负责渠道接入、cron、heartbeat
- MCP 动态工具接入
- Outlook 集成：通过外部 `BW_Outlook_Mcp` 服务接入 Microsoft Graph / Exchange EWS
- 工作区文件、技能、插件、代理、MCP 管理等 Web API

如果你后续要把它打包成 Docker 丢到服务器，这份 README 就是给开发和部署同事看的执行文档。

## 这套仓库现在是什么

这不是一个自带前端静态页面的全栈仓库，而是后端仓库：

- Web 模式启动的是 FastAPI API 服务
- Gateway 模式启动的是常驻 agent / channel / cron 进程
- WhatsApp 相关逻辑依赖 `bridge/` 里的 Node 20 bridge
- Outlook 不是仓库内置模块，而是通过外部 `BW_Outlook_Mcp` 仓库接进来

更细的执行链路可以看 [workflow.md](./workflow.md)。

## 目录结构

```text
.
├── nanobot/              # Python 主体：CLI、agent、web、channels、config、MCP
├── bridge/               # WhatsApp bridge（Node 20）
├── tests/                # 测试
├── Dockerfile            # 当前镜像构建文件
├── docker-compose.yml    # 当前自带 compose 示例（偏 gateway / CLI）
└── workflow.md           # 运行链路说明
```

## 运行模式

| 命令 | 用途 | 默认端口 | 适合谁 |
| --- | --- | --- | --- |
| `nanobot agent` | 本地单轮 / 交互调试 | 无 | 开发排查 |
| `nanobot web` | 启动 FastAPI 后端 | `18080` | 独立前端、接口调试、单用户使用 |
| `nanobot gateway` | 启动常驻 worker | 无固定 HTTP 入口 | Telegram/Slack/Email/cron/heartbeat |
| `nanobot status` | 查看配置和 provider 状态 | 无 | 开发、运维 |

注意：

- 如果你是给 Web 前端提供后端，请启动 `nanobot web`，不要误用 `gateway`
- `gateway` 当前不是对外 Web API 服务
- `web` 和 `gateway` 都会碰到同一份 workspace / cron / MCP 状态，通常不要在同一份数据目录上无脑同时跑两套

## 环境要求

- Python `>=3.11`
- 推荐使用 `uv`
- 如果要构建 WhatsApp bridge 或使用仓库自带 Dockerfile，需要 Node.js `20`

本地开发最省事的方式：

```bash
uv sync --extra dev
```

如果你不用 `uv`，也可以：

```bash
python3 -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
```

## 本地快速启动

### 1. 初始化配置

```bash
nanobot onboard
```

初始化后默认会生成：

- 配置文件：`~/.nanobot/config.json`
- 工作区：`~/.nanobot/workspace`

### 2. 填最小配置

下面是一份适合服务器环境的最小示例，重点是：

- 用绝对路径的 workspace
- 建议打开 `restrictToWorkspace`
- 先用 API Key provider，少踩 OAuth 交互坑

```json
{
  "agents": {
    "defaults": {
      "workspace": "/root/.nanobot/workspace",
      "model": "openai/gpt-5"
    }
  },
  "providers": {
    "openai": {
      "apiKey": "sk-xxxx"
    }
  },
  "tools": {
    "restrictToWorkspace": true
  }
}
```

如果你不是跑在容器里，把 `/root/.nanobot/workspace` 换成你自己的绝对路径。

### 3. 检查配置

```bash
nanobot status
```

### 4. 本地调试 agent

```bash
nanobot agent -m "你好"
```

### 5. 启动 Web 后端

```bash
nanobot web --host 0.0.0.0 --port 18080
```

启动后可直接访问：

- `http://127.0.0.1:18080/docs`
- `http://127.0.0.1:18080/api/ping`

## Web API 能力概览

当前 `nanobot web` 提供的 API 大致包括：

- 聊天与流式输出
- 会话管理
- cron 任务管理
- skills / plugins / agents 管理
- 工作区文件浏览、上传、下载、删除
- MCP server 管理与测试
- Outlook 集成状态、连接测试、连接/断开、Overview、Message Detail

如果你有独立前端，这个后端就是给前端接的；如果没有前端，也可以直接走 `/docs` 调试。

## Outlook MCP 集成

这是当前仓库里最容易部署时踩坑的一块。

### 关系先说清楚

当前后端不会自己实现 Outlook 协议，它依赖外部仓库 `BW_Outlook_Mcp`：

- 后端代码位置：`nanobot/web/outlook.py`
- 默认查找逻辑：
  1. 先看环境变量 `NANOBOT_OUTLOOK_MCP_ROOT`
  2. 再看与本仓库同级目录的 `../BW_Outlook_Mcp`
  3. 如果以上都没有，就尝试直接执行 PATH 里的 `bw-outlook-mcp`

也就是说，部署同事必须额外把 `BW_Outlook_Mcp` 这个仓库准备好，或者把它直接安装进镜像。

### 推荐的两种接法

#### 方案 A：把 `BW_Outlook_Mcp` 安装进同一个 Python 环境

这是生产环境更稳的方案。

部署同事需要：

```bash
git clone <你们的 BW_Outlook_Mcp 仓库地址> /srv/BW_Outlook_Mcp
cd /srv/BW_Outlook_Mcp
pip install -e .
```

安装完成后，容器或宿主机里能直接执行：

```bash
bw-outlook-mcp --help
```

这样 Boardware Genius 就会直接用 PATH 里的 `bw-outlook-mcp`，不依赖额外挂载路径。

#### 方案 B：把 `BW_Outlook_Mcp` 作为外部目录挂进来

这是开发或临时部署更方便的方案。

部署同事需要至少做到两件事：

1. 把 `BW_Outlook_Mcp` 仓库拉到服务器
2. 让这个目录里存在一个可执行的 `bw-outlook-mcp`

最简单的约定是：

```bash
git clone <你们的 BW_Outlook_Mcp 仓库地址> /srv/BW_Outlook_Mcp
cd /srv/BW_Outlook_Mcp
python3 -m venv .venv
. .venv/bin/activate
pip install -e .
```

然后给 Boardware Genius 设置：

```bash
export NANOBOT_OUTLOOK_MCP_ROOT=/srv/BW_Outlook_Mcp
```

因为当前后端会优先寻找：

```text
$NANOBOT_OUTLOOK_MCP_ROOT/.venv/bin/bw-outlook-mcp
```

如果你挂了仓库目录但里面没有 `.venv/bin/bw-outlook-mcp`，那就必须确保 `bw-outlook-mcp` 已经在容器 PATH 里。

### Outlook 的认证和配置

`BW_Outlook_Mcp` 本身支持两套后端：

- `graph`：Microsoft 365 / Exchange Online
- `ews`：本地或回迁后的 Exchange Server

#### Graph 登录

```bash
bw-outlook-mcp auth login-graph \
  --workspace /root/.nanobot/workspace \
  --client-id YOUR_CLIENT_ID \
  --tenant-id YOUR_TENANT_ID
```

#### EWS 配置

```bash
bw-outlook-mcp auth setup-ews \
  --workspace /root/.nanobot/workspace \
  --email you@example.com \
  --username your_username \
  --domain example.com \
  --server mail.example.com
```

如果你已经有固定 EWS URL，也可以改用：

```bash
bw-outlook-mcp auth setup-ews \
  --workspace /root/.nanobot/workspace \
  --email you@example.com \
  --username your_username \
  --service-endpoint https://mail.example.com/EWS/Exchange.asmx
```

#### 查看状态

```bash
bw-outlook-mcp auth status --workspace /root/.nanobot/workspace
```

### Outlook 状态文件会落在哪里

所有 Outlook 相关状态默认都落在 workspace 下：

```text
<workspace>/state/bw_outlook_mcp/
├── config.json
├── secrets.json
├── graph_token_cache.bin
├── delta_store.json
└── idempotency.sqlite3
```

所以 Docker 部署时，不要只挂配置文件；要把整份 `~/.nanobot` 或至少 workspace 做持久化。

### Nanobot 里如何注册 Outlook MCP

如果你通过 Web 接口完成 Outlook 连接，后端会自动把 MCP server 注册到配置里。

手工写配置时，结构类似这样：

```json
{
  "tools": {
    "mcpServers": {
      "outlook": {
        "command": "bw-outlook-mcp",
        "args": ["serve", "--workspace", "/root/.nanobot/workspace"],
        "sensitive": true,
        "toolTimeout": 60
      }
    }
  }
}
```

这里一定要用绝对路径，不要写 `~/.nanobot/workspace`。

### 可选的 Outlook 环境变量

| 变量 | 作用 |
| --- | --- |
| `NANOBOT_OUTLOOK_MCP_ROOT` | 指向外部 `BW_Outlook_Mcp` 仓库目录 |
| `NANOBOT_OUTLOOK_MCP_COMMAND` | 强制指定 `bw-outlook-mcp` 可执行文件 |
| `NANOBOT_OUTLOOK_MCP_EXTRA_ARGS` | 给 `bw-outlook-mcp serve` 追加参数 |
| `NANOBOT_OUTLOOK_DEFAULT_DOMAIN` | Web 连接表单的默认域名 |
| `NANOBOT_OUTLOOK_DEFAULT_EWS_URL` | Web 连接表单默认 EWS 地址 |
| `NANOBOT_OUTLOOK_DEFAULT_EWS_SERVER` | Web 连接表单默认 Exchange 主机 |
| `NANOBOT_OUTLOOK_DEFAULT_TIMEZONE` | Web 连接表单默认时区 |
| `NANOBOT_OUTLOOK_DEFAULT_AUTODISCOVER` | Web 连接表单默认是否启用 autodiscover |

## Docker 部署

### 先说结论

服务器部署时，最重要的是持久化这份目录：

```text
/root/.nanobot
```

因为它里面不只是 `config.json`，还包括：

- workspace
- sessions
- cron 状态
- Web 登录信息
- Outlook 状态与 token 缓存

### 构建镜像

```bash
docker build -t nanobot-backend:latest .
```

### 首次初始化

第一次跑容器时，先执行一次：

```bash
docker run --rm \
  -v /srv/nanobot/data:/root/.nanobot \
  nanobot-backend:latest \
  onboard
```

然后去编辑宿主机上的：

```text
/srv/nanobot/data/config.json
```

或者先进去执行：

```bash
docker run --rm -it \
  -v /srv/nanobot/data:/root/.nanobot \
  nanobot-backend:latest \
  status
```

### 作为 Web 后端启动

如果你是给前端项目配后端，推荐这样跑：

```bash
docker run -d \
  --name nanobot-web \
  -p 18080:18080 \
  -v /srv/nanobot/data:/root/.nanobot \
  -e NANOBOT_OUTLOOK_MCP_ROOT=/opt/BW_Outlook_Mcp \
  -v /srv/BW_Outlook_Mcp:/opt/BW_Outlook_Mcp \
  nanobot-backend:latest \
  web --host 0.0.0.0 --port 18080
```

如果你已经把 `bw-outlook-mcp` 安装进镜像了，就不需要挂 `/srv/BW_Outlook_Mcp`，也不需要 `NANOBOT_OUTLOOK_MCP_ROOT`。

### 作为 Gateway/Worker 启动

如果你要接 Telegram / Slack / Email / cron 之类的常驻能力，再跑 gateway：

```bash
docker run -d \
  --name nanobot-gateway \
  -v /srv/nanobot/data:/root/.nanobot \
  nanobot-backend:latest \
  gateway
```

### 推荐的服务器 compose 片段

仓库自带的 [docker-compose.yml](./docker-compose.yml) 更偏本地 gateway/CLI 示例。  
如果你是部署 Web 后端到服务器，更建议单独写成这样：

```yaml
services:
  nanobot-web:
    image: nanobot-backend:latest
    container_name: nanobot-web
    command: ["web", "--host", "0.0.0.0", "--port", "18080"]
    restart: unless-stopped
    ports:
      - "18080:18080"
    volumes:
      - /srv/nanobot/data:/root/.nanobot
      - /srv/BW_Outlook_Mcp:/opt/BW_Outlook_Mcp
    environment:
      NANOBOT_OUTLOOK_MCP_ROOT: /opt/BW_Outlook_Mcp
```

如果你想把 Outlook 依赖做得更稳，推荐直接把 `BW_Outlook_Mcp` 安装进镜像，而不是运行时挂载仓库。

## 部署给同事时，至少要交代这几件事

1. 这是后端仓库，不带前端静态页面，前端请单独部署
2. Web API 用 `nanobot web` 启动，不是 `gateway`
3. 数据目录必须持久化到 `/root/.nanobot`
4. 如果要 Outlook，必须额外拉取 `BW_Outlook_Mcp`
5. Outlook 有两种接法：装进镜像，或者挂外部仓库并设置 `NANOBOT_OUTLOOK_MCP_ROOT`
6. Outlook 的状态文件也在 workspace 里，删容器不挂卷就会丢

## 常用命令

```bash
nanobot onboard
nanobot status
nanobot agent -m "你好"
nanobot web --host 0.0.0.0 --port 18080
nanobot gateway
nanobot provider login openai-codex
```

## 开发备注

- `workflow.md` 记录了当前代码实际运行链路，和旧版 README 更接近“真实代码”
- `nanobot/web/outlook.py` 是当前 Outlook 集成入口
- `tests/` 里有 Web API、Email、Docker 相关测试
- 如果要上服务器，建议在配置里显式打开 `tools.restrictToWorkspace=true`

## 排错

### Web 启动了，但 Outlook 相关接口报错

优先检查：

- `bw-outlook-mcp` 是否能在当前容器里执行
- `NANOBOT_OUTLOOK_MCP_ROOT` 是否指向正确目录
- 如果走目录挂载模式，目录里是否真的有 `.venv/bin/bw-outlook-mcp`

### MCP 注册了，但工具没有出现

检查：

- `config.json` 里的 `tools.mcpServers`
- `nanobot web` 或 `nanobot agent` 启动时是否用了同一份 `~/.nanobot`
- Outlook MCP 是否能单独执行 `bw-outlook-mcp auth status --workspace ...`

### Docker 里配置改了没生效

优先检查你挂载的是不是整份：

```text
/srv/nanobot/data:/root/.nanobot
```

不是只挂了某一个文件。
