Org Social: the social network that survives its own infrastructure

Leer en español

Org Social is so simple it looks like it was born before the internet. A single plain text file, an editor and a host are enough to interact with other people.

To "create an account", you just create a plain text file in any editor. Your "database" is your own hierarchy of posts. Your "algorithm" is however you decide to sort other people's posts. There is no "character limit". Your "server" is any hosting or web server. Your "interface" is your favorite editor. And if you want to "delete your account", you just delete the file. And of course, the syntax is richer than Markdown and just as easy to learn: Org Mode. You share and edit wherever you want, and you use it as a microblog, a journal, a forum, a bulletin board or a blog. Your file, your rules.

Behind it there is infrastructure that enriches the interaction and connects it with other systems and formats (the Fediverse, RSS, clients...). Each piece adds one more level of convenience, but none of them is essential: they are 100% optional! And that is what I want to talk about.

I'd like to take it apart piece by piece, explaining what each one does and why it exists.

Layer 0: a plain text file

Everything starts and ends here. A file called social.org, in UTF-8, with LF line endings.

The header is your profile. They are Org Mode keywords:

#+TITLE: My journal
#+NICK: Alice
#+DESCRIPTION: I write about Emacs and coffee
#+AVATAR: https://alice.com/avatar.jpg
#+LINK: https://alice.com
#+FOLLOW: https://bob.com/social.org
#+FOLLOW: friend https://carol.net/social.org

Below it, in a * Posts section, go your posts. Each one is a heading with an RFC 3339 timestamp, which works as a unique identifier:

** 2025-05-01T12:00:00+0100
:PROPERTIES:
:LANG: en
:TAGS: emacs org-social
:END:

Today I discovered Org Social and I can't stop writing.

And you already have a social network.

Anyone can curl your file, read it with their own eyes or with a client or script, and follow you by adding your URL to their #+FOLLOW:.

