Mastodon API - reference social.
  • Ada 57.4%
  • Python 39.6%
  • JavaScript 2.4%
  • CSS 0.6%
Find a file
LowEel 5f32e0c662
All checks were successful
continuous-integration/drone/push Build is passing
Fix HTTP date helper for GNAT dependencies and visibility
2026-08-06 23:01:09 +02:00
alire Use Debian GNAT toolchain in Docker builds 2026-08-03 18:50:14 +02:00
doc Define resettling as contact follow refresh 2026-08-02 15:45:19 +02:00
docs
etc Simplify runtime Docker builders 2026-08-03 18:34:58 +02:00
smoketest Fixing fanout with audience 2026-08-05 15:29:30 +02:00
spark Fix HTTP date helper for GNAT dependencies and visibility 2026-08-06 23:01:09 +02:00
src Align signature metadata and strict HTTP-date formatting 2026-08-06 22:34:25 +02:00
static Use single-column profile settings layout 2026-08-03 22:14:45 +02:00
tests
.dockerignore Cache Docker CI dependency layers 2026-08-01 22:37:44 +02:00
.drone.yml Split Dockerfiles by CI role and architecture 2026-08-03 18:15:40 +02:00
.gitignore
alire.toml
DOCKER.md Use Debian GNAT toolchain in Docker builds 2026-08-03 18:50:14 +02:00
Dockerfile.amd64 Use Debian GNAT toolchain in Docker builds 2026-08-03 18:50:14 +02:00
Dockerfile.arm64 Use Debian GNAT toolchain in Docker builds 2026-08-03 18:50:14 +02:00
Dockerfile.spark Isolate SPARK Dockerfile from runtime lock 2026-08-03 19:00:30 +02:00
INSTALL.md
LICENSE.md
README.md Document admin login divergence from snac2 2026-08-03 17:38:27 +02:00
spark_helpers.gpr Fix SPARK profile probe bounds and move invalid-input logging to non-SPARK adapter 2026-08-06 14:32:02 +02:00
xenomorph.gpr Release xenomorph egg 2026-08-02 17:13:01 +02:00

Xenomorph

Xenomorph is a usable ActivityPub server written in Ada.

At this stage it starts as a source-guided port of snac2, especially for the visible interfaces and filesystem behavior. The long-term goal is not to pretend that Ada is C, but to carry the same small-server idea into a codebase with stronger type safety, better modularity, and a maintenance model that fits exposed Internet software.

The short version is: Daddy is Snac.

Why

snac2 is fascinating because it proves that a single-person project can still implement a practical ActivityPub server without turning into a large platform. ActivityPub federation is difficult, and the protocol often feels much more complicated than it needs to be. snac2 approaches that problem with discipline: plain storage, small moving parts, and a bias toward direct, understandable behavior.

Xenomorph exists because that approach deserves an Ada implementation.

This is not a claim that snac2 has specific security problems. It is a different engineering bet: C can be used extremely well by expert programmers, but Internet-facing C services also live close to classes of memory and data handling bugs that Ada is designed to make harder. Xenomorph tries to keep the practical minimalism of snac2 while gaining Ada type and data safety.

Also, it is fun.

Goals

  • Keep the visible behavior close to snac2 while the port is young.
  • Use snac2 as the design map: simple filesystem storage, simple processes, clear HTTP behavior, and as little machinery as possible.
  • Avoid a database. The filesystem is the storage model.
  • Keep configuration transparent and inspectable.
  • Make the project suitable for small Docker deployments.
  • Fit homelab-scale servers, including very small machines and NFS-backed storage.
  • Stay aligned with snac2 development where that makes sense.
  • Eventually let Xenomorph grow its own features once the port has legs.

Current Status

Current version: Xenomorph/egg.

Xenomorph is now usable for real small-instance testing and everyday dogfooding, but it is still hardening and should not yet be treated as a conservative production recommendation.

The project currently has working ActivityPub federation for the implemented S2S flows, filesystem storage, Web UI work, WebFinger and actor output, login/admin scaffolding, and the subset of the Mastodon client API implemented by snac2. Comparative smoke tests exercise Xenomorph and a real snac2 server side by side.

