The X algorithm in May 2026

How Phoenix ranks every post: a creator's guide to the 19 engagement heads

X.AI's open-sourced Phoenix model does not score posts on a single "engagement" number. It predicts 19 separate user actions in parallel: favorites, replies, quotes, reposts, photo expands, clicks, profile clicks, video quality views, three share variants, two dwell variants, follow-author, plus four negative actions and an implicit not-dwelled signal. A final weighted sum decides feed position. This article walks each head from the phoenix/run_pipeline.py source: which UI gesture trains it, which weight it pairs with in home-mixer/scorers/weighted_scorer.rs, and what content patterns light it up. By the end, a creator understands why a post that gets 500 likes can rank below one with 80 likes and a 12-second dwell. We close with a quick framework for designing posts that fire multiple heads, not one.

May 20, 2026 · 16 min read · VoiceMoat team

A post can rank above another post with six times the likes. That sentence is true for the same reason a creator with a quiet but thoughtful follower base can outperform one with bigger absolute numbers. The 2026 X ranker does not score posts on a scalar "engagement." It runs nineteen separate probabilistic predictions per candidate, combines them with weights, and the resulting score decides feed position. This piece is the index of those nineteen heads. The structure of the score is in home-mixer/scorers/weighted_scorer.rs. The output shape of the model is documented in phoenix/README.md. The index-to-name mapping is partially redacted; we will be explicit about what is verified and what is inferred. A1 of this series walks the wider architectural change. This is the deep dive on the scoring layer.

The two-line summary of how the math works

Phoenix outputs a tensor of shape [batch, num_candidates, num_actions] with num_actions = 19. Each value is P(action_i), the predicted probability that the viewer takes action i if the candidate is served. home-mixer/scorers/weighted_scorer.rs then runs the following:

combined = Σ_i (P(action_i) × WEIGHT_i)
final = offset_score(combined)

That is the entire scoring formula. The weights WEIGHT_i are static per action, defined in the redacted params module. offset_score is an asymmetric branch: if the combined score is positive (the model expects net engagement), the value passes through largely unchanged. If the combined score is negative (the model expects more mutes and "not interested" reactions than likes and replies), the value is rescaled through (combined + NEGATIVE_WEIGHTS_SUM) / WEIGHTS_SUM × NEGATIVE_SCORES_OFFSET so that the resulting score is strongly penalised. A5 walks the offset branch in detail; for now the takeaway is that predicted negatives compete on the same scoring formula as predicted positives, and one strong predicted mute can sink the score even of a post with several strong predicted positives.

All nineteen heads

The next three tables enumerate the nineteen heads. The first is what we can verify directly from phoenix/run_pipeline.py: six index-to-name pairs that appear as named constants in the public source. The second is the remaining thirteen, where the WEIGHT constant exists in weighted_scorer.rs and the field name exists in the PhoenixScores proto referenced by home-mixer/scorers/vm_ranker.rs, but the specific output index is not spelled out in the README.

The six action heads with index-to-name mapping verified in run_pipeline.py

Source: phoenix/run_pipeline.py + phoenix/README.md

IndexHeadWeight constantUI gesture that fires it
1Favorite (like)FAVORITE_WEIGHTtap the heart
4ReplyREPLY_WEIGHTcompose and send a reply
5QuoteQUOTE_WEIGHTcompose a quote-post
6RepostRETWEET_WEIGHTtap repost (formerly retweet)
11Dwell (binary)DWELL_WEIGHTviewer paused on the post above a threshold
13Video quality viewVQV_WEIGHTvideo played past MIN_VIDEO_DURATION_MS
The remaining thirteen heads. WEIGHT constants and proto field names are documented; specific Phoenix output indices are inferred.

Source: home-mixer/scorers/weighted_scorer.rs + home-mixer/scorers/vm_ranker.rs (PhoenixScores proto)