The interaction itself lives inside the format. There are no magic buttons, there are properties:

  • Replying is a post with :REPLY_TO: <url>#<id> pointing to the original.
  • Reacting is a reply with just :MOOD: ❤ and an empty body.
  • Sharing is :INCLUDE: with a reference to someone else's post.
  • Voting in a poll is replying with :POLL_OPTION:.
  • Mentioning someone is a link [[org-social:https://bob.com/social.org][Bob]].

Since it is plain text, you can edit all of it by hand if you feel like it.

When you are done, you save the file and upload it to your server.

Every decentralized social network has a weak spot, whichever one comes to mind. I covered this in There is no such thing as full decentralization, but in short, you always have to decide which of these five things the network sacrifices:

  • Identity
  • Connectivity
  • Discovery
  • Cost
  • Moderation

Org Social sacrifices discovery. Nobody can find you unless you give them your URL, just like an email address. And that makes some interactions impossible to reconstruct. For example, what happens if someone you don't follow joins a thread you started? If you don't follow them, you never find out.

That's why we need upper layers that mitigate the problem, although you should only use them if you think you need them. It may be that everyone taking part follows each other and needs nothing else. Otherwise, you will need a Relay: an index.

Layer 1: the client

You can check each feed directly with curl or with your browser. However, just like with your list of RSS/Atom feeds, what we all end up doing for convenience is using a client. It reads every source, sorts them, filters them and merges them into a list that is easier to read and that you can also navigate. The same goes for Org Social.

There is a client for Emacs, another for iOS, another for Android (in alpha as I write this), command line implementations and a public web viewer that needs no account or client. Clients build a timeline by merging all the feeds you follow, and they let you reply, react, share and vote in polls. But every change happens in your own file, not on a central server, and reading is volatile, since it is built on the fly.

Screenshot of org-social.el in Emacs: the Org Social timeline with navigation buttons, posts with hashtags, reactions, author and an embedded image

The client also acts as a translator between Org Social and the interface you choose. And it is a good way in for people who are already used to X/Twitter or Mastodon, or who don't want to bother learning the syntax.

Layer 2: the Relay

The Relay is a server that crawls the network of social.org files and builds an index: users, mentions, replies, groups and threads. It does this by reading the #+FOLLOW: lines of every feed it knows and downloading the files it finds. You can also register your feed manually so it reads it.

It doesn't store content, only addresses. It notes who mentions whom, what replies to what and what belongs to each thread.

Now you can write a client or a script that asks the Relay for the information that fills in the parts where you were blind before:

# Who mentioned me?
curl "https://relay.org-social.org/notifications/?feed=..."

# Give me the full thread of this post
curl "https://relay.org-social.org/replies/?post=..."

# Find everything about Emacs
curl "https://relay.org-social.org/search/?q=emacs"

And that's not all: anyone can run their own Relay, locally or on a server. Their instance will connect to other public Relays and they will exchange information, so the whole network knows which feeds exist and how they relate.

It also offers other features, such as real-time notifications, RSS/Atom feeds, post search and bridges to ActivityPub/Mastodon. Yes, you can follow Mastodon accounts from Org Social, or keep up with Org Social from your favorite RSS/Atom reader.

Layer 3: Org Social Host

Needing your own hosting just to start taking part in the network is a tough requirement. That's why there is a free and open hosting service, integrated with the clients, that puts your social.org online with a single click.

You pick a nick and get two addresses:

  • public-url: the one you share with everyone, for example https://host.org-social.org/alice/social.org.
  • vfile: a secret, signed URL that works as a password. Whoever has it can overwrite your file, so keep it safe.

If you use a client, all of this is automatic and you never even see the secret URL, since it is stored in your configuration. It all happens behind the scenes.

If you are curious, signing up is a single request:

curl -X POST https://host.org-social.org/signup \
  -H "Content-Type: application/json" \
  -d '{"nick": "alice"}'

And overwriting your file, another one:

curl -X POST https://host.org-social.org/upload \
  -F "vfile=YOUR_VFILE" \
  -F "file=@social.org"

It doesn't lock you in either. You can ask it for a permanent redirect (HTTP 301) to your new URL and your followers won't even notice. Their clients follow the redirect on their own, although it's a good idea to let them know so they update their #+FOLLOW:. It is a way in, not a requirement.

You can also run it on your own server, with public sign-up disabled and your own domain.

And it has an advantage that seasoned app developers will have guessed already: it makes syncing between devices easy. You can, for example, write in the mobile client and carry on in the Emacs one with simple HTTP requests. No old protocols, no third-party APIs.

Layer 4: Mirror or CDN

Do you use an RSS/Atom reader? Then you already know that the more feeds you follow, the slower it gets.

It doesn't matter how fast and parallel the downloads are. There will always be dropped connections, timeouts, errors and redirects. And if a feed is very large, the client has to parse all of it to keep what it cares about.

In my case, I follow 250 feeds. Download and parse them every time I scroll? Not viable. Cache them? Then the problem becomes when to invalidate the cache.

This is where the Mirror comes in. It is a server that keeps an up-to-date copy of every feed and saves you the parsing, sorting, thread building and mention consolidation. It exposes a simple REST API that returns JSON ready to use in a client.

You can think of it as a client of clients, or a general-purpose client without an interface. Internally, it works non-stop to keep the most recent copy and to prepare the processed information so it is easy to consume.

For example, if I want to build the timeline with Bob's and Carol's posts from the last 14 days:

curl --get "https://mirror.org-social.org/api/posts/" \
  --data-urlencode "following=https://bob.com/social.org" \
  --data-urlencode "following=https://carol.net/social.org" \
  --data-urlencode "sinceDays=14"

It doesn't replace the Relay. In fact, it needs it to know which feeds exist and which ones have changed. And most importantly: it is read-only. It never edits or deletes anything at the source. To publish, you still write to your own file. Its only way in is a webhook that a client can call to say a feed has changed and the Mirror should update it:

curl -X POST "https://mirror.org-social.org/api/webhook/refresh/" \
  -H "Content-Type: application/json" \
  -d '{"feed": "https://alice.com/social.org"}'

It is optional. The client calls it right after publishing or uploading a new version of the file to your hosting, so the Mirror updates its copy straight away instead of waiting for the next refresh cycle.

Layer 5: Push

The Relay already sends real-time notifications with Server-Sent Events, which clients can listen to in order to tell you about mentions, replies and reactions. But phones don't let an app keep connections open in the background, so there you need push notifications. It is the most specific layer of all, since each platform, iOS and Android, has its own notification system with its own certificates and tokens.

If this layer goes down, all you lose is the convenience of getting alerts on your phone while the app is closed.

Layer 6: Live Preview

An Org Social post has an address in the format https://<host>/social.org#<timestamp>. For example, my first post: https://host.org-social.org/andros/social.org#2025-08-14T09:11:00+0200. It works fine between Org Social clients, but what happens if you want to share it on another social network? Nothing pretty: the whole social.org file gets shared.

Live Preview turns a post into a web page. You give it the post URL, it downloads the original social.org (straight from the source, not through the Relay), finds the post and generates an HTML card with its Open Graph metadata: nick, avatar, text and date. Ready to share on any social network.

For example, the URL above becomes:

https://preview.org-social.org/?post=https%3A%2F%2Fhost.org-social.org%2Fandros%2Fsocial.org%232025-08-14T09%3A11%3A00%2B0200

Live Preview card of my first Org Social post: avatar, the nick andros, the text "Hello Org Social." and the date 2025-08-14T09:11:00+0200

And if I share it on social media, it looks like this:

WhatsApp screenshot after pasting the Live Preview link: the card shows my avatar, the nick andros, the text "Hello Org Social." and the domain preview.org-social.org

Clients also use this link format in their share option.

The same need gave birth to another very interesting feature: generating an HTML blog from your social.org, if it is hosted on host.org-social.org.

For example, my Org Social web version would be preview.org-social.org/blog/andros.

Screenshot of the Live Preview blog at preview.org-social.org/blog/andros: a header with my avatar, the title Andros' journal and my description, the pinned post "Hello Org Social." and my latest posts below with date, links and tags

You write in Org Mode, upload the file to the hosting (with a simple curl if you like) and your HTML blog is generated automatically, ready to share. It isn't perfect, since you don't control the design, but it saves you from running a static site generator.

Summary

In the end, they are not layers, but pieces orbiting around your social.org.

flowchart TB
    File["social.org"]
    Client["Client"]
    Relay["Relay"]
    Host["Host"]
    Mirror["Mirror"]
    Push["Push"]
    Preview["Live Preview"]

    Client -- "reads and writes" --> File
    Client -- "uploads and syncs" --> Host
    Host -- "hosts" --> File
    Host -- "registers feeds" --> Relay
    Relay -- "indexes" --> File
    Client -- "mentions, threads and search" --> Relay
    Mirror -- "which feeds exist and which change" --> Relay
    Mirror -- "copies" --> File
    Client -- "JSON timeline and webhook" --> Mirror
    Relay -- "real-time notifications" --> Push
    Push -- "phone alerts" --> Client
    Preview -- "reads" --> File
    Client -- "share link" --> Preview
Piece What it gives you If you remove it
social.org Your identity and your posts There is no network
Client Reading and writing comfortably You read with curl and edit by hand
Relay Discovery, mentions, threads and bridges You only see who you follow
Host Hosting without a server and syncing between devices You use your own hosting
Mirror Ready-to-use JSON, no Org parsing The client downloads and parses every file
Push Alerts on your phone You find out when you open the app
Live Preview Sharing posts outside the network You share the raw file URL

Whatever you use, the only essential piece is your social.org.

If every Org Social server shut down tomorrow, what would you lose? Convenience. And what would you keep? Your file, intact, on your disk. You upload it anywhere else and keep posting.

Few social networks can say the same.

Help me keep writing

Every coffee gives me a push toward the next article.

Comments

There are no comments yet.

2 mentions from other sites

You may also like