惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Hacker News
The Hacker News
Martin Fowler
Martin Fowler
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
F
Full Disclosure
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recorded Future
Recorded Future
Security Archives - TechRepublic
Security Archives - TechRepublic
阮一峰的网络日志
阮一峰的网络日志
T
Threatpost
P
Privacy International News Feed
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
I
Intezer
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Privacy & Cybersecurity Law Blog
A
Arctic Wolf
博客园 - 聂微东
博客园 - 叶小钗
Cisco Talos Blog
Cisco Talos Blog
H
Help Net Security
S
Schneier on Security
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Exploit Database - CXSecurity.com
T
Tor Project blog
月光博客
月光博客
NISL@THU
NISL@THU
A
About on SuperTechFans
Spread Privacy
Spread Privacy
Blog — PlanetScale
Blog — PlanetScale
D
DataBreaches.Net
雷峰网
雷峰网
C
CXSECURITY Database RSS Feed - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 【当耐特】
G
Google Developers Blog
W
WeLiveSecurity
P
Palo Alto Networks Blog
The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
博客园 - 司徒正美
L
LINUX DO - 热门话题
小众软件
小众软件

Discord Blog

Making It Easier Than Ever to Connect with Friends in League & VAL! Every Voice and Video Call on Discord Is Now End-to-End Encrypted How to Link Discord to Battlefield 6, Marvel Rivals & More Official Discord Integrations for Steal a Brainrot, Grow a Garden, Brookhaven RP, and more Celebrate Discord’s 11th Birthday with an Exclusive Set of Emoji and Wallpapers Nitro Now Comes with Xbox Game Pass and New Benefits. Welcome to Nitro Rewards. How to Use Nitro: A Beginner’s Guide to Discord’s Premium Subscription Stock Up in the New Rust Shop! Enjoy a Discord-Only 20% Sale on Most Items until 5/21 How Discord Automates ScyllaDB Clusters at Scale Discord Patch Notes: May 4, 2026 You’ve Got (Too Much) Mail: Behind the Scenes of the 3/25/26 Voice Outage Measure Less to Learn More: Using Fewer, Higher-quality Metrics to Capture What Matters Discord Patch Notes: April 6, 2026 MULTIPLAYER SEQUEL TO ACCLAIMED AAAA GAME “THE LAST MEADOW” ANNOUNCED: PLAYABLE NOW Making Discord on Desktop Look Just Right: Display Settings to Ease the Eyes Discord Patch Notes: December 8, 2025 Building on the Social Layer of Games: What’s New from GDC 2026 Gift Ideas for the Dedicated Discord User in Your Life Discord Update: November 6, 2025 Changelog During October, Treat a Friend to Nitro and Trick Out Your Profile for Halloween 🎃 Discord Social SDK Updates & Integrations Go Beyond, Plus Ultra! with the My Hero Academia Collection STAR WARS™ Makes Its Way to Discord Worthy of a Plaque: Nameplates Land in the Shop Announcing Discord’s Social SDK, Helping Power Your Game’s Social Experiences A Cornucopia of Updates Make Discord on Desktop Fresher Than a Crisp Fall Breeze Starting Your First Discord Server Transforming Game Discovery with Instant Play Experiences on Discord Introducing the Discord for Business Newsletter, Vol. 1 Discord Update: March 24, 2026 Changelog Discord Update: December 19, 2024 Changelog How Multi-Factor Authentication Helps Keep Your Discord Account Safe How ROOST is Advancing Online Safety You’re Now Discord Official: Developers, Claim Your Game and Verify Your Server Discord Patch Notes: March 6, 2026 Tracing Discord's Elixir Systems (Without Melting Everything) Getting Global Age Assurance Right: What We Got Wrong and What's Changing Discord Patch Notes: February 4, 2026 How to Change Your Theme to Bring Your Vibe to Discord Your Discord Checkpoint is Rolling Out! Celebrate What You Did in 2025 How to Customize Your Discord Profile How to Make and Use Custom Emoji on Discord Save and Display Your Faves: Add Discord Shop & Marvel Rivals Items to Your Profile’s Wishlist Discord Patch Notes: November 4, 2025 Bringing In-Game Commerce to Discord Communities Reward Your Play: Complete Quests. Earn Orbs. Get Sweet Stuff. How to Share What You’re Playing, Listening to, or Watching as Your Status on Discord Staff Picks, September 2025: Welcome to Our Video Game Museum From Single-Node to Multi-GPU Clusters: How Discord Made Distributed Compute Easy for ML Engineers Discord Patch Notes: October 7, 2025 Discord Update: September 25, 2025 Changelog New Looks for Nitro, New Looks for You. Get Yourself a Nitro-exclusive Profile Bundle! Discord Patch Notes: September 3, 2025 Bringing DAVE to All Discord Platforms Discord’s Powerful Cross-Platform Chat: Ready for Your Game Introducing the Community Server Cleanup Report for August 2025 Discord for Business Vol. 2: Cannes-worthy ad product updates Discord Patch Notes: August 4, 2025 ROOST Announces “Coop” and “Osprey”: Free, Open-Source Trust and Safety Infrastructure for the AI Era *FLAILS AROUND* SUMMER SPECIAL! JOIN NITRO, GET AN EXTRA MONTH OF NITRO ON US! Get More From Your Boosts With New Server Perks Discord Patch Notes: July 7, 2025 Discord Update: June 30, 2025 Changelog Authenticity Matters: Discord's Pride Month 2025 Staff Picks, June 2025: Summer of Showcases How to Set Up Your Server’s Roles for Members, Mods & Admins Gift Nitro and Earn A Flavorful Splash for your Avatar Discord Patch Notes: June 3, 2025 How to Use the Discord Soundboard & Add More Sounds Checkpoint 3: Leveling Up Discord Quests with Orbs and Advanced Measurement Thank You for Ten Years Staff Picks, May 2025: The Games That Brought Us to Discord Discord Patch Notes: May 1, 2025 How Discord Indexes Trillions of Messages Passing the Torch Discord Appoints Humam Sakhnini as Chief Executive Officer Staff Picks, April 2025: All The Adaptations Make More Closet Space! Nitro Members Can Now Keep Avatar Decoration Quest Rewards for Longer How to Use Discord’s In-Game Overlay to Talk While Playing on PC The Game Developer Playbook, Part One: Getting Started on Discord The Game Developer Playbook, Part Two: Early Access and Pre-Launch MAJOR NEWS: DISCORD ANNOUNCES ITS FIRST IN-HOUSE AAAA VIDEO GAME, “THE LAST MEADOW” Overclocking dbt: Discord's Custom Solution in Processing Petabytes of Data Wicked Saints Turns Players into IRL Superheroes with the Help of e.l.f. Beauty and Discord Discord Update: March 25, 2025 Changelog How to Stream Games and Applications to Discord from Desktop or Mobile Discord Patch Notes: April 3, 2025 Checkpoint 2: Our First Year With Discord Quests How to Create & Upload Your Own Stickers on Discord Revamped Overlay & Refreshed Desktop Give Game Time a Boost Discord Announces First Mobile Ad Format, Broadening Advertising Opportunities Announcing Discord’s Social SDK, Helping Power Your Game’s Social Experiences The Game Developer Playbook: Three Incredible Game-Focused Communities Modern Image Formats at Discord: Supporting WebP and AVIF Discord Patch Notes: March 11, 2025 Supercharging Discord Mobile: Our Journey to a Faster App December Staff Picks: It’s Giving Games Discord Patch Notes: February 3, 2025 Leveling Up Black Voices in Gaming How Discord Seamlessly Upgraded Millions of Users to 64-Bit Architecture
Osprey: Open Sourcing our Rule Engine
Discord EngineeringFebruary 19, 2026 · 2026-02-19 · via Discord Blog