HeadWeight constantUI gesture that fires itSign
Quoted click inferredQUOTED_CLICK_WEIGHTtap the embedded quoted post inside a quote-postpositive
Photo expand inferredPHOTO_EXPAND_WEIGHTtap a photo to open it full screenpositive
Click inferredCLICK_WEIGHTtap a link inside the post bodypositive
Profile click inferredPROFILE_CLICK_WEIGHTtap the author's name or avatarpositive
Share inferredSHARE_WEIGHTsystem share sheetpositive
Share via DM inferredSHARE_VIA_DM_WEIGHTsend to a specific user via direct messagepositive
Share via copy link inferredSHARE_VIA_COPY_LINK_WEIGHTcopy the post URL to clipboardpositive
Continuous dwell time inferredCONT_DWELL_TIME_WEIGHTregression target over the actual time the viewer pausedpositive
Follow author inferredFOLLOW_AUTHOR_WEIGHTtap follow from inside the post unitpositive
Not interested inferredNOT_INTERESTED_WEIGHTlong-press menu, "Not interested in this post"negative
Block author inferredBLOCK_AUTHOR_WEIGHTblock the author from inside the post menunegative
Mute author inferredMUTE_AUTHOR_WEIGHTmute the author from inside the post menunegative
Report inferredREPORT_WEIGHTreport the post for a policy violationnegative

One subtle item: home-mixer/scorers/vm_ranker.rs's PhoenixScores proto contains a not_dwelled_score field that does not appear among the nineteen-head outputs and does not pair with a WEIGHT constant in the simpler weighted scorer. The presence of this field suggests that an experimental scoring path through vm_ranker.rs is running with at least one extra signal the public weighted_scorer.rs does not use. A6 walks the four dwell-related signals including this implicit one.

The third table places the open 2026 stack next to the only widely distributed reference point we have for comparable numeric weights: the 2023 release. The 2023 numbers are not authoritative for 2026 in any way; they are included only because they are the loudest existing reference. Treat them as directional indicators of relative weight magnitudes, not as production values.

Relative weight magnitudes: 2023 leaked release vs 2026 redacted release

Source: 2023 from twitter/the-algorithm-ml SrcEngagementWeights.scala; 2026 from xai-org/x-algorithm with params/ excluded

Head2023 leaked weight2026 statusPolarity
Favorite 2023 ref0.5redacted+
Retweet (repost) 2023 ref1.0redacted+
Reply 2023 ref13.5 or 27.0 (two constant sets)redacted+
Profile click 2023 ref12redacted+
Dwell (continuous) 2023 ref0.0001redacted+
Not interested 2023 refminus 74redactedminus
Mute author 2023 refapproximately minus 100redactedminus
Block author 2023 refapproximately minus 100redactedminus

Two relative-magnitude properties survive across both stacks. Reply is worth far more than favorite per action (the 2023 ratio is roughly 27 to 0.5, a factor of 54). Profile click is worth more than favorite by a similar order. Continuous-dwell time is a very small per-unit weight multiplied by a number that can be tens or hundreds of milliseconds, so its expected contribution per impression is in the same range as the discrete heads despite the tiny constant. And the negative heads dwarf the positive heads in absolute magnitude. A single predicted mute, at roughly minus 100 to the favorite's plus 0.5, costs the equivalent of roughly two hundred favorites of expected score in the 2023 numbers. The 2026 redaction prevents us from claiming a current ratio, but the asymmetric offset_score branch and the four explicit negative WEIGHT constants in the 2026 code make clear that the structural property (negatives outweigh positives per action) persists.

The four heads everyone teaches and why they are not the most important

Most public algorithm coverage focuses on four heads: favorite, retweet (repost), reply, and follow. These are the visible engagement actions, in the sense that the post unit on the screen displays counts for the first three and that follower count is an obviously trackable metric. The fourth, follow author from a post, was the prized 2023 signal because the public Twitter algorithm code described follow as the conversion event the ranker most wanted.

Three structural reasons those four are not the most predictive of feed position in 2026.

