给 Codex 增加自动整理并发布博客的 Skill

最近把博客的发布链路改成了一个很直接的 MCP:本地启动 astro-blog-ssh,再通过 SSH 直接把 Markdown 写到远端 Astro 博客的 content/blog 目录。

有了这条链路之后,一个很自然的下一步,就是让 Codex 不只是“能调用工具”,而是“知道什么时候应该把当前对话整理成文章并直接发布”。这次做的,就是把这套行为沉淀成一个可安装的 skill。

目标不是安装说明,而是行为约束

一开始最需要收窄的问题,不是怎么写 SKILL.md,而是这个 skill 到底要教 Codex 做什么。

这次明确的目标是:

  1. 当用户明确说“发布到我的博客”时,Codex 直接整理并发布。
  2. 当当前对话已经形成成体系的技术内容时,Codex 也默认自动发布。
  3. 如果上下文不够,Codex 不能乱编内容,只能缩小主题、说明假设,或者停下来补信息。

也就是说,这个 skill 不是安装器,不是 MCP 教程,而是一个“从对话到公开文章”的行为规范。

先写 spec,再落 skill 目录

为了避免把 skill 写成随意提示词,先在仓库里补了一份设计文档:

  • docs/superpowers/specs/2026-05-01-astro-blog-auto-publish-design.md

这份 spec 主要固定了几件事:

  • 触发条件分成显式发布和隐式发布两类。
  • 默认行为是自动发布,而不是先出草稿等确认。
  • 自动发布不等于可以编造内容,缺关键信息时必须收窄或中止。
  • skill 只负责教 Codex 调用现有 MCP 工具,不改 MCP 服务本身。

接着又补了一份实现计划:

  • docs/superpowers/plans/2026-05-01-astro-blog-auto-publish.md

这样后续生成的 skill 文件就有了清晰边界,既不容易超范围,也更方便以后继续维护。

最终生成的 skill 结构

这次只保留最小必要文件:

skills/astro-blog-auto-publish/SKILL.md
skills/astro-blog-auto-publish/agents/openai.yaml

SKILL.md 负责定义核心行为:

  • 什么时候使用这个 skill
  • 什么时候不要使用
  • 如何把对话重写成公共技术文章
  • 如何处理信息不足
  • 何时调用 generate_slugcreate_post
  • 发布失败时如何保留草稿并说明失败原因

agents/openai.yaml 则负责给 Codex 的技能列表和显式调用入口提供元数据,比如:

  • display_name
  • short_description
  • default_prompt

这个分层很重要。真正的工作规范应该放在 SKILL.md,而不是都挤进 description 里,不然模型很容易只读简短描述、不读完整 skill。

skill 里最重要的几条规则

相比“写出一篇文章”,更重要的是“什么时候不该发”。

所以这次 skill 里最关键的约束有几条:

  1. 默认自动发布,但前提是当前对话已经足够完整。
  2. 文章必须围绕一个清晰技术主题,而不是原样搬运聊天记录。
  3. 对于小缺口,可以用保守假设补齐,并在最终响应里说明。
  4. 对于关键缺口,不能编造事实,只能补问或缩小文章范围。
  5. 涉及私密、凭据、内部细节的内容,不能直接发。

这几条基本决定了 skill 的可用性。如果没有这些边界,所谓“自动发布”很容易变成“自动制造垃圾文章”。

一个实际踩到的坑:元数据生成脚本依赖 PyYAML

为了避免手写 agents/openai.yaml,我直接复用了现成 skill 自带的生成脚本。

第一次运行时,脚本报错了:缺少 yaml 模块。

根因不是脚本逻辑错误,而是它默认会读取 SKILL.md frontmatter,并使用 PyYAML 解析。本地当前 Python 环境没有这个依赖。

这时候最小改动不是去改环境,也不是去改脚本,而是直接使用它支持的 --name 参数,绕开 frontmatter 解析步骤。这样既不污染环境,也不偏离当前任务范围。

这个处理方式的好处很明显:

  • 不增加仓库依赖
  • 不修改外部 skill 提供的脚本
  • 仍然能产出标准 openai.yaml

另一个小坑:$skill-name 被 shell 吃掉了

openai.yaml 里有个 default_prompt 字段,规范要求显式写出 $skill-name

第一次生成后,结果从:

Use $astro-blog-auto-publish ...

变成了:

Use -blog-auto-publish ...

问题出在 shell 展开:$astro 被当成环境变量替换掉了,剩下后半截字符串。

根因明确之后,修复也很简单:不要怀疑 skill 内容本身,直接把生成后的 openai.yaml 用字面量修正为正确的 $astro-blog-auto-publish

这个问题很小,但挺典型:

  • 不是业务逻辑问题
  • 不是 MCP 问题
  • 是命令层的字符串展开问题

如果没有在最后做一次完整验证,很容易带着这个细小错误交付出去。

最后做了哪些验证

这次没有去验证“Codex 运行时一定会自动触发 skill”,因为那取决于实际的 skill 加载环境和 MCP 可用性。但本地已经做了这些可证实的检查:

  1. skill 目录结构完整。
  2. SKILL.md frontmatter 合法,命名符合 hyphen-case。
  3. openai.yaml 已生成,字段和 skill 语义一致。
  4. default_prompt 中的 $astro-blog-auto-publish 已按字面量保留。
  5. 仓库 diff 范围只包含 spec、plan 和 skill 目录,没有误改 MCP 服务代码。

这意味着“skill 包结构正确”这件事是可以确认的;至于“运行时是否自动发布成功”,则仍然依赖 Codex skill 加载能力和 astro-blog-ssh MCP 是否在线。

这类 skill 的价值

如果只是偶尔发一篇文章,直接手工整理也能做。

但当你已经有了 MCP 工具链,下一步最有价值的就不是重复调用工具,而是把“什么时候该调用、如何整理、什么情况下不能发”固化下来。

skill 的真正价值,不在于省掉几个命令,而在于让自动化行为有边界、有默认策略、也有失败回退路径。

这次的 astro-blog-auto-publish 就属于这种类型:它不是新能力,而是把已有能力变成了可重复复用的工作流。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注