

🎯 学什么:从特定平台提取结构化数据的完整设计——Consent Check 变体实现 + 三态设计模式的跨 Skill 复用 + 正列表边界设计 + 自包含输出目录。同时巩固 Danger Skill 的四条设计原则(L1-07 之后第一个继续深化的 danger Skill)。 💡 难易度:⭐⭐ | ⏱️ 预计时间:45 分钟
1. 课程概览

💡 白话小课堂:你在 X/Twitter 上看到一篇特别好的长文,想保存下来慢慢看——但直接截图只能看不能编辑,复制粘贴格式全丢了,发推的人删了你就再也找不到了。baoyu-danger-x-to-markdown 把推文「翻译」成 Markdown(Markdown:用简单符号如 # = 标题来排版的纯文本格式,是写文档的通用语言) 文件——文字结构化保存、图片视频下载到本地、元数据自动提取为 YAML(YAML:一种人类易读的数据格式,用缩进表示层级) frontmatter(frontmatter/前置元数据:Markdown 文件顶部的 YAML 区域,用 --- 包裹,存文件属性)——让流动的社交媒体信息变成永久可检索的知识资产。
本课与 L1-07 的关系——两课都是 danger- 前缀的 Skill,但用途相反:
| L1-07 Gemini网页抓取 | L1-08 推文转Markdown | |
|---|---|---|
| CDP 方向 | 写入(往网页发 prompt) | 读取(从网页抓数据) |
| 数据粒度 | AI 生成的新内容(不可控) | 已有结构化数据(可控) |
| Consent 设计 | 每次使用显示风险+同意时间 | consent.json 持久记录 |
| 核心设计挑战 | 认证管理(浏览器 Profile) | 输出结构设计(自包含目录) |
🔑 核心秘诀:L1-08 有四个独立的设计亮点可以推广——1) Consent Check 的持久化变体(consent.json vs 每次弹窗);2) 三态设计模式(ask / always / never)的跨课程复用——验证了好的设计模式不限于一个 Skill;3) 正列表边界设计——列出支持什么比列出不支持什么更简洁;4) 自包含输出目录——Markdown + 本地媒体 = 完整可移动的数据包。
⚠️ 避坑指南:SKILL.md 里必须明确列举支持的 URL 格式——如果只写「支持 X/Twitter 链接」,AI 可能把用户主页链接、搜索页面链接都往里塞,然后报错。正列表(列出支持什么)= 划定边界(其他都不支持)。
2. Consent Check 设计详解 —— danger Skill 的同意机制变体

2.1 与 L1-07 的区别:每次提醒 vs 持久记录

L1-07(Gemini 网页抓取)的 Consent Check 设计是「每次使用都显示风险提示 + 上次同意时间」——让用户永远记得这是非官方接口。
L1-08(推文转 Markdown)采取了不同的策略——consent.json 持久记录。为什么不同?
L1-07 的场景:用户每次主动让 AI 去 Gemini 网页生成内容
→ 「每次提醒」合理:用户在每次使用前都需要意识到风险
L1-08 的场景:用户批量处理推文(可能一次抓 20 条)
→ 「每次提醒」不合理:用户第一次已经了解了风险,后面 19 次弹窗是噪音
→ 「持久记录」合理:同意一次,记录在文件里,后续静默通过
🔑 设计要点:同是 Danger Skill,Consent Check 的交互频率应该匹配使用场景。交互频率高 → 每次提醒合理;交互频率低(批量) → 持久记录合理。没有绝对正确的设计,只有匹配场景的设计。
2.2 consent.json 的完整流程

首次使用:
Step 1: 检查 consent 文件
→ macOS: ~/Library/Application Support/baoyu-skills/x-to-markdown/consent.json
→ Linux: ~/.local/share/baoyu-skills/x-to-markdown/consent.json
→ 不存在 → 进入 Step 3
Step 3: 展示免责声明
DISCLAIMER
此工具使用的是逆向工程 X API,非官方 API。
风险:
- X 改变 API 后可能中断
- 无保障无支持
- 可能导致账号受限
- 使用风险自负
接受条款并继续?
Step 4: 用户选择
→ "Yes, I accept" → 创建 consent.json → 记录时间戳和版本 → 继续
→ "No, I decline" → 停止执行
后续使用:
Step 2: consent.json 存在且 accepted=true 且 disclaimerVersion匹配
→ 打印简短警告 + 上次同意时间 → 静默继续
Warning: Using reverse-engineered X API. Accepted on: 2026-05-01T10:30:00Z
2.3 disclaimerVersion:Consent 版本控制

