はじめに
AI エージェント(Muse)に技術記事を書いてもらう機会が増えてきました。ただ、「AI が書いた記事をそのまま公開する」のは抵抗があります。かといって、1本ごとにコピペして投稿画面に貼るのも面倒です。
そこで作ったのが、記事ごとに Pull Request を作り、私がマージしたものだけが Qiita に自動投稿されるパイプラインです。公開の判断は必ず人間が行う、という線引きを仕組みに埋め込むことが目的でした。この記事では、その構成と運用上の約束、実際に動かして確認したところまでを書きます。
仕組みの流れ
- 私が Muse に記事テーマと素材を渡す
- Muse が記事ごとに作業ブランチと Pull Request を作る
- 私がスマホ/PC で PR を確認し、採用するものだけ
mainにマージする(=公開の承認) - マージをきっかけに GitHub Actions + 公式 Qiita CLI が Qiita へ投稿/更新する
- 公開された記事の ID が記事ファイルに自動で書き戻され、次回は同じ記事を更新できる
大事なのは、Muse の push や PR 作成だけでは公開されないことです。公開トリガーは「人間によるマージ」ただ1つに絞っています。
構成要素
| 要素 | 役割 |
|---|---|
GitHub リポジトリ qiita-article-pipeline(非公開) |
原稿の保管・差分確認・承認の場 |
| Qiita CLI(公式) | Markdown と Qiita の同期 |
GitHub Actions publish.yml
|
main マージ後の投稿(public/**/*.md の変更時のみ起動) |
GitHub Actions validate.yml
|
PR の記事検証(トークン不使用) |
GitHub Secret QIITA_TOKEN
|
Qiita 認証。置き場所はここだけ |
validate.yml では、ファイル名の規約、Front Matter の構文、title / tags / private / ignorePublish の値、新規記事の id が null であることなどを検査します。あくまで形式の補助チェックで、技術的な正確さを保証するものではありません。
運用上の約束(3つ)
1. トークンを AI に触らせない
Qiita トークンは GitHub の Secret にだけ置きます。記事本文・PR・チャットに貼らない、というのはもちろん、Muse 側の操作対象からも外しています。AI に渡すのはテーマと素材だけです。
2. マージは本人のみ
Muse には main への直接 push と PR のマージをさせません。5本の候補のうち2本だけ採用する、といった選別も PR 単位なので簡単です。スマホから PR を読んで、そのままマージできるのも実運用では効いています。
なお正直に書くと、これは現時点では「運用ルール」としての承認分離です。Muse の GitHub 連携が私と同じ権限で動く以上、技術的にマージ不可能にしているわけではありません。強い分離が必要になったら、Muse 用の低権限アイデンティティやブランチ保護を別途検証する計画です(ただし Qiita CLI の公式アクションは記事 ID を main へ書き戻すため、単純なブランチ保護と競合しうる点も設計時に洗い出しました)。
3. 書き戻しまで確認して「公開完了」とする
公式アクションは投稿後に記事 ID と更新日時を Markdown へ書き込み、コミットして戻します。ここが失敗すると、再実行で二重投稿になる危険があります。なので「Qiita に記事が出た」だけではなく「ID の書き戻しコミットが成功した」までを確認対象にしています。再実行する前には Qiita 側の公開状態を先に見る、という手順も運用ドキュメントに明記しました。
実際に動かして確認したこと
初期設定として、Qiita トークンの Secret 登録と、Actions の Workflow permissions を「Read and write」に変更しました(この2つは私の作業)。
その後の E2E テストでは、テスト記事の PR をスマホからマージし、限定共有での Qiita 投稿と、記事ファイルへの記事 ID 書き戻しまで確認できました。現在はこの仕組みで通常運用に入っています。
なお、執筆ルールについては「記事作成プロンプト集」の提供を受けない運用に決め、リポジトリ内のスタイルガイド(docs/article-style-guide.md)を正として運用しています。
障害時の対応も先に決めてある
自動投稿は「失敗したときの動き」まで決めておかないと、怖くて運用できません。設計時に洗い出した主なケースと対応は次のとおりです。
- Actions が起動しない:対象ブランチ・パス条件・Actions 設定を確認する
- 認証失敗(401/403):トークンの失効や権限を確認する
- 投稿は成功したが ID の書き戻しが失敗:再実行しない。 Qiita 側の記事 ID と原稿の Front Matter を手動で照合して復旧する(再実行すると二重投稿になりうるため)
- 意図せず公開された場合:Qiita 側で公開停止・削除を判断し、どの経路で公開されたかを調査する
特に「書き戻し失敗時に再実行しない」は、この仕組みで一番大事な運用ルールだと思っています。困ったときほど自動化を再実行したくなりますが、投稿系ではそれが事故の元です。
まとめ
- 「AI に書かせる」と「人間が公開を決める」を、PR マージという1点で分離した
- トークンの置き場所を Secret だけに限定し、AI の操作範囲から外した
- 投稿だけでなく ID 書き戻しまでを完了条件にしたことで、二重投稿のリスクを手順で潰した
記事のネタが溜まってきたら、候補をまとめて PR 化して、通勤中にスマホで選ぶ、という回し方ができるようになりました。