Kb peertube
A Fediverse & ActivityPub plugin for those wishing to use LLM coding tools for the Fediverse and the Social Web.
npx -y skills add reiver/vibefed --skill kb-peertubeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Background knowledge about PeerTube, the decentralized video streaming platform. Load when the user asks about implementing a PeerTube- compatible ActivityPub server, federating with PeerTube instances, PeerTube's two-tier actor model (Person actors own Group channel actors, Application instance actor), PeerTube's attributedTo requirement (videos must reference a Group actor which references an owning Person actor), PeerTube's supported ActivityPub activities (Accept, Announce, ApproveReply via FEP-5624, Create, Delete, Dislike, Flag, Follow, Like, Reject, Undo, Update, View), PeerTube's object types (Video with live streaming and comment policy extensions, Note for comments, CacheFile for video redundancy/mirroring, Playlist, PlaylistElement, WatchAction), PeerTube's JSON-LD context namespaces (joinpeertube.org/ns#, schema.org, join-lemmy.org/ns#), PeerTube's Video object extensions (isLiveBroadcast, liveSaveReplay, permanentLive, latencyMode, commentsPolicy, canReply, downloadEnabled, sensitive, waitTranscoding, state, embedUrl), the CacheFile redundancy system (WebSeed injection, Create{CacheFile}, Undo{CacheFile}), PeerTube's Dislike activity (non-standard in the Fediverse), cross-platform federation with Mastodon (comments as replies, favourites as thumbs up, asymmetrical instance following), PeerTube's P2P video delivery (HLS with WebRTC), live streaming (RTMP/RTMPS ingestion, HLS output, permanent streams, replay saving), remote runners for transcoding, the plugin system, or PeerTube's technical stack (TypeScript, Node.js, Express, PostgreSQL, Redis, Angular, FFmpeg). Also load when reviewing or writing code that needs to interoperate with PeerTube instances, implement PeerTube's channel model, handle PeerTube Video objects, or process CacheFile activities.
SKILL.md
21.2 KB, ~5.0k tokens by cl100k_base, as published. Nobody here has run it
PeerTube — Complete Reference
Overview
PeerTube is a free, open-source, decentralized video streaming platform — the Fediverse's alternative to YouTube. Created by Chocobozzz and supported by the French non-profit Framasoft since October 2017, it federates via ActivityPub. As of October 2025, it has approximately 1,906 active instances, 815,000 registered users, and 1.56 million hosted videos. Licensed under AGPL-3.0.
PeerTube federations are asymmetrical — one instance can follow another to display their videos without the other having to reciprocate. This is fundamentally different from Mastodon's symmetrical user-follow model.
1. Technical Stack
| Layer | Technology |
|---|---|
| Backend language | TypeScript (Node.js) |
| Backend framework | Express |
| Database | PostgreSQL 12+ (with pg_trgm and unaccent extensions) |
| Cache / Queue | Redis (BullMQ for job queues) |
| ORM | Sequelize |
| Video processing | FFmpeg (LTS 4.3+) |
| OAuth | Built-in OAuth 2.0 |
| Web server | Nginx (official configs provided) |
| Package manager | pnpm |
| Frontend framework | Angular (TypeScript) |
| Playback | VideoJS, hls.js, P2P Media Loader |
| Frontend build | Webpack |
| Frontend CSS | SASS / Bootstrap |
| Mobile | Official app (iOS + Android, December 2024) |
| License | AGPL-3.0 |
| Runtime | Node.js LTS 20.19+ (excl. v21) or v22.12+ (excl. v23) |
Server Components
- REST API — handles client requests and video operations
- RTMP server — accepts live streaming input (port 1935/TCP, 1936/TCP for RTMPS)
- ActivityPub implementation — federation between instances
- Socket.io server — real-time client notifications
- Task scheduler — processes transcoding and ActivityPub delivery jobs via BullMQ
2. Actor Model
PeerTube uses a two-tier actor model that is central to how it federates video content:
- Person — represents user accounts
- Group — represents video channels, owned by Person actors
- Application — platform-level instance actor for federation and anonymous activities
A single Person can own multiple Group (channel) actors.
Person Actor (Account)
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{"pt": "https://joinpeertube.org/ns#"}
],
"type": "Person",
"id": "https://peertube.example/accounts/alice",
"preferredUsername": "alice",
"name": "Alice",
"summary": "<p>Bio text</p>",
"inbox": "https://peertube.example/accounts/alice/inbox",
"outbox": "https://peertube.example/accounts/alice/outbox",
"following": "https://peertube.example/accounts/alice/following",
"followers": "https://peertube.example/accounts/alice/followers",
"publicKey": {
"id": "https://peertube.example/accounts/alice#main-key",
"owner": "https://peertube.example/accounts/alice",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
},
"endpoints": {
"sharedInbox": "https://peertube.example/inbox"
}
}
Group Actor (Video Channel)
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{"pt": "https://joinpeertube.org/ns#"}
],
"type": "Group",
"id": "https://peertube.example/video-channels/alice_channel",
"preferredUsername": "alice_channel",
"name": "Alice's Channel",
"summary": "<p>Channel description</p>",
"inbox": "https://peertube.example/video-channels/alice_channel/inbox",
"outbox": "https://peertube.example/video-channels/alice_channel/outbox",
"following": "https://peertube.example/video-channels/alice_channel/following",
"followers": "https://peertube.example/video-channels/alice_channel/followers",
"attributedTo": [
{
"type": "Person",
"id": "https://peertube.example/accounts/alice"
}
],
"publicKey": {
"id": "https://peertube.example/video-channels/alice_channel#main-key",
"owner": "https://peertube.example/video-channels/alice_channel",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
},
"endpoints": {
"sharedInbox": "https://peertube.example/inbox"
}
}
Key points:
- The Group actor's
attributedTopoints to the owning Person actor - Users follow channels (Group), not accounts (Person) directly
- Both Person and Group actors are discoverable via WebFinger
- The shared inbox path is
/inbox - The Application instance actor handles platform-level federation and anonymous GET request signing
Interoperability with Non-Channel Platforms
For platforms that don't have a channel concept, PeerTube recommends:
- Simulate a Group actor representing the account, or
- Put the Person actor as a Group actor in
attributedToowned by a global Person actor
Without a Group actor in attributedTo, PeerTube cannot properly
federate the video.
3. Supported Activities
| Activity | Description |
|---|---|
Accept | Approves follow requests |
Announce | Channel announces a video (primary video distribution mechanism) |
ApproveReply | Comment moderation approval (v6.2+, implements FEP-5624) |
Create | Creates Video, Note (comment), CacheFile, Playlist |
Delete | Removes Video, Note, Person, Group, Playlist, CacheFile |
Dislike | Thumbs down on a video (non-standard — most Fediverse software only has Like) |
Flag | Federated report functionality |
Follow | Subscribe to a channel or instance |
Like | Thumbs up on a video |
Reject | Denies follow requests |
Undo | Reverses Follow, Announce, Like, Dislike, CacheFile |
Update | Modifies Video, Note, Person, Group, Playlist, CacheFile |
View | View count tracking |
How Video Publishing Works
When a user uploads a video:
- The Person actor sends a
Create{Video}activity - The Group (channel) actor sends an
Announce{Video}to its followers - Followers of the channel receive the video via the Announce
This two-step flow is how PeerTube distributes videos — the channel
Announce is the primary distribution mechanism.
4. Object Types
Video Object
PeerTube uses Video as the object type (not Note). This is an
extended ActivityStreams object with many custom properties:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{"pt": "https://joinpeertube.org/ns#"},
{"sc": "http://schema.org/"}
],
"type": "Video",
"id": "https://peertube.example/videos/watch/abc-123",
"name": "My Video Title",
"content": "<p>Video description</p>",
"summary": "Content warning text",
"sensitive": false,
"published": "2025-06-15T12:00:00Z",
"updated": "2025-06-15T13:00:00Z",
"attributedTo": [
{
"type": "Group",
"id": "https://peertube.example/video-channels/alice_channel"
},
{
"type": "Person",
"id": "https://peertube.example/accounts/alice"
}
],
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://peertube.example/video-channels/alice_channel/followers"],
"duration": "PT5M30S",
"downloadEnabled": true,
"waitTranscoding": true,
"state": 1,
"commentsPolicy": 0,
"canReply": "https://www.w3.org/ns/activitystreams#Public",
"isLiveBroadcast": false,
"url": [
{
"type": "Link",
"mediaType": "text/html",
"href": "https://peertube.example/videos/watch/abc-123"
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube.example/static/streaming-playlists/hls/abc-123/master.m3u8",
"height": 1080,
"fps": 30
}
],
"embedUrl": "https://peertube.example/videos/embed/abc-123",
"tag": [
{
"type": "Hashtag",
"name": "#technology"
}
]
}
Key points about the Video object:
attributedTomust contain both a Group (channel) and a Person (account) — the Group entry is required for federationnameis the video title (notsummaryas with Mastodon posts)contentis the video description (HTML)summaryis used for content warnings (like Mastodon)durationuses ISO 8601 duration format (e.g.,PT5M30S)urlis an array with multiple entries for different formats and resolutions (HTML page, MP4 files, HLS playlists)- If
embedUrlis absent, the video has embedding restrictions sensitiveand a tag oftype: SensitiveTagindicate sensitive content
Video Object Extensions
Live streaming properties:
isLiveBroadcast— whether this is a live streamliveSaveReplay— whether to save the replay after stream endspermanentLive— persistent stream URL that can be reusedlatencyMode— latency configuration for the streamschedules— array for scheduled broadcast times
Interaction controls:
commentsPolicy— comment policy (integer value)canReply— FEP-5624; when set to the public collection, comments require approval viaApproveReplydownloadEnabled— boolean controlling whether viewers can download
State:
waitTranscoding— whether to wait for transcoding before publishingstate— current video state (integer)
Note (Comments)
Comments are represented as Note objects, compatible with Mastodon
and other text-based platforms:
{
"type": "Note",
"id": "https://peertube.example/comments/456",
"content": "<p>Great video!</p>",
"inReplyTo": "https://peertube.example/videos/watch/abc-123",
"attributedTo": "https://peertube.example/accounts/bob",
"published": "2025-06-15T14:00:00Z",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://peertube.example/accounts/alice"]
}
When a Mastodon user replies to a PeerTube video post, the reply appears as a comment on the video in PeerTube.
CacheFile (Redundancy)
A non-standard object type used for PeerTube's video mirroring system:
{
"type": "CacheFile",
"object": "https://peertube.example/videos/watch/abc-123",
"expires": "2025-07-15T12:00:00Z",
"url": {
"type": "Link",
"mediaType": "application/x-mpegURL",
"href": "https://mirror.example/redundancy/hls/abc-123/master.m3u8"
}
}
Other Object Types
| Type | Purpose |
|---|---|
Playlist | Non-standard OrderedCollectionPage containing PlaylistElement items |
PlaylistElement | Individual playlist entries with start/stop timestamps |
WatchAction | Schema.org-derived object for aggregated viewer statistics |
5. Video Redundancy and CacheFile
PeerTube has a built-in redundancy system allowing instances to mirror videos from other instances, improving resilience and bandwidth sharing.
How Redundancy Works
- An admin configures a redundancy strategy (cache trending videos, recently uploaded videos, etc.)
- PeerTube periodically checks for new videos to duplicate
- When a video is selected, all resolution files are imported and stored locally
- A
Create{CacheFile}ActivityPub message is sent to federated instances - The caching instance is injected as a WebSeed by instances that receive this message — viewers can now download video chunks from the mirror
- When the cache is full, old videos are evicted and new ones selected
ActivityPub Flow
Create{CacheFile}— sent when a mirror instance begins cachingUndo{CacheFile}— sent when the cached copy is removed
Redundancy Strategies
- Most viewed — cache the most popular videos
- Recently added — cache the newest videos
- Complete mirror — use
recently-addedwith view count set to 0
Benefits
- If the origin server goes down, the video remains accessible from cache instances
- Servers share bandwidth for popular content
- P2P delivery benefits from additional WebSeeds
6. P2P Video Delivery
PeerTube uses HLS with WebRTC P2P for video playback:
- Video chunks are loaded via HTTP from the origin server and any mirrors (WebSeeds)
- Simultaneously, chunks are exchanged between viewers via WebRTC peer-to-peer connections
- Under optimal conditions (many concurrent viewers), P2P can reduce server bandwidth usage by 80-90%
- P2P efficacy diminishes with few concurrent viewers
Up until version 6.0.0, PeerTube also supported WebTorrent for P2P delivery. WebTorrent was dropped in v6.0 in favour of HLS-only P2P.
Privacy Consideration
P2P streaming exposes viewer IP addresses to other peers. This is inherent to how WebRTC works and should be considered when deploying PeerTube in privacy-sensitive contexts.
7. Live Streaming
PeerTube supports live streaming (introduced in v3.0, January 2021):
- RTMP ingestion — stream via OBS or any RTMP-compatible software (port 1935/TCP)
- RTMPS — encrypted streaming (port 1936/TCP)
- Live transcoding — real-time transcoding to multiple resolutions
- HLS output — live streams delivered via HLS with P2P WebRTC
- Permanent live streams — persistent stream URLs that can be reused
- Stream scheduling — schedule when a stream starts (v7.3+)
- Live chat — basic integration (v7.3+)
- Save replay — optionally save recordings as VOD after stream ends
- Federation — live streams federate to channel followers via
ActivityPub using Video objects with
isLiveBroadcast: true
Live transcoding is processed differently from VOD transcoding — it happens in real-time and can be offloaded to remote runners.
8. JSON-LD Context
PeerTube uses extended contexts with multiple custom namespaces:
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{"pt": "https://joinpeertube.org/ns#"},
{"sc": "http://schema.org/"}
]
| Namespace | Prefix | Purpose |
|---|---|---|
https://www.w3.org/ns/activitystreams | — | ActivityStreams 2.0 vocabulary |
https://w3id.org/security/v1 | — | W3C Security Vocabulary (publicKey) |
https://joinpeertube.org/ns# | pt: | PeerTube-specific properties (commentsPolicy, downloadEnabled, isLiveBroadcast, etc.) |
http://schema.org/ | sc: | Schema.org vocabulary (WatchAction, etc.) |
https://join-lemmy.org/ns# | lemmy: | Lemmy compatibility (postingRestrictedToMods) |
When processing PeerTube JSON-LD documents, unknown properties from the
pt: namespace should be ignored rather than causing errors.
9. HTTP Signatures and WebFinger
HTTP Signatures
PeerTube signs ActivityPub messages with JSON Linked Data Signatures using the private key of the account that authored the action. HTTP Signatures are used for server-to-server authentication.
Each actor (Person, Group, Application) has its own key pair. The Application instance actor is used for platform-level operations.
WebFinger
PeerTube supports WebFinger at /.well-known/webfinger for actor
discovery. Both Person (account) and Group (channel) actors are
discoverable:
- Account:
acct:[email protected] - Channel:
acct:[email protected]
10. Cross-Platform Federation
Mastodon Interoperability
| Action on Mastodon | Result on PeerTube |
|---|---|
| Follow a PeerTube channel | Videos appear in Mastodon home timeline |
| Reply to a PeerTube video post | Appears as a comment on the video |
| Favourite a PeerTube video | Appears as a thumbs up (Like) |
| Boost a PeerTube video | Increases reach on federated timelines |
| Action on PeerTube | Result on Mastodon |
|---|---|
| Upload a video | Appears as a post in followers' timelines |
| Like a Mastodon comment | Standard Like activity |
| Dislike | Not processed — Mastodon ignores Dislike activities |
Dislike (Non-Standard)
PeerTube supports the Dislike activity (thumbs down), which is
non-standard in the broader Fediverse. Most Fediverse software only
implements Like. Mastodon does not send or process Dislike
activities, so dislikes from PeerTube are silently ignored by Mastodon
and most other platforms.
Comment Approval (FEP-5624)
PeerTube v6.2+ supports comment moderation via the ApproveReply
activity (implementing FEP-5624). When a video has canReply set to
the public collection, comments from remote instances require approval
before becoming visible. The origin PeerTube instance sends an
ApproveReply activity back to the commenter's instance when approved.
Asymmetrical Instance Following
PeerTube instances can follow other PeerTube instances to display their videos without the followed instance needing to reciprocate. This is an admin-level operation used for content discovery.
11. Plugin System and Remote Runners
Plugin System
- Plugins are installed via NPM in a dedicated directory
- The server
requires the module and calls itsregister()function - Hooks fire on application events (video creation, page initialization, transcoding, etc.)
- Themes operate as client-only plugins with CSS injection
- Plugins can add custom API routes, settings pages, and client-side components
Remote Runners
PeerTube can offload heavy processing to remote machines:
- Remote runners register with the instance using registration tokens
- They poll the REST API for pending jobs
- Supported tasks: VOD transcoding, Studio transcoding, Live transcoding, Automatic transcription
- When remote runners are enabled for a task, PeerTube stops processing that task locally
- The runner posts the job result back to PeerTube
Known limitation: Server-side transcoding plugins are disabled when remote runners are enabled for transcoding tasks.
12. Common Implementation Mistakes
- Missing Group actor in
attributedTo: PeerTube requires videos to have anattributedTofield containing a Group actor — without it, the video cannot be properly federated. If your platform does not have channels, simulate a Group actor or use the Person actor in the Group role - Treating PeerTube videos as Note objects: PeerTube uses
Videoas the object type, notNote— code that only handlesNotewill miss all PeerTube content. Implement handling fortype: "Video"in your ActivityPub processor - Ignoring the two-tier
attributedTo: PeerTube'sattributedTocontains both a Group (channel) and a Person (account) — if you only read the first entry, you may attribute the video to the channel instead of the person, or vice versa - Not handling
Dislikegracefully: PeerTube sendsDislikeactivities that most Fediverse software does not understand — your implementation should ignore unknown activity types rather than erroring - Assuming video URL is a single string: PeerTube's
urlfield is an array with multiple entries for different formats (HTML page, MP4 at various resolutions, HLS playlists) — pick the appropriate entry based onmediaType - Not handling
CacheFile: if you receive aCreate{CacheFile}activity, it means a remote instance is mirroring one of your videos — you should add the mirror as a WebSeed for that video, not reject the activity as unknown - Expecting symmetrical follows: PeerTube instance-level follows are asymmetrical — following an instance does not mean they follow you back. Don't assume mutual federation.
- Ignoring
embedUrlabsence: if a PeerTube Video object lacksembedUrl, the video has embedding restrictions — do not attempt to generate an embed URL by guessing the pattern - Not supporting
ApproveReply: if your users comment on PeerTube videos with comment approval enabled, the comment won't be visible until the PeerTube instance sends back anApproveReply— handle this pending state in your UI rather than showing it as posted