First, like and retweet are the lowest-weighted positive heads in the 2023 reference and there is no reason to expect that to invert in 2026. The relative ratios suggest they exist to nudge the score, not to drive it. Reply has a much higher per-action weight, but reply requires composing text and shipping it; the volume of replies per impression on any given post is structurally a fraction of the volume of likes. The math works out to reply being a heavier per-action signal but a lighter total-volume contribution than its constant suggests for most posts.

Second, follow author depends on the viewer not already following the author. If the viewer is in your follower base, that head is zero for every one of your posts they see. The signal exists primarily for out-of-network candidates served via the Phoenix retrieval lane, where the viewer is meeting you for the first time.

Third, all four of these heads are visible-engagement heads. The model also predicts probability of profile click, photo expand, click, share, and three dwell-related variants for the same impression. A creator optimising for visible counts is leaving the per-impression score of nine of the fifteen positive heads on the table. Posts that fire only the visible heads run into a ceiling. Posts that fire visible plus invisible heads break through.

The six heads nobody teaches

A creator who has read three Twitter-algorithm explainers in the last year has probably never seen the following heads enumerated. They are the ones worth understanding in detail.

Video quality view (VQV_WEIGHT, index 13). Gated on video_duration_ms exceeding a MIN_VIDEO_DURATION_MS threshold. Below the threshold, the video earns zero on this head no matter how many times it plays. Above the threshold, every qualifying play contributes. For creators shipping video, this single threshold means a 4-second loop and a 15-second cut produce categorically different score contributions on the same content. Production thresholds are not in the public source. Verified at index 13 in phoenix/run_pipeline.py.

Photo expand (PHOTO_EXPAND_WEIGHT). A viewer taps a photo to open it full screen. That gesture is far more deliberate than scroll-past or like. Posts whose photos are detail-rewarding (text in the photo, chart detail, layered image) fire this head; posts whose photos are decorative do not.

Profile click (PROFILE_CLICK_WEIGHT). Viewer taps the author's name or avatar to view the profile. Authority-and-curiosity signal. The ratio of profile clicks to impressions is one of the cleanest indicators of "this post made me want to learn who you are." The 2023 reference weight for this was 12, the second highest after reply.

Click (CLICK_WEIGHT). Tap on a link inside the post body. Note that this is the link click, not the post click. Posts that earn the click are posts that have made the case for the link inside the 280 characters above it. A short post with a link and no setup gets very few clicks; a short post with a one-sentence setup that earns the click fires both this head and the continuous dwell head while the viewer reads the setup.

Share via DM (SHARE_VIA_DM_WEIGHT). The viewer sent your post to a specific other person via direct message. The most under-discussed positive signal on the platform. It encodes "I think this is worth a specific other human's attention." Idiosyncratic, opinionated, useful, and well-framed posts fire it. Generic engagement-shaped posts almost never do.

Share via copy link (SHARE_VIA_COPY_LINK_WEIGHT). The viewer copied the URL to send out of channel. Slack, Notion, an email, an external forum. Same intent as share via DM, different surface. Combined with share via DM, these two heads are the platform's best proxies for "this post will be referenced again later."

These six are all in the inferred-index table above. The WEIGHT constants and proto field names exist in the public code. The exact Phoenix output index they pair with is inferred from field-name correspondence.

The four negative heads and the math that makes them outweigh dozens of positives

Not interested, mute, block, report. Four explicit negative WEIGHT constants in home-mixer/scorers/weighted_scorer.rs. Each is a one-action gesture by a viewer that tells the ranker "show me less of this." Each carries a large-magnitude negative weight.

The math: the weighted sum combined = Σ_i (P(action_i) × WEIGHT_i) runs over all nineteen heads with their respective weights. Phoenix's predicted probability for each negative action sits between 0 and 1 like every other head, but multiplied by weights that are an order of magnitude larger and negative in sign. In the 2023 numbers, a predicted mute probability of even five percent applied to a weight of minus 100 yields a contribution of minus 5. That single contribution dominates the contribution of dozens of predicted favorites at weight 0.5.

