Loading...
Loading...
Use this when the user wants to post a daily X/Twitter tweet inspired by one of their recently published WeChat Official Account articles. It selects the newest article that hasn't been tweeted yet, drafts 3 tweet candidates from it (from different angles — quote / metaphor / one-liner), posts the selected one via xurl, and records the action to history. Triggers — "Post a daily tweet", "Tweet from an article", "Today's tweet", "/wjs-tweeting-from-articles".
npx skill4agent add jianshuo/claude-skills wjs-tweeting-from-articlesstate/history.jsonlxurl POST/wjs-tweeting-from-articles/schedule daily /wjs-tweeting-from-articlesxurl POST /2/tweets/publish-skill/wjs-promoting-skillsscripts/pick-next-article.sh<folder><folder>/article.md| Angle | Content Selection | Example |
|---|---|---|
| A · Quote | Pick the most quotable sentence from the article, can add a lead-in | "When your pen tip goes blunt and can't write sharply — dip it in ink, twist it twice on the inkstone, and it regains its sharpness." |
| B · Metaphor | The core metaphor of the article + a sentence that connects it to the reader | "Writing prompts is like painting — it's a matter of muscle memory. You have to write a little every day." |
| C · Contrast | Cognitive flip in the form of "It's not X, it's Y" | "It's not about getting smarter, it's about getting into the groove." |
AskUserQuestionTWEET_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"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"angleABCother/wjs-tweeting-from-articles # Automatically select the latest untweeted article
/wjs-tweeting-from-articles <article-folder> # Explicitly specify an article
/wjs-tweeting-from-articles --dry-run # Draft only, no posting~/.claude/skills/wjs-tweeting-from-articles/
├── SKILL.md
├── scripts/
│ └── pick-next-article.sh # Find the latest untweeted article folder
└── state/
├── .gitignore # Exclude history.jsonl from public repo
└── history.jsonl # One JSON record per tweet, line-separated/schedule daily 09:00 /wjs-tweeting-from-articles| Do Not | Reason |
|---|---|
| Add hashtags (#AI #prompt) | Wang Jianshuo's X style doesn't use hashtags; adding them makes it sound like marketing |
| Tweet twice from the same article | One tweet per article; if the article is particularly long/multi-core, delete one entry from history and retweet next time |
| Include mp.weixin links in the tweet | Do not include by default; if you want to add it, put it in a reply |
| Post all 3 candidates | The user selects 1; if no selection is made, skip today |
| Create a tweet from scratch that's not in the article | Inspiration must be extracted from article.md; the value of this skill is that "the article is the source" |
| Let LLM rewrite the original text in its own style for "refinement" | Wang Jianshuo's original text is already concise enough; direct extraction is better than rewriting |
xurl whoami~/code/wechat-publish/articles/YYYY-MM-DD-*/article.md