Skip to content

Flows

A flow is what the bot does when something happens. Each flow is one file, and it’s either a command flow (a slash command) or an event flow (something that happens on Discord).

Every flow starts at exactly one Start block. When the command or event fires, the runtime begins there and follows the connections:

  1. It runs the current block.
  2. The block picks an output port. Most blocks have a single next port. Condition has true and false.
  3. The runtime follows the connection leaving that port to the next block.
  4. The flow ends when a port has no connection.

Each port carries one connection. Connecting a port again replaces the old connection, and the Problems panel warns about files where a port has more than one.

  • Shift, Ctrl or ⌘ click adds blocks to the selection, and Shift drag selects an area.
  • Ctrl+C, Ctrl+X and Ctrl+V copy, cut and paste blocks with the connections between them, also from one flow to another. Ctrl+D duplicates and Ctrl+A selects everything. Right-click a block or empty space for the same actions.
  • Add note in the palette or the right-click menu puts a sticky note on the canvas. Notes are saved in the flow file and ignored by the bot.

In the Project panel, right-click a file or folder to rename, duplicate or delete it, or to create files and folders. Renaming a message design updates the blocks that use it.

A command flow defines a slash command: its name, description and options. Pick the Start block, or click empty space on the canvas, and edit them in the Properties panel.

  • Names are lowercase, without spaces, up to 32 characters.

  • Up to 25 options, each with a type: text, whole number, number, yes/no, user, channel, role, user or role, or file. Numbers can have a min and max value, text a min and max length. A file option gives its URL.

  • Read an option’s value in the flow as {{options.name}}. For user, channel and role options this is the ID.

  • string, integer and number options can have up to 25 choices. Discord then shows a list instead of a text box. Write one per line, or Label = value to store something other than the label.

  • Who can use it hides the command from members who lack the ticked permissions. Server admins can override this in Server Settings › Integrations.

  • Can be used in DMs with the bot makes the command work in direct messages too. By default commands only work in servers.

Tick This flow is a subcommand to turn the flow into one part of a bigger command. Every flow with the same command name adds a subcommand, so /config show and /config reset can be two flows. A group adds one more level, like /config role add. The command description is shared, and each subcommand has its own description and options. A command can’t mix a plain flow with subcommand flows, and the Problems panel says so.

Switch the type to User menu or Message menu to add the command to the right-click menu, under Apps. These commands have a name that can contain spaces and capital letters, and no options. In the flow, {{target.*}} is the user that was clicked, or the author of the message, and {{message.*}} is the message.

Tick Suggest values while typing on a text or number option, then create an event flow for When someone types in an autocomplete option. Set its target to command.option, like search.query, or command.subcommand.option for subcommands. In the flow, {{focused.value}} is what the person typed so far, and the Suggest Choices block answers with up to 25 suggestions. Autocomplete flows have to answer within 3 seconds.

The bot registers its commands when it starts and again whenever the set of commands changes.

An event flow runs when Discord sends the bot an event. Supported events:

Event When it runs Needs intent
clientReady Once, when the bot comes online —
guildMemberAdd A member joins a server GuildMembers
guildMemberRemove A member leaves a server GuildMembers
messageCreate Someone sends a message (messages from bots are ignored) GuildMessages
messageUpdate Someone edits a message GuildMessages
messageDelete A message is deleted GuildMessages
messageReactionAdd Someone adds a reaction GuildMessageReactions
messageReactionRemove Someone removes a reaction GuildMessageReactions
messagePollVoteAdd Someone votes in a poll GuildMessagePolls
guildMemberUpdate A member’s roles, nickname, boost or timeout changes GuildMembers
guildBanAdd, guildBanRemove Someone is banned, or a ban is lifted GuildModeration
voiceStateUpdate Someone joins, leaves, moves or mutes in voice GuildVoiceStates
channelCreate, channelDelete A channel is created or deleted Guilds
threadCreate A thread is created Guilds
roleCreate, roleDelete A role is created or deleted Guilds
inviteCreate An invite is created GuildInvites
guildCreate, guildDelete The bot is added to, or removed from, a server Guilds
autoModerationActionExecution AutoMod blocks or flags something AutoModerationExecution
autocomplete Someone types in an option with autocomplete —
buttonClick Someone clicks one of the bot’s buttons —
selectMenu Someone picks from one of the bot’s menus —
modalSubmit Someone submits a form opened with Show Form —
schedule Every N minutes, or every day at a set time —

GuildMembers is a privileged intent: turn on Server Members Intent under Bot in the Developer Portal as well. To read the text of messages you also need MessageContent, which is privileged too.

Buttons, menus and forms carry a custom ID that you choose. Menus can list your own options, or let people pick members, roles, both, or channels; {{values}} holds the picked IDs. Set the same ID on the event flow and it runs only for that component. End the ID with * to match everything that starts with it: vote:* catches vote:yes and vote:no, and {{customId}} tells you which one it was. Leave it empty to catch them all.

These flows can answer the person with Reply, Defer Reply and, for buttons and menus, Show Form. Discord expects an answer within 3 seconds, so put Defer Reply first when the flow does something slow. Wait does this for you when it waits longer than 2 seconds.

A schedule flow runs every N minutes (1 to 10080) or every day at HH:MM, using the clock of the machine the bot runs on. It runs only while the bot is online, and a run that was missed while the bot was offline doesn’t catch up later.

While the bot runs from the IDE, the runtime watches your flow files. When you save one, flows reload immediately and slash commands are re-registered if anything about them changed. Changes to makecord.json need a restart.

You rarely need to edit flow files by hand, but they’re meant to be readable:

commands/ping.flow.json
{
"specVersion": 1,
"kind": "command",
"command": { "name": "ping", "description": "Shows the bot's latency", "options": [] },
"nodes": [
{ "id": "start", "type": "core.trigger", "position": { "x": 0, "y": 0 }, "data": {} },
{
"id": "reply",
"type": "core.reply",
"position": { "x": 320, "y": 0 },
"data": { "content": "Pong! {{client.ping}} ms", "ephemeral": false }
}
],
"edges": [{ "id": "e1", "source": "start", "sourceHandle": "next", "target": "reply" }]
}

type names the block (see the Blocks reference), data holds its settings and sourceHandle is the output port a connection leaves from.