Skip to main content

A fully-featured Python SDK for building Nerimity bots

Project description

nerimity-sdk

A Python library for building bots on Nerimity.

pip install nerimity-sdk

How it works

You create a Bot, attach handlers to it with decorators, then call bot.run(). The bot connects to Nerimity over a WebSocket, receives events, and dispatches them to your handlers.

Nerimity server
      │
      │  WebSocket (Socket.IO)
      ▼
  GatewayClient          ← receives raw events, puts them in a queue
      │
      ▼
  EventEmitter           ← deserializes events into typed objects, calls your handlers
      │
      ├── @bot.on("message:created")   ← your event listeners
      ├── @bot.command("ping")         ← prefix commands  (!ping)
      ├── @bot.slash("info")           ← slash commands   (/info)
      └── @bot.button("confirm:*")     ← button clicks

Everything your handlers need is in the ctx (Context) object passed to them.


Quickstart

1. Get a bot token

Go to nerimity.com/app/settings/developer/applications, create an application, add a Bot, and copy the token.

2. Scaffold a project

nerimity create my-bot
cd my-bot
cp .env.example .env   # paste your token in here
python bot.py

3. Or start from scratch

# bot.py
import os
from dotenv import load_dotenv
from nerimity_sdk import Bot

load_dotenv()
bot = Bot(token=os.environ["NERIMITY_TOKEN"], prefix="!")

@bot.on("ready")
async def on_ready(me):
    print(f"Logged in as {me.username}#{me.tag}")

@bot.command("ping", description="Replies with Pong!")
async def ping(ctx):
    await ctx.reply("Pong! 🏓")

bot.run()

Core concepts

The Bot object

bot = Bot(
    token=os.environ["NERIMITY_TOKEN"],
    prefix="!",          # prefix for commands like !ping
)

bot.run() is blocking — it connects and stays connected until you Ctrl+C.


Event listeners

Listen to anything happening on Nerimity:

@bot.on("message:created")
async def on_message(event):
    # event is a typed MessageCreatedEvent — not a raw dict
    print(event.message.content)

@bot.on("server:member_joined")
async def on_join(event):
    print(f"{event.member.user.username} joined {event.server_id}")

@bot.on("*")  # wildcard — fires for every event
async def log_everything(event):
    print(event)

Every event is a typed dataclass — you get autocomplete, not event["data"]["user"]["id"] chains.


Prefix commands

Commands triggered by a message starting with your prefix (e.g. !ping):

@bot.command("ping", description="Replies with Pong!")
async def ping(ctx):
    await ctx.reply("Pong!")

With argument convertersctx.args are already the right types:

from nerimity_sdk import Int, MemberConverter

@bot.command("add", description="Add two numbers", args=[Int, Int])
async def add(ctx):
    a, b = ctx.args   # guaranteed ints, friendly error if user types garbage
    await ctx.reply(f"{a} + {b} = {a + b}")

@bot.command("kick", args=[MemberConverter], guild_only=True)
async def kick(ctx):
    member = ctx.args[0]   # a Member object, not a raw string
    if not await ctx.confirm(f"Kick {member.user.username}?"):
        return await ctx.reply("Cancelled.")
    await ctx.rest.kick_member(ctx.server_id, member.user.id)
    await ctx.reply("Done.")

The Context object (ctx)

Every command handler receives a ctx with everything you need:

ctx.author          # User who sent the message
ctx.server          # Server it was sent in (None in DMs)
ctx.channel_id      # Where to reply
ctx.args            # Parsed arguments
ctx.flags           # --flag=value flags
ctx.mentions        # [@:id] mentions resolved to User objects

await ctx.reply("hello")                    # send a message
await ctx.react("👍")                       # react to the message
await ctx.ask("What's your name?")          # wait for a follow-up
await ctx.confirm("Are you sure?")          # yes/no prompt → True/False/None
await ctx.author.send(bot.rest, "Hi!")      # send a DM

Slash commands

Every @bot.command is automatically a slash command — it registers with Nerimity's API and shows in the / menu. No separate handler needed.

@bot.command("ban", description="Ban a user")
async def ban(ctx):
    # works as !ban AND /ban
    ...

To keep a command prefix-only (not in the / menu):

@bot.command_private("debug")
async def debug(ctx):
    await ctx.reply("secret")

@bot.slash is just an alias for @bot.command.


Buttons

from nerimity_sdk import Button

@bot.command("confirm", description="Confirm an action")
async def confirm_cmd(ctx):
    await ctx.reply(
        "Are you sure?",
        buttons=[
            Button(id="yes:confirm", label="✅ Yes"),
            Button(id="no:confirm",  label="❌ No", alert=True),
        ]
    )