An array of protective shields with the Discord logo displayed on them.

This is a collaborative piece written by Jared Miller and Ayu.

Despite virtually every online platform facing these sorts of challenges, many are left to reinvent tools from scratch, with varying degrees of success. We’d like to help our fellow companies get a head-start on their safety measures — that's why, in partnership with  ROOST and the internet.dev team, we’re excited to open-source Osprey: our safety rules engine.

With Osprey, teams can investigate real-time activities across their platforms and quickly deploy dynamic rules to address emerging threats, all with minimal engineering overhead.

This post will walk you through what Osprey is, how it works, and how your team can start using it to build stronger safety measures.

What do we want in a Rule Engine?

Fighting bad actors requires tools that can adapt to new challenges in real-time. A service as large as Discord needs a system that can: 

  • Process at Scale: Handle thousands of events per second, in real-time, and scale seamlessly as our platform grows.
  • Enable Rapid Response: Let teams write expressive rules that take effect in minutes.
  • Provide Clear Decisions: Deliver actionable verdicts on whether ongoing user activities are safe, suspicious, or malicious. 
  • Show Its Work: Offer transparency into how rules were executed and when errors arise, making investigating and debugging straightforward.
  • Learn and Adapt: Support a continuous feedback loop where detection insights improve future rules. 
  • Stay Future-Proof: Accommodate extensibility for new features to combat attack patterns we have yet to imagine.

