Vibefed kb-pixelfed
git clone https://github.com/reiver/vibefed
T=$(mktemp -d) && git clone --depth=1 https://github.com/reiver/vibefed "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/kb-pixelfed" ~/.claude/skills/reiver-vibefed-kb-pixelfed && rm -rf "$T"
skills/kb-pixelfed/SKILL.mdPixelfed — Complete Reference
Overview
Pixelfed is a free, open-source, decentralized photo and video sharing platform — the Fediverse's answer to Instagram. Created by Daniel Supernault ("dansup") and launched December 25, 2018, it federates via ActivityPub. As of mid-2025, it has approximately 900,000 registered users across roughly 1,800 servers with 96+ million media items shared. Licensed under AGPL-3.0.
Pixelfed only displays posts with images or video — text-only posts from other Fediverse platforms are hidden. This is a fundamental design decision, not a bug.
1. Technical Stack
| Layer | Technology |
|---|---|
| Backend language | PHP |
| Backend framework | Laravel (currently v12) |
| Database | MySQL 8.0 or PostgreSQL 13 |
| Cache / Queue | Redis |
| Queue management | Laravel Horizon |
| OAuth | Laravel Passport |
| Frontend framework | Vue.js 2.6.14 |
| Frontend state | Vuex |
| CSS | Bootstrap |
| Build | Webpack via Laravel Mix |
| Mobile | React Native (iOS + Android) |
| Storage | Local filesystem or S3/Object Storage |
| License | AGPL-3.0 |
| Runtime | PHP 8.3+ (supports 8.4, 8.5), Node.js for assets |
2. Actor Model
Pixelfed uses
Person type actors for user accounts:
{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {"pixelfed": "http://pixelfed.org/ns#"} ], "type": "Person", "id": "https://pixelfed.example/users/alice", "preferredUsername": "alice", "name": "Alice", "summary": "<p>Bio text</p>", "inbox": "https://pixelfed.example/users/alice/inbox", "outbox": "https://pixelfed.example/users/alice/outbox", "following": "https://pixelfed.example/users/alice/following", "followers": "https://pixelfed.example/users/alice/followers", "manuallyApprovesFollowers": false, "indexable": true, "publicKey": { "id": "https://pixelfed.example/users/alice#main-key", "owner": "https://pixelfed.example/users/alice", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----" }, "icon": { "type": "Image", "mediaType": "image/jpeg", "url": "https://pixelfed.example/storage/avatars/alice.jpg" }, "endpoints": { "sharedInbox": "https://pixelfed.example/f/inbox" }, "alsoKnownAs": [] }
Key points:
- The shared inbox path is
(not/f/inbox
as with some other implementations)/inbox
controls locked/private account behaviourmanuallyApprovesFollowers
signals whether the account should appear in search indexesindexable
is present but account migration between servers is not currently supportedalsoKnownAs
Instance Actor
Pixelfed uses an instance-wide actor with
"type": "Application" to
sign GET requests to remote instances. This is separate from the
Person actors used by regular accounts. The instance actor is used
for authorized fetch (secure mode) — when a remote server requires
signed GET requests, Pixelfed uses this actor's key.
3. Supported Activities
| Activity | Description |
|---|---|
| Approves follow requests |
| Federates Stories (uses Bearcap URIs for access control) |
| Reblogs/boosts |
| Creates Note and Question objects |
| Removes Person, Tombstone, and Story objects |
| Federated report functionality |
| Follow request |
| Favorites a post |
| Denies follow requests |
| Reverses Announce, Follow, and Like |
| Modifies Note (status) and Person (profile) |
| Story view tracking |
| Reaction to a Story (Pixelfed-only) |
| Reply to a Story (Pixelfed-only) |
Story:Reaction and Story:Reply are Pixelfed-specific activity types
that are not understood by other Fediverse software.
4. Object Types and Post Structure
Pixelfed supports three object types: Note, Image, and Document.
Posts are represented as
Note objects:
{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {"pixelfed": "http://pixelfed.org/ns#"} ], "type": "Note", "id": "https://pixelfed.example/p/alice/123456", "attributedTo": "https://pixelfed.example/users/alice", "content": "<p>Caption text with #hashtag</p>", "summary": null, "inReplyTo": null, "published": "2025-06-15T12:00:00Z", "url": "https://pixelfed.example/p/alice/123456", "sensitive": false, "to": ["https://www.w3.org/ns/activitystreams#Public"], "cc": ["https://pixelfed.example/users/alice/followers"], "attachment": [ { "type": "Image", "mediaType": "image/jpeg", "url": "https://pixelfed.example/storage/m/photo.jpg", "name": "Alt text description", "blurhash": "LEHV6nWB2yk8pyoJadR*.7kCMdnj" } ], "tag": [ { "type": "Hashtag", "href": "https://pixelfed.example/discover/tags/hashtag", "name": "#hashtag" } ], "commentsEnabled": true, "capabilities": { "announce": "https://www.w3.org/ns/activitystreams#Public", "like": "https://www.w3.org/ns/activitystreams#Public", "reply": "https://www.w3.org/ns/activitystreams#Public" } }
Key points:
is used for content warnings (null when not set)summary
containsattachment
objects with optionalImageblurhash- Albums can have up to 20 items (some sources say 12 for photos)
- Captions support up to 2,000 characters (configurable)
- Three visibility levels: public, unlisted, followers-only
5. Pixelfed-Specific Extensions
Capabilities
Per-post access control added to
Note objects:
"capabilities": { "announce": "https://www.w3.org/ns/activitystreams#Public", "like": "https://www.w3.org/ns/activitystreams#Public", "reply": null }
Each capability value is either:
— allowed for everyone"https://www.w3.org/ns/activitystreams#Public"
— disablednull
This controls who can boost, like, or reply to a specific post. Other Fediverse software generally ignores this extension — they will still allow their users to interact with the post regardless of these settings.
commentsEnabled
A boolean property on
Note objects:
"commentsEnabled": true
When
false, replies are disabled on the post. Like capabilities,
this is enforced by Pixelfed but generally ignored by other
implementations.
Stories
Ephemeral 24-hour content, similar to Instagram Stories:
- Federated only between Pixelfed instances — not visible on Mastodon, Pleroma, or other platforms
- Use Bearcap URIs for access control (recipients must present a token to access the content)
- Require
in server configurationSTORIES_ENABLED=true - Support activities:
,Add
,Delete
,View
,Story:ReactionStory:Reply - Transform to
andStoryReaction
internal modelsStoryView
Location Geo-tagging
Posts can include a
Place object for location data:
"location": { "type": "Place", "name": "Paris, France", "longitude": 2.3522, "latitude": 48.8566, "country": "France" }
Blurhash
Pixelfed includes
blurhash on image attachments for compact preview
placeholders. This uses the toot:blurhash property from Mastodon's
namespace (http://joinmastodon.org/ns#). The blurhash is a short
string that encodes a blurred preview of the image, useful for showing
a placeholder while the full image loads.
Federated Groups
Pixelfed supports federated Groups via FEP-400e and FEP-1b12 extensions. Group actors use
"type": "Group" with standard inbox/outbox
collections.
6. JSON-LD Context
Pixelfed uses a multi-context approach with four namespaces:
"@context": [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {"pixelfed": "http://pixelfed.org/ns#"}, {"toot": "http://joinmastodon.org/ns#"} ]
| Namespace | Purpose |
|---|---|
| ActivityStreams 2.0 vocabulary |
| W3C Security Vocabulary (publicKey) |
| Pixelfed-specific properties (capabilities, commentsEnabled) |
| Mastodon compatibility (blurhash, indexable) |
When processing Pixelfed JSON-LD documents, unknown properties from the
pixelfed: and toot: namespaces should be ignored rather than causing
errors.
7. HTTP Signatures and WebFinger
HTTP Signatures
- Pixelfed signs every POST and GET request
- All incoming POST requests must be signed
- GET requests may require signatures (configurable — this is "authorized fetch" or "secure mode")
- The instance
actor's key is used for signing GET requestsApplication - Individual
actor keys are used for signing POST requests (activities from that user)Person
WebFinger
Pixelfed requires each ActivityPub actor to uniquely map to an
acct:
URI resolvable via WebFinger at /.well-known/webfinger. Standard
WebFinger resolution applies.
8. Collections
Three primary user collections using the
OrderedCollection pattern:
| Collection | Path | Content |
|---|---|---|
| Following | | Accounts this user follows |
| Followers | | Accounts following this user |
| Outbox | | User's published statuses |
totalItems may return 0 if the collection is hidden per user
privacy preference. This is intentional, not a bug — do not assume an
empty collection means the user has no followers/following.
9. Mastodon API Compatibility
Pixelfed implements a subset of the Mastodon REST API, allowing Mastodon client apps to work with Pixelfed instances.
Working endpoints
- Account endpoints (verify_credentials, update_credentials, relationships, search)
- Status endpoints (create, view, delete, favourite, boost)
- Timeline endpoints (home, public, hashtag)
- Notification endpoints
- OAuth 2.0 authentication (requires
)OAUTH_ENABLED=true
Known compatibility gaps
- OOB OAuth redirect (
) is not supported — apps relying on this flow will failurn:ietf:wg:oauth:2.0:oob - Authorization code grant type has reported issues
- Some public API endpoints incorrectly require OAuth tokens
- Pixelfed-specific features (Stories, Collections, capabilities) are not accessible via the Mastodon API — only through Pixelfed's own API
10. Federation Interoperability
Cross-platform behaviour
| Feature | Pixelfed to Mastodon | Mastodon to Pixelfed |
|---|---|---|
| Photo posts | Appear as image posts with text | Appear normally if image attached |
| Text-only posts | N/A (Pixelfed requires media) | Not displayed on Pixelfed |
| Album posts (>4 images) | Only first 4 images shown | N/A (Mastodon max 4) |
| Stories | Not visible | N/A |
| Boosts | Appear as boosts | Appear as boosts |
| Likes/Favourites | Federate normally | Federate normally |
| Replies | Federate, but display may be incomplete | Federate normally |
| Content warnings | Show as content warnings | Show as content warnings |
Known federation issues
- Pixelfed does not display older posts created before federation with a particular instance began
- Comment counts may be inaccurate (showing N comments but not all visible) due to incomplete federation of reply threads
- Nested reply threading can be incomplete across platforms
- Profile photo updates sometimes fail to federate properly
- The
extension is not respected by other platforms — a post withcapabilities
can still receive replies from Mastodon users"reply": null
11. Configuration Reference
Federation
| Variable | Description |
|---|---|
| Enable/disable federation entirely |
| Allow/prevent remote following |
Media
| Variable | Default | Description |
|---|---|---|
| 15000 (KB) | Per-file size limit (15 MB) |
| 1000000 (KB) | Per-user total storage (1 GB) |
| 4 | Items per post |
| 80 | JPEG quality 1-100 |
| — | Automatic image optimization |
| — | Automatic video optimization |
| — | S3/Object Storage support |
Accounts
| Variable | Default | Description |
|---|---|---|
| 500 | Caption character limit |
| 125 | Bio character limit |
| 30 | Display name limit |
| true | New account creation |
| 1000 | User registration cap |
| — | Email confirmation required |
Features
| Variable | Default | Description |
|---|---|---|
| false | Stories functionality |
| — | Third-party app authentication |
| — | Public explore feature access |
| — | Anonymous hashtag feed browsing |
12. Common Implementation Mistakes
- Ignoring the
extension: when federating with Pixelfed, be aware thatcapabilities
exists — even if you choose not to enforce it, you should not strip it when forwarding posts between instancescapabilities - Sending text-only posts to Pixelfed: Pixelfed silently drops posts without media attachments — there is no error response, the post simply does not appear
- Assuming Mastodon API parity: Pixelfed's Mastodon API implementation has gaps (no OOB OAuth, some endpoints require tokens when they should not) — test against a real Pixelfed instance
- Not handling
: if your software creates replies, check this field before sending a reply to a Pixelfed post — while Pixelfed cannot prevent your server from delivering the reply, respecting this field is good federation citizenshipcommentsEnabled: false - Expecting Stories to federate universally: Stories only work between Pixelfed instances — do not implement Story support expecting cross-platform compatibility
- Treating
as empty: Pixelfed returnstotalItems: 0
for hidden collections — a followers count of 0 does not mean the account has no followers0 - Wrong shared inbox path: Pixelfed uses
as the shared inbox, not/f/inbox
— always read the/inbox
value from the actor document rather than guessingendpoints.sharedInbox - Not handling the Application instance actor: Pixelfed uses a
separate
-type actor for GET request signing — if your server requires signed fetches, be prepared to resolve and verify keys from actors withApplication
, not just"type": "Application""Person"