ShapelessAI← All notes

№ 004Account standing11 minTal Weiss

X open-sourced its algorithm. What it says about your reach

We read the xai-org/x-algorithm repo today: the enforcement rules, the 30-day label expiry, the cold-start boost, and the one number that replaced TweepCred.

An engraving of a glass-walled clockwork engine in a public square, its gears and levers fully visible to a crowd pressed against the panes. In the middle of the open machinery sits one locked strongbox, drawn as a blueprint, that nobody can see into.

X's recommendation algorithm is open source at xai-org/x-algorithm: 33,316 stars, Apache 2.0, last pushed 2026-09-18. We read it on 2026-09-21 at commit 8b25829. Four things in it change what a founder should do, and all four are missing from the coverage: soft enforcement labels expire after exactly 30 days, the rules that hide you from strangers only ever run on the recommendations path, an account under 1,000 followers gets a published cold-start lift, and TweepCred is gone and has a named successor with a formula you can read.

What you cannot get from the repo is the thing everyone wants: the learned weights inside the ranking model. X publishes the shape of every decision and withholds the numbers the model learned. That is the honest boundary, and this note stays on the right side of it.

30 days
every soft label lasts, then lapses
enforcement_user.yaml, x-algorithm
0.75
multiplier on every out-of-network post's score
param.rs, x-algorithm
1,000
followers: below this, the cold-start lift applies
param.rs, x-algorithm
0
files mentioning TweepCred in the current repo
searched 2026-09-21

What actually changed since 2023

The 2023 repository, twitter/the-algorithm, is still up and still frozen, last pushed 2025-09-08. Its architecture was a pipeline of hand-built parts: Earlybird for search, GraphJet for the graph, a heavy ranker over engineered features, and TweepCred, which its own README describes as a PageRank over the graph of users and their interactions, post-adjusted by each user's follower-to-following ratio.

The current repo is a different machine. One model, Phoenix, predicts your probability of every action on every candidate, in network and out, and a separate service decides whether the post may be shown at all. The README states that split as a design decision:

Ranking decides the order. Visibility filtering decides whether a post can be shown at all. Different services, different inputs, different rules.

It also drops the vocabulary problem: "Both retrieval and ranking use multiple hash functions for embedding lookup, so there is no vocabulary to maintain and a new post is representable immediately." A brand new account's first post is representable in the model on publication. That is a real change from the 2023 design, and it is the mechanical reason "warm up the embedding" advice is empty.

Search "tweepcred" in the current repo and you get nothing. We checked: zero files. The old repo returns 32 code hits for the same query.

The number that replaced it

user-cred-v2/ is a Scala batch job that runs PageRank over the follow graph and turns the resulting mass into a per-account score. The conversion is nine lines and fully published:

private val ScoreSlope = 7.07
private val ScoreIntercept = 165.2

def fromMass(id: Long, mass: Double): UserCredV2 = {
  val rawScore = if (mass <= 0) 0.0 else ScoreIntercept + ScoreSlope * scala.math.log(mass)
  val score = (rawScore max 0.0) min 100.0
  UserCredV2(id = id, mass = mass, score = score)
}

The graph it runs on is worth reading carefully, because the two halves do different jobs. The random walk itself runs on the follow graph. The engagement edges are something else: they are built only from favourites and reposts in a 7-day window, self-engagement excluded, and they set where the walk restarts. The teleport weight for an account is (1 - beta) * uniform + beta * normalised engagement, with jumpProbability 0.2 and engagementTeleportBeta 0.5 as published defaults. So one step in five is a restart, and half of that restart mass lands in proportion to who got liked and reposted this week.

Two consequences worth sitting with. The score is logarithmic in mass, so every 7.07 points costs a factor of e, about 2.72 times, in PageRank mass. Moving from 30 to 50 is not twenty points of effort, it is roughly seventeen times the mass. And nothing in it reads your raw follower count: it reads the follow graph weighted by each follower's own mass, and it re-seeds the walk on whoever was actually liked and reposted in the last seven days. A monitoring gate fails the job if total mass leaves the range 0.99 to 1.005, so mass is a distribution summing to one across every account on the platform.

The enforcement rules, and the 30 days

abuse-enforcement-service/service-lib/rules/enforcement_user.yaml is not source code that someone wrote for the repo. Its first line says # mirrored from GrowthBook dynamic config; last sync 2026-08-26T16:31:18Z. It is production configuration, dumped. 35 user rules, and a sibling file with 13 post rules.

The rules are evaluated in order and the first match wins. The first five are skips, and three of those are the reason established accounts feel like they live under different physics:

- id: very_high_follower_count
  # Prod uses a different follower count floor; this is a mock value to reduce gaming.
  when: cred.follower_count >= 12.34
  then: { kind: skip, reason: very_high_follower_count }

- id: pagerank_skipped
  when: cred.is_high || cred.score >= 50.0
  then: { kind: skip, reason: pagerank_skipped }

