Treat "writing good tweets" as engineering:continuously revise prompts/x/prompt.md, use impression data to see which version is best, and dig out "what content features correlate with high impressions" to feed back into the next version. It is the twin of [[wjs-x-increasing-follower]]—that one measures profile→follow conversion rate, this one measures prompt→impressions of each tweet。
Core Principle
impressions are mainly determined by the source article / topic; the prompt is only a second-order factor. A good article paired with any prompt can blow up. So honestly look at it on two levels:
| What to look at | Signal strength | How to use it |
|---|---|---|
| prompt version comparison(which prompt version's tweets have a higher median impression) | weak (dominated by the article, requires a large number of samples) | directional reference; don't pass judgment until enough samples are accumulated |
| content features(angle A/B/C, length, hook—what the prompt directly controls) | relatively strong (under the same topic, only feature differences reveal the prompt's craftsmanship) | the basis for truly feeding back into the prompt |
So: version comparison gives direction, content features give leverage. Don't treat version judgments as causality.
Use the median, not the mean, for judgments(impressions are extremely long-tailed; one viral tweet can fool the mean);at least 5 mature tweets per versionbefore making a version-level judgment;maturity window = 3 full days since posting(tweets that are still too new with impressions still rising are not counted).
Rollback is a first-class citizen: the prompt is in git, rollback = git checkout <旧SHA> -- prompts/x/prompt.md。
version = the git short-SHA of prompt.md
Which prompt version each tweet is attributed to,derive by time: tweet posting time T → prompts/x/prompt.md the last commit in git history with time ≤ T = the version that tweet used.No need to modify the Action, and historical tweets can be backfilled. Tweets earlier than when the prompt file existed → prompt_sha=null(pre-prompt)。
Where the data comes from
the impressions of each tweet X API is unstable, rely on Content CSV export:x.com/i/account_analytics → Content tab → export CSV (including Post id / Impressions / Engagements …) → drop it into inbox/。Post id is tweet_id, and it matches the posting history.
When This Skill Fires
- "change X's prompt" "which prompt version is best" "what content gets high impressions" "X content improvement"
- Run
/wjs-x-improving-content
When NOT to use
- gaining followers / changing profile → [[wjs-x-increasing-follower]]
- just posting one tweet →
/wjs-tweeting-from-articles - promoting the skill →
/wjs-promoting-skills
Workflow
The script is in scripts/, the state is in state/. First cd to the skill directory.
Step 1 — Ingest the data
python3 scripts/ingest-tweets.py /path/to/content.csv
join Content CSV + posting history (~/.claude/skills/wjs-tweeting-from-articles/state/history.jsonl, with slug/angle) → state/tweets.jsonl, derive by date prompt_sha, compute char_len and mature(≥3 days). upsert; re-running a longer export is safe.
Step 2 — Mine content features (the core, immediately useful)
python3 scripts/analyze-content.py # 成熟推
python3 scripts/analyze-content.py --all # 含未成熟(angle 样本更全)
Break down impression median + engagement rate by angle / length / source, list the highest/lowest tweets.This layer tells you where the prompt should be changed.
Step 3 — Propose a prompt change (with a hypothesis)
Based on the signals from Step 2, make prompts/x/prompt.md toa falsifiable change(e.g. "prefer short sentences", "when unsure, prioritize the golden-line angle"). After changing, commit:
cd ~/code/wechat-publish
# 编辑 prompts/x/prompt.md ...
git add prompts/x/prompt.md && git commit -m "x prompt: <一句话改了啥>"
NEW_SHA=$(git log -1 --format=%h -- prompts/x/prompt.md)
Register as a numbered experiment:
python3 ~/.claude/skills/wjs-x-improving-content/scripts/ledger.py register "$NEW_SHA" \
--hypothesis "短句比长句 impression 高,prompt 收紧到 80 字以内"
After that, every 6h the Action automatically generates tweets with the new version.Change only one thing at a time, otherwise you can't tell which change had the effect.
Step 4 — Judge after enough samples
python3 scripts/evaluate.py # 各版本中位 impression + 相邻版本 Δ% 判决
Δ ≥ +10% → keep;Δ ≤ -10% → rollback; in between → flat. Insufficient samples (<5 mature tweets) shows measuring.
- keep:
ledger.py keep <SHA> --note "短句 +18%" - rollback (ask Wang Jianshuo first):
thengit -C ~/code/wechat-publish checkout <旧SHA> -- prompts/x/prompt.md git -C ~/code/wechat-publish commit -m "x prompt: rollback to <旧SHA>"ledger.py rollback <SHA> --note "短句反而掉了"
Step 5 — Dashboard
python3 scripts/scoreboard.py # 写并打印 state/SCOREBOARD.md
Current status + version leaderboard + content features (angle) + to-do. To show Wang Jianshuo, send this.
Data model (state/)
tweets.jsonl—— one row per tweet:{tweet_id, date, impressions, engagements, likes, replies, reposts, new_follows, char_len, text, slug, angle, source(bot|manual), prompt_sha, age_days, mature}versions.jsonl—— one row per prompt version:{id, prompt_sha, hypothesis, registered, status(active|kept|rolled_back), verdict, notes}SCOREBOARD.md—— generated output
Default parameters (to change, pass a flag / edit _common.py)
- Maturity window
MATURITY_DAYS=3 - Minimum samples for version judgment
MIN_TWEETS_PER_VERSION=5 - keep/rollback threshold
--threshold 0.10 - Rollback prompt always ask first
Path assumptions (top of _common.py, change here when switching machines)
- Tweet history:
~/.claude/skills/wjs-tweeting-from-articles/state/history.jsonl - prompt file:
~/code/wechat-publish/prompts/x/prompt.md