These requirements shaped every architectural decision we made when developing Osprey, from its rule language to its distributed processing model.

How does it work?

Key Concepts

Osprey is built around several core concepts. It ingests Actions, either synchronously via GRPC or asynchronously via a Message Queue, and runs them through a series of Rules written in SML (just Some Made Up Language) that can be expanded upon with UDFs (User Defined Functions), and processes them via a combination of Features and Effects, some of which can be applied to Entities. Synchronous actions in particular can return Verdict effects, which inform the caller about any determinations made by the rules. All outputs are then sent to our Apache Druid cluster to power our investigations UI.

Easy right! 

… okay, that was a LOT of bolded words and new terms thrown around. Let’s drill down what all these terms mean: 

Actions

Actions are events that we send to Osprey. Each type of action has a unique ID and schema. They’re effectively JSON blobs consumed by the rules engine, and can be customized to contain whatever data the caller provides.

{
   "__action_name": "user_login_attempted",
  "user": {
    "id": "939242044545716254",
    "username": "Daffy Duck",
    "email": "despicable@example.com",
    "ip": "170.83.36.125",
  },
}

Rules

Rules are the heart of Osprey. Within the main Osprey “engine,” we define a rules language that we call SML (Some Made-up Language). Writing rules should be simple and accessible to folks with minimal technical knowledge, so we based it on Python! Even with a fairly simple syntax, we can make powerful statements, with rules capable of referencing other rules and data.

The rules language enables static validation that can enforce a particular way rules should be written. Provided that validation is consistent, new validation logic can be easily added via Python code. It can be as simple as requiring all variable names to start with an uppercase letter, or as complicated as a given case needs.

UserId: Entity[int] = EntityJson(type='User', path='$.user.id', coerce_type=True)
UserEmail: str = JsonData(type='Email', path='$.user.email', required=False)
UserIsDaffy = Rule(
    when_all=[
        UserEmail == 'despicable@example.com',
    ],
    description='(known spammer) is trying to register',
)
WhenRules(
    rules_any=[
    UserIsDaffy
    ],
    then=[
        LabelAdd(entity=UserId, label='spammer'),
    ],
)

UDFs

UDFs are functions written in (actual, not SML) Python that can be called anywhere within the rules. UDFs define the standard library for Osprey, such as Rule (here), WhenRules (here), and JsonData (here), to name a few. UDFs are how you’ll be expanding upon Osprey’s language functionality if you decide to incorporate Osprey into your own products. 

To give an example, if rule writers want to access data from an external service, one may define a UDF to call said service and present the result. 

@register
class LinkSpamScore(HasHelper[LinkSpamScoreProvider], UDFBase[LinkSpamArguments, float]):
    """
    Get a float [0,1] score from link spam model
    """

    category: ClassVar[str] = UdfCategories.ML
    execute_async: ClassVar[bool] = True

    def execute(self, execution_context: ExecutionContext, arguments: LinkSpamArguments) -> float:
        provider = execution_context.get_udf_helper(self)
        accessor = execution_context.get_external_service_accessor(provider)
        response: PredictResponse = accessor.get(arguments)
        return response.score

Features

A feature is any variable in the global namespace in Osprey. All features must be uniquely named. However, prefixing a `_` at the start of a variable name prevents it from being exported as a feature and keeps the variable within the local file’s namespace.

Features are outputs of Osprey executions. Downstream, they are sent to and indexed by Druid, so users can query for events based on feature names later, i.e. `UserEmail == 'despicable@example.com`.

UserId: Entity[int] = EntityJson(type='User', path='$.user.id', coerce_type=True)

UserEmail: str = JsonData(type='Email', path='$.user.email', required=False)

In the example above, both UserId and UserEmail are features.

Entities

Entities are a special type of Feature. All entities are features, but not all features are entities. Within Discord, these represent persistent units like Users, Servers, or emails. 

An entity can have effects applied to it, such as labels, classifications, or signals. Every entity has a type that determines which effects can be applied to it based on static validations.

Entities get special treatment within the Osprey UI. Clicking on an entity in the tool will take you to an Entity View, providing a deep dive into its history.

Effects

