PieFed — Complete Reference
Overview
PieFed is a free, open-source, federated link aggregation and discussion
platform — a Python-based alternative to Reddit and Lemmy in the
Fediverse "Threadiverse." Created by Rimu Atkinson (Christchurch, New
Zealand) with the first code published July 28, 2023 and the flagship
instance (piefed.social) launched January 4, 2024. Licensed AGPL-3.0.
PieFed federates via ActivityPub using the same Group/Page/Note model as
Lemmy, making it fully interoperable with Lemmy, Mbin, and the wider
Fediverse. Its distinguishing features are: cross-post deduplication
with merged comments, federated Feeds (multi-community collections
via a custom Feed actor type), private/anonymous voting via proxy
user profiles, trust & safety as a first-class design concern
(reputation tracking, 3,000+ pre-blocked disinformation domains, AI
content filtering), and a deliberately simple Python/Flask codebase
designed for contributor accessibility.
The name "PieFed" is a portmanteau of "Python" and "Federation." The
repository is named "pyfedi" and hosted on Codeberg (not GitHub). As of
early 2026: 75+ instances, ~2,000 MAU, 82,571 lines of code, 62
contributors. "Very High Activity" on Open Hub.
1. Technology Stack
| Component |
Technology |
| Backend language |
Python (3.9+, ~70% of codebase) |
| Web framework |
Flask |
| Frontend |
htmx + vanilla JavaScript + Bootstrap CSS |
| Template engine |
Jinja2 |
| Database |
PostgreSQL 17 |
| ORM |
SQLAlchemy (Flask-SQLAlchemy) |
| Migrations |
Alembic (flask db upgrade) |
| Task queue |
Celery with Redis broker |
| Cache |
Redis 6.2 (optional) |
| Application server |
Gunicorn |
| Real-time notifications |
FastAPI + Uvicorn (separate service) |
| Linting |
Ruff |
| i18n |
Babel |
| Deployment |
Docker (5-service compose), bare metal, YunoHost |
| License |
AGPL-3.0 |
Design philosophy: "Clean, simple code" with "no fancy design patterns
or algorithms." Only requires Python + PostgreSQL; Redis is optional.
Dramatically lighter resource usage than Lemmy — one user reported
server load of ~1 vs Lemmy's ~12 on identical hardware.
2. ActivityPub Object Type Mapping
| PieFed Concept |
ActivityPub Type |
Notes |
| Community |
Group |
Relay actor; Announces content to followers |
| User |
Person |
Creates content, moderates |
| Bot |
Service |
Bot accounts |
| Feed |
Feed |
PieFed extension (FEP-1d80); federated multi-community collection |
| Post |
Page |
Primary post type, mandatory title (name) |
| Article |
Article |
Long-form content |
| Link post |
Link |
URL submissions |
| Comment |
Note |
Tree structure via inReplyTo |
| Poll |
Question |
oneOf/anyOf choices, up to 15 options |
| Event |
Event |
startTime, endTime, timezone, participantCount |
| Video |
Video |
PeerTube video embeds |
| Direct message |
ChatMessage |
Private user-to-user |
3. Communities as Group Actors
Communities are Group actors with their own inboxes, following the
same Announce relay pattern as Lemmy — all content flows through the
community actor and is wrapped in Announce for distribution to
subscribers across instances.
Community-Specific Attributes
| Attribute |
Description |
sensitive |
NSFW flag |
nsfl |
Not-safe-for-life flag (separate from NSFW) |
genAI |
AI-generated content flag |
postingRestrictedToMods |
Only moderators can post |
newModsWanted |
Community is seeking moderators |
privateMods |
Moderator list is hidden |
defaultPostType |
Default content type for new posts |
questionAnswer |
StackOverflow-style Q&A mode enabled |
moderators |
OrderedCollection of moderators |
featured |
Pinned posts collection |
tagsForPosts |
Available flair/tag options (Lemmy-compatible) |
Moderator Attribution
PieFed accepts both attributedTo (Lemmy/Mbin style) and
moderators (Kbin style) for moderator lists, improving cross-platform
compatibility.
Community Types
- Federated (default): Full ActivityPub federation
- Local-only: Visible only on the home instance, no federation
- Private (v1.6+): Invitation-only, no federation, posts visible
only to members
4. Voting — Like, Dislike, and Private Votes
PieFed uses Like (upvote) and Dislike (downvote) activities, same
as Lemmy. However, PieFed adds a private/anonymous voting system
that is unique in the Threadiverse.
Private Voting Mechanism
Users have two profiles: a main profile (for posting) and an
anonymous proxy profile (no name, avatar, or bio) used exclusively
for voting. When "Vote privately" is enabled:
- Votes sent to Lemmy/Mbin instances use the anonymous proxy profile
- New accounts have private voting enabled by default
- Votes can also be fully local (not federated at all)
Community-Level Vote Controls
- Moderators can restrict downvoting to subscribed members only
- Downvoting can be restricted to "trusted" instances (a third tier
between full federation and defederation)
- Communities can disable downvotes entirely
- "Low quality" communities (e.g., memes) don't award karma for upvotes
Reputation Tracking
- "Attitude" metric: tracks ratio of downvotes to upvotes per user;
flags excessive downvoters
- Comments scoring -10 or below are auto-collapsed
- Users with negative karma get red warning icons next to names
(double red for severely negative)
- New accounts (first 7 days) display a special indicator
5. The Feed Actor (FEP-1d80)
PieFed introduces a custom Feed actor type — a federated equivalent
of Reddit's multi-reddits. This is defined in FEP-1d80.
A Feed is an ActivityPub actor of type Feed that aggregates multiple
communities (Group actors) into a single subscribable collection. Feeds
can include communities from any federated instance, PeerTube channels,
and Mastodon accounts.
- Feeds can be public (discoverable, subscribable) or private
- Feed actors are discoverable via WebFinger
- Users on remote PieFed instances can subscribe to a Feed like any
other actor
- Feeds are managed via
Add/Remove activities to add/remove
communities
This is a PieFed-specific extension — Lemmy and Mbin do not support
the Feed actor type, though the FEP is open for adoption.
6. Full Activity Reference
Incoming Activities
| Activity |
Purpose |
Follow |
Subscribe to community/feed |
Accept / Reject |
Subscription response |
Create |
New post, comment, chat message, poll |
Update |
Edit post/comment, update community profile |
Delete |
Remove post, comment, PM, feed |
Like |
Upvote |
Dislike |
Downvote |
EmojiReact |
Custom emoji reaction (unicode or :name: format) |
PollVote |
Vote in a poll |
ChooseAnswer |
Mark comment as answer (Q&A mode) |
Add |
Add moderator, sticky post, add community to feed |
Remove |
Remove moderator, unsticky post, remove from feed |
Lock |
Lock post or comment (including children) |
Flag |
Report content |
Announce |
Boost/share (wraps other activities) |
Undo |
Reverse any previous activity |
Community → Followers
| Activity |
Purpose |
Accept{Follow} |
Automatic response to Follow |
Announce{*} |
Rebroadcast received activities to all followers |
Community outboxes serve Announce(Create(Page)) activities even for
non-local posts, functioning as content relays.
7. JSON-LD Context and Extensions
Context
[
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1"
]
Lemmy-Compatible Extensions
| Property |
Used on |
Description |
tagsForPosts |
Group |
Available flair/tag options (Lemmy CommunityTag) |
postingRestrictedToMods |
Group |
Restricted posting |
language |
Page, Note |
Language metadata (identifier + name) |
PieFed-Specific Extensions
| Property |
Used on |
Description |
genAI |
Group, Page |
AI-generated content flag |
nsfl |
Group, Page |
Not-safe-for-life flag |
flair |
Note |
User flair (custom extension on comments) |
postingWarning |
Group |
Contextual warning above comment form |
interactionPolicy |
Page |
Interaction restrictions |
newModsWanted |
Group |
Community seeking moderators |
questionAnswer |
Group |
Q&A mode enabled |
8. Federation Architecture
Activity Processing Flow
- Parse JSON request body
- Check federation pause status (normal / overload / permanently closed)
- Extract actor and validate HTTP signature
- Deduplicate via Redis (activity IDs stored with 90-second TTL)
- Route to handler based on activity type
- Process asynchronously via Celery task
HTTP Signatures
| Aspect |
Detail |
| Algorithm |
RSA-SHA256 (also accepts hs2019) |
| Key size |
2048-bit RSA |
| Signed headers |
(request-target), Host, Date, Digest, Content-Type, Accept |
| Date tolerance |
3,600 seconds (1 hour) |
| Fallback |
LD signatures via URDNA2015 normalization |
| Key cache |
Up to 1,000 entries |
Reliability
- Failed deliveries enter a retry queue with retries over several days
- Batched federation between PieFed instances reduces load
- Redis-based locking minimizes database deadlocks
- Federation can be paused during overload conditions
Key Endpoints
| Path |
Purpose |
/.well-known/webfinger |
User, community, and feed discovery |
/.well-known/nodeinfo |
NodeInfo schema links |
/nodeinfo/2.0, /nodeinfo/2.1 |
Server stats and protocol info |
/u/<actor> |
User actor (content-negotiated JSON/HTML) |
/c/<actor> |
Community actor |
/inbox |
Shared inbox |
/site_inbox |
Site-level inbox |
/api/v1/instance |
Mastodon-compatible instance info |
9. REST API
PieFed's API is intentionally "95% the same as the Lemmy API" to
enable reuse of Lemmy's mobile app ecosystem.
| Aspect |
Detail |
| Base path |
/api/alpha/ |
| Documentation |
Swagger at /api/alpha/swagger |
| Total endpoints |
100+ |
| Rate limiting |
Applied to creation endpoints |
Compatible Mobile Apps
Voyager, Interstellar (Android/iOS/Linux/Windows), Blorp (iOS),
Summit, with Boost and Photon in development.
Endpoint Categories
- Site (5): instance info, configuration
- Communities (17): CRUD, flair, bans, moderation
- Feeds (3): create, edit, list
- Posts (18): CRUD, polls, flair, voting
- Comments (13): CRUD, answer marking
- Private messages (8): send, read, delete
- Users (20): profiles, notifications, flair, bans
- Search (4): content discovery
- Images (4): upload, manage
- Admin (2): site management
Notable Unique Endpoints (beyond Lemmy)
/post/poll_vote — poll voting
/comment/mark_as_answer — Q&A answer selection
/feed/* — Feed (multi-reddit) management
/community/flair/* — flair management
/user/set_flair — user flair
10. Moderation and Trust & Safety
PieFed was designed with safety as a first-class concern, drawing
inspiration from the Mastodon Covenant and "nudge theory."
Reputation System
- Karma tracking with sortable low-karma account lists
- "Attitude" metric: percentage of downvotes vs upvotes per user
- Visual indicators: red icons for negative karma, double-red for
severe, special icon for accounts < 7 days old
- Auto-collapse for comments at -10 or below
Content Filtering
- 3,000+ pre-loaded domain blocklist (disinformation, conspiracy,
fake news sites)
- 4chan screenshot detection via image recognition (auto-reported)
- AI content labeling: posts/communities tagged as AI-generated;
users can hide all AI content like NSFW
- NSFW and NSFL as separate flags
- Keyword filtering: user-configurable
- Bot content filter: single checkbox
Admin Tools
- Ban / Ban + Purge on user profiles
- IP-based ban evasion detection
- Username keyword filtering (blocks e.g. "1488")
- Web of trust: follow another instance's blocklist automatically
- Registration approval queue
- "Authoritarian Inoculation" feature with default blocks on known
extremist instances
Community-Level Moderation
- Per-community downvote policies
- Comment and post locking
- Post approval workflow (optional pre-publication review)
- Contextual warnings above comment forms
- Searchable moderation log
- Federated community bans
newModsWanted flag for moderator recruitment
11. Content Types
| Type |
Details |
| Link posts |
URL submissions |
| Text posts |
Markdown body |
| Image posts |
With alt text; width control via  |
| Video posts |
Direct upload (v1.5+, admin-configurable) |
| Polls |
Question with oneOf/anyOf, up to 15 options, Mastodon-compatible |
| Events |
Time, timezone, location, participant count |
| PeerTube videos |
Embedded player, auto-import from channels |
| Cross-posts |
Deduplicated with consolidated comment views |
| Scheduled posts |
With timezone support |
| Wiki pages |
Per-community editable wikis |
| Emoji reactions |
Unicode and custom (:piefed:), federated as Likes for Lemmy compat |
| Quote posts |
v1.6+, Mastodon quote-boost interop |
| StackOverflow Q&A |
Comments markable as answers via ChooseAnswer |
| Spoilers |
Flair-based with image blurring + inline spoiler text |
12. Interoperability
Lemmy
- Fully compatible: Group communities, Page posts, Note comments,
Like/Dislike votes, Announce relay
- API is 95% Lemmy-compatible (mobile apps work)
- Shared extensions:
tagsForPosts, CommunityTag
- Limitation: polls and events cannot be posted TO Lemmy communities
(prevented in PieFed's code to avoid errors)
- Community outboxes follow Lemmy's
Announce(Create(Page)) pattern
Mastodon
- Users follow PieFed communities by mentioning them
- First paragraph becomes post title; rest becomes body
- Works: hashtags, images, alt text, videos, NSFW, polls, markdown,
mentions, comments, editing, likes, boosts
- Poll voting is bidirectional
- Quote-boost interop (v1.6+)
/api/v1/instance Mastodon-compatible endpoint
PeerTube
- Channels can be followed directly from PieFed
- Videos arrive with embedded player
- New channels auto-import 10 recent videos
- Posts restricted to channel owners
Mbin / Kbin
- Full community federation
- PieFed accepts Kbin's
moderators property alongside Lemmy's
attributedTo
Known Limitations
- "Discoverability between PieFed and other parts of the Fediverse is
limited"
- Markdown variants differ slightly from Lemmy's
- Remote Mastodon
Announce activities without full inlined objects
are logged but skipped
13. Installation and Deployment
Bare Metal
git clone https://codeberg.org/rimu/pyfedi.git
python -m venv venv && source venv/bin/activate
pip install wheel && pip install -r requirements.txt
cp env.sample .env # configure SECRET_KEY, DATABASE_URL, etc.
flask db upgrade && flask init-db
gunicorn -b 0.0.0.0:5000 pyfedi:app
Setup reported to take "within half an hour."
Docker (5 services)
| Service |
Purpose |
db |
PostgreSQL 17 |
redis |
Redis 6.2 |
celery |
Celery worker for async federation tasks |
app |
Flask/Gunicorn web app (port 8030) |
piefed_notifs |
FastAPI/Uvicorn real-time notifications (port 8040) |
Other Options
- YunoHost: available in app store (v1.4+)
- Managed hosting: fedihost.co (beta), Elest.io
- S3 storage: Cloudflare R2, Wasabi, Backblaze B2 for media and
post archival
Scaling (piefed.social reference: 8-core, 16GB, ~1000 MAU)
- PostgreSQL:
shared_buffers=6GB, effective_cache_size=9GB,
max_connections=300
- DB pool:
POOL_SIZE=30, MAX_OVERFLOW=70
- Nginx caching recommended (RAM-backed
/dev/shm/nginx)
- Post archival to S3 reduces database size over time
14. Codebase Structure
pyfedi/
├── app/
│ ├── activitypub/ # Federation (routes, signatures, util, actor)
│ ├── admin/ # Admin panel
│ ├── api/alpha/ # Lemmy-compatible REST API
│ ├── auth/ # Authentication
│ ├── chat/ # Real-time chat
│ ├── community/ # Community management
│ ├── feed/ # Feed (multi-reddit) management
│ ├── post/ # Post handling
│ ├── search/ # Search
│ ├── shared/tasks/ # Celery async tasks (adds, blocks, deletes,
│ │ # flags, follows, groups, likes, locks,
│ │ # notes, pages, removes, users, maintenance)
│ ├── plugins/ # Plugin system
│ ├── tag/ # Hashtag management
│ ├── models.py # All DB models (209KB single file)
│ ├── inoculation.py # Anti-propaganda feature
│ └── constants.py
├── migrations/ # Alembic migrations
├── tests/
├── docs/ # Developer docs, AP examples, ERD
├── compose.yaml # Docker Compose (5 services)
├── pyfedi.py # Entry point
├── FEDERATION.md # Federation documentation
└── CONTRIBUTING.md
Key namespaces: app.activitypub, app.api.alpha, app.community,
app.post, app.feed, app.shared.tasks
15. PieFed vs Lemmy — Key Differences for Implementers
| Aspect |
PieFed |
Lemmy |
| Language |
Python/Flask |
Rust/Actix-web |
| Resource usage |
~1 load avg |
~12 load avg (same hardware) |
Feed actor type |
Yes (FEP-1d80) |
No |
| Private voting |
Proxy user profiles |
All votes public/federated |
| Cross-post dedup |
Merged comment views |
Separate posts |
| AI content flag |
genAI property |
No |
| NSFL flag |
Separate from NSFW |
No (NSFW only) |
EmojiReact |
Yes (federated as Likes to Lemmy) |
No |
ChooseAnswer |
Yes (Q&A mode) |
No |
Event objects |
Yes |
No |
PollVote |
Yes (Mastodon-compatible) |
No native polls |
| Flair federation |
flair on Note + tagsForPosts |
tagsForPosts only |
| API path |
/api/alpha/ |
/api/v3/ |
| API compatibility |
95% Lemmy-compatible |
— |
| JSON-LD processing |
Plain JSON (no expansion) |
Plain JSON (no expansion) |
16. Common Implementation Mistakes
Assuming PieFed is a Lemmy fork: PieFed is a completely separate
Python codebase, not a Rust fork — protocol-compatible but
architecturally different
Not handling the Feed actor type: PieFed federates Feed
actors via WebFinger; other software should treat unknown actor types
gracefully rather than erroring
Expecting public votes: PieFed defaults to private voting — vote
activities may come from anonymous proxy profiles or not at all.
Do not assume vote counts match federated Like/Dislike activities
Ignoring genAI and nsfl properties: PieFed adds these to
Group and Page objects — unknown properties should be ignored, not
cause parsing errors
Sending polls/events to PieFed communities hosted on Lemmy:
PieFed prevents posting polls and events to remote Lemmy communities
because Lemmy doesn't support them — but if you federate these object
types to PieFed-hosted communities, they will work
Not handling EmojiReact: PieFed sends EmojiReact activities
for emoji reactions — these federate as Like activities to Lemmy
for compatibility, but other implementations may receive the raw
EmojiReact type
Assuming all communities federate: PieFed supports local-only
and private communities that are invisible to federation
Not supporting ChooseAnswer: In Q&A mode communities, PieFed
sends ChooseAnswer activities to mark accepted answers — unknown
activity types should be ignored gracefully
1---2name: kb-piefed3description: Background knowledge about PieFed, the federated link aggregation and discussion platform (Python-based Reddit/Lemmy alternative in the Threadiverse). Covers PieFed's tech stack (Python/Flask, PostgreSQL, Celery/Redis, htmx, Jinja2, AGPL-3.0), the Lemmy-compatible ActivityPub implementation (Community as Group, Post as Page, Comment as Note, Like/Dislike voting, Announce relay pattern, ChatMessage for DMs), the unique Feed actor type (FEP-1d80 for federated multi- community collections), private/anonymous voting via proxy user profiles, additional activity types (EmojiReact, PollVote, ChooseAnswer for Q&A mode, Event objects with startTime/endTime), the 95%-Lemmy-compatible REST API (/api/alpha/ with Swagger docs, enabling Voyager/Interstellar/Blorp/Summit mobile apps), custom JSON-LD extensions (genAI, nsfl, flair, postingWarning, interactionPolicy, lemmy:tagsForPosts compatibility), the federation architecture (Celery async processing, Redis dedup with 90s TTL, RSA-SHA256 HTTP signatures, LD signature fallb4---5
6# PieFed — Complete Reference
7
8## Overview
9
10PieFed is a free, open-source, federated link aggregation and discussion
11platform — a Python-based alternative to Reddit and Lemmy in the
12Fediverse "Threadiverse." Created by Rimu Atkinson (Christchurch, New
13Zealand) with the first code published July 28, 2023 and the flagship
14instance (piefed.social) launched January 4, 2024. Licensed AGPL-3.0.
15
16PieFed federates via ActivityPub using the same Group/Page/Note model as
17Lemmy, making it fully interoperable with Lemmy, Mbin, and the wider
18Fediverse. Its distinguishing features are: **cross-post deduplication**
19with merged comments, **federated Feeds** (multi-community collections
20via a custom `Feed` actor type), **private/anonymous voting** via proxy
21user profiles, **trust & safety as a first-class design concern**
22(reputation tracking, 3,000+ pre-blocked disinformation domains, AI
23content filtering), and a **deliberately simple Python/Flask codebase**
24designed for contributor accessibility.
25
26The name "PieFed" is a portmanteau of "Python" and "Federation." The
27repository is named "pyfedi" and hosted on Codeberg (not GitHub). As of
28early 2026: 75+ instances, ~2,000 MAU, 82,571 lines of code, 62
29contributors. "Very High Activity" on Open Hub.
30
31---
32
33## 1. Technology Stack
34
35| Component | Technology |
36|-----------|-----------|
37| Backend language | Python (3.9+, ~70% of codebase) |
38| Web framework | Flask |
39| Frontend | htmx + vanilla JavaScript + Bootstrap CSS |
40| Template engine | Jinja2 |
41| Database | PostgreSQL 17 |
42| ORM | SQLAlchemy (Flask-SQLAlchemy) |
43| Migrations | Alembic (`flask db upgrade`) |
44| Task queue | Celery with Redis broker |
45| Cache | Redis 6.2 (optional) |
46| Application server | Gunicorn |
47| Real-time notifications | FastAPI + Uvicorn (separate service) |
48| Linting | Ruff |
49| i18n | Babel |
50| Deployment | Docker (5-service compose), bare metal, YunoHost |
51| License | AGPL-3.0 |
52
53Design philosophy: "Clean, simple code" with "no fancy design patterns
54or algorithms." Only requires Python + PostgreSQL; Redis is optional.
55Dramatically lighter resource usage than Lemmy — one user reported
56server load of ~1 vs Lemmy's ~12 on identical hardware.
57
58---
59
60## 2. ActivityPub Object Type Mapping
61
62| PieFed Concept | ActivityPub Type | Notes |
63|----------------|------------------|-------|
64| Community | `Group` | Relay actor; Announces content to followers |
65| User | `Person` | Creates content, moderates |
66| Bot | `Service` | Bot accounts |
67| Feed | `Feed` | PieFed extension (FEP-1d80); federated multi-community collection |
68| Post | `Page` | Primary post type, mandatory title (`name`) |
69| Article | `Article` | Long-form content |
70| Link post | `Link` | URL submissions |
71| Comment | `Note` | Tree structure via `inReplyTo` |
72| Poll | `Question` | `oneOf`/`anyOf` choices, up to 15 options |
73| Event | `Event` | `startTime`, `endTime`, `timezone`, `participantCount` |
74| Video | `Video` | PeerTube video embeds |
75| Direct message | `ChatMessage` | Private user-to-user |
76
77---
78
79## 3. Communities as Group Actors
80
81Communities are `Group` actors with their own inboxes, following the
82same Announce relay pattern as Lemmy — all content flows through the
83community actor and is wrapped in `Announce` for distribution to
84subscribers across instances.
85
86### Community-Specific Attributes
87
88| Attribute | Description |
89|-----------|-------------|
90| `sensitive` | NSFW flag |
91| `nsfl` | Not-safe-for-life flag (separate from NSFW) |
92| `genAI` | AI-generated content flag |
93| `postingRestrictedToMods` | Only moderators can post |
94| `newModsWanted` | Community is seeking moderators |
95| `privateMods` | Moderator list is hidden |
96| `defaultPostType` | Default content type for new posts |
97| `questionAnswer` | StackOverflow-style Q&A mode enabled |
98| `moderators` | OrderedCollection of moderators |
99| `featured` | Pinned posts collection |
100| `tagsForPosts` | Available flair/tag options (Lemmy-compatible) |
101
102### Moderator Attribution
103
104PieFed accepts **both** `attributedTo` (Lemmy/Mbin style) and
105`moderators` (Kbin style) for moderator lists, improving cross-platform
106compatibility.
107
108### Community Types
109
110- **Federated** (default): Full ActivityPub federation
111- **Local-only**: Visible only on the home instance, no federation
112- **Private** (v1.6+): Invitation-only, no federation, posts visible
113 only to members
114
115---
116
117## 4. Voting — Like, Dislike, and Private Votes
118
119PieFed uses `Like` (upvote) and `Dislike` (downvote) activities, same
120as Lemmy. However, PieFed adds a **private/anonymous voting** system
121that is unique in the Threadiverse.
122
123### Private Voting Mechanism
124
125Users have **two profiles**: a main profile (for posting) and an
126**anonymous proxy profile** (no name, avatar, or bio) used exclusively
127for voting. When "Vote privately" is enabled:
128
129- Votes sent to Lemmy/Mbin instances use the anonymous proxy profile
130- New accounts have private voting **enabled by default**
131- Votes can also be fully local (not federated at all)
132
133### Community-Level Vote Controls
134
135- Moderators can **restrict downvoting** to subscribed members only
136- Downvoting can be restricted to "trusted" instances (a third tier
137 between full federation and defederation)
138- Communities can **disable downvotes entirely**
139- "Low quality" communities (e.g., memes) don't award karma for upvotes
140
141### Reputation Tracking
142
143- **"Attitude" metric**: tracks ratio of downvotes to upvotes per user;
144 flags excessive downvoters
145- Comments scoring **-10 or below** are auto-collapsed
146- Users with negative karma get **red warning icons** next to names
147 (double red for severely negative)
148- New accounts (first 7 days) display a special indicator
149
150---
151
152## 5. The Feed Actor (FEP-1d80)
153
154PieFed introduces a custom `Feed` actor type — a federated equivalent
155of Reddit's multi-reddits. This is defined in **FEP-1d80**.
156
157A Feed is an ActivityPub actor of type `Feed` that aggregates multiple
158communities (Group actors) into a single subscribable collection. Feeds
159can include communities from any federated instance, PeerTube channels,
160and Mastodon accounts.
161
162- Feeds can be **public** (discoverable, subscribable) or **private**
163- Feed actors are discoverable via WebFinger
164- Users on remote PieFed instances can subscribe to a Feed like any
165 other actor
166- Feeds are managed via `Add`/`Remove` activities to add/remove
167 communities
168
169This is a PieFed-specific extension — Lemmy and Mbin do not support
170the `Feed` actor type, though the FEP is open for adoption.
171
172---
173
174## 6. Full Activity Reference
175
176### Incoming Activities
177
178| Activity | Purpose |
179|----------|---------|
180| `Follow` | Subscribe to community/feed |
181| `Accept` / `Reject` | Subscription response |
182| `Create` | New post, comment, chat message, poll |
183| `Update` | Edit post/comment, update community profile |
184| `Delete` | Remove post, comment, PM, feed |
185| `Like` | Upvote |
186| `Dislike` | Downvote |
187| `EmojiReact` | Custom emoji reaction (unicode or `:name:` format) |
188| `PollVote` | Vote in a poll |
189| `ChooseAnswer` | Mark comment as answer (Q&A mode) |
190| `Add` | Add moderator, sticky post, add community to feed |
191| `Remove` | Remove moderator, unsticky post, remove from feed |
192| `Lock` | Lock post or comment (including children) |
193| `Flag` | Report content |
194| `Announce` | Boost/share (wraps other activities) |
195| `Undo` | Reverse any previous activity |
196
197### Community → Followers
198
199| Activity | Purpose |
200|----------|---------|
201| `Accept{Follow}` | Automatic response to Follow |
202| `Announce{*}` | Rebroadcast received activities to all followers |
203
204Community outboxes serve `Announce(Create(Page))` activities even for
205non-local posts, functioning as content relays.
206
207---
208
209## 7. JSON-LD Context and Extensions
210
211### Context
212
213```json
214[
215 "https://www.w3.org/ns/activitystreams",
216 "https://w3id.org/security/v1"
217]
218```
219
220### Lemmy-Compatible Extensions
221
222| Property | Used on | Description |
223|----------|---------|-------------|
224| `tagsForPosts` | Group | Available flair/tag options (Lemmy `CommunityTag`) |
225| `postingRestrictedToMods` | Group | Restricted posting |
226| `language` | Page, Note | Language metadata (`identifier` + `name`) |
227
228### PieFed-Specific Extensions
229
230| Property | Used on | Description |
231|----------|---------|-------------|
232| `genAI` | Group, Page | AI-generated content flag |
233| `nsfl` | Group, Page | Not-safe-for-life flag |
234| `flair` | Note | User flair (custom extension on comments) |
235| `postingWarning` | Group | Contextual warning above comment form |
236| `interactionPolicy` | Page | Interaction restrictions |
237| `newModsWanted` | Group | Community seeking moderators |
238| `questionAnswer` | Group | Q&A mode enabled |
239
240---
241
242## 8. Federation Architecture
243
244### Activity Processing Flow
245
2461. Parse JSON request body
2472. Check federation pause status (normal / overload / permanently closed)
2483. Extract actor and validate HTTP signature
2494. Deduplicate via Redis (activity IDs stored with 90-second TTL)
2505. Route to handler based on activity type
2516. Process asynchronously via Celery task
252
253### HTTP Signatures
254
255| Aspect | Detail |
256|--------|--------|
257| Algorithm | RSA-SHA256 (also accepts `hs2019`) |
258| Key size | 2048-bit RSA |
259| Signed headers | `(request-target)`, `Host`, `Date`, `Digest`, `Content-Type`, `Accept` |
260| Date tolerance | 3,600 seconds (1 hour) |
261| Fallback | LD signatures via URDNA2015 normalization |
262| Key cache | Up to 1,000 entries |
263
264### Reliability
265
266- Failed deliveries enter a retry queue with retries over several days
267- **Batched federation** between PieFed instances reduces load
268- Redis-based locking minimizes database deadlocks
269- Federation can be **paused** during overload conditions
270
271### Key Endpoints
272
273| Path | Purpose |
274|------|---------|
275| `/.well-known/webfinger` | User, community, and feed discovery |
276| `/.well-known/nodeinfo` | NodeInfo schema links |
277| `/nodeinfo/2.0`, `/nodeinfo/2.1` | Server stats and protocol info |
278| `/u/<actor>` | User actor (content-negotiated JSON/HTML) |
279| `/c/<actor>` | Community actor |
280| `/inbox` | Shared inbox |
281| `/site_inbox` | Site-level inbox |
282| `/api/v1/instance` | Mastodon-compatible instance info |
283
284---
285
286## 9. REST API
287
288PieFed's API is intentionally **"95% the same as the Lemmy API"** to
289enable reuse of Lemmy's mobile app ecosystem.
290
291| Aspect | Detail |
292|--------|--------|
293| Base path | `/api/alpha/` |
294| Documentation | Swagger at `/api/alpha/swagger` |
295| Total endpoints | 100+ |
296| Rate limiting | Applied to creation endpoints |
297
298### Compatible Mobile Apps
299
300Voyager, Interstellar (Android/iOS/Linux/Windows), Blorp (iOS),
301Summit, with Boost and Photon in development.
302
303### Endpoint Categories
304
305- **Site** (5): instance info, configuration
306- **Communities** (17): CRUD, flair, bans, moderation
307- **Feeds** (3): create, edit, list
308- **Posts** (18): CRUD, polls, flair, voting
309- **Comments** (13): CRUD, answer marking
310- **Private messages** (8): send, read, delete
311- **Users** (20): profiles, notifications, flair, bans
312- **Search** (4): content discovery
313- **Images** (4): upload, manage
314- **Admin** (2): site management
315
316### Notable Unique Endpoints (beyond Lemmy)
317
318- `/post/poll_vote` — poll voting
319- `/comment/mark_as_answer` — Q&A answer selection
320- `/feed/*` — Feed (multi-reddit) management
321- `/community/flair/*` — flair management
322- `/user/set_flair` — user flair
323
324---
325
326## 10. Moderation and Trust & Safety
327
328PieFed was designed with safety as a first-class concern, drawing
329inspiration from the Mastodon Covenant and "nudge theory."
330
331### Reputation System
332
333- **Karma tracking** with sortable low-karma account lists
334- **"Attitude" metric**: percentage of downvotes vs upvotes per user
335- **Visual indicators**: red icons for negative karma, double-red for
336 severe, special icon for accounts < 7 days old
337- **Auto-collapse** for comments at -10 or below
338
339### Content Filtering
340
341- **3,000+ pre-loaded domain blocklist** (disinformation, conspiracy,
342 fake news sites)
343- **4chan screenshot detection** via image recognition (auto-reported)
344- **AI content labeling**: posts/communities tagged as AI-generated;
345 users can hide all AI content like NSFW
346- **NSFW and NSFL as separate flags**
347- **Keyword filtering**: user-configurable
348- **Bot content filter**: single checkbox
349
350### Admin Tools
351
352- Ban / Ban + Purge on user profiles
353- IP-based ban evasion detection
354- Username keyword filtering (blocks e.g. "1488")
355- **Web of trust**: follow another instance's blocklist automatically
356- Registration approval queue
357- **"Authoritarian Inoculation"** feature with default blocks on known
358 extremist instances
359
360### Community-Level Moderation
361
362- Per-community downvote policies
363- Comment and post locking
364- Post approval workflow (optional pre-publication review)
365- Contextual warnings above comment forms
366- Searchable moderation log
367- Federated community bans
368- `newModsWanted` flag for moderator recruitment
369
370---
371
372## 11. Content Types
373
374| Type | Details |
375|------|---------|
376| Link posts | URL submissions |
377| Text posts | Markdown body |
378| Image posts | With alt text; width control via `` |
379| Video posts | Direct upload (v1.5+, admin-configurable) |
380| Polls | `Question` with `oneOf`/`anyOf`, up to 15 options, Mastodon-compatible |
381| Events | Time, timezone, location, participant count |
382| PeerTube videos | Embedded player, auto-import from channels |
383| Cross-posts | Deduplicated with consolidated comment views |
384| Scheduled posts | With timezone support |
385| Wiki pages | Per-community editable wikis |
386| Emoji reactions | Unicode and custom (`:piefed:`), federated as Likes for Lemmy compat |
387| Quote posts | v1.6+, Mastodon quote-boost interop |
388| StackOverflow Q&A | Comments markable as answers via `ChooseAnswer` |
389| Spoilers | Flair-based with image blurring + inline spoiler text |
390
391---
392
393## 12. Interoperability
394
395### Lemmy
396
397- Fully compatible: Group communities, Page posts, Note comments,
398 Like/Dislike votes, Announce relay
399- API is 95% Lemmy-compatible (mobile apps work)
400- Shared extensions: `tagsForPosts`, `CommunityTag`
401- **Limitation**: polls and events cannot be posted TO Lemmy communities
402 (prevented in PieFed's code to avoid errors)
403- Community outboxes follow Lemmy's `Announce(Create(Page))` pattern
404
405### Mastodon
406
407- Users follow PieFed communities by **mentioning** them
408- First paragraph becomes post title; rest becomes body
409- Works: hashtags, images, alt text, videos, NSFW, polls, markdown,
410 mentions, comments, editing, likes, boosts
411- Poll voting is **bidirectional**
412- Quote-boost interop (v1.6+)
413- `/api/v1/instance` Mastodon-compatible endpoint
414
415### PeerTube
416
417- Channels can be followed directly from PieFed
418- Videos arrive with embedded player
419- New channels auto-import 10 recent videos
420- Posts restricted to channel owners
421
422### Mbin / Kbin
423
424- Full community federation
425- PieFed accepts Kbin's `moderators` property alongside Lemmy's
426 `attributedTo`
427
428### Known Limitations
429
430- "Discoverability between PieFed and other parts of the Fediverse is
431 limited"
432- Markdown variants differ slightly from Lemmy's
433- Remote Mastodon `Announce` activities without full inlined objects
434 are logged but skipped
435
436---
437
438## 13. Installation and Deployment
439
440### Bare Metal
441
442```
443git clone https://codeberg.org/rimu/pyfedi.git
444python -m venv venv && source venv/bin/activate
445pip install wheel && pip install -r requirements.txt
446cp env.sample .env # configure SECRET_KEY, DATABASE_URL, etc.
447flask db upgrade && flask init-db
448gunicorn -b 0.0.0.0:5000 pyfedi:app
449```
450
451Setup reported to take "within half an hour."
452
453### Docker (5 services)
454
455| Service | Purpose |
456|---------|---------|
457| `db` | PostgreSQL 17 |
458| `redis` | Redis 6.2 |
459| `celery` | Celery worker for async federation tasks |
460| `app` | Flask/Gunicorn web app (port 8030) |
461| `piefed_notifs` | FastAPI/Uvicorn real-time notifications (port 8040) |
462
463### Other Options
464
465- **YunoHost**: available in app store (v1.4+)
466- **Managed hosting**: fedihost.co (beta), Elest.io
467- **S3 storage**: Cloudflare R2, Wasabi, Backblaze B2 for media and
468 post archival
469
470### Scaling (piefed.social reference: 8-core, 16GB, ~1000 MAU)
471
472- PostgreSQL: `shared_buffers=6GB`, `effective_cache_size=9GB`,
473 `max_connections=300`
474- DB pool: `POOL_SIZE=30`, `MAX_OVERFLOW=70`
475- Nginx caching recommended (RAM-backed `/dev/shm/nginx`)
476- Post archival to S3 reduces database size over time
477
478---
479
480## 14. Codebase Structure
481
482```
483pyfedi/
484├── app/
485│ ├── activitypub/ # Federation (routes, signatures, util, actor)
486│ ├── admin/ # Admin panel
487│ ├── api/alpha/ # Lemmy-compatible REST API
488│ ├── auth/ # Authentication
489│ ├── chat/ # Real-time chat
490│ ├── community/ # Community management
491│ ├── feed/ # Feed (multi-reddit) management
492│ ├── post/ # Post handling
493│ ├── search/ # Search
494│ ├── shared/tasks/ # Celery async tasks (adds, blocks, deletes,
495│ │ # flags, follows, groups, likes, locks,
496│ │ # notes, pages, removes, users, maintenance)
497│ ├── plugins/ # Plugin system
498│ ├── tag/ # Hashtag management
499│ ├── models.py # All DB models (209KB single file)
500│ ├── inoculation.py # Anti-propaganda feature
501│ └── constants.py
502├── migrations/ # Alembic migrations
503├── tests/
504├── docs/ # Developer docs, AP examples, ERD
505├── compose.yaml # Docker Compose (5 services)
506├── pyfedi.py # Entry point
507├── FEDERATION.md # Federation documentation
508└── CONTRIBUTING.md
509```
510
511Key namespaces: `app.activitypub`, `app.api.alpha`, `app.community`,
512`app.post`, `app.feed`, `app.shared.tasks`
513
514---
515
516## 15. PieFed vs Lemmy — Key Differences for Implementers
517
518| Aspect | PieFed | Lemmy |
519|--------|--------|-------|
520| Language | Python/Flask | Rust/Actix-web |
521| Resource usage | ~1 load avg | ~12 load avg (same hardware) |
522| `Feed` actor type | Yes (FEP-1d80) | No |
523| Private voting | Proxy user profiles | All votes public/federated |
524| Cross-post dedup | Merged comment views | Separate posts |
525| AI content flag | `genAI` property | No |
526| NSFL flag | Separate from NSFW | No (NSFW only) |
527| `EmojiReact` | Yes (federated as Likes to Lemmy) | No |
528| `ChooseAnswer` | Yes (Q&A mode) | No |
529| `Event` objects | Yes | No |
530| `PollVote` | Yes (Mastodon-compatible) | No native polls |
531| Flair federation | `flair` on Note + `tagsForPosts` | `tagsForPosts` only |
532| API path | `/api/alpha/` | `/api/v3/` |
533| API compatibility | 95% Lemmy-compatible | — |
534| JSON-LD processing | Plain JSON (no expansion) | Plain JSON (no expansion) |
535
536---
537
538## 16. Common Implementation Mistakes
539
5401. **Assuming PieFed is a Lemmy fork**: PieFed is a completely separate
541 Python codebase, not a Rust fork — protocol-compatible but
542 architecturally different
543
5442. **Not handling the `Feed` actor type**: PieFed federates `Feed`
545 actors via WebFinger; other software should treat unknown actor types
546 gracefully rather than erroring
547
5483. **Expecting public votes**: PieFed defaults to private voting — vote
549 activities may come from anonymous proxy profiles or not at all.
550 Do not assume vote counts match federated Like/Dislike activities
551
5524. **Ignoring `genAI` and `nsfl` properties**: PieFed adds these to
553 Group and Page objects — unknown properties should be ignored, not
554 cause parsing errors
555
5565. **Sending polls/events to PieFed communities hosted on Lemmy**:
557 PieFed prevents posting polls and events to remote Lemmy communities
558 because Lemmy doesn't support them — but if you federate these object
559 types to PieFed-hosted communities, they will work
560
5616. **Not handling `EmojiReact`**: PieFed sends `EmojiReact` activities
562 for emoji reactions — these federate as `Like` activities to Lemmy
563 for compatibility, but other implementations may receive the raw
564 `EmojiReact` type
565
5667. **Assuming all communities federate**: PieFed supports local-only
567 and private communities that are invisible to federation
568
5698. **Not supporting `ChooseAnswer`**: In Q&A mode communities, PieFed
570 sends `ChooseAnswer` activities to mark accepted answers — unknown
571 activity types should be ignored gracefully