Two consequences for creators. First, posts that drift off voice trigger non-trivial predicted mute probability from followers who built the follow on a different voice. A8 walks the embedding mechanism behind that prediction. Second, the offset_score branch makes the penalty asymmetric: a post that nets positive scores roughly linearly, while a post that nets negative through predicted mutes and not-interested gets rescaled into a different range entirely. Net-negative posts are not just lower-scored; they sit in a different regime.

The negative-signal economy is the single most defensible reason to build a voice-fidelity check into a writing tool. Tweet Hunter and similar template-driven generators have no concept of voice match; they optimise visible-engagement template fit, which is exactly the surface that drifts away from a creator's audience-anchored voice. The downstream math is the negative-head economy multiplying that drift across every predicted mute.

There is also a hard-filter layer running in parallel to the weighted score. home-mixer/filters/muted_keyword_filter.rs removes candidates whose tokens match the viewer's muted-keyword list before they ever reach the scorer. home-mixer/filters/author_socialgraph_filter.rs runs six explicit conditions including block-author and mute-author boolean gates, regardless of what Phoenix predicts. The four negative heads in the weighted scorer handle the probabilistic case (the viewer will probably want to mute this if served). The filter layer handles the deterministic case (the viewer has already muted this author, do not serve their posts at all). Both layers feed the same "less of this" intent, on different signal pathways. A creator who drifts off voice faces probabilistic predicted-mute penalties first, and accrues deterministic mute-filters from followers second. The two effects compound: each actual mute removes that follower from your impression pool entirely while raising the predicted-mute prior for similar followers next time.

Continuous dwell time as the silent kingmaker

Discrete dwell is index 11, verified. Continuous dwell time (CONT_DWELL_TIME_WEIGHT) is inferred and operates on the actual duration the viewer's eye sat on your post in the scroll feed. The per-millisecond weight is tiny in the 2023 reference (0.0001) but the total contribution scales with the duration. A post that holds a viewer for twelve seconds, at 12,000 milliseconds times 0.0001, contributes 1.2 on a single head. Compare that to the favorite weight of 0.5 per like. One twelve-second dwell, in the 2023 numbers, is worth more than two likes.

That math is structurally important because dwell is unfakeable in a way favorites are not. Likes can be reciprocated, traded, automated. Dwell happens or does not happen on the basis of whether the viewer actually reads the post. Hook density, line-break rhythm, second-line payoff, narrative arcs that need to be finished to make sense, all of these fire continuous-dwell. Generic engagement-bait does the opposite: it delivers its full payload in the first three words and the viewer scrolls past.

The graph below sketches the score-shape difference between a likes-only post and a balanced post that fires multiple heads. Numbers are illustrative, not from production telemetry.

Score contribution by head class, two post archetypes

Source: illustrative simulation, weights and counts notional

1007550250FavoriteReplyProfile clickContinuous dwellShare via DMrelative head contribution
Likes-only post (200 likes, no dwell, no profile clicks)Multi-head post (80 likes, 12s dwell, profile clicks, DM shares)

Read the right column carefully. The multi-head post earns less than half the favorites but lights up four other heads at material contribution. The sum of the right column is structurally several times the sum of the left, even though only one head is "higher" on the visible-counts surface. That is the central property of the 2026 ranker. It rewards distribution of contribution across heads, not concentration on one.

Voice as a meta-head

The argument that closes this piece is the one most algorithm coverage will not make because it requires connecting the model architecture to audience-specific reaction patterns. Phoenix conditions every prediction on the viewer's history sequence. That sequence is a record of which heads each viewer has historically fired on, for which authors. A viewer whose history sequence is dominated by long-form thread reads with twelve-second dwells has, encoded in their history embedding, a strong prior on dwell-firing posts from accounts they have engaged with.

