SDKs
lamma.py
Build Lamma bots in Python with the patterns you know from discord.py.
lamma.py lets you build Lamma bots in Python with the names and patterns you know from discord.py. It runs on Lamma's own REST API and gateway and never talks to Discord.
#Example
Python
import lamma
from lamma import app_commands
from lamma.ext import commands
intents = lamma.Intents.default()
intents.message_content = True
class MyBot(commands.Bot):
async def setup_hook(self):
await self.tree.sync() # global commands show up everywhere at once
bot = MyBot(command_prefix='!', intents=intents)
@bot.command()
async def hello(ctx):
await ctx.reply(f'Hello, {ctx.author.display_name}!')
@bot.tree.command(description='Roll a die')
@app_commands.describe(sides='How many sides')
async def roll(interaction: lamma.Interaction, sides: app_commands.Range[int, 2, 100]):
await interaction.response.send_message(f'You rolled a d{sides}', ephemeral=True)
bot.run() # reads LAMMA_TOKEN#Options
| Option | Default | Notes |
|---|---|---|
base_url | LAMMA_URL | Another copy of Lamma to reach, such as a local one. Defaults to Lamma's own address |
intents | required | Which events to receive |
gateway_url | from GET /v1/gateway, or LAMMA_GATEWAY_URL | Set it when your bot reaches Lamma by another address |
max_messages | 1000 | Messages kept, in memory only, for edit and delete events |
allowed_mentions | every mention allowed | The default for every message |
#Coming from discord.py
Most bots port by changing import discord to import lamma as discord, from discord.ext import commands to from lamma.ext import commands, and setting LAMMA_TOKEN. The migration guide has the details.
| discord.py | lamma.py |
|---|---|
discord.Client(intents=...), commands.Bot(...) | The same |
Intents.default(), .message_content, .members, .guilds, .messages, .reactions, .moderation, .expressions | The same. Other flags are accepted, ignored with one warning, and read as False |
Int IDs, guild.get_channel(id), discord.utils.get(..., id=...) | The same. Lookups also take an ID as a string |
TextChannel, VoiceChannel, CategoryChannel, channel.type, guild.text_channels, guild.voice_channels | The same. Bots can post in a voice channel's text chat |
discord.Permissions and its presets, role.permissions, member.guild_permissions, interaction.permissions, interaction.app_permissions | The same |
MessageFlags, PublicUserFlags, MemberFlags, ChannelFlags, RoleFlags, AttachmentFlags, EmbedFlags, SystemChannelFlags, ApplicationFlags, MemberCacheFlags, AppCommandContext and the other flag classes | The same names and bits. Lamma has none of these features, so the flags on messages, users, members, channels and roles are always empty |
app_commands.checks.has_permissions(), bot_has_permissions() | The same, exact for the channel |
commands.bot_has_permissions(), has_guild_permissions(), bot_has_guild_permissions() | The same |
commands.has_permissions() | Uses the author's server-wide permissions, because Lamma doesn't send channel overrides. It warns once |
channel.permissions_for(guild.me) | The same for the bot itself. For anyone else it raises ClientException |
client.run(token), await client.start(token) | The same. run() defaults to LAMMA_TOKEN |
setup_hook, on_ready, on_message, on_message_edit, on_message_delete, on_raw_*, on_guild_join, on_guild_remove, on_interaction | The same |
on_member_join, on_member_update, on_member_remove, on_member_ban, on_member_unban, on_audit_log_entry_create | The same. Timeouts, bans and audit entries need moderation access |
guild.audit_logs(...) | The same. Entries Discord has no action for have action set to None and entry.lamma_action |
channel.send(), message.reply(), edit(), delete(), add_reaction() | The same |
channel.history(), channel.fetch_message() | The same |
guild.fetch_members(), guild.fetch_member() | The same. Needs members.read |
discord.Embed | The same. Images and thumbnails aren't shown yet |
app_commands.CommandTree, @tree.command, describe, choices, Range, Literal | The same |
Option types str, int, float, bool, Member, User, TextChannel, VoiceChannel, Role | The same |
tree.sync(), tree.sync(guild=...) | The same. Global commands appear at once |
interaction.response.send_message(ephemeral=True), defer(), edit_original_response(), followup.send() | The same, within 3 seconds and 15 minutes |
commands.Cog, Cog.listener(), @bot.command(), Context, converters, checks | The same |
await bot.load_extension('cogs.fun') with async def setup(bot), unload_extension(), reload_extension() | The same |
discord.utils.get, find, format_dt, escape_markdown, escape_mentions | The same |
#What's different
- IDs are Lamma IDs, so a Discord ID won't find anything.
channel.permissions_for()only works for the bot itself. Lamma doesn't send channel overwrites to bots, so it raisesClientExceptionfor anyone else rather than guess. Useinteraction.permissionsfor the person who ran a command, ormember.guild_permissionsfor server-wide permissions.- Lamma's Mention roles permission has no Discord flag, so it isn't part of
Permissions. default_permissionsandguild_onlyare accepted but have no effect yet, so checkinteraction.permissionsin your command code.- Channel options aren't limited by type yet. If someone picks a voice channel for a
TextChannelparameter, the command fails withapp_commands.TransformerError. - There are no buttons, views, select menus, modals, autocomplete, context menus or subcommand groups yet.
app_commands.Groupandcommands.GroupCograise so you notice. - Bots can't upload files yet.
discord.Fileworks, butfile=andfiles=are left out of the message with one warning. - Bots can't send DMs, show a status or show typing.
user.send()raisesForbiddenwith code50007, as Discord does for someone with DMs closed.typing()andchange_presence()do nothing. Each logs one warning. - Bots can't kick, ban or time out members yet.
client.fetch_user()only returns people the bot has already seen.- Reaction events are raw only: use
on_raw_reaction_addandon_raw_reaction_remove. - When the connection drops, the client reconnects and
on_readyruns again. There is no resume, so read anything you missed withchannel.history().
See Coming from Discord for everything that differs.