mcpField
W
wjs-tweeting-from-articles

wjs-tweeting-from-articles

github.com/jianshuoマーケティング・グロース137147 回インストール今日更新
リポジトリ

wjs-tweeting-from-articles について

最近の WeChat 記事をもとに X の投稿を作成・公開するスキルです。ユーザーが選ぶ毎日1件の投稿フローに加え、複数記事をキューに入れて間隔を空けて公開する方法もあります。

主な機能

  1. 01最近の未投稿記事を選択
  2. 02記事から3つの投稿案を作成
  3. 03選択後に投稿を公開
  4. 04投稿済み記事を履歴で記録
  5. 05間隔を設けて投稿をキュー配信

活用シーン

  1. 01記事をもとに毎日1件投稿
  2. 02複数記事からの投稿を予約
  3. 03使用済み記事の再投稿を防止

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jianshuo/claude-skills --skill wjs-tweeting-from-articles

インストール後、Claude Code で/wjs-tweeting-from-articlesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

com.jianshuo.wjs-tweeting-from-articles.plist.template
daily.sh
setup.sh
uninstall.sh
scripts/
mirror-articles.py
pick-next-article.sh
pick-next-article.sh.bak.1779689674
state/
.gitignore
queue-2026-05-24.tsv

詳細

wjs-tweeting-from-articles

毎日 X に 1 件投稿します。インスピレーションは最近公開した公式アカウントの記事から直接拾います。記事が元で、tweet はそれをさらに短く抽出したものです。

Core Principle

記事はすでに王建硕風に一度磨かれており、tweet はそれをもう一段短くしたものにすぎません。 新たに考え直さず、article.md から最も引用したくなる一文/一段落をそのまま抜き出し、X のリズムに合わせて区切ります。

1 日に最大 1 件、1 つの記事につき投稿は 1 回だけです。 状態ファイル state/history.jsonl に、投稿済みの記事を記録します。重複投稿はしません。(例外:一括スケジュールモード——複数の記事を一度にキューに登録し、N 時間ごとに 1 件ずつ自動投稿します。詳しくは以下を参照。)

下書き保存ではなく、実際に投稿します。 ユーザーの確認後、すぐに xurl POST を実行します。失敗した場合は元の内容をそのまま出力し、ユーザーが再試行できるようにします。

When This Skill Fires

  • ユーザーが「今日の tweet」「X に投稿して」「記事からツイートして」と言ったとき
  • ユーザーが /wjs-tweeting-from-articles を実行したとき
  • ユーザーが /schedule daily /wjs-tweeting-from-articles を設定し、その後毎日自動で呼び出されたとき

When NOT to use

  • ユーザーが投稿したい内容が最近の公式アカウントの記事と関係ない場合——そのまま xurl POST /2/tweets を実行してください
  • ユーザーが投稿したいのが製品/スキルの宣伝の場合——/publish-skill または /wjs-promoting-skills を使ってください

Workflow

Step 1: 今日投稿する記事を選ぶ
scripts/pick-next-article.sh

投稿済みでない最新の記事のフォルダーパスを出力します(直近 1 週間以内から、日付の降順で最初の未投稿記事を探します)。すべて投稿済みの場合は、終了コード 0 で出力なしとし、「直近 7 日間の記事はすべて投稿済みです。今日は rest day にしましょう」とユーザーに伝えます。

ユーザーが特定の記事を投稿したい場合は、このスクリプトをスキップし、直接 <folder> を使います。

Step 2: 記事を読み、tweet 候補を 3 件作成する

<folder>/article.md を読み、以下の3 つの観点それぞれで 1 件ずつ草案を作成します。

観点選び方例
A · 名言本文から最も引用したくなる一文を選び、前置きを 1 文加えてもかまいません"筆先が鈍ると、鋭い言葉が書けなくなる。墨をつけて、硯の上で二回ほど回せば、また尖ってくる。"
B · 比喩記事の中心となる比喩と、その比喩を読者自身に引き寄せる一文"prompt を書くのは絵を描くのと同じで、手の感覚がものを言います。毎日少しは書きましょう。"
C · 対比「X ではなく、Y」という認識の転換"賢くなったんじゃない。手の感覚が戻ってきたんです。"

文字数の厳守事項:tweet は 280 文字以下(X の制限。中国語は 1 文字につき 2 文字として計算)——そのため、中国語の tweet は実質 140 文字以下です。120 文字以内に収めると余裕があって安心です。

スタイル:王建硕の語り口を保ちます——飾らず、日常的な比喩を使い、宣伝っぽい表現は避けます。ハッシュタグや @、絵文字は追加しないでください(原文にある場合を除きます)。mp.weixin のリンクも追加しないでください(デフォルト)。ユーザーからリンクを付けるべきか尋ねられた場合は、reply に添付できると伝えます。

Step 3: ユーザーに 1 件選んでもらう

AskUserQuestion を使って A/B/C の 3 件の候補と「その他(4 つ目の選択肢)」を提示します。ユーザーが 1 件選んだら Step 4 に進みます。

Step 4: X に実際に投稿する
TWEET_TEXT='<picked text>'
JSON=$(jq -nc --arg text "$TWEET_TEXT" '{text:$text}')
resp=$(xurl -X POST -d "$JSON" /2/tweets)
# Don't use `jq -r '.data.id'` here — X API returns raw newlines in the echoed
# `text` field, which strict jq rejects with "control characters must be escaped".
# Grep the id directly instead.
TWEET_ID=$(printf '%s' "$resp" | grep -oE '"id":"[0-9]+"' | head -1 | sed -E 's/.*"([0-9]+)".*/\1/')
[[ -n "$TWEET_ID" ]] || { echo "POST failed: $resp"; exit 1; }
echo "https://x.com/jianshuo/status/$TWEET_ID"

