Skywatch Automod 2.0.0

I had intended for my first post to be something more along the lines of "Reflecting upon 18 months of running Skywatch." Life and work have conspired to keep that post in drafts for now, so we're kicking it off with a big release of the Skywatch Automod tool.

@skywatch.blue/skywatch-automod

A tool for parsing traffic on the jetstream and applying a moderation workstream based on regexp based rules

A quick history of Automod

Automod started as a collection of bash scripts and regular expressions which tracked the Bluesky firehose and automatically labeled or reported certain content. These worked when the site was small, but were unstable and required frequent restart.

Then November 2024 happened and the site's user base exploded. Over the holidays that year, I entered a fugue state (also known as ADHD hyperfocus) and re-wrote the entire tool in TypeScript in about a week.

I should mention that I had to learn TypeScript to do this. Again, ADHD hyperfocus.

Skywatch Automod 1.0.0 was broadly similar in that it monitored the firehose, and applied labels to posts and accounts if they were flagged by certain regular expressions. Labels with high rates of false positives auto-reported content instead.

Skywatch Automod 2.0.0

Skywatch Automod 2.0.0 adds three new big features (well, some of these were released incrementally over the last few days, but I'm counting them towards the major version update), as well as a collection of small bug fixes and improvements. I want to talk a bit about the big features.

Threshold based account labeling

Previously, for situations where we wanted to label an account if said accounts' posts were frequently labeled, we had to set the post label to make reports against the account each time a post met labeling criteria. This cluttered up reports with automated reports that we couldn't always action.

{
labels: [
"alt-tech",
"disinformation-network",
"fringe-media"
],
threshold: 5,
accountLabel: "amplifier",
accountComment: "Account has posted alt-tech content multiple times",
windowDays: 5,
reportAcct: false,
commentAcct: false,
toLabel: true,
},

Now we've automated that. Users can choose the labels they want to monitor posts for, set the account label that is to be applied, and set a threshold count at which the label is applied. Since raw numbers aren't necessarily meaningful, a window in days must be supplied. This window is rolling, and options to report or comment instead of label remain. Underneath, Redis is used to track post labels per account.

Account Age Interaction Monitoring

Site raids, harassment, and astroturfing campaigns often feature new accounts being created to amplify certain content or to harass users. To address this, we've built in the ability to watch for accounts that were created within a certain number of days of a user provided date anchorDate, and automatically label them if they interact with specific accounts or content.

[
// Example: Monitor replies to specific accounts
{
monitoredDIDs: [
"did:plc:example123",
"did:plc:example456",
],
anchorDate: "2025-01-15",
maxAgeDays: 7,
label: "new-account-reply",
comment: "New account replying to monitored user during campaign",
expires: "2025-02-15", // Optional: automatically stop this check after this date
},
Example: Monitor replies to specific posts
{
monitoredPostURIs: [
"at://did:plc:example123/app.bsky.feed.post/abc123",
"at://did:plc:example456/app.bsky.feed.post/def456",
],
anchorDate: "2025-01-15",
maxAgeDays: 7,
label: "brigading-suspect",
comment: "New account replying to specific targeted post",
expires: "2025-02-15",
},
]

You can even set the rule to expire after a certain date!

Facet Abuse

luna (@imlunahey.com)

29 years old - she/her/they/them - 🏳️‍⚧️🏳️‍🌈 bluesky's #1 professional yapper checkout my bluesky client: akari.blue alt: @imlunahey.bsky.social company: @lucidsoft.works message me on signal @ImLunaHey.69

Bluesky user imlunahey.com recently detected a new way in which spammers were manipulating the protocol and network. A user would create a post hundreds of facets. Each facet would contain a reference to app.bsky.richtext.facet#mention, and a unique DID. Critically, each facet would occupy the same index space in the post, that was a single byte long. The result is the ability to tag hundreds of users in a single post, without their handles showing up on the post itself.

We can now detect and automatically label accounts engaging in this sort of abuse.

{
"$type": "app.bsky.richtext.facet",
"features": [
{
"$type": "app.bsky.richtext.facet#mention",
"did": "did:plc:rbkrgfqegcmv4atgmcpejtxp"
}
],
"index": {
"byteEnd": 1,
"byteStart": 0
}
},
{
"$type": "app.bsky.richtext.facet",
"features": [
{
"$type": "app.bsky.richtext.facet#mention",
"did": "did:plc:z6plbxyjv7anjnmypci7xj3x"
}
],
"index": {
"byteEnd": 1,
"byteStart": 0
}

Prometheus Metrics

So this one is mostly just for fun, but if you ever wanted a sense of just how much was being automated, you can go over and take a look!

Label Duplication Prevention

This one is minor, but we've pushed hard at making sure accounts and profiles don't have duplicate labels applied. This is annoying to users of listifications.app, made it harder for us to remove people from lists, and generally ate into bandwidth.

What's next?

For the tool, we have some planned improvements on the horizon—automatic label removal for certain labels, improving the metrics, and some additional cleanup.

We hope to integrate additional tooling as time goes on. For, example, we're building a library of BlueWave slop imagery to train a classifier on. Our goal is to make our users timeline a better place and to create the sort of social media we want to use.

If you've made it this far, thanks for reading! If you use Skywatch, we'd love to hear your feedback on what we're doing and would be grateful if you could take the Skywatch User Survey!

Skywatch Survey

Skywatch thrives on community input and exists to make Bluesky a better place for you. Please complete the short user survey below to help us improve the Skywatch User Experience