Stegodon implements ActivityPub Server-to-Server (S2S) federation, allowing users to follow and be followed by accounts on other Fediverse servers (Mastodon, Pleroma, etc.). Activities are signed with HTTP Signatures and delivered via a background queue with retry logic.
- ActivityPub (Server-to-Server)
- WebFinger
- HTTP Signatures (RSA-SHA256)
- NodeInfo 2.0/2.1
Follow(Actor)- Auto-accepted, creates follower relationshipAccept(Follow)- Confirms outgoing follow requestsUndo(Follow)- Removes follower relationship (authorization verified)Undo(Like)- Removes like and decrements counterUndo(Announce)- Removes boost and decrements counterCreate(Note)- Stores posts from followed accounts or relay subscriptions (withinReplyTosupport)Update(Note)- Updates stored post contentUpdate(Person)- Re-fetches and caches actor profileDelete(Note)- Removes stored post (authorization verified)Delete(Actor)- Removes actor and all associated followsLike- Stores like and increments counter on target noteAnnounce- Stores boost/reblog or relay-forwarded content
Accept(Follow)- Sent automatically when receiving FollowFollow(Actor)- Sent when following a remote userFollow(Public)- Sent when subscribing to a relay (object ishttps://www.w3.org/ns/activitystreams#Public)Undo(Follow)- Sent when unfollowing a remote user or unsubscribing from a relayCreate(Note)- Delivered to all followers when posting (includesinReplyTofor replies)Update(Note)- Delivered to all followers when editingDelete(Note)- Delivered to all followers when deletingLike- Sent when pressing 'l' on a remote post (TUI)Undo(Like)- Sent when unliking a previously liked remote postAnnounce- Sent when pressing 'b' to boost a post (TUI)Undo(Announce)- Sent when unboosting a previously boosted post
Note- Primary content type for postsTombstone- Received in Delete activities
Person- User accounts
/users/:username- Actor profile/users/:username/inbox- Actor inbox (POST)/users/:username/outbox- Actor outbox (GET, paginated)/users/:username/followers- Followers (OrderedCollection)/users/:username/following- Following (OrderedCollection)/inbox- Shared inbox (POST, used by relays)/notes/:id- Individual note objects
/.well-known/webfinger- WebFinger endpoint (JRD format)/.well-known/nodeinfo- NodeInfo discovery (links to 2.0 and 2.1)/nodeinfo/2.0- NodeInfo 2.0 endpoint/nodeinfo/2.1- NodeInfo 2.1 endpoint (adds repository, homepage)
- Algorithm:
rsa-sha256 - Signed headers:
(request-target),host,date,digest - Key format: RSA 2048-bit (PKIX/PKCS#8)
- All incoming activities require valid signatures
- Relay-forwarded content: signature verified against the relay's key (signer may differ from activity actor)
- Outgoing posts use
mediaType: text/html - Markdown links are converted to HTML anchor tags
- Hashtags are parsed and included in the
tagarray with typeHashtag - Hashtag HTML format:
<a href="..." class="hashtag" rel="tag">#<span>tag</span></a> - Mentions (@username@domain) are parsed and included in the
tagarray with typeMention - Mention HTML format:
<span class="h-card"><a href="..." class="u-url mention">@<span>username</span></a></span> - Mentioned actors are added to the
ccfield for delivery - JSON-LD context includes
Hashtag: as:Hashtagwhen hashtags are present - Incoming content stored as-is in activity JSON
- Incoming mentions are extracted from the
tagarray and stored innote_mentionstable
- Replies include the
inReplyTofield pointing to the parent note's URI - When replying to a remote user, the parent author's inbox is added to the
cclist - Replies are stored with their
in_reply_to_uriin the database for thread reconstruction - Reply counts are denormalized and recursively updated (includes all nested sub-replies)
- Duplicate detection prevents counting federated copies of local posts twice
- TUI: Press
rto reply,Enterfor thread view,lto like/unlike,bto boost/unboost - Web: Single post pages show parent context and replies section
- Full thread depth supported with nested reply navigation
Stegodon supports ActivityPub relays for discovering content beyond direct follows. Relays aggregate and forward posts from across the Fediverse.
FediBuzz-style relays (e.g., relay.fedi.buzz):
- Hashtag-based subscriptions (e.g.,
https://relay.fedi.buzz/tag/music) - Content wrapped in
Announceactivities - Multiple tag subscriptions from same relay domain supported
YUKIMOCHI Activity-Relay (e.g., relay.toot.yukimochi.jp):
- Full firehose relay
- Raw
Createactivities forwarded directly - Uses shared inbox (
/inbox) for delivery - Follow object must be
https://www.w3.org/ns/activitystreams#Public
Access the relay panel from the admin menu:
| Key | Action |
|---|---|
a |
Add new relay subscription |
d |
Delete/unsubscribe from relay |
p |
Pause/resume relay (toggle) |
r |
Retry failed subscription |
x |
Delete all relay content from timeline |
- pending - Follow request sent, waiting for Accept
- active - Relay accepted, receiving content
- paused - Subscription active but content not saved (logged only)
- failed - Subscription failed (can retry)
When a relay forwards content, the HTTP signature is from the relay, not the original author. Stegodon:
- Extracts the
keyIdfrom the Signature header - Verifies the signature against the relay's public key
- Identifies relay-forwarded content when signer differs from activity actor
- Marks such activities with
from_relay=truein the database
Stegodon includes a real-time notifications system accessible via the TUI (press Ctrl+N). Notifications are generated for the following events:
- Like - When another user (local or remote) likes your post
- Follow - When another user (local or remote) follows you
- Mention - When you are mentioned in a post (
@usernameor@username@domain) - Reply - When another user replies to your post
- Notifications appear in real-time with a badge count in the header (e.g.,
🦣 username [3]) - Badge updates every 30 seconds even when not viewing the notifications screen
- Press
nto view notifications,Enterto acknowledge and delete individual notifications - Press
ato delete all notifications at once - Notifications use an inbox-zero pattern (deleted on acknowledgment, not marked as read)
- All incoming Follow requests are auto-accepted
- Remote actors are cached for 24 hours
- Delivery queue uses exponential backoff (10 seconds to 24 hours)
- Create activities accepted from: followed accounts, relay subscriptions, or replies to local posts
- Paused relays: content is logged but not stored
- Rate limiting: 5 requests/second for ActivityPub endpoints
- Maximum activity body size: 1MB
- Direct messages
- Media attachments
- ActivityPub C2S (Client-to-Server)
- Object integrity proofs (FEP-8b32)
- Account migrations