consent.json 中有一个巧妙的设计——disclaimerVersion 字段:
{
"version": 1,
"accepted": true,
"acceptedAt": "2026-05-01T10:30:00Z",
"disclaimerVersion": "1.0"
}
它的作用:如果将来免责声明的措辞或风险描述有重大更新(比如逆向 API 的法律风险变化),Skill 作者可以更新 disclaimerVersion 到 2.0,旧的 1.0 就不匹配了——用户会被重新提示查看新的免责声明。
🔑 设计要点:
disclaimerVersion解决的是「免责声明不是一成不变的」问题。如果风险条款变了但用户用的是旧版本的同意记录,那同意就失效了。版本号 = 让同意记录的时效性可控。
2.4 两个 danger Skill 的 Consent 设计对比

| L1-07 Gemini 网页 | L1-08 推文转 Markdown | |
|---|---|---|
| 同意存储 | consent.json(项目目录) | consent.json(系统应用数据目录) |
| 提醒频率 | 每次使用都显示 | 仅首次(后续打印简短提示) |
| 版本控制 | 无 | disclaimerVersion 字段 |
| 设计理由 | 生成操作风险更高,需持续提醒 | 批量提取场景,重复弹窗是噪音 |
| 共同点 | BLOCKING — 不同意不能继续 | BLOCKING — 不同意不能继续 |
🔑 核心洞察:两个 Skill 的 Consent Check 都遵循 Danger Skill 四条原则(风险前置、显式同意、替代方案、透明运行),但交互频率的调校不同。这说明四条原则是「宪法」,具体实现是「法律」——宪法不变,法律可以按情况调整。
3. 偏好管理详解 —— 三态设计模式的跨 Skill 复用

3.1 First-Time Setup:BLOCKING 的三连问

baoyu-danger-x-to-markdown 的 EXTEND.md 首次设置是一个精心设计的交互流程——三个问题一次问完(不是分三次弹窗):
AskUserQuestion(一次调用,三个问题):
Question 1 — 媒体下载策略
header: "Media"
question: "推文中的图片和视频怎么处理?"
options:
- "每次都问我(推荐)" → download_media: ask
- "总是下载" → download_media: 1
- "从不下载" → download_media: 0
Question 2 — 输出目录
header: "Output"
question: "默认输出到哪个目录?"
options:
- "x-to-markdown(推荐)" → 输出到 ./x-to-markdown/{username}/{tweet-id}.md
- "其他..." → 用户自定义路径
Question 3 — 偏好存储位置
header: "Save"
question: "偏好设置存哪里?"
options:
- "用户级(推荐)" → ~/.baoyu-skills/(所有项目共用)
- "项目级" → .baoyu-skills/(当前项目专用)
🔑 设计要点:三个问题一次性抛出比分三次弹窗好。分三次每次都要打断用户——「刚设置完媒体,又弹出输出目录,又弹出存储位置」——用户会觉得这个 Skill 很烦。一次问完三个问题,交互次数从 3 降为 1。
3.2 三态设计:ask / always / never

这是本课最重要的设计模式——它和 L1-02 的图片压缩策略完全相同:
L1-02(图片压缩)的三态:
→ 每次都问我是否压缩
→ 总是压缩到 1920px
→ 从不压缩
L1-08(推文转 Markdown)的三态:
→ ask:每次推文保存后问「要不要下载媒体?」
→ 1 (always):总是下载图片和视频到本地
→ 0 (never):从不下载,保持远程 URL
| 状态 | 存储值 | 含义 | 适合谁 |
|---|---|---|---|
ask | ask | 每次转换后提示用户选择 | 不确定要本地化还是要省空间 |
always | 1 | 静默下载所有媒体 | 需要离线阅读 + 永久保存 |
never | 0 | 保持远程 URL | 只需要文字,不关心图片 |
🔑 核心洞察:L1-08 的三态设计与 L1-02 完全相同——这不是巧合,这是设计模式的复用。好的 Skill 设计模式不局限于一个特定 Skill——「让用户在每次都问 / 总是 / 从不之间选择」是处理任何可选下载/处理操作的通用模式。这就是为什么我们学 Skill 的核心不是「学会这一个」,而是「学会这一类」。
3.3 ask-each-time 的完整工作流

