GEOZ

本文详细介绍了安装方法、核心功能、常见问题排查以及实测数据

2026/9/3
本文详细介绍了安装方法、核心功能、常见问题排查以及实测数据

AIAI Summary (BLUF)

publishing-kit 是一个将技术文章发布流程打包成 Claude Code 技能的开源工具。它能把一份 Markdown 源文件自动转换为 dev.to、AWS Builder Center、Medium 和 LinkedIn 所需的不同格式,并处理封面图生成、表格转图片、数字溯源、预检和自动发布等环节。作者使用该工具发布介绍它自身的文章,实现了彻底的“自举”(dogfooding),并借此发现了工具本身的多个缺陷。本文详细介绍了安装方法、核心功能、常见问题排查以及实测数据。

核心洞察

这篇文章最有意思的点在于,作者为了不再过“四份文件改来改去,最后搞不清哪份才是最新”的日子,写了套发布工具,然后直接拿这套工具来写介绍它的文章。工具拿自己开刀,当场查出五个 bug。这个结果比任何自夸都有说服力,而那些平台文档里查不到的坑,像粘贴时图片全灭、发布后每段带碎断行,全是实测撞出来的。光冲这点,就值得往下读。

长话短说:publishing-kit 把一套完整的发布流程打包成了一个 Claude Code skill。你只要写一个 markdown 文件,它会生成 dev.toAWS Builder CenterMediumLinkedIn 四个平台的版本,做完检查,把有 API 的直接发布出去。这篇文章、封面、四个平台的成品,都由这套工具自己产出,狗粮从头吃到尾。细节放到文末说。

把一篇技术文章发到四个平台,中间要走的流程多到让人意外。每个平台的封面尺寸要求不一样。Medium 的导入器会吃掉表格,得先把表格渲染成图片。AWS 那边的版本不能有 emoji。稿子里每个数字都要确认来自真实运行记录。一篇很长的 markdown 要贴进一个没有 API 的网页编辑器。还要记住文章挂在哪个组织名下。等这些全忙完,四份文件已经各自有了差异,哪份才是最新的,你心里完全没底。

我把这些都打包成了 publishing-kit。一个 Claude Code skill,外加一组小脚本。装好以后,你只需要让 Claude 去发布。

核心结论

  1. publishing-kit 是一个 Claude Code skill(加一组 Python 脚本),安装后可从同一份 Markdown 源文件生成 dev.to、AWS Builder Center、Medium、LinkedIn 四个平台的版本;有 API 的平台直接发布,没有 API 的用 Chrome 自动化操作编辑器。

  2. 工具用本文做了端到端自测:文章、封面和四个平台成品都由 publishing-kit 自己产出,并且从工具自身查出 5 个 bug,包括 make-medium.py 默认图片路径写错、make-cover.py--tile 参数被 argparse 吞掉、check-facts.py127.0.0.1 读成版本号等。

  3. dev.to 的坑是实测出来的:它渲染 Markdown 时保留硬换行,一篇已发布文章里 62 段有 47 段带多余断行;它不托管封面,只按 2.381:1 的比例做代理,一张 1376×768 的封面上下各被裁掉 95px。

  4. Medium 的坑也是实测的:粘贴时会丢弃 data: URI 图片,4 张内嵌图片存活 0 张;改成真实托管 URL 后 4 张全部存活。因此 Medium 版本需要先把表格渲染成 PNG,并把图片 commit 后按 URL 引用。

  5. LinkedIn Posts API 无法创建草稿,创建时唯一接受的状态是 PUBLISHED;AWS Builder Center 和 Medium 没有可用的发布 API,工具通过 Chrome 自动填表完成发布,而不是像 dev.to 那样直接调 API。

它能干什么

