Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision ae05747989c0db698829b0eccb94de8a33d7399f)
+++ src/routes/posts.js	(revision 4424af7fc82df76bcf2fcaf1e1f373a4eb94a526)
@@ -1070,4 +1070,8 @@
     html = html.replace(/\[\[(track|album|playlist):[^\]]+\]\]/gi, '');
   }
+  // Linkify inline #hashtags and bare URLs for on-site display — same rules as the
+  // federated copy (buildNote). Was: only the Mastodon copy got links; the website
+  // showed raw "#tag"/URL text. Idempotent, so editor links + embeds are untouched.
+  html = ActivityPubService.linkifyBody('', html);
   post.content_html = html;
 
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision ae05747989c0db698829b0eccb94de8a33d7399f)
+++ src/services/ActivityPubService.js	(revision 4424af7fc82df76bcf2fcaf1e1f373a4eb94a526)
@@ -1422,4 +1422,17 @@
   return parts.join('');
 }
+// Linkify inline #hashtags and bare URLs in BODY html for on-site DISPLAY, using the
+// EXACT same rules as the federated copy (linkHashtags/linkUrls), so the website and the
+// Mastodon copy agree instead of the website showing raw text. Idempotent: existing
+// <a>…</a> (editor links, embeds, shortcode buttons) are split out and left untouched, so
+// nothing is double-wrapped. Pass base='' → root-relative /tag/<slug> links.
+export function linkifyBody(base, html) {
+  const withTags = String(html || '')
+    .split(/(<a\b[^>]*>[\s\S]*?<\/a>)/gi)
+    .map((seg) => (/^<a\b/i.test(seg) ? seg : linkHashtags(base, seg)))
+    .join('');
+  return linkUrls(withTags);
+}
+
 // Extract the AP Hashtag tag objects from already-linked reply content.
 function hashtagTags(base, content) {
@@ -2421,3 +2434,4 @@
   deliverWithRetry, enqueueDelivery, processDeliveryQueue, startDeliveryWorker,
   getReplyUris, markNotificationsSeen, countUnseenNotifications, hasPlayableAudio,
+  linkifyBody,
 };