当 download_media 设为 ask(默认值)时,媒体下载遵循以下流程:
Step 1: 先运行脚本(不带 --download-media)
→ 推文内容保存为 Markdown(图片/视频链接仍是远程 URL)
→ 为什么不直接带 --download-media?
→ 因为可能这推文根本没有媒体——先保存看看有没有再说
Step 2: 检查 Markdown 文件中是否有远程媒体 URL
→ 扫描 和视频链接
→ 没有媒体?→ 完成,不需要问用户
→ 有媒体?→ 进入 Step 3
Step 3: AskUserQuestion
header: "Media"
question: "下载 N 个图片/视频到本地?"
→ "是" → Step 4
→ "否" → 完成(保留远程 URL)
Step 4: 再次运行脚本(带 --download-media)
→ 下载媒体到 imgs/ 和 videos/ 目录
→ 重写 Markdown 中的链接为本地相对路径
→ 覆盖之前的 Markdown 文件
🔑 设计要点:先不带 flag 运行再检查,比直接带 flag 运行更聪明——因为很多推文根本没有任何媒体文件。如果用户设了
ask,但每次都直接弹窗「要不要下载?」(即使没东西可下载),用户会觉得这个 Skill 很蠢。检查有没有东西可下载 → 有东西才问。
4. 输出结构设计 —— 自包含目录

4.1 目录结构

baoyu-danger-x-to-markdown 的输出不是单个 Markdown 文件,而是一个自包含目录:
x-to-markdown/
└── {username}/ ← 按用户组织
└── {tweet-id}/ ← 每条推文独立目录
├── {content-slug}.md ← 推文正文(Markdown)
├── imgs/ ← 下载的图片
│ ├── photo1.jpg
│ └── photo2.png
└── videos/ ← 下载的视频
└── clip1.mp4
4.2 为什么是自包含目录?

方案 A:Markdown 文件 + 远程 URL
优点:简单,不占磁盘空间
缺点:推文删除 → 图片没了;离线看不了;迁移文件夹时链接全失效
方案 B:自包含目录(Markdown + imgs/ + videos/)
优点:
→ 推文被删了,本地依然有完整备份
→ 离线可读
→ 整个目录可以移动到任何地方——图片不会丢失
→ Obsidian 可以直接预览本地图片 ![[imgs/photo1.jpg]]
缺点:占磁盘空间(但图片通常不大)
🔑 设计要点:自包含目录的设计哲学是「数据独立性」——不依赖任何外部资源(远程 URL),整个数据包可以独立存在。这是信息归档 Skill 的核心设计原则:你保存的不只是一个链接,而是一段完整的历史记录。
4.3 YAML Frontmatter 的结构化元数据

每条推文转 Markdown 后,自动提取元数据:
---
url: "https://x.com/user/status/123"
author: "Name (@username)"
tweetCount: 3 # 推文线程的推文数
coverImage: "https://pbs.twimg.com/media/example.jpg"
---
这些元数据让 Obsidian 的 Dataview 可以直接查询——比如「显示所有 @某人 的推文」。
5. 认证管理 —— 两种方式适用不同场景

baoyu-danger-x-to-markdown 提供两种认证方式:
| 方式 | 怎么做 | 适合场景 | 优缺点 |
|---|---|---|---|
| 环境变量 | 设置 X_AUTH_TOKEN 和 X_CT0 | CI/自动化批量抓取 | ✅ 无浏览器交互 ❌ 需要手动获取 token |
| Chrome 浏览器登录 | 利用浏览器的 X/Twitter 登录缓存 | 个人手动使用 | ✅ 无需管理 token ❌ 依赖浏览器 |
🔑 设计要点:提供两种认证方式不是为了「多一个选择」,而是为了覆盖两种完全不同的用户场景——自动化 vs 手动。这是 danger Skill 认证设计的灵活度体现(也是 L1-07 浏览器 Profile 方案的变形——同样利用浏览器已有登录状态)。
6. 正列表边界设计 —— 划定 Skill 的能力圈