When a new candidate from you arrives in front of that viewer, Phoenix's prediction for your dwell head is conditioned on two things: the candidate post itself, and the viewer's per-creator history pattern. If your past posts in that viewer's history have systematically fired their dwell head, the model has a high prior for your next post firing it too. If your past posts have systematically fired favorite-only, the prior is concentrated on favorite, not on dwell.

Voice consistency feeds that per-creator prior. A creator whose posts systematically fire dwell, replies, and DMs in their follower base builds up a per-creator history pattern across all those followers' history sequences that anchors Phoenix's prediction for new posts. A creator whose recent posts diverge from that pattern (off-voice generic engagement-bait, suddenly) breaks the prior, and Phoenix falls back on the candidate-only signal, which is much weaker. The drift is felt as quieter posts. The mechanism is the predicted-action mix collapsing toward the cold-start baseline.

That is the structural argument for voice as a writing-product surface worth measuring. Auden's job, inside VoiceMoat, is to keep posts on a creator's historical distribution across the heads their audience reliably fires on. The full inventory of how Auden does this lives in the product docs; the algorithm-level reason it matters lives in the nineteen heads above.

A practical framework for writing toward multiple heads

The framework that falls out of the nineteen heads is shorter than most "X algorithm playbooks" by an order of magnitude. Five operational moves, each backed by a specific head.

One: end with something replyable, not a takeaway. Replies have the heaviest per-action positive weight in every reference set we have, and the cost of "writing for replies" is low: ask one question your audience has a real answer to, or land on one opinion they will want to push back on. Generic CTAs ("agree?", "thoughts?") underperform specific prompts because the predicted-reply head is conditioned on the viewer's history of which kinds of posts they actually reply to. Specific prompts that match historical reply patterns fire the head; generic ones do not.

Two: write a second-line payoff that earns the dwell. Continuous dwell rewards posts whose first line opens a loop the second line closes. "I shipped three products in 2025. Two failed. Here is what the third did differently." That structure fires the dwell head because the viewer has to read past the hook to extract the value. Headline-only posts deliver the payload in the first line and lose the dwell.

Three: include exactly one click-worthy element when the post needs it, and otherwise omit the link. The click head rewards posts that make the case for the link inside the post body. Linkless posts lose the click head but win on other surfaces; link-heavy posts that fail to earn the click hurt the predicted-click probability across the creator's history pattern. Be deliberate.

Four: prefer posts that someone would specifically DM another person about. The share-via-DM head is the cleanest signal of "this is worth referencing later." Posts that fire it tend to be opinionated, operational, or counter-conventional. Posts that are simply pleasant or mildly informative do not fire it. The test is concrete: would a specific person you know send this to a specific person they know? If yes, the head fires. If no, it does not.

Five: do not optimise visible counts at the expense of voice. The nine invisible-engagement heads (profile click, photo expand, click, three share variants, two dwell variants, follow-author) are not visible to the creator or the audience, but they sum to the majority of the weighted score for most posts. Visible-count optimisation usually means template fit, which usually means voice drift, which means raising predicted-mute probability across the follower base. That is a worse trade per impression than the visible-count gain pays for.

That is the entire framework. Five moves. Each maps onto a specific head or head cluster. Each survives the redacted weights because each rests on the relative-ratio property (replies and clicks and dwell weigh more than likes; negatives weigh more than positives in magnitude; multiple heads distribute risk; voice consistency anchors the per-creator prior) rather than any specific numeric weight.

Up next in this series: A5 on the negative-signal economy, which expands the four negative heads into the full filter stack and the off-voice-drift pipeline. A6 walks the four dwell heads in particular, including the not_dwelled_score puzzle. A8 returns to the embedding mechanism that makes voice-as-a-meta-head operational.

AI disclosure

This article was drafted with AI assistance and human-edited by the VoiceMoat team. All technical claims are sourced to the xai-org/x-algorithm repository; file paths are cited inline.