How It Works
1. Fetch Your Likes
We query Bluesky's API to get your last 100 likes and build a fast picture of who you reliably engage with:
GET app.bsky.feed.getActorLikes?actor={your_did}&limit=100
2. Calculate Affinity
We identify which authors you engage with most and keep the post URIs you already liked:
def get_affinity(user_did):
likes = bsky.get_actor_likes(actor=user_did, limit=100)
liked_uris = {post.uri for post in likes}
# Count likes per author
author_counts = Counter()
for post in likes:
if post.author.did != user_did:
author_counts[post.author.did] += 1
return author_counts, liked_uris
3. Measure Recent Affinity
For each top author, we check what percentage of their recent posts you've liked. This becomes the core ranking signal, but not the only one:
def get_like_rate(author_did, liked_uris):
# Get author's recent posts
author_posts = bsky.get_author_feed(author_did, limit=100)
# Count how many you've liked
liked_count = sum(1 for p in author_posts if p.uri in liked_uris)
like_rate = liked_count / len(author_posts) * 100
return like_rate # e.g. "70% (7/10)"
4. Add Exploration Lanes
Orbit is no longer just "people you already like." It now mixes in two small exploration lanes:
- Discovery - people multiple favorites already follow.
- Frontier - recent posts from authors adjacent to your orbit in the interaction graph, filtered for lightweight quality.
def build_candidates(user_id, affinity, liked_uris):
candidates = affinity_posts(...)
candidates += discovery_posts(...)
candidates += frontier_posts_from_interaction_graph(...)
return candidates
5. Rank Core + Frontier Together
We rank the combined pool with different score shapes for each lane. Affinity posts still dominate, but fresh low-signal posts can break through:
def score(post):
if post.source == "discovery":
return recency + bounded_exploration + entropy
if post.source == "frontier":
return recency + adjacency_bonus + bounded_exploration + entropy
return affinity + like_rate + recency + low_signal_boost + entropy
Why This Approach?
No data storage needed - We query Bluesky directly. Your likes are already
stored there; we don't duplicate them.
Always up to date - Every feed request gets fresh data from Bluesky.
If you like someone new, they appear immediately.
Core + frontier - Orbit still treats likes as the strongest signal, but it now reserves a small amount of space for adjacent and underexposed posts so the feed can move beyond incumbents.
Shaped exploration - Exploration is not just blind randomness. Frontier posts come from recent graph-adjacent authors and are filtered for basic quality before they enter ranking.
Ideas for Improvement
Reciprocity
Show who engages back with you. Fetch likes on your recent posts and count by author:
my_posts = bsky.get_author_feed(my_did, limit=20)
for post in my_posts:
likes = bsky.get_likes(post.uri)
for like in likes:
who_likes_me[like.actor.did] += 1
Frontier Quality
Make the shaped frontier smarter instead of simply larger:
- Semantic frontier - Prefer posts near the edge of your taste profile instead of just graph-adjacent accounts.
- Underexposed quality - Detect posts with substance and early replies even before they accumulate broad engagement.
- Lane budgeting - Explicitly reserve percentages for core, discovery, and frontier instead of using fixed candidate counts.
# Future direction: rank frontier by both graph and semantics
frontier_score = (
graph_adjacency(author) +
semantic_similarity(post, user_profile_edge) +
reply_quality(post) +
freshness(post)
)