Vibefed kb-writefreely
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-writefreely" ~/.claude/skills/reiver-vibefed-kb-writefreely && rm -rf "$T"
skills/kb-writefreely/SKILL.mdWriteFreely — Complete Reference
Overview
WriteFreely is a free, open-source, federated blogging platform written in Go, created by Matt Baer and developed under Musing Studio (formerly the Write.as team). Licensed AGPL-3.0.
WriteFreely originated from Write.as, a privacy-focused anonymous writing platform launched in late 2014. After adding ActivityPub federation support, the codebase was refactored and released as open source in November 2018. It describes itself as "the social media hater's blogging platform" — deliberately rejecting feeds, alerts, and engagement metrics in favor of a distraction-free writing environment.
WriteFreely's federation model is write-only/broadcast: blogs can be followed from Mastodon and other ActivityPub platforms, but WriteFreely cannot follow others, does not display incoming replies or comments, and has no follower moderation. This is a deliberate design choice — it is a writing platform, not a social network.
As of early 2026, Write.as has hosted over 600,000 users with 6.6 million posts. The WriteFreely open-source software powers hundreds of independent instances across the fediverse.
1. Technology Stack
| Component | Technology |
|---|---|
| Backend | Go (golang) — 64% of codebase |
| Templates | Go Template — 24% |
| Styling | LESS — 6.5% |
| Client-side | JavaScript — 3.8% |
| Database | MySQL/MariaDB 5.6+ or SQLite |
| Rich editor | ProseMirror (WYSIWYG "classic" mode) |
| License | AGPL-3.0 |
Key Technical Characteristics
- Single binary deployment on any platform/architecture Go supports
- Minimal resources: runs on servers with 256 MB RAM, including Raspberry Pi
- No external dependencies in SQLite mode
- Built-in HTTP server with TLS support (Let's Encrypt auto-cert)
- Optional Gopher protocol server (since v0.13)
- Go 1.23+ and Node.js 15+ required for development builds
Database
Two backends supported:
- MySQL/MariaDB 5.6+:
CREATE DATABASE writefreely CHARACTER SET latin1 COLLATE latin1_swedish_ci; - SQLite: Built-in, no external database needed
PostgreSQL is not supported.
Database tables include: user access tokens, public/private RSA keypairs per collection (for signing ActivityPub requests), collections (blogs), posts, remote users, and remote follows.
2. ActivityPub Implementation
Actor Model
Each blog (collection) is an ActivityPub actor of type
Person. In
single-user mode, the instance acts as the single blog actor.
The fediverse handle format is
@blog@instance.com (or
@username@instance.com in single-user mode).
Each collection/blog has:
- A public/private RSA keypair for signing requests
- An inbox endpoint for receiving activities
- An outbox endpoint for published content
- A followers collection
Object Types
WriteFreely federates posts as either
Article or Note:
: Posts containing a double-line break (paragraph break). The default for multi-paragraph blog posts. Includes the post title in theArticle
property.name
: Posts without paragraph breaks (single-paragraph). Can be forced for all posts viaNote
configuration.notes_only = true
The heuristic: if the post body contains
\n\n (double newline), it is
sent as Article; otherwise as Note. This was implemented in v0.13
(merged March 2021).
Since v0.16, posts include
preview/summary fields so microblogging
platforms like Mastodon and Threads show excerpts with links rather than
just a link.
Activities
WriteFreely supports a deliberately limited set of activities:
Outbound (WriteFreely sends):
| Activity | Trigger |
|---|---|
or | Post published |
or | Post edited |
| Post deleted |
Inbound (WriteFreely receives):
| Activity | Effect |
|---|---|
| Remote user follows a blog |
| Remote user unfollows |
| Remote user favorites a post (count tracked since v0.16) |
Write-Only / Broadcast Nature
This is the most critical detail for interoperability:
- Blogs can be followed from Mastodon, Pleroma, and other AP platforms
- Posts are delivered to followers' timelines
- No incoming replies/comments: WriteFreely does not display replies from federated users on the blog itself
- No outgoing follows: Cannot follow other users from WriteFreely
- No blocking/managing follows: No moderation tools for followers
- No Announce/boost: WriteFreely does not send or process boosts
- Mentions as workaround: Authors can mention their own Mastodon
account (
) in posts so fediverse replies route to their microblogging account@handle@their.instance
HTTP Signatures
RSA-SHA256 signatures with per-blog keypairs. Signed headers include: request target, date, host, and digest. Remote user data stored: actor ID, inbox URL, shared inbox URL, user handle, and public key.
Libraries
- go-fed/activity/streams: ActivityPub library for Go
- writefreely/go-nodeinfo: Fork of NodeInfo with WriteFreely-specific metadata
3. Configuration
WriteFreely uses an
.ini config file (config.ini by default).
Instance Modes
- Single-user: One blog, the instance is the blog actor
- Multi-user: Multiple accounts, each with up to 5 blogs (default), local timeline/reader, admin dashboard, invitation system
Key Federation Settings
| Field | Description | Default |
|---|---|---|
| ActivityPub federation toggle | true |
| Send all posts as Note (not Article) | false |
| NodeInfo statistics visibility | true |
Other Notable Settings
| Field | Description | Default |
|---|---|---|
| Single-blog instance mode | false |
| Editor template: pad, bare, classic | pad |
| Public signup (multi-user) | true |
| Blogs per account (multi-user) | 5 |
| New blog visibility | unlisted |
| Instance reader (multi-user) | true |
| Web Monetization support | true |
| Gopher server port (0 = disabled) | 0 |
4. NodeInfo
WriteFreely implements NodeInfo via
github.com/writefreely/go-nodeinfo
(v1.2.0, MIT license), a fork with WriteFreely-specific metadata.
Discovery
/.well-known/nodeinfo → points to full NodeInfo URL.
WriteFreely-Specific Metadata
{ "metadata": { "nodeName": "My Blog", "nodeDescription": "A writing community", "private": false, "software": { "homepage": "https://writefreely.org", "github": "https://github.com/writefreely/writefreely", "follow": "https://writing.exchange/@writefreely" }, "maxBlogs": 5, "publicReader": true, "invites": true }, "protocols": ["activitypub"], "services": { "outbound": ["rss2.0"] }, "software": { "name": "writefreely", "version": "0.16.0" } }
5. API
WriteFreely provides a RESTful API (shared with Write.as) with full read access and publishing.
Authentication
Token-based:
Authorization: Token {access_token} (UUID format).
Anonymous publishing is supported — no auth required for creating posts.
Accepts form data (default) or
application/json. Returns JSON.
Core Endpoints
Posts:
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
| POST | | Optional | Create post |
| GET | | No | Retrieve post |
| POST | | Optional | Update post |
| DELETE | | Optional | Delete post |
| POST | | Required | Claim anonymous posts |
Collections (Blogs):
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
| POST | | Required | Create collection |
| GET | | No | Get metadata |
| POST | | Required | Publish to blog |
| GET | | No | List posts |
| GET | | No | Get single post |
Users:
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
| POST | | No | Authenticate |
| GET | | Required | Get user info |
| GET | | Required | List user's posts |
| GET | | Required | List user's blogs |
Data Models
Post: id, slug, token (for anonymous updates), title, body (Markdown), appearance (sans/serif/wrap/mono/code), language, rtl, created, updated, views, tags, collection.
Collection: alias (URL slug), title, description, style_sheet, script, visibility (0=Unlisted, 1=Public, 2=Private, 4=Password-protected), views, total_posts.
6. Features
Writing and Publishing
- Distraction-free Markdown editor with three modes: pad (default), bare, classic (WYSIWYG via ProseMirror, since v0.13)
- MathJax formula rendering
- Hashtag organization
- Custom CSS and JavaScript per blog
- Font appearances: serif, sans-serif, monospace, wrapped
- RTL script support, 20+ language localizations
- Draft posts, static pinned pages, post signatures
- RSS feed per blog (automatic)
- SEO best practices encoded by default
- No native image hosting — must embed from external sources (Snap.as or other hosts)
Multi-User Community
- Multiple blogs per account (configurable, default 5)
- Local timeline / reader for shared content
- Privacy levels: public, unlisted, private, password-protected
- Open or closed registration, invitation system
- Admin dashboard with instance stats and user management
Federation Features
- Fediverse verification badges via rel="me" (since v0.14)
- Like counts visible to blog authors (since v0.16)
- Subscribers page showing fediverse followers
- fediverse:creator tag linking to another profile (since v0.16)
- Mentions via
in post content@handle@their.instance
Other Protocols and Integrations
- Gopher protocol server (since v0.13)
- Web Monetization micropayments (since v0.13)
- Email newsletters via Mailgun (since v0.15)
- SMTP for password resets and notifications (since v0.16)
- OAuth 2.0: Generic, Gitea, GitLab, Slack, Write.as
7. Ecosystem
WriteFreely is part of the Musing Studio ecosystem:
| Service | Purpose |
|---|---|
| Write.as | Hosted blogging platform ($1-10/month) |
| WriteFreely | Open-source software (self-hosted) |
| WriteFreely.host | Managed WriteFreely community hosting |
| Snap.as | Minimalist photo sharing |
| Remark.as | Commenting system for Write.as blogs |
| Submit.as | Accept writing submissions |
| Read.as / ReadFreely | ActivityPub reading client (paused) |
Musing Studio was founded by Matt Baer in 2015. He runs the company solo. Core values: ad-free, tracking-free, customer-funded (no venture capital), open web interoperability.
8. Comparisons
WriteFreely vs Plume
| Aspect | WriteFreely | Plume |
|---|---|---|
| Language | Go | Rust |
| Federation model | Write-only (broadcast) | Bidirectional (shows replies) |
| Customization | Custom CSS only | Themes, fonts, layouts |
| Maintenance | Actively maintained | Not actively maintained |
| Object types | Article + Note | Article |
WriteFreely vs Ghost
| Aspect | WriteFreely | Ghost |
|---|---|---|
| Language | Go | Node.js |
| AP integration | Since 2018 (core) | Since 2024 (core) |
| Focus | Minimalist writing | Full-featured CMS |
| Image hosting | None (external only) | Built-in |
| Newsletters | Mailgun integration | Built-in |
| Themes | Custom CSS | Full theme system |
| Resources | 256 MB RAM | 1 GB+ RAM |
9. Interoperability Notes for Implementers
-
Blogs are
actors — each WriteFreely blog (collection) presents itself as aPerson
actor with a fediverse handle ofPerson
. Follow a blog by sending@alias@instance.com
to this actor.Follow -
Write-only federation — WriteFreely will never send
,Follow
,Announce
, or reply activities. It only sendsLike
,Create
, andUpdate
for its own posts. If your software expects bidirectional interaction, WriteFreely will not reciprocate.Delete -
Article vs Note distinction — multi-paragraph posts arrive as
objects (withArticle
containing the title), single-paragraph posts arrive asname
objects (noNote
). If an instance hasname
, all posts arrive asnotes_only = true
. Your software should handle both types from WriteFreely.Note -
No incoming comment support — if your users reply to a WriteFreely post, their reply will be delivered to the WriteFreely inbox but will not be displayed on the blog. The reply exists only on your platform. Authors may work around this by mentioning their Mastodon account in posts.
-
Like tracking — since v0.16, WriteFreely tracks
activities and shows a count to the blog author. SendingLike
to a WriteFreely blog will be acknowledged, butLike
handling may vary.Undo{Like} -
No shared inbox optimization — WriteFreely stores shared inbox URLs from remote actors but primarily uses individual inboxes. Verify delivery works with both paths.
-
Post excerpts on microblogging platforms — since v0.16, WriteFreely includes
/preview
fields onsummary
objects. Mastodon and Threads will show an excerpt with a link rather than just a bare link. Older WriteFreely versions may send Articles without summaries.Article -
NodeInfo identifies the software — look for
in the NodeInfo software block to identify WriteFreely instances. The metadata includes WriteFreely-specific fields like"name": "writefreely"
,maxBlogs
, andpublicReader
.invites -
RSS is always available — every WriteFreely blog has an RSS feed regardless of federation settings. If federation is disabled, RSS is still the primary syndication method.
-
No image hosting — WriteFreely posts reference externally-hosted images via Markdown image syntax. If your software processes WriteFreely content, images will be URLs to third-party hosts (including Snap.as), not to the WriteFreely instance itself.