@bot.button("yes:{action}")
async def on_yes(bctx):
    await bctx.popup("Done!", f"Confirmed: {bctx.params['action']}")

@bot.button("no:{action}")
async def on_no(bctx):
    await bctx.popup("Cancelled", "Nothing was changed.")

bctx.popup(title, content) shows a modal to the user who clicked. bctx.reply(content) posts in the channel instead.


Error handling

Without error handlers, errors are logged but don't crash the bot. With them, you can send a friendly message to the user:

@bot.on_command_error
async def on_error(ctx, error):
    await ctx.reply(f"❌ {error}")

@bot.on_slash_error
async def on_slash_error(sctx, error):
    await sctx.reply(f"❌ {error}")

@bot.on_button_error
async def on_button_error(bctx, error):
    await bctx.reply(f"❌ {error}")

Plugins

Split your bot into reloadable modules:

# plugins/welcome.py
from nerimity_sdk import PluginBase, listener, mention

class WelcomePlugin(PluginBase):
    name = "welcome"

    @listener("server:member_joined")
    async def on_join(self, event):
        await self.bot.rest.create_message(
            "YOUR_CHANNEL_ID",
            f"👋 Welcome {mention(event.member.user.id)}!"
        )

async def setup(bot):
    await bot.plugins.load(WelcomePlugin())

Load it:

await bot.plugins.load_from_path("plugins/welcome.py")

# Hot-reload without restarting:
await bot.plugins.reload("welcome")

Persistent storage

Save data between restarts:

from nerimity_sdk import JsonStore

bot = Bot(token=..., store=JsonStore("data.json"))

# In any command:
await bot.store.set(f"guild:{ctx.server_id}:prefix", "?")
prefix = await bot.store.get(f"guild:{ctx.server_id}:prefix") or "!"

Swap JsonStore for SqliteStore or RedisStore with no other code changes.


Scheduled tasks

@bot.cron("0 9 * * 1")   # every Monday at 09:00 UTC
async def weekly():
    await bot.rest.create_message("CHANNEL_ID", "Good morning!")

Requires pip install "nerimity-sdk[cron]".


Waiting for events

# Wait for a specific member to join
event = await bot.wait_for(
    "server:member_joined",
    check=lambda e: e.member.user.id == "12345",
    timeout=60,
)

Paginator

For long responses like help menus or leaderboards:

from nerimity_sdk import Paginator

@bot.command("help")
async def help_cmd(ctx):
    pages = bot.router.help_text().split("\n\n")
    await Paginator(pages).send(ctx)

Mention helpers

from nerimity_sdk import mention

mention("123456")          # → "[@:123456]"  (use in messages to ping someone)
ctx.mentions               # list of User objects mentioned in the command message

CLI tools

nerimity create my-bot    # scaffold a new project
nerimity version          # show SDK version
nerimity lint             # check your bot code for common mistakes
nerimity-help             # quick reference in your terminal

Optional extras

pip install "nerimity-sdk[cron]"     # @bot.cron() scheduled tasks
pip install "nerimity-sdk[watch]"    # watch=True auto-reload plugins on save
pip install "nerimity-sdk[sqlite]"   # SqliteStore
pip install "nerimity-sdk[redis]"    # RedisStore

Full docs

https://joddabodscripts.github.io/Nerimity-SDK/


Built by @Lyney:SHOW on Nerimity · JoddabodScripts on GitHub

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nerimity_sdk-0.3.1.tar.gz (60.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nerimity_sdk-0.3.1-py3-none-any.whl (53.8 kB view details)

Uploaded Python 3

File details

Details for the file nerimity_sdk-0.3.1.tar.gz.

File metadata

  • Download URL: nerimity_sdk-0.3.1.tar.gz
  • Upload date:
  • Size: 60.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for nerimity_sdk-0.3.1.tar.gz
Algorithm Hash digest
SHA256 d2291d8de6243f85e7dd83c6bb1973436d0c82ae395945cc419d25c7f7e39912
MD5 ef68aa6c68afa61ec8f82d7f586c9c78
BLAKE2b-256 15f2c86075adc9c683922442f6660528e416289181c67ee601c8a65e4b8ae374

See more details on using hashes here.

File details

Details for the file nerimity_sdk-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: nerimity_sdk-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 53.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for nerimity_sdk-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fd2cfba7f992d8e64f5926d623064de860ca89b08a85e4f1e799be7c9dbca159
MD5 8032f09d4d69897d90bf99efa6b21d61
BLAKE2b-256 6b561b9f585f19acab853a5eb454a8df248c0a8efb7ac84a92260bba5475deff

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page