A Study of the 𝕏 For You Algorithm
A static source audit of xAI's open repository, covering candidate retrieval, multi-action scoring, author diversity, DPP reranking, and visibility filtering in X's For You timeline.
Source repository: x-algorithm.
This report is based on the public main branch. The README records the most recent public update as 2026-08-13. Scoring weights and enforcement-rule files are annotated as synced with production configuration on 2026-08-12.
The report is a static reading of the repository source and the official README. Numeric values are the committed defaults in param.rs, config.rs, and YAML. Experiment flags, GrowthBook or feature-switch overrides, and unpublished rules may cause production behavior to differ from the description below. This is not an observation of live traffic.
1. Overview
The For You timeline is assembled per request. Candidates come from two sources:
- In-network: recent posts from accounts the viewer follows, read from in-memory storage (Thunder).
- Out-of-network: posts from accounts the viewer does not follow, retrieved by vector search (Phoenix retrieval) and interest clustering (SimClusters).
Both sets of candidates are scored by the same Phoenix ranking model. The model predicts, for each candidate, the probability of several viewer actions. Explicit weights then combine those predictions into a single score. Author diversity, an out-of-network discount, a new-author lift, and DPP reranking are applied in that order.
After ranking, visibility filtering decides separately whether the post is shown normally to the current viewer, shown behind an interstitial, or dropped. Visibility filtering does not change the score.
Ranking optimizes predicted action value for the viewer and the candidate. It does not optimize accumulated engagement counts on the post.
The following constraints can be read directly from the code defaults:
- The For You eligibility window is about 48 hours.
- The default weight on share-via-copy-link is 40 times the like weight. The absolute default weight on report is 468 times the like weight.
- Out-of-network posts, and in-network replies and reposts, are multiplied by 0.75 by default.
- Within one request result, later posts by the same author are decayed by formula starting at the second post.
- Subscriber-only or exclusive content does not enter For You for viewers who are not subscribers.
- Out-of-network recommendations apply an additional set of drop rules that do not apply in-network.
2. Scope and method
2.1 What the repository covers
The official README states that the purpose of the repository is to let the public audit how posts enter For You. The top-level directories of the public repository are as follows.
| Layer | Directories | Role |
|---|---|---|
| Orchestration | home-mixer/, candidate-pipeline/ | Request path: retrieval, hydration, filtering, scoring, blending |
| Retrieval | thunder/, phoenix/, simclusters/, phoenix-rankall/, phoenix-rankall-strato/ | In-network memory, out-of-network vectors, interest clusters, retrieval index |
| Ranking | phoenix/ (ranking), vm-ranker/ | Multi-action prediction; DPP reranking |
| Visibility | visibility-filtering/, visibility-filtering-client/ | Allow / Interstitial / Drop |
| Labeling | scarecrow/, botmaker/, botmaker-rules/, abuse-enforcement-service/, safety-label-user-agg/ | Event rules, account enforcement, post-to-account label aggregation |
| Understanding | grox/, clip/, media-model-proxy/, adult-content/, pnsfwmedia/, agatha/, bdsm/, user-cred-v2/ | Text and media classification, account scores, action sequences |
| Transparency | under-the-hood/ | Aggregated reports of account and post labels |
| Documentation | README.md, docs/BIDIRECTIONAL_BOOST_CHANGE.md | System design notes and one recorded parameter change |
The main languages are Scala, Rust, Python, and Java, with smaller amounts of Strato and Thrift. phoenix/ includes training, serving, and synthetic data, and can be used to reproduce one training and inference run independently.
2.2 What the repository does not include
The official README states the following boundaries:
- Some Grox LLM prompts (
.j2files) are unpublished. - Some botmaker rules are unpublished. The README gives the reason as reducing the risk of targeted circumvention.
- Deployment, cluster orchestration, internal telemetry, and production data pipelines are mostly absent.
- Thresholds in BDSM
sink_policy.yamlare rewritten to9.99. Follower-count floors in abuse-enforcement-service are replaced with placeholder values. Those files describe the mechanism. They are not production thresholds.
This report can therefore describe the default Home Mixer pipeline, the scoring formula, the visibility-rule table, and how published labels are consumed. It cannot claim to exhaust every path by which a post receives a given label.
2.3 Method
- The two Home Mixer pipelines are used as the spine. Source is read along the call chain.
- Numeric values are repository defaults, cited by parameter name.
- Intermediate claims that disagree with source are resolved in favor of source. Limits are listed in section 10.
3. System structure
3.1 Design principles
The official README states five design principles. The source is consistent with them.
- Multi-action prediction. Phoenix emits a set of action probabilities plus a dwell-time regression. Combining them into one score is a separate weighted sum.
- Candidate isolation. In the ranking transformer, candidates cannot attend to one another. They read only viewer context. A candidate’s score does not depend on which other candidates are in the batch, so scores can be cached.
- Hash and semantic-ID embeddings. Retrieval and ranking do not maintain a closed vocabulary. A new post can be represented immediately. The production retrieval tower uses residual-quantized semantic IDs (6 levels × 256 codes) and hashed author IDs. It does not use a learned per-user ID embedding.
- Ranking and visibility are separate. They use different services, different inputs, and different rules.
- A composable pipeline.
candidate-pipeline/separates source, hydrator, filter, scorer, selector, and side effect. Stages can run in parallel and can be toggled independently.
3.2 Two paths
Request path Labeling path (continuous)
──────────── ──────────────────────────
Home Mixer grox / clip / media-model-proxy
├ PhoenixCandidatePipeline agatha / bdsm / user-cred-v2
│ retrieve → filter → score → Top 50 scarecrow + botmaker
│ → visibility filter → filter again abuse-enforcement-service
└ ForYouCandidatePipeline safety-label-user-agg
posts + ads + Who to Follow + prompts written to storage, read by VF on requestThe request path decides the order of this response. The labeling path decides which labels a post or account carries. Labels do not rewrite Phoenix scores. They can remove a candidate before or after scoring.
4. Request path
The entry point is ForYouCandidatePipeline. Its first candidate source, ScoredPostsSource, runs the full PhoenixCandidatePipeline, converts selected posts into FeedItems, and blends them with ads, Who to Follow, prompts, and other items.
4.1 Query hydration
Before any candidate source is queried, PhoenixCandidatePipeline hydrates viewer-side features in parallel. Items registered in phoenix_candidate_pipeline.rs include:
- Two User Action Aggregation sequences, one for ranking and one for retrieval (
ScoringSequenceQueryHydrator,RetrievalSequenceQueryHydrator) - Block, mute, follow, and subscription lists
- Redis-cached posts
- Mutual-follow relations
- Demographics, inferred gender, installed apps
- Followed Grok topics and Starter Packs
- Explicit and implicit engagement signals
- Impression Bloom filter, IP, and geography
ImpressedPostsQueryHydrator is constructed but is not inserted into the query_hydrators vector. Already-seen posts are handled mainly by the Bloom filter, by exclusion in the Thunder request, and by the later PreviouslySeen* and PreviouslyServed* filters.
Candidate sources are queried only after these features are ready.
4.2 Candidate sources
The code registers seven sources. Thunder, Phoenix, SimClusters, and the cache source are enabled by default.
| Source | Default switch | Default cap | Served type | Role |
|---|---|---|---|---|
ThunderSource | Always registered | 1200 | ForYouInNetwork | In-network posts from the in-memory PostStore, using the follow list with already-seen tweet IDs removed |
PhoenixSource | EnablePhoenixSource = true | 1000 | ForYouPhoenixRetrieval | Out-of-network nearest neighbors from the retrieval-sequence embedding |
SimclustersSource | EnableSimclustersSource = true | 800 | ForYouSimclusters | Cosine approximate nearest neighbors on LOG_FAV embeddings of the viewer’s engagement-signal posts; maximum age 48 hours |
TweetMixerSource | EnableTweetMixerSource = false | 800 | — | Off by default |
PhoenixTopicsSource | Used on topic requests | 1000 | — | Topic retrieval |
PhoenixMOESource | EnablePhoenixMOESource = false | 200 | ForYouPhoenixRetrievalMoe | Off by default |
CachedPostsSource | EnableCachedPosts = true | — | — | Reuses the previous request’s cache |
Thunder supplies in-network candidates. Phoenix and SimClusters supply out-of-network candidates. SimClusters also requires post-level engagement signals on the request; otherwise that path returns empty.
4.3 Candidate hydration
After retrieval, features are attached in order: in-network flag, mutual follow, TES text and author, quote, media, subscription, Gizmoduck account data, whether the author has blocked the viewer, filtered topics, language, engagement counts, semantic ID.
These fields are consumed by later filters and scorers.
4.4 Pre-scoring filters
The filter order in phoenix_candidate_pipeline.rs is as follows. The order is part of the semantics.
| Order | Filter | Removes |
|---|---|---|
| 1 | DropDuplicatesFilter | The same post returned by more than one source |
| 2 | CoreDataHydrationFilter | Posts whose text or metadata failed to load |
| 3 | AgeFilter | Posts older than MAX_POST_AGE (48 hours) |
| 4 | SelfTweetFilter | The viewer’s own posts |
| 5 | OONRetweetReplyFilter | Out-of-network reposts and replies, and replies whose parent is missing |
| 6 | OONNsfwSimclustersFilter | Posts whose ServedType is ForYouSimclusters, whose author has an NSFW flag, and whom the viewer does not follow |
| 7 | RetweetDeduplicationFilter | Repeated reposts of the same original |
| 8 | IneligibleSubscriptionFilter | Subscriber-only posts the viewer has not subscribed to |
| 9–11 | PreviouslySeen* / PreviouslyServed* | Already-seen or already-served posts |
| 12 | MutedKeywordFilter | Posts matching the viewer’s muted keywords |
| 13 | AuthorSocialgraphFilter | Posts from authors the viewer has blocked or muted |
| 14 | VideoFilter | Video posts when the request excludes video |
| 15 | TopicIdsFilter | Posts outside the requested topics on a topic request |
| 16 | NewUserMinEngagementFilter | Low-engagement out-of-network posts under the new-account condition |
| 17 | InventoryHoldoutFilter | Inventory held out by a deterministic sample over post and viewer |
Two points need a separate note:
OONNsfwSimclustersFilterapplies only to the SimClusters source. Out-of-network originals from NSFW-flagged authors that arrive via Thunder, Phoenix, or the cache are not removed by this pre-filter. They may still be dropped by out-of-network visibility rules.- Subscriber-only content is already removed at this layer.
DropExclusiveTweetContentRulein visibility filtering further restricts exclusive content: only the conversation author, a super-follow viewer, or a non-repost author may pass.
4.5 Scoring
Three scorers run in sequence.
PhoenixScorercallsPredictNextActions(return_logprob: true) and writes the heads intophoenix_scores. This step does not compute a weighted score.RankingScorerapplies the weighted sum, offset, author diversity, out-of-network discount, and new-author lift, and writescandidate.score.VMRankersends a request with DPP context tovm-ranker/. If the service has DPP enabled, only the greedily selected subset keeps its original score; the rest are set to 0. Otherwise the scores are returned unchanged.
Home Mixer sends value_model_id = "dpp" by default, with theta = 0.65 and max_selected_rank = 150. The vm-ranker CLI default for --dpp-enabled is false. The repository does not state whether the production process passes that flag.
4.6 Selection, visibility, and blending
TopKScoreSelectorkeeps 50 posts by descendingcandidate.score(TOP_K_CANDIDATES_TO_SELECT).- After selection,
VFCandidateHydrator,VFFilter,AncillaryVFFilter, andDedupConversationFilterrun. - Posts whose visibility result is
Dropare removed. Posts whose result isInterstitialremain in the timeline. This repository does not contain the interstitial UI. - If an ancestor, quoted post, or reposted post was dropped,
AncillaryVFFilterremoves the current post. DedupConversationFiltercollapses extra branches of the same conversation.- There is no rescoring after visibility filtering. On-screen position can differ from score rank.
The outer ForYouCandidatePipeline uses BlenderSelector to insert non-post items:
| Item | Default position or behavior |
|---|---|
| Ads | Default partition_organic_low_risk, handled by PartitionOrganicAdsBlender; organic posts may be reordered for ad adjacency |
| Prompt | Position 0 |
| Who to Follow | Position 6 |
| Feed survey | Position 12 |
| Push-to-home, Jetfuel frames | Separate insertion logic |
The organic result-size constant is RESULT_SIZE = 35. Ads and module slots are added separately, so one response can contain more than 35 slots.
After selection, the framework records served history, ad, client, and Kafka events, and refreshes the post cache, via tokio::spawn. That async work may overlap URT serialization. Served records become pre-filter inputs on later requests.
5. Scoring
5.1 Phoenix ranking model
phoenix/ is trained in JAX and served over Rust gRPC. The ranking model is a transformer:
- Inputs are the viewer’s recent action sequence and the current candidates.
- Outputs are a set of action logits per candidate, plus a dwell-time regression.
- Candidates cannot attend to one another. They read only viewer context.
- Embeddings use multiple hashes and semantic IDs. A new post does not need to enter a closed vocabulary.
Retrieval is a two-tower model. The user tower reads action history. The production configuration also includes country, language, and other profile tokens. It does not include a learned per-user ID embedding. The candidate tower reads semantic IDs and hashed author IDs. Retrieval takes Top-K by dot product. The index is stored in the checkpoint and updated from events by phoenix-rankall/. phoenix-rankall-strato/ decides which index a post enters and queries visibility filtering before insertion.
Home Mixer requests return_logprob: true. The serving side fills top_log_probs = log_sigmoid(logits). The prediction client that writes those values into PhoenixScores.favorite_score and related fields is not in this repository. The official README states the formula as a weighted sum of probabilities. If the client passes log-probabilities through unchanged, the numeric scale changes. Relative weight magnitudes still hold. This report follows the official README and RankingScorer::apply(score, weight) = score * weight.
5.2 Default weighted formula
ValueModelMode defaults to weighted. RankingScorer computes:
raw = Σ_i weight_i × P̂(action_i)
score = offset_score(raw)offset_score adds 0.001 when the value is non-negative. Negative values are mapped into the interval (0, 0.001). Author-diversity and out-of-network factors are applied next. The new-author lift runs last.
EnableMpnScoring defaults to false. When it is on, diversity and out-of-network factors apply only to a positive net value. A negative net value is not scaled. dwell_regret_sigmoid and gated_dwell_regret are a different formula that modulates dwell by within-batch relative position. They are not the default path.
5.3 Default weights
Source: home-mixer/params/param.rs. The file is annotated as mirrored from config feature-switch defaults; last sync 2026-08-12T04:09:22Z.
Positive and zero-weight terms:
| Predicted action | Parameter | Default weight | Relative to FavoriteWeight |
|---|---|---|---|
| Share via copy link | ShareViaCopyLinkWeight | 20.0 | 40 |
| Reply | ReplyWeight | 5.0 | 10 |
| Quote | QuoteWeight | 5.0 | 10 |
| Share via DM | ShareViaDmWeight | 5.0 | 10 |
| Follow author | FollowAuthorWeight | 4.0 | 8 |
| Share (generic) | ShareWeight | 2.0 | 4 |
| Repost | RetweetWeight | 1.0 | 2 |
| Like | FavoriteWeight | 0.5 | 1 |
| Open post | ClickWeight | 0.4 | 0.8 |
| Open link | OpenLinkWeight | 0.2 | 0.4 |
| Expand photo, open video, video quality view (VQV), click quoted post | corresponding *Weight | 0.05 | 0.1 |
| Continuous dwell (seconds) | ContDwellTimeWeight | 0.004 | — |
| Unexplored post | PostUnexploredWeight | 0.02 | In-network only; additive by default |
| Click dwell, quoted VQV, profile click, binary dwell | corresponding parameters | 0.0 | Not in the default weighted sum |
Negative terms:
| Predicted action | Parameter | Default weight | Absolute ratio to FavoriteWeight |
|---|---|---|---|
| Not dwelled | NotDwelledWeight | −0.02 | 0.04 |
| Block author | BlockAuthorWeight | −31.2 | 62.4 |
| Not interested | NotInterestedWeight | −43.2 | 86.4 |
| Mute author | MuteAuthorWeight | −58.8 | 117.6 |
| Report | ReportWeight | −234.0 | 468 |
Weights are not multipliers on engagement counts. The model predicts the probability that the current viewer takes each action on the current candidate. A post with a high existing engagement count can still receive a low weighted score if the model assigns low probability to positive actions and high probability to negative actions for this viewer.
5.4 Mutual-follow boost
This applies only when the candidate is original (not a reply and not a repost) and is_mutual_follow_author == true:
- Reply weight is increased by
BidirectionalFollowReplyWeightBoost, default 15. The effective reply weight is then 5 + 15 = 20. - Dwell weight is increased by
BidirectionalFollowDwellWeightBoost, default 0. That boost was experimented with and was not enabled as the default main path.
docs/BIDIRECTIONAL_BOOST_CHANGE.md records the July 2026 experiment: values 5, 10, 15, and 20 were tested; on 13 July, 20 was expanded to a larger set of users; on 24 July it was changed back to 15. The document’s stated reason is that some users saw less discussion from accounts they did not follow during a large public event.
5.5 Author diversity
EnableAuthorDiversity defaults to true. Candidates are first ordered by the pre-diversity score. Let k be the number of times the same author has already appeared (the first post has k = 0):
multiplier(k) = (1 − floor) × decay^k + floorDefaults are decay = 0.5 and floor = 0.25. The corresponding multipliers are:
| Position among that author’s posts in the result | k | Multiplier |
|---|---|---|
| 1st | 0 | 1.00 |
| 2nd | 1 | 0.625 |
| 3rd | 2 | 0.4375 |
| 4th | 3 | 0.34375 |
| further | → ∞ | → 0.25 |
The formula is not 0.5^k clipped at 0.25. The second post’s multiplier is 0.625.
5.6 Out-of-network discount
After the weighted sum, diversity, and cold start:
- Out-of-network posts are multiplied by
OonWeightFactor, default 0.75. EnableOonRescoreForInNetworkRepliesRetweetsdefaults to true, so in-network replies and reposts are also multiplied by 0.75.- Topic requests use
TopicOonWeightFactor, default 0.5. - The extra factor
NEW_USER_OON_WEIGHT_FACTOR = 0.00001is used only when account age is belowNewUserAgeThresholdSecsand the viewer follows at least five accounts. That threshold defaults to 0. Under repository defaults, this branch usually does not run unless production overrides the age threshold to a positive value.
On the default path, the same original post therefore receives a higher multiplier as an in-network candidate than as an out-of-network candidate, and a higher multiplier than as a reply or a repost.
5.7 New-author lift
EnableViewerColdStart defaults to true. Each request adjusts at most one eligible original:
- Not a reply and not a repost
- Author follower count at most
ColdStartFollowerCap(1000) - View count below
ColdStartImpressionThreshold(1000) - Rank among non-zero scores below
LowImpressionsMaxPositionRatio(0.85) - Score is replaced with
max(score, target), wheretargetis a score drawn at random from the interval[ColdStartSlotMin, ColdStartSlotMax) = [15, 16)after ranking
The rule applies to at most one original per request. It does not apply to replies or reposts.
5.8 DPP reranking
vm-ranker/ uses a determinantal point process over embeddings, trading off score against dissimilarity to neighboring candidates. The greedily selected subset keeps its original scores. The rest are set to 0. The later Top-K step then drops the zeroed candidates. As a result, some high-scoring candidates that are close in topic to others may leave the selected set.
6. Visibility filtering
6.1 Outcomes
visibility-filtering/ returns one of three outcomes for a (viewer, post) pair:
ALLOW: show normallyINTERSTITIAL: keep in the timeline; the client draws an interstitial (for example adult or graphic content)DROP: Home Mixer removes the post
Rules are evaluated in registration order and short-circuit. The first rule that returns Drop ends evaluation.
In-network uses TimelineHome. Out-of-network uses TimelineHomeRecommendations. The latter contains all of the former’s drop rules and adds a set of recommendation-only drop rules.
6.2 Rules that drop on both surfaces
base_home_rules() includes:
- Author suspended, deactivated, erased, or offboarded
- Protected account that the viewer does not follow
- Viewer blocks the author, mutes the author, or mutes reposts
- Exclusive content the viewer is not entitled to see
- Post labels:
PDNA,BOUNCE,SPAM,FOR_EMERGENCY_USE_ONLY - FOSNR: hateful conduct, violent speech, abuse, civic integrity (the author is usually exempt; the emergency-use label is not)
- Nullcast, stale edits, legal or local-law takedowns
- Sensitive-media gates for logged-out viewers, underage viewers, or viewers with no stated age
The same set also registers interstitial rules for high-precision NSFW, gore and violence, NSFW card images, and NSFW authors. On the out-of-network surface, later drop rules hit some of those cases first. See the next subsection.
6.3 Rules that drop only on the recommendation surface
timeline_home_recommendations_policy() adds:
- DMCA media and geo-restricted media
- NSFW user/admin flags on the author or the post
- Post labels: NSFW high recall, NSFW high precision, gore-and-violence high precision, NSFW card image, NSFW text,
DO_NOT_AMPLIFY, malicious URL, SPAM high recall, FOSNR insults (out-of-network only) - Author labels: NSFW high recall, NSFW high precision, NSFW near-perfect, NSFW avatar, NSFW banner, SPAM high recall, compromised, read-only, high-precision impersonation
- User-side
ABUSIVE_HIGH_RECALLandDO_NOT_AMPLIFY: drop only when the viewer does not follow the author
A post with high-recall spam or high-precision NSFW labels can therefore appear on a follower’s home timeline and still be withheld from For You recommendations to non-followers.
Repository tests show that EGREGIOUS_NSFW and RECOMMENDATIONS_BLACKLIST have been removed from the drop rules. Those names alone no longer drop recommendations.
6.4 Where labels come from
Labeling systems run continuously. They are not on the request hot path.
| System | Input | Output |
|---|---|---|
grox/ | Text and media at publish time | Classifications such as spam, adult, and violence, plus text and image representations |
clip/ | Image–text pairs | Media embeddings for downstream classifiers |
media-model-proxy/ | Images and video | XxNsfw, violence and gore, hateful symbols, fingerprinting and categories. The repository has no in-service model named AdultContent. disable_adult_content_v1 is an unused decider |
adult-content/, pnsfwmedia/ | Training and calibration | Adult-media classifiers. The latter combines CLIP embeddings with Agatha calibration scores |
agatha/ | Block, report, and like ratios on an account’s posts | Offline account labels, including spam and adult |
bdsm/ | Account action sequences | Signs of inauthentic or abusive behavior; may write labels such as enforcement_threshold_reached |
user-cred-v2/ | PageRank over the follow graph and engagement edges | An account score in 0–100. The score itself is not a visibility drop rule |
scarecrow/, botmaker/, botmaker-rules/ | Real-time events | Labels written when conditions hold. Some rules are unpublished |
abuse-enforcement-service/ | Model scores, not individual events | First matching YAML rule: skip, write SpamHighRecall with a 30-day TTL, write RiskyHighVizReply, challenge or liveness check, or suspend |
safety-label-user-agg/ | Post-level safety labels | Aggregated account-level labels |
The structure of enforcement_user.yaml is: skip on allowlist, high follower count (the floor is a placeholder), cred.is_high, or score ≥ 50; otherwise act on BDSM, slop, majority-poster, and related labels. The file header states that the file is mirrored from GrowthBook. Production CEL or dynamic configuration may differ.
Labels that Scarecrow or Grox write, but that the published visibility-rule table does not read, include AGATHA_SPAM, AGATHA_SPAM_TOP_USER, SEARCH_BLACKLIST, UNSAFE_URL, COPYPASTA_SPAM, and RISKY_HIGH_VIZ_REPLY. They may affect Search or other surfaces, or act indirectly through unpublished rules. This repository alone does not show that they independently drop a For You post.
7. Other subsystems
The following directories do not compute the For You score. They affect whether a candidate enters the retrieval pool, which features it carries, or how it is explained after the fact.
thunder/: consumes new posts from Kafka, stores them in an in-memoryPostStore, and returns them by follow list. In-network freshness and capacity are determined here.simclusters/: Scala. Clusters accounts and posts by engagement. The approximate-nearest-neighbor service is insimclustersann/.phoenix-rankall/andphoenix-rankall-strato/: maintain the retrieval index. Visibility filtering is queried before insertion. A post dropped by visibility filtering should not enter the out-of-network retrieval pool.candidate-pipeline/: a generic orchestration framework. Home Mixer is a business instance of it.under-the-hood/: daily jobs collect visibility-affecting labels on accounts and posts; the serving layer aggregates them over a period. The product entry point is x.com/i/under_the_hood.
8. Experiments and configuration
Most weights and switches are read from feature switches rather than hardcoded as literals in the logic. The repository uses scheduled jobs to write primary production values back into param.rs. The README states that experiments at a notable share of traffic (for example 10% or more) are intended to be visible in the repository.
Therefore:
- Numbers in this report are the primary-path defaults recorded in the repository. They are not constants that hold for every viewer.
- The mutual-follow reply boost moved through 0, experimental values 5/10/15/20, a broader rollout of 20, and a change back to 15. Weights change with experiments and product decisions.
EnablePhoenixSource,EnableSimclustersSource, the ads blender type, andValueModelModecan all be switched by viewer cohort.
When reading the repository, the defaults can be treated as the current primary hypothesis, and diffs to param.rs as a log of algorithm changes.
9. Implications for creators
This section states only consequences that follow directly from the source. They are descriptions of mechanism, not an operating playbook.
9.1 Conditions for entering the candidate set
AgeFilterand the 48-hour SimClusters cap jointly define For You eligibility. A post older than that window does not enter this pipeline. It is not kept and down-weighted.- Already-seen or already-served posts are removed by pre-filters. A later request from the same viewer will not select the same post again.
- A viewer’s own posts do not appear in that viewer’s For You. An author viewing their own post is not a distribution signal.
- Subscriber-only or exclusive content does not enter For You for non-subscribers. Distribution to non-subscribers requires an original root post without a subscription wall.
- Out-of-network reposts and replies are removed before scoring. The unit of distribution to non-followers is the original root post.
9.2 Weighted score versus existing engagement counts
Default weights are the relative contribution of each predicted action to the combined score. They are not a statement of preferred content form.
| Predicted action | Default weight |
|---|---|
| Share via copy link | 20 |
| Reply, quote, share via DM | 5 each; 5 + 15 = 20 for reply when a mutual-follow viewer sees an original |
| Follow author | 4 |
| Like | 0.5 |
| Profile click, binary dwell | 0 |
From the table:
- Share via copy link, reply, quote, share via DM, and follow author contribute more to the default weighted score than like.
- The mutual-follow boost applies only to original root posts. A reply under the author’s own post and a reply under someone else’s post do not use the same weight.
- The default like weight is low. Existing like count is also not a ranking input.
- The default profile-click weight is 0. Bio, highlights, and outbound links can affect follow conversion. They do not enter the default For You weighted sum.
9.3 Negative terms
Under the default weights, the absolute value of report is 468 times that of like. Mute, not interested, and block are also much larger in absolute value than like.
The model predicts the probability that the current viewer takes those actions. It does not predict the post’s global controversy.
Out-of-network recommendations read an additional, wider set of safety labels. NSFW, high-recall spam, malicious URL, DO_NOT_AMPLIFY, and similar labels can remove a recommendation after ranking. Content that can still appear on a follower’s home timeline is not thereby eligible for For You recommendation.
Account-level labels (high-recall spam, NSFW avatar or banner, read-only, impersonation, compromised) apply to later recommendations from that account, not only to a single post. Avatar and banner also appear in the out-of-network drop rules.
9.4 Form and spacing of posts
- In one request result, an author’s second post is multiplied by 0.625, the third by about 0.44, with a floor of 0.25. When several posts from the same author enter the same viewer request in a short interval, later items are scaled down by that formula.
- In-network replies and reposts are multiplied by 0.75 by default. Out-of-network replies and reposts are removed before scoring. On the default path, an original root post receives a higher applicable multiplier than a reply or a repost.
- Expand photo, open video, and video quality view have a default weight of 0.05. Continuous dwell has a default weight of 0.004 per unit. Media is not the main term in the default weighted sum.
- If DPP is enabled, some high-scoring candidates that are close in topic are set to 0 and leave the Top 50.
9.5 New-author lift and account score
- An original from an author with at most 1,000 followers and fewer than 1,000 views on that post may be lifted to around position 15. At most one post is treated per request.
- When
user-credis at least 50 orcred.is_highis set, abuse-enforcement-service may skip later automatic enforcement. That score is not added to the For You weighted sum. It comes from PageRank over the follow graph and engagement edges.
9.6 Mechanism table
| Action | Corresponding mechanism |
|---|---|
| Publish an original that can be shared via copy link | ShareViaCopyLinkWeight = 20 |
| Discuss under one’s own original with mutual followers | Reply weight is 5 + 15 when the post is original and the follow is mutual |
| Accumulate likes | FavoriteWeight = 0.5; inauthentic behavior may also enter BDSM or abuse-enforcement-service |
| Publish several posts in a short interval | Author diversity decays from the second post |
| Reach non-followers via reply or repost | OONRetweetReplyFilter removes them before scoring |
| Make the root post subscriber-only | IneligibleSubscriptionFilter and exclusive-content rules keep it out of non-subscribers’ For You |
| NSFW labels on avatar or banner, with recommendation distribution | Out-of-network user-label rules drop the post |
| Raise the predicted probability of not interested, block, or report | Corresponding negative terms are larger in absolute value than like |
| Post older than about 48 hours | AgeFilter removes For You eligibility |
| Infer ranking from existing like count | Ranking input is predicted action probability for the current viewer |
9.7 Label lookup
Under the Hood aggregates visibility-affecting labels on accounts and posts. If recommendation distribution changes, the labels listed in section 6.3 can be checked there first. The repository describes the mechanism. The tool reports the labels currently attached to an account and its posts.
10. Limits
The following claims cannot be closed from this repository alone, or need to be qualified against the source:
- TweetMixer, Phoenix Topics, and MOE sources exist in the code. TweetMixer and MOE are off by default. Whether they are on for some viewers in production is not recorded.
- Whether
PhoenixScoresfields are probabilities or log-probabilities depends on the unpublished prediction client. - Home Mixer sends DPP parameters. The
vm-rankerCLI does not enable DPP by default. Whether the production process enables it is not recorded. NewUserAgeThresholdSecsdefaults to 0, so the extra new-user out-of-network factor usually does not apply under repository defaults.- There is no score-based rerank after visibility filtering. Ad blending can reorder remaining organic posts. On-screen position need not equal score rank.
- Some labeling rules are unpublished. BDSM thresholds and the abuse-enforcement-service follower floor are placeholders.
- Labels such as
AGATHA_SPAMare written but are not in the published visibility drop table. media-model-proxydoes not serve a model named AdultContent. Adult-related capability is implemented through heads such as XxNsfw and through the training code inadult-content/andpnsfwmedia/.- The author-diversity formula is
(1 − 0.25) × 0.5^k + 0.25, not0.5^kclipped at 0.25. - Whether the Following timeline uses the same 48-hour limit was not separately verified in the public source. The 48-hour window in this report applies only to the For You Phoenix pipeline.
11. Source index
| Topic | Path |
|---|---|
| Official overview | README.md |
| For You outer blending | home-mixer/candidate_pipeline/for_you_candidate_pipeline.rs |
| Post-pipeline assembly | home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs |
| Default weights and switches | home-mixer/params/param.rs |
| Size constants (50 / 35 / 48 hours) | home-mixer/params/config.rs |
| Weighted sum, diversity, out-of-network discount | home-mixer/scorers/ranking_scorer.rs |
| New-author lift | home-mixer/scorers/author_cold_start.rs |
| Mutual-follow boost change log | docs/BIDIRECTIONAL_BOOST_CHANGE.md |
| Visibility rule table | visibility-filtering/rules/registry.rs |
| Enforcement user rules | abuse-enforcement-service/service-lib/rules/enforcement_user.yaml |
| Phoenix model notes | phoenix/README.md |
| DPP | vm-ranker/scoring/dpp_model.rs |
This report is based on static source in the public repository. Live experiments, unpublished rules, and unsynced configuration overrides are defined by 𝕏’s production systems.