Application services are passive and can only observe events from
homeserver. They can inject events into rooms they are participating in.
They cannot prevent events from being sent, nor can they modify the
content of the event being sent. In order to observe events from a
homeserver, the homeserver needs to be configured to pass certain types
of traffic to the application service. This is achieved by manually
configuring the homeserver with information about the application
service.
### Registration
Note
Previously, application services could register with a homeserver via
HTTP APIs. This was removed as it was seen as a security risk. A
compromised application service could re-register for a global `*` regex
and sniff *all* traffic on the homeserver. To protect against this,
application services now have to register via configuration files which
are linked to the homeserver configuration file. The addition of
configuration files allows homeserver admins to sanity check the
registration for suspicious regex strings.
Application services register "namespaces" of user IDs, room aliases and
room IDs. These namespaces are represented as regular expressions. An
application service is said to be "interested" in a given event if one
of the IDs in the event match the regular expression provided by the
application service, such as the room having an alias or ID in the
relevant namespaces. Similarly, the application service is said to be
interested in a given event if one of the application service's
namespaced users is the target of the event, or is a joined member of
the room where the event occurred.
An application service can also state whether they should be the only
ones who can manage a specified namespace. This is referred to as an
"exclusive" namespace. An exclusive namespace prevents humans and other
application services from creating/deleting entities in that namespace.
Typically, exclusive namespaces are used when the rooms represent real
rooms on another service (e.g. IRC). Non-exclusive namespaces are used
when the application service is merely augmenting the room itself (e.g.
providing logging or searching facilities). Namespaces are represented
by POSIX extended regular expressions and look like:
users:
- exclusive: true
regex: "@_irc_bridge_.*"
Application services may define the following namespaces (with none
being explicitly required):
<table>
<colgroup>
<colstyle="width: 24%"/>
<colstyle="width: 75%"/>
</colgroup>
<thead>
<trclass="header">
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td>users</td>
<td>Events which are sent from certain users.</td>
</tr>
<trclass="even">
<td>aliases</td>
<td>Events which are sent in rooms with certain room aliases.</td>
</tr>
<trclass="odd">
<td>rooms</td>
<td>Events which are sent in rooms with certain room IDs.</td>
</tr>
</tbody>
</table>
Each individual namespace MUST declare the following fields:
<table>
<colgroup>
<colstyle="width: 12%"/>
<colstyle="width: 87%"/>
</colgroup>
<thead>
<trclass="header">
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td>exclusive</td>
<td><strong>Required</strong> A true or false value stating whether this application service has exclusive access to events within this namespace.</td>
</tr>
<trclass="even">
<td>regex</td>
<td><strong>Required</strong> A regular expression defining which values this namespace includes.</td>
</tr>
</tbody>
</table>
Exclusive user and alias namespaces should begin with an underscore
after the sigil to avoid collisions with other users on the homeserver.
Application services should additionally attempt to identify the service
they represent in the reserved namespace. For example, `@_irc_.*` would
be a good namespace to register for an application service which deals
with IRC.
The registration is represented by a series of key-value pairs, which
this specification will present as YAML. See below for the possible
options along with their explanation:
<table>
<colgroup>
<colstyle="width: 11%"/>
<colstyle="width: 88%"/>
</colgroup>
<thead>
<trclass="header">
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td>id</td>
<td><strong>Required.</strong> A unique, user-defined ID of the application service which will never change.</td>
</tr>
<trclass="even">
<td>url</td>
<td><strong>Required.</strong> The URL for the application service. May include a path after the domain name. Optionally set to <code>null</code> if no traffic is required.</td>
</tr>
<trclass="odd">
<td>as_token</td>
<td><strong>Required.</strong> A unique token for application services to use to authenticate requests to Homeservers.</td>
</tr>
<trclass="even">
<td>hs_token</td>
<td><strong>Required.</strong> A unique token for Homeservers to use to authenticate requests to application services.</td>
</tr>
<trclass="odd">
<td>sender_localpart</td>
<td><strong>Required.</strong> The localpart of the user associated with the application service.</td>
</tr>
<trclass="even">
<td>namespaces</td>
<td><strong>Required.</strong> A list of <code>users</code>, <code>aliases</code> and <code>rooms</code> namespaces that the application service controls.</td>
</tr>
<trclass="odd">
<td>rate_limited</td>
<td>Whether requests from masqueraded users are rate-limited. The sender is excluded.</td>
</tr>
<trclass="even">
<td>protocols</td>
<td>The external protocols which the application service provides (e.g. IRC).</td>
</tr>
</tbody>
</table>
An example registration file for an IRC-bridging application service is
**Note:** All labels are to be placed on the proposal PR.
<table>
<thead>
<trclass="header">
<th>Name</th>
<th>GitHub Label</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td>Proposal Drafting and Feedback</td>
<td>N/A</td>
<td>A proposal document which is still work-in-progress but is being shared to incorporate feedback. Please prefix your proposal's title with <code>[WIP]</code> to make it easier for reviewers to skim their notifications list.</td>
</tr>
<trclass="even">
<td>Proposal In Review</td>
<td>proposal-in-review</td>
<td>A proposal document which is now ready and waiting for review by the Spec Core Team and community</td>
</tr>
<trclass="odd">
<td>Proposed Final Comment Period</td>
<td>proposed-final-comment-period</td>
<td>Currently awaiting signoff of a 75% majority of team members in order to enter the final comment period</td>
</tr>
<trclass="even">
<td>Final Comment Period</td>
<td>final-comment-period</td>
<td>A proposal document which has reached final comment period either for merge, closure or postponement</td>
</tr>
<trclass="odd">
<td>Final Comment Period Complete</td>
<td>finished-final-comment-period</td>
<td>The final comment period has been completed. Waiting for a demonstration implementation</td>
</tr>
<trclass="even">
<td>Spec PR Missing</td>
<td>spec-pr-missing</td>
<td>The proposal has been agreed, and proven with a demonstration implementation. Waiting for a PR against the Spec</td>
</tr>
<trclass="odd">
<td>Spec PR In Review</td>
<td>spec-pr-in-review</td>
<td>The spec PR has been written, and is currently under review</td>
</tr>
<trclass="even">
<td>Spec PR Merged</td>
<td>merged</td>
<td>A proposal with a sufficient working implementation and whose Spec PR has been merged!</td>
</tr>
<trclass="odd">
<td><p>Postponed</p></td>
<td><p>proposal-postponed</p></td>
<td><p>A proposal that is temporarily blocked or a feature that may not be useful currently but perhaps sometime in the future</p></td>
</tr>
<trclass="even">
<td>Closed</td>
<td>proposal-closed</td>
<td>A proposal which has been reviewed and deemed unsuitable for acceptance</td>
</tr>
<trclass="odd">
<td>Obsolete</td>
<td>obsolete</td>
<td>A proposal which has been made obsolete by another proposal or decision elsewhere.</td>
</tr>
</tbody>
</table>
# Categories
We use category labels on MSCs to place them into a track of work. The
Spec Core Team decides which of the tracks they are focusing on for the
next while and generally makes an effort to pull MSCs out of that
category when possible.
The current categories are:
<table>
<thead>
<trclass="header">
<th>Name</th>
<th>GitHub Label</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td>Core</td>
<td>kind:core</td>
<td>Important for the protocol's success.</td>
</tr>
<trclass="even">
<td>Feature</td>
<td>kind:feature</td>
<td>Nice to have additions to the spec.</td>
</tr>
<trclass="odd">
<td>Maintenance</td>
<td>kind:maintenance</td>
<td>Fixes or clarifies existing spec.</td>
</tr>
</tbody>
</table>
Some examples of core MSCs would be aggregations, cross-signing, and
groups/communities. These are the sorts of things that if not
implemented could cause the protocol to fail or become second-class.
Features would be areas like enhanced media APIs, new transports, and
bookmarks in comparison. Finally, maintenance MSCs would include
improving error codes, clarifying what is required of an API, and adding
properties to an API which makes it easier to use.
The Spec Core Team assigns a category to each MSC based on the
descriptions above. This can mean that new MSCs get categorized into an
area the team isn't focused on, though that can always change as
priorities evolve. We still encourage that MSCs be opened, even if not
the focus for the time being, as they can still make progress and even
be merged without the Spec Core Team focusing on them specifically.
# Implementing a proposal
As part of the proposal process the spec core team will require evidence
of the MSC working in order for it to move into FCP. This can usually be
a branch/pull request to whichever implementation of choice that proves
the MSC works in practice, though in some cases the MSC itself will be
small enough to be considered proven. Where it's unclear if an MSC will