6.1 什么是正列表?

baoyu-danger-x-to-markdown 在 SKILL.md 中明确列出了支持的 URL 格式:
Supported URLs
- https://x.com//status/
- https://twitter.com//status/
- https://x.com/i/article/
这三行看似简单,实则是一个精妙的设计决策——正列表(列出支持什么)= 同时划定边界(不支持其他的)。
6.2 为什么用正列表而不是负列表?

正列表(推荐):
✓ 支持的 URL:
- x.com/<user>/status/<id> (推文)
- twitter.com/<user>/status/<id> (推文)
- x.com/i/article/<id> (X 文章)
→ 隐含规则:列表中没提到的都不支持
→ 3 行代码,边界清晰
负列表(不推荐):
✗ 不支持的 URL:
- x.com/<user> (用户主页)
- x.com/search?q=... (搜索结果)
- x.com/settings/... (设置页面)
- x.com/messages/... (私信)
- x.com/explore/... (探索页面)
- ... (永远列不完)
→ 无穷无尽,永远有漏网之鱼
🔑 核心原则:正列表说「我只支持这三样」——简洁、明确、无法误解。负列表说「我不支持这些」——但总有你没列到的。在 Skill 设计中,用正列表定义边界永远比负列表更可靠。
6.3 正列表作为通用设计模式

可以推广到任何需要「划定能力边界」的场景:
- API Skill:支持的 endpoint 列表
- 文件处理 Skill:支持的文件格式列表
- 平台适配 Skill:支持的平台列表
- 格式转换 Skill:支持的输入格式 → 输出格式映射表
7. 结构拆解:特定平台数据提取型模板

从 L1-08 提取「特定平台数据提取型」Skill 的通用模板——融合了 danger 模式 + 三态设计 + 自包含输出。
特定平台数据提取型 Skill 模板
Layer 1: Consent Check(如果是 danger 类型)
- consent.json 持久记录(批量场景)
- disclaimerVersion 版本控制(免责条款更新时重新提示)
- 未同意 → BLOCKING,不同意不能继续
Layer 2: 偏好管理(EXTEND.md)
- First-Time Setup BLOCKING:三个关键问题一次问完
- 媒体/数据下载策略(三态:ask/always/never)
- 输出目录偏好
- 偏好存储位置(用户级 vs 项目级)
- 设置后自动复用,用户无需重复配置
Layer 3: 能力声明(正列表)
- 明确列出支持的 URL/输入格式
- 不在列表中的 → 不支持(无需说明为什么不支持)
- 3-5 个条目足够,多了说明 Skill 职责太宽
Layer 4: 输出结构(自包含)
- 数据单元独立目录
- 媒体文件本地化(图片/视频下载到同目录)
- YAML frontmatter 存储结构化元数据
- 整个目录可独立移动、搜索、备份
Layer 5: 认证管理(多方式)
- 环境变量:自动化场景
- 浏览器登录缓存:手动场景
- 两种方式覆盖不同用户类型
本课与前几课的模式对比:
| 课程 | 架构 | Consent | 下载设计 | 输出 |
|---|---|---|---|---|
| L1-02 图片压缩 | 工具型 | 不需要 | 三态(ask/always/never) | 单文件 |
| L1-07 Gemini 网页 | CDP桥接型 | 每次提醒 | — | 文本 |
| L1-08(本课) | 数据提取型 | 持久记录 | 三态(复用 L1-02) | 自包含目录 |
8. 电商案例:海外竞品品牌Twitter/X情报——10个品牌每日动态自动归档

