個人ブログのX投稿を自動化した3段パイプライン設計——記事→スレッド生成→post_queue→GitHub Actions投稿

「記事は量産できるようになった。でもアクセスが来ない」——これは、コンテンツ自動化を組み終えた直後に直面した壁でした。
2026年6月26日、GA4のデータを改めて分析したところ、人間からの外部流入が9セッションという数字が出てきました。記事を増やしてもリーチが広がらない原因が、外部拡散の設計がゼロだったことにありました。
この記事は、その課題を「X投稿の完全自動化」で解いた設計の実録です。
結論
既存のcontent-executor(記事執筆パイプライン)を一切触らず、疎結合の新ルーチンとしてx-thread-distributorを追加しました。
パイプラインの全体像:
- 記事取得 — 公開済み記事のリストからその日の対象を選ぶ
- スレッド生成 — 記事内容からX用スレッドを自動生成
- 機械ガード — 捏造・誇張・禁止表現をチェックして差し戻し
- post_queue投入 — Supabaseの投稿キューに
approved=trueでINSERT - GitHub Actions投稿 — 毎時:15(UTC)に
auto_publisherが期限到来分を投稿
疎結合にした結果、コンテンツ生成と配信が独立して動くようになりました。どちらかが止まっても、もう一方は影響を受けません。
この記事の前提(自分の状況・スタック・実験条件)
- 運用: masatoman.net(AI業務設計の実験ログ)を複数の自動化ルーチンで動かしている
- スタック: sns-automation(TypeScript + GitHub Actions + Supabase + X API v2)
- 実装日: 2026年6月26日(dev_journal記録)
- 計測: GA4で人間の外部流入を定点観測中
「外部流入9セッション」という数字が出てくるまで、正直ボトルネックがどこにあるか把握できていませんでした。データを見て初めて「記事を増やすより先に、出口(配信)を作る必要があった」と気づいた経緯があります。
読者のよくある詰まり(「それ俺だ」を作る)
個人ブログの自動化を組むとき、たいてい記事生成側を先に作りこんで、配信側が後回しになります。
- 記事は量産できる → でも流入がない
- Xに手動投稿するのは面倒 → 結局サボる
- 「自動投稿ツール」を入れようとしたら設定が複雑で諦めた
- 既存の自動化パイプラインを壊したくない → 追加できない
最後の「壊したくない」が、今回の設計判断の核心です。
実際に起きたこと(判断と実装)
なぜ疎結合にしたか
content-executorは「ブリーフ取得→執筆→publish-gate→commit→push」という一連のパイプラインです。ここにX投稿を組み込もうとすると、2つの問題が生じます:
- 責任の混在: 記事の公開とSNS配信は別のジョブ。片方が失敗したとき、切り分けができなくなる
- タイミングのズレ: 記事は夜中に公開されるが、X投稿は朝の時間帯が効果的。同じパイプラインに入れると制御しにくい
そのため、x-thread-distributorを完全に別の定期実行ルーチンとして追加しました。毎日02:30 JSTに起動し、前日〜当日に公開された記事を対象にスレッドを生成します。
post_queue経由にした理由
直接X APIを叩くのではなく、Supabaseのpost_queueテーブルを経由させています。
x-thread-distributor → post_queue(pending) → auto_publisher → X API
この設計のメリット:
- 再試行が容易: 投稿失敗しても
status='failed'のまま残るので、手動でもリトライできる - スケジュール調整:
scheduled_atを変えるだけで投稿時刻を制御できる - 監査ログ: 「何を・いつ・投稿したか」がDBに残る
auto_publisherはもともと存在していたスクリプトで、毎時:15(UTC)にGitHub Actionsで動いています。post_queueにapproved=trueのpending投稿があれば投稿し、postedに更新する。この既存の仕組みをそのまま流用しました。
機械ガードを入れた理由
スレッド生成をAIに任せると、記事に書いていない数字や表現が紛れ込むことがあります。「完全自動化できました」「月◯件のアクセスが来るようになった」——これを機械ガードなしで出してしまうと、記事の当事者性が崩れます。
そのため、投稿前に禁止パターンを正規表現でチェックし、引っかかった投稿はrejectedに落として人間確認に回す仕組みを入れました。自動化でも「出してはいけないもの」を構造で止める設計です。
sitemapのnoindex除外も同時対応
今回の作業と同日に、sitemapからnoindex記事を除外しました。noindex記事をsitemapに含めるとGoogleへの矛盾シグナルになります(「インデックスしてほしくないが、sitemap経由でクロールしてほしい」という矛盾)。
小さな修正ですが、配信設計を整えるついでにSEO側の不整合も解消できました。
原因分析
今回の設計変更の根本は、「記事生成と配信は別のジョブという認識が遅れた」ことです。
コンテンツ自動化を始めると、つい「書く」部分に集中して「届ける」部分が後回しになります。GAの数字(9セッション)が出てくるまで、ボトルネックが配信にあることに気づけていませんでした。
設計としては、最初から「生成→公開→配信」の3ステップを別パイプラインとして設計しておくべきでした。後付けで追加した場合でも、疎結合にすることで既存への影響を最小化できます。
判断基準(読者が当てはめられる形)
同じ課題を抱えている場合、次の判断軸が使えます:
- 外部流入が月◯セッション以下で推移している → 配信パイプラインを先に作る
- 既存の自動化パイプラインを壊したくない → 疎結合で別ルーチンとして追加する
- 投稿の再試行・ログが必要 → 直接API呼び出しよりキュー経由にする
- AIが生成した文章をそのまま出したくない → 投稿前に機械ガードを入れる
「記事が増えてもアクセスが来ない」状態が続くなら、配信設計を先に作るほうが効果的です。
今日やること(3つ以内)
- GA4で「外部からの流入」を確認し、Organic Social / Referralの数字を把握する(ボトルネックの現状把握)
- sns-automationの
queue-x-post.mjsを試して、手動でpost_queueに投稿を登録してみる(仕組みの理解) - X投稿の自動化を検討するなら、既存パイプラインに組み込まず「別の定期実行」として設計する
masatoman のメルマガ — 毎週月曜の朝に手紙を 1 通
masatoman.net の今週の記事 1 本を、読者目線で深掘りした手紙が毎週月曜 9:00 に届きます。「これ自分のことだ」が見つかる予告編。登録特典に「個人開発の収益化チェックリスト 15 項目」。
masatoman のメルマガ — 毎週月曜の朝に 1 通
masatoman.net で今週公開した記事の中から 1 本を、読者目線で深掘りした手紙が届きます。「自分も同じことやってる」「ここで詰まってた」が見つかる予告編。