Files
nanoclaw/docs/zh/SPEC.md
2026-05-12 13:14:17 +00:00

30 KiB
Raw Permalink Blame History

NanoClaw 规范

一款个人 Claude 助手,支持多渠道、按会话持久化记忆、定时任务以及容器隔离的 agent智能体执行。


目录

  1. 架构
  2. 架构:渠道系统
  3. 目录结构
  4. 配置
  5. 记忆系统
  6. 会话管理
  7. 消息流转
  8. 命令
  9. 定时任务
  10. MCP 服务器
  11. 部署
  12. 安全考量

架构

┌──────────────────────────────────────────────────────────────────────┐
│                        HOST宿主机macOS / Linux                    │
│                     (主 Node.js 进程)                                │
├──────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  ┌──────────────────┐                  ┌────────────────────┐        │
│  │ Channels         │─────────────────▶│   SQLite 数据库    │        │
│  │ (渠道,启动时    │◀────────────────│   (messages.db)    │        │
│  │   自行注册)      │  存储/发送       └─────────┬──────────┘        │
│  └──────────────────┘                            │                   │
│                                                   │                   │
│         ┌─────────────────────────────────────────┘                   │
│         │                                                             │
│         ▼                                                             │
│  ┌──────────────────┐    ┌──────────────────┐    ┌───────────────┐   │
│  │  Message Loop    │    │  Scheduler Loop  │    │  IPC Watcher  │   │
│  │  (消息轮询循环) │    │  (调度器循环)  │    │ IPC 监听器) │   │
│  └────────┬─────────┘    └────────┬─────────┘    └───────────────┘   │
│           │                       │                                   │
│           └───────────┬───────────┘                                   │
│                       │ 启动容器                                       │
│                       ▼                                               │
├──────────────────────────────────────────────────────────────────────┤
│                     CONTAINER容器Linux VM                         │
├──────────────────────────────────────────────────────────────────────┤
│  ┌──────────────────────────────────────────────────────────────┐    │
│  │                    AGENT RUNNER智能体运行器                 │    │
│  │                                                                │    │
│  │  工作目录: /workspace/group从宿主机挂载                     │    │
│  │  卷挂载:                                                        │    │
│  │    • groups/{name}/ → /workspace/group                         │    │
│  │    • groups/global/ → /workspace/global/(仅非主群组)          │    │
│  │    • data/sessions/{group}/.claude/ → /home/node/.claude/      │    │
│  │    • 额外目录 → /workspace/extra/*                              │    │
│  │                                                                │    │
│  │  工具(所有群组):                                              │    │
│  │    • Bash安全——在容器内沙箱化                             │    │
│  │    • Read, Write, Edit, Glob, Grep文件操作                  │    │
│  │    • WebSearch, WebFetch互联网访问                          │    │
│  │    • agent-browser浏览器自动化                              │    │
│  │    • mcp__nanoclaw__*(通过 IPC 的调度器工具)                  │    │
│  │                                                                │    │
│  └──────────────────────────────────────────────────────────────┘    │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

技术栈

组件 技术 用途
Channel System Channel registry (src/channels/registry.ts) 渠道在启动时自行注册
Message Storage SQLite (better-sqlite3) 存储消息供轮询
Container Runtime ContainersLinux VM 用于 agent 执行的隔离环境
Agent @anthropic-ai/claude-agent-sdk (0.2.29) 带工具和 MCP 服务器的 Claude 运行环境
Browser Automation agent-browser + Chromium Web 交互与截图
Runtime Node.js 20+ 用于路由和调度的宿主机进程

架构:渠道系统

核心不含任何内置渠道——每个渠道WhatsApp、Telegram、Slack、Discord、Gmail作为 Claude Code skill 安装,将渠道代码添加到您的 fork 中。渠道在启动时自行注册;已安装但缺少凭证的渠道会发出 WARN 日志并被跳过。

系统图

graph LR
    subgraph Channels["渠道"]
        WA[WhatsApp]
        TG[Telegram]
        SL[Slack]
        DC[Discord]
        New["其他渠道 (Signal, Gmail...)"]
    end

    subgraph Orchestrator["编排器 — index.ts"]
        ML[Message Loop]
        GQ[Group Queue]
        RT[Router]
        TS[Task Scheduler]
        DB[(SQLite)]
    end

    subgraph Execution["容器执行"]
        CR[Container Runner]
        LC["Linux Container"]
        IPC[IPC Watcher]
    end

    %% Flow
    WA & TG & SL & DC & New -->|onMessage| ML
    ML --> GQ
    GQ -->|并发控制| CR
    CR --> LC
    LC -->|文件系统 IPC| IPC
    IPC -->|任务与消息| RT
    RT -->|Channel.sendMessage| Channels
    TS -->|到期任务| CR

    %% DB Connections
    DB <--> ML
    DB <--> TS

    %% Styling for the dynamic channel
    style New stroke-dasharray: 5 5,stroke-width:2px

渠道注册表

渠道系统建立在 src/channels/registry.ts 中的工厂注册表之上:

export type ChannelFactory = (opts: ChannelOpts) => Channel | null;

const registry = new Map<string, ChannelFactory>();

export function registerChannel(name: string, factory: ChannelFactory): void {
  registry.set(name, factory);
}

export function getChannelFactory(name: string): ChannelFactory | undefined {
  return registry.get(name);
}

export function getRegisteredChannelNames(): string[] {
  return [...registry.keys()];
}

每个工厂接收 ChannelOpts(包含回调 onMessageonChatMetadataregisteredGroups),并返回一个 Channel 实例,如果该渠道的凭证未配置则返回 null

渠道接口

每个渠道实现此接口(定义在 src/types.ts 中):

interface Channel {
  name: string;
  connect(): Promise<void>;
  sendMessage(jid: string, text: string): Promise<void>;
  isConnected(): boolean;
  ownsJid(jid: string): boolean;
  disconnect(): Promise<void>;
  setTyping?(jid: string, isTyping: boolean): Promise<void>;
  syncGroups?(force: boolean): Promise<void>;
}

自行注册模式

渠道使用 barrel 导入模式自行注册:

  1. 每个渠道 skill 向 src/channels/ 添加一个文件(例如 whatsapp.tstelegram.ts),在模块加载时调用 registerChannel()

    // src/channels/whatsapp.ts
    import { registerChannel, ChannelOpts } from './registry.js';
    
    export class WhatsAppChannel implements Channel { /* ... */ }
    
    registerChannel('whatsapp', (opts: ChannelOpts) => {
      // 如果凭证缺失则返回 null
      if (!existsSync(authPath)) return null;
      return new WhatsAppChannel(opts);
    });
    
  2. barrel 文件 src/channels/index.ts 导入所有渠道模块,触发注册:

    import './whatsapp.js';
    import './telegram.js';
    // ... 每个 skill 在此处添加其导入
    
  3. 启动时,编排器(src/index.ts)循环遍历已注册的渠道,连接返回有效实例的渠道:

    for (const name of getRegisteredChannelNames()) {
      const factory = getChannelFactory(name);
      const channel = factory?.(channelOpts);
      if (channel) {
        await channel.connect();
        channels.push(channel);
      }
    }
    