Effects can be triggered when one or more rules are evaluated to be true. These are validated and handled in aggregate at the end of an execution output. For example, an effect might apply a label to an entity, marking it as a “Spammer”.

WhenRules(
    rules_any=[UserIsDaffy],
    then=[
      LabelAdd(entity=UserId, label='spammer')
      DeclareVerdict(verdict='reject')
    ],
)

System Components

Osprey System Diagram

The actual Osprey system is built from a few independently operating services. Actions are first sent to the Osprey Coordinator, which acts as an intermediary between a fleet of Osprey Rules Workers, balancing asynchronous and synchronous requests between them. Rules workers have a locally mounted copy of the Rules

At Discord, we use ETCD to distribute rules to the workers. This lets us push new rules into production without requiring deployment. When the rules worker finishes evaluating an Action, it outputs the result to a configurable set of Output Sinks. These take the results and apply or write them as needed. Among the Output Sinks, one provided by default is a publisher to a Kafka queue, which pipes execution results into a Druid database. All these power investigations via our Osprey UI

Investigative Tooling: The Osprey UI

The Osprey UI is our real-time investigation platform for tracking bad actors, analyzing rule performance, and reviewing execution results. Using our custom query language, security teams can run complex queries against our Druid database to spot trends and identify new attack patterns.

The interface (displayed below with dummy data) combines an event stream with visualization tools, such as time series charts and Top N tables. This allows teams to spot anomalies quickly, whether it's unusual spikes in account creation, patterns in guild joining behavior, or coordinated Direct Message campaigns. The feedback loop is immediate: insights from investigations directly inform new rules and protections. 

The Osprey UI showing the results of an example query populated by test data generated for demo purposes. The UI is split into three columns. At the top left, there is an input box to submit new queries. Underneath we see the history of past queries as well as an option to load saved queries. The middle column shows different charts, at the top is a bar graph representing a time series between “January 25 7PM” and “January 26 7pm”. The values range between 5 and 7 events with a column for every hour. Underneath is another bar graph chart  representing the time series broken down by minutes. The values range between 0 and 4 events with a column for every minute. The right most column is the Event Stream. There are three events showing “identity_change”. Each event has several data fields indicating the features that were part of that event. For example “DisplayName”, “userId”, “IpNetworkValue”, AccountCreatedAt” are all features included for each event. A tooltip is shown as a cursor hovers over a display name in one of the events showing the label assigned to the display name, “spam_display_name”. There are options to edit the label or add the entity to the query or open in a new tab of Osprey.

Integrated Investigation Workflow

The Osprey UI treats Entities (like User IDs, Guild IDs, IP addresses), Features (contextual data like usernames), and Effects (like applied labels) as first-class components. This creates a natural investigation workflow where, when examining a suspicious entity, investigators can instantly see all related events, applied labels, and behavioral patterns in one unified view. The interface below uses dummy data to show a User Entity view:

The Osprey UI Entity showing the results for a particular User populated by test data generated for demo purposes. The UI is split into three columns. At the top left, there is an input box to submit new queries. Underneath we see labels that have been applied to the entity, split into Negative, Positive , and Neutral sections. One label, “identity_evasion” is expanded showing a description for the label “User showing identity evasion patterns” as well as an action associated with the label, “RapidHandleChange”. The middle column shows different charts, at the top is a bar graph representing a time series between “February 12, 2026 7pm” and “February 12, 2026 8pm”. The values range between 0 and 17 with a column for every minute. Underneath is a table showing the “Top N Results” broken down by the count for each action name. For example, the top row says “39” for the count and “send_message” for the action name. The right most column is the Event Stream. There are three events shown, “identity_change”, “send_message”, and “create_post”. Each event has several data fields indicating the features that were part of that event. For example “UserId”, “DisplayName”, “IpAddress”, “MessageText” are all features included for events.

Handling Sensitive Data

Osprey is hosted on your own infrastructure and can only access data and information you send to it. At Discord, since we use Osprey to respond to incidents that can contain sensitive user data, we maintain strict access controls and audit trails. Team members can only access certain actions or entity-specific views with proper justification and permissions, ensuring user privacy while enabling effective investigations.

Operating at Scale

Osprey was built to scale. As of December 2025, Discord uses the open source version of Osprey to handle ~400 million actions per day. Although mostly benign, these events provide valuable signals that are then categorized across 204 action types and 2288 rules, with the average action triggering ~500 rules. Among the rules, we’ve included 99 custom UDFs, many of which perform RPCs to other internal services. Individual performance mileage varies based on the amount and complexity of the rules being triggered. 

