はじめに
技術記事を続けて出すのは、書くことそのものより、書いた後の作業(2つの媒体への転記、タグ付け、記録、振り返り)で挫けがちです。
この記事では、AIコーディングエージェントと組んで、企画 → 執筆 → 検証 → 投稿 → 改善 を1つのGitHubリポジトリで回す仕組みを作った記録を書きます。
方針は1つだけです。
公式に用意された手段だけで自動化する
非公式APIを叩いたり、ブラウザを自動操作してログイン状態を再現したりする方法は選びませんでした。理由は後半に書きます。
- 環境: Windows + Python 3.11(追加ライブラリなし)
- 投稿先: Zenn(主)+ Qiita(副)
全体像
[企画] loop/queue.md(候補と状態)
|
[執筆] articles/<slug>.md(本文 + frontmatter)
| \
[投稿] git push --→ Zenn(GitHub連携デプロイ)
| scripts/post_qiita.py --→ Qiita API v2
|
[記録] loop/published.md / loop/metrics.md
|
[改善] 閲覧数を確認 → 次の題材・タイトル・タグへ
ポイントは 記事ファイルを1つだけ持つことです。Zenn用のfrontmatter(title / emoji / topics / published)をそのままQiita投稿スクリプトが読み、タグだけ変換して投稿します。媒体間の転記は発生しません。
リポジトリ構成
.
├─ AGENTS.md # AIエージェント向けの運用ルール
├─ articles/ # 記事。ここが唯一の正
├─ books/ # Zennの本(必要になったら)
├─ loop/
│ ├─ queue.md # 企画キュー
│ ├─ published.md # 公開ログ
│ └─ metrics.md # 週次メトリクス
├─ scripts/
│ ├─ post_qiita.py
│ └─ fetch_qiita_metrics.py
└─ .secrets/ # APIトークン(gitignore済み)
- Pythonスクリプトは標準ライブラリのみ(urllib)で書きました。仮想環境もpip installも不要です。
- APIトークンは
.secrets/qiita_token.txtに1行で置き、.gitignoreで除外しています。AIエージェントには「トークンをチャットに貼らない」ことと合わせて運用ルールに明記しました。
Zenn:pushがそのまま公開になる
Zennには GitHubリポジトリとの連携が公式機能として用意されています。
- Zennダッシュボード →「GitHubからのデプロイ」→「リポジトリを連携」
- 連携するリポジトリと、デプロイ対象ブランチ(ここでは
main)を設定 - あとは
articles/*.mdを push するだけ
1点だけ注意があります。連携は必ずZenn側から始めます。先にGitHub側からZenn Connectをインストールしてしまうと、Zennに戻ったときに連携が記録されない、という既知のハマりがあります。
記事のfrontmatterはこうです。
---
title: "記事タイトル"
emoji: "🔁"
type: "tech"
topics: [zenn, qiita, github, python, ai]
published: false
---
published: false のままpushすると、Zenn側では下書きとしてデプロイされ、ダッシュボードからプレビューできます。true に変えてpushすれば公開です。ローカルにZenn CLIを入れる必要はありません。
Qiita:API v2 に標準ライブラリだけで投稿する
QiitaにはAPI v2が公開されていて、アクセストークン(scope: read_qiita / write_qiita)で記事をPOSTできます。
スクリプトの核はこれだけです(抜粋)。
payload = {
"title": title,
"body": body,
"tags": [{"name": t} for t in qiita_tags],
"private": private,
}
req = Request(
"https://qiita.com/api/v2/items",
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
method="POST",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
)
frontmatterは最小限の自前パーサーで読んでいます(PyYAMLは使いません)。topics はZennでは小文字スラッグですが、Qiitaのタグは表示名なので、マップで変換します。
TAG_MAP = {
"python": "Python",
"windows": "Windows",
"linux": "Linux",
"ai": "AI",
"ollama": "Ollama",
}
使い方は2つだけです。
python scripts/post_qiita.py articles/<slug>.md # 公開
python scripts/post_qiita.py articles/<slug>.md --private # 限定共有でテスト
一番効いたのは自動化ではなく「品質ゲート」
正直に言うと、投稿の自動化そのものは半日で終わる作業です。継続で効いてくるのは、AIエージェントに毎回読ませる運用ルールのほうでした。AGENTS.md にこんなことを書いています。
## 記事の源泉と品質基準
- 源泉は実作業・一次情報(作業ログ、実際に動作するコード)
- 記事内のコマンド・コード・数値は、投稿前に実行して確認する。
確認できない場合は published: false のままにするか、該当部分を削除する
- 収益・儲けの断言、投資銘柄推奨は禁止
- 機械的な大量投稿をしない(週1〜2本)
「AIに書かせる」だけなら誰でもできますが、「検証できないネタは公開させない」をルールとして固定するのが、AIと技術記事を回す上での生命線だと思っています。
あわせて loop/queue.md に企画候補と状態(候補 / 執筆中 / 公開済み など)を持たせています。AIのセッションは毎回まっさらなので、キューと公開ログをリポジトリに置くことで、次にどのセッションから再開しても同じループを続けられます。
ハマった点・外した選択肢
noteは対象外にした
noteには個人向けの投稿APIがありません(note pro向けの「note API」は、提携サービスの下書き保存に限られます)。加えて2026年2月に、機械的な大量投稿や外部サービスを使った自動化への対策強化が公式発表されており、「違反時は事前通知なく利用停止があり、通知義務を負わない」旨も規約に明記されています。
「規約に名指しの禁止がなければ大丈夫」と読むのは、判断の余地がすべて運営側にあるということで、こちらに有利な材料にはならない、というのが調べた上での結論でした。
X(旧Twitter)は従量課金に
X APIは2026年2月から従量課金制へ移行し、新規アカウントは初回$5のチャージがないと投稿できません(1投稿あたり$0.01)。記事の投稿先としては主軸から外し、告知用として後から足すか検討しています。
デプロイ結果はZenn側でしか分からない
Zennはpush後にZenn側でデプロイが走ります。成否はダッシュボードのデプロイ履歴で確認するため、ここは人間の目(またはスクリーンショットを撮る仕組み)が残るポイントです。逆に言えば、それ以外の工程は全部コマンドで完結します。
まとめ
- 投稿先は公式手段のある場所(Zenn = GitHub連携、Qiita = API v2)を選ぶと、規約リスクを避けたまま push とAPIだけで自動投稿が回せる
- 記事ファイルを1つにし、媒体差分(タグの表示名)だけをコードで吸収すると、転記ゼロで両媒体に出せる
- 自動化そのものより、**「検証を強制するAGENTS.md」と「企画キュー」**のほうが、AIと組む記事運用では効く
ZennもQiitaも無料枠だけで構成しているので、同じ形はそのまま真似できます。この構成が誰かの参考になれば幸いです。