@botlearn-course/daemon
v0.0.6
Published
Lightweight BotLearn Course daemon: run course tasks on your own machine with your own agent runtime (BYOA).
Downloads
231
Readme
@botlearn-course/daemon
BotLearn Course 的轻量本机 daemon:把课程任务(run)分发到你自己机器上的 agent runtime 执行 (BYOA,Bring Your Own Agent)。daemon 用 install code 绑定你的 BotLearn 账号,然后轮询 Course API 领取分配给本机的 run,在隔离工作区内调用本机已登录的 CLI runtime(Codex、 Claude Code、Gemini 等)完成任务,并把过程事件与产出文件候选回传给课程服务。
- 零 production 依赖,只用 Node 内建模块(Node >= 20)。
- 凭据只存本机,不经过第三方;runtime 复用你本机已有的登录状态。
安装与使用
无需安装,直接用 npx:
# 1. 环境自检:探测各 runtime 的安装 / 版本 / 登录状态
npx @botlearn-course/daemon@latest course doctor
# 2. 登录:用前端「我的 Daemon」页面生成的 install code 绑定本机
npx @botlearn-course/daemon@latest course login --api-url <course-api-url> --code <blic_xxx> [--label <名称>]
# 3. 启动:前台轮询并执行分配给本机的 run(Ctrl+C 优雅退出)
npx @botlearn-course/daemon@latest course start [--once] [--poll-interval-ms <ms>]
# 4. 登出:删除本机凭据文件
npx @botlearn-course/daemon@latest course logout命令说明:
| 命令 | 说明 |
| --- | --- |
| course login | 用 install code 换取 daemon 凭据并写入本机 auth.json。--api-url 缺省时读 BOTLEARN_COURSE_API_URL;--label 缺省为本机 hostname。成功后打印 daemon id。 |
| course start | 读取 auth.json,轮询 Course API 领取 run 并执行。--once 只领取一次(有 run 则等它执行完再退出);--poll-interval-ms 调整空轮询间隔。凭据过期/被吊销时提示重新 login 并退出。 |
| course logout | 删除本机 auth.json。服务端吊销请在前端 daemon 列表操作。 |
| course doctor | 打印 Auth 状态(不含 token)与 runtime 探测表(安装路径 / 版本 / 登录状态 / 安装提示)。 |
| --help / --version | 帮助与版本。 |
包内还包含供 BotLearn 托管 E2B Template 使用的内部命令
botlearn-sandbox-supervisor agent-service session。它不是 BYOA 用户入口:生产环境只允许由
Agent Service 以固定 argv 启动,通过 stdin 接收一次性 bootstrap,并把 daemon/runtime 分别降权
到 botlearn-control/user UID。E2B Template 通过 root-owned 固定 launcher 将 DeepSeek
单向降权为 user 并设置 no_new_privs;runtime 用户本身没有 sudo 权限。托管启动链只执行
/opt 下的固定 Node、supervisor、daemon、launcher 与 DeepSeek 文件,不信任 E2B 会开放给 runtime
写入的 /usr/local/bin。
agent-service session --bootstrap-stdin 同样属于受 supervisor 保护的内部协议,不应直接暴露给
课程任务或 workspace shell。
支持的 runtime
run 的 runtime.id 决定用哪个 adapter 执行;未指定时默认 codex。runtime 不可用时 run 会
直接失败(不做静默回退),请先用 course doctor 确认目标 runtime 可用。
| runtime id | 名称 | 依赖的本机命令 | 二进制覆盖变量 | 说明 |
| --- | --- | --- | --- | --- |
| codex | Codex CLI | codex | BOTLEARN_CODEX_BIN | 默认 runtime |
| claude-code | Claude Code | claude | BOTLEARN_CLAUDE_BIN | doctor 会额外探测登录状态 |
| gemini | Gemini CLI | gemini | BOTLEARN_GEMINI_BIN | |
| kimi-cli | Kimi CLI | kimi | BOTLEARN_KIMI_CLI_BIN | |
| deepseek-tui | DeepSeek TUI | deepseek | BOTLEARN_DEEPSEEK_TUI_BIN | Linux/macOS 本地 server 会保留现有 MCP 配置并注入零依赖 report_progress;botlearn 是保留 server key。Windows 因固定 runtime 无法保证 MCP clean-env,首版 fail closed、不注入 progress |
| hermes-agent | Hermes Agent | hermes-acp | BOTLEARN_HERMES_AGENT_BIN | ACP stdio 协议 |
| openclaw-acp | OpenClaw (ACP) | openclaw | BOTLEARN_OPENCLAW_BIN | 还需配置 BOTLEARN_OPENCLAW_URL(可选 BOTLEARN_OPENCLAW_TOKEN / BOTLEARN_OPENCLAW_AGENT),二进制或 URL 缺失时 doctor 标记不可用 |
| fake | 假 runtime | 无 | — | 仅测试/演示用:产出确定性文本与一个 draft.md。默认隐藏,只有 BOTLEARN_DAEMON_ENABLE_FAKE_RUNTIME=1 时才注册并上报 |
各 runtime 的登录(API key / OAuth)沿用你本机已有的配置 —— daemon 不保存、不代管任何 runtime 凭据。
环境变量
| 变量 | 说明 |
| --- | --- |
| BOTLEARN_COURSE_API_URL | course login --api-url 缺省值 |
| BOTLEARN_DAEMON_HOME | 覆盖本地状态根目录(默认 ~/.botlearn-course/daemon;测试/多实例用) |
| BOTLEARN_DAEMON_DEBUG | 非空时输出 debug 级日志 |
| BOTLEARN_<X>_BIN | 覆盖某个 runtime 的二进制路径,各 runtime 的变量名见上表(如 BOTLEARN_CLAUDE_BIN),以 course doctor 输出为准 |
| BOTLEARN_OPENCLAW_URL | OpenClaw gateway 地址(openclaw-acp 必需) |
| BOTLEARN_OPENCLAW_TOKEN | OpenClaw gateway token(可选) |
| BOTLEARN_OPENCLAW_AGENT | OpenClaw agent 名称(可选) |
| BOTLEARN_DAEMON_ENABLE_FAKE_RUNTIME | 设为 1 时启用测试用 fake runtime |
本地文件布局与权限
所有状态位于 ~/.botlearn-course/daemon(可用 BOTLEARN_DAEMON_HOME 覆盖):
~/.botlearn-course/daemon/ # 0700
auth.json # 0600,daemon 凭据(access/refresh token、courseApiUrl)
machine-id # 0600,首次运行生成的机器指纹
logs/ # 0700
daemon.log # 0600,按 10MiB 轮转,保留 20 个历史文件
workspaces/<agent_run_id>/ # 每个 run 一个隔离目录,0700
work/ # runtime 的工作目录(cwd),产出文件候选从这里扫描
transcript.jsonl # 本地执行记录(脱敏后写入)安全说明
auth.json是敏感凭据文件(0600),token 只存本机、只发给你 login 时指定的 Course API; 日志、transcript、doctor 输出、错误信息在写出前都会经过脱敏(token / api key / 密码等 字段与常见 token 形态一律替换为[REDACTED])。- 文件扫描只访问 workspace 内路径;包含
..、绝对路径或反斜杠的路径会被拒绝。本机 BYOA daemon 上报相对路径、大小、sha256 和脱敏 preview;Agent Service sandbox 还会在 终态前把完整文件上传到 Course Service 的受保护存储。 - 每个 run 在独立 workspace 内执行并有超时上限;runtime 进程在取消/超时后会被终止 (SIGTERM → SIGKILL)。
report_progressMCP 子进程以 clean environment 启动,不继承 Course 控制字段或模型凭据; transcript 与 Course event 只保留严格归一化后的summary/status,不保存原始 tool arguments。course logout只删除本机凭据;要让服务端立即吊销该 daemon,请在前端 daemon 列表执行 revoke。- 本包 production 依赖为零,发布 tarball 只包含
dist/、README.md、package.json、LICENSE(CI 发布前强制校验)。 - 托管 session 的 control token/reconnect state 位于 runtime UID 不可访问的
0700control home; runtime workspace 独立可写,Prompt Pack/Skill 则通过 control-owned、group-readable 的只读视图 提供。长期模型 provider key 留在 Agent Service,runtime 只拿 generation-scoped proxy grant。
发布
在 GitHub Actions 中手动运行 Publish Course Daemon。version 留空时,CI 读取 npm 的
latest 版本并自动增加 patch;包尚不存在时首次发布为 0.0.1。只有需要指定
major、minor 或 prerelease 时才填写精确 SemVer(例如 1.0.0 或 1.1.0-rc.1)。
所有正式版发布到 npm dist-tag latest,prerelease 发布到 next。CI 会串行化发布并在
上传前确认目标版本尚不存在,避免并发任务重复发布同一个版本。
