Draupnir is being supported with a grant from NLnet
Table of Contents
- Good news
- Draupnir's plan
- The goals
- Command system refactor
- Command system library
- Safe Mode
- Protection Configuration Management
- Capability Management
- Release v2.0.0
- Preview effects of policy list subscription
- Work with and Implement feedback from accessibility and security audits
- Approval and disapproval ratings for policies
- Integrated appservice
- Policy server capability
- Room upgrade support
- Long-term improvements to maintenance
- Rationale of abandoned and reworked goals
- Abandoned or reworked goals
- Baseline documentation for Draupnir’s matrix-protection-suite
- Agreement and Disagreement ratings for policies
- Explicit Agreement watch mode for policy lists
- Integrated appservice (multi-tenancy V2)
- Dynamic protection loading
- Timeline introspection (visible events cache)
- Simple participation metric
- Policy expiration and temporary bans
- Internationalisation
Good news
Our application for a grant from NGI Zero Core has been accepted1. The goals of the work are listed below, we don't expect them to change much but if they do then this post will be updated.
Without this grant, development on Draupnir would have ceased and we would only be able to carry out maintenance. I'm not sure what the future of Draupnir would have been within the context of the upcoming 2.0.0 release, but we don't have to worry about that now.
You can find more information about NGI Zero and NLnet here2.
It's also worth mentioning that the European Commission’s Horizon programme seems to have made moves to drop NLnet's NGI programme from future funding. Within the context of Matrix, NGI has helped fund a number of projects, most notably work on matrix's cryptography and Fractal, although I am unable to find a complete list projects or specific details. If you have some clout to spare please find the open letter3. You can also see the Matrix foundation's own response4.
Initiatives like this ending will negatively impact all software for everyone5, not just the open source ecosystems or bubbles we find ourselves in.
Draupnir's plan
Statement
This statement was written at the beginning of 2024, many of the goals have now been achieved and Draupnir's focus now lies in directly supporting Matrix communities.
Important Trust & Safety work within Matrix7 has proceeded slowly over the course of the last 5+ years due to a lack of resources and split focus. Draupnir is built on this legacy, that is inherited from an older sister project called Mjolnir. Draupnir and Mjolnir are both moderation bots that collectively protect an overwhelming majority of Matrix's public facing communities. Both projects have outstanding issues that are blocked by a significant need for a refactoring and rearchitecting of their core concepts. Draupnir has now almost fulfilled this need with an open source library called the matrix-protection-suite. The plan is to complete this work and finally address the pain points for Matrix room moderators with Draupnir, and make it easier for Draupnir’s behaviour to be modified by developers, system administrators, and in some cases room moderators. This will be done with the aim to create less dependence and pressure on the maintainers of Draupnir itself to meet all the differing requirements of Matrix's communities.
Reading the goals
The goals can be implemented in any order, but they're roughly in the order that they will be tackled in.
For an accurate picture of what is being worked on, please see the planning board on GitHub https://github.com/orgs/the-draupnir-project/projects/5.
I will keep the board up to date, and if I have neglected and failed at that, it shouldn't be too difficult to infer from this what the direction currently is. These goals directly map to a planning story or description within Draupnir's planning tracker https://github.com/the-draupnir-project/planning/issues. And we generally will describe any other big pieces of work there.
The goals certainly look ambitious, but there has already been a lot of work in the background over the past year on the matrix-protection-suite. These features were in mind and the code and architecture was designed somewhat explicitly to allow expansion towards these goals.
The Draupnir blog series
The draupnir blog series, starting here, has been superseded by regular project governance reporting, which can be found on the documentation website.
The goals
Command system refactor
The current API for defining commands depends on too much ambient context that makes unit testing commands difficult. The API will be modified so that commands only have access to their direct dependencies and there is a separate layer of glue to provide these dependencies from a generic common context. The direct dependencies can now be faked on a per command basis in unit testing.
Milestones
- The ban, unban, kick, watch, unwatch commands all have unit tests, not integration tests8.
Completion
- Blog update: https://marewolf.me/posts/draupnir/2405.html
- This Week in Matrix: TWIM-2024-09-13
- Pull requests: Story tracker (see list)
- Draupnir release: v2.0.0-beta.6
- Unit tests: Draupnir/test/unit/commands
Command system library
The current command definition system, including the JSX templating system for rendering Matrix messages, is to be made available as a library and npm package.
Milestones
- The command system is released with a distinct GitHub repository and npm package.
Completion
This was completed at the same time as the command system refactor.
- Blog update: https://marewolf.me/posts/draupnir/2405.html
- This Week in Matrix: TWIM-2024-09-13
- Pull requests: Story tracker (see list)
- Draupnir release: v2.0.0-beta.6
- NPM package: @the-draupnir-project/interface-manager
- GitHub: @the-draupnir-project/interface-manager
Safe Mode
Problems with runtime settings can be diagnosed and resolved without external tooling or editing.
Milestones
- New pre-release (2.0.0-beta.*) containing the safe mode feature.
Completion
- Blog update: https://marewolf.me/posts/draupnir/2406.html
- This Week in Matrix: TWIM-2024-10-25 and TWIM-2024-10-04
- Story:
- Draupnir release: v2.0.0-beta.8 (via v2.0.0-beta.7)
Protection Configuration Management
Protection settings can be accessed and modified. Protections can establish subcommands9.
Milestones
- New pre-release (2.0.0-beta.*) containing the configuration management feature.
Completion
- Blog update: https://marewolf.me/posts/draupnir/2407.html
- This Week in Matrix: TWIM-2024-12-20
- Story:
- Draupnir release: v2.0.0-beta.9
- Tutorial: https://the-draupnir-project.github.io/draupnir-documentation/protections/configuring-protections
Capability Management
As a room moderator, I can see the active capability provider for each protection and read about the capability providers that they are compatible with. I should then be able to change the active capability provider for each protection as I see fit.
Milestones
- New pre-release (2.0.0-beta.*) containing the capability management feature.
Completion
This goal is better understood as a stepping stone for the goal to Preview effects of policy list subscription, as simulated capabilities will be required to preview effects. The work does enable protections to use custom capabilities, including the simulated capabilities included for each interface. But there has not been and demonstration of alternative capabilities for protections beyond that yet. It is however relatively straightforward for protections to start to do so.
- Story:
- Releases:
- v2.2.0
- Compatible capability providers are shown in the
!protections showcommand. - The
!draupnir protections capability reset <protection name>command is added to restore the default capabilities for a protection.
- Compatible capability providers are shown in the
- v2.0.0-beta.9
- Active capability provider set is shown in the
!protections showcommand. !draupnir protections capability <protection name> <capability name> <capability provider name>command is introduced to change the active capability providers for a protection.
- Active capability provider set is shown in the
- v2.2.0
Release v2.0.0
Draupnir v2.0.0 https://github.com/the-draupnir-project/planning/issues/17
Milestones
- All issues marked with ‘blocks release’ label are resolved https://github.com/the-draupnir-project/Draupnir/issues?q=is%3Aissue+is%3Aopen+label%3A%22blocks+release%22
- All issues marked with ‘MPS Follow Up’ label are resolved or have a planning issue to resolve them.
- Draupnir v2.0.0 is released.
- Post release bugs are triaged and added to the planning project https://github.com/orgs/the-draupnir-project/projects/5/views/8
Completion
- Blog update: https://marewolf.me/posts/draupnir/25/01.html
- This Week in Matrix: TWIM-2025-01-17, TWIM-2025-01-27, TWIM-2025-02-03
- Planning: [Task] Final v2.0.0-beta feedback integration and bughunt
- Contains a list of all the pull requests and issues that were worked on or re-prioritiesed.
- Draupnir release: v2.2.0 (via v2.1.0, v2.0.2, v2.0.1, v2.0.0, v2.0.0-beta.11, and v2.0.0-beta.10)
- These were all releases focussed on squashing the last major bugs or issues.
- Post release bugs: 2.0.0 Follow up (GitHub label)
- Squashed 'MPS Follow Up' bugs: MPS Follow Up (GitHub label)
- These are bugs that were a priority to fix before the release of 2.0 discovered in the aftermath of the integration of the matrix-protection-suite into Draupnir.
- Squashed 'blocks release' bugs: blocks release (GitHub label)
- These are bugs that were blocking a release discovered in the beta programme or after the integration of the matrix-protection-suite into Draupnir.
Preview effects of policy list subscription
A summary of changes that will be made to Matrix rooms will be presented when watching a list. A prompt is given to confirm or cancel the change. This essentially runs all protections in a dry run mode.
Milestones
- New release (2.*.*) containing the preview effects feature.
Completion
- TWIM: TWIM-2025-11-28
- Planning: https://github.com/the-draupnir-project/planning/issues/2
- Release: v2.8.0
Work with and Implement feedback from accessibility and security audits
Draupnir's accessibility will be audited against WCAG where applicable and Draupnir will receive a security quickscan at some point after the v2.0.0 release.
Completion
Acessibility documentation: https://the-draupnir-project.github.io/draupnir-documentation/contributing/accessibility Accessibility report: https://github.com/user-attachments/files/23337837/HAN.Accessibility.Report.Draupnir.pdf Accessibility report response: https://github.com/the-draupnir-project/Draupnir/issues/997 Security documentation: https://the-draupnir-project.github.io/draupnir-documentation/contributing/security
The security report and response will be published in May, we're waiting on matrix.org to review the report as it may have implications for their projects. There were no significant findings in any case.
Approval and disapproval ratings for policies
This goal is an incorporation of goals "Agreement and Disagreement ratings for policies" and "Explicit agreement watch mode for policy lists" (see Abandoned or reworked goals). The goals are still relevant intact, but we break down the milestones to make them more achievable together.
Draupnir moderators will be able to rate policies in other lists with using a binary agree/disagree rating. Draupnir will ignore policies that have a disagree rating. Policies that conflict while unbanning a user that originate from lists that are not controlled by Draupnir will automatically be rated with disagree. https://github.com/the-draupnir- project/planning/issues/3
A new policy list subscription mode is introduced, which allows a lists policies to be applied lazily. This means policies from a list in this mode are only enforced when a policy also has an agreement rating. Any entities marked by a policy from a list that is being watched by Draupnir in explicit agreement mode that are present within the protected rooms set will cause Draupnir to warn the management room. https://github.com/the-draupnir-project/ planning/issues/4
They both cover very similar features and code paths and in order to break down the milestones we need to merge them together. Specifically Draupnir currently treats all policies as "trusted" in the sense that any policy that propagates all the way to a protection has an identical interface regardless of source. And the most important part of the work for both goals is to make policy handling and propagation secure within Draupnir itself. Trusted policies have to be made to have distinct interface that allows them to be applied by protections. And policies have to be introduced into the system as untrusted and later become authorised. Milestones to be delivered together or individually in a Draupnir release.
- Milestones
- Draupnir's code base is modified to source all policies with an interface that allows them to be rendered by offering a preview. Infrastructure code that performs matching (for the purpose of showing which policies match which members) use a mirror to access a preview of the entity. Downstream protections may still use the legacy interface at this stage.
- A new "trusted" interface is introduced that contains the provenance data for the policy and allows direct access to the entity. Untrusted policies become trusted at the existing watched policy rooms abstraction where provenance data is added (at this stage this will most likely be the "direct propagation" policy room subscription method). Protections are modified to use this interface and the legacy policy interface is removed
- Draupnir can be used to rate policies with "disapprove", this weighs above all other ratings and these policies cannot be made trusted without removing the rating first. Unbanning a user will add "disapproval" ratings to policies sourced from third party lists. Feature is made available in a release of Draupnir.
- Draupnir can be used to rate policies with "approve". An explicit approval policy room watch mode is available as an alternative to direct propagation. Feature is made available in a release of Draupnir.
Integrated appservice
he appservice is adapted to provide close integration to Matrix's Spaces feature. We provide a simple, minimalistic web frontend to the service, described as a community management portal. In effect this frontend is a special matrix client that can automatically provision a Draupnir for a community to protect all of the rooms within a space. The portal eventually can become a one-stop shop for managing a community on matrix. Milestones to be delivered together or individually in a Draupnir release.
- Milestones
- The appservice is adjusted for the service administrator to monitor on-demand provisioning. Specifically the onboarding workflow is adjusted so that administrators can fallback to a manual approval based system AND the infrastructure exists for Draupnir developers to arbitrarily filter provision requests into an awaiting- approval state.
- A minimal frontend is developed whereby the user can authenticate using their matrix account and provision a Draupnir from a pre-configured Draupnir service backend. This simply provisions an existing Draupnir for a given Matrix space, with no additional onboarding steps.
- The frontend is adapted to provide automatic protection of an entire Matrix space and assignment of appropriate power level for the Draupnir service account.
- Draupnir and the frontend are modified so that it is possible to automatically propagate room level bans to a policy list
- A migration pathway exists for draupnir deployed without a dedicated homeserver can switch to the appservice version. This is important as draupnir without dedicated deployments will be unable to use policy server capability
Policy server capability
Giving Draupnir policy server capability would allow Draupnir to augment the Matrix room model's access control system proactively https://matrix.org/blog/2025/04/introducing-policy-servers/
- Milestones
- The capability for Draupnir to simply respond to the policy server
/signendpoint is developed for Draupnir, either through a deployable proxy or through Draupnir itself. This allows for Draupnir deployed with dedicated homeserver or the appservice to make use of the policy server. To be delivered within a Draupnir release or a dedicated project release. - Draupnir provides an internal API to protections similar to the synapse-http-antispam api that would allow a policy-server proxy to forward events to Draupnir. These events are then passed through to protections running in relevant rooms. This includes pass-through to distinct draupnir deployed via the appservice. This is not expected to be deployable
- Draupnir is able to communicate directly to room participants that are currently being sanctioned by protections at the policy server level. This feature should provide a be generic way for Draupnir to communicate with users, for instance to share updates to the communities code of conduct and is expected to be one way. The most likely way this will be implemented is as a readonly direct message chat that the user cannot reply to. Feature to be delivered within a Draupnir release.
- The capability for Draupnir to simply respond to the policy server
Room upgrade support
- Draupnir can list all of the rooms that are out of date within a community
- Draupnir can upgrade individual rooms https://github.com/the-draupnir-project/planning/issues/45 (note acceptance criteria may be updated before work begins.
- Draupnir can upgrade all eligible protected rooms as part of one process.
- Draupnir can follow policy room upgrades from watched policy rooms.
- Draupnir can upgrade policy rooms.
Long-term improvements to maintenance
Draupnir has accumulated a number of small tasks that need to be carried out for the long term health of the project and to reduce complexity for new contributors.
- Milestones
- Contributor onboarding. A tutorial exists for creating a new protection that does something simple, it doesn't have to protect the room, it could equally be a welcome of FAQ bot. The tutorial covers how to find relevant protection handles and includes a skeleton protection
- Migrate npm packages under @the-draupnir-project scope from yarn classic (1.x) to npm.
- Consolidate as many of our TypeScript repositories into a single mono repository as feasible
Rationale of abandoned and reworked goals
Objectives of the rework
It has become evident that the project should now pursue the following objectives as a priority:
- Better onboarding / service architecture for communities that do not have a systems admin or infrastructure of their own
- Some kind of web frontend for setting up Draupnir for a new or existing Matrix community. This would be as simple as possible (which can be a base to later can be extended to do more tasks, although not a priority).
- In the wake of the Matrix foundation's project hydra security disclosure, specific tooling within Draupnir to support matrix room upgrades may be required.
- Focus on what we are confident we can and want to complete before May. Drop anything out of scope.
Commentary on significantly reworked or abandoned goals
Timeline introspection (visible events cache)
This goal was designed specifically because the Matrix room model required Draupnir to play "catch up" with abuse. It could only react to what has already happened. Since April this year a proposal has been developed that would allow Draupnir to effectively dynamically augment the access control system of the matrix room model. This proposal is called "Policy Servers" https://matrix.org/blog/2025/04/introducing-policy-servers/.
The resources from this goal should really be catered to implementing and providing policy server capability for draupnir so that we can proactively manage events via a policy server rather than retroactively react with the timeline cache.
Simple participation metric
This is the ultimate jackpot for the project. Especially when combined with policy server capability. https://github.com/the-draupnir-project/planning/issues/2,%C2%A0https://marewolf.me/posts/draupnir/25/02.html#priorities-a-focus-on-on-boarding-users (written before policy servers were proposed). We have done some exploratory development work here but it is clear to me that we need to spend some time thinking about how Draupnir deals with persistent storage (which for the most part, so far we have managed to evade thinking about with all together).
Unfortunately without some thought and a conclusive decision about persistent storage for the project in general, progress cannot currently be made here without significant technical debt. Exploration here at this stage is particularly risky and uncertain at this stage, and so is not a priority. However, the discussion for how to solve the associated problems is ongoing.
Abandoned or reworked goals
The original goals were written at the very start of 2024. By the end of 2025 naturally some of the goals had changed or needed refining. These goals are listed below
Baseline documentation for Draupnir’s matrix-protection-suite
Conceptual documentation exists to explain policy rooms, policy lists, revisions, protections, capabilities and protected rooms sets.
- Milestones
- Conceptual documentation is available to read and linked from matrix-protection-suite’s README.
- A how to guide exists for scanning timeline events.
- A how to guide exists for scanning new members.
- A tutorial exists for creating a new protection that does something simple, it doesn't have to protect the room, it could equally be a welcome or FAQ bot.
Agreement and Disagreement ratings for policies
Draupnir moderators will be able to rate policies in other lists with using a binary agree/disagree rating. Draupnir will ignore policies that have a disagree rating. Policies that conflict while unbanning a user that originate from lists that are not controlled by Draupnir will automatically be rated with disagree.
Explicit Agreement watch mode for policy lists
A new policy list subscription mode is introduced, which allows a lists policies to be applied lazily. This means policies from a list in this mode are only enforced when a policy also has an agreement rating. Any entities marked by a policy from a list that is being watched by Draupnir in explicit agreement mode that are present within the protected rooms set will cause Draupnir to warn the management room.
Integrated appservice (multi-tenancy V2)
The appservice is redesigned such that Draupnir operates much more closely to the homeserver, providing an almost transparent integration to Matrix’s Spaces feature. When users create spaces or add rooms to them, the appservice automatically provisions a Draupnir for the space and protects all of the rooms, without any manual intervention.
Dynamic protection loading
Allow protections defined externally to be loaded at startup from an arbitrary directory. Which will allow standalone protections to be developed and maintained for Draupnir by third parties without conflicting with the upstream.
Timeline introspection (visible events cache)
When searching for events from a given user, Draupnir has to call /messages in every single protected room. This is a very expensive operation, and on homeservers with less resources can prevent Draupnir from redacting harmful messages when the operation takes too long. A timeline cache of visible events would allow Draupnir and protections to cheaply scan and locate events matching arbitrary criteria. We also need an API to be able to extract all media that has been included within an event so that it can be accessed by protections.
Simple participation metric
Draupnir and MPS have no standard way of determining how long a user has been participating in a community. Draupnir’s protections each have an adhoc way of doing this and then discriminating against newer users without considering all of the rooms in the entire community (leading to false positives). A metric needs to be derived representing how likely a moderator is likely to have observed a user’s behaviour, probably from participation.
Policy expiration and temporary bans
There are many reasons why policies may no longer be relevant. A room moderator often issues bans in the heat of the moment or when tensions are high. Things can change. There may no longer be any context for why a ban is in place. As a room moderator I should be notified when policies expire or are approaching expiry and be given options for how to proceed.
Internationalisation
Draupnir is made ready for internationalisation by translators.
Footnotes:
On a personal note, I did not expect this application to be successful and it hasn't really set in yet. Trying not to think about it too hard, I'm just going to focus on delivering. It took about 5-6 months to get through the process, which was pretty smooth, the limiting factor was time if anything. Of course waiting that long with uncertainty is not great and I wish I had managed myself better.
Honestly I'm confused about what and how I'm supposed to refer to them if you can't tell. I'm pretty sure it's just "NGI Zero" but idk.
I don't really know who wrote this or the context or how to write this properly, but it's more important that you just see it.
The consequences people focus on are usually immediate, like the the open source ecosystem as a whole becoming weaker. Maybe you will even go as far to worry about how software development is tilting towards some kind of gig/grift economy. But what I worry about is how taking software for granted will change how software is produced structurally from the ground up. And that's important, because I get the feeling that the way people program is a reflection of how they think. If the essentials become "corrupted", such as programming languages and environments. Then this means we end up unable to express ourselves properly6. To an extent, this has already happened, and it is exactly why programming is currently so terrible.
I don't mean expression like, some funky lisper writing a tonne of macros, or something like that. I mean more that structurally programming itself becomes tilted to serve the needs of corporations, to sell products. Rather than the needs of people who can be helped by software.
If you are unfamiliar with what Matrix is, it is an open source instant messaging protocol that was created in 2014. See https://matrix.org
Integration tests will still exist, the point is that we want it to to be a lot easier to create tests for commands. Please see https://marewolf.me/posts/draupnir/2402.html#development-testing-commands.
We broke this at some point either during the original command refactor back in 2023 or during the migration to MPS.