关键文件

文件 用途
src/channels/registry.ts 渠道工厂注册表
src/channels/index.ts 触发渠道自行注册的 barrel 导入
src/types.ts Channel 接口、ChannelOpts、消息类型
src/index.ts 编排器——实例化渠道、运行消息循环
src/router.ts 查找 JID 所属的渠道,格式化消息

添加新渠道

要添加新渠道,请向 .claude/skills/add-<name>/ 贡献一个 skill该 skill 需要:

  1. 添加一个 src/channels/<name>.ts 文件,实现 Channel 接口
  2. 在模块加载时调用 registerChannel(name, factory)
  3. 如果凭证缺失,工厂返回 null
  4. src/channels/index.ts 添加一条导入行

请参考已有的 skills/add-whatsapp/add-telegram/add-slack/add-discord/add-gmail)了解模式。


目录结构

nanoclaw/
├── CLAUDE.md                      # Claude Code 的项目上下文
├── docs/
│   ├── SPEC.md                    # 本规范文档
│   ├── REQUIREMENTS.md            # 架构决策
│   └── SECURITY.md                # 安全模型
├── README.md                      # 用户文档
├── package.json                   # Node.js 依赖
├── tsconfig.json                  # TypeScript 配置
├── .mcp.json                      # MCP 服务器配置(参考)
├── .gitignore
│
├── src/
│   ├── index.ts                   # 编排器状态、消息循环、agent 调用
│   ├── channels/
│   │   ├── registry.ts            # 渠道工厂注册表
│   │   └── index.ts               # 渠道自行注册的 barrel 导入
│   ├── ipc.ts                     # IPC 监听器与任务处理
│   ├── router.ts                  # 消息格式化和出站路由
│   ├── config.ts                  # 配置常量
│   ├── types.ts                   # TypeScript 接口(包含 Channel
│   ├── logger.ts                  # Pino 日志器配置
│   ├── db.ts                      # SQLite 数据库初始化与查询
│   ├── group-queue.ts             # 带全局并发限制的按群组队列
│   ├── mount-security.ts          # 容器挂载白名单验证
│   ├── whatsapp-auth.ts           # 独立的 WhatsApp 认证
│   ├── task-scheduler.ts          # 到期时运行定时任务
│   └── container-runner.ts        # 在容器中启动 agent
│
├── container/
│   ├── Dockerfile                 # 容器镜像(以 'node' 用户运行,包含 Claude Code CLI
│   ├── build.sh                   # 容器镜像的构建脚本
│   ├── agent-runner/              # 在容器内运行的代码
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── src/
│   │       ├── index.ts           # 入口点查询循环、IPC 轮询、会话恢复)
│   │       └── ipc-mcp-stdio.ts   # 基于 stdio 的 MCP 服务器,用于宿主机通信
│   └── skills/
│       └── agent-browser.md       # 浏览器自动化 skill
│
├── dist/                          # 编译后的 JavaScriptgitignored
│
├── .claude/
│   └── skills/
│       ├── setup/SKILL.md              # /setup - 首次安装
│       ├── customize/SKILL.md          # /customize - 添加能力
│       ├── debug/SKILL.md              # /debug - 容器调试
│       ├── add-telegram/SKILL.md       # /add-telegram - Telegram 渠道
│       ├── add-gmail/SKILL.md          # /add-gmail - Gmail 集成
│       ├── add-voice-transcription/    # /add-voice-transcription - Whisper
│       ├── x-integration/SKILL.md      # /x-integration - X/Twitter
│       ├── convert-to-apple-container/  # /convert-to-apple-container - Apple Container 运行时
│       └── add-parallel/SKILL.md       # /add-parallel - 并行 agent
│
├── groups/
│   ├── CLAUDE.md                  # 全局记忆(所有群组都读取此文件)
│   ├── {channel}_main/             # 主控制渠道(例如 whatsapp_main/
│   │   ├── CLAUDE.md              # 主渠道记忆
│   │   └── logs/                  # 任务执行日志
│   └── {channel}_{group-name}/    # 按群组目录(注册时创建)
│       ├── CLAUDE.md              # 群组专属记忆
│       ├── logs/                  # 此群组的任务日志
│       └── *.md                   # agent 创建的文件
│
├── store/                         # 本地数据gitignored
│   ├── auth/                      # WhatsApp 认证状态
│   └── messages.db                # SQLite 数据库messages、chats、scheduled_tasks、task_run_logs、registered_groups、sessions、router_state
│
├── data/                          # 应用状态gitignored
│   ├── sessions/                  # 按群组会话数据(.claude/ 目录,含 JSONL 对话记录)
│   ├── env/env                    # .env 的副本,用于挂载到容器
│   └── ipc/                       # 容器 IPCmessages/、tasks/
│
├── logs/                          # 运行时日志gitignored
│   ├── nanoclaw.log               # 宿主机 stdout
│   └── nanoclaw.error.log         # 宿主机 stderr
│   # 注意:每个容器的日志在 groups/{folder}/logs/container-*.log
│
└── launchd/
    └── com.nanoclaw.plist         # macOS 服务配置

