Skip to content
cccskills
FreePublished on GitHub

wjs-tweeting-from-articles

Use when the user wants to post a daily X/Twitter tweet inspired by one of their recently-published 微信公众号 articles. Picks the newest article that hasn't been tweeted yet, drafts 3 tweet candidates from it (different angles — quote / metaphor / one-liner), posts the chosen one via xurl, records to history. Triggers — "每天发一个 tweet", "从文章里发推", "今天的 tweet", "/wjs-tweeting-from-articles".

The English summary is being prepared. Showing the original description.

Works withX (Twitter)

Run score Not tested

See how to install

Files included (10)

  • SKILL.md7.7 KB
  • com.jianshuo.wjs-tweeting-from-articles.plist.template1.0 KB
  • daily.sh6.0 KB
  • scripts/mirror-articles.py2.1 KB
  • scripts/pick-next-article.sh2.7 KB
  • scripts/pick-next-article.sh.bak.17796896741.7 KB
  • setup.sh2.4 KB
  • state/.gitignore8 B
  • state/queue-2026-05-24.tsv4.4 KB
  • uninstall.sh510 B

SKILL.md (original)

Review the instructions the agent will receive before you install.

wjs-tweeting-from-articles

每天一条 X tweet,灵感直接从最近发的公众号文章里抠。文章是源头,tweet 是更短的萃取。

Core Principle

文章已经过了一轮王建硕式的精炼,tweet 只是再短一格的版本。 不要重新构思——从 article.md 里直接抠最 quotable 的一句 / 一段,按 X 的节奏切。

一天最多一条,一篇文章只推一次。 状态文件 state/history.jsonl 记录哪些 article 已经推过;不重复。(例外:批量排期模式——一次把多篇排进队列、按每 N 小时一条自动发,见下文。)

真发,不暂存。 用户确认后立刻 xurl POST。失败原文 dump 给用户重试。

When This Skill Fires

  • 用户说「今天的 tweet」/「发一条 X」/「从文章里发推」
  • 用户跑 /wjs-tweeting-from-articles
  • 用户设了 /schedule daily /wjs-tweeting-from-articles 之后每天自动调

When NOT to use

  • 用户要发的内容和最近的公众号文章无关——直接 xurl POST /2/tweets 即可
  • 用户要发的是产品 / skill 推广——用 /publish-skill 或 /wjs-promoting-skills

Workflow

Step 1: 挑今天要推的文章

scripts/pick-next-article.sh

输出最新一篇还没推过的文章的 folder 路径(最近一周内,按日期倒序找第一个未推的)。已经全推完 → 退出 0、空输出,告诉用户「最近 7 天的文章都推过了,今天 rest day」。

如果用户想推特定那一篇:跳过此脚本,直接用 <folder>。

Step 2: 读文章 + 草拟 3 条 tweet 候选

读 <folder>/article.md,按下面三个角度各起草一条:

角度选材例子
A · 金句从文中挑一句最 quotable 的,可以加一句铺垫"笔头钝了,写不出锋——蘸点墨,在砚台上转两圈,重新有了尖。"
B · 比喻文章的核心比喻 + 一句把比喻落到读者头上"写 prompt 跟画画一样,是手感活儿。每天都得写点。"
C · 反差「不是 X,是 Y」式的认知翻转"不是变聪明,是手感来了。"

长度硬约束:tweet ≤ 280 字符(X 限制;中文每字算 2)——所以中文 tweet 实际 ≤ 140 字。留 buffer 到 120 字以内比较稳。

风格:保留王建硕语气——平实、家常比喻、不写营销腔。不要加 hashtags、不要加 @、不要加 emoji(除非原文有)。不要加 mp.weixin 链接(默认);如果用户问要不要带链接,提示可以 reply 里附。

Step 3: 让用户挑一条

用 AskUserQuestion 给出 A/B/C 三条候选 + 「四选其他」。用户选一条之后进入 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 小时一条)

一次要发很多篇(典型来源:wjs-mining-articles 从一场长对谈挖出十几篇文章),用这个模式——一次连发会被 X 判刷屏,所以排成队列、按固定间隔自动发。

为什么不用 AskUserQuestion 逐篇选 angle:十几篇 × A/B/C 太多。每篇直接抠一条最 quotable 的(≤120 字、王建硕语气、无 hashtag/emoji/链接、带盘古之白),列全文给用户一次过目 + 定节奏,确认后排期。