🛒 实战案例:某消费电子跨境品牌做欧美市场,市场部每天要在Twitter/X上追踪10个海外竞品、5个行业KOL、3个科技媒体的动态。以前是手动截图→粘贴到飞书文档→下班前整理汇总——一天花2.5小时。更关键的痛点是:竞品3周前发的一条"正在测试XX功能"的推文被删了,但团队当时没截图存档,现在产品会上想不起来了。
用 baoyu-danger-x-to-markdown 搭建情报自动归档系统:
Step 1:目标筛选
- 从10个竞品、5个KOL、3个科技媒体的每日推文中,选出值得归档的内容
- 筛选标准:新品发布/预告、产品功能更新、定价变动、用户投诉(负面信号也是情报——竞品的差评就是你的卖点)
Step 2:批量抓取 + 结构化存档
- Consent Check:首次使用时团队负责人点「Yes, I accept」→ consent.json 记录
- EXTEND.md 设置:
download_media: 1(总是下载——推文截图不能依赖远程链接)- 每条推文自动生成YAML frontmatter(品牌、作者、时间、原始链接)
- 存入
海外情报/{品牌}/{YYYY-MM-DD}/目录,按品牌+日期层级归档Step 3:每周竞品周报
- 周五下午搜索
date:[本周日期范围]→ 所有本周竞品动态10分钟汇总- Dataview查询所有
brand: "@某竞品"的文件 → 按时间排列,一键生成周报草稿效果:
情报收集:2.5小时/天 → 20分钟/天(减少87%)
推文被删后本地仍有完整备份——不再有"记得发过但找不到了"的情况
竞品周报从"凭记忆写"变成"从归档文件提取"——每条信息都可追溯原始出处
3个月积累800+条归档推文,形成可搜索的时序竞品情报库
🔑 启示:社交媒体情报的敌人不是"信息太少"而是"信息来了又走了"。Twitter/X上的竞品动态是流动的——今天看到明天可能就删了。把流动态信息固化为本地结构化文件,你的情报资产才会随时间增值而非蒸发。自包含目录设计让每条推文变成一个完整的数据包——可搜索、可追溯、可移动、可备份。
9. 掌握检验

Q1:baoyu-danger-x-to-markdown 的 Consent Check 与 L1-07(Gemini 网页抓取)有何不同?为什么 L1-08 用 consent.json 持久记录而不是每次弹窗提醒?
Q2:baoyu-danger-x-to-markdown 能处理以下哪类 X/Twitter URL?
- A) 推文、X 文章、推文线程(Thread),还包括用户主页链接
- B) 推文、X 文章、推文线程(Thread),不包括用户主页和搜索页面
- C) X/Twitter 上的所有类型的页面,包括私信和设置页面
- D) 只能处理单条推文,不能处理线程和文章
Q3:媒体下载的三态设计(ask / always / never)与 L1-02 的图片处理策略有何关系?这说明 Skill 设计的什么原则?
Q4:为什么 SKILL.md 中必须用「正列表」明确列举支持的 URL 格式,而不能只写「支持 X/Twitter 链接」?正列表和负列表哪个更好?为什么?
Q5:baoyu-danger-x-to-markdown 的 EXTEND.md 首次设置为什么把三个问题一次问完而不是分三次弹窗?这种「批量交互」设计的优势是什么?
Q6:什么是「自包含目录」设计?它比「Markdown 文件 + 远程 URL」有什么优势?这个设计体现了信息归档的什么原则?
Q7:某消费电子品牌想用 baoyu-danger-x-to-markdown 搭建海外 Twitter 情报收集系统。从 Consent Check 到周报生成,完整流程包括哪些关键步骤?这个系统的核心价值是什么?
10. 答案

