Model or dataset
serenity-rs/poise avatar
serenity-rs/poise

Poise: a Discord bot framework where one function is a slash command

Discord bot command framework for serenity, with advanced features like edit tracking and flexible argument parsing

916 stars154 forksRustMIT

At a glance

What is it?
Poise is a Rust framework for Discord bots built on serenity, where a slash command is defined by a single function signature and parameters are declared as ordinary Rust types that the framework parses. It also supports legacy text commands and automatically updates its response when a user edits their message.
Who is it for?
Poise suits a Rust developer writing a Discord bot who wants typed arguments and a command signature that reads like a function call rather than a hand parsed message, and the edit tracking feature is genuinely rare in this ecosystem.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One function signature is the whole slash command

Poise is described as an opinionated Discord bot framework with a few distinctive features, and the first of those is the one that defines the design.

Slash commands are completely defined with a single function signature. There is no separate registration file, no builder that assembles a command from parts, and no parallel declaration of arguments. The command is the function, and the arguments are the function's parameters.

That works because Discord's slash command model already forces you to declare a name, a description and a set of typed parameters somewhere, and Poise derives that declaration from the Rust signature. A function that takes a String and an Option of i64 becomes a command with a string option and an integer option, and the framework generates the command definition from it. The cost is that renaming a parameter renames the option, which matters for Discord's command surface, but the benefit is that the source of truth for a command is one place.

The framework is opinionated, and the word is doing real work. There is one way to define a command in Poise, and the project has made choices for you rather than leaving them open. That is a reasonable position for a framework whose selling point is consistency.

Poise is built on serenity, the Rust Discord library, and the dependency list shows it pulling in serenity 0.12.5 with the builder, client, gateway, model, utils, collector and framework features enabled. The framework sits on the library rather than replacing it, so the raw Discord API is still reachable when a command needs something the abstraction does not cover.

Arguments are ordinary Rust types, parsed for you

Flexible argument parsing is the second headline feature, and the description is precise about what that means: command parameters are defined with normal Rust types and parsed automatically.

The practical effect is that the validation, the error messages and the Discord option types are all derived from the type you write. A u64 parameter becomes an integer option. An Option of a String becomes an optional string option. A type you implement yourself can become a custom option type, which is how the framework supports things like a member parameter that resolves to a cached user.

The bots using poise list in the project documentation gives a sense of the range, and the notable features listed per bot include variadic and lazy arguments for Etternabot, fuzzy search and RNG for DisQuip Bot, response transformation for Etternabot, and custom prefixes for Ferrisbot and CrackTunes.

The variadic and lazy argument types are worth pausing on, because they are the cases where automatic parsing is not obvious. A variadic argument accepts a repeating option, which Discord supports for some option kinds, and a lazy argument is one that is only resolved if a later argument needs it. Both exist because the type drives the parser, so if the framework had only fixed built-in types those cases would need escape hatches, and escape hatches are what the opinionated design is trying to avoid.

The dependency list shows the machinery underneath. regex at 1.6.0 with default-features off and the std feature is commented as being for prefix, which is the text command path. trim-in-place is there for text handling, and indexmap preserves insertion order for the structures the framework builds.

Text commands and slash commands from the same code

The third listed feature is that commands are agnostic over old text-based commands and slash commands. The same command definition answers both.

This matters more than it sounds. Discord has moved towards slash commands, but plenty of existing bots have a large body of prefixed text commands, and a framework that only does slash commands forces a migration of every command and breaks every existing invocation. A framework that treats the two as equivalent means you can add slash commands to an existing bot without rewriting the old ones.

That is also why the regex dependency is there, and why the bots list includes custom prefixes. The prefix is configurable, per bot, and the framework parses the message against it. Ferrisbot and CrackTunes both list custom prefixes among their notable features.

The catch is the mental model. A framework that accepts both invocation styles has to decide, at runtime, whether an incoming message is a prefixed command or a slash command interaction, and it has to resolve the arguments from a string in one case and from a structured interaction payload in the other. The typed parameter model is what makes that possible, because the same parameter list describes both the option set and the string to be parsed. The cost is that a text command can accept anything the type accepts and no more, so a slash command's stricter option validation is not available in the text path.

Edit tracking is the fourth feature and the most unusual. When a user edits their message, the bot response updates automatically. On a platform where messages are cheap to send and expensive to keep tidy, that turns a common annoyance, a bot responding to a typo that has already been corrected, into something the framework handles.

The dependency set tells you what the framework assumes

Reading Cargo.toml for poise gives a clearer picture of the design than the four bullet points do.

