skill-b-pre-brief

Automation

【会前简报定时任务】每15分钟由 OpenClaw cron 触发一次。负责在会议开始前15分钟至6小时内自动生成并发送会前进度简报。不处理会议创建、会议修改、取消会议、会后纪要等场景。触发关键词:会前简报、pre_brief、发简报、会前准备报告。cron 场景下自动触发,无需用户主动输入。

Install

openclaw skills install @myd2002/skill-b-pre-brief

Skill-B: pre_brief — 会前简报自动发送

定位

本技能是 cron 定时执行的会前简报流程总控

职责分工:

  • OpenClaw(本次对话/cron 任务)

    • 触发本技能 scan 脚本
    • 读取 scan 返回的会议列表
    • 对每场会议:调用 gitea-routine-report 拉取 Gitea 活动数据
    • 作为 AI 生成 ai_overview / ai_suggestion / member_summaries / risk_notes
    • 调用 gitea-routine-report 的 render_email.py 渲染 HTML
    • 调用本技能 commit 脚本保存文件并更新状态
    • 调用 imap-smtp-email 向全体参会人发送简报邮件
  • Skill-B(本技能)

    • scan:遍历所有受管仓库,找出需要发简报的会议,计算时间窗口
    • commit:将简报存入 Gitea 会议目录,更新 meta.yaml 状态,写日志,返回邮件参数
  • gitea-routine-report

    • 只做数据拉取 + HTML 渲染
    • 不直接触发其自带邮件发送逻辑(由 OpenClaw 决定发给谁)
  • imap-smtp-email

    • 发送最终简报邮件给全体参会人

配置要求

配置文件:~/.config/skill-b-pre-brief/.env

首次使用前运行:

bash setup.sh

严格工作流(每次 cron 触发必须按顺序执行)


第一步:运行 scan,获取待发简报会议列表

node main.js scan

返回 JSON,meetings 字段包含所有需要处理的会议,每条有以下字段:

  • action"generate_brief" = 正常发简报;"mark_only" = 改期会议只改状态不发邮件
  • repo:仓库全名,如 HKU-AIFusion/dexterous-hand
  • meeting_dir:会议目录名,如 2026-04-22-1500
  • topic:会议主题
  • scheduled_time:会议时间(ISO8601)
  • organizer:组织者 Gitea 用户名
  • attendees:参会人 Gitea 用户名列表
  • attendee_emails:参会人邮箱列表
  • since:Gitea 活动统计开始时间(ISO8601)
  • until:Gitea 活动统计结束时间(ISO8601)
  • report_params:传给 gitea-routine-report 的参数 {repo, since, until}

只有会议时间落在“开始前 15 分钟到 6 小时”这个窗口内,才会被 scan 命中。

如果 meetings 为空,本次 cron 无需继续执行。


第二步:对 action == "mark_only" 的会议,直接更新状态

对每条 action == "mark_only" 的会议,运行:

node main.js commit \
  --repo "HKU-AIFusion/dexterous-hand" \
  --meeting-dir "2026-04-22-1500" \
  --mark-only

这会直接将 meta.yaml status 改为 brief-sent,不生成简报、不发邮件。


第三步:对 action == "generate_brief" 的会议,逐条生成并发送简报

对每条 action == "generate_brief" 的会议,按以下子步骤处理:

3a. 调用 gitea-routine-report 拉取 Gitea 活动数据

使用 scan 返回的 report_params

python <gitea-routine-report路径>/scripts/generate_report.py \
  --repo "HKU-AIFusion/dexterous-hand" \
  --since "2026-04-15" \
  --until "2026-04-22"

输出是 JSON 数组,取 [0] 元素作为本次会议仓库的数据。

注意since / until 日期格式为 YYYY-MM-DD,从 scan 返回的 report_params.since / report_params.until 字段取值(已格式化为此格式)。

3b. OpenClaw 作为 AI 生成纯文字内容

严格按照 gitea-routine-report 的 SKILL.md 第三步格式输出,对上一步的数据生成:

{
  "ai_overview": "...",
  "ai_suggestion": "...",
  "member_summaries": { "成员名": "一句话摘要" },
  "risk_notes": "..."
}

规则同 gitea-routine-report:

  • 只输出 JSON,不加任何 markdown 代码块标记
  • member_summaries 键名必须与数据中成员用户名完全一致
  • 严禁编造数据中没有的内容
  • risk_notes 无风险时填空字符串 ""

3c. 将 AI JSON 保存到临时文件

将上一步 JSON 内容存入 /tmp/ai_brief_{meeting_dir}.jsonmeeting_dir/ 替换为 _):

echo '{"ai_overview": "...", ...}' > /tmp/ai_brief_2026-04-22-1500.json

3d. 调用 gitea-routine-report 渲染 HTML

python -c "
import json, sys, os
sys.path.insert(0, '<gitea-routine-report路径>/scripts')
from render_email import render
data = json.loads(open('/tmp/report_data.json').read())
ai_content = json.loads(open('/tmp/ai_brief_MEETING_DIR.json').read())
repo_data = data[0]
html = render(repo_data, ai_content)
open('/tmp/brief_body_MEETING_DIR.html', 'w').write(html)
print('HTML 已生成,长度:', len(html))
"

注意:generate_report.py 的输出需要先保存到 /tmp/report_data.json,再供 render 使用。MEETING_DIR 替换为实际目录名(如 2026-04-22-1500)。

3e. 调用本技能 commit,保存简报文件并更新状态

node main.js commit \
  --repo "HKU-AIFusion/dexterous-hand" \
  --meeting-dir "2026-04-22-1500" \
  --topic "v2 设计评审" \
  --html-file "/tmp/brief_body_2026-04-22-1500.html" \
  --attendee-emails "email1@163.com,email2@163.com" \
  --since "2026-04-15" \
  --until "2026-04-22"

返回 JSON,关键字段:

  • success:是否成功
  • brief_email.to:收件人邮箱列表
  • brief_email.subject:邮件主题
  • brief_email.html:邮件 HTML 正文

3f. 调用 imap-smtp-email 发送简报邮件

使用 commit 返回的 brief_email 字段,调用 imap-smtp-email 发送。

收件人:brief_email.to(全体参会人邮箱) 主题:brief_email.subject 正文:brief_email.html(HTML 格式)


错误处理规则

错误场景处理方式
scan 无结果正常退出,本次 cron 结束
generate_report.py 失败记录错误,跳过本条会议,继续处理下一条
AI 内容生成失败记录错误,跳过本条会议
render_email 失败记录错误,跳过本条会议
commit 写 Gitea 失败记录错误,不发邮件,下次 cron 重试(status 未变,仍为 scheduled)
邮件发送失败记录错误,但 status 已更新为 brief-sent(日志标注 email_failed)

幂等性说明

  • scan 只返回 status == scheduled 且不含 rescheduled_from 的会议
  • commit 成功后 status → brief-sent
  • 下次 cron 不会再次命中同一场会议
  • commit 失败时 status 不变,下次 cron 自动重试