点击查看答案
Q1:两个 danger Skill 的 Consent Check 交互频率不同:L1-07(Gemini 网页抓取)每次使用都显示风险提示 + 同意时间——因为用户主动让 AI 去非官方网页生成内容,风险更高,需要持续提醒。L1-08(推文转 Markdown)用 consent.json 持久记录——同意一次后静默通过(只打印简短提示),因为使用场景是批量抓取(可能一次处理 20 条推文),如果每次都弹窗,19 次是噪音。设计原则:交互频率应该匹配使用场景——高频交互场景适合每次提醒,低频/批量场景适合持久记录。同时,L1-08 的 disclaimerVersion 字段提供了「免责声明更新后重新提示」的能力——在持久记录中保留了灵活性。
Q2:B — Skill 的正列表只包含推文(tweet)、X 文章(article)和推文线程(thread)三种类型。列表中没有提到的 URL 格式(如用户主页、搜索结果、设置页面)都不应该用这个 Skill 处理。这种「正列表」设计既告诉 AI 能做什么,也隐式告诉 AI 不能做什么——简洁且无法误解。
Q3:L1-08 的媒体下载三态(ask: 每次问 / 1: 总是下载 / 0: 从不下载)与 L1-02 的图片压缩策略(每次问 / 总是压缩 / 从不压缩)是完全相同的设计模式。这说明好的 Skill 设计模式具有跨课程可复用性——「让用户在每次都问 / 总是 / 从不之间选择」是处理任何可选操作(下载、压缩、格式化、加水印等)的通用模式。学 Skill 的核心不是学会「这一个」,而是学会「这一类」——识别可复用的设计模式并应用到新的场景。
Q4:正列表(列举支持什么)比负列表(列举不支持什么)更好,因为:正列表只有 3 行——简洁明了,AI 一看就知道能力边界;负列表无穷无尽——总有没有列到的格式,AI 仍然可能犯错。正列表的隐含规则是「列表中没有的都不支持」,这比「我列了好多不支持的但可能漏了」要可靠得多。这是 Skill 设计中的「定义能力圈」原则——不是在出错后告诉用户「不支持」,而是在设计阶段就明确边界。
Q5:三个问题一次问完的优势:1) 减少交互次数——从 3 次弹窗降为 1 次,用户不会觉得「这个 Skill 怎么一直问问题」;2) 上下文连续性——用户在同一界面看到所有配置选项,可以比较后一起决定;3) 降低放弃率——分三次弹窗每多一次用户就多一次「算了不设了」的机会。这是「批量交互」设计原则——把多个相关决策合并到一个交互中,减少对用户工作流的打断。
Q6:「自包含目录」是指输出不是单个 Markdown 文件,而是一个包含 Markdown + imgs/ + videos/ 的独立文件夹。优势:1) 推文被删仍有备份——图片已本地化,不依赖远程 URL;2) 离线可读——整个目录移动到无网络环境也能完整阅读;3) 目录可迁移——复制到任何地方图片不丢失;4) Obsidian 兼容——本地图片可直接用 ![[path]] 预览。体现的信息归档原则是「数据独立性」——保存的不只是一个链接,而是一段完整且独立的历史记录。信息资产应该自包含、可迁移、不依赖外部服务的持续存在。
Q7:完整流程五个关键步骤:1) Consent Check——首次使用时获得明确同意,创建 consent.json(团队负责人操作);2) 目标筛选 + 偏好设置——从 10+ 竞品/5 个 KOL/3 个媒体中筛选优质推文链接,EXTEND.md 设置 download_media: 1(总是下载——竞品截图必须本地保存);3) 批量抓取 + 结构化存档——自动生成 YAML frontmatter(作者、时间、链接),存入 海外情报/ 文件夹按日期归档;4) Obsidian 搜索与查询——全文搜索 + Dataview 查询(按作者、日期、关键词),10 分钟完成竞品动态汇总;5) 周报输出——从本地文件库提取一周动态生成竞品周报,每条有可追溯的原始出处。核心价值:信息收集的核心不是「看得多」而是「找得到」——把流动的社交媒体信息固化成结构化本地文件,信息资产随时间增值(可搜索、可追溯、可备份)而非随时间流失(被删除、被刷走、被遗忘)。
(6/7 通过)
11. 延伸阅读
- [[L1-09-Markdown转网页|下一课:Markdown转网页]] — 格式转换经典案例
- [[L1-07-Gemini网页抓取|上一课:Gemini网页版接口]] — 回顾 Danger Skill 四条原则 + CDP 桥接
- [[L1-02-无损图片压缩|L1-02:图片压缩]] — 三态设计的原始出处
- [[L2-11-一键发布到X|L2-11:一键发布到X]] — CDP 发布方向(往 X 发数据,本课是从 X 抓数据)

评论区
共 0 条评论