- Ada 51.6%
- Python 44.4%
- JavaScript 3.2%
- CSS 0.6%
- Dockerfile 0.2%
| alire | ||
| docs | ||
| etc | ||
| smoketest | ||
| src | ||
| static | ||
| tests | ||
| .dockerignore | ||
| .drone.yml | ||
| .gitignore | ||
| alire.toml | ||
| DOCKER.md | ||
| Dockerfile | ||
| INSTALL.md | ||
| LICENSE.md | ||
| README.md | ||
| xenomorph.gpr | ||
Xenomorph
Xenomorph is a work-in-progress 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
Xenomorph is not ready for production.
The project currently has substantial ActivityPub S2S behavior, 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.
- Web composer and status controls for replies, media, content warnings, polls, scheduling, visibility, language, likes, reposts, bookmarks, pins, edits, deletion, and emoji reactions.
- Settings UI for snac-compatible user fields, including avatar/header-related data.
- 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 ready to federate as a real instance.
- 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.
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.
- 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.
- Email:
uriel.fanelli@keinpfusch.net - Matrix:
@uriel:chat.keinpfusch.net