# OpenClaw 博客自动化生产流水线：从会话内容到一键发布


# OpenClaw 博客自动化生产流水线：从会话内容到一键发布
## 一、背景：被低估的时间成本

作为一个内容创作者，写技术文章最耗时的往往不是写作本身，而是发布前的「包装」工作。以我之前的发布流程为例：

| 环节 | 耗时 | 痛点 |
|------|------|------|
| 整理会话/内容到 Markdown | 1-2 小时 | 要手动去除对话中的无关信息，重新组织结构 |
| 填写 Hugo 博客 Front Matter | 30-60 分钟 | 50+ 个字段（ruby, fraction, toc, code, share, comment 等），每次都要逐个检查 |
| 制作封面图 | 1-2 小时 | 设计配图、调整尺寸、导出 WebP 格式 |
| 追加文末页脚 | 10-15 分钟 | 感谢阅读图、关于我、夜雨灯图，每篇文章都要重复 |
| Git 提交推送 | 5 分钟 | 手动 add、commit、push |
| **合计** | **3-5 小时** | 发布一篇博客几乎等于重新写一遍 |

面对这种重复劳动，我决定用 OpenClaw 的 Agent 编排能力，搭建一套自动化生产流水线。

---

## 二、设计哲学：编排而非替代

整个流水线的核心思路是 **编排（Orchestration）而非替代（Replacement）**。我们不试图让一个 Agent 完成所有事情，而是让一个轻量的编排 Agent 协调多个专业 Agent 分工合作。

这就是 `blog-writer` 技能的设计定位——它本身不写文章、不做图、不部署，它只做三件事：

1. 收到"写博客"指令后，拉取会话历史
2. 调用 `kb-writer` 将内容结构化写入 Obsidian 知识库
3. 调用 `design-yuntianguang` 使用 agnes-image 生成 1600×900 的 WebP 封面图

这种编排模式的优势在于：**每个 Agent 只做自己最擅长的事，职责清晰，可独立升级。**

---

## 三、系统架构：三 Agent 分工协作

### 3.1 blog-writer：流程编排器

blog-writer 是一个 OpenClaw Skill，位于 `~/.openclaw/skills/blog-writer/`。它的 SKILL.md 中定义了完整的博客文章 Front Matter 格式（50+ 字段），以及调用 kb-writer 和 design-yuntianguang 的流程规范。

核心设计决策：

- **不直接操作文件系统**：所有写操作委托给 kb-writer
- **Front Matter 在 kb-writer 阶段完成**：publish 脚本不再处理 Front Matter，只做 categories 修正和页脚追加
- **封面图路径固定**：`/images/Code-Art-Studio-images/{slug}/{slug}.webp`

### 3.2 kb-writer：文章撰写者

kb-writer 负责将会话内容转化为结构化文章。它是 Obsidian 知识库的写入入口，提供了两步写入法：

```bash
# Step 1: create_note.sh 生成 Front Matter + 标题行
~/.openclaw/skills/obsidian-vault/scripts/create_note.sh \
  "<路径>/<文件名>.md" \
  "<标题>" \
  "tag1,tag2" \
  "<session_key>" \
  "<caller_agent>" \
  "<content_type>"

# Step 2: update_note.sh append 追加正文
~/.openclaw/skills/obsidian-vault/scripts/update_note.sh append \
  "<文件路径>" \
  "$(cat /tmp/note_body.md)"
```

**关键经验教训**：create_note.sh 只生成 Front Matter 和标题行，不会写入正文。正文必须通过 update_note.sh append 追加，不能跳过。

### 3.3 design-yuntianguang：封面设计师

负责使用 agnes-image 工具生成文章封面图。规范：

- 尺寸：1600×900 像素
- 格式：WebP
- 存储路径：`static/images/Code-Art-Studio-images/{slug}/{slug}.webp`
- 触发时机：kb-writer 完成文章写入后自动调用

---

## 四、发布脚本实现

### 4.1 publish-technical.mjs

核心发布脚本，位于 `/data/oklifeme/publish-technical.mjs`。它的职责非常清晰：