The system can support more actions by horizontally scaling the number of rule worker instances. Running the Osprey Coordinator helps balance synchronous and asynchronous actions across the rule workers. This adds some resilience against spiky traffic patterns without over-provisioning the number of rules workers and minimizing the need to add workers on demand. 

Optimizing Osprey's performance remains a high priority for Discord. By reducing costs and increasing rule executions per second, we can directly enhance Osprey's impact and effectiveness as a safety tool.

Customizing Osprey for the Public

There is no one-size-fits-all rules engine that can efficiently meet all the needs of every adopter. In its original form, Osprey was built using Discord’s internal libraries, conforming to our internal infrastructure and use cases. 

From the beginning of our open-sourcing journey, we knew configurability would be essential. We started planning by looking at our complex and featureful system, stripping away components bit by bit until we arrived at a minimal, yet fully-featured, product.

To achieve this, we needed to make some changes to our system:

  • The Osprey Rule engine should accept events sent via GRPC requests or via a Message Queue (PubSub or Kafka) as opposed to only accepting events via Osprey Coordinator.
  • We should support open-source alternatives to any proprietary dependencies being used. For example, where we used PubSub, we also want to support Apache Kafka, which can be self-hosted.
  • Only a small set of Discord’s UDFs, particularly simple ones without external dependencies, would be included out of the box. We should provide an adaptor layer for users to easily incorporate their own custom UDFs.
  • We should support loading Rules via the file system at build time. The ability to hotload rules via ETCD would be maintained, but we didn’t want to require an extra dependency and configuration step for those who could do without.
  • The rules engine should return Verdicts. These could be ignored if passing in actions asynchronously, but they serve as a clear communication method to synchronous callers.
  • We should support arbitrary Output Sinks so users can process execution results as they wish.

We also wanted to provide optional extra features to everyone:

  • A UI investigation tool. This required having an Output Sink publishing to a Kafka topic and subscribed to via Druid.
  • The Osprey Coordinator, which can act as a load-balancer to prioritize synchronous actions when facing surges of asynchronous actions. It’s particularly useful in environments where traffic can be bursty. For systems that don’t require the Coordinator, such as ones with little traffic or upstream rate limiting, Actions can be sent directly to the rules workers using the same methods (GRPCs for synchronous and a Message Queue for asynchronous).

What we knew we wouldn’t be able to provide:

  • Our full set of UDFs and Rules. This included things like our Counter service, which is heavily integrated with our internal Scylla databases. 
  • Our full set of Output Sinks. For example, we write all of our rule execution results to BigQuery. While this might be useful to some, it’s not strictly necessary, and we didn’t want to bias towards any non-open-sourced software. 

Taking our existing rules engine and making it conform to these requirements, while still operating for our needs, was akin to repairing a car engine while driving down the highway. We made UDFs, Rules, and Output Sinks configurable by using the “Pluggy” Python library. We then removed and replaced internal Discord dependencies one by one, placing our internal configurations behind our new Pluggy integrations. And even as changes were being made, we carefully tested and deployed into our own production environment (but not at the same time), maintaining parity with our intended end product while weeding out potential bugs that could pop up along the way. 

In the end, it took months of work among five incredible engineers to carve out our tool for the public.

What’s Osprey Flying Towards Next? 

Open-sourcing Osprey is just the beginning. We’ve got an ambitious roadmap ahead, focused on making the tool even more powerful and accessible for the community.

A sneak peek at some of our plans:

  • We’re looking into performance improvements to support even higher volumes of actions per second for the Rule Engine.
  • Upgrading dependencies to their latest versions to support newer, more advanced features.
  • Improving our documentation, including best practice guides and tutorials for using the service.
  • Build out a toolkit of open-sourced plugins for Osprey, like the Counter service.

Join Us in Building Better Safety Tools

The safety challenges facing online platforms are bigger than any one company can solve alone. That's why we are proud to participate in efforts like ROOST and why we're committed to building Osprey as a true community project. Whether you're contributing code, joining the public working group meetings, sharing use cases, or just providing feedback, your participation helps make the internet safer for everyone.

We actively encourage contributions of all kinds: new features, performance improvements, documentation, or creative applications we haven't thought of yet. Your unique perspective and challenges can help make Osprey better for the entire community.

At Discord, we believe the best safety innovations happen when we all work together. We're committed to long-term investment in Osprey's development and will continue working with our partners at ROOST to bring more powerful safety tools to the open source community.

Discord Engineering

We make Discord!

related articles