Install
openclaw skills install @noaheleven/dingtalk-auto-reply监控钉钉未读会话,单聊用 AI 以老板口吻自动回复,群聊/指定名单只发微信提醒(不代发,防社死)。覆盖 dws 未读接口、CodeBuddy Agent SDK 生成回复的 SERVER__PORT 端口冲突坑、自报家门坑、回复自己坑。当用户要求「钉钉自动回复/钉钉代回/监听钉钉未读+AI回复」时使用。
openclaw skills install @noaheleven/dingtalk-auto-reply监控钉钉未读会话,单聊用 AI 以老板口吻自动回复,群聊/指定名单只发微信提醒(不代发,防社死)。
🔗 项目主页 / 源码:https://github.com/NoahEleven/dingtalk-auto-reply
dingtalk-auto-reply/
├── SKILL.md # 本说明
├── dingtalk_unread_monitor.py # 主脚本(轮询+生成+回复+推送;含日志轮转/单实例锁/缓存清理/心跳)
├── gen_launcher.py # 启动器生成器(本机自动生成 Startup .vbs,.vbs 不随包分发)
├── secretary_system_prompt.txt # 老板口吻人设(SDK system_prompt 注入)
├── _validate.py # 自测脚本(集成验证,不真发回复)
├── stop_monitor.ps1 # 精确结束本脚本 python(仅停进程)
└── recover_missed.py # 补发漏掉的消息(监控曾宕机/DRY_RUN 时,手动拉未读并代复)
移植:把整个目录复制到目标机的 ~/.workbuddy/skills/ 即可,无需改代码。
⚙️ 移植后必做一步:把 dws 加入系统 PATH(根因与自动追加机制见下方「dws 依赖」段)。dws 不在 PATH → get_unread 恒空;换机部署先跑一次 gen_launcher.py 自动幂等追加(无需重登),新终端敲 dws 有输出即就位。
⚠️ 启动器 .vbs 不随包分发:.vbs 是机器专属胶水文件(路径用 %USERPROFILE% 环境变量展开动态推导、无硬编码用户名,并备 SpecialFolders("Profile") / %HOMEDRIVE%%HOMEPATH% 兜底),被列入 .gitignore,不会随仓库/打包上传。换机或重新克隆后,启动器由 gen_launcher.py 在本机生成(见下方「Windows · Startup 启动器」),监控脚本首次运行也会自动自检并生成,无需手动复制 .vbs。
dws chat message list-unread-conversations --format json → 只返回有未读的会话(天然过滤)。
字段:openConversationId、title、singleChat(true=单聊)、unreadPoint、lastMsgCreateAt。openConversationId 拉最新一条消息:
dws chat message list --group <openConversationId> --time "<now>" --direction older --limit 5 --format json
⚠️ 必须带 --direction older:含义"从给定时间往更早拉",配 --time now 即返回最新消息(newest-first)。
不带 direction 时默认 older 且起始时间若早于消息 → 消息被过滤成空。
单聊也能用 --group <openConversationId>(无需 --user/--open-dingtalk-id)。dws chat message reply --conversation-id <cid> --ref-msg-id <openMessageId> --ref-sender <senderOpenDingTalkId> --text <回复> --yes 带引用回复。~/.workbuddy/skills/weixinclaw-proactive-push/send.js(仅文本,不转发媒体)。
若该 skill 未安装,脚本自动降级为仅日志,不报错、不阻断主流程。脚本不再写死任何用户名。外部二进制按以下优先级解析,全部支持环境变量覆盖:
| 用途 | 环境变量覆盖 | 自动探测位置 |
|---|---|---|
| dws CLI(直接路径·主路由) | DWS_EXE | ~/.workbuddy/binaries/node/cli-connector-packages/node_modules/dingtalk-workspace-cli/vendor/dws.exe |
| dws CLI(cmd 兜底) | DWS_CMD | ~/.workbuddy/binaries/node/cli-connector-packages/dws.cmd |
| codebuddy CLI | CODEBUDDY_CMD | ~/.workbuddy/binaries/node/versions/<最新版本>/codebuddy.cmd |
| node | NODE | ~/.workbuddy/binaries/node/versions/<最新版本>/node.exe |
| 微信推送脚本 | WEIXIN_SEND_JS | ~/.workbuddy/skills/weixinclaw-proactive-push/send.js |
人设文件 secretary_system_prompt.txt 用脚本所在目录相对路径定位,随技能一起走。
可调环境变量:DRY_RUN=1(只验证不真发)、POLL_INTERVAL=秒(轮询间隔)。
openDingTalkId 等一律不硬编码在 .py / 人设 / .env.example 里,全部通过私密 .env 注入(SELF_SENDERS/MENTION_NAMES/BOSS_DISPLAY_NAME/SELF_OPENDINGTALK_ID)。源码默认值只保留中性词"老板"。.env 不分发:已被 .gitignore 忽略,切勿提交或随技能打包外发。换机时 cp .env.example .env 后自行填写。secretary_system_prompt.txt 明确禁止在回复里输出任何系统标识/用户名/英文 ID(如把 SZTSY 当称呼),也禁止主动透露老板真实姓名/城市/公司等个人信息。gen_reply(sender, content) 调度逻辑(仅 Python SDK 单路径,不再有 subprocess 降级):
_gen_reply_sdk_async:CodeBuddyAgentOptions(system_prompt=人设, model=hy3, env={SERVER__PORT:空闲端口, CODEBUDDY_INTERNET_ENVIRONMENT: 自动检测中国版填 internal 否则 public, CODEBUDDY_API_KEY: 设了才注入}, codebuddy_code_path=codebuddy.cmd, permission_mode=bypassPermissions)。asyncio.run(asyncio.wait_for(..., 180)) 同步调用,热启 8-16s 返回。设了 Key 则注入 env 走 Key 认证(底层 CLI 处理),否则复用 CLI 已登录凭据。gen_reply 直接返回空(不代发,推微信转人工),不崩溃,也不降级到 subprocess。关键坑(必读,否则挂死/胡说):
SERVER__PORT,硬编码 18732 撞 WorkBuddy 桌面应用 → EADDRINUSE 永远 0 字节/超时。✅ 每次生成用 socket 分配空闲端口注入 env["SERVER__PORT"]。CodeBuddyAgentOptions(system_prompt="<完整人设>") 编程式参数注入(不是 append_system_prompt,否则仍保留 agent 人格)。人设里写死"你是老板本人、禁止自我介绍、禁止称呼对方为老板、只输出回复正文"。编程式传参天然避免命令行 -p 经 cmd /c 传递多行文本时的换行截断/乱码(人设里的 emoji、→ 都能完整传入)。get_self_openid() 缓存老板 openDingTalkId,_is_self(sender, sender_open_id) 优先用 openid 精确匹配,openid 拿不到才回退 SELF_SENDERS 昵称关键字(私密 .env 配置,源码默认仅"老板")。命中则跳过自动回复。query() 以 async for 流式返回消息对象,最终回复在 AssistantMessage.TextBlock.content,天然不带 prewarm 日志/工具噪音。✅ 直接拼接所有 AssistantMessage 的 TextBlock.text 即得原始回复,比 -p --output-format json 再 json.loads 更稳。SDK 调用是"跑完一次性返回",冷启动 + hy3 首次可能 3-5 分钟才返回,asyncio.wait_for(..., 180) 超时给 180s 安全余量;超时返回空 → 走「不代发转人工」。extract_reply() 抽 <reply> 标签正文,_looks_like_reply() 反向拒掉空回复/反问/角色扮演/自称老板/助理口吻;质量不达标/超时/异常返回空 → 调用方走「不代发,转人工通知」。codebuddy_code_path 必须用 codebuddy.cmd(非无扩展名 bin/codebuddy,否则 WinError 193);中国版 env={"CODEBUDDY_INTERNET_ENVIRONMENT":"internal"};末尾 ValueError: I/O operation on closed pipe 是 Windows asyncio 清理警告,无害。问题:发现单聊未读后立即代发,会抢老板自己的回答(老板正拿着手机准备回,AI 已代回)。
方案:发现未读不立即发,走「延迟 + 活跃检测」两步:
owner_recently_active(cid) 拉该会话最近消息,看老板最近 ACTIVE_WINDOW_SEC(默认 300s=5分钟)内是否在该会话发过消息(SELF_OPEN_ID 精确匹配)。活跃 → 跳过不代发(老板在跟,会自己回)。PENDING 等 REPLY_DELAY_SEC(默认 120s=2分钟)。
gen_reply+send_reply+审计+微信通知)。可调环境变量(默认已配好):
REPLY_DELAY_SEC=120:延迟窗口时长(秒),给老板自己回的时间。ACTIVE_WINDOW_SEC=300:老板活跃判定窗口(秒),最近 N 秒在该会话发过消息算"正在跟"。效果:既给老板充足回复时间,又从根上避免"老板正在聊却被 AI 抢话"。群聊/媒体无文本/生成失败仍走原"不代发转人工"逻辑,不受影响。
问题:早期实现把所有群消息都推到微信——普通群刷屏、@别人的消息、特别关注的人发言全都会打扰老板。老板只关心"有人@我"这类真正重要的群消息。
接口事实(已实测):
list-unread-conversations 和 chat message list 的单条消息对象里没有 @我 结构化字段(atUsers/atDingTalkIds 都不返回);群消息里 @ 某人只表现为内容前缀纯文本 @昵称(如 @盘锦丽 已经试过了)。chat message list-mentions --group <cid>(只返回 @我 的消息),但空群返回无 messages 字段的空结果,结构不稳定,不适合做热路径每轮轮询。方案(内容启发式,零额外 API 调用 + GROUP_PUSH 策略开关):
group_msg_is_at_me(content) 判据:
@所有人 / @all / <@all>(dws 发送占位)→ 必然含老板 → True;@昵称 开头且昵称命中 MENTION_NAMES → True;False。GROUP_PUSH 策略(仅作用于群消息;单聊代复+提醒不受影响):
atme(默认):仅 at_me=True(@我/@all)才推微信;其余群消息静默跳过,不推。all:所有群消息都推(旧行为)。off:群聊完全不推微信(连@我都不推)。🔔 钉钉新消息(群聊·有人@你),一眼区分。配置:
MENTION_NAMES(源码默认仅 老板;真实群昵称在私密 .env 配置),群昵称特殊时覆盖:MENTION_NAMES="你的昵称,你的简称"。GROUP_PUSH=atme(默认)| all | off。局限:纯展示名匹配,若群里恰好有人昵称与你相同会误判(极罕见);如需 100% 服务端权威,可改用 list-mentions 二次确认(见上"接口事实"),当前为成本/可靠性权衡选择启发式。
问题:钉钉图片消息不是"无文本"——mediaId 内嵌在 content 里([图片消息](mediaId=@lQLP...)),常带文字说明+@人。原逻辑把图片当"(图片/媒体消息)"丢弃,老板既看不到图里是什么,也修不掉"图片被误当纯文本代复"的隐患(content 含 mediaId 噪音,喂给 AI 会乱回)。
实现:
extract_media_ids(content):正则提取所有图片 mediaId(一条消息可能多张,最多取前 4 张)。clean_text_for_ai(content):去掉 [图片消息](mediaId=...) 噪音,保留纯文字说明,作为 AI 上下文(修掉误代复 bug)。download_images(...):调 dws chat message download-media 把图下到 _media_cache/(路径必须用 Windows 原生反斜杠绝对路径,否则底层 Go 组件误解析 /c/ 导致落盘失败)。describe_image(path) + describe_images(paths):默认复用 hy3 内置多模态(CodeBuddy Agent SDK 的 image 协议,把图 base64 内联进 SDK query,实测可准确读出文字/颜色/图形,文本落在 AssistantMessage/TextBlock,抽取方式与 gen_reply 一致);若 .env 显式配 VISION_API_KEY 则改用外部 OpenAI 兼容视觉 API(可选更快/更便宜模型)。两条路径都返回中文描述。主要用于群聊 @我 通知和单聊不代复时让老板知道图里是什么。🖼️ 图片内容:XXX(describe_images 1 次调用)。AUTO_REPLY_IMAGE 开启(默认开) → 把图以 image 协议直接内联进 gen_reply 的 hy3 调用(识别+代复 1 次调用完成,不再先 describe 再代复的二次调用);失败/质量不达标仍走安全网不代发。单聊不代复(开关关,AUTO_REPLY_IMAGE=0)时则只走 describe_images 1 次拿描述补通知。降级:CodeBuddy Agent SDK 不可用(_SDK_AVAILABLE=False)→ VISION_ENABLED=False → 不识别、不下载图片,微信通知里图片只显示 (图片/媒体消息),不报错、不阻断。只要 SDK 可用即开箱即用识别,无需任何 key。
配置:视觉后端默认 hy3(零配置);如需覆盖填 VISION_API_KEY / VISION_BASE_URL / VISION_MODEL(OpenAI 兼容协议,如 gpt-4o-mini)。单聊图片自动代复开关 AUTO_REPLY_IMAGE(默认开,设 AUTO_REPLY_IMAGE=0 可关闭)。
[heartbeat] alive, unread_now=N,无未读也打——静默但健康,区别于"静默空转假死"(详见下方「读取日志」)。lastMsgCreateAt(媒体消息 openMessageId 可能为空,不能做去重依据)。DRY_RUN=1 环境变量:只生成+打印,不真发回复/不推微信,用于验证。SKIP_SENDERS 可配置不代发的名单(家人/上级)。_looks_like_reply 拒绝)、或媒体消息无文本时,绝不发兜底话术(避免对方以为老板看到了其实没看到),只推微信「需手动处理」转人工。单聊即使质检拦下也会把 AI 生成的草稿原文一并带进微信通知(不代发到钉钉,但让老板看到草稿、便于手动补发)。~/.workbuddy/dingtalk_auto_audit.jsonl(每行一个 JSON:时间、会话、发件人、内容、回复、发送结果)。代老板发消息是高风险对外操作,必须可追溯。_dws_ok() 解析 dws 返回的 JSON 看 success/errcode,空输出/含 error/errcode≠0 都判失败;不再用"不含 error 即成功"的弱判据。~/.workbuddy/dingtalk_auto.lock 存 PID(原子 O_CREAT|O_EXCL 创建,避免竞态),启动检测到锁里 PID 还活着则立刻退出(杜绝同条消息双发);锁里是陈旧 PID(进程已死)则接管。dingtalk_auto_debug.log 超 1MB、dingtalk_auto_audit.jsonl 超 512KB 自动重命名为 .1(保留一份回溯),常驻进程下不再无限撑爆磁盘。_media_cache/ 下超过 7 天的图片,防常驻下缓存无限增长。try/except 包裹整轮;get_unread() 等持续失败时按次数退避(每次 +10s、上限 120s)避免热循环狂刷日志;异常被捕获后下一轮继续,监控不会"死掉"。Python 环境:必须用装了
codebuddy-agent-sdk的 python。WorkBuddy 上即 default venv: Windows%USERPROFILE%\.workbuddy\binaries\python\envs\default\Scripts\python.exe;macOS/Linux$HOME/.workbuddy/binaries/python/envs/default/bin/python3(下文统称$PY) 未装codebuddy-agent-sdk时脚本无法生成回复(走「不代发」逻辑),但不会崩溃。装:$PY -m pip install codebuddy-agent-sdk
# Windows
PY="$USERPROFILE/.workbuddy/binaries/python/envs/default/Scripts/python.exe"
# macOS / Linux
PY="$HOME/.workbuddy/binaries/python/envs/default/bin/python3"
# 0) 自测(集成验证,不真发回复;会真实调一次 SDK 生成)
"$PY" ~/.workbuddy/skills/dingtalk-auto-reply/_validate.py
# 1) 先验证(不发真实回复、不推微信)
DRY_RUN=1 "$PY" ~/.workbuddy/skills/dingtalk-auto-reply/dingtalk_unread_monitor.py
# 2) 真实运行(会代老板发钉钉 + 推微信)
"$PY" ~/.workbuddy/skills/dingtalk-auto-reply/dingtalk_unread_monitor.py
dws 环境变量:监控本体走绝对路径,但为让你手动用
dws及兜底DWS_CMD,本技能gen_launcher.py会自动把 dws/node 目录追加进用户 PATH(详见下方「dws 依赖」段);手动补 PATH 亦见该段。
脚本启动即做认证健康检查,未通过会打印醒目提示并退出(exit 2),不会悄悄空跑:
.env 填 CODEBUDDY_API_KEY=你的key(申请:https://copilot.tencent.com 控制台)→ 用 Key 直连,不依赖交互登录。codebuddy 登录过的凭据。codebuddy 完成登录;②在 .env 填 CODEBUDDY_API_KEY。~/.codebuddy/local_storage 是否标记 internal,自动注入 CODEBUDDY_INTERNET_ENVIRONMENT=internal,无需手动配。脚本绝不代填/存储你的登录凭据,只检测"是否已登录"并给提醒——认证动作由你本人在终端完成。首次启动前请先确认已登录(终端跑一次
codebuddy或填 Key),未登录会打印提示并以退出码 2 退出,绝不代发。
WorkBuddy 桌面客户端不能作为后台常驻进程;但本脚本是独立 Python 进程,可自行后台常驻轮询。生成回复走 Python SDK(即起即退的子进程),不依赖 WorkBuddy 桌面客户端运行。
启动器 .vbs 不随技能分发(见上方移植说明,已被 .gitignore 排除),由本机 gen_launcher.py 生成到 %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\。两种落地方式,任选其一(或都做):
# 方式 A:手动生成一次(推荐,部署时执行)
"$PY" ~/.workbuddy/skills/dingtalk-auto-reply/gen_launcher.py
# 方式 B:什么都不做 —— 监控脚本首次运行会自动自检并生成(日志可见 [launcher] 行)
dingtalk_unread_monitor.py 的 python——进程不在立刻拉起;进程在但调试日志超 180s 未更新(卡死/静默空转)则杀掉重拉,~30s 内自愈,无需重登。.vbs(全英文注释),Windows Script Host 读取零风险。dingtalk_auto_reply_launcher.vbs(由 gen_launcher.py 的 VBS_CONTENT 常量生成,改动请以改 gen_launcher.py 为准,勿手改运行中的 .vbs 以免漂移)。⚠️ 为什么不用 Windows 计划任务:计划任务把脚本跑在隔离会话里,该会话无网络出口、也拿不到 WorkBuddy 宿主本地服务 →
dws连不上后端、每次get_unread超时返回空 → 日志只剩启动 banner、看不到raw unread、不会代复(进程活着 CPU≈0 却不工作)。Startup 启动器在登录后的交互式会话(与 WorkBuddy 宿主同会话、有完整网络)拉起,从根上避开。故计划任务方案已弃用,不要再注册。
🔴 窗口样式与 dws 访问无关(2026-07-15 老板纠偏):VBS 拉起监控的窗口样式
N(0=隐藏 / 1=普通 / 2=最小化)不影响 dws 能否拿到未读。能否拿到未读只取决于「dws 在系统 PATH」+「跑在登录后的交互式会话」(见上方「为什么不用 Windows 计划任务」与下方「dws 依赖」两段),与隐藏/最小化无关。之前"隐藏窗口会摘出会话导致 dws 返回空"是错误猜想,真实根因是 dws 当时没进 PATH。
nohup python ~/.workbuddy/skills/dingtalk-auto-reply/dingtalk_unread_monitor.py \
> ~/.workbuddy/dingtalk_auto_daemon.log 2>&1 & disown
python dingtalk_unread_monitor.py(前台 python 调试;正式运行由 VBS 启动器以 python.exe 隐藏窗口拉起)。stop_monitor.ps1(精确结束本脚本 python,不动其它 python)。pkill -f dingtalk_unread_monitor.py 按 PID 杀。监控只通过 dws(DingTalk Workspace CLI,WorkBuddy 连接器) 读取未读、发送回复,
不依赖本机钉钉桌面客户端(dws 走 WorkBuddy 宿主本地服务,与是否在跑钉钉客户端无关)。
今天实测已石锤:dws 独立工作,之前「unread_now 恒为 0」的真实根因是 dws 不在系统 PATH 上,
而非客户端。需满足:
dws 已授权(dws patch chmod 授权 chat.message:list / chat.message:send / contact:search);
dws 在系统 PATH 上(User 环境变量):终端能敲出 dws 即说明已就位;本技能 gen_launcher.py 会自动把 dws/node 目录追加进用户 PATH(HKCU\Environment,幂等、写后广播刷新),无需手动配;
监控进程跑在登录后的交互式会话(与 WorkBuddy 宿主同会话、有完整网络,而非计划任务/服务那种隔离会话);
dws 取不到未读(返回空/超时)的典型原因:PATH 缺失(dws 找不到)、会话隔离(无网)、未授权 → 监控"看着活着"却什么都不做。
⚙️ 关于"读取空"的另一层根因(已实现方案,无需用户操作):dws 是 Node 打包二进制,对匿名管道(PIPE)的 stdout 是异步写,进程退出前未 flush → Python
capture_output读到 0 字节(与父进程是否控制台无关,python.exe 下同样复现)。监控统一用文件重定向(dws 输出写临时文件再读)绕过,每次稳定拿到数据;此实现细节已封装,用户只需保证上方 PATH / 会话 / 授权三条即可。
日志位置(监控以 python.exe 隐藏窗口运行,全部写文件,不落 stdout):
~/.workbuddy/dingtalk_auto_debug.log —— 运行日志(超 1MB 自动轮转为 .1)~/.workbuddy/dingtalk_auto_audit.jsonl —— 代发/跳过审计(超 512KB 轮转)如何判断监控健康(tail 最后几行):
| 日志现象 | 含义 | 处理 |
|---|---|---|
每 ~120s 一行 [heartbeat] alive, unread_now=N, ts=HH:MM:SS | 正常轮询中 | 无需处理 |
有 raw unread: [...] | 拉到未读会话了 | 正常,走代复/提醒流程 |
只有启动 banner、长时间无 heartbeat/raw unread | 卡死或掉进无网会话 | 看门狗应在 180s 内自动杀掉重拉;若仍无,检查钉钉客户端是否在跑、网络是否通 |
已有另一个监控实例在运行,本进程退出 | 单实例锁生效,重复启动被拒 | 正常,无需处理 |
auto-reply monitor started | 新实例刚拉起 | 正常 |
审计日志出现 skip_reply / notify_only | 主动跳过(老板活跃 / 群非@我 / 生成失败) | 设计内,非 bug |
_validate.pyDEBUG_DWS_CALL=1,把「配置的路径(DWS_EXE/DWS_ENTRY/DWS_CMD/NODE 是否存在)」与「run_dws 实际选用的路由(DIRECT-exe / NODE-direct / DWS_CMD-fallback / NONE)」和「接口真实返回的字节长度 / 解析出的会话数」三者对齐打印,并给 PASS / WARN / FAIL 结论;同时把每次 dws 调用的真实 argv + 返回码 + stdout 长度写进调试日志([dws-call] / [dws-route] 行,数据抓取表现为 [dws-file] OK out_len=N)。三条路由输出统一走文件重定向(dws 对 PIPE 异步 flush 丢失、Python 读 PIPE 恒空,文件重定向是当前主力方案,与控制台/解释器无关)。排障"dws 找不到/调不通"时,先看这段比对 + 日志里的 argv,一眼定位是 PATH 缺失还是入口解析错。get_unread 看未读接口是否通;若有单聊未读,继续验证 get_latest_msg 字段、gen_reply 生成、reply --dry-run 命令形态。--dry-run),但 gen_reply 会真实调一次 codebuddy 生成文本(仅一次、不发送)。--test-guard:验证抢答防护逻辑(活跃检测 owner_recently_active + 延迟窗口参数),不真发、不触碰任何人会话。自动探测真实单聊 cid,打印活跃检测结果并演示"进窗口→到期代发"(DRY_RUN 下只生成不真发)。recover_missed.py监控曾宕机、或历史某次以 DRY_RUN=1 启动过(只生成不真发)导致漏掉的单聊消息,用本脚本手动补发:拉取当前未读单聊 → 用 hy3 生成老板口吻回复 → 真正发送并推微信通知。
# 补发所有漏掉的单聊未读(实时真发)
"$PY" ~/.workbuddy/skills/dingtalk-auto-reply/recover_missed.py
⚠️ 会真实代老板发消息,仅在你确认"确有漏发"时使用;群聊不代发(只通知),符合全局策略。
chat.message:list、chat.message:send 与 contact:search(后者用于获取本人 openid 以精确识别「回复自己」;用 dws patch chmod 授权)。
codebuddy_code_path 指向其 codebuddy.cmd,SDK 内部 spawn 它来跑 agent;模型 hy3。pip install codebuddy-agent-sdk。必须装到运行脚本的 python 环境——WorkBuddy managed python 的 default venv(Windows:%USERPROFILE%\.workbuddy\binaries\python\envs\default\Scripts\python.exe -m pip install codebuddy-agent-sdk;macOS/Linux:$HOME/.workbuddy/binaries/python/envs/default/bin/python -m pip install codebuddy-agent-sdk)。未装则 gen_reply 直接返回空(不代发),不会崩溃。secretary_system_prompt.txt 已随技能打包,可按需改老板口吻。.env,可选但推荐)技能目录自带 .env.example,移植到新机:cp .env.example .env 后按需填写。所有项均可选,留空=自动探测/默认。已存在的系统环境变量不被 .env 覆盖。
POLL_INTERVAL(轮询秒)、DRY_RUN=1(只验证不真发)、REPLY_DELAY_SEC(延迟窗口秒,默认120)、ACTIVE_WINDOW_SEC(活跃窗口秒,默认300)、GROUP_PUSH=atme|all|off(群消息推微信策略,默认 atme)、MENTION_NAMES(群 @我 昵称候选,在私密 .env 配你的昵称)、SKIP_SENDERS(不代发名单)、SELF_SENDERS(本人昵称)、AUTO_REPLY_IMAGE(单聊图片代复开关,默认开)、VISION_API_KEY/BASE_URL/MODEL(图片识别后端,默认 hy3 零配置)、各二进制路径。全在 .env.example 有注释。