本文へ移動
cccskills
無料GitHub で公開

substack-post

Claudeが生成したMarkdown文章をSubstackに下書き投稿するスキル。「Substackに投稿して」「下書きにして」「Substackの記事にして」「このMarkdownをSubstackへ」などの依頼、またはMDファイルを添付した上で、投稿指示があった場合に必ず使用する。Substackへの投稿・入稿・記事作成・下書き保存が話題になったら必ずこのスキルを使うこと。どのSubstackニュースレターに対しても使える汎用スキル。

インストール方法を見る

含まれるファイル(2)

  • SKILL.md16.1 KB
  • references/post_executor.js9.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Substack 下書き投稿スキル

会話内で生成した文章や添付MDファイルをSubstackエディタへ自動入力し、タイトル・サブタイトル・セクション・SEO・URLスラッグを設定して下書き保存する。タグ設定は人間が行うため、投稿完了後にタグ候補を提示する。特定のニュースレターに固定されない汎用スキルで、投稿先・セクション名・タグ一覧はユーザーごとに異なるため、Claudeのメモリ機能を使って前回までの情報を引き継ぐ。

設計思想

  • computer ツール(スクリーンショット→視覚判断)は一切使わない
  • fetch・ローカルサーバは使わない:Chrome の Private Network Access 制限により HTTPS ページからのローカル fetch はブロックされるため、executor JS を直接 javascript_tool へ渡すインライン方式を使う
  • 本文の JSON エンコードは bash に任せる:バッククォートや ${ を含む Markdown を Claude が手動エスケープすると誤りが出るため、python3 に委ねる
  • タグ設定は自動化せず、完了後に候補を提示する
  • 投稿先ドメイン・セクション名・タグ一覧はハードコードしない:ユーザーごと・ニュースレターごとに異なるため、都度メモリを確認し、指定されていればそれを使う。ファイルへの保存はしない(このスキルはClaudeチャットでの利用を前提とし、セッションをまたぐ永続化はメモリ機能に委ねる)

全体フロー概要

フェーズ内容
フェーズ 1投稿コンテンツ(本文Markdown)を取得する。1500文字以上なら貼り付け方法も確認対象にする
フェーズ 2メモリを確認し、不足フィールド(本文貼り付け方法を含む)をユーザーに確認する
フェーズ 3「おまかせ」項目とSEO説明文を自動生成する
フェーズ 4エディタへ移動 → 本文書き込み → JSONエンコード → IIFE生成 → javascript_tool で実行
フェーズ 5完了をリンクで報告し、タグ候補を提示する。新しく判明した情報はメモリへの保存を提案する

前提条件

  • ブラウザで対象のSubstackニュースレターにログイン済み
  • Claude in Chrome コネクタが接続済み
    • navigate — URLへ移動
    • javascript_tool — アクティブタブで JavaScript を実行
  • bash_tool が利用可能(本文の JSON エンコードに使用)
  • python3 が利用可能(JSON エンコードに使用)
  • computer ツールは使用しない

フェーズ 0:投稿先の特定(メモリ確認)

  1. 会話内で投稿先のSubstackサブドメイン(例: xxxx.substack.com)がすでに指定されていれば、それを使う(質問しない)
  2. 指定がなければ、メモリに保存された投稿先ニュースレターの情報を確認する
    • 1件だけ見つかった場合:「前回は xxxx.substack.com に投稿しましたが、今回もこちらでよいですか?」と確認する
    • 複数件見つかった場合:候補を提示して選んでもらう
    • 見つからない場合:投稿先のサブドメインをユーザーに質問する
  3. 新しい投稿先が判明した場合は、後述のフェーズ5で記憶を提案する

以降、確定した値を SUBSTACK_DOMAIN(例: xxxx)として扱う。


フェーズ 1:コンテンツを受け取る

種類取得方法
会話内で生成した文章直前のアシスタント出力をMarkdownとして使用。あるいは、生成されたmdファイル
添付Markdownファイルファイル内容を読み込んでMarkdownとして使用

本文が取得できない場合は、ユーザーに確認してから進む。

文字数チェック(自動貼り付けの時間・トークン消費に関わる)

本文Markdownの文字数を数える。1500文字以上の場合、フェーズ2の質問に以下を追加する:

本文が約◯◯◯文字あります。JavaScriptによる自動貼り付けは文章量に比例して時間・トークンを消費する場合があります。どちらの方法で本文を反映しますか?

選択肢動作
Claudeが自動で貼り付ける従来どおりフェーズ4 Step 4 で自動ペーストする
自分で貼り付けるフェーズ4 Step 4(本文ペースト)を スキップ。タイトル・サブタイトル・セクション・SEO・URLスラッグは自動設定し、本文だけ手動貼り付けを依頼する

この選択結果を BODY_PASTE_MODE("auto" または "manual")として以降使用する。1500文字未満の場合は質問せず BODY_PASTE_MODE = "auto" とする。


フェーズ 2:不足フィールドの確認・質問

  1. 会話内ですでに決まっている項目は質問しない
  2. セクションについては、まずメモリに SUBSTACK_DOMAIN でよく使われるセクション名の記録がないか確認する。見つかれば選択肢の先頭に「おまかせ(前回と同じ: ◯◯)」として提示する
  3. 不足している項目(および該当する場合は上記の本文貼り付け方法)を ask_user_input_v0 でまとめて質問する
  4. 各質問の最初の選択肢は必ず「おまかせ」
  5. SEO説明文は常に自動生成するため質問しない
  6. タグは質問しない(完了後に候補提示)

質問フィールドと選択肢・生成ルール

項目選択肢おまかせ時の生成ルール
タイトル(必須)おまかせ(Claudeが生成) / 指定する本文の主題を端的に表す10〜30文字
サブタイトル(任意)おまかせ(生成する) / 指定する / なし本文の要旨を1〜2文で表現
セクション(任意)おまかせ(メモリにあればそれを使用、なければ「なし」) / 指定する / なしメモリの記録があればそれを使用。なければセクション未設定のまま投稿
URLスラッグ(任意)おまかせ(英語で自動生成) / 指定するタイトルの意味を英訳しハイフン区切り(例: claude-substack-auto-post)
SEOタイトル(任意)おまかせ(タイトルと同じ) / 指定するタイトルと同じ文字列
本文貼り付け方法(1500文字以上のみ)Claudeが自動で貼り付ける / 自分で貼り付ける該当なし(必ずどちらか選んでもらう)

フェーズ 3:おまかせ項目・SEO説明文

「おまかせ」を選んだ項目を上記の生成ルールに従って本文から生成する。

SEO説明文(常に自動生成・質問なし)

Substackは記事冒頭の文章をSEO説明文に自動入力するが内容が不適切なため、必ず上書き生成する。

生成ルール:

  • 文字数:50〜160文字
  • 記事の価値・対象読者・得られる知識を含む
  • 独立した要約文として書く

フェーズ 4:Substackエディタへの入力

ポイント: fetch・ローカルサーバを使わず、変数・本文・executor ロジックを一体化した IIFE を javascript_tool に直接渡す。本文の JSON エンコードだけ bash に委ねることでエスケープ誤りを防ぐ。

Step 1:新規投稿ページへ移動

navigate ツールで、フェーズ0で確定した SUBSTACK_DOMAIN を使い以下のURLへ移動する:

https://{SUBSTACK_DOMAIN}.substack.com/publish/post?type=newsletter

Step 2:本文を書き込む

Write ツールで /tmp/body.md に記事 Markdown をそのまま書き込む(BODY_PASTE_MODE が "manual" の場合もスキップせず書き込む。文字数チェックや万一の自動化に使うため)。

Step 3:本文を JSON エンコードする(bash)

python3 -c "import json; print(json.dumps(open('/tmp/body.md').read()))"

出力は "..." 形式の1行。これを次のステップで BODY_MD の値として使う。

Step 4:executor ロジックを読み込む

Read ツールで references/post_executor.js を1回で全体を読み込む(offset/limit を指定しない)。

Step 5:完全な IIFE を javascript_tool に渡す

Step 3 の JSON 文字列・Step 4 のコードを組み合わせ、以下の形式で javascript_tool の text に渡す。

重要: javascript_tool は渡されたテキストを「単一の式」として評価し、その完了値(Promiseなら解決後の値)を返す。トップレベルの await / return は使えないため、必ず (async () => { ... })() の IIFE 式で包むこと。

(async () => {
  const TITLE     = '実際のタイトル';
  const SUBTITLE  = '実際のサブタイトル';  // null なら: null
  const SECTION   = '実際のセクション名';  // 不要なら: null
  const SEO_TITLE = TITLE;
  const SEO_DESC  = '実際のSEO説明文(50〜160文字)';
  const URL_SLUG  = 'actual-url-slug';
  const BODY_MD   = [Step 3 の出力をそのまま貼る];
  const BODY_PASTE_MODE = 'auto'; // または 'manual'(フェーズ1.5で選択された値)

  // ↓ Step 4 で読み込んだ post_executor.js の内容をそのまま展開 ↓

})()

Step 6:戻り値で分岐

戻り値対応
{...R, url}(正常)フェーズ5へ
{error:'editor_not_loaded', url}再試行しない(下書き重複の恐れ)。ユーザーに報告し、エディタページの再読込を促す

フェーズ 5:完了確認・報告

JSスクリプトの戻り値(R オブジェクト)を確認し、以下の形式でユーザーに報告する。

タグ候補

  1. メモリに SUBSTACK_DOMAIN のタグ一覧(よく使うタグリスト)が保存されていれば、その中から内容に合うものを最大3〜5つ選ぶ
  2. 保存されていなければ、本文の内容から最大3〜5個のタグ候補を新規に考案する(自動入力はしない)

メモリへの保存提案

以下のいずれかに該当する場合、報告の末尾で「今後のために覚えておきますか?」とユーザーに確認する(強制はしない):

  • フェーズ0で新しい投稿先(SUBSTACK_DOMAIN)が判明した
  • フェーズ2でセクション名を新規に指定してもらった(メモリに記録がなかった)
  • タグ候補をメモリなしで新規に考案した(ユーザーが今後も使いたいタグ一覧として確定した場合)

ユーザーが同意した内容のみメモリに保存する。

報告フォーマット

✅ Substackへの下書き投稿が完了しました。

📄 投稿を確認: [投稿タイトル](https://{SUBSTACK_DOMAIN}.substack.com/publish/post/[ID])

---
⚠️ 手動設定が必要な項目:
- タグ(候補を下記に提示)
(セクション・SEO等で失敗があればここに追記)
(BODY_PASTE_MODEが"manual"の場合は「本文の貼り付け」もここに追記)

🏷️ タグ候補(設定モーダルの「タグ」欄から追加してください):
1. [タグ名1]
2. [タグ名2]
3. [タグ名3]

BODY_PASTE_MODE が "manual" の場合、上記リンクとともに「本文をエディタに貼り付けてください」と伝え、本文Markdown全文をコピーしやすい形(コードブロック)で併記する。

URL の取得方法

JSスクリプトの戻り値 url フィールド(location.href)を使う。 必ずクリッカブルなMarkdownリンク形式で提示する(コードブロック禁止)。

失敗項目の報告

R フィールドfalse だった場合の報告内容
bodyfalse=「本文の貼り付けに失敗しました。手動で貼り付けてください」/'skipped'=BODY_PASTE_MODEが"manual"だったため意図的にスキップ(失敗ではない)
section「セクションの設定に失敗しました。手動で設定してください」
modal「設定モーダルが開けませんでした。⚙ボタンを手動で押してください」
seoForm1「SEOタイトル・説明文の保存に失敗しました。手動で設定してください」
seoForm2「URLスラッグの保存に失敗しました。手動で設定してください」
done「完了ボタンが押せませんでした。モーダルを手動で閉じてください」

補足: 「完了」クリック後、モーダルが実際に閉じるまで数秒の退場アニメーションがかかる。R.done が true であれば処理としては成功しており、モーダルが即座に閉じて見えなくてもエラーではない。


参照ファイル

  • references/post_executor.js — Substackエディタ操作のJSロジック本体。変数宣言なし・IIFEなし。フェーズ4 Step 4 で Read して IIFE 内に展開する

クイックリファレンス

項目方式
投稿先ドメインメモリ確認 → なければ質問(フェーズ0)。ファイルへの保存はしない
セクション・タグ一覧メモリにあれば「おまかせ」の既定値として提示
本文が1500文字以上「自分で貼り付け/Claudeが自動貼り付け」を質問(フェーズ1.5)→ BODY_PASTE_MODE
本文書き込みWrite ツールで /tmp/body.md
本文 JSON エンコードbash: python3 -c "import json; print(json.dumps(open('/tmp/body.md').read()))"
executor 読み込みRead ツールで references/post_executor.js(1回・全体)
JS 実行変数 + BODY_MD + executor を IIFE で包んで javascript_tool に直接渡す
fetch・サーバー使用しない(Chrome PNA 制限によりブロックされる)
タイトルJS: [data-testid="post-title"] に React setter でセット(UI言語非依存)
サブタイトルJS: textarea.subtitle(クラストークン。placeholder不使用・UI言語非依存)
セクションJS: simulatePointerClick → [role="menuitem"](NFKC正規化照合。セクション名はユーザー命名のため言語非依存)
本文JS: ClipboardEvent + DataTransfer(HTML + plaintext)
設定モーダルJS: [data-testid="settings-button"] クリック→[data-testid="settings-modal"] [role="combobox"] の出現で読み込み確認
SEOアコーディオンJS: モーダル内で svg.lucide-chevron-down/up を持つ cursor-pointer 要素を特定(見出しテキスト不使用)
SEO Form 1/2JS: アコーディオン内の <form> を2つ取得し、textarea を含む方=タイトル+説明文、input[name="code"] を含む方=URLスラッグ。保存ボタンはラベル文字列ではなく各 <form> 内の button[type="submit"](動的出現)を待ってクリック
タグ自動入力しない → 完了後に候補を提示
完了ボタンJS: [data-modal-role="footer"] button(ラベル文字列不使用)。クリック後、閉じるまで数秒のアニメーション遅延がある
確認URLMarkdownリンク形式(コードブロック禁止)

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

ai-fluency-check

無料日本語概要

/ai-fluency-check と入力されたときだけ起動するAIフルーエンシー自己評価スキル。Anthropicの4D AI Fluency Framework(Delegation / Description / Discernment / Diligence)に基づく18項目のルーブリックを使い、対話的に自己評価する。過去の評価記録と比較して成長を可視化し、研究根拠にもとづく改善アドバイスと参考文献を提供する。ユーザーが /ai-fluency-check と明示的に入力した場合のみ使用すること。自動起動・推測起動は一切しない。

toiee-kameda/libehub-skills22026年9月18日 更新

coach-me

無料日本語概要

/coach-me と入力されたときだけ起動する、Learning by Doing コーチングスキル。現在の会話を分析し、Anthropicの4D AIフルーエンシーフレームワーク(Delegation / Description / Discernment / Diligence)に基づいて「うまくできていた点」「改善できる点」「次回に使えるプロンプト例」をフィードバックする。オプションで /coach-me 詳細 または /coach-me --detail と入力すると次元ごとの深掘りフィードバックを提供。自動起動は一切しない。ユーザーが /coach-me と明示的に入力した場合のみ使用すること。

toiee-kameda/libehub-skills22026年9月18日 更新

context-builder

無料日本語概要

/context-builder と入力されたときだけ起動する、コンテキストドキュメント作成インタビュースキル。人・プロジェクト・プロダクトなどの対象について、1問ずつ掘り下げる対話を通じて情報を集め、今後 Claude との対話の冒頭に貼り付けるための context.md(自分についてなら aboutme.md)を作り上げる。/context-builder me(自分=aboutme)/ project / product のように対象を指定できる。「aboutme を作りたい」「プロジェクトのコンテキストをまとめたい」「プロダクトの前提情報を用意したい」ときに使う。自動起動はせず、ユーザーが /context-builder と明示的に入力した場合のみ使用すること。

toiee-kameda/libehub-skills22026年9月18日 更新

copywriting-grill

無料日本語概要

セールスレターを書き始める前に、素材(読者・約束・抵抗・証拠・価格や保証などの確定事項)を一問ずつ執拗に聞き出すスキル。「セールスレターについて質問攻めして」「レターを書く前にヒアリングして」「素材を聞き出して」「grillして」、または具体性の乏しいブリーフのままセールスレター執筆を依頼されたときに使う。コピーライティングの「構想メモ」を、書く前に埋めるための対話手順。このスキル自体はレター本文を書かない。

toiee-kameda/libehub-skills22026年9月18日 更新

craft-whiteboard-excalidraw

無料日本語概要

Craft のホワイトボードに Excalidraw 要素を追加・描画するときに必ず使うスキル。 whiteboardElements_add を使う場面、Craft ホワイトボードに図を描く場面、 Excalidraw の JSON を Craft に反映させる場面では常にこのスキルを参照すること。 label 内包記法や cameraUpdate を使うと Craft でテキストが消えるため、 このスキルの互換フォーマットに従う必要がある。

toiee-kameda/libehub-skills22026年9月18日 更新

eli5

無料日本語概要

5歳の子どもにもわかるように、要望されたテーマを説明します。ユーザーが /eli5 "テーマ" と入力したとき、または何かの仕組みをとても簡単な図解で説明してほしいと頼んだときに使います

toiee-kameda/libehub-skills22026年9月18日 更新

toiee-kameda のスキルをすべて見る

このスキルの問題を報告する