skill 教 Claude 完整的发布流程,脚本负责做语言模型不该手工碰的部分。

  • 生成各平台的版本。一份源文件变成四样东西:dev.to 的 markdown、Builder Center 版本(去掉 emoji,追加 AWS 免责声明)、Medium 的 HTML(表格全部渲染成 PNG)、一条 LinkedIn 帖子。对应脚本是 make-builder.pymake-medium.pymake-linkedin.py
  • 封面只做一次。make-cover.py --flow --sizes devto,builder 把发布流程画成示意图,再按各平台要求的几何尺寸出图。文件名由图片自身字节的哈希决定。脚本会告诉你哪些字号在缩到 320px 的信息流卡片里还撑得住。封面真正被人看到的地方就是这个 320px,小字号的图缩到这儿基本糊成一团。
  • 每个数字都要有出处。check-facts.py 从文章里抽出价格、测量值、版本号,跟证据文件做对照,然后报告哪些数字在证据文件里不存在。数字本身对不对它判断不了。哪些是你凭记忆硬写的,它会指给你看。
  • 预检。preflight.py --live 把所有检查跑一遍,没过就非零退出。封面已提交且与 HEAD 一致、几何尺寸正确、front matter 完整、没有硬换行的段落,每一样都要查。最后再把每个已发布 URL 拉回来,跟本地文件逐字节对比。
  • 有 API 的平台直接发。publish-devto.py --create 把 front matter 原样作为请求 payload,标题、标签、封面跟着正文一起走。--org-slug 指定文章进哪个社区频道。不用开浏览器。
  • 没有 API 的编辑器,就用 Chrome 操作。AWS Builder Center 和 Medium 都得靠浏览器,skill 认得路:payload 从 window.name 传进去,两边核对 checksum,粘贴之前先断言页面是空的,粘贴之后数一遍页面上的关键元素确认成功。

工具还把发布第二天才会学到的教训全编码了进去。dev.to 渲染 markdown 时硬换行是开着的,源码按 95 列折行,发布出来每个段落都带着一个多余的断点。dev.to 不托管封面,它只按 2.381:1 的比例做代理,一张 1376x768 的封面上下各被切掉 95px。Medium 粘贴时会丢弃 data: URI 图片,那份自以为自包含的构建发过去,图片一张不剩。LinkedIn 的 Posts API 建不了草稿,创建时唯一接受的状态就是 PUBLISHED

安装

最省事的路径是插件市场:

/plugin marketplace add xbill9/publishing-kit
/plugin install publishing@publishing-kit

想走传统路线也行。clone 下来,建个软链:

git clone https://github.com/xbill9/publishing-kit
ln -s "$PWD/publishing-kit/skills/publishing" ~/.claude/skills/publishing

依赖很少。Python 3 加 Pillow,封面和表格渲染要用。dev.to 的 API key 放在 ~/.devto.key。另外需要有一个公开仓库来放文章目录,封面和 Medium 图片在页面渲染时按 URL 抓取,不推上去就是裂图。

大部分时候你不会自己跑这些脚本,跑的是 Claude,SKILL.md 会把位置告诉它。想手动跑一个的时候,路径按安装方式会不一样,别记,直接问。skill-footprint.py --where 会打印 skill 目录。clone 方式装在 skills/publishing,市场安装则落在带版本号的缓存路径下。你写下来的任何一条调用命令,升一次级就会失效。

版本号这件事,等你打算改 skill 本身时会咬你一口。市场安装拿到的是快照,claude plugin update 比较的是版本字符串。同一个版本号下改了文件,内容不会进入你的会话。迭代阶段就乖乖用软链。

实际用起来长什么样

装好之后,和 Claude Code 的对话大概长这样:

把这篇文章的 benchmark 写出来,发到 dev.to 的 aws-builders 频道。

Claude 先写源文章,按两种几何尺寸生成封面,对着你的运行产物逐个核实数字,跑一遍预检,把失败的地方报给你。全部通过后,它以草稿形式发上去,把链接交回来。你再跟一句:

把 Medium 和 Builder Center 的版本也做了。

它会从源文件推导两个版本,表格渲染成图片,打开 Chrome,把编辑器填好。每个平台都停在草稿状态,链接递回给你。发布这最后一步,留给你自己按。

发布翻车了怎么排查

这块是我最意外的,skill 大部分的价值都堆在了这里。

页面和本地文件长得不一样。别坐那儿推理自己到底传了什么,直接把线上实际返回的东西抓回来对比:

python3 ../../skills/publishing/scripts/check-links.py article.md
devto-publishing-kit.md  (branch URLs)
  ok    cover.77acc7c4.jpg: HTTP 200, bytes match disk
  ok    img/cover.77acc7c4.jpg: HTTP 200, bytes match disk
  ok    img/devto-publishing-kit-table-1.png: HTTP 200, bytes match disk

FAIL 大多是“HTTP 200 但服务端字节和磁盘不一致”,常见于图片在 commit 之后被重新生成过。工具里其余检查只关心本地状态,文件在不在、有没有被 git 跟踪。这些检查可以全部通过,线上 URL 照样吐着别的东西。