An account above the follower floor, or with user-cred-v2 score at least 50, is skipped before any enforcement rule is considered. The 12.34 is a deliberate placeholder and xAI tells you so on the line. The 50.0 is not commented as mocked. Treat the structure as real and the numbers as unknown.

Past the skips, seven rules apply a soft label, and all seven carry the same expiry:

- id: act_add_llm_slop_label
  when: '"llm_slop_user" in score.labels'
  then:
    kind: act_add_labels_v2
    labels: ["SpamHighRecall"]
    ttl_msec: 2592000000

2,592,000,000 milliseconds is 30 days exactly. There is a detail here that matters more than the number: directly above each rule that applies the label sits a rule that skips when the label is already present.

- id: already_spam_high_recall_labeled_llm_slop
  when: '"llm_slop_user" in score.labels && "SpamHighRecall" in user.labels'
  then: { kind: skip, reason: already_spam_high_recall_labeled }

First match wins, so a live label is never re-stamped and never extended. The 30 days run from the day it landed, whatever you do next. What decides your next 30 days is how you look on the day it lapses. There is an llm_slop_user label and a SpamEmbeddingMajorityPoster one, both landing on SpamHighRecall for 30 days. The post-level file adds llm_slop_post, which attaches RiskyHighVizReply, and fast_reply_spam_post and gibberish_post, which attach SpamHighRecall to the post for 30 days.

The ladder above a label is explicit in the rule kinds: act_captcha, act_arkose and act_spam_liveness_check are challenges, act_add_labels_v2 is the quiet one, and act_suspend_user carries perm: true or perm: false. Several rules combine a label and a challenge in one act_all. The last rule in the file is when: "true", then suspend, which is only reached once every skip and every named label has failed to match.

A soft label is a 30-day seal: sealed posts stay on the shelf for followers while the open conveyor to strangers carries everything else
A soft label is a 30-day seal: sealed posts stay on the shelf for followers while the open conveyor to strangers carries everything else

Where a label actually bites

This is the part that is consistently reported wrong. A label on your account does not remove you from everything.

visibility-filtering/rules/registry.rs defines three policies:

pub enum SafetyLevel {
    FilterAll,
    TimelineHome,
    TimelineHomeRecommendations,
}

TimelineHome runs nine shared rule sets. TimelineHomeRecommendations runs the same nine plus five more, and author_rules::OON_USER_LABEL_DROPS is in that second group only. Eleven rules, one per author label, each dropping the post for viewers who are being recommended the author rather than following them. Every one sets reason: FilteredReason::UnspecifiedReason. Two of them, AbusiveHighRecall and DoNotAmplify, set exempt_follower: true, so followers still see the post and strangers do not.

So a SpamHighRecall label does not mute you. It removes you from out-of-network distribution. If your reach was already almost entirely followers, you might not notice. If your growth depended on strangers, it stops.

The path of a post on X from writing to the For You feed, showing that enforcement labels are read only by the out-of-network recommendation rules
The path of a post on X from writing to the For You feed, showing that enforcement labels are read only by the out-of-network recommendation rules

The four numbers that are not mocked

home-mixer/params/param.rs holds tunable values, and the README says cron scripts keep its defaults equal to the primary production values. The ones a founder should know:

ParameterDefaultWhat it does
OonWeightFactor0.75Every out-of-network post's score is multiplied by this, as are replies and reposts from accounts the viewer does follow
AuthorDiversityDecay / AuthorDiversityFloor0.5 / 0.25Your second post in one feed is worth half, decaying to a floor of a quarter. Posting five times in an hour does not get you five slots
ColdStartFollowerCap1000The cold-start lift only considers authors below this follower count
ColdStartImpressionThreshold1000And only posts below this many impressions
ColdStartSlotMin / ColdStartSlotMax15 / 16Where in the feed a qualifying post gets lifted to
ColdStartMaxPostAgeSecs17280048 hours. Older than that and the lift does not apply

Read together, those last four are a published new-author boost. If you are under 1,000 followers and a post is under 1,000 impressions and under 48 hours old, author_cold_start.rs will try to place it around slot 15 of someone's feed. A Thompson-sampling variant for choosing between qualifying posts is in the file, defaulting to off. The code calls this a boost, not a penalty. The common belief that X throttles new accounts in ranking is not what the ranking code does. The throttling lives in the enforcement rules, where a new account is the one with no credibility score to be skipped by.

One filter genuinely does restrict, and it is about the viewer, not you: NewUserMinEngagementFilter drops out-of-network posts below an engagement threshold for viewers whose accounts are new. New readers get a safer feed. That is a different thing from your account being throttled.

What the repo says about replies and links, checked rather than assumed

