social-badge is software for a wearable badge that lets people send short messages to each other on a system they can run, read and change themselves. It is written in Crystal and runs on BeagleBadge, a small Linux computer from BeagleBoard.org that is worn on a lanyard, and on ordinary servers.
What it's for
Many people rely on Facebook to keep in touch with friends and family. social-badge asks whether something can connect them even better while staying in their hands. A badge passes short messages directly from one person to another by radio, so no internet connection is needed. When there is an internet connection, the same messages can also reach people on the Fediverse: the network of independent social sites, such as Mastodon servers, that exchange posts with each other. Those sites are run by others; the badge and its own server are not.
What it's made of
- Crystal for all of its code, including the web server, which uses the Kemal library.
- Meshtastic, an open radio protocol for sending small text messages between low-power radios over a few kilometres, with no phone network or internet. Messages are kept short to fit it.
- Fossil, a version-control system that also keeps users, a forum and a timeline in one file, called a repository. Two Fossil repositories can copy each other's changes with Fossil's own sync protocol. Each saved change in a repository is a check-in. This project's own code lives in a Fossil repository too.
- ActivityPub, the protocol that Fediverse sites use to exchange posts.
- LVGL, a graphics library for small screens, which draws the badge's own display.
- Typst, a typesetting program, which lays out each message for the badge's 320×240-pixel screen, so a message looks the same in the browser preview and on the badge.
How it's shaped
One program runs on each badge and on each server. It serves a web page for writing messages and an HTTP API (requests that other programs send to it, by default on port 30000) for reading and posting them. On a badge it also draws the badge's screen. A message is also called a post. Each person's timeline is the list of posts they have written and received.
- Badge to badge, without internet: the program turns a message into a compact Meshtastic packet for the radio, and turns arriving packets back into messages. The packet code is written; driving a real radio is not.
- Badge to badge, with internet: each badge's users and timeline are to live in a Fossil repository, and badges are to copy each other's posts with Fossil sync. Today the timeline is kept in JSON files.
- To the Fediverse: a server running the program speaks ActivityPub, so Mastodon users can follow its users. It already stores posts arriving from the Fediverse in a Fossil forum, and sends its own forum posts to the Mastodon users who follow them.
- To iPhones: the badge should also talk to iPhones through Stone, a sister project that builds an iPhone app, probably over Bluetooth Low Energy (BLE), the short-range radio that phones use for accessories.
What success looks like
Each item says where it stands and links to the evidence.
- A public server. A server shows public posts on the web. Running at badge.beagle.group. Which version it runs hasn't been checked since Nov 3.
- Runs on BeagleBadge. The program is built for BeagleBadge and runs on it. Built, not yet run: the build is checked (post 6b26b45ec7), but the badge itself isn't booting (post 8478db6c9a). The build was made by hand rather than by OCX (see below), a shortcut to be replaced (ticket e4eb4e1582).
- Two badges by radio. Two badges exchange posts over Meshtastic. Not yet: no real radio has carried a post.
- Badges synced by Fossil. Badge timelines live in Fossil repositories and sync with each other. Not yet (ticket 0b0735b023).
- Seen on Mastodon. A post written on a badge or server is visible from a real Mastodon account. Not yet shown: the ActivityPub code is written and tested, but no real Mastodon account has seen a post.
- iPhone through Stone. A badge exchanges messages with an iPhone running Stone. Not yet: nothing for it is written.
The virtues behind it
social-badge is one of a group of projects that share a workbench called
OCX, which runs their builds and
their AI agent sessions across several machines. OCX's code is kept in a
Fossil repository named ollama.
The Big Picture page
says why each project is in the group. Every project follows the same four
virtues:
- Clearly stated: anyone can tell what each part does. Messages are short plain text, and each service in the code does one job.
- Loosely coupled: each part can be swapped without breaking the rest. Radio, Fossil sync and ActivityPub are separate paths to the same timeline.
- Demonstrably verified: every claim is shown working, not just stated. The list above says not yet until a real badge, radio or Mastodon account has shown it.
- Parsimoniously bounded: it does no more than it needs to. The plan is for users, posts and sync to come from Fossil instead of new code.
Run it
You need Crystal and its package tool, shards. The libraries the program
uses (Crystal calls them shards) aren't stored in this repository; the file
shard.lock pins their versions. Two of them run an extra setup step after
download: the lvgl shard's needs SDL2, a desktop graphics library, and the
typst shard's needs cargo, Rust's build tool. Many machines lack them, so
skip those steps and build LVGL with the
project's own script, which uses SDL2 only if it's installed:
shards install --frozen --skip-postinstall --skip-executables
crystal run scripts/build_liblvgl.cr
crystal run src/main.cr
Then open http://127.0.0.1:30000/health, which answers with a short JSON
status. The web page and the badge screen run from the same process. With no
screen attached, the program uses LVGL's headless mode, which draws to
memory instead of a display; set SOCIAL_BADGE_LOCAL_UI=1 to use a real
screen.
The browser preview needs a typst program on your PATH (see
docs/typst-runtime.md). Without one, /health
reports the preview as unavailable, and everything else still works.
More detail
- docs/architecture-decisions.md: why the code is built the way it is.
- docs/fossil-forum-activitypub-integration.md: using a Fossil repository's users and forum as the store behind ActivityPub, and which traffic goes by Fossil sync and which by ActivityPub.
- docs/protocol-implementation-notes.md: what the code must do to follow ActivityPub, WebFinger (how Fediverse sites find a user by name) and Meshtastic.
- docs/message-rendering-320x240.md: how messages are laid out for the badge's screen.
- docs/typst-layout-tests.md, docs/open-font-profiles.md and docs/typst-runtime.md: the Typst layout, its tests, its fonts, and installing Typst.