Vibefed kb-lemmy

install
source · Clone the upstream repo
git clone https://github.com/reiver/vibefed
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/reiver/vibefed "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/kb-lemmy" ~/.claude/skills/reiver-vibefed-kb-lemmy && rm -rf "$T"
manifest: skills/kb-lemmy/SKILL.md
source content

Lemmy — Complete Reference

Overview

Lemmy is a self-hosted, federated social link aggregation and discussion forum — the Fediverse equivalent of Reddit. Created by Dessalines in February 2019, with Nutomic as co-creator and primary federation implementer. Built in Rust (Actix-web, Diesel ORM, PostgreSQL) with a TypeScript/Inferno.js frontend. Licensed AGPL-3.0.

Lemmy federates via ActivityPub. Its fundamental design choice is representing communities as Group actors that automatically relay all content via

Announce
activities, ensuring cross-instance consistency. It is the largest platform in the "Threadiverse" — the threaded discussion subset of the Fediverse.


1. Technology Stack

ComponentTechnology
Backend languageRust
Web frameworkActix-web (actor-model based)
ORMDiesel (type-safe)
DatabasePostgreSQL (R2D2 connection pooling)
Frontend languageTypeScript + CSS
Frontend frameworkInferno.js (React-compatible)
API clientlemmy-js-client
Image servicepictrs
DeploymentDocker, Ansible, ARM64/RPi supported
LicenseAGPL-3.0
Federation libraryactivitypub-federation-rust (standalone reusable crate)

2. ActivityPub Object Type Mapping

Lemmy ConceptActivityPub TypeNotes
Community
Group
Automated relay actor; Announces all content to followers
User
Person
Creates content, moderates, sends PMs
Instance
Application
Instance-level actor at root path
Post
Page
Mandatory title (
name
), optional URL and body
Comment
Note
Tree structure via
inReplyTo
Private Message
ChatMessage
Direct user-to-user, no threading

Why Page for Posts?

Lemmy posts have a mandatory title (

name
), distinguishing them from
Note
(typically untitled) and
Article
(long-form). The
Page
type aligns with the concept of a web page with a URL, title, and optional body.


3. Communities as Group Actors

This is the fundamental architectural decision. Communities are

Group
actors with their own inboxes. Every post, comment, vote, and moderation action is received by the community and then Announced (wrapped and forwarded) to all followers across all instances.

Community Object

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://join-lemmy.org/context.json"
  ],
  "id": "https://enterprise.lemmy.ml/c/main",
  "type": "Group",
  "preferredUsername": "main",
  "name": "The Main Community",
  "summary": "<p>Welcome to the main community!</p>",
  "inbox": "https://enterprise.lemmy.ml/c/main/inbox",
  "outbox": "https://enterprise.lemmy.ml/c/main/outbox",
  "followers": "https://enterprise.lemmy.ml/c/main/followers",
  "featured": "https://enterprise.lemmy.ml/c/main/featured",
  "attributedTo": ["https://enterprise.lemmy.ml/u/picard"],
  "publicKey": {
    "id": "https://enterprise.lemmy.ml/c/main#main-key",
    "owner": "https://enterprise.lemmy.ml/c/main",
    "publicKeyPem": "..."
  }
}

Key Fields

FieldDescription
preferredUsername
Machine-readable community name
name
Human-readable display name
summary
Description / rules (HTML)
icon
/
image
Avatar / banner
outbox
Limited to 20 latest posts
followers
Count only (no individual references — privacy)
attributedTo
Creators and moderators
featured
Pinned posts collection
postingRestrictedToMods
Whether only mods can post

The Announce Relay Pattern

User on Instance A              Community on Instance B         Instance C subscriber
       |                               |                              |
       |--- Create{Page} -----------> |                              |
       |                               |--- Announce{Create{Page}} ->|
       |                               |                              |

All content activities (Create, Update, Delete, Like, Dislike, Remove, Lock) flow through the community Group actor, which wraps each in an

Announce
and broadcasts to all followers. This is how cross-instance consistency is maintained.


4. Post (Page) Object

{
  "type": "Page",
  "id": "https://enterprise.lemmy.ml/post/123",
  "attributedTo": "https://enterprise.lemmy.ml/u/riker",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public",
    "https://ds9.lemmy.ml/c/main"
  ],
  "audience": "https://ds9.lemmy.ml/c/main",
  "name": "An interesting link",
  "content": "<p>Check this out!</p>",
  "source": {
    "content": "Check this out!",
    "mediaType": "text/markdown"
  },
  "attachment": [],
  "image": {},
  "commentsEnabled": true,
  "sensitive": false,
  "stickied": false,
  "published": "2024-01-15T12:00:00.000Z"
}
FieldDescription
name
Title (mandatory — distinguishes Post from Comment)
content
Body text (HTML-rendered)
source
Original markdown with
mediaType: "text/markdown"
audience
Target community (for routing)
attachment
Links/images array
image
Thumbnail
commentsEnabled
Post lock status (custom extension)
sensitive
NSFW flag
stickied
Pinned status (custom extension)
language
Language metadata (
identifier
+
name
)