The default feature set is serenity/rustls_backend, cache, chrono and handle_panics. The rustls backend is the TLS implementation used by serenity, and the cache feature turns on serenity's caching layer, which the typed argument resolution depends on. chrono is pulled in for date and time handling in commands. handle_panics enables support for handling panics inside commands via FrameworkError::CommandPanic, and the comment says the feature has no overhead and can always be enabled.

That last one is a good default for a bot framework. A panic in a command handler should not take down the gateway connection and kill the whole bot, and routing it into a framework error means the command can report the failure.

The async foundation is tokio 1.25.1 with default-features off, plus futures-util 0.3.13, both with the comment for async in general. async-trait 0.1.48 is there for the various traits, so the framework's own traits can be object safe. tracing 0.1.40 with the log feature is there for warnings about weird state, which tells you the framework emits structured diagnostics rather than printing to stdout.

derive-where 1.6.1 is an unusual dependency. It allows deriving traits conditionally, which is how one type can implement different behaviour depending on which generic parameters are present, a common need when a command's behaviour depends on optional features like localization.

parking_lot 0.12.1 is the lock implementation, and indexmap 2.2.6 gives ordered maps, which matters when the framework builds ordered structures that are rendered to users.

The macros directory is a separate crate, poise_macros, at the same version as the main crate, and the comment in the manifest reminds the maintainer to update the version on changes. That is the procedural macro that turns a function signature into a command definition, and keeping it a separate crate is what makes the derive work without the main crate pulling in syn and quote for everyone who only uses the runtime.

Branches, documentation and the release line

The default branch is called current, which is unusual and tells you how this project handles versioning.

The documentation links point at two sets of API docs: one for the current branch and one for next. The readme explains the convention: if you are using a development version from git directly, you probably want the documentation for the current or next branch instead of the released docs on docs.rs.

So there are effectively three documentation targets, published API documentation for the latest release, and two branch-specific sets for people tracking master or working toward the next release. The MSRV badge points at Rust 1.82, and the manifest states rust-version = 1.82.0, with the crate edition at 2021.

The release history shows steady work: v0.6.2 on 2026-04-13, v0.7.0 on 2026-09-06 and v0.7.1 on 2026-10-12, with the last push on 2026-10-19. A 0.x version with regular minor bumps means the API is still moving, and the two-branch documentation setup exists precisely because of that.

The repository layout supports the ecosystem claims. The examples directory holds twelve separate example projects, including quickstart, advanced_cooldowns, event_handler, feature_showcase, fluent_localization, generic_commands, invocation_data, manual_dispatch, basic_structure, framework_usage and advanced_cooldowns. There is a macros/ directory for the procedural macro crate, a release-guide.md, and a CHANGELOG.md.

The examples are worth more attention than they usually get, because each one is a small complete bot. Manual_dispatch in particular suggests you can bypass the framework's dispatch entirely and handle interactions yourself, which is the escape hatch for the cases the abstraction does not fit.

The readme also directs you to the examples, especially feature_showcase, as the way to learn what poise can do, and to the API documentation for the rest. There is a support server, and the list of bots using poise is maintained by pull request, which is a good sign about community activity and also a good source of ideas for what a serious bot needs.

Editorial conclusion

Poise suits a Rust developer writing a Discord bot who wants typed arguments and a command signature that reads like a function call rather than a hand parsed message, and the edit tracking feature is genuinely rare in this ecosystem. It does not suit a project that wants to move away from serenity, since Poise is built directly on it and inherits its version cadence, and it does not suit a bot with a large existing text command base that cannot afford to migrate every command signature. Before adopting it, read the examples directory, since the feature_showcase example is what the project points to as the way to learn the API, and note that the crate requires Rust 1.82 or newer.

Frequently asked questions

How does poise define a slash command?

Completely with a single function signature. The command parameters are defined with normal Rust types and parsed automatically, so the framework derives both the Discord command definition and the argument parsing from the function you write.

Can poise handle both slash commands and old text commands?

Yes. Commands are agnostic over old text-based commands and slash commands, and the bots using poise list custom prefixes among their notable features, with regex in the dependency list for the prefix parsing.

What is poise edit tracking?

When a user edits their message, the bot response updates automatically. It is listed as one of the framework's distinctive features alongside slash command definition and flexible argument parsing.

What Rust version and which Discord library does poise require?

The manifest sets rust-version = 1.82.0 with edition 2021, and poise depends on serenity 0.12.5 with the builder, client, gateway, model, utils, collector and framework features. The default features are serenity/rustls_backend, cache, chrono and handle_panics.

Where should I look to learn the poise API?

The readme points at the API documentation and at the examples directory, especially the feature_showcase example, as the way to learn what poise can do. There are separate published docs for the current and next branches for anyone tracking a git version rather than a release.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. serenity-rs/poise on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/serenity-rs-poise.svg)](https://hysenlabs.com/projects/serenity-rs-poise)

Was this useful?