Claude Code にブログを毎日書かせて自動公開するパイプライン全公開 — CLAUDE.md / adapt-spec / routine の設計をそのまま見せる

「Claude Code にブログを書かせたいが、どこから手を付けていいか分からない」——それがスタート地点だとして、この記事では私が実際に組んで動かしているパイプラインの設計をそのまま公開します。
結論
CLAUDE.md(指示書)+ adapt-spec ファイル(媒体別仕様書)+ クラウドルーチン(Claude Code on the Web)の 3 レイヤーを組むと、Supabase のブリーフキューを起点に記事の執筆から Qiita・Zenn・はてなへの配信まで無人で動く。
ただし「すごい AI が全部やってくれた」話ではありません。設計ミスで何度も止まり、そのたびにゲートを追加して固めてきた実運用ログです。
この記事の前提
- スタック: masatoman.net(Next.js + Supabase)+ Qiita / Zenn / はてな外部配信
- 運用主体: content-executor v2.1(クラウドルーチン、火〜土 02:00 JST 自動実行)
- 記事ソース: Supabase
content_briefsテーブルにstatus='planned'で積まれたブリーフ - 「うまくいった話」ではなく「壊れながら設計を固めてきた航海日誌」です
読者のよくある詰まり
- Claude Code に「ブログを書いて」と指示したら一度は動いたが、再現性がない
- プロンプトに仕様を書き込んでも毎回フォーマットがブレる
- ローカルで手動実行は面倒。夜中に自動実行させたいが設計の見通しが立たない
- Skills や CLAUDE.md を整備したが、クラウド自動化にどう活かすかイメージできない
パイプライン全体図
実際に稼働している流れを順番に示します。
1. [Supabase: content_briefs]
status='planned' のブリーフをキューイング
(title_proposal / slug_target / rationale / data_evidence)
2. [content-executor routine]
02:00 JST 起動 → ブリーフを 1 件取得(priority ASC)
→ CLAUDE.md の指示に従い MDX 執筆(1500〜3000 字)
→ publish-gate(誇張 grep + lint-article-claims.mjs)通過確認
→ masatoman.net リポジトリに push
→ push 検証(git merge-base で main 到達を確認)
3. [外部配信 Step5]
adapt-spec ファイルを Read → 媒体別 Markdown を生成
→ Qiita / Zenn / はてな / Dev.to / note へ push
4. [SNS 配信]
疎結合の別ルーチン x-thread-distributor が記事 URL を X スレッドに投稿
シンプルに見えますが、各ステップに「落ちたら公開しない」ゲートが挟まっています。publish-gate を通らなければ Supabase のステータスを published に更新しません。push が main に届いたことを確認してから published に変えるステップもここに含まれます。
各レイヤーの役割と設計判断
CLAUDE.md — 「何を書くか」の指示書
各リポジトリのルートに置く CLAUDE.md が、content-executor が従う唯一の仕様書です。ここに書くのは次の 4 つです。
- ターゲット読者の定義(「誰のために書く」を 1 文で)
- 禁止パターン(「稼げる系」「完全ガイド乱発」「使ってみた型」等)
- 標準記事構造(結論 → 前提 → 読者の詰まり → 実際 → 判断軸 → 今日やること)
- frontmatter の必須フィールドと値の制約
CLAUDE.md を厚くするほど一貫性は上がりますが、長すぎると LLM が見落とします。私の現在の判断は「禁止事項は箇条書きで短く、構造テンプレートは具体的なサンプルで見せる」です。
adapt-spec ファイル — クラウドで Skills の代わりになるもの
当初はローカルの Skills ファイル(~/.claude/skills/)に媒体別ルールを書いていました。しかしクラウドルーチンはローカルファイルにアクセスできません(2026-06-23 に発覚)。Skills が整備されていても、Claude Code on the Web から参照する手段がないのです。
解決策は docs/adapt-spec-{媒体}.md というリポジトリ内ファイルに移すことです。content-executor は Step5 で各ファイルを Read してから配信用 Markdown を生成します。Qiita / Zenn / はてな / Dev.to / note それぞれに仕様が異なるため、ファイルを分けることで「その媒体の公式制限を毎回 LLM が参照する」形になります。
クラウドルーチン — スケジュール自動実行の本体
Claude Code on the Web のルーチン機能で火〜土 02:00 JST に自動起動します。ここに書くのはプロンプトだけです。「Supabase から planned を 1 件取って記事を書いて push する」という手順を自然言語で記述します。
重要な設計判断が 1 つあります。「書き手ルーチンは 1 本に絞る」。
かつては content-executor の他に複数の自動書き手(Cowork の aff-writer / aff-engineer / night-writer 等)が並走していました。その結果、同じリポジトリへの push 衝突・同スラッグの重複生成・旧 CTA の混入が頻発しました。2026-06-23 に legacy aff-crew を全部停止し、書き手を content-executor 1 本に集約しました。複数ルーチンを並走させることの複雑さは、得られるスループット増よりずっと大きかったです。
設計上の落とし穴(実際に踏んだもの)
1. ゴーストパブリッシュ
push が成功していないのに Supabase のステータスを published に更新するバグが起きました。対策は git merge-base --is-ancestor で push が main に届いたか確認するステップを追加することです。確認できなければ status='planned' に差し戻して再試行可能にします。
2. フォーマット指示違反
CLAUDE.md に「このフォーマットで出力」と書いても LLM は確率的に崩します。Qiita/Zenn の frontmatter が崩れて CI が連続失敗した事故(10 日間)から、validate-frontmatter.sh を push 前に必ず通すゲートを追加しました。詳細は「決定論的ゲートで守る」の記事にあります。
3. 書き手の並走
前述の通り。同じリポジトリに複数ルーチンが書き込もうとすると衝突します。書き手は 1 本に絞ること。
今日やること(3 つ)
- Supabase に
content_briefsテーブルを作る(id, title_proposal, slug_target, rationale, status, priorityの最小構成) - リポジトリのルートに CLAUDE.md を置き、ターゲット読者と禁止パターンだけ書く
- クラウドルーチンに「ブリーフを 1 件取って MDX を書いて push する」手順を書いてテスト実行する
インフラを全部揃えてから動かそうとすると永遠に動きません。まずブリーフ 1 件で通しで動かして、崩れたところにゲートを追加する順番がおすすめです。
masatoman のメルマガ — 毎週月曜の朝に手紙を 1 通
masatoman.net の今週の記事 1 本を、読者目線で深掘りした手紙が毎週月曜 9:00 に届きます。「これ自分のことだ」が見つかる予告編。登録特典に「個人開発の収益化チェックリスト 15 項目」。
masatoman のメルマガ — 毎週月曜の朝に 1 通
masatoman.net で今週公開した記事の中から 1 本を、読者目線で深掘りした手紙が届きます。「自分も同じことやってる」「ここで詰まってた」が見つかる予告編。