Paste the first post of a Bluesky thread and see which accounts the replies @ the most.

Files
README.md

Thread mention counter #

Paste the first post of a Bluesky thread and see which accounts the replies (and replies to replies) @-mention most. Each result shows the avatar, display name, handle, and how many different people named them, and links to the Bluesky profile.

Built with SvelteKit, Tailwind CSS, and daisyUI. All data comes from microcosm.blue services:

  • constellation joins every post whose reply.root is the pasted post to the DIDs those posts mention, in one paged query per facet path (blue.microcosm.links.getManyToMany).
  • slingshot resolves handles and DIDs (resolveMiniDoc) and fetches the root post and each profile record (com.atproto.repo.getRecord). Avatar URLs are built from the profile blob CID against cdn.bsky.app.

Only thread roots are accepted. Pasting a reply shows an error with a link to the root.

Developing #

pnpm install
pnpm dev

Then open http://localhost:5173/?post=https://bsky.app/profile/syntax.fm/post/3mxcbvqg4mc23.

Set MICROCOSM_USER_AGENT (for example in .env.local) to a string naming your project and a contact; microcosm asks for this on every request. A fallback is used when it is unset.

pnpm test    # unit tests for the URL parser and the tally
pnpm check   # svelte-check
pnpm build   # production build

Caching #

src/lib/server/cache.ts wraps lru-cache with a getOrSet(key, ttl, fetcher) helper that also coalesces concurrent fetches for the same key. It is in-process, so it needs a long-running server (adapter-node, Bun, a container) to be useful; on serverless each cold start begins empty. Swap the backing store in that one file if you ever need Redis.

What Key TTL
Handle ⇄ DID (slingshot mini-doc) identity:<handle or did> 24 h
Profile record profile:<did> 1 h
Empty results (deleted account, no profile) same keys 5 min
Whole thread analysis analysis:<actor>/<rkey> 2 min

Errors are never cached.

How counting works #

src/lib/server/tally.ts dedupes on (post, mentioned DID) and then counts, per DID, the distinct posts and distinct authors that mentioned them. Results sort by distinct authors, then by posts, so one person repeatedly mentioning the same account only counts once. The constellation getManyToManyCounts endpoint is not used because it undercounts.

Deploying #

The app uses @sveltejs/adapter-node, so pnpm build produces build/ and pnpm start (node build) serves it on PORT (default 3000). It runs on Railway with zero config: Railpack detects pnpm (pinned via packageManager), runs pnpm build, then pnpm start.

railway up          # deploy the current directory to the linked service

Set MICROCOSM_USER_AGENT on the service to identify your deployment to microcosm.