経営者向けThreads自動投稿
09_threads_curator
経営者向け Threads 自動投稿システム。 HOOTL(Human Out of the Loop)24 時間自走 + HITL は Discord 絵文字 1 タップだけ。knowledge/ で「Koji の声」を保つ。
RSS 収集・スコアリング・So What 抽出・ドラフト生成・投稿までを 24 時間自走させ、人間の判断は Discord 絵文字 1 タップに圧縮。フォロワー数を伸ばす装置ではなく、リアルで会った経営者に「ちゃんと活動している」と伝わる信頼装置であり、Koji の頭の中に情報を地図化していく思考補助装置。
---
TL;DR
| 項目 | 内容 |
|---|---|
| 何を作ったか | 経営者向けに「翻訳」する Threads アカウントの自動運用システム |
| 技術構成 | 3 層分離(collector / analyzer / publisher)+ SQLite 経由通信、すべて短命 cron、常駐プロセスゼロ |
| 人間の介入 | Discord 絵文字 1 タップ(✅承認 ❌棄却 🔥即出 📝編集)、48h 無反応で自動棄却 |
| 実装ステータス | Phase 1 完了(Loop 1:投稿ループ)、本番投稿は Task Scheduler で自走中 |
| 横展開可能性 | knowledge/ + agents/ + feeds.yaml を差し替えれば別テーマに丸ごと転用可能(Phase 2 で実証予定) |
---
3 評価軸での自己評価
| 評価軸 | 自己評価 | 主張の根拠 |
|---|---|---|
| ① 稼働性 — 止まらず動き続け、障害から自己復旧する | 強み | 3 層分離 + SQLite 経由通信、claim パターンによる二重実行防止、stuck 検知、トークン自動 refresh、48h 自動棄却、Codex レビュー反映による稼働性指摘の修正済み |
| ② 進化性 — 実行するほどデータが溜まり、自動で賢くなる | 現状は弱い、Phase 2 で集中強化 | Phase 1 では SQLite はトランザクション用途のみ。棄却理由・反応データの蓄積 → プロンプト自動反映ループは未実装。Phase 2 で rejection_log / engagement_log 追加と週次バッチで knowledge/07_lessons.md への集約を実装予定 |
| ③ 事業性 — 解いた課題の大きさ・実世界でのインパクト | 思想として強い | 「経営者向け翻訳」というポジションは、エンジニア向け技術メディアにも、純粋な情報メディアにも代替されにくい。機能の提供者ではなく、人生の節目に立ち会う人としてのポジショニングを AI で支える試み。テーマ可換性により別ジャンルへの横展開も可能 |
以下、3 軸それぞれを詳述。
---
① 稼働性 — 止まらず動き続け、障害から自己復旧する
1.1 設計上の稼働性
3 層分離 + SQLite 経由通信:各層は SQLite (data/threads.db) を介してのみ通信する。直接 import しない。
flowchart LR
subgraph L1["Layer 1: Collector"]
a1[RSS 取得] --> a2[pre_filter]
end
subgraph L2["Layer 2: Analyzer"]
b1[scorer] --> b2[distiller] --> b3[drafter]
end
subgraph L3["Layer 3: Publisher"]
c1[discord_notifier] --> c2[discord_listener] --> c3[publisher]
c4[expirer] & c5[token_refresher]
end
DB[(SQLite WAL<br/>busy_timeout=30s)]
L1 --> DB --> L2 --> DB --> L3 --> DB
style DB fill:#fff3e0,stroke:#f57c00,stroke-width:2px
この構造による稼働性上のメリット:
- 1 層が落ちても他は生きる:collector が RSS 取得に失敗しても、analyzer は既存の articles を処理し続ける
- 状態が DB に永続化:プロセスがいつ死んでも、次の cron が続きから走る
- 常駐プロセスゼロ:すべて短命 cron。メモリリーク・プロセス死リスクを構造的に排除
1.2 障害自己復旧の具体的実装
| シナリオ | 対策 | 実装 |
|---|---|---|
| 二重投稿 | claim パターン(BEGIN IMMEDIATE + rowcount 確認)で、同時に複数プロセスが同じドラフトを掴めないようにした | publisher/publisher.py |
| 二重通知 | notifying 状態を経由してから pending に戻す。Discord notifier の二重起動でも通知は 1 回 | publisher/discord_notifier.py |
| publish 後の通信断(Threads 側が成功したか不明) | post_unknown 状態を新設、再試行禁止、人間確認に回す。creation_id を DB 保存してリカバリ可能に | publisher/publisher.py, shared/db.py |
| 判断滞留 | Koji が 48h 反応しなければ自動 expired、通知が溜まらない | publisher/expirer.py |
| トークン失効(Threads は 60 日 long-lived) | token_refresher を 30 日ごとに走らせて自動延長 | publisher/token_refresher.py |
| API レート制限 | Discord API は 429 を Retry-After 尊重で待機、5xx は警告のみで status 変更しない | publisher/discord_listener.py |
| 誤承認(承認権限の越境) | APPROVER_DISCORD_USER_ID 環境変数で押せるユーザーを 1 人に限定 | publisher/discord_listener.py |
| @everyone 事故 | allowed_mentions: {"parse": []} を Discord payload に追加 | publisher/discord_notifier.py |
| 並行アクセス(複数 cron が同時に DB 触る) | SQLite WAL モード + busy_timeout=30000 | shared/db.py |
1.3 「静かに失敗する」原則
通知が鳴っていいのは 「トークン失効」と「投稿 stuck」だけ。それ以外のエラー(RSS が空、ドラフトが 0 件、スコアが全部低い、など)はログに残して静かに終わる。Koji の Discord に通知が来た = 本当に対応すべき何か、という信号価値を保つ。
1.4 稼働性に関する Codex ダブルチェック
実装後、別 AI(Codex)にコードレビューを依頼。重大な稼働性指摘(二重投稿防止の不完全さ、publish 後の通信断対応の欠如、@everyone 事故防止、API エラー処理不足など 8 点)はその場で反映済み。詳細は IMPLEMENTATION_LOG.md を参照。
1.5 現時点の制約
- 稼働実績:Task Scheduler で 5 本(collect / listen / publish / expire / refresh)が自走中、本番投稿モード(
DRY_RUN=False)で運用継続中 - token_refresher の有効期限ログ:「有効期限タイムスタンプ: 不明」のままで、次回失効時期が明示記録されていない(運用上は 60 日 long-lived の前提で 30 日ごとに走らせている)
docs/architecture.mdのディレクトリ図が古いまま(1_collector/などの数字プレフィックス時代の表記)
---
② 進化性 — 実行するほどデータが溜まり、自動で賢くなる
正直に書く:Phase 1 では進化性はほぼ実装されていない。 ここが本システムの現状最大の弱点。
2.1 現状(Phase 1):DB はトランザクション用、学習用ではない
SQLite には 3 テーブル(articles / drafts / post_log)あるが、すべて「いま処理中の状態を持つ」ためのテーブル。以下が記録されていない:
- 棄却したドラフトの理由(なぜ ❌ を押したか)
- 投稿後の反応(いいね・コメント・伸び)
- Koji が手で修正した差分(drafter の生成物と最終投稿の差)
結果として、システムは毎回ゼロから判断している。人間が回数を重ねるほど賢くなるはずの装置が、現状そうなっていない。
2.2 進化性の「種」は仕込んである
ただし、進化に必要な土台は Phase 1 で用意した:
| 仕組み | 進化の意味 |
|---|---|
**agents/*.md と Python コードの分離** | プロンプト改修コストがほぼゼロ。shared/agent_loader.py が agents/scorer.md の frontmatter から knowledge/*.md を結合して system prompt を組み立てる。プロンプトを直したいときに .py を一切触らない |
knowledge/ フォルダ構造(8 ファイル) | 「Koji の声」「対象読者」「原則」を分離管理。drafter のプロンプトに自動的に挿入される。ここに気づきを追記すれば即座に出力に反映される |
config/feeds.yaml | 情報源 RSS をコード変更なしで増減可能 |
つまり「進化の入口」は用意してあるが、「進化を駆動するデータ収集とフィードバックループ」が抜けている、というのが現状。
2.3 Phase 2:学習ループの実装
DB スキーマ追加(2 テーブルのみ、既存テーブルに影響なし):
rejection_log 棄却理由 + 棄却時刻 + draft_id + Koji の自由記述(Discord で 📝 + コメント)
engagement_log Threads API から取得した投稿後の反応(いいね・コメント・閲覧数)
週 1 のバッチで両テーブルを集計 → knowledge/07_lessons.md に追記 → 次回以降の drafter / scorer プロンプトに自動的に含まれる。
flowchart LR
A[棄却・反応データ蓄積<br/>rejection_log / engagement_log] --> B[週次バッチ<br/>集計・抽象化]
B --> C[knowledge/07_lessons.md<br/>追記]
C --> D[agents/drafter.md<br/>agents/scorer.md<br/>のシステムプロンプトに含まれる]
D --> E[次回のドラフト生成・スコアリング]
E -.経験を反映.-> A
style C fill:#fff3e0,stroke:#f57c00,stroke-width:2px
実装コストは小さい(2 テーブル追加 + 週次バッチ 1 本)。Phase 2 の最優先論点。
2.4 進化の 3 階層
進化性は単一の層ではなく、以下の 3 階層で動かす設計:
| 階層 | 何が進化するか | 駆動データ |
|---|---|---|
| プロンプト層 | scorer / distiller / drafter の判断基準 | knowledge/07_lessons.md(週次バッチ) |
| ナレッジ層 | Koji の声・現場知の解像度 | knowledge/04_domain/ への現場体験追加(Koji が随時) |
| テーマ層 | システム全体が扱う対象ドメイン | knowledge/ + agents/ + feeds.yaml の差し替え |
最上位の「テーマ層」の進化が、後述のテーマパッケージ可換性につながる。
2.5 複数ループ並走による進化(Phase 2 以降)
docs/concept.md で設計済み。Phase 1 は Loop 1 のみ:
flowchart TB
K((Koji の<br/>頭の地図))
L1["Loop 1: 投稿ループ<br/>『これ、出していい?』"] --> K
L2["Loop 2: 深掘り提案ループ<br/>『このテーマは調べながら書いた方がよくないか?』"] --> K
L3["Loop 3: 対比構造提案ループ<br/>『経営の○○と対比すると面白くない?』"] --> K
L4["Loop 4: 投稿パターン拡張ループ<br/>『今日は問いの形で出してみたら?』"] --> K
K -.判断.-> L1 & L2 & L3 & L4
style K fill:#ffeb3b,stroke:#f57c00,stroke-width:3px
style L1 fill:#e3f2fd
異なる問いを投げてくる複数ループを持つことで、AI 生成の同質化を防ぎつつ Koji の頭の中の地図が複数軸で太る、という仮説。
---
③ 事業性 — 解いた課題の大きさ・実世界でのインパクト
3.1 解こうとしている課題
非エンジニアの経営者は、AI 時代の発信で 2 つの罠にハマる:
- 手で書くと続かない:本業が忙しい
- AI に丸投げすると差別化が消える:当たり障りない要約・解説は、AI 時代に最も価値が出ない情報になる
この狭間に「経営者向けに翻訳する」という独自ポジションがある:
- HowTo・ツール紹介ではなく、「経営者として何が見えているか・何ができるのか」を発信する
- 技術的に正しい解説ではなく、経営の文脈での So What を出す
- 機能紹介ではなく、それが経営判断にどう効くかを読み解く
このポジションは、エンジニアにも、純粋な情報メディアにも代替されにくい。経営者の文脈を持っている人だけが書けるものを、自動化と人間の判断を組み合わせて出し続ける。これが本プロジェクトの本丸。
3.2 想定ターゲット
「自分と同じような 非エンジニアの経営者」。ただし以下の条件付き:
- 自分より忙しい
- プロダクト(Claude / ChatGPT など)はすでに少し触っている
- 触ってはいるが、本格的な活用にはまだ踏み込めていない
- 情報を自分で集める時間がない
このターゲットには、HowTo を投げても消費されない。「自分の事業に持ち込む時、何が変わるのか」を判断する材料が欲しい。
3.3 2 つの目的
目的 A:発信の信頼装置
フォロワー数を伸ばすこと自体は目的ではない。
リアルで会った経営者に「こんな投稿もしてるんですよ」と伝えた時に、「ちゃんと活動している人だ」と伝わる状態を作る。質を作ることで、結果的にフォロワーの質も上がり、リアルの信頼関係につながる。
目的 B:思考の地図化
毎日いろんな Web サイトを見に行くのではなく、選別された情報が手元に届く。それを判断する過程で、Koji の頭の中に全体像が地図として整理されていく。
このシステムは「投稿を量産する装置」ではなく、「Koji の頭の中の地図を太らせる装置」でもある。発信は、その地図化プロセスの副産物。
3.4 単なる自動投稿システムとの違い
| 観点 | A: 単なる自動投稿 | B: 本プロジェクト |
|---|---|---|
| 目的 | フォロワー数・PV | 翻訳ポジションの可視化・思考の地図化 |
| 視点 | 記事の要約・分析 | 経営者として「何が見えているか」 |
| 出力 | AI 文体(誰が書いても同じ) | knowledge/ により Koji の声で出る |
| 介入 | なし or 手動レビュー | Discord 絵文字 1 タップ(HITL 最小) |
| 学習 | なし | 棄却・採用ログから AI の判断が育つ(Phase 2) |
| 副産物 | なし | 棄却ドラフトが思考の素材庫になる |
3.5 横展開可能性:テーマパッケージ可換性
このシステムは「経営者 × Claude Code」という現テーマに密結合させない設計にしている。3 つのフォルダを差し替えれば、テーマ丸ごと別のものに切り替えられる:
| フォルダ | 役割 | 差し替えるとどうなるか |
|---|---|---|
knowledge/ | 発信主体の声・対象読者・原則(8 ファイル) | 別の発信主体に切り替わる |
agents/ | scorer / distiller / drafter のシステムプロンプト | 翻訳の切り口が変わる |
config/feeds.yaml | 情報源 RSS | 取得する情報ジャンルが変わる |
候補:「中小医療法人 × AI」「不動産オーナー × データ活用」「サプライチェーン × 生成 AI」など、別ドメインに丸ごと差し替えても、3 層パイプライン自体は同じものが走る。
現状は設計レベルでの分離に留まる。実際に別テーマで品質維持できるかは Phase 2 で実証する必要がある。実証ゴールは「別テーマでも 1 週間 5 投稿、人手大幅修正なしで通せるか」。
仮に「経営者 × Claude Code」という現テーマが当たらなかったとしても、システム自体は別パッケージで生き続けられる。これが事業性として一番伝えたいポイント。
3.6 経営者個人へのインパクト
このシステムが Koji 自身に与える効果(事業性の隠れた本丸):
- AI で「機能の提供者」ではなく「人生の節目に立ち会う人」へのポジショニングを支える
- 中小企業・医療法人・オーナー経営者が AI で価値を上げる入口と設計を担うときに、「自分も実践している」という具体物を持っている状態を作る
- 知性・ロジックはコピーされるが、文脈と信頼関係の蓄積はコピーされない
---
設計の全体像(再掲・データフロー)
flowchart TB
RSS[Zenn RSS<br/>config/feeds.yaml] --> F[collector.fetcher]
F --> PF[collector.pre_filter<br/>重複・鮮度・NG除外]
PF --> DB1[(articles<br/>status=fetched)]
DB1 --> S[analyzer.scorer<br/>agents/scorer.md<br/>閾値 8.0]
S --> DB2[(articles<br/>status=scored)]
DB2 --> D[analyzer.distiller<br/>agents/distiller.md<br/>So What 抽出]
D --> DB3[(articles<br/>status=distilled)]
DB3 --> DR[analyzer.drafter<br/>agents/drafter.md<br/>500字本文]
DR --> DB4[(drafts<br/>status=pending<br/>expires=+48h)]
DB4 --> N[publisher.discord_notifier<br/>4絵文字プリセット]
N --> Koji{Koji<br/>✅❌🔥📝}
Koji --> L[publisher.discord_listener]
L --> DB5[(drafts<br/>status=approved/<br/>force_post/rejected)]
DB5 --> P[publisher.publisher<br/>Threads 2ステップ投稿]
P --> Threads[Threads]
P --> DB6[(post_log)]
EX[publisher.expirer<br/>48h 経過 → expired] -.-> DB4
TR[publisher.token_refresher<br/>30日ごと] -.-> Threads
style Koji fill:#ffeb3b,stroke:#f57c00,stroke-width:3px
---
ディレクトリ構造
09_threads_curator/
├── collector/ Layer 1: 情報収集(外→DB)
│ ├── fetcher.py
│ └── pre_filter.py
├── analyzer/ Layer 2: 分析・ドラフト生成(DB→DB)
│ ├── scorer.py
│ ├── distiller.py
│ └── drafter.py
├── publisher/ Layer 3: HITL & 投稿(DB→Discord/Threads)
│ ├── discord_notifier.py
│ ├── discord_listener.py
│ ├── publisher.py
│ ├── expirer.py
│ └── token_refresher.py
├── shared/ 共通基盤
│ ├── db.py SQLite 初期化・状態遷移
│ ├── llm_client.py Anthropic SDK ラッパ
│ └── agent_loader.py agents/*.md + knowledge/ を system prompt に結合
├── agents/ 各機能のシステムプロンプト(MD 分離)
├── knowledge/ AI に渡す「Koji の声」8 ファイル
├── config/feeds.yaml
├── scripts/ run_*.bat(Windows Task Scheduler 用 5 本)
├── data/ SQLite 置き場(gitignore)
├── docs/
│ ├── concept.md 何を作るか・なぜか
│ ├── architecture.md どう作るか(Mermaid 5 枚)
│ └── status_machine.md articles/drafts の全状態遷移表
├── CLAUDE.md
└── IMPLEMENTATION_LOG.md 進捗・引き継ぎ
注:当初設計の 1_collector/ 2_analyzer/ 3_publisher/ はディレクトリ名から数字プレフィックスを外した(Python の python -m がモジュール解決できない仕様への対応)。
---
セットアップ
.env.exampleをコピーして.envを作成し、5 変数を埋める
ANTHROPIC_API_KEYDISCORD_BOT_TOKEN/DISCORD_CHANNEL_IDTHREADS_ACCESS_TOKEN/THREADS_USER_ID
knowledge/の 8 ファイルを Koji の情報で埋める(特に06_principles.md)pip install -r requirements.txtpython -m shared.db initで DB 初期化- Task Scheduler 5 本登録:
scripts\install_tasks.bat
詳細手順と Discord Bot 作成方法は IMPLEMENTATION_LOG.md 朝の手順 を参照。
---
進捗
Phase 1 実装完了(2026-05-09)。コード一式・構文チェック・Codex レビュー反映・DB スキーマ自動マイグレーションまで完了。
| 項目 | 状態 |
|---|---|
| ディレクトリ構造・knowledge/ テンプレ・docs・.env.example | ✅ |
| Layer 1(fetcher / pre_filter) | ✅ |
| Layer 2(scorer / distiller / drafter) | ✅ |
| Layer 3(discord_notifier / listener / publisher / expirer / token_refresher) | ✅ |
| shared 基盤(db / llm_client / agent_loader) | ✅ |
| agents/*.md(scorer / distiller / drafter / critic) | ✅ |
| Codex レビュー反映(重大 + 中の指摘 8 件) | ✅ |
| Discord Bot 作成・サーバー招待 | ✅ |
| knowledge/ 中身執筆(04_domain/executive_insights.md 含む 8 ファイル) | ✅ |
| Task Scheduler 5 本登録 | ✅ |
| end-to-end 本番連続走行(DRY_RUN=False) | ✅ |
| Phase 1.5: 編集機能(📝 → reply → 再通知 → ✅) | ✅ |
| Phase 1.5: critic agent + executive_insights によるドラフト品質改善 | ✅ |
| Phase 2: rejection_log / engagement_log | 未 |
| Phase 2: テーマパッケージ可換性の実証 | 未 |
詳細は IMPLEMENTATION_LOG.md、設計プランは C:\Users\kouji\.claude\plans\zippy-tumbling-micali.md。
---
設計原則
- Streamlit を起動しない(HOOTL 概念維持)
- 常駐プロセス禁止、すべて短命 cron
- Discord 操作は 4 種のみ(✅承認 ❌棄却 🔥即出 📝編集)
- 48h 無反応で自動棄却、判断疲れを防ぐ
- 静かに失敗する、通知が鳴っていいのは「トークン失効」と「投稿 stuck」だけ
---
関連ドキュメント
docs/concept.md— 何を作っているか・なぜか(経営者向け翻訳という本丸、2 つの目的、複数ループ設計)docs/architecture.md— どう作るか(3 層構造、Mermaid 5 枚で全データフロー可視化)docs/status_machine.md—articles/draftsの全状態遷移表、claim パターン、post_unknownリカバリ手順IMPLEMENTATION_LOG.md— Phase 1 実装ログ、Codex レビュー反映記録、朝の手順CLAUDE.md— Claude Code 用ガイド(コマンド一覧・SQLite スキーマ・ハマりポイント)