Vibefed kb-writefreely

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-writefreely" ~/.claude/skills/reiver-vibefed-kb-writefreely && rm -rf "$T"
manifest: skills/kb-writefreely/SKILL.md
source content

WriteFreely — 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

ComponentTechnology
BackendGo (golang) — 64% of codebase
TemplatesGo Template — 24%
StylingLESS — 6.5%
Client-sideJavaScript — 3.8%
DatabaseMySQL/MariaDB 5.6+ or SQLite
Rich editorProseMirror (WYSIWYG "classic" mode)
LicenseAGPL-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
:

  • Article
    : Posts containing a double-line break (paragraph break). The default for multi-paragraph blog posts. Includes the post title in the
    name
    property.
  • Note
    : Posts without paragraph breaks (single-paragraph). Can be forced for all posts via
    notes_only = true
    configuration.

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):

ActivityTrigger
Create{Article}
or
Create{Note}
Post published
Update{Article}
or
Update{Note}
Post edited
Delete
Post deleted

Inbound (WriteFreely receives):

ActivityEffect
Follow
Remote user follows a blog
Undo{Follow}
Remote user unfollows
Like
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 (
    @handle@their.instance
    ) in posts so fediverse replies route to their microblogging account

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

FieldDescriptionDefault
federation
ActivityPub federation toggletrue
notes_only
Send all posts as Note (not Article)false
public_stats
NodeInfo statistics visibilitytrue

Other Notable Settings

FieldDescriptionDefault
single_user
Single-blog instance modefalse
editor
Editor template: pad, bare, classicpad
open_registration
Public signup (multi-user)true
max_blogs
Blogs per account (multi-user)5
default_visibility
New blog visibilityunlisted
local_timeline
Instance reader (multi-user)true
monetization
Web Monetization supporttrue
gopher_port
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:

MethodEndpointAuthPurpose
POST
/api/posts
OptionalCreate post
GET
/api/posts/{id}
NoRetrieve post
POST
/api/posts/{id}
OptionalUpdate post
DELETE
/api/posts/{id}
OptionalDelete post
POST
/api/posts/claim
RequiredClaim anonymous posts

Collections (Blogs):

MethodEndpointAuthPurpose
POST
/api/collections
RequiredCreate collection
GET
/api/collections/{alias}
NoGet metadata
POST
/api/collections/{alias}/posts
RequiredPublish to blog
GET
/api/collections/{alias}/posts
NoList posts
GET
/api/collections/{alias}/posts/{slug}
NoGet single post

Users:

MethodEndpointAuthPurpose
POST
/api/auth/login
NoAuthenticate
GET
/api/me
RequiredGet user info
GET
/api/me/posts
RequiredList user's posts
GET
/api/me/collections
RequiredList 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
    @handle@their.instance
    in post content

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:

ServicePurpose
Write.asHosted blogging platform ($1-10/month)
WriteFreelyOpen-source software (self-hosted)
WriteFreely.hostManaged WriteFreely community hosting
Snap.asMinimalist photo sharing
Remark.asCommenting system for Write.as blogs
Submit.asAccept writing submissions
Read.as / ReadFreelyActivityPub 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

AspectWriteFreelyPlume
LanguageGoRust
Federation modelWrite-only (broadcast)Bidirectional (shows replies)
CustomizationCustom CSS onlyThemes, fonts, layouts
MaintenanceActively maintainedNot actively maintained
Object typesArticle + NoteArticle

WriteFreely vs Ghost

AspectWriteFreelyGhost
LanguageGoNode.js
AP integrationSince 2018 (core)Since 2024 (core)
FocusMinimalist writingFull-featured CMS
Image hostingNone (external only)Built-in
NewslettersMailgun integrationBuilt-in
ThemesCustom CSSFull theme system
Resources256 MB RAM1 GB+ RAM

9. Interoperability Notes for Implementers

  1. Blogs are

    Person
    actors — each WriteFreely blog (collection) presents itself as a
    Person
    actor with a fediverse handle of
    @alias@instance.com
    . Follow a blog by sending
    Follow
    to this actor.

  2. Write-only federation — WriteFreely will never send

    Follow
    ,
    Announce
    ,
    Like
    , or reply activities. It only sends
    Create
    ,
    Update
    , and
    Delete
    for its own posts. If your software expects bidirectional interaction, WriteFreely will not reciprocate.

  3. Article vs Note distinction — multi-paragraph posts arrive as

    Article
    objects (with
    name
    containing the title), single-paragraph posts arrive as
    Note
    objects (no
    name
    ). If an instance has
    notes_only = true
    , all posts arrive as
    Note
    . Your software should handle both types from WriteFreely.

  4. 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.

  5. Like tracking — since v0.16, WriteFreely tracks

    Like
    activities and shows a count to the blog author. Sending
    Like
    to a WriteFreely blog will be acknowledged, but
    Undo{Like}
    handling may vary.

  6. No shared inbox optimization — WriteFreely stores shared inbox URLs from remote actors but primarily uses individual inboxes. Verify delivery works with both paths.

  7. Post excerpts on microblogging platforms — since v0.16, WriteFreely includes

    preview
    /
    summary
    fields on
    Article
    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.

  8. NodeInfo identifies the software — look for

    "name": "writefreely"
    in the NodeInfo software block to identify WriteFreely instances. The metadata includes WriteFreely-specific fields like
    maxBlogs
    ,
    publicReader
    , and
    invites
    .

  9. 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.

  10. 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.