If this sounds interesting, follow the project and expect the feature list and release notes to become useful as the implementation matures.

Implemented So Far

The implemented list is intentionally conservative. It should only describe what exists in the code today.

  • Ada project built with Alire.
  • Filesystem-based server and user storage.
  • User creation with local key material.
  • WebFinger responses for local users.
  • ActivityPub actor endpoint with local profile data.
  • Web login and a Semantic UI client for home, federated and hashtag timelines, notifications, conversations, profiles, people, follow requests, bookmarks, pinned posts, followed hashtags, lists, and search.
  • The Web UI uses locally vendored Atkinson Hyperlegible Mono by default.
  • Web composer and status controls for replies, media, content warnings, polls, scheduling, visibility, language, likes, reposts, bookmarks, pins, edits, deletion, and emoji reactions.
  • Remote media attachments and remote custom emoji caching for inbound S2S posts.
  • Settings UI for Mastodon-compatible profile fields and advanced local settings, including CSV contact-list import and asynchronous resettling.
  • Inbox and shared-inbox request handling.
  • Input, shared input, output, and local user queues.
  • Signed ActivityPub delivery for S2S output.
  • HTTP signature checking for queued inbound S2S messages.
  • Basic S2S handling for Follow, Accept Follow, Undo Follow, Create, Update, Delete, Like, Announce, EmojiReact, Ping/Pong, and Move behavior.
  • Filesystem indexes for timeline objects, replies, likes, announces, emoji reactions, public objects, collected inboxes, blocked instances, failed instances, and public hashtags.
  • snac-style handling for content rejection filters, blocked hashtags, followed hashtag distribution, dropped DMs from unknown actors, and blocked/muted actors.
  • The Mastodon client API subset implemented by snac2, including its OAuth authorization flow.
  • A Debian 12 multi-stage container image and a single-replica Docker Swarm deployment with separate data and configuration mounts.
  • Smoke tests that exercise the implemented HTTP and storage behavior and keep selected responses aligned with snac2.

What It Is Not Yet

  • It is not a complete ActivityPub server.
  • It is not yet a conservative production recommendation for unattended public instances.
  • It does not implement Mastodon's entire API, only the subset implemented by snac2.

Development installation is documented in INSTALL.md. Container and Docker Swarm deployment is documented in DOCKER.md. Container images use the loweel/xenomorph Docker Hub repository as their publication target.

Design Shape

Xenomorph is meant to stay small.

The intended deployment model is a tiny ActivityPub instance for one person or a few users, especially in a homelab. The concrete target environment is Docker on small machines, such as ODROID-class nodes, with storage that can live on NFS. Ada plus Docker should make the executable and runtime environment highly reproducible, while filesystem storage keeps data visible and easy to reason about.

Relationship With snac2

snac2 by grunfink is the reference, inspiration, and credit source for this project. Xenomorph initially follows it as a port for the externally visible interfaces and for many internal storage and queue decisions.

The goal is not to redesign the product while porting it. The goal is to understand what snac2 does, reproduce the behavior in Ada, and then only add new direction once there is a solid foundation.

One intentional divergence is the browser admin login flow. snac2 exposes the admin page through an HTTP Basic authentication challenge; Xenomorph redirects unauthenticated /user/admin browser requests to its OAuth-style Web UI login page and then uses the xenomorph_ui session cookie for the admin shell and Web UI actions. The ActivityPub and Mastodon-compatible API compatibility tests should not assume snac2-style Basic-auth behavior for Xenomorph's Web UI.

License

Xenomorph is intended to be licensed under the European Union Public Licence, using the current version or later: EUPL-1.2-or-later.

Acknowledgements

  • snac2 and grunfink, for the design path and the practical approach this project follows.
  • Braille Institute, for the Atkinson Hyperlegible font family used by the Web UI.
  • OpenAI Codex, for refreshing my memory about Ada. The last time I seriously programmed in Ada, it was still called Ada 95 and ran on SGI machines.

Contact

This is a personal project, and feedback is welcome through the channels below.

  • Email: uriel.fanelli@keinpfusch.net
  • Matrix: @uriel:chat.keinpfusch.net