```
读入 Obsidian 原文 → 修正 categories → 追加固定页脚 HTML → Git 提交推送
```

关键代码结构：

```javascript
// 扫描 Obsidian 草稿目录，只筛选 content_type: blog-post 的文章
const drafts = [];
for (const file of files) {
  const content = readFileSync(filePath, 'utf-8');
  const parsed = parseFrontMatter(content);
  if (parsed && parsed.frontMatter.content_type === 'blog-post') {
    drafts.push({ file, filePath, ...parsed });
  }
}

// 用户交互选择 → 确认要发布的文章
const choice = await askQuestion(`选择要发布的文章（1-${drafts.length}）: `);

// 读入原文 → 修正 categories → 追加页脚
let article = readFileSync(draft.filePath, 'utf-8');
article = article.replace(/^(categories:).*/m, 'categories:\n  - "Code Art Studio"');
article = article.replace(/\n$/, '') + '\n' + FOOTER_HTML;

// Git 提交推送
shell(`git add "${relOut}"`, hugoRootDir);
shell(`git commit -m "feat: 技术文章 ${slug}"`, hugoRootDir);
shell(`git push origin main`, hugoRootDir);
```

### 4.2 固定页脚 HTML

页脚内容三段式：

1. **--全文完--** 分隔线
2. **感谢阅读图**：响应式图片，三档分辨率（800w/1200w/1600w）
3. **关于我**：可折叠面板 + 约我聊天的引导文案
4. **夜雨灯图**：文尾配图水墨画

这些内容通过 `FOOTER_HTML` 常量定义，所有文章统一使用，publish 脚本在复制到 Hugo 目录时自动追加。

### 4.3 run-publish-technical.sh（桌面双击）

为了让发布操作更加便捷，创建一个 Shell 包装脚本，放在桌面可直接双击运行：

```bash
#!/bin/bash
cd /data/oklifeme
node publish-technical.mjs
read -p "按回车退出..."
```

---

## 五、手动 vs 自动：完整流程对比

| 维度 | 手动流程 | 自动流程 |
|------|---------|---------|
| 触发方式 | 手动打开编辑器 | 会话中说"写博客" |
| 内容整理 | 1-2 小时手动编辑 | kb-writer 自动分析会话 |
| Front Matter | 30-60 分钟填写 | kb-writer 写入时自动完成 |
| 封面图 | 1-2 小时设计 | design-yuntianguang 自动生成 |
| 文末页脚 | 10-15 分钟手动粘贴 | publish 脚本自动追加 |
| Git 提交 | 手动 add + commit + push | 脚本自动执行 |
| 总耗时 | 3-5 小时 | 3-5 分钟（Agent 执行）+ 2 分钟审核 |
| 部署方式 | 手动 | Cloudflare Pages 自动部署 |
| 出错的概率 | 高（遗漏字段/格式错误） | 极低（模板化） |

**实际效果**：现在写博客只需要在会话中说"写博客"，然后审核文章内容，双击桌面脚本即可发布。1-2 分钟后 `oklife.me` 就已经更新。

---

## 六、技术要点总结

### 6.1 Front Matter 字段的归属问题

**经验：Front Matter 应该在 kb-writer 写文章时完成，而不是在 publish 脚本中补全。**

最初的设计打算让 publish 脚本自动生成 Front Matter，但发现这样会写出大量重复代码，而且每个会话的内容不同，Front Matter 也不同（keywords、summary、tags 等字段与文章内容直接相关）。

最终决策：**kb-writer 在写入 Obsidian 时就应该包含完整的 Front Matter**，publish 脚本只做两件事：
1. 修正 `categories` 为固定值 `["Code Art Studio"]`
2. 追加固定页脚 HTML

### 6.2 封面图路径规范

所有技术博客的封面图遵循统一规范：

```
/images/Code-Art-Studio-images/{slug}/{slug}.webp
```

这意味着封面设计 agent 需要根据 slug 确定输出路径，而 kb-writer 在写 Front Matter 时直接引用这个路径，保证图片引用不会出错。

### 6.3 流水线的可扩展性