配置

配置常量在 src/config.ts 中定义:

import path from 'path';

export const ASSISTANT_NAME = process.env.ASSISTANT_NAME || 'Andy';

// 路径必须是绝对路径(容器挂载需要)
const PROJECT_ROOT = process.cwd();
export const STORE_DIR = path.resolve(PROJECT_ROOT, 'store');
export const GROUPS_DIR = path.resolve(PROJECT_ROOT, 'groups');
export const DATA_DIR = path.resolve(PROJECT_ROOT, 'data');

// 容器配置
export const CONTAINER_IMAGE = process.env.CONTAINER_IMAGE || 'nanoclaw-agent:latest';
export const CONTAINER_TIMEOUT = parseInt(process.env.CONTAINER_TIMEOUT || '1800000', 10); // 默认30分钟
export const IDLE_TIMEOUT = parseInt(process.env.IDLE_TIMEOUT || '1800000', 10); // 30分钟——最后一次结果后保持容器存活
export const MAX_CONCURRENT_CONTAINERS = Math.max(1, parseInt(process.env.MAX_CONCURRENT_CONTAINERS || '5', 10) || 5);

export const TRIGGER_PATTERN = new RegExp(`^@${ASSISTANT_NAME}\\b`, 'i');

注意: 路径必须是绝对路径,容器卷挂载才能正常工作。