成功したら、tweet_id と URL を取得してユーザーに伝えます。

Step 5: history に記録する
HIST="$HOME/.claude/skills/wjs-tweeting-from-articles/state/history.jsonl"
SLUG=$(basename "$FOLDER")
jq -nc --arg date "$(date +%F)" --arg slug "$SLUG" --arg angle "$ANGLE" \
       --arg tweet_id "$TWEET_ID" --arg text "$TWEET_TEXT" \
       '{date:$date,slug:$slug,angle:$angle,tweet_id:$tweet_id,text:$text,status:"posted"}' \
  >> "$HIST"

angle は A/B/C/other のいずれかです。

Step 6: 完了を伝える

ユーザーに以下を伝えます。

  • tweet の URL
  • 記事(slug)
  • angle
  • 今日の history 行を記録済みであること

Inputs

/wjs-tweeting-from-articles                       # 自动挑最近一篇没推过的
/wjs-tweeting-from-articles <article-folder>      # 显式指定
/wjs-tweeting-from-articles --dry-run             # 草稿不发

File Layout

~/.claude/skills/wjs-tweeting-from-articles/
├── SKILL.md
├── scripts/
│   ├── pick-next-article.sh        # 找最近一篇未推的 article folder
│   └── post-next-from-queue.sh     # 批量排期模式:每次发队列里下一条,自节流
└── state/
    ├── .gitignore              # 屏蔽 history.jsonl 不被推到 public repo
    ├── history.jsonl           # 每条 tweet 一行 JSON record
    ├── queue-<DATE>.tsv        # 批量模式:待发队列 idx/slug/text
    ├── queue-cursor            # 批量模式:下一条序号
    └── last-post-epoch         # 批量模式:上次发出的时间戳(节流用)

一括スケジュールモード(複数の記事を一度に予約し、N 時間ごとに 1 件投稿)

複数の記事を一度に投稿したい場合(よくある例:wjs-mining-articles で長時間の対談から十数本の記事を掘り起こした場合)は、このモードを使います。一度に連続投稿すると X にスパムと判定されるため、キューに登録し、一定の間隔で自動投稿します。

記事ごとに angle を AskUserQuestion で選ばない理由:十数本の記事それぞれに A/B/C を用意すると多すぎます。各記事から最も引用したくなる一文を1 件だけ直接抜き出し(120 文字以下、王建硕の語り口、ハッシュタグ/絵文字/リンクなし、句読点の前後に半角スペースを入れる)、候補をすべてユーザーに一度に見せて、投稿の間隔を決めてもらいます。確認後、スケジュールを設定します。

仕組み(scripts/post-next-from-queue.sh と毎時の cron。スクリプト自体が投稿間隔を制御します):

# 1. 队列文件:state/queue-<DATE>.tsv,每行  idx<TAB>slug<TAB>text
# 2. cursor: state/queue-cursor(下一条序号);last-post-epoch(上次发的时间)
# 3. 立刻发第一条(FORCE 绕过节流,顺便验证 xurl 能发):
FORCE=1 bash scripts/post-next-from-queue.sh
# 4. 装 cron:每小时跑,脚本只在距上次 ≥ MIN_GAP(默认 4h)才真发:
( crontab -l 2>/dev/null | grep -v post-next-from-queue.sh; \
  echo "5 * * * * /bin/bash $HOME/.claude/skills/wjs-tweeting-from-articles/scripts/post-next-from-queue.sh >/dev/null 2>&1" ) | crontab -

スクリプトのポイント:単一マシン上のロック(同時実行を防止)、投稿に失敗した場合は cursor を進めない(次の 1 時間後に再試行)、投稿に成功した場合のみ history.jsonl に記録して cursor を進める、キューの投稿が完了したら、自身の cron 行を自動削除します。間隔を変更するには MIN_GAP(秒)を使います。

Daily 自動化(任意)

毎日自動で実行するには、以下を設定します。

/schedule daily 09:00 /wjs-tweeting-from-articles

または cron に設定します。ただし、デフォルトでは自動実行しません——毎日ユーザーが angle を確認して選ぶほうが確実です。

Anti-Patterns

しないこと理由
ハッシュタグ(#AI #prompt)を追加する王建硕の X ではハッシュタグを使いません。追加すると宣伝っぽくなります
同じ記事から 2 件投稿する1 つの記事につき 1 件です。記事が特に長い/中心となるテーマが複数ある場合は、次回の実行時に history から該当する 1 行を削除して再投稿してください
tweet に mp.weixin のリンクを含めるデフォルトでは含めません。付けたい場合は reply に記載してください
3 件の候補をすべて投稿するユーザーが 1 件選びます。選ばれなかった場合は、その日の投稿をスキップします
記事にない tweet をでっち上げるインスピレーションは必ず article.md から拾います。このスキルの価値は「記事が元」であることです
LLM が原文のスタイルを勝手に変えて「要約」する王建硕の原文はすでに十分簡潔です。書き直すより、そのまま抜き出してください

Dependencies

  • xurl:xurl whoami でユーザー名が返ること(認証 OK)
  • jq:xurl が返す JSON を解析します
  • ~/code/wechat-publish/articles/YYYY-MM-DD-*/article.md が存在すること:元の記事

コメント