Skip to content

Community moderation

fedi-report-triage

Reads the open reports on a Mastodon server with a moderator's own read-only token and prints them as a queue sorted by severity. It never acts on a report.

Kind
Open-source tool
Language
JavaScript
License
MIT
Status
First release
  • cli
  • fediverse
  • jev
  • mastodon
  • moderation
  • trust-and-safety
  • typesafe

Newest first is not most urgent first

Mastodon lists open reports newest first, and nothing in that list says which one is a threat and which one is a disagreement someone reported out of spite. A moderator opens every report to find out, and an urgent report can sit below a dozen newer ones. A keyword list cannot tell a threat from a joke. fedi-report-triage reads the open reports and prints them as a queue sorted by severity, with the kind of problem each one shows and whether the reporter's comment matches the reported posts.

Read-only, always

It sends one kind of request to Mastodon: GET /api/v1/admin/reports. It has no code to resolve, assign or reopen a report, to warn, limit, suspend or silence an account, or to delete a post. A token with only the admin:read:reports scope is all it needs, and such a token cannot change anything, even by mistake. Every decision stays with the moderator, in Mastodon's own interface, from the report link the tool prints.

The reporter's words cannot raise the severity

Jev, TypeSafe AI's System One model, answers typed questions with probabilities and writes no text. Each report gets up to two requests, each with its own state.

The first holds the reported posts alone and asks which kind of problem they show (spam, harassment, hate, illegal content, misinformation, not a violation, or other) and how much harm they can do if they stay up, on four levels from no harm to urgent. The levels describe situations: "urgent" covers threats of violence, a home address, encouraging self-harm, sexual content involving minors and terrorist propaganda. The second request adds the reporter's comment and asks one yes or no question: do the posts show what the comment says about them?

Because the category and the severity are judged on the posts alone, a comment that calls an ordinary post "illegal" cannot raise its severity; it shows up as a comment that does not match. Each report is its own state, so spam written to steer a model in one report cannot change the answers about another.

A report goes to the queue when every answer reached the threshold (0.8 by default) and Jev saw the whole report. Everything else goes to a review list: an answer below the threshold, a post with images or video (Jev reads text only, so it sees their descriptions at most), followers-only posts or direct messages that were not sent, or nothing to send at all. What Jev did not see can only make a report worse, so a report it confidently rates urgent stays at the top even when it has media.

What leaves your server, and what does not

To TypeSafe go the text of the reported posts (up to 3,000 characters each, with content warnings, media descriptions and poll options), and the reporter's comment in the second request only. Followers-only posts and direct messages go only with --include-private. Never sent: account names and handles, email and IP addresses, who reported what, report and post IDs, dates, links to the posts, and your Mastodon token. Reports hold other people's words and sometimes personal data, so check your server's privacy policy and the law that applies to you before running it on real reports.

Limits

  • Jev reads text only, so a report whose problem is in its media goes to review unless the text alone is urgent.
  • It judges the attached posts, not the reported account's profile or its other posts, so a report about impersonation with no posts attached goes to review with nothing sent.
  • The categories and levels are Jev's reading against fixed descriptions, not your server's rules. Compare a sample with your own decisions before you trust a threshold.
  • Text written to steer a model, common in spam, can move Jev's answers, and Jev is most accurate in English.
  • One run reads at most 1,000 open reports, newest first.
  • It was written against Mastodon's admin API as documented for Mastodon 4.x and tested with synthetic answers in that format; other server software that copies the API has not been tried. The example report in the repository uses a made-up server and hand-written probabilities.

Install and run

It needs Node.js 20 or later and has no dependencies. Create the token in Mastodon under Preferences, Development, New application, with every scope unticked except admin:read:reports; your account needs a role with the Manage Reports permission.

npm install -g github:hamzaahmadaslam/fedi-report-triage
export MASTODON_TOKEN=<your-access-token>
export TYPESAFE_API_KEY=<your-key>
fedi-report-triage https://mastodon.example --dry-run

The exit code is 1 when at least one report is confidently urgent, so a scheduled job can alert the moderators.

Related