Briefed
A daily newsletter digest pipeline + local web reader. Gmail → Haiku summaries → web app → notification ping.
Architecture
CODEBLOCK0
Why split fetch/summarise? Raw Gmail API JSON overflows Haiku's context. Python handles data wrangling; Haiku handles cognition.
Security & Scope
- - Gmail access is read-only (
gmail.readonly). - OAuth token is stored locally at
~/.openclaw/workspace/briefed-gmail-token.json (or BRIEFED_GMAIL_TOKEN_FILE). - The workflow should only read/write the following workspace files:
-
newsletter-inbox.json
-
newsletter-today.json
-
newsletter-interests.json
-
newsletter-notes.json
-
reading-list.md
- - Do not send newsletter content to external endpoints other than the configured model provider and user-selected notification channel.
Prerequisites
- - Python 3.9+
- Python deps for Gmail API (
google-api-python-client, google-auth, google-auth-oauthlib) - A Google OAuth Desktop client JSON file (for Gmail read-only auth)
- Node.js ≥18 (for the reader web app)
- INLINECODE11 on the OpenClaw models allowlist
- A notification channel configured in OpenClaw (Telegram, Discord, etc.)
Setup
1. Install Python dependencies
CODEBLOCK1
2. Configure Gmail OAuth
Create a Google Cloud OAuth Desktop app and download the client JSON, then set:
CODEBLOCK2
On first script run, Briefed opens a browser OAuth flow and stores a reusable token at:
CODEBLOCK3
3. Deploy the reader app
CODEBLOCK4
4. Configure Gmail token paths (optional)
Defaults (works for most users):
- - Token file: INLINECODE12
- Client secret: INLINECODE13
Override via env vars if needed:
CODEBLOCK5
5. Configure interests
Create ~/.openclaw/workspace/newsletter-interests.json (or let it be auto-created on first run):
CODEBLOCK6
6. Start the reader
Run manually if you prefer no persistence. LaunchAgent is optional convenience for auto-start.
CODEBLOCK7
LaunchAgent plist template:
CODEBLOCK8
CODEBLOCK9
7. Create the daily cron job
Use the OpenClaw cron tool with this agent prompt (fill in the placeholders):
CODEBLOCK10
Before enabling cron, run this once manually to complete OAuth in a browser:
CODEBLOCK11
Cron schedule: 0 7 * * * (7am daily), model: anthropic/claude-haiku-4-5, delivery: announce.
Data Files
All data files live in ~/.openclaw/workspace/:
| File | Purpose |
|---|
| INLINECODE19 | Compact pre-fetched email metadata (ephemeral) |
| INLINECODE20 |
Today's stories with summaries + HTML bodies |
|
newsletter-interests.json | Topic weights + vote/open signals |
|
newsletter-notes.json | Per-story user notes |
|
reading-list.md | Saved/bookmarked stories |
Reader API
| Endpoint | Method | Purpose |
|---|
| INLINECODE24 | GET | All stories (bodies stripped) |
| INLINECODE25 |
GET | Single story with full HTML body |
|
/api/vote | POST |
{ storyId, vote: "up"\|"down"\|"open" } |
|
/api/save | POST |
{ storyId } — adds to reading-list.md |
|
/api/note | POST |
{ storyId, note } |
|
/api/notes | GET | All notes |
Filtering Transactional Email
INLINECODE33 has two tunable lists near the top:
- -
SKIP_SUBJECT_PATTERNS — subject substrings that flag an email as transactional - INLINECODE35 — sender names that are always transactional (e.g. banks, shops)
Tune these when transactional emails slip through.
Branding
The reader shows "Briefed" with a blue "B" logo by default. To customise, edit public/index.html and public/icon.svg.
Briefed
每日简报摘要流水线 + 本地网页阅读器。Gmail → Haiku 摘要 → 网页应用 → 通知推送。
架构
[Gmail]
↓ pre-fetch.py(获取、过滤、提取精简元数据)
[newsletter-inbox.json]
↓ Haiku 定时任务代理(读取精简 JSON,撰写 AI 摘要)
[newsletter-today.json]
↓ fetch-bodies.py(添加完整 HTML 邮件正文)
[newsletter-today.json + 正文]
↓ Express 网页阅读器(默认端口 3001)
[通知推送 → 用户打开阅读器]
为何拆分获取/摘要? 原始 Gmail API JSON 超出 Haiku 的上下文限制。Python 处理数据整理;Haiku 处理认知任务。
安全与范围
- - Gmail 访问权限为只读(gmail.readonly)。
- OAuth 令牌本地存储于 ~/.openclaw/workspace/briefed-gmail-token.json(或 BRIEFEDGMAILTOKEN_FILE)。
- 工作流仅应读写以下工作区文件:
- newsletter-inbox.json
- newsletter-today.json
- newsletter-interests.json
- newsletter-notes.json
- reading-list.md
- - 除配置的模型提供商和用户选择的通知渠道外,不得将简报内容发送至外部端点。
前置条件
- - Python 3.9+
- Gmail API 的 Python 依赖(google-api-python-client、google-auth、google-auth-oauthlib)
- Google OAuth 桌面客户端 JSON 文件(用于 Gmail 只读认证)
- Node.js ≥18(用于阅读器网页应用)
- OpenClaw 模型许可列表中的 claude-haiku-4-5
- 在 OpenClaw 中配置的通知渠道(Telegram、Discord 等)
设置
1. 安装 Python 依赖
bash
cd ~/.openclaw/workspace/briefed
python3 -m pip install -r scripts/requirements.txt
2. 配置 Gmail OAuth
创建 Google Cloud OAuth 桌面应用并下载客户端 JSON,然后设置:
bash
export BRIEFEDGMAILCLIENTSECRET=~/clientsecret.json
首次运行脚本时,Briefed 会打开浏览器 OAuth 流程,并将可重复使用的令牌存储于:
bash
~/.openclaw/workspace/briefed-gmail-token.json
3. 部署阅读器应用
bash
将阅读器复制到工作区
cp -r assets/reader/ ~/.openclaw/workspace/briefed/
cd ~/.openclaw/workspace/briefed
npm install
4. 配置 Gmail 令牌路径(可选)
默认值(适用于大多数用户):
- - 令牌文件:~/.openclaw/workspace/briefed-gmail-token.json
- 客户端密钥:~/client_secret.json
如需覆盖,可通过环境变量:
bash
export BRIEFEDGMAILCLIENTSECRET=~/path/to/clientsecret.json
export BRIEFEDGMAILTOKEN_FILE=~/.openclaw/workspace/briefed-gmail-token.json
5. 配置兴趣
创建 ~/.openclaw/workspace/newsletter-interests.json(或首次运行时自动创建):
json
{
version: 1,
topics: { ai: 0.9, startups: 0.8, design: 0.75 },
signals: [],
sources: {}
}
6. 启动阅读器
如果您不希望持久运行,可手动启动。LaunchAgent 是用于自动启动的可选便捷方式。
bash
快速测试
node ~/.openclaw/workspace/briefed/server.js
持久运行 — 创建 ~/Library/LaunchAgents/ai.openclaw.briefed.plist
LaunchAgent plist 模板:
xml
Labelai.openclaw.briefed
ProgramArguments
/usr/local/bin/node
/Users/YOUR_USER/.openclaw/workspace/briefed/server.js
EnvironmentVariables
BRIEFEDGMAILCLIENTSECRET/Users/YOURUSER/client_secret.json
BRIEFEDGMAILTOKENFILE/Users/YOURUSER/.openclaw/workspace/briefed-gmail-token.json
RunAtLoad
KeepAlive
WorkingDirectory/Users/YOUR_USER/.openclaw/workspace/briefed
StandardOutPath/tmp/briefed.log
StandardErrorPath/tmp/briefed.log
bash
launchctl load ~/Library/LaunchAgents/ai.openclaw.briefed.plist
7. 创建每日定时任务
使用 OpenClaw 定时任务工具,配合以下代理提示词(填写占位符):
运行我的每日简报摘要。请严格按照以下步骤执行:
第 1 步 — 预获取邮件
运行:python3 ~/.openclaw/workspace/briefed/scripts/pre-fetch.py
第 2 步 — 读取精简收件箱
读取:~/.openclaw/workspace/newsletter-inbox.json
第 3 步 — 使用 AI 摘要写入 newsletter-today.json
对于每封简报,仅写入此文件:~/.openclaw/workspace/newsletter-today.json。
此步骤中不要修改任何其他文件。
使用 snippet 字段撰写真实摘要 — 不要仅重复主题行。
按兴趣评分:(调整主题和权重以匹配您的兴趣)
ai/ml=0.9, startups=0.85, design=0.8, finance=0.75, general=0.6
每条故事的架构:
{ id, rank, source, subject, headline, summary, bullets: [], threadId, gmailUrl, score, body: }
第 4 步 — 获取 HTML 正文
运行:python3 ~/.openclaw/workspace/briefed/scripts/fetch-bodies.py
第 5 步 — 发送通知
发送(通过您配置的渠道):
📬 今日摘要已就绪 —
条故事等待阅读。\n→ http://YOUR_HOST:3001
第 6 步 — 最终回复
📬 Briefed — [DD Mon YYYY] · 条故事
. <来源> — <标题>
<一句话摘要>
(重复所有故事)
打开阅读器 → http://YOURHOST:3001_
在启用定时任务前,请手动运行一次以在浏览器中完成 OAuth:
bash
python3 ~/.openclaw/workspace/briefed/scripts/pre-fetch.py
定时任务调度:0 7 *(每天上午 7 点),模型:anthropic/claude-haiku-4-5,投递方式:announce。
数据文件
所有数据文件位于 ~/.openclaw/workspace/:
| 文件 | 用途 |
|---|
| newsletter-inbox.json | 精简的预获取邮件元数据(临时) |
| newsletter-today.json |
今日故事,含摘要 + HTML 正文 |
| newsletter-interests.json | 主题权重 + 投票/打开信号 |
| newsletter-notes.json | 每条故事的用户笔记 |
| reading-list.md | 已保存/已收藏的故事 |
阅读器 API
| 端点 | 方法 | 用途 |
|---|
| /api/today | GET | 所有故事(不含正文) |
| /api/story/:id |
GET | 单条故事,含完整 HTML 正文 |
| /api/vote | POST | { storyId, vote: up\|down\|open } |
| /api/save | POST