机制(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(下小时重试)、发成功才写 history.jsonl 并推进、队列发完自动删掉自己的 cron 行。改间隔用 MIN_GAP(秒)。

Daily 自动化(可选)

要每天自动跑:

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

或写 cron。但默认不自动跑——每天人工确认 angle 选哪条更稳。

Anti-Patterns

不要原因
加 hashtags(#AI #prompt)王建硕的 X 风格不用 hashtag,加了变营销腔
同一篇文章推两条一篇一推;如果文章特别长 / 多核心,下次跑时把它从 history 删一行重推
tweet 里塞 mp.weixin 链接默认不带;想带就放 reply 里
把 3 条候选都发出去用户挑 1 条;不挑 = 跳过今天
凭空生造一条不在文章里的 tweet灵感必须从 article.md 抠;这条 skill 的价值就是「文章是源」
LLM 自己改原文风格做"提炼"王建硕原文已经够紧;直接抠 > 重写

Dependencies

  • xurl:xurl whoami 能返回用户名(auth OK)
  • jq:解析 xurl 返回的 JSON
  • 存在 ~/code/wechat-publish/articles/YYYY-MM-DD-*/article.md:源文章

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

王建硕的思维框架与表达方式。基于 7 份深度调研(约 100 万词英文博客 + 约 109 万字中文博客, 2002–2022,全部一手)提炼出 7 个核心心智模型、10 条决策启发式和完整的双语表达 DNA。 用途:以王建硕的身份和声音写作、回应、思考——他平实、诚恳、好奇,爱用家常比喻和自造词, 在具体和抽象之间反复架梯子,从不写自己没亲身验证过的东西。 当用户提到「用王建硕的视角」「王建硕会怎么看」「王建硕模式」「像王建硕一样写」 「Jian Shuo Wang perspective」「切换到王建硕」时使用。 即使用户只是说「帮我用王建硕的角度想想」「如果是王建硕会怎么写这篇」也应触发。 一旦激活,本次对话后续所有回应都保持王建硕身份,直到用户明确说「退出」—— 不需要每轮重新点名。 不适用:用户要的是关于王建硕本人的客观介绍 / 事实查询(「王建硕是谁」「他哪年创业的」), 那种问题正常回答即可,不要进入角色扮演。

The English summary is being prepared. Showing the original description.

jianshuo/claude-skills137Updated Oct 16, 2026

Use when the user asks to audit what's wrong with a project, "make it right", "看看项目出了什么问题", "为什么用户的需求还没上线", "为什么没提交App Store", "为什么没新build", or wants a holistic state-of-the-project check covering unmerged branches, stalled PRs, failed GitHub Actions, stale builds, plan drift (TODOS.md / ROADMAP), unreleased commits, and log errors. Runs read-only investigation, presents a grouped checklist, fixes only after explicit user confirmation. Aware of the Cathier iOS app workflow (Xcode + fastlane + auto-merge @claude PRs from in-app feedback).

The English summary is being prepared. Showing the original description.

jianshuo/claude-skills137Updated Oct 16, 2026

Use when the user has a video + an SRT and wants the subtitles either burned into the pixels (libass, always-visible) or soft-muxed as a togglable track. Also handles the final composite step for the localization pipeline — burn subs, mix a dub track, and keep the original audio as a low-volume bed, all in ONE ffmpeg encode (no cascade). Verifies libass availability and auto-downloads a static evermeet ffmpeg build when Homebrew's stripped binary lacks it. Triggers — "烧字幕", "硬字幕", "burn subtitles", "burn-in subs", "embed subtitle", "soft mux SRT", "把字幕烧进视频", "做最终合成".

The English summary is being prepared. Showing the original description.

jianshuo/claude-skills137Updated Oct 16, 2026

Use when the user complains about spam on his X/Twitter posts — 同城面付 / 寻固炮 / 线下上门 / 免费破处 这类引流号在他推文下刷的 emoji 垃圾回复 — and wants them removed. Covers the last 7 days (X recent-search window). Triggers — "把这些spam删掉", "清理X垃圾回复", "推文下面好多引流号", "clean spam replies", "/wjs-cleaning-spam".

The English summary is being prepared. Showing the original description.

jianshuo/claude-skills137Updated Oct 16, 2026

Use when the user wants a 王建硕-style WeChat article (article.md) turned into a narrated short MP4 video — TTS voiceover via 火山引擎 Volcano TTS, HyperFrames CSS/GSAP animation per scene, subtle SFX, abstract watercolor background, full pipeline rendering to 1080×1920 portrait MP4 (30-90s). Triggers — "把这篇文章做成视频", "做一个解说视频", "讲解视频", "/wjs-converting-text-to-video".

The English summary is being prepared. Showing the original description.

jianshuo/claude-skills137Updated Oct 16, 2026

Use when migrating a WordPress site to a Hugo static site on GitHub Pages from a WXR export (.xml) plus the wp-content/uploads folder — preserving /archives/<id>/ URLs, localizing images, and deploying via GitHub Actions. Triggers — "把 WordPress 迁成 Hugo", "wordpress 转静态站", "migrate WordPress to Hugo", "WXR to Hugo", "publish WordPress to GitHub Pages", "/wjs-converting-wp-to-hugo".

The English summary is being prepared. Showing the original description.

jianshuo/claude-skills137Updated Oct 16, 2026

See all skills by jianshuo

Report a problem with this skill