The feed is explicitly ordered by a post’s predicted chance of getting favorited. That means content that reliably earns likes from the target audience tends to rise to the top. Use clear, opinionated takes, strong hooks, and easy-to-like formats (quick wins, templates, relatable truths). If your posts get impressions but low likes, the system is likely to rank them lower over time for similar viewers.
Source Evidence
📁 phoenix/run_ranker.py
The demo prints ranking results ordered by predicted 'Favorite Score' probability, indicating favorites are a primary ordering signal in this ranking view.
print("RANKING RESULTS (ordered by predicted 'Favorite Score' probability)")
for rank, idx in enumerate(ranked_indices):
(main(): output section near ranking display)
Try This
▸“Unpopular opinion: most creators should post less often and edit more. Here’s my 3-step editing checklist…”
▸“If you only do ONE thing to improve your posts this week, do this: [simple actionable tip].”
▸“I tested 5 hooks for the same idea. The winner doubled likes. Here are all 5 hooks (steal them).”
High
Hold attention to boost dwell signals
The system uses both a “dwelled” signal and a dwell-time estimate, so keeping people reading matters. Use strong first lines, short paragraphs, and clear structure (numbered steps, bold claims + proof). Deliver value early, then expand—don’t bury the point. If people pause on your post, it can score better even without immediate likes.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted dwell and predicted dwell time as separate positive terms.
▸“Here’s the exact 5-step process I use to turn one idea into 10 posts (step-by-step).”
▸“I wasted 6 months doing this wrong. The fix took 10 minutes. Here’s the breakdown…”
▸“A simple framework: Problem → Mistake → Fix → Example. Let me show it on a real post…”
High
Write posts that spark replies
Replies are one of the engagement outcomes the system predicts and uses in scoring. Posts that invite thoughtful responses can gain a meaningful boost because they signal conversation value. Ask a specific question, present a tradeoff, or share a strong stance that encourages people to respond. Avoid vague “thoughts?” prompts—make the reply easy by giving options.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes a term for predicted replies, meaning reply likelihood contributes directly to ranking.
+ Self::apply(s.reply_score, p::REPLY_WEIGHT)
(compute_weighted_score())
Try This
▸“Creators: would you rather have 10k followers who never buy, or 1k who do? Why?”
▸“Hot take: threads are overrated. Single posts win. Agree/disagree—tell me your experience.”
▸“Pick one: A) Post daily with rough drafts B) Post 3x/week but polished. Which grows faster for you?”
High
Build in-network reach by earning follows
Out-of-network posts are explicitly downweighted compared to in-network posts. The practical takeaway: growing your follower base increases how often you’re “in-network,” which protects your distribution. Convert profile visits into follows with clear positioning and consistent value. Also, nurture existing followers so your posts keep getting strong early engagement.
Source Evidence
📁 home-mixer/scorers/oon_scorer.rs
If a candidate is marked out-of-network, its score is multiplied by a weight factor (a downweight).
▸“If you’re new here: I share 3 practical writing tactics every week. Start with this one…”
▸“Follow if you want more teardown posts—next one is tomorrow: ‘How to write hooks that convert.’”
▸“My best posts (for new followers): 1) … 2) … 3) …”
High
Make your posts retweetable
Retweets are a direct scoring input, so content that people want to share publicly can climb. Create “identity” posts people want to be associated with, concise summaries, or useful checklists. The easier it is to share without extra context, the more likely it gets amplified. Tighten wording so someone can retweet it as-is.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted retweets as a positive term.
+ Self::apply(s.retweet_score, p::RETWEET_WEIGHT)
(compute_weighted_score())
Try This
▸“A simple rule: if your hook doesn’t create curiosity in 1 line, rewrite it.”
▸“Creator checklist before you hit post: 1) Hook 2) Proof 3) One clear takeaway 4) CTA.”
▸“Stop doing ‘tips’ with no examples. Show the exact wording you’d use.”
High
Turn profile visits into a ranking boost
Profile clicks and follows are both scored, meaning posts that make people want to learn who you are can rank better. Use posts that signal expertise (case studies, results, strong frameworks) and make your bio match the promise. Add a line that naturally invites a profile check, like “I share more breakdowns like this.” If your profile is unclear, you’ll waste this signal.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted profile clicks and predicted follows of the author.
▸“Case study: how I grew from 0 to 10k impressions/day with 3 post formats (screenshots + steps).”
▸“If you want more teardown posts like this, I write one every week—follow for the series.”
▸“I’ve written 200 hooks. Here are the 10 that keep winning (and why).”
High
Create content people share via DMs
Private sharing (sending via direct message) is explicitly scored, which is a strong sign your post is valuable or emotionally resonant. Make posts that feel “send this to a friend”: hiring advice, relationship-to-work insights, warnings, or highly practical templates. Write in a way that helps someone help someone else. If it’s too niche or too self-promotional, people won’t DM it.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted sharing, including sharing via DM.
▸“If your friend is burned out, send them this: 5 signs you need a real break (and what to do).”
▸“Template: the exact message to ask for a raise without sounding awkward.”
▸“A hiring manager’s checklist: 7 red flags in job postings (save/share this).”
High
Post videos long enough to qualify
Video quality viewing only counts if your video is longer than a minimum duration. Very short clips may miss out on this scoring boost entirely. If you’re using video, make it long enough to clear the threshold and deliver value quickly so people keep watching. Consider 20–60 seconds of tight teaching rather than ultra-short fragments.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The video-quality-view weight is applied only when video duration exceeds a minimum duration; otherwise the weight becomes zero.
if candidate.video_duration_ms.is_some_and(|ms| ms > p::MIN_VIDEO_DURATION_MS) { p::VQV_WEIGHT } else { 0.0 }
(vqv_weight_eligibility())
Try This
▸A 30–45s screen recording: “3 hook rewrites in real time”
▸A 25s video: “One editing trick to make your posts clearer”
▸A 60s mini-tutorial: “How to structure a post: hook → proof → takeaway”
High
Use images people will tap to expand
Image expansion is explicitly measured and contributes to ranking. That means images that reward a tap—charts, before/after, carousels, screenshots, or dense “cheat sheet” graphics—can help your post score better. Make the image legible and intriguing at thumbnail size so people want to open it. Pair the image with a caption that sets up what they’ll see.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted photo expansion as a positive term.
▸“I rewrote this hook 7 times. Screenshot of the final version + the 6 bad ones below.”
▸“Here’s my exact content calendar template (image). Steal it.”
▸“Before/after: how I turned a boring tip into a high-performing post (image breakdown).”
High
Earn clicks with curiosity and clarity
The system scores predicted clicks, so posts that make people tap through (to open, read more, or explore) can benefit. Use a clear promise plus a curiosity gap, but make sure the content delivers—otherwise negative feedback can offset gains. Structure posts so the first line sells the click and the next lines pay it off quickly. Avoid clickbait that frustrates readers.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted clicks as a positive term.
+ Self::apply(s.click_score, p::CLICK_WEIGHT)
(compute_weighted_score())
Try This
▸“I found a 2-sentence hook formula that consistently boosts engagement. Here it is + 5 examples…”
▸“Most ‘growth tips’ miss this one step. I’ll show the exact step-by-step workflow…”
▸“I audited 20 viral posts and noticed the same pattern. Breakdown below…”
Medium
Make posts worth saving via copy link
Copy-link sharing is scored, which usually happens when content is reference-worthy. Create evergreen resources: checklists, scripts, step-by-step guides, and “do this, not that” comparisons. Make it skimmable so people can quickly decide it’s worth saving. The more your post feels like a tool, the more likely it gets copied and shared.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted share via copy link.
▸“Copy/paste scripts: 5 ways to follow up after no reply (word-for-word).”
▸“A one-page checklist for launching a product in 7 days (bookmark this).”
▸“The 12-post idea bank I use when I’m stuck (steal it).”
Medium
Make each post stand alone (even in series)
Because only a limited number of top candidates are selected, each post needs to compete on its own merits. Don’t rely on “Part 2/Part 3” context to carry the post—make every entry valuable by itself. Use a quick recap line and deliver a complete takeaway. This increases the chance any single post makes the cut.
Source Evidence
📁 home-mixer/selectors/top_k_score_selector.rs
Selects only a fixed number of top-scoring candidates based on score, meaning posts compete for limited slots.
▸“Part 3” post that starts with: “Quick recap: the framework is X. Today: step 3 with examples.”
▸A series where each post includes one complete template or checklist
▸“If you only read one part, read this: [core takeaway]”
Medium
Use quote posts to add your take
Quote-post engagement is part of scoring, so content that inspires people to quote with commentary can help. Share strong, debatable ideas or useful posts that invite “adding your perspective.” Also, when you quote others, add real value—your quote can earn quotes too. Avoid low-effort quote dunking that triggers negative reactions.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted quote actions and clicks on quoted tweets.
▸“Most advice about consistency is wrong. Consistency without feedback is just repetition. Here’s the better rule…”
▸“Quote this with your niche: ‘The best content is a solved problem, explained simply.’”
▸“I disagree with this take—and here’s the data from my last 30 posts…”
▼
Things that hurt your reach
Negative Signals
17 signals
Critical
Safety/visibility flags can drop you entirely
There’s a visibility filtering step that can remove posts before they ever get ranked. If your content triggers safety actions, it may be dropped outright rather than merely ranked lower. Avoid borderline policy content, harassment, and anything that looks like manipulation or scams. When in doubt, rewrite to be factual, non-targeted, and non-inflammatory.
Source Evidence
📁 home-mixer/filters/vf_filter.rs
Drops candidates when a visibility filtering reason exists; for safety results, drops when the action is Drop; other filtered reasons are also dropped.
▸Harassment or targeted insults toward a person or group
▸Scam-like “guaranteed money” claims with pressure tactics
▸Coordinated manipulation calls like “report this account” or “brigade this post”
Critical
Stay far away from report-worthy posts
Reports are explicitly included as a negative outcome in scoring. Even if a post gets engagement, report risk can suppress it. Avoid misleading claims, impersonation vibes, harassment, and anything that looks like scams. When discussing sensitive topics, be careful with wording and provide context to reduce misinterpretation.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted reports as a term (negative in practice).
+ Self::apply(s.report_score, p::REPORT_WEIGHT)
(compute_weighted_score())
Try This
▸“DM me for the secret method” with no transparency (scam-like pattern)
▸Harassing callouts that encourage dogpiling
▸Misleading medical/financial claims presented as facts
Critical
Don’t post content that gets blocks
Blocks are explicitly modeled and included in scoring, which is a strong negative signal. Content that feels spammy, aggressive, misleading, or harassing increases the chance people block you. Keep claims honest, avoid personal attacks, and don’t over-DM or tag-bomb people. If you polarize, do it with ideas—not with insults.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted blocks as a term (negative in practice).
▸“Anyone who disagrees is an idiot” style posts aimed at individuals
▸Misleading ‘guaranteed results’ claims with no proof
▸Repeatedly tagging large accounts to force attention
Critical
Blocked or muted by a viewer means zero reach
If a viewer has blocked or muted you, your posts are removed before scoring for that person. This makes audience trust and tone a real distribution factor: annoying people doesn’t just lose a follower, it removes you from their feed entirely. Avoid spammy behavior, excessive tagging, and aggressive engagement tactics. Focus on consistent value so people don’t mute you.
Source Evidence
📁 home-mixer/filters/author_socialgraph_filter.rs
Removes candidates whose author ID is in the viewer’s muted or blocked lists.
let muted = viewer_muted_user_ids.contains(&author_id);
let blocked = viewer_blocked_user_ids.contains(&author_id);
if muted || blocked { removed.push(candidate); }
(filter(): AuthorSocialgraphFilter)
Try This
▸Reply-spamming large accounts to force visibility
▸Posting repetitive promos that lead people to mute you
▸Aggressive dunking on individuals that causes blocks
Critical
Freshness matters: old posts get removed
There is a hard cutoff that removes posts older than a configured age window. Even great posts won’t be considered if they’re too old for this feed request. If you want ongoing reach, repurpose the idea into a new post rather than relying on an old one to keep circulating. For evergreen topics, re-post with updated examples or a new hook.
Source Evidence
📁 home-mixer/filters/age_filter.rs
Filters out tweets whose creation time (derived from ID) is older than a maximum age duration.
snowflake::duration_since_creation_opt(tweet_id)
.map(|age| age <= self.max_age)
.unwrap_or(false)
(is_within_age() and filter(): AgeFilter)
Try This
▸Turning a high-performing tip from last month into a new post with a new example
▸“Updated for 2026: my 5-step posting workflow (with new tools)”
▸Reposting an old thread as a fresh single post summary + link to the original
Critical
Avoid triggering “Not interested” feedback
If people mark your post as “not interested,” it directly drags your score down. This often happens when content feels irrelevant, repetitive, or bait-and-switch. Stay consistent with your niche promise, and don’t overuse trending topics that don’t fit your audience. Make sure your hook matches what the post actually delivers.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted 'not interested' as a term (with a negative weight in practice).
▸“[Bait] ‘This will change your life’ … [delivers generic advice with no specifics]”
▸Posting off-topic viral drama to an audience that follows you for marketing tips
▸Reposting the same tip daily with slightly different wording
High
Avoid content that makes people mute you
Mutes are also predicted and used in scoring, so annoying patterns can quietly reduce your reach. Overposting, repetitive promos, and constant outrage are common mute triggers. Mix in value posts between promotions and keep a consistent cadence. If you run series content, vary the angle so it doesn’t feel like the same post every day.
Source Evidence
📁 home-mixer/scorers/weighted_scorer.rs
The weighted score includes predicted mutes as a term (negative in practice).
▸Posting the same product pitch multiple times per day
▸Daily rage-bait commentary unrelated to your niche
▸Long threads that repeat identical points without new info
High
Don’t expect repeat reach from the same post
Posts a viewer has already seen are filtered out using both explicit seen IDs and probabilistic history checks. That means recycling the exact same post won’t keep showing to the same people. If you want to revisit a topic, rewrite it with a new hook, new example, or a different format. Think “new packaging,” not “same post again.”
Source Evidence
📁 home-mixer/filters/previously_seen_posts_filter.rs
Removes candidates if any related post ID is in the viewer’s seen IDs or matches a bloom filter of seen content.
▸Reposting the exact same tip word-for-word every week
▸Posting the same thread again without updates
▸Reusing identical screenshots and captions repeatedly
High
Don’t flood the feed with many posts
The system reduces scores for repeated appearances from the same author within a single feed response. So even if you have multiple strong posts, the second, third, and fourth may be pushed down. Space out your best posts and focus on one standout piece at a time. If you post frequently, vary timing so you’re not competing with yourself in the same refresh.
Source Evidence
📁 home-mixer/scorers/author_diversity_scorer.rs
Sorts candidates by score, counts how many times each author appears, and applies a decaying multiplier to later posts from the same author (with a floor).
let position = *entry;
*entry += 1;
let multiplier = self.multiplier(position);
let adjusted_score = candidate.weighted_score.map(|score| score * multiplier);
(score(): AuthorDiversityScorer)
Try This
▸Posting 6 separate tips back-to-back in 10 minutes
▸Instead: one strong post + one follow-up reply thread that adds depth
▸Scheduling your top posts across different hours rather than clustering them
If a post is marked as subscription-only, it’s filtered out for viewers who aren’t subscribed to that author. That means subscription posts are great for monetization but limited for discovery. Use public posts for growth and reserve subscription posts for deeper, premium content. Tease the value publicly without locking the entire idea behind a paywall.
Source Evidence
📁 home-mixer/filters/ineligible_subscription_filter.rs
Filters out subscription-only posts unless the viewer is subscribed to the subscription author.
▸Public post: “3 lessons from my latest launch” + subscription post: full teardown with numbers
▸Public teaser: “Here’s the framework” + subscription: “Here are the templates and examples”
▸Public: “What I changed to grow” + subscription: “Exact weekly schedule and prompts”
Medium
Retweets are scored as the original post
For retweets, the system looks up predictions using the original post, not the retweet wrapper. That means adding no commentary doesn’t create a “new” piece of content for ranking—its fate is tied to the original. If you want your share to perform, add meaningful commentary (quote-post) so it becomes its own content. Use retweets for endorsement, quote-posts for distribution.
Source Evidence
📁 home-mixer/scorers/phoenix_scorer.rs
When building prediction requests and when looking up predictions, retweets use the original tweet ID and original author ID.
let tweet_id = c.retweeted_tweet_id.unwrap_or(c.tweet_id as u64);
let author_id = c.retweeted_user_id.unwrap_or(c.author_id);
...
let lookup_tweet_id = c.retweeted_tweet_id.unwrap_or(c.tweet_id as u64);
(score(): tweet_infos mapping and lookup_tweet_id)
Try This
▸Instead of a plain retweet: “This is the best explanation of hooks I’ve seen—here’s how I apply it in my niche…”
▸Quote-post with a counterexample: “I disagree with point 2; here’s what worked for me…”
▸Quote-post with a summary: “If you read one thing today, read this. Key takeaway: …”
Medium
Don’t rely on retweeting the same post
The feed removes duplicate appearances of the same original post, even if it shows up as multiple retweets. That means repeated retweets of the same content won’t keep getting extra slots in a single feed response. If you want more reach, create a fresh angle or a new post rather than repeatedly resurfacing the same one. For collaborations, encourage original commentary instead of identical reshares.
Source Evidence
📁 home-mixer/filters/retweet_deduplication_filter.rs
Deduplicates retweets by tracking the original tweet ID; if the same original appears again (as retweet or original), later occurrences are removed.
match candidate.retweeted_tweet_id {
Some(retweeted_id) => { if seen_tweet_ids.insert(retweeted_id) { kept.push(candidate) } else { removed.push(candidate) } }
None => { seen_tweet_ids.insert(candidate.tweet_id as u64); kept.push(candidate) }
}
(filter(): RetweetDeduplicationFilter)
Try This
▸Retweeting your own viral post 5 times in a day expecting repeated feed placement
▸A group of accounts retweeting the exact same original post without adding commentary
▸Reposting the same announcement as a retweet instead of a new update
Medium
If someone mutes keywords, you disappear
Viewers can mute keywords, and posts matching those muted terms are filtered out completely for them. If you rely heavily on buzzwords or polarizing terms, you may lose reach with parts of your audience who muted them. Use clearer, more specific language and avoid stuffing the same trendy keyword into every post. Consider synonyms or more descriptive phrasing when appropriate.
Source Evidence
📁 home-mixer/filters/muted_keyword_filter.rs
Tokenizes viewer-muted keywords and removes any candidate whose tokenized text matches the mute matcher.
if matcher.matches(&tweet_text_token_sequence) { removed.push(candidate); } else { kept.push(candidate); }
(filter(): MutedKeywordFilter)
Try This
▸Overusing a commonly muted buzzword in every post title
▸Posting about a controversial topic using the exact muted term repeatedly
▸Hashtag stuffing with terms people often mute
Medium
Only one post per conversation branch survives
If multiple posts from the same conversation thread are candidates, only the highest-scored one is kept. That means flooding a thread with many similar replies won’t get multiple slots in the same feed response. If you want a thread to travel, make the best single reply the strongest and most self-contained. Put your key point in one standout post rather than spreading it across many.
Source Evidence
📁 home-mixer/filters/dedup_conversation_filter.rs
Groups candidates by conversation branch and keeps only the highest score per conversation ID; others are removed.
if let Some((kept_idx, best_score)) = best_per_convo.get_mut(&conversation_id) {
if score > *best_score { ... } else { removed.push(candidate); }
}
(filter(): DedupConversationFilter)
Try This
▸Posting 8 separate replies in the same thread hoping all will be recommended
▸Instead: one high-quality reply with a mini-framework and example
▸A single reply that summarizes your full argument clearly in 3–5 lines
Medium
At the bottom of feed, repeats get removed
When the app requests more posts (a “bottom” request), previously served posts are filtered out. So if you’re trying to game reach by pushing the same content into multiple fetches, it won’t keep appearing to the same viewer in that session. To benefit from continued scrolling, publish multiple distinct posts rather than one repeated idea. Build a content ladder: post A leads to post B, not post A again.
Source Evidence
📁 home-mixer/filters/previously_served_posts_filter.rs
Only enabled for bottom requests; removes candidates whose related IDs are in served_ids.
(enable() and filter(): PreviouslyServedPostsFilter)
Try This
▸Posting one announcement repeatedly instead of a sequence of updates
▸Recycling the same hook across multiple posts in a short session window
▸Publishing a series where each part is genuinely new instead of rephrased repeats
Medium
Don’t post empty or missing-text content
Posts with missing author info or empty text are filtered out before ranking. If your post is effectively blank (or looks blank due to formatting), it may not be eligible for recommendation at all. Always include meaningful text, even when posting media. Add a clear caption that explains why the viewer should care.
Source Evidence
📁 home-mixer/filters/core_data_hydration_filter.rs
Filters out candidates with missing author ID or empty/whitespace-only text.
▸Posting media with a single ambiguous character and no context
Low
Duplicate posts are removed from candidates
Exact duplicate IDs are dropped, so the system won’t keep multiple copies of the same post in the candidate set. While creators can’t control internal duplication, this reinforces a broader point: repetition doesn’t create extra slots. Focus on unique posts and unique angles. If you’re syndicating, vary the content rather than duplicating it.
Source Evidence
📁 home-mixer/filters/drop_duplicates_filter.rs
Tracks tweet IDs and removes any candidate whose tweet_id has already been seen in the candidate list.
if seen_ids.insert(candidate.tweet_id) { kept.push(candidate); } else { removed.push(candidate); }
(filter(): DropDuplicatesFilter)
Try This
▸Posting the same text as multiple separate posts (copy/paste) in a short window
▸Re-uploading identical content without changes expecting extra distribution
▸Instead: rewrite the same idea with a new example and a different hook