置顶说明
本项目的基础架构思路学习和参考了开源项目 HKUDS/nanobot。
SolonClaw不是对 nanobot 的直接移植,而是基于Solon + Solon AI + 文件工作区 + 多渠道适配的本地化实现。理解项目时,请以当前仓库代码与测试为准。
SolonClaw 是一个基于 Solon 3.9.5 构建的轻量级 Agent 服务。它把模型调用、会话历史、子任务编排、工作区工具、定时任务、调试页和钉钉渠道统一到同一套运行时中。
适合用来做这些事情:
- 🤖 构建一个可持续运行的个人/团队 AI 助手
- 💬 同时接本地 Debug Web 与钉钉机器人
- 🧠 让 Agent 基于工作区文件获得记忆、身份和行为约束
- 🛠️ 让 Agent 通过工具读写工作区、通过 CLI 技能执行命令、管理任务
- 🧩 把复杂问题拆成多个子任务并回流父会话
- ⏰ 创建持久化定时任务,让 Agent 定期执行工作
-
🚀 统一运行时 所有消息都会先进入
AgentRuntimeService,统一完成去重、会话落盘、调度、模型执行与渠道回发。 -
🔀 会话级并发 并发控制按
sessionKey生效,而不是全局串行。当前默认单会话最大并发数为4。 -
🧵 子任务编排 Agent 可以通过
spawn_task派生独立子任务;子任务完成后会回流父会话,并支持按batchKey聚合状态。 -
🔔 主动通知 Agent 在一次运行中可以主动向当前外部会话发送通知,而不必等最终回复。
-
🗂️ 工作区驱动提示词
AGENTS.md / SOUL.md / IDENTITY.md / USER.md / TOOLS.md / HEARTBEAT.md / MEMORY.md / memory/YYYY-MM-DD.md会自动参与系统提示词拼装。 -
🧰 内置工具与技能 支持文件读写、片段编辑、任务查询、定时任务管理,并可从
workspace/skills挂载 CLI 技能池@skills。 -
🧪 本地调试友好 自带 Debug Web 页面,可直接查看 run 状态、流式事件、子任务列表与聚合摘要。
-
📁 文件持久化 会话、运行、去重标记、路由状态和任务定义都可以直接在工作区中看到。
Inbound Message
-> ChannelAdapter / Debug Web / System Job
-> AgentRuntimeService
-> RuntimeStoreService (dedup + conversation events + run events + reply target)
-> ConversationScheduler (per sessionKey concurrency)
-> SolonAiConversationAgent
-> ChatModel
-> Workspace Tools
-> Runtime Tools
-> Job Tools
-> CLI Skills (@skills)
-> OutboundEnvelope
-> ChannelRegistry
-> DingTalk / Debug Web
核心模块:
-
agent/runtime统一运行时、调度器、心跳、子任务与通知能力。 -
agent/store统一文件落盘与历史重建。 -
agent/workspace工作区路径边界、模板初始化、提示词拼装。 -
agent/tool工作区工具、运行时工具、定时任务工具。 -
agent/job持久化定时任务与恢复机制。 -
channel/dingtalk钉钉 Stream 入站与机器人 OpenAPI 出站。 -
webDebug Web 页面与调试 API。
默认工作区根目录为 ./workspace。
运行后常见文件结构如下:
workspace/
AGENTS.md
SOUL.md
IDENTITY.md
USER.md
TOOLS.md
HEARTBEAT.md
MEMORY.md
memory/
skills/
jobs.json
runtime/
runs/
conversations/
dedup/
meta/
media/
其中:
-
workspace/runtime/runs保存 run 明细与 run 事件。 -
workspace/runtime/conversations保存会话事件和会话元数据。 -
workspace/runtime/meta保存最近一次外部回复路由等状态。 -
workspace/jobs.json保存定时任务定义。
本地调试页默认可用,访问根路径即可进入:
GET /POST /api/debug/chatGET /api/debug/runs/{runId}GET /api/debug/runs/{runId}/eventsGET /api/debug/runs/{runId}/children
特性:
- 与钉钉共用同一个运行时
debug-web会话与外部渠道隔离- 可查看流式事件、最终回复、子任务和聚合摘要
当前钉钉接入方式:
- 入站:
DingTalkStreamTopics.BOT_MESSAGE_TOPIC - 出站:机器人 OpenAPI
- 群聊:
orgGroupSend - 私聊:
batchSendOTO - 输出格式:markdown 文本
当前行为边界:
- 群聊与私聊会使用不同
sessionKey - 回复目标完全依赖
ReplyTarget - 附件暂时只做文本化降级
- 白名单为空时默认允许;一旦配置白名单,则只允许命中项通过
当前 Agent 可以使用的核心工具包括:
read_filewrite_fileedit_filenotify_userspawn_tasklist_child_runsget_run_statusget_child_summarylist_jobsget_jobadd_jobremove_jobstart_jobstop_job
能力特点:
- 文件读写受工作区边界保护
- 命令执行走 CLI
TerminalSkill的bash能力 TerminalSkill默认启用沙盒模式,可通过solonclaw.agent.tools.sandboxMode控制- 定时任务会绑定最近一次外部会话路由
- 心跳检查会读取
HEARTBEAT.md并触发静默内部运行
sandboxMode 规则:
true:CLI 的bash/ls/read/grep/glob等能力只允许工作区相对路径、~/和@skills逻辑路径true:禁止绝对路径,禁止通过../等方式越出工作区true:@skills逻辑路径可读、可执行,但仍是只读挂载池false:放开绝对路径访问,CLI 能力进入更开放模式
- JDK
8 - Maven
3.9+ - 推荐本地安装并启动 Ollama
开发环境可直接使用 src/main/resources/app-dev.yml 中的 Ollama 示例配置。
生产或本地自定义配置建议参考:
可在项目根目录创建 config.yml,注入你的模型与钉钉配置。
mvn -q -DskipTests compile
mvn -q test说明:
ChatModelConfigTest在本地 Ollama 不可达时会自动跳过真实调用测试。
java -jar target/solonclaw.jar或开发模式:
java -jar target/solonclaw.jar --env=dev默认端口:
12345
启动后可打开:
如果你希望 README 里直接给出“先设置变量,再启动”的现成命令,可以直接使用下面这些示例。
PowerShell:
$env:APP_JAR="target/solonclaw.jar"
$env:APP_ENV="dev"
$env:APP_PORT="12345"
$env:APP_WORKSPACE="./workspace"
$env:APP_XMS="256m"
$env:APP_XMX="512m"
java `
"-Xms$env:APP_XMS" `
"-Xmx$env:APP_XMX" `
"-Dserver.port=$env:APP_PORT" `
"-Dsolonclaw.workspace=$env:APP_WORKSPACE" `
-jar $env:APP_JAR `
--env=$env:APP_ENVBash:
export APP_JAR="target/solonclaw.jar"
export APP_ENV="dev"
export APP_PORT="12345"
export APP_WORKSPACE="./workspace"
export JAVA_OPTS="-Xms256m -Xmx512m"
java ${JAVA_OPTS} \
-Dserver.port="${APP_PORT}" \
-Dsolonclaw.workspace="${APP_WORKSPACE}" \
-jar "${APP_JAR}" \
--env="${APP_ENV}"生产环境示例:
export APP_JAR="target/solonclaw.jar"
export APP_ENV="prod"
export APP_PORT="12345"
export APP_WORKSPACE="./workspace"
export JAVA_OPTS="-Xms512m -Xmx1024m"
java ${JAVA_OPTS} \
-Dserver.port="${APP_PORT}" \
-Dsolonclaw.workspace="${APP_WORKSPACE}" \
-jar "${APP_JAR}" \
--env="${APP_ENV}"主配置文件:
src/main/resources/app.yml
当前关键项:
solonclaw.workspace=./workspacesolonclaw.agent.scheduler.maxConcurrentPerConversation=4solonclaw.agent.scheduler.ackWhenBusy=falsesolonclaw.agent.tools.sandboxMode=truesolonclaw.agent.heartbeat.enabled=truesolonclaw.agent.heartbeat.intervalSeconds=1800solonclaw.channels.dingtalk.*
注意:
- 仓库内不提交生产密钥
prod环境默认追加加载根目录./config.yml
仓库现在已经提供:
docker build -t solonclaw:latest .建议在项目根目录准备:
config.ymlworkspace/
其中:
config.yml用来放生产环境密钥、模型配置、钉钉配置workspace/用来持久化运行时数据、记忆文件、技能和任务定义
可先参考:
docker run -d \
--name solonclaw \
-p 12345:12345 \
-e JAVA_OPTS="-Xms256m -Xmx512m" \
-e APP_ARGS="--env=prod" \
-v "$(pwd)/workspace:/app/workspace" \
-v "$(pwd)/config.yml:/app/config.yml:ro" \
solonclaw:latestWindows PowerShell:
docker run -d `
--name solonclaw `
-p 12345:12345 `
-e JAVA_OPTS="-Xms256m -Xmx512m" `
-e APP_ARGS="--env=prod" `
-v "${PWD}/workspace:/app/workspace" `
-v "${PWD}/config.yml:/app/config.yml:ro" `
solonclaw:latest说明:
- 容器工作目录固定为
/app APP_ARGS="--env=prod"会启用app.yml中的prod段,并加载/app/config.ymlworkspace目录挂载后,运行数据不会随容器删除而丢失
docker compose up -d --build停止:
docker compose down查看日志:
docker compose logs -f solonclaw当前 docker-compose.yml 默认会:
- 暴露端口
12345 - 挂载
./workspace到/app/workspace - 挂载
./config.yml到/app/config.yml - 以
--env=prod启动应用
如果你需要自定义 JVM 参数或启动参数,可以直接修改 docker-compose.yml 里的环境变量:
JAVA_OPTSAPP_ARGS
例如:
environment:
JAVA_OPTS: "-Xms512m -Xmx1024m"
APP_ARGS: "--env=prod"- 生产环境务必挂载独立的
workspace目录 - 生产环境不要把真实密钥写进镜像
- 如果使用本地 Ollama,请确保容器能访问你的模型服务地址
- 如果要接钉钉,请在
config.yml中补齐clientId、clientSecret、robotCode
当前测试已覆盖这些方向:
- Solon 启动与 ChatModel 装配
- 工作区模板初始化与提示词拼装
- 工作区工具路径边界
- 运行时文件落盘
- 会话并发与忙时回执
- 子任务派生、回流、聚合与按批次查询
- 主动通知
- 心跳静默执行
- 钉钉入站转换与 markdown 发送参数
- 定时任务持久化
- 新增渠道先抽象成
ChannelAdapter - 回复必须来自
ReplyTarget - 会话历史只能通过
RuntimeStoreService维护 - 长时资源优先接入 Solon 生命周期
- 新增配置优先并入
SolonClawProperties - 调试能力优先复用现有 Debug Web
- 不要把系统退回成全局串行队列
- 实体类、DTO、事件载荷、结果对象、配置承载对象优先使用 Lombok 管理字段访问器;明确适合的类优先使用
@Data - 无参构造优先交给 Lombok 管理,这类数据类默认优先使用
@NoArgsConstructor - 需要持久化、序列化传输、缓存或作为稳定数据载体的类,应按需实现
Serializable - 尽量避免新增内部类;配置承载对象优先拆成独立类维护
建议所有 Pull Request 默认包含这些内容:
背景改动内容影响范围验证方式风险与回滚
推荐模板:
## 背景
- 为什么要做这次修改
## 改动内容
- 这次具体改了什么
## 影响范围
- 涉及哪些模块、接口、配置或部署方式
## 验证方式
- 执行了哪些测试
- 做了哪些人工验证
## 风险与回滚
- 潜在风险是什么
- 出现问题如何回滚附加要求:
- 一个 PR 尽量只做一类改动
- PR 标题与提交信息建议使用中英双语
- 改动涉及配置或行为变化时,要同步更新文档
提交信息默认采用 Conventional Commits 风格:
<type>(<scope>): <subject>
说明:
- 冒号
:后必须有一个空格 scope选填,表示 commit 的作用范围,可以写模块名、目录名,或runtime、workspace、web这类职责范围subject必填,用于简短描述本次提交内容,建议使用中英双语
type 必填,允许值如下:
feat:新功能 featurefix:修复 bugdocs:文档注释style:代码格式(不影响代码运行的变动)refactor:重构、优化(既不增加新功能,也不是修复 bug)perf:性能优化test:增加测试chore:构建过程或辅助工具的变动revert:回退build:打包
推荐示例:
feat(agent): 增加了子任务聚合能力 (Add child-run aggregation)
docs(readme): 补充了提交信息格式说明 (Add commit message format notes)
fix(runtime): 修复了 continuation 丢失问题 (Fix continuation dispatch issue)
额外约定:
- 默认按职责拆分 commit,优先拆成“提示词与上下文 / 运行时治理 / 配置默认值与注释 / 测试”这类最小修改单元
- 尽量做到一个 commit 只解决一类问题,避免把无关改动混在一起
本项目允许使用 AI 辅助编写代码和文档。
但需要明确:
- AI 可以参与实现,不可以替代开发者责任
- 所有 AI 参与生成的代码,都必须由开发者人工阅读
- 所有待合并改动,都必须经过开发者人工测试和验证
- 不能因为使用了 AI,就跳过 Review、测试或关键链路回归
建议至少完成与风险等级匹配的人工验证:
- 本地编译
- 单元测试或集成测试
- 关键功能手工验证
- 配置与部署检查
结论很简单:
- 允许使用 AI 写代码
- 不允许未经开发者人工测试和验证直接合并
更完整的仓库协作说明请阅读:
- src/main/java/com/jimuqu/claw/SolonClawApp.java
- src/main/java/com/jimuqu/claw/config/SolonClawConfig.java
- src/main/java/com/jimuqu/claw/agent/runtime/AgentRuntimeService.java
- src/main/java/com/jimuqu/claw/agent/store/RuntimeStoreService.java
- src/main/java/com/jimuqu/claw/agent/workspace/WorkspacePromptService.java
- src/main/java/com/jimuqu/claw/agent/job/WorkspaceJobService.java
- src/main/java/com/jimuqu/claw/channel/dingtalk/DingTalkChannelAdapter.java
- src/main/resources/static/index.html
当前仓库未单独声明许可证时,请以仓库实际发布方式和作者说明为准。