5. Comment (Note) Object

{
  "type": "Note",
  "id": "https://enterprise.lemmy.ml/comment/95",
  "attributedTo": "https://enterprise.lemmy.ml/u/picard",
  "to": "https://enterprise.lemmy.ml/c/main",
  "content": "I agree with this take.",
  "source": {
    "content": "I agree with this take.",
    "mediaType": "text/markdown"
  },
  "inReplyTo": [
    "https://enterprise.lemmy.ml/post/38",
    "https://voyager.lemmy.ml/comment/73"
  ],
  "tag": [
    {
      "type": "Mention",
      "href": "https://voyager.lemmy.ml/u/janeway",
      "name": "@janeway@voyager.lemmy.ml"
    }
  ],
  "distinguished": false,
  "published": "2024-01-15T13:00:00.000Z"
}
FieldDescription
inReplyTo
Parent post and/or parent comment (builds tree)
tag
Mention
objects for user references
distinguished
Mod-highlighted comment (custom extension)

6. Voting — Like and Dislike

Lemmy uses both

Like
(upvote) and
Dislike
(downvote) as first-class ActivityPub activities. This is unique among major Fediverse platforms — most only support
Like
.

Upvote

{
  "type": "Like",
  "actor": "https://enterprise.lemmy.ml/u/picard",
  "object": "https://enterprise.lemmy.ml/post/123",
  "audience": "https://ds9.lemmy.ml/c/main"
}

Downvote

{
  "type": "Dislike",
  "actor": "https://enterprise.lemmy.ml/u/worf",
  "object": "https://enterprise.lemmy.ml/post/123",
  "audience": "https://ds9.lemmy.ml/c/main"
}

Undo Vote

{
  "type": "Undo",
  "actor": "https://enterprise.lemmy.ml/u/picard",
  "object": {
    "type": "Like",
    "actor": "https://enterprise.lemmy.ml/u/picard",
    "object": "https://enterprise.lemmy.ml/post/123"
  }
}

All votes include

audience
for community routing and are wrapped in
Announce
by the community actor.

Privacy note: Every instance that subscribes to the community receives all vote activities — instance admins can see who voted on what.

Ranking Algorithms

AlgorithmDescription
Active (default)Score + latest comment time with decay
HotScore + post publication time with decay
ScaledHot with boost for less active communities
New / OldChronological
Most CommentsComment count
New CommentsForum-style bump on new reply
Top (Day/Week/Month/Year/All)Score within time window

Score = upvotes minus downvotes.


7. Full Activity Reference

User → Community

ActivityPurpose
Follow
Subscribe to community
Undo{Follow}
Unsubscribe
Create{Page}
New post
Create{Note}
New comment
Update{Page}
Edit post
Update{Note}
Edit comment
Like
Upvote
Dislike
Downvote
Undo{Like}
/
Undo{Dislike}
Remove vote
Delete
Delete own content
Undo{Delete}
Restore deleted content
Flag
Report content (with
summary
reason)

Community → Followers

ActivityPurpose
Accept{Follow}
Automatic response to Follow
Announce{*}
Rebroadcast any received activity to all followers

Moderation

ActivityPurpose
Remove
Remove content (with
summary
reason)
Block
Ban user (with
target
scope, optional
removeData
,
expires
,
summary
)
Lock
Prevent new comments on post
Add
to
/moderators
Add moderator
Remove
from
/moderators
Remove moderator
Add
to
/featured
Pin post
Remove
from
/featured
Unpin post

User → User

ActivityPurpose
Create{ChatMessage}
Send private message
Update{ChatMessage}
Edit private message
Delete{ChatMessage}
Delete private message

Instance-Level

  • Instance actor (type
    Application
    ) at root path
  • Admins can remove any content instance-wide
  • Delete
    on user actor with
    removeData: true
    for account deletion

All activities are signed with RSA keys (key ID:

{actor-url}#main-key
).


8. JSON-LD Context and Custom Extensions

Required Context

[
  "https://join-lemmy.org/context.json",
  "https://www.w3.org/ns/activitystreams"
]

Namespace Prefixes

{
  "lemmy": "https://join-lemmy.org/ns#",
  "litepub": "http://litepub.social/ns#",
  "pt": "https://joinpeertube.org/ns#",
  "sc": "http://schema.org/"
}

Custom Properties

