从本地 AI 到 Typecho 草稿箱:DraftPublisher 插件的设计与实现
之前使用过一些微信公众号的skills,可以在本地使唤codex攥写文章并发布到微信公众号草稿箱,于是想了想,我不是有个Blog吗,如果也能同样操作,可以省事一些,在解决了某些技术难题后,只能让其总结形成文章,并发布到blog的草稿箱多好,于是,本插件就诞生了。DraftPublisher 是为 Typecho 设计的草稿写入插件:它接收经过鉴权的 JSON 请求,并且只创建 Markdown 草稿。
目标与边界
插件的目标很明确:让 Codex 等本地 AI 工具能够把已经生成并经过检查的文章写入 Typecho 草稿箱。接口不会发布公开文章,不使用后台管理员 Cookie,也不接受 HTML 正文。请求成功后,只会得到一条 post_draft 记录,仍需在 Typecho 后台完成审核和发布。
接口使用以下形式:
POST /index.php/action/draftpublisher正文采用 JSON,核心字段包括 title、text、format、标签和分类 ID。format 被固定为 markdown,使文章从本地文件到 Typecho 编辑器的表现一致。
安全模型
草稿写入接口仍然拥有内容创建能力,因此安全配置不能只是一个静态 Token。DraftPublisher 将多项限制组合使用:
- 接口默认关闭,且默认只接受
127.0.0.1和::1的本机请求。 - 每次请求必须携带 Bearer Token,服务端使用恒定时间比较来验证它。
- 远程模式需要显式开启,并要求配置来源 CIDR 白名单;默认要求 HTTPS。
- 只有列入“受信任反向代理”的地址才可以提供
X-Forwarded-For与X-Forwarded-Proto,避免客户端伪造这些头部绕过来源和 TLS 判断。 - 接口限制请求体大小,并按来源 IP 限流,降低误用和资源耗尽风险。
Token 应当只保存在本地环境变量、系统凭据管理工具或 CI Secret 中,不应写入文章、代码仓库、浏览器前端或日志。
为什么需要幂等键
网络请求的失败并不总能说明服务端没有执行成功。客户端可能在文章已写入后才失去连接;如果随后用新的请求直接重试,就会产生重复草稿。
因此,DraftPublisher 要求每次逻辑发布都携带 Idempotency-Key。首次请求会预留该 Key 并创建草稿;使用同一个 Key 重发相同正文时,接口返回原草稿 ID,而不会再次创建文章。如果同一个 Key 对应不同内容,则返回冲突响应。发布脚本会自动生成 UUID,并在网络错误时输出该 Key,供调用者安全重试。
代码和 JSON 的关系
Markdown 正文中可以包含 PHP、Python、Shell、JSON、SQL 或任意代码块。代码围栏、换行、反引号、花括号和方括号本身不会破坏接口,因为它们都位于 JSON 的 text 字符串中。
真正容易出错的是手工拼接 JSON:双引号、反斜杠和字符串内换行需要正确转义。随插件提供的本地发布器直接读取 UTF-8 Markdown 文件,再用 Python 标准库的 json.dumps 生成请求体,因此代码示例和多行内容会被正确编码。对于直接调试接口的场景,也应先用 JSON 库生成 request.json,再使用 curl --data-binary @request.json 发送,而不是把整篇 Markdown 拼进命令行字符串。
与 Codex 的协作方式
技能包 typecho-draft-publisher 封装了一个最小而明确的工作流:先审阅 Markdown,执行 dry-run 检查请求,再创建草稿;如果结果不确定,则复用同一个幂等键重试。技能不会自动放宽 CIDR、HTTPS 或 Token 设置,也不会把草稿提升为公开文章。
这种分工让 AI 负责起草和结构化输出,让 Typecho 后台继续承担编辑审核与发布控制。对于需要频繁写作、但仍希望保有最终编辑权的网站,这比把完整后台账号交给自动化工具更容易控制,也更符合日常内容生产的实际流程。
实际安装效果:

需要注意的一点,设置IP白名单的时候,IP后面需要加/32,如果是IP段,可以是/16。
小结
DraftPublisher 提供一个“能远程发布文章”的接口。默认本机访问、分层远程限制、Token、TLS、限流和幂等处理共同构成了接口边界;而 JSON 序列化与 Markdown 文件输入则保证了含代码文章的可靠传输。