段落碎得没法看。check-article.py 会把带硬换行的段落报出来,附上第一处断行的行号。publish-devto.py 在发出去前会把断行并回整行。仓库里的副本按 95 列折行方便阅读,线上页面干干净净,没有那些多余的换行符。

Medium 图片不见了。八成正贴了 -embed.html。改贴 -hosted.html,那份引用的是 Medium 会重新托管的真实 URL。图片记得先 commit。

某个数字背后没有产物支撑。check-facts.py 会直接点名。没被追踪的数字只有三种情形:测过但没存档、属于推算但没标成推算、凭记忆硬写。出错的永远是第三种。

内部结构

一个 SKILL.md,每个平台一份记录怪癖的参考文件,再加一个任务一个脚本。什么时候跑哪个由 skill 决定,脚本可以独立运行,跑完会打印自己做了什么。

整套工具里最值得抄走的是 references/house-style.md。语气、段落顺序、开头结尾怎么写,全部收在这个文件里,SKILL.md 和脚本都不依赖它。换掉这个文件,这套工具写出来的就是另一个人的文章。

skill-footprint.py 量的是 skill 自己的体积和 token 开销,顺便生成本文这类文章里附带的成本表和封面页脚。会随每次 commit 变化的数字,不该躺在需要你记得手动改的正文里。

拿自己开刀:本文和它的封面

本文所有产物都出自这套工具。封面由 make-cover.py 渲染,Builder Center 版本由 make-builder.py 派生,Medium 构建走 make-medium.py,dev.to 草稿是 publish-devto.py 发出去的。

封面上的两个数字是真的,而且都是拿工具量工具得来的:

现象 实测结果
dev.to 硬换行段落 一篇已发布文章,62 段里有 47 段带着多余的断行
Medium data URI 图片 4 张存活 0 张。换真实 URL 之后,4 张全活

第一个问题让我的文章难受了好几个月。第二个第一次撞上时,整篇返工。这两个坑在两家平台的文档里都查不到,现在它们都进了检查项。

自测还从工具自身揪出五个 bug:

  • make-medium.py 把另一个项目的仓库写死成了默认图片路径。
  • check-article.py 对一张已跟踪但重新生成过的封面放了行。
  • make-cover.py--tile 参数以连字符开头,被 argparse 吞了值。
  • check-facts.py127.0.0.1 读成了版本号。
  • unwrap() 跳过块引用,本文的 TL;DR 被发成了五行独立文字。本该拦住这个问题的检查同样跳过块引用,两边一致认为没问题。

链接

欢迎提 issue 和 PR。这是第三方社区项目,和 dev.to、Medium、AWS、LinkedIn 都没有关联。文中的平台行为实测于 2026 年 8 月 31 日,真要用之前,自己再验一遍。

常见问题(FAQ)

publishing-kit是什么?它能自动发布到哪些平台?

publishing-kit是一个开源工具,将技术文章的发布流程打包成Claude Code技能。它能把一份Markdown源文件自动转换成dev.to、AWS Builder Center、Medium和LinkedIn等平台所需的不同格式,并实现封面生成、表格转图片、数字溯源和预检自动发布。

如何安装并使用publishing-kit?

可通过插件市场命令“/plugin marketplace add xbill9/publishing-kit”安装,或者用git clone和软链方式部署。日常使用时,由Claude Code的skill自动处理,无需手动跑脚本;若需查看目录位置可运行skill-footprint.py。

publishing-kit发布文章时遇到问题如何排查?

已实测的排查方法包括:用check-links.py对比线上与本地字节,段落碎行用check-article.py检测,Medium图片丢失时改用-hosted.html引用,数字无法溯源则用check-facts.py找出凭记忆写出的数据。

Roger深圳
本文由 Roger 审核,最后更新于 2026年9月3日
联系编辑 →
← 返回文章列表
分享到:微博

版权与免责声明:本文仅用于信息分享与交流,不构成任何形式的法律、投资、医疗或其他专业建议,也不构成对任何结果的承诺或保证。

文中提及的商标、品牌、Logo、产品名称及相关图片/素材,其权利归各自合法权利人所有。本站内容可能基于公开资料整理,亦可能使用 AI 辅助生成或润色;我们尽力确保准确与合规,但不保证完整性、时效性与适用性,请读者自行甄别并以官方信息为准。

若本文内容或素材涉嫌侵权、隐私不当或存在错误,请相关权利人/当事人联系本站,我们将及时核实并采取删除、修正或下架等处理措施。也请勿在评论或联系信息中提交身份证号、手机号、住址等个人敏感信息。