PropertyNamespaceUsed onDescription
stickied
lemmyPagePinned post
distinguished
lemmyNoteMod-highlighted comment
commentsEnabled
lemmyPagePost lock status
postingRestrictedToMods
lemmyGroupRestricted posting
moderators
lemmyGroupModerator collection
language
lemmyPage, NoteLanguage metadata
sensitive
asPageNSFW flag
matrixUserId
lemmyPersonMatrix chat ID

Important: Lemmy parses ActivityPub objects as plain JSON, not as JSON-LD. The

@context
is included for other software's benefit but Lemmy does not perform JSON-LD expansion or compaction.


9. Federation Modes and Fetching

Federation Modes

ModeDescription
AllowlistOnly connect to specified instances
BlocklistBlock specific instances, open to all others
Open (default)Connect to any instance

Cascading Fetch Behavior

  • Community fetch: Also fetches most recent posts (not comments/votes)
  • Post fetch: Also fetches community and author
  • Comment fetch: Also fetches all parent comments, the post, authors, and the community

This ensures referential integrity across the federated network.


10. REST API

AspectDetails
Versionv3 (
/api/v3/...
)
AuthJWT (cookies or
Authorization
header since 0.19.0)
Image servicepictrs — upload, resize, format conversion
FeedsRSS/Atom at
/feeds/
paths
Rate limitingIP-based (Docker: requires
X-Forwarded-For
header)
Client librarylemmy-js-client (official TypeScript)
OpenAPI specUnofficial:
mv-gh.github.io/lemmy_openapi_spec/

11. Interoperability Issues

name vs preferredUsername (Historical)

Lemmy initially reversed these:

name
for usernames,
preferredUsername
for display names. This is the opposite of the ActivityPub spec and Mastodon. Nutomic acknowledged it as "completely counterintuitive."

JSON-LD Context Errors

Lemmy's

@context
had incorrect declarations:

  • "stickied": "as:stickied"
    — falsely implied
    stickied
    is in the ActivityStreams namespace
  • "pt"
    prefix expanded to Lemmy's domain instead of PeerTube's

Nutomic admitted: "the truth is that I don't really understand how [@context] works."

Mastodon Reply Propagation

Replies from Mastodon can fail to reach all Lemmy instances because Mastodon doesn't include the community inbox in its recipient lists. The community Group actor must be in the recipient list to Announce the reply.

Mastodon Vote Federation

Mastodon's

Like
targets personal inboxes, not shared inboxes. Lemmy processes the vote locally but does not Announce it, causing vote count inconsistencies across instances.

Strict Parsing

Lemmy is "really inflexible when it comes to incoming activities." Arrays vs single values, or object IDs vs full inlined objects, can cause parsing errors. The Lemmy protocol is described as "a strict subset of the ActivityPub Protocol."


12. The Threadiverse Ecosystem

"Threadiverse" refers to Reddit-style threaded discussion platforms in the Fediverse. All federate with each other via ActivityPub.

PlatformLanguageTerminologyNotes
LemmyRustCommunitiesLargest, most mature
MbinPHP (fork of Kbin)MagazinesAlso supports microblogs (Mastodon-style)
PieFedPythonTopicsRapid development, approaching feature-parity
SublinksJavaDrop-in Lemmy replacement (alpha)

Users on any Threadiverse platform can see and interact with content from any other, including subscribing to Lemmy communities from Mbin or PieFed.


13. Known Quirks for Implementers

  1. Posts use

    Page
    , not
    Note
    — if your server sends
    Note
    objects to a Lemmy community, they will be treated as comments, not posts. Posts require
    Page
    type with a
    name
    (title).

  2. Community must be in recipients — activities targeting a Lemmy community must include the community in

    to
    or
    cc
    . Sending only to the post author's inbox will not distribute the activity.

  3. audience
    field — Lemmy uses the
    audience
    property to route activities to the correct community. Include it for reliable delivery.

  4. Dislike
    is real — unlike most Fediverse platforms, Lemmy uses
    Dislike
    as a distinct activity type for downvotes, not
    Undo{Like}
    .

  5. source
    with markdown — Lemmy preserves original markdown in the
    source
    field with
    mediaType: "text/markdown"
    . The
    content
    field contains the HTML-rendered version.

  6. Outbox is limited — community outbox only contains the 20 most recent posts. Comments and votes are not included.

  7. Followers collection is opaque — returns only a total count, not individual follower references (for privacy).

  8. No JSON-LD processing — Lemmy parses JSON directly. Do not rely on JSON-LD compaction/expansion when interoperating with Lemmy.

  9. ChatMessage
    for PMs — Lemmy uses the non-standard
    ChatMessage
    type for private messages rather than
    Note
    with direct addressing.