Skip to main content

Custom Commands

Custom commands let you create your own prefix-triggered commands (like ?hello or !rank) that respond with dynamic text, embeds, reactions, direct messages and more. Every response is powered by TagScript — a small, easy-to-learn templating language. A response can be as simple as a line of plain text, or as advanced as a mini program with variables, conditions, randomness and math.
You never have to learn TagScript. The dashboard includes a visual, no-code builder that writes TagScript for you. This page documents the language itself so you can build anything you can imagine.

Creating a Command

  1. Select Custom Commands from the sidebar and click Create Command.
  2. Fill in the fields:
  • Name — the command word typed after the prefix, e.g. hello runs as ?hello. Stored in lowercase.
  • Aliases — optional alternative names that trigger the same command (e.g. rank, level, lvl).
  • Response — the TagScript that runs when the command is used. This is the heart of the command.
  1. Save. Your command is live instantly.
A name or alias can only belong to one command per server. If you try to reuse a name that another command already owns, saving fails.

AI Command Assistant

The command editor includes an AI assistant powered by Gemini. Describe what the command should do in plain language, then select Generate. The result opens in TagScript mode so you can review and test it before saving. The assistant receives the same variables, functions and examples shown in the TagScript catalogue. MurFFy validates the generated response and rejects unknown or malformed tags before placing it in the editor. Each user can generate one command every seven days. Failed AI requests do not use the weekly generation. If the shared AI quota is unavailable, the editor shows a temporary service-unavailable message and you can try again later.

Prefixes

By default, custom commands are triggered with the ? prefix, so a command named hello runs as ?hello. You can change or add prefixes under Custom Commands → Settings. When several prefixes could match, the longest one wins (so !! is matched before !). Prefixes cannot contain spaces.

How TagScript Works

Anything you type in the response is sent back as-is, except for tags wrapped in curly braces {}. Tags are replaced with real values or perform an action when the command runs. A tag has up to three parts: Tags can be nested — the inside is resolved first:
If the user is named mafi, this outputs MAFI.
Some tags (called actions and restrictions, like {dm}, {delete} or {require}) don’t print anything — they change how the response is sent. They output nothing where you place them.

The Pipe |

Many tags use the pipe character | to separate several values or “branches”, for example the true/false branches of {if} or the options of {choose}. If you need a literal | in your text, escape it as \|.

Escaping Special Characters

To output a character that TagScript treats specially, put a backslash \ in front of it: \{, \}, \(, \), \|, \:, \\.
Output: Use {user} to mention someone.

Variables

Variables are replaced with information about the user, server, channel or the arguments they typed. Most accept a property in parentheses to pick exactly what you want.
Discord renders {user(created)}, {server(created)} and {time} as live timestamps that update automatically (e.g. “5 minutes ago”).
Examples
Used as ?boop @friend.

Conditionals & Logic

Make the response react to what the user typed.

{if(condition):then|else}

Outputs the first branch when the condition is true, and the branch after | when it is false (the else branch is optional). Conditions support the comparators ==, !=, >, <, >=, <=. Numbers are compared as numbers; anything else is compared as text. A condition with no comparator is true unless it is empty, false, 0, no or none.
Here the condition is simply whether any arguments were given.

Combining conditions


Utilities

Helpers for text, numbers and randomness. Examples
Capitalises the first letter of whatever the user typed.

Custom Variables

Store a value once and reuse it, which keeps complex commands readable and avoids repeating expensive tags.
Variable names are stored in lowercase and only exist for the duration of a single command run.

Embeds

Build a rich embed by setting one property per {embed(...)} tag. All the tags in a response combine into a single embed. Named colors: red, green, blue, yellow, orange, purple, blurple, white, black, gold, pink, gray.
{embed:some text} with no property is a shortcut that sets the description.

Economy

Economy tags connect a custom command to the server’s configured currencies and inventory. They only work while Economy is enabled for the server.

Reading balances and items

The account in {balance} can be wallet, bank or total. Its output format can be:
  • formatted — exact amount with the configured currency symbol, such as 🪙 1,250;
  • decimal — display amount without the symbol, respecting the currency’s decimal places;
  • raw — integer base units stored by the ledger.
The user selector can be self, target, a Discord mention or a user ID. target means the first user mentioned in the command arguments. Currency properties: key, name, plural, symbol, decimals, transferable, tradable, bankable, maxwallet. Item properties: key, name, description, emoji, rarity, type, usable, tradable, sellable, giftable.

Currency and item operations

Operations return true when they succeed and false when they cannot be completed. Put them inside {if} to show the correct response without guessing the result. currency is optional and defaults to the server’s default currency. A reward cooldown is mandatory and must be between 60 seconds and 7 days. The optional bucket lets several reward tags or commands share the same per-user cooldown.
Reward tags can only reward the member who runs the command. They cannot edit another member’s balance. Currency changes always pass through the double-entry ledger, while item changes respect supply, ownership and stack limits. Testing a command in the dashboard only reports what would happen and never changes balances or inventory. Separate economy tags are separate operations; use the built-in Shop when a payment and item delivery must be one atomic purchase.

Actions

Actions change how the response is delivered. They print nothing where you write them, so you can place them anywhere in the response.
For safety, replies never ping roles or @everyone unless you add {allowmentions}. A {user(mention)} still shows as a mention but won’t send a notification without it.

Restrictions

Restrictions decide who and where a command can be used. If a restriction fails, the command stops. If you provide a reason, it is shown to the user; otherwise the command fails silently. Roles and channels can be given as a mention (@Staff, #logs), an ID, or a plain name.

Worked Examples

Simple

Used as ?boop @friend.

Complex

Only answers when a question is provided, otherwise explains how to use it.
Rolls a random reward, records it through the economy ledger, and enforces a one-day per-user reward cooldown in the shared daily bucket.
Restricts to staff, posts the embed into #announcements (with pings enabled), and stays silent in the channel where it was typed.
Deletes the trigger, reposts the suggestion as an embed in #suggestions, and adds vote reactions.
Uses nested {if} tags to pick a tier and a matching color from a number.

Good to Know

  • Responses are limited to 2000 characters (Discord’s message limit). Longer output is trimmed.
  • A single command has an execution budget (a maximum number of tags and nesting depth) to keep things fast — normal commands never come close to it.
  • If a tag can’t be resolved, it is shown back as plain text so you can spot the typo.
  • Custom commands respect the Allowed / Ignored roles and channels you set on the command itself, in addition to any {require} / {blacklist} tags in the response.
Test a command safely from the dashboard before going live — the Test button renders the response (including embeds) without actually sending anything to Discord.