Draft: Amalgam Specification
Amalgam, version 0.1
This document defines the Amalgam social-media ecosystem. It is defined as a non-Bluesky profile of the Authenticated Transfer Protocol (AT Protocol, or ATProto). As such, it directly inherits the following traits from AT Protocol:
- Personal data servers (PDSes). Amalgam PDSes are expected to be fully-compatible ATProto PDSes, including support for repositories and accounts.
- DID-based identification and the associated repository cryptography.
- The
atproto-proxyheader and its associated inter-service token. - XRPC and Lexicons.
The following sections detail changes, including but not limited to:
- The NSID
placeholder.amalgam.deliverActivity, which is for an XRPC procedure which accepts an Activity. - The NSID
placeholder.amalgam.handleActivity, which is for an XRPC procedure triggered by remote servers with an Activity that should be handled. - The NSID
placeholder.amalgam.object, which is for a repo collection and record type representing an Object in storage, in crawling, and in Activities. - Object representations of ActivityStreams2 and ActivityPub Activities.
- The NSID
placeholder.amalgam.resolveDelegatedHandle, which is an XRPC query that resolves a delegated handle, also known as a sub-handle. - The NSID
placeholder.amalgam.relay.publishRecord, which is an XRPC procedure that instructs a relay to publish the current state of a single record. - The NSID
placeholder.amalgam.relay.publishRecords, which is an XRPC procedure that instructs a relay to publish the current state of multiple records.
Ecosystem Roles
The following ecosystem roles are defined with Amalgam. Others may exist that are not defined here, and which may overlap partially with some functions of these roles.
An AppView is a server which handles conveniences, collecting posts from the user's follows, disseminating Activities that the user publishes, counting likes, and approving followers.
A personal data server, or PDS, is a server which handles the user's personal data. It is fully compatible with ATProto, to allow for re-use of PDS server software and even existing PDSes and repositories.
A search provider is a server which indexes the network and allows users to search it. Sometimes, the AppView also fills this role.
A feed generator or feed provider is a server which indexes discoverable posts from the network and creates "feeds" of posts from them, which the user can browse. This role is inherited from the Bluesky profile of ATProto.
A labeler or moderation service is a server which applies "labels" to posts (records) and repos. These follow the ATProto Labels specification.
A relay crawls or is told by AppViews about posts and publishes them in a firehose format. Labelers and feed generators, as well as Bluesky AppViews, often use this to index posts. Amalgam encourages relays to not use a "bootstrapping" mechanism, instead allowing for individual AppViews or users to opt-in to it. Further, Amalgam encourages relays to only re-publish "public" or "discoverable" data, or data which was once designated as "public" or "discoverable," particularly to change the visibility.
Federation model
Bluesky's profile of ATProto relies on a fundamentally centralized "federation" model: all posts must go through a relay to be effectively published. The AppView is also expected to accumulate a lot of information for every user on the network. While it has its practical advantages, it is financially unsustainable, and prohibitive for smaller entrants into the network.
Amalgam takes Christine Webber's advice and makes ATProto function more like ActivityPub. Here's our message-passing federation model. Look familiar?
- Client interacts with an AppView (
deliverActivityor a more specialized API). - The AppView figures out who a given Activity should be sent to, and tries to send it to each of them using a token-authenticated
handleActivityprocedure. - Each receiving server files it away, notifies its users, or discards it depending on its relevance.
handleActivity inter-server token
It can't be the same as the one used for atproto-proxy, it may need to be longer-lived. It shall consist of the SHA-256 hash of the CBOR content , which shall be signed with the sending server's key as noted in the user's DID document. This is to be used as a bearer token; that is, it follows Authorization: Bearer .
The server key, which MAY differ between users on the same server, SHALL be cached for some time on the receiving server. It SHOULD be kept for longer, ideally permanently, if the receiving server has a user following the sending user. Note: these keys MAY differ between users on the same server, and any given user MAY be associated with multiple Amalgam AppViews. While it may not be necessary to do so, you MAY go ahead and cache all of that users' keys. In storage, they should be keyed by both destination server (i.e. domain) and user.
Delegated handle (sub-handle) resolution
The resolveDelegatedHandle query resolves a "delegated handle," which in Amalgam is a handle of the form @username@domain.tld. In an AT URI, a delegated handle appears with the form at://username@domain.tld. It's called "delegated" because it is based on the identity registered for domain.tld, and they have given username access to use the domain. This is easier to configure than a domain, and it is useful to semantically separate people at an organization (i.e. @mary@contoso.com) from the organization itself or its projects (i.e. @nytimes.com or @dept.college.edu).
A delegated handle consists of a username and a domain. In the first example, the username is "username", and the domain is "domain.tld".
To resolve such a handle:
- Acquire the handle. You've probably already done that.
- Use the ATProto handle specification to look up the DID document for the domain part.
- Look for a service of type
AmalgamHandleDelegator. Append/xrpc/placeholder.amalgam.resolveDelegatedHandleto theserviceEndpoint. Fill out and send the query according to its Lexicon. - Look up the DID document for the given DID, if there is any, or handle any errors.
This is an optional feature that may not always be supported. If the endpoint fails to return a DID, or if the DID does not map to the handle being requested, the handle is invalid.
Amalgam does not currently specify any way to request or acquire such a handle.
Delivery rules
When an AppView is delivering an Activity (deliverActivity or another API):
- The Activity MUST be in DAG-CBOR and, after necessary modifications are made, signed by the key specified in the sending user's DID document for the sending server.
- It MUST be delivered to every user (specified by repo AT URI) in the "to" and "cc" fields, by delivering it to their server
- It MUST also be delivered to every user (specified by repo AT URI) in the "bcc" field.
- The "bcc" field, if present, MUST be stripped before delivery. It MAY be saved for the sending user to reference later, but it MUST NOT be visible to anyone else. Note: receiving AppViews may simply dismiss Activities which do not concern them.
- If there is no "to", the Activity MUST NOT be sent, and an appropriate error message SHOULD be returned to the user's client.
- If there is no "from", it MUST be added before signing.
- The target Object(s) being referenced, if the Activity is public, SHOULD already exist (or, for Delete, MUST no longer exist) in the appropriate repositories, and MUST be valid Objects of their base Types. (For example, a Create activity MUST NOT reference a record outside of its sender's repository.)
- Notable exceptions to this rule include Deletes (which MUST no longer exist), Likes, Follows, Follow responses, and other Activities which ought to remain ephemeral.
- The target Object(s) SHOULD be included in the Activity when it is being sent, and they MUST match the actual Object record. It is the AppView's responsibility to fill in and correct the data. Notable exceptions are for Likes, follow requests, follow request responses, deletions,
- Failures to deliver to certain users MUST be mentioned, but MUST NOT inhibit delivery to other users (UNLESS the reason for failure is on the sender's side, such as a network failure, if and only if this can be determined).
- Any additional delivery instructions for a Type of Activity or Object MUST also be followed.
NOTE: Some to/cc/bcc addresses MAY not point to a repository, but instead they may point to an ActivityPub Actor or inbox, or to a record which may specify a group.
When an AppView receives an Activity (handleActivity):
- If no-one associated with the AppView follows the sender, the message SHOULD be discarded or filed into a public feed. After this, the below rules SHOULD NOT apply -- consider carefully each rule you decide to continue processing! This is a known spam vector in the Fediverse!
- If the Activity is addressed (in "to" or "cc") to more than some threshold (such as 15) recipients total, all relevant notifications SHOULD be silent or simply not sent. In fact, these Activities MAY be dropped entirely! At least, the rule(s) below about the "discoverable" token SHOULD NOT be applied.
- Rate limits should apply, and they should be much stricter when no user on the server follows the sending user (or any user associated with the sending server).
- If the Activity is addressed "to" the "discoverable" token, the Activity SHOULD be put into an appropriate "global" or "discovery" feed. It MAY then be sent to a relay.
- If the Activity is addressed "to" an associated user, whether or not that user follows the sender, they SHOULD be notified or alerted of the Object or Activity.
- Users MUST never be notified of Deletes.
- If the Activity is a follow request, the AppView MAY automatically deliver an Accept in response, BUT ONLY IF the user has requested it (or otherwise fully expects it) to do so.
- Any additional handling or re-delivery instructions for a Type of Activity or Object MUST also be followed.
STILL more to do...
Discussion in the ATmosphere