Install
openclaw skills install @oracis/multiplatform-publish-core把一份内容分发到多个内容平台时的编排层:落盘清单状态机、幂等判据、 批量串行约束、以及三条质量门禁(回读校验、禁| tail 截断、平台合规预检)。 当用户说「发到几个平台」「批量发」「一条都没发成功但脚本报成功」 「重复发了」「草稿箱对不上」「点了保存但远端没变」「内容被判违规下架」 「多平台发布状态怎么对账」时使用。 ⚠ 只管编排,不管各平台的具体接口 —— 平台适配见 cn-social-platform-adapters。
openclaw skills install @oracis/multiplatform-publish-core🚧 骨架状态(2026-10-01):本文已写入三条经过实战验证的门禁规则 (回读校验、批次串行、品类匹配),但平台适配层与完整实现尚未补齐。 见文末「待补」。
多平台分发真正难的不是「调发一篇文章」,而是重复、遗漏、与「以为成功其实没成」:
| 症状 | 真实原因 |
|---|---|
| 脚本报「成功 37 条」,远端一条没变 | 判成功只看「按钮点中了」,没有回读 |
| 重跑一遍,37 条全部重发 | 没先 sync 既有状态,幂等判据缺失 |
| 跑 19 分钟一条没删 | 目标列表分页渲染,只处理了首屏 |
| 内容被判违规、笔记被下架 | 发布前没有平台合规预检 |
这四类都不是平台 API 的问题,是编排层缺门禁。本技能只解决这四类。
pending → building → draft_saved → published
↑ │ │
└─────────┴────────────┘(失败回到 pending,attempt+1)
failed(重试耗尽 / 需人工介入)
| 状态 | 含义 | 是否算完成 |
|---|---|---|
pending | 排队中 | ❌ |
building | 正在写 | ❌ 崩在这里必须能续跑 |
draft_saved | 远端已确认存草稿 | ✅ |
published | 正式发表 | ✅ |
failed | 失败 | ❌ 需 retry |
⚠ 关键约束
building 不算完成 —— 进程崩在building 时,重跑必须能接着走,
否则用户永远看不到那条。设计成幂等重入而不是从头再来。tmp + os.replace 原子替换 —— 状态文件被截断等于丢记录,
用户会对着一个「少一条」的清单干瞪眼。out/) —— 远端只存在草稿箱的平台上,
本地清单是唯一事实来源。丢了只能人肉翻四个平台草稿箱重建。
⚠ 用 .gitignore 排除机器产物时,务必确认清单文件没被一起排除。已完成 ⟺ 清单里状态已完成 OR 平台侧状态文件记录已完成
两者都查,任一为已完成就跳过
⚠ 首次使用必须先 sync,把既有记录灌进清单。否则清单是空的,
37 条会被当成全新内容全部重发一遍。
反向也要做:平台状态文件里有、清单里没有的(比如清单被覆盖过), 要回写进清单 —— 否则会重复发。
这是本技能最重要的一条。
判「保存成功」不能只看「保存按钮点中了」。
实战(2026-09-30):某平台的
publish_one点完「保存为草稿」就return True,日志打印「成功」。实测远端正文一字未变 —— 整轮 37 条全部「成功」,但用户看到的还是旧排版。 根因:编辑器内容没提交到内部文档状态,点按钮只是触发了保存动作, 而保存的是「上一次的状态」。
点保存
↓
回读远端(列表接口 / 重新打开草稿 / API 拉详情)
↓
比对关键内容(正文纯文本 / summary 前缀 / mtime)
↓
一致 → 才写 draft_saved
不一致 → 判失败,可重试
校验用纯文本比,别比字节 —— 本地与远端的 HTML 结构往往不同
(远程编辑器会重排标签、补 、删空属性),字节比对永远不一致。
⚠ 别拿 warn 当失败结论:刷新类操作常报「超时 / 连接断开」但实际成功。 必须回读核实,而不是看日志级别。
⚠ 回读要挑对通道。小红书草稿是浏览器本地的,列表 UI 只有标题+时间,
拿它回读等于只验了标题 —— 正文和图片数量根本没验。要验就得进 IndexedDB
(见 cn-social-platform-adapters)。
⚠ 回读的匹配键要用稳定标识,别用标题。标题会随数据修正而变, 按标题反查会「一个都匹配不上」,而匹配失败常被当成「无需更新」—— 这会伪造出一份「全部正常」的结论。用篇号/固定 id 这类不会变的标识。
| tail -N批处理脚本输出是块缓冲的,| tail -N 会一直攒着不发,
表现为「跑19 分钟一条输出都没有」,用户以为卡死。
❌ python publish.py --all | tail -20 # 全程零输出
✅ python -u publish.py --all # -u 行缓冲,逐条可见
✅ python -u publish.py --all | tee run.log # 既实时可见又留档
配套要求:脚本自己要 flush=True 逐条打印 + 打印单条/累计耗时。
这个坑踩过 3 次 —— 用户看不到进度就会打断你。
不同平台的禁售类目差别极大,同一段内容 A 平台过、B 平台直接下架。
发布前必须过一遍目标平台的类目红线,见 cn-social-platform-adapters
的「合规预检」章节。
通用红线(跨平台都适用的)
| 红线 | 典型触发词 |
|---|---|
| 引流 / 导流 | 微信号、QQ、加群、私信、评论区引导、联系方式 |
| 灰产工具 | 破解、刷量、批量注册、接码、代实名、虚拟号 |
| 规避平台规则 | 「绕过风控」「免实名」「不需验证」 |
| 非正规服务 | 账号租售、接码平台、外挂、脚本批量 |
⚠ 红线是「语义级」的,不是关键词级。正文里写「面向 XX 群体提供服务」 被判成导流,即使没有任何联系方式 —— 因为它暗示了「你可以来找我」。 改文案要改整段的意图表达,不是替换个别词。
实战(2026-10-01):一篇案例被小红书判违规,但同一份数据还要发 公众号/头条/B站。直接改源数据会牵连另外三个平台 —— 公众号那35 篇 得重建 HTML 并重跑 refresh(每条 4–5 分钟,全量要几小时)。
正确做法:加平台专属覆盖层。
data/<platform>_note_overrides.json ← 覆盖表(只存差异,不是全量拷贝)
↓ build_<platform>() 里读,优先级高于规则生成
out/<platform>/<case>/note.json+卡片
覆盖范围要包含所有会被渲染出去的文字:标题、正文、标签、 以及图片卡片上的每一个字段。
⚠ 只改正文是错的 —— 卡片是把同一批文案印到图片上, 不覆盖卡片等于把违规文案重新印了一遍。图片违规和文本违规是分开判的。
判「这个平台真的干净了」的测试:把最终产物(标题+正文+卡片文字) 拼起来跑禁售词表,要求零命中。卡片文字要单独抽出来参与检查 —— 只查正文会漏掉图片上的雷。
skip = set(published) | set(drafted) | {"某个案例"} 这种写法看起来无害,
实际后果是那个案例永久无法再被队列选中,只能手动 --case 发。
临时跳过应该是「临时改代码 + 记得改回来」,而不是留一个永久陷阱。
测试要钉死这条不变量:待发判定只允许看那两个台账。
实战(2026-10-01):用户要发一篇开源工具推广,被塞进了 「海外小生意案例」的骨架。用户原话:「1,2,3,4 这几个都是为了拆解海外 文章所需要的,但这个是 free llm 的推广和使用,不需要这些」。
那 1/2/3/4 是案例骨架的栏目:钱从哪来/ 它到底做到多大 / 能搬走的部分 / 一个人能不能做。对一篇推广工具的文章,它们全是错的:
| 案例栏目 | 用在工具推广上会怎样 |
|---|---|
| 钱从哪来 | 工具不收费 → 逼你编一段「其实它不赚钱」 |
| 它到底做到多大 | 读者去找收入/客户数 → 找不到,文章就软了 |
| 能搬走的部分 | 读者不是来抄生意��,是来用这个工具的 |
| 一个人能不能做 | 商业可行性评分,与推广无关 |
根因不是文案写不好,是品类不匹配。 改措辞救不回来 —— 「它不赚钱」这句话不管怎么润色都还是「钱从哪来」这一栏。
content_kind 让渲染层分流data/<id>.json里声明 content_kind: "tool"
↓
build_sections() 按 kind 走不同骨架
"case" → 它是干什么的 / 钱从哪来 / 做到多大 / 为什么能成 / 能搬走什么
"tool" → 它是什么 / 怎么用 / 实测结果 / 适合谁 / 它不做什么 / 判断
配套原则:
content_kind == "tool",既有 39 条不填该字段,渲染结果逐字节不变
(用 git diff --stat -- out/ 验证,为空才算合格)。how_to_use / who_is_it_for /
limits,不要复用 how_it_makes_money / playbook。
复用等于把新内容塞进旧栏目,骨架分流就白做了。series_tag)、页脚署名(series_footer)、
栏目简介(footer_text)都要能覆盖。CASE_ONLY = ["钱从哪来", "它到底做到多大", "能搬走的部分",
"一个人能不能做", "能不能搬回国内"]
SERIES = ["拆解海外", "万物解释者", "CASE STUDY", "案例库"]
# 对四个平台的**正文层产物**逐个扫,命中即失败
⚠ 要扫「所有会被渲染出去的文字」,包括封面/卡片上的字。
CASE STUDY · 海外小生意 这类版式文案常被硬编码在模板里,
按字段取的覆盖表碰不到它 —— 得单独给版式字段开覆盖口。
图片违规与文本违规是分开判的,只改正文等于把违规文案重新印一遍。
⚠ 并发抢同一个浏览器/CDP 会批量报错(ConnectionAborted 10053 /
TimeoutError),甚至挤掉已经打开的标签页。实测批量发版串行 70s/条,
并发反而全部失败。
✅ 单线程串行,逐条处理
❌ 线程池 / asyncio 并发调同一CDP
单条也要有界:失败重试有上限,超了就归failed 等人工,
不要无限重试卡住整批。
发现「数量对不上」时,先对账再操作。按标题反查、把差异分成 5 类:
| 类别 | 含义 | 处置 |
|---|---|---|
| 远端有 / 台账无 | 之前发了没记 | 回写台账,别重发 |
| 台账有 / 远端无 | 记了但没发 | 才需要补发 |
| 两边都有 | 正常 | 跳过 |
| 远端重复 | 发了多次 | 按标题去重,保留信息更全的 |
| 孤儿草稿 | 远端有、内容不在本次范围 | 人工确认 |
实战(2026-10-01):对账发现「台账多 2 条」,看着像要补发, 细查发现是
purge删掉的记录没从台账移除 —— 若是直接补发就会重复发布。 ⚠mark_drafted类台账只增不减,对账时必须反向清理 (正解 = 台账 ∩ 远端,只留远端确实存在的)。
平台接口能力(能不能 API 直发、有没有删除接口)必须先核实再动手, 不要凭印象回答。核实途径:官方开放平台文档页 → 实际草稿列表回读 → 网络资料交叉验证。
实战:某平台文档站已把内容发布 API 重定向到另一套开放平台, 网页搜索出来的多篇「如何用 API 发文」文章是 AI 生成的幻觉 (接口路径、示例代码全为空)。不能作为技术依据。
sync / queue / run / status / retry / verify 六个命令cn-social-platform-adapters 的适配器接口定义--strict 直接拒绝出图)check_content_kind.py --id X --kind tool)content_kind 支持更多形态(目前只有 case 默认 / tool 两种)cn-social-platform-adapters —— 各平台具体接口、认证门槛、
编辑器陷阱、合规红线明细(待建)web-console-cdp-upload —— 通用 CDP 能力(复用登录态、给 file input 塞文件、
富文本编辑器 CSS 实测)