Treat "growing followers" as engineering:each change is a numbered experiment, with a hypothesis, a target metric, a before (rollback-able), and a verdict. Not by feel, by numbers.
Core Principle
A single account can't do parallel A/B — only before-and-after comparisons on a timeline. So the only trustworthy north star metric is conversion rate = new follows ÷ profile visits (ratio): it's immune to viral traffic. A tweet going viral brings a bunch of visits, and the ratio doesn't necessarily move; but if the bio is improved, every visitor is more willing to follow, and the ratio definitely moves.
So metrics are layered (every action must declare which metric it's judged by):
| Action type | Lever it moves | Judged by what |
|---|---|---|
| profile(bio / name / avatar / banner / pinned / URL / location) | Conversion | ratio(north star, viral-resistant) |
| posting(format / hook / frequency / thread vs single tweet) | Reach | profile visits + impressions (ratio as guardrail, don't drag down conversion) |
| engagement(replies / following others / engagement) | Reach | new follows + visits |
| timing(posting time) | Reach | profile visits |
Honesty guardrails (hardcoded in evaluate.py): use median not mean (one viral day can't fool the verdict); only give a verdict after 7 days / enough data; overlapping experiment windows on the same metric → mark confounded ; only give "directional" conclusions, don't claim causation.
Rollback is a first-class citizen. Every action stores the exact before value, so #N can always be restored. If judged ❌ rollback ask 王建硕 first, never silently change his bio。
Where the data comes from (key constraint)
The ratio number can't be obtained via X API / xurl — it only lives in the Analytics dashboard. So rely on CSV export:
Open x.com/i/account_analytics → Overview → download icon in the top right (pick 7D/2W/4W/3M/1Y for whichever range you want first) → export CSV → drop it into inbox/(or just give the path).
When This Skill Fires
- 王建硕 says "grow followers", "set up an X follower-growth experiment", "A/B test my profile", "today's follower-growth check"
- Run
/wjs-x-increasing-follower - set up
/schedule daily /wjs-x-increasing-follower(see "Daily check" at the end)
When NOT to use
- Just want to post a tweet →
/wjs-tweeting-from-articlesor directlyxurl post - Promotion skill →
/wjs-promoting-skills//publish-skill - Distribute the article to various platforms →
/wjs-syndicating-articles
Workflow
All scripts are in scripts/, state is in state/. First cd to the skill directory.
Step 1 — Ingest data (CSV → daily.jsonl)
python3 scripts/ingest-csv.py /path/to/export.csv
The script fuzzy-matches column names (Profile visits / New follows / Impressions / Followers), upserts by date, and automatically computes the ratio.It will print the column mapping it recognizes — take a look to check it's right, if not then --visits-col "X" --follows-col "Y". Re-running a longer export will overwrite overlapping days, which is safe.
Step 2 — Produce a to-do (propose experiments)
Look at state/daily.jsonl current state, give 王建硕 aNumbered experiment menu. Each must have:category / title / hypothesis / metric. Principles:
- Only let a few profile experiments run at a time(overlapping metrics will contaminate each other's readings).
- Hypotheses must be falsifiable: "a concrete one-liner converts better than a vague tagline" ✅; "make the bio better" ❌.
- profile-type before posting-type — conversion is the foundation; first catch the people who visit, then amplify traffic.
Log it (auto-assigns the number, don't hand-edit the jsonl):
python3 scripts/ledger.py add --category profile --metric ratio \
--title "Bio: 开头一行放硬证明" \
--hypothesis "访客看到具体成绩比看到口号更愿意关注"
Experiment menu reference (grouped by leverage):
- profile/ratio: bio rewrite (hook upfront / hard proof / CTA "follow to see X"), display name with identity anchor, avatar switched to a high-res front-facing photo, banner with a one-line value proposition, pinned switched to the strongest thread, URL pointing to a landing page.
- posting/visits: posting format (thread vs single post), first-sentence hook, with image vs text only, topic focus.
- engagement/follows: consistently replying to a certain circle, proactively following the target audience, participating in trending topics.
- timing/visits: 9am vs 9pm, weekday vs weekend.
state/SCOREBOARD.md 's "To-do" section is the executable version of this checklist (see Step 6).
Step 3 — Launch one experiment (including capturing before)
First capture the before-state(profile fields):
xurl "/2/users/me?user.fields=name,description,url,location,profile_image_url,pinned_tweet_id"
Record the current values.Then actually go change them:
- bio / name / URL / location — can go through the API (OAuth1 v1.1):
(xurl --auth oauth1 -X POST "/1.1/account/update_profile.json?description=<urlencoded>"name/url/locationsame logic. If it fails / OAuth1 not enrolled → fall back to editing by hand in the App, and still log it.) - avatar / banner / pinned tweet — no reliable public API,edit by hand in the App / web, the skill only handles recording before/after + tracking.
Log it (stamp the applied date + before values):
python3 scripts/ledger.py apply 1 \
--before-field description --before-value "<原 bio 原文>" \
--after-value "<新 bio>"
After that this experiment enters the measurement period: baseline = the median of the metric over the window_days(default 7) days before applied; the verdict must wait until enough data accumulates after applied.
Step 4 — Feed data daily + recompute (also used for the "daily check")
scripts/daily-check.sh
It will: ingest inbox/ 's new CSV (archive to inbox/done/)→ evaluate.py --write-verdict after use), write the directional verdict back to the ledger → regenerate SCOREBOARD.md。Note: it only writes the verdict, it doesn't touch the status — keep/rollback is a human decision.
Step 5 — Verdict and rollback
python3 scripts/evaluate.py # 看每个在跑实验:baseline vs post,Δ%,verdict
Verdict (relative to baseline median):Δ ≥ +10% → keep;Δ ≤ -10% → rollback; in between → flat. Note the ⚠ confounded / ⚠ thin baseline flag — if present, don't take it too seriously; extend the window or stop the overlapping experiment and retest.
- keep:
python3 scripts/ledger.py keep 1 --note "+58% 转化" - rollback (ask Wang Jianshuo first!): after confirming, use the
applybefore values stored at the time to restore (API or manual edit), thenpython3 scripts/ledger.py rollback 1 --note "转化掉了,还原 bio"(the command will print the before values to restore) - flat: keep observing, or classify as "no effect" and remove it.
Step 6 — Dashboard
python3 scripts/scoreboard.py # 写并打印 state/SCOREBOARD.md
Four blocks: 📈 Current state (latest ratio / 7-day median ratio / follower count), 🧪 Running experiments (baseline/post/Δ/verdict/alert), ✅ To-do (proposed list), 📚 Closed (kept / rolled_back). To show Wang Jianshuo, just send this file.
Data model (state/)
daily.jsonl— one row per day:{date, profile_visits, new_follows, ratio, impressions, followers_total}。actions.jsonl— one row per experiment:{id, category, title, hypothesis, metric, window_days, before:{field,value}, after:{value}, applied, status, evaluated, verdict, notes}. Status flow:proposed → active → (kept | rolled_back)。SCOREBOARD.md— generated artifact, for humans to read.
Default parameters (pass a flag if you want to change them)
- Evaluation window
--window-daysdefault 7 days - keep/rollback threshold
--thresholddefault ±0.10 (relative ±10%) - Minimum post data before making a decision
--min-post-daysdefault 3 days - Rollback always ask first, never silently
Daily check (optional scheduling)
/schedule daily /wjs-x-increasing-follower —— invoke this skill every day: run daily-check.sh, send SCOREBOARD.md current status + any experiments judged ❌ rollback to Wang Jianshuo and ask whether to roll back. The CSV still has to be manually exported by him and dropped into inbox/(the ratio data can't be obtained via API; there's no way around this step).