容器配置

群组可以通过 SQLite registered_groups 表中的 containerConfig(以 JSON 形式存储在 container_config 列中)挂载额外目录。注册示例:

setRegisteredGroup("1234567890@g.us", {
  name: "Dev Team",
  folder: "whatsapp_dev-team",
  trigger: "@Andy",
  added_at: new Date().toISOString(),
  containerConfig: {
    additionalMounts: [
      {
        hostPath: "~/projects/webapp",
        containerPath: "webapp",
        readonly: false,
      },
    ],
    timeout: 600000,
  },
});

目录命名遵循 {channel}_{group-name} 约定(例如 whatsapp_family-chattelegram_dev-team)。主群组在注册时会设置 isMain: true

额外挂载在容器内显示为 /workspace/extra/{containerPath}

挂载语法说明: 读写挂载使用 -v host:container,但只读挂载需要使用 --mount "type=bind,source=...,target=...,readonly":ro 后缀可能不是所有运行时都支持)。

Claude 认证

在项目根目录的 .env 文件中配置认证。有两种选择:

选项1Claude 订阅OAuth token

CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...

如果您已登录 Claude Code可以从 ~/.claude/.credentials.json 中提取 token。

选项2按用量付费的 API Key

ANTHROPIC_API_KEY=sk-ant-api03-...

只有认证变量(CLAUDE_CODE_OAUTH_TOKENANTHROPIC_API_KEY)从 .env 中提取并写入 data/env/env,然后挂载到容器中的 /workspace/env-dir/env,由入口点脚本加载。这确保 .env 中的其他环境变量不会暴露给 agent。此变通方案是必要的因为某些容器运行时在使用 -i(带管道 stdin 的交互模式)时会丢失 -e 环境变量。

更改助手名称

设置 ASSISTANT_NAME 环境变量:

ASSISTANT_NAME=Bot pnpm start

或编辑 src/config.ts 中的默认值。这会更改:

  • 触发模式(消息必须以 @YourName 开头)
  • 响应前缀(自动添加 YourName:

launchd 中的占位符值

包含 {{PLACEHOLDER}} 值的文件需要进行配置:

  • {{PROJECT_ROOT}} - nanoclaw 安装的绝对路径
  • {{NODE_PATH}} - node 二进制文件的路径(通过 which node 检测)
  • {{HOME}} - 用户的主目录

记忆系统

NanoClaw 使用基于 CLAUDE.md 文件的层级记忆系统。

记忆层级

层级 位置 读取者 写入者 用途
全局 groups/CLAUDE.md 所有群组 仅主群组 在所有对话之间共享的偏好、事实、上下文
群组 groups/{name}/CLAUDE.md 该群组 该群组 群组专属上下文、对话记忆
文件 groups/{name}/*.md 该群组 该群组 对话过程中创建的笔记、研究、文档

记忆如何运作

  1. Agent 上下文加载

    • Agent 运行在 groups/{group-name}/ 作为 cwd
    • Claude Agent SDK 使用 settingSources: ['project'] 自动加载:
      • ../CLAUDE.md(上级目录 = 全局记忆)
      • ./CLAUDE.md(当前目录 = 群组记忆)
  2. 写入记忆

    • 当用户说"记住这个"agent 写入 ./CLAUDE.md
    • 当用户说"全局记住这个"仅主渠道agent 写入 ../CLAUDE.md
    • Agent 可以在群组目录中创建 notes.mdresearch.md 等文件
  3. 主渠道权限

    • 只有"主"群组(自我聊天)可以向全局记忆写入
    • 主群组可以管理已注册的群组并为任何群组安排定时任务
    • 主群组可以为任何群组配置额外的目录挂载
    • 所有群组都有 Bash 访问权限(安全,因为在容器内运行)

Session 管理

Session 实现了对话连续性——Claude 会记住你们之前谈过的内容。

Session 如何运作

  1. 每个群组在 SQLite 中有一个 session IDsessions 表,按 group_folder 索引)
  2. Session ID 传递给 Claude Agent SDK 的 resume 选项
  3. Claude 以完整上下文继续对话
  4. Session 对话记录以 JSONL 文件形式存储在 data/sessions/{group}/.claude/

消息流转

入站消息流程

1. 用户通过任何已连接的渠道发送消息
   │
   ▼
2. 渠道接收消息(例如 WhatsApp 使用 BaileysTelegram 使用 Bot API
   │
   ▼
3. 消息存入 SQLitestore/messages.db
   │
   ▼
4. 消息循环轮询 SQLite每2秒
   │
   ▼
5. 路由检查:
   ├── chat_jid 是否在已注册群组中SQLite→ 否:忽略
   └── 消息是否匹配触发模式?→ 否:存储但不处理
   │
   ▼
6. 路由追上对话:
   ├── 获取自上次 agent 交互以来的所有消息
   ├── 使用时间戳和发送者名称格式化
   └── 构建包含完整对话上下文的 prompt
   │
   ▼
7. 路由调用 Claude Agent SDK
   ├── cwd: groups/{group-name}/
   ├── prompt: 对话历史 + 当前消息
   ├── resume: session_id用于连续性
   └── mcpServers: nanoclaw调度器
   │
   ▼
8. Claude 处理消息:
   ├── 读取 CLAUDE.md 文件获取上下文
   └── 按需使用工具(搜索、邮件等)
   │
   ▼
9. 路由在响应前添加助手名称前缀,并通过所属渠道发送
   │
   ▼
10. 路由更新最后 agent 时间戳并保存 session ID

触发词匹配

消息必须以触发模式开头(默认:@Andy

  • @Andy what's the weather? 触发 Claude
  • @andy help me 触发(不区分大小写)
  • Hey @Andy 忽略(触发词不在开头)
  • What's up? 忽略(无触发词)

对话追上

当触发消息到达时agent 会收到自上次在该聊天中交互以来的所有消息。每条消息都带有时间戳和发送者名称:

[Jan 31 2:32 PM] John: hey everyone, should we do pizza tonight?
[Jan 31 2:33 PM] Sarah: sounds good to me
[Jan 31 2:35 PM] John: @Andy what toppings do you recommend?

这使得 agent 能够理解对话上下文,即使它没有在每条消息中被提及。


命令

任何群组中可用的命令

命令 示例 效果
@Assistant [message] @Andy what's the weather? 与 Claude 对话

仅主渠道可用的命令

命令 示例 效果
@Assistant add group "Name" @Andy add group "Family Chat" 注册新群组
@Assistant remove group "Name" @Andy remove group "Work Team" 取消注册群组
@Assistant list groups @Andy list groups 显示已注册群组
@Assistant remember [fact] @Andy remember I prefer dark mode 添加到全局记忆

定时任务

NanoClaw 内置调度器,将任务作为完整 agent 在其群组上下文中运行。

调度如何运作

  1. 群组上下文:在群组中创建的任务使用该群组的工作目录和记忆运行
  2. 完整的 Agent 能力定时任务可以访问所有工具WebSearch、文件操作等
  3. 可选的消息发送:任务可以使用 send_message 工具向其群组发送消息,也可以静默完成
  4. 主渠道权限:主渠道可以为任何群组安排任务并查看所有任务

调度类型

类型 值格式 示例
cron Cron 表达式 0 9 * * 1每周一上午9点
interval 毫秒 3600000(每小时)
once ISO 时间戳 2024-12-25T09:00:00Z

创建任务

User: @Andy remind me every Monday at 9am to review the weekly metrics

Claude: [调用 mcp__nanoclaw__schedule_task]
        {
          "prompt": "Send a reminder to review weekly metrics. Be encouraging!",
          "schedule_type": "cron",
          "schedule_value": "0 9 * * 1"
        }

Claude: Done! I'll remind you every Monday at 9am.

一次性任务

User: @Andy at 5pm today, send me a summary of today's emails

Claude: [调用 mcp__nanoclaw__schedule_task]
        {
          "prompt": "Search for today's emails, summarize the important ones, and send the summary to the group.",
          "schedule_type": "once",
          "schedule_value": "2024-01-31T17:00:00Z"
        }

管理任务

在任何群组中:

  • @Andy list my scheduled tasks - 查看此群组的任务
  • @Andy pause task [id] - 暂停任务
  • @Andy resume task [id] - 恢复暂停的任务
  • @Andy cancel task [id] - 删除任务

在主渠道中:

  • @Andy list all tasks - 查看所有群组的任务
  • @Andy schedule task for "Family Chat": [prompt] - 为其他群组安排任务

MCP 服务器

NanoClaw MCP内置

nanoclaw MCP 服务器在每次 agent 调用时动态创建,带有当前群组的上下文。

可用工具:

工具 用途
schedule_task 安排定期或一次性任务
list_tasks 显示任务(本群组的任务,主群组则显示全部)
get_task 获取任务详情和运行历史
update_task 修改任务的 prompt 或调度
pause_task 暂停任务
resume_task 恢复暂停的任务
cancel_task 删除任务
send_message 通过群组的渠道发送消息

部署

NanoClaw 作为单个 macOS launchd 服务运行。

启动序列

NanoClaw 启动时会:

  1. 确保容器运行时正在运行——如需要自动启动;终止前次运行遗留的 NanoClaw 孤儿容器
  2. 初始化 SQLite 数据库(如果存在 JSON 文件则从中迁移)
  3. 从 SQLite 加载状态已注册群组、sessions、路由状态
  4. 连接渠道——遍历已注册渠道,实例化有凭证的渠道,对每个调用 connect()
  5. 一旦至少有一个渠道连接:
    • 启动调度器循环
    • 启动用于容器消息的 IPC 监听器
    • 设置按群组队列及 processGroupMessages
    • 恢复关闭前未处理的消息
    • 启动消息轮询循环

服务com.nanoclaw

launchd/com.nanoclaw.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.nanoclaw</string>
    <key>ProgramArguments</key>
    <array>
        <string>{{NODE_PATH}}</string>
        <string>{{PROJECT_ROOT}}/dist/index.js</string>
    </array>
    <key>WorkingDirectory</key>
    <string>{{PROJECT_ROOT}}</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>{{HOME}}/.local/bin:/usr/local/bin:/usr/bin:/bin</string>
        <key>HOME</key>
        <string>{{HOME}}</string>
        <key>ASSISTANT_NAME</key>
        <string>Andy</string>
    </dict>
    <key>StandardOutPath</key>
    <string>{{PROJECT_ROOT}}/logs/nanoclaw.log</string>
    <key>StandardErrorPath</key>
    <string>{{PROJECT_ROOT}}/logs/nanoclaw.error.log</string>
</dict>
</plist>

管理服务

# 安装服务
cp launchd/com.nanoclaw.plist ~/Library/LaunchAgents/

# 启动服务
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist

# 停止服务
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist

# 检查状态
launchctl list | grep nanoclaw

# 查看日志
tail -f logs/nanoclaw.log

安全考量

容器隔离

所有 agent 在容器(轻量级 Linux VM内运行提供

  • 文件系统隔离Agent 只能访问已挂载的目录
  • 安全的 Bash 访问:命令在容器内运行,而不是在您的 Mac 上
  • 网络隔离:可按容器配置(如需要)
  • 进程隔离:容器进程无法影响宿主机
  • 非 root 用户:容器以非特权 node 用户uid 1000运行

Prompt 注入风险

WhatsApp 消息可能包含试图操纵 Claude 行为的恶意指令。

缓解措施:

  • 容器隔离限制爆炸半径
  • 仅处理已注册的群组
  • 需要触发词(减少误处理)
  • Agent 只能访问其群组挂载的目录
  • 主群组可以按群组配置额外目录
  • Claude 内置的安全训练

建议:

  • 仅注册受信任的群组
  • 仔细审查额外的目录挂载
  • 定期审查定时任务
  • 监控日志中的异常活动

凭证存储

凭证 存储位置 说明
Claude CLI Auth data/sessions/{group}/.claude/ 按群组隔离,挂载到 /home/node/.claude/
WhatsApp Session store/auth/ 自动创建持续约20天

文件权限

groups/ 目录包含个人记忆,应加以保护:

chmod 700 groups/

故障排除

常见问题

问题 原因 解决方案
消息无响应 服务未运行 检查 `launchctl list
"Claude Code process exited with code 1" 容器运行时启动失败 检查日志NanoClaw 会自动启动容器运行时,但可能失败
"Claude Code process exited with code 1" Session 挂载路径错误 确保挂载到 /home/node/.claude/ 而非 /root/.claude/
Session 无法继续 Session ID 未保存 检查 SQLitesqlite3 store/messages.db "SELECT * FROM sessions"
Session 无法继续 挂载路径不匹配 容器用户是 nodeHOME=/home/nodesessions 必须位于 /home/node/.claude/
"QR code expired" WhatsApp session 过期 删除 store/auth/ 并重启
"No groups registered" 尚未添加群组 在主渠道中使用 @Andy add group "Name"

日志位置

  • logs/nanoclaw.log - stdout
  • logs/nanoclaw.error.log - stderr

调试模式

手动运行以获取详细输出:

pnpm run dev
# 或
node dist/index.js