Chisle
The coding-agent plugin that bills 52% of a bare model across 20 live tasks. Terse persona + tool-output compressor + context diet.
翻訳待ち
The web framework for Discord bots.
翻訳待ち
Loading the full README.
Read the full README ↗Discord bots that live on the edge.
Slash commands, buttons, modals and rich Components V2 layouts, written once in Rust and served from Cloudflare Workers or any server. No gateway, no idle process, no bill while nobody is talking to your bot.
Guide · API docs · Examples · Discord · Crates
use composure::{app, command, types::User};
/// Give someone a cookie
#[command]
fn cookie(
#[option("Who gets it")] user: &User,
#[option("How many", min = 1, max = 12)] count: Option<u8>,
) -> String {
format!("{} gets {} 🍪", user.display_name(), count.unwrap_or(1))
}
#[app(handlers(cookie))]
pub struct Bot;
The function is the command. Its parameters become Discord Options (with min/max
enforced by Discord and checked against u8 at compile time), its doc comment the description,
its return value the reply. Hand Bot to an Adapter to serve it, and to composure_sync to
register it.
Composure handles Interactions only: commands, buttons, selects and modals that Discord delivers to your bot as signed HTTP requests.
&str, u8, &User, Role or your own enums.
Duplicate commands, too many Options, out-of-range bounds and bad custom_id prefixes fail
to compile, not in production.rsx!,
with click handlers right next to the buttons they belong to.custom_id. Button and modal state is encoded into the custom_id for
you, so a counter needs no database.tracing, and a command
sync CLI with CI drift checks.| Gateway bot | Composure | |
|---|---|---|
| Connection | A WebSocket, always open | None: Discord calls you |
| Hosting | A server running 24/7 | Cloudflare Workers, a container, any server |
| Scales to zero | No | Yes |
| Commands defined | Often twice (registration + handler) | Once, as a function |
| Reads every message | Possible (with intents) | No: Interactions and Webhook Events only |
If your bot needs to watch every message or presence update, use a gateway library. If it only answers people, Composure needs no gateway connection, and on Workers no server at all.
rsx! and #[view]use composure::{rsx, view, command::View};
/// A card that counts its likes. The count lives in the button's custom_id.
#[view]
pub fn Card(title: String, likes: u32) -> View {
rsx! {
<Container>
"## " {title.as_str()}
<Text>"-# " {likes} " likes"</Text>
<Row>
<Button primary on:click:like=move |_| Card { likes: likes + 1, title }>
"Like"
</Button>
<Button url="https://discord.com/developers/docs">"Docs"</Button>
</Row>
</Container>
}
}
Clicking Like re-renders the message with new Props. Every Discord component has a tag, and every tag's attributes are documented.
This is the beginning of the README. Read the rest at the original. Read the full README ↗