



























一个轻量级的个人 Claude AI 助手框架
✅ 小到可以理解 - 单进程、少量源文件、无微服务
✅ 通过隔离实现安全 - Agent 在 Linux 容器中运行,文件系统隔离
✅ 为个人用户定制 - 通过 Claude Code 技能(Skills)按需扩展功能
✅ AI 原生设计 - 无需安装向导,用自然语言配置和调试
GitHub地址: https://github.com/qwibitai/nanoclaw
nanoclaw/
├── 📄 CLAUDE.md # Claude Code 项目上下文
├── 📄 package.json # 依赖管理
├── 📄 tsconfig.json # TypeScript 配置
│
├── 📂 src/ # 核心源码
│ ├── 📄 index.ts # ⭐ 主 orchestrator:消息循环、Agent 调度
│ ├── 📂 channels/
│ │ ├── 📄 registry.ts # ⭐ Channel 工厂注册中心
│ │ └── 📄 index.ts # 渠道模块自动注册入口
│ ├── 📄 container-runner.ts # ⭐ 容器启动与管理
│ ├── 📄 group-queue.ts # ⭐ 分组消息队列(并发控制)
│ ├── 📄 router.ts # 消息格式化与路由
│ ├── 📄 ipc.ts # 文件系统 IPC 通信
│ ├── 📄 task-scheduler.ts # 定时任务调度器
│ ├── 📄 db.ts # SQLite 数据库操作
│ ├── 📄 mount-security.ts # 挂载安全校验
│ ├── 📄 config.ts # 配置常量
│ └── 📄 types.ts # TypeScript 接口定义
│
├── 📂 container/ # 容器构建与运行时代码
│ ├── 📄 Dockerfile # 容器镜像定义
│ ├── 📂 agent-runner/ # 容器内 Agent 执行逻辑
│ │ ├── 📄 index.ts # 容器入口:查询循环、IPC 轮询
│ │ └── 📄 ipc-mcp-stdio.ts # MCP 服务器(stdio 通信)
│ └── 📂 skills/ # 容器内可用技能
│
├── 📂 .claude/skills/ # Claude Code 技能包(插件系统)
│ ├── setup/SKILL.md # /setup - 初始化安装
│ ├── add-whatsapp/SKILL.md # /add-whatsapp - WhatsApp 渠道
│ ├── add-telegram/SKILL.md # /add-telegram - Telegram 渠道
│ ├── customize/SKILL.md # /customize - 自定义配置
│ └── ... # 其他扩展技能
│
├── 📂 groups/ # 分组记忆存储(核心数据)
│ ├── CLAUDE.md # 全局记忆(所有组可读)
│ ├── {channel}main/ # 主控制通道
│ │ ├── CLAUDE.md # 主通道专属记忆
│ │ └── logs/ # 任务执行日志
│ └── {channel}/ # 各分组独立空间
│ ├── CLAUDE.md # 分组专属记忆
│ ├── logs/ # 分组任务日志
│ └── *.md # Agent 创建的文档
│
├── 📂 store/ # 持久化数据(.gitignore)
│ ├── auth/ # WhatsApp 认证状态
│ └── messages.db # SQLite 数据库
│
└── 📂 data/ # 运行时状态(.gitignore)
├── sessions/ # 会话数据(.claude/JSONL)
├── env/env # 环境变量副本(容器挂载)
└── ipc/ # 容器间通信目录
核心文件的函数解析
(1)loadState,用于加载应用程序的状态,加载数据库的变量到全局变量中 lastTimestamp,lastAgentTimestamp,sessions,registeredGroups
(2)saveState,保存当前状态,主要存储当前全局变量到数据库中 lastTimestamp, lastAgentTimestamp
(3)chats表的作用,追踪每个聊天会话的存在。 三大核心作用:群组发现和路由决策;活动排序和最近会话展示;多渠道支持和基础设施。
┌─────────────────────────────────────────┐
│ chats 表 = 轻量级"会话地址簿" │
├─────────────────────────────────────────┤
│ • 记录系统"见过"的所有对话(非仅注册群组)│
│ • 仅存储元数据,不存消息内容 │
│ • 支撑群组发现、路由决策、活动排序 │
│ • 与 messages 表形成"元数据/内容"分离 │
└─────────────────────────────────────────┘
main函数的核心流程
(1)ensureContainerSystemRunning 确保本地有docker容器正在运行,清理孤立的容器,镜像或其他容器系统资源
(2)initDatabase 初始化数据库,建表建索引
(3)loadState 加载数据库的状态信息到全局变量中
(4)restoreRemoteControl 用于从文件系统中恢复之前保存的远程控制会话,从本地的remote-control.json来加载数据到全局变量 RemoteControlSession 中。
(5)startCredentialProxy 实现了一个凭据代理服务器(Credential Proxy),主要用于处理与 Anthropic API 的认证请求转发。
(5.1) readEnvFile,从.env文件中读取相关LLM的参数
(5.2) createServer 启动凭据代理(容器通过此路由API调用)
(6)定义一个shutdown函数变量,创建一个异步函数,在接收到关闭信号的时候,关闭proxyServer和群组queue,最后process.exit(0)退出
(7)创建一个异步函数 handleRemoteControl, 用于处理远程控制命令. 可传入的参数为命令-command,会话ID-chatJid和消息-NewMessage.先确认当前会话是在主群组中,然后在channels数组中进行遍历,查找chatJid对应的channel. 若命令是 /remote-control, 启动远程控制,并发送相关命令;否则是关闭远程控制。
(8)创建一个channelOpts变量,用来作为channel的callback。
(9)接下来进入正式环节,逐个连接所有已经注册的渠道
(10)进入任务调度的循环,调用startSchedulerLoop函数
(11)开始监测IPC工作,startIpcWatcher
(12)进入消息循环处理,调用startMessageLoop函数
代码是在/src/env.ts, 根据传入的参数为key,来找.env下所对应的参数设置
处理组文件夹的验证和路径解析,代码是在 src/group-folder.ts 中。
resolveGroupFolderPath函数,将字符串的形式的相对路径转为完整的绝对路径。
采用了nodejs的better-sqlite3来实现数据持久化,代码在db.ts中
提供了以下几个接口:
initDatabase,初始化数据库的主函数,包括读写messages.db文件(采用异步读写),初始化库表,
createSchema,初始化数据库连接,建表,建索引。
代码是在 /src/remote-control.ts 文件中。
restoreRemoteControl函数的是: 管理和保存远程控制的信息(pid,url,startedBy,startedInChat,startedAt)
startRemoteControl函数是:
函数的关键语句是:根据本地的保存的远程控制信息来启动远程控制。
proc = spawn('claude', ['remote-control', '--name', 'NanoClaw Remote'], {cwd, stdio: ['ignore', stdoutFd, stderrFd], detached: true,});
stopRemoteControl 函数则是:停止远程控制,关键语句是 process.kill(pid, 'SIGTERM');
代码是在 src/group-queue.ts 中, 该文件只有一个类GroupQueue类.
用于管理多个群组的消息和任务队列,控制并发容器数量,并提供重试机制。 它负责启动、监控和关闭容器,确保消息和任务按顺序处理。
该类的属性
(1)groups,组的字典,根据
(2)activeCount,活跃个数
(3)waitingGroups,等待的groups组
(4)processMessagesFn信息处理函数,传入groupId,得到一个异步结果。
(5)shuttingDown 标记量
代码是在 /src/container-runner.ts 中,容器运行器的实现,主要用于在容器中执行代理程序并处理进程间通信(ICP)。
该文件对外暴露三个函数
(1)runContainerAgent 创建和管理容器,实现容器的启动,监控和清理机制。 启动容器创建,并执行容器内部执行指令,然后等待执行结果,同时还有超时机制,超过一定时间会直接杀掉容器。得到结果后,就close掉容器。
(2)writeTasksSnapshot 代码只是简单地把当前的tasks,按照groupfolder过滤之后,保存在current_tasks.json文件中
(3)writeGroupsSnapshot 代码只是简单地把可用的group进行本地保存在文件 available_groups.json 文件中。
还有内部函数
(1)buildVolumeMounts 根据组的信息来加载卷挂载
(2)buildContainerArgs 根据卷挂载信息来初始化命令的参数
代码是在 /src/container-runtime.ts 中,简单封装对docker容器的操作的一些方法。
hostGatewayArgs 函数是: 容器解析主机网关所需的CLI参数
readonlyMountArgs 函数是: 返回只读挂载的CLI参数
stopContainer 返回根据name来停止容器的命令
ensureContainerRuntimeRunning 确保容器可以运行。
cleanupOrphans 函数是:从之前的运行的容器中将孤立的nanoclaw容器杀死
代码是在 src/ipc.ts 文件中,主要实现一个进程间通信的监视器,用于处理不同群组之间的消息和任务调度。
主要函数有两个
startIpcWatcher 函数,传入IpcDeps接口结构,轮询processIpcFiles函数。 该函数围绕 IpcDeps 进行执行。
processTaskIpc 函数,根据传入的data来执行IPC任务,核心工作函数。
代码是在 src/logger.ts 文件中
简单的基于Pino日志库来实现一个日志记录器,日志级别(level)设置为环境变量 LOG_LEVEL 的值,如果未设置则默认为 'info'
启用了 pino-pretty 传输方式,用于美化输出日志格式,并启用了颜色显示
主要有两个函数:
uncaughtException 用于处理未捕获异常
unhandledRejection 用来处理未处理的 Promise 拒绝的错误处理机制
tips:Pino 是一个高性能的 Node.js 日志记录库,以其极低的开销而闻名。
代码是在 src/mount-security.ts文件夹中,主要是验证和管理容器中的额外挂载mounts。
loadMountAllowlist函数是: 从配置文件中加载mount允许的挂载数据
validateMount函数是: 将挂载数据进行验证是否合法。
validateAdditionalMounts函数的是: 将mounts进行合法检验后提取得到结果
generateAllowlistTemplate函数:获取一个合法的mounts的模板
escapeXml(s: string): string 函数是:对字符串进行 XML 转义处理。实现原理:使用正则表达式将特殊字符(&, <, >, ")替换为对应的 XML 实体。用途:防止 XML 注入攻击,确保生成的 XML 格式正确
formatMessages 函数的作用是: 将消息数组格式化为 XML 字符串。实现原理: 使用 map 遍历消息数组,每条消息转换为 XML 格式
stripInternalTags 函数的作用是: 移除文本中的 internal 标签及其内容
routeOutbound 函数的作用是:将消息路由到正确的频道。
代码在 /src/task-scheduler.ts 文件中。 代码实现了一个任务调度器,用于管理和执行定时任务。
围绕核心接口 SchedulerDependencies ,
核心函数有:
runTask函数是:记录该任务的状态,执行任务的内容,调用 runContainerAgent
startSchedulerLoop函数的是:开始执行任务调度。间隔地从DB中获取需要执行的任务,拿到task中进行执行。
resetSchedulerLoopForTests函数:将 schedulerRunning 变量置为False。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。