这套架构天然支持扩展：
- 新增发稿渠道 → 只需要加一个 publish agent
- 新增内容类型 → 扩展 kb-writer 的 Front Matter 模板
- 更换封面风格 → 替换 design-yuntianguang 的 prompt

---

## 七、写在最后

这套自动化流水线最大的收获不是省了多少时间，而是**建立了内容生产的标准流程**。将一次性的手动操作转化为可重复的自动化流程后，创作的心态从「又要花半天发布」变成了「随时可以记录和分享」。

对于同样使用 OpenClaw 或类似 Agent 平台的读者，这套架构模式——编排器 + 专业 Agent 分工——也适用于很多场景：数据分析报告生成、文档自动编写、运维故障排查记录等。

**关键记住一条原则**：不要让一个 Agent 做完所有事情，让专业的 Agent 做专业的事，用一个轻量的编排器把它们串起来。


***
--全文完--

<a href="/images/Journal-Notes/Thank-you-for-reading-1600.webp" class="lightgallery">
    <img src="/images/Journal-Notes/Thank-you-for-reading-1200.webp"
         srcset="/images/Journal-Notes/Thank-you-for-reading-800.webp 800w,
                 /images/Journal-Notes/Thank-you-for-reading-1200.webp 1200w,
                 /images/Journal-Notes/Thank-you-for-reading-1600.webp 1600w"
         sizes="(max-width: 600px) 800px, (max-width: 1200px) 1200px, 1600px"
         alt="感谢阅读"
         loading="lazy"
         style="width:100%; height:auto; border-radius:8px;">
</a>

***


{{< admonition type=question title="若你有故事想讲、有困惑想聊、或是想找个人说说心里话，甚至只是吐槽发泄一下情绪，都欢迎来找我聊聊：　　　《内容已折叠，点击展开》 " open=false >}}

{{< typeit tag=h4 >}}

**"同频之人，终会相遇；同行之路，终有光亮。愿与身处同境、灵魂同频、砥砺前行的你相遇相伴，倾听彼此的故事与困惑，分享心路与感悟，在逆境中自救破局的路上彼此陪伴、相互照亮、同行向前,一起走向重生与新生。"**...

{{< /typeit >}}

<figure style="width:100%; margin:0;">
  <a href="https://www.oklife.me/about/"
     style="display:block; transition:opacity .25s ease;">
    <img src="/images/site-wide/about-me-1200.webp"
         srcset="/images/site-wide/about-me-800.webp 800w,
                 /images/site-wide/about-me-1200.webp 1200w,
                 /images/site-wide/about-me-1600.webp 1600w"
         sizes="(max-width: 600px) 800px, (max-width: 1200px) 1200px, 1600px"
         alt="关于我页面配图"
         loading="lazy"
         style="width:100%; height:auto; border-radius:8px; display:block;">
  </a>

  <figcaption style="text-align:center; margin-top:8px; color:#666; font-size:14px;">
    <a href="https://www.oklife.me/about/"
       style="color:inherit; text-decoration:none;">
      点击跳转：关于我
    </a>
  </figcaption>
</figure>


{{< /admonition >}}



***
{{< admonition type=success title="希望我写的每一个字，成为我自己和某个人活下去、拼下去的力量。　　　　　　　　　　　　　　　　　　　　　《内容已折叠，点击展开》" open=false >}}
"技术终归是工具，而我们一次次认真把问题理顺，守住的其实不只是页面样式和代码输出，还有那一点不愿被混乱打败的心气，是每一个深夜仍愿点灯前行的人。"

转载请注明来自https://oklife.me。

<a href="/images/post-end/night-rain-lamp-1600.webp" class="lightgallery">
    <img src="/images/post-end/night-rain-lamp-1200.webp"
         srcset="/images/post-end/night-rain-lamp-800.webp 800w,
                 /images/post-end/night-rain-lamp-1200.webp 1200w,
                 /images/post-end/night-rain-lamp-1600.webp 1600w"
         sizes="(max-width: 600px) 800px, (max-width: 1200px) 1200px, 1600px"
         alt="文尾配图水墨画图片"
         loading="lazy"
         style="width:100%; height:auto; border-radius:8px;">
</a>
{{< /admonition >}}

