Skip to content
Simon Roy edited this page Feb 15, 2026 · 2 revisions

What is a Check?

A check is a function that runs before your command. It returns:

  • True - Allow the command to run
  • False - Block the command and raise CheckError

Add a Check

Let's create an admin-only command:

@bot.command()
async def restricted(ctx):
    await ctx.reply("You passed all checks!")


@restricted.check
async def is_admin(ctx):
    admins = ["@alice:example.com", "@bob:example.com"]
    return ctx.sender in admins

Multiple Checks

You can add multiple checks to one command. ALL checks must pass:

@bot.command()
async def restricted(ctx):
    await ctx.reply("You passed all checks!")

@restricted.check
async def check_one(ctx):
    # Must be from a specific room
    allowed_rooms = ["!room1:example.com", "!room2:example.com"]
    return ctx.room_id in allowed_rooms

@restricted.check
async def check_two(ctx):
    # Must not be banned
    banned = ["@troublemaker:example.com"]
    return ctx.sender not in banned

Both checks must return True for the command to run.

Global Checks (Bot-Level)

You can apply a check to all commands with @bot.check:

@bot.check
async def not_banned(ctx):
    """No banned users can run ANY commands"""
    banned_users = ["@spammer:example.com", "@troll:example.com"]
    return ctx.sender not in banned_users

Now this check runs before every command on your bot.

What is a Cooldown?

A cooldown prevents users from running a command too frequently. It's like a check, but specifically for rate limiting.

Adding a Cooldown

@bot.command(
    description="Searches for something",
    cooldown=(3, 60.0)  # 3 calls per 60 seconds
)
async def search(ctx, query: str):
    # Simulate expensive operation
    await ctx.reply(f"Searching for: {query}")

Cooldown format: (rate, period)

  • rate (int): Number of times the command can be called
  • period (float): Time window in seconds

Example interpretations:

  • (1, 10.0) - Once every 10 seconds
  • (5, 60.0) - 5 times per minute
  • (10, 3600.0) - 10 times per hour

Setting Cooldowns Programmatically

@bot.command()
async def limited(ctx):
    await ctx.reply("This command is rate-limited")

# Set cooldown after command creation
limited.set_cooldown(rate=2, period=30.0)  # 2 times per 30 seconds

Handling Cooldown Errors

When a user hits the cooldown limit, you can tell them how long to wait:

from matrix.errors import CooldownError

@bot.error(CooldownError)
async def handle_cooldown(error):
    # error.retry tells you how many seconds until they can retry
    wait_time = int(error.retry)
    # You can send a message here if you have access to context
    print(f"Cooldown hit! Wait {wait_time} seconds")

Hooks

@command.before_invoke
async def before(ctx):
    # Runs before command

@command.after_invoke
async def after(ctx):
    # Runs after command succeeds

Clone this wiki locally