Replies. OONRetweetReplyFilter removes replies and reposts from accounts the viewer does not follow, before scoring. So a reply you write is never a For You candidate for anyone who does not already follow you: it reaches strangers through the conversation, not through recommendation. Separately, EnableOonRescoreForInNetworkRepliesRetweets defaults to true, which applies the 0.75 out-of-network factor to replies and reposts even from accounts the viewer follows. Replies are cheaper than originals in the feed, by design, in both directions. And fast_reply_spam_post plus RiskyHighVizReply are the two labels aimed squarely at high-volume reply behaviour, which is worth knowing before you adopt a reply-a-day-times-twenty growth plan.

Links. There is no link penalty rule in this repository. The only place a URL appears in the ranking path is home-mixer/models/content_features.rs, which computes has_url: text.external_urls > 0 and hands it to the model next to has_video, has_photo, media_count, weighted_text_len and newline_count. We grepped the whole repo: nothing reads has_url outside that file's own tests. So the accurate statement is that link posts are a feature the model has learned a weight for, and that weight is not published. Anyone claiming to know the size of the link penalty from this repo has not read it.

What is not in the repo, and what replaces it

X names the gaps itself: Grox prompts, some botmaker rules, and, throughout, the trained parameters. Its stated substitute is a transparency tool rather than more code:

one can match any labels present on their account to the code to understand if or how the visibility of their posts is affected, and critique it if desired

That tool is Under the Hood, and as of the 2026-09-18 release it also reports posts withheld in a country following a legal demand. It is a pilot with limited availability. Code plus your own labels is a genuinely better answer than either alone, and no other platform offers half of it. We cover what every other platform does and does not show you in what a shadowban is, and how to check on each platform.

If you run one account

Five things follow from the above and nothing else does.

  1. Your standing is a graph score, not a follower count. user-cred-v2 walks the follow graph and restarts half its teleport mass in proportion to the favourites and reposts of the last seven days. A follower puts you on the graph. A like or a repost from someone who has their own mass is what sends the walk back to you. Replies are not in the engagement set at all, which is worth knowing before you build a growth plan on them.
  2. Thirty days is the number to hold in your head. A soft label expires 30 days after it is applied, cannot be extended while it is live, and is simply re-applied if you still look the same on the day it lapses. There is no faster route and nothing to buy.
  3. The symptom to watch is the split, not the total. A label removes you from out-of-network distribution while followers see you normally. If follower reach holds and non-follower reach collapses, that is the shape. If both fall, it is the post.
  4. Posting more into one hour does not work. Author diversity halves your second post in a given feed and floors at a quarter. Spacing is not superstition here, it is a published multiplier.
  5. Under 1,000 followers you are being lifted, not throttled. The cold-start scorer is aimed exactly at you and it expires as you grow. The thing to avoid in that window is anything that looks like llm_slop_user or fast_reply_spam_post, because you have no credibility score to be skipped by.

The rules file is mirrored from live config and carries its own sync timestamp, so it moves. Ours says 2026-08-26. Check the header before you quote a number, including ours.

We are ShapelessAI: an agentic content team that researches, writes, designs and publishes to nine platforms for founders. Reading the code is how we decide what to do on a real account instead of guessing.

Questions

Is TweepCred still how X scores accounts?
No. The word TweepCred does not appear anywhere in xai-org/x-algorithm, which we checked on 2026-09-21. What is there is user-cred-v2: a PageRank over the follow graph whose restarts are weighted by the favourites and reposts of the last seven days, turned into a 0 to 100 score by the published formula 165.2 plus 7.07 times the natural log of the account's mass. Any calculator still computing a TweepCred number is re-deriving a 2023 artefact and selling it as current.
Does the X algorithm penalise posts with links?
Not in any rule in the repo. Whether a post carries an external URL is computed as has_url in home-mixer/models/content_features.rs and passed to the ranking model as one feature among many, alongside video, photos, media count, text length and newline count. There is no filter, no multiplier and no visibility rule anywhere in the code that reads it. What the learned model does with that feature is not published.
Does a new X account get suppressed?
The opposite, in the ranking code, and yes in the enforcement code. Posts from authors under 1,000 followers with fewer than 1,000 impressions are lifted toward slot 15 or 16 of the feed by the cold-start scorer. But the enforcement rules skip an account with a high follower count or a credibility score of at least 50 before any rule runs, and a new account has neither, so it is the one with nothing to exempt it.
Can I use the repo to check my own account?
Not from the code. The repo holds the rules, not your account's state. X ships that separately as Under the Hood at x.com/i/under_the_hood, which shows aggregate statistics about the visibility-limiting labels on your own account and posts. It is a pilot with limited availability, and it is the only first-party label view any major platform offers.
Are the follower thresholds in the enforcement rules real?
No, and xAI says so in a comment on the line: "Prod uses a different follower count floor; this is a mock value to reduce gaming." Three rules carry the placeholder 12.34. Quote the structure of those rules, which is real and mirrored from production config, and never the numbers.