Discord Nadeshot is a high-performance, modular Discord bot framework built from scratch. It offers powerful features for managing commands, events, and tasks with a flexible architecture, ideal for collaborative development and control over every aspect of your bot’s behavior.
- Object-Oriented Design: Each command and task is isolated in its own file, promoting clean, modular, and maintainable code.
- Asynchronous Multi-Threading: Supports asynchronous tasks that run at scheduled intervals without impacting performance.
- Event-Driven Architecture: Built-in support for easy-to-use events, making it simple to extend functionality.
- Advanced Command Handling: Includes support for typed arguments and structured command parsing.
- Middleware Integration: Middleware support for adding pre/post-execution logic to commands and tasks.
- Authorization System: Fine-grained authorization control over who can run specific commands.
If you're looking for a solution that makes building modular, extensible Discord bots simple, while giving you full control over the architecture and functionality, Discord Nadeshot is the framework for you. Say goodbye to constraints imposed by pre-built libraries—this framework gives you complete freedom to design your bot without restrictions.
You can set up Discord Nadeshot either by installing it locally or using Docker for a production-like environment. Docker is the recommended option for ease of use and consistent deployment.
- Clone the repository:
git clone <repository-url>
- Install the required dependencies:
pip install -r requirements.txt
- Configure your environment:
- Modify the
.env
file based on the.env_sample
template.
- Modify the
- Configure your environment:
- Modify the
.env
file based on the.env_sample
template.
- Modify the
- Build and run the project using Docker:
docker-compose up --build
After setting up, you can further tweak your bot's settings by editing the config/bot.json
file. Here’s a basic configuration:
{
"config": {
"bot-name": "Nadeshot",
"bot-listens-to": "/nade",
"bot-description": "Run /nade help for a full list of commands",
"enable-reset-cooldowns": true,
"enable-cooldowns": true,
"cooldown-duration": 15,
"enable-global-errors": true,
"enable-automatic-command-helper": false,
"development-mode": true,
"enable-multiple-bots": false
}
}
Key | Description | Example Value |
---|---|---|
bot-name | The name of the bot as it appears to users. | "Nadeshot" |
bot-listens-to | A specific command or keyword the bot listens for as its primary interaction point. | "/nade" |
bot-description | A short description or helper message for users. | "Run /nade help for a full list of commands" |
enable-reset-cooldowns | Allows resetting command cooldowns if enabled. Works on par with utils/cooldown_immune.py |
true |
enable-cooldowns | Enables cooldowns for commands to prevent spamming. | true |
cooldown-duration | Duration of the cooldown (in seconds). | 15 |
enable-global-errors | Enables global error handling to notify users of issues. | true |
enable-automatic-command-helper | Automatically provides helper messages for commands. | false |
development-mode | Enables development mode for debugging and testing. | true |
enable-multiple-bots | Allows running multiple instances of the bot. | false |
To speed up development, the framework includes a built-in boilerplate generator for both commands and tasks. This allows you to create new features without starting from scratch.
To generate a new command:
py bin/console.py generate-command my-command-name/sub-command-name
py bin/comsole.py generate-cmmand --name my-new-command/some-sub-command --prefix !
To generate a new task:
py bin/console.py generate-task my-task-name
The generated files will be placed in:
- Commands:
commands
->config/commands.json
- Tasks:
tasks
->config/tasks.json
To generate a new middleware
py bin/console.py generate-middleware my-middleware before
py bin/console.py generate-middleware my-middleware after
The generated files will be placed in:
- Middlewares:
middlewares
This is found ins config/commands.json
"commands": {
"firewall": {
"commands": {
"RevokeAll": {
"syntax": "/firewall revoke-all",
"description": "Forces the system to revoke all invites across servers.",
"filePath": "firewall/RevokeAll.py",
"authorization": ["admin"],
"hasValue": false,
"slashCommand": false,
"middlewares": ["before_force_dm"],
"arguments": {
"help": {
"required": false,
"hasValue": false
},
"list": {
"required": false,
"hasValue": false
},
"server": {
"required": false,
"hasValue": true,
"minLength": 3,
"maxLength": 40,
"type": "integer"
}
}
}
}
}
}
This is found in config/tasks.json
"tasks": {
"LogServerIfNotExist": {
"file_name": "log_server_if_not_exist.py",
"class_name": "LogServerIfNotExist",
"hours": 0,
"minutes": 30,
"seconds": 0,
"enabled": true
}
}
Middlewares in Discord Nadeshot
act as pre- or post-execution hooks for commands and tasks, similar to middleware in HTTP request handling.
- Before Middleware: Runs before the command is executed. If it returns false, the command won’t run.
- After Middleware: Runs after the command is executed, regardless of the result.'
Middlewares are defined in the middlewares
block of the command configuration in config/commands.json
. Files are prefixed with before_
or after_
to clarify when they are run.
"middlewares": ["before_force_dm", "after_log_execution"]
When defining commands, you can specify various types of arguments for fine control over user inputs. Arguments in Discord Nadeshot can be configured with properties like required status, type, and constraints such as minimum or maximum length. Below are the common properties you can define for each argument:
-
required (boolean): Specifies whether the argument is mandatory.
-
hasValue (boolean): Determines if the argument requires a value or can be a flag.
-
minLength (integer): Sets the minimum length for string arguments.
-
maxLength (integer): Sets the maximum length for string arguments.
-
type (string): Defines the type of the argument. Supported types include:
- integer: A whole number.
- string: A sequence of characters.
- float: A true or false value.
- boolean: Refers to a Discord user (by mention or ID).
- array: Refer to an array
-
accepts (array): Defines a list of values that can be provided
Here’s how you would define arguments for a command in the commands.json
file:
"commands": {
"exampleCommand": {
"syntax": "/example command",
"description": "A sample command with arguments",
"filePath": "exampleCommand.py",
"authorization": ["admin"],
"hasValue": false,
"slashCommand": true,
"middlewares": ["before_validate"],
"arguments": {
"user": {
"required": true,
"hasValue": true,
"type": "user"
},
"count": {
"required": false,
"hasValue": true,
"type": "integer",
"minLength": 1,
"maxLength": 100
},
"verbose": {
"required": false,
"hasValue": false,
"type": "boolean"
},
"elements": {
"type": "array",
"required": true,
"accepts": [
"pc",
"psn",
"xbox"
]
}
}
}
}
There are several other components that can be used to manipulate responses, handle discord object data, interact with the API directly, handle environment variables, interact with redis and so on.
-
- Contains the code that is getting run each time you add the
authorization
directive in yourconfig/commands.json
. Additional database logic can be used in here
- Contains the code that is getting run each time you add the
-
- Contains a class which you can tap in if you wish to setup personalized cooldowns for your users
-
- Contains a class which gets called during errors. This can be used to actually tap into errors and do something with them
-
- This is my custom implementation for reading environment variables. I wanted something that has 0 dependencies and supports a few more features than traditional packages
-
- This is a HTTP Request Wrapper that interacts with Didscord's RESTful API. This was implemented as a necessitiy, since the concurrent task mechanism boots up new threads, we cannot hook into the traditional async / await main thread. Therefore, we must run them in sync and not async.
-
- A class I built to interact with redis. It's useful for storing data, queueig, dequeueing data
-
- This is nothing more than a wrapper around python's std logger, but with color coding and custom structure.
-
- This is a class that will sync responses to each user avoiding overlapping responses for multiple commands. You should not use self.ctx.response, instead, use Synced.
-
- Nothing more than a wrapper used for the Guild object. It serves as an elegant way to get data from it.
-
- A Wrapper for the Member object. Provides getters.
-
- A wrapper for the Message Object. Provides getters.
-
- A wrapper for the User object. Provides getters.
-
- A wrapper for the User object coming from context.
-
- A wrapper for the Guild / Server object from context.
Discord’s restrictions on Intents
for verified apps and other limitations make it challenging to deploy large-scale bots efficiently. To address this, I implemented a multi-bot system that allows multiple bot variants to coexist in servers without overlapping or redundant command handling.
- Homebase Concept: A primary bot serves as the main handler for commands in a specified server (homebase).
- Secondary Variants: Additional bot variants can be invited to servers as needed without all bots responding to the same command simultaneously.
This ensures a clean and efficient command structure while allowing multiple bot instances to exist in the same environment.
-
Obtain Additional Tokens:
- Acquire multiple bot tokens to deploy multiple variants.
-
Deploy Bot Variants:
- Deploy each bot instance using its unique token.
-
Configure Multi-Bot Settings:
- Add your configuration to
config/multi-bot.json
(see example below). - Enable the
enable_multiple_bots
option inconfig/bot.json
.
- Add your configuration to
-
Environment Setup:
- Define each bot's
BOT_VARIANT
in its environment (e.g.,.env
file). - Deploy each bot instance into its container or environment.
- Define each bot's
Heres an example of how to structure your multi-bot.json
file:
{
"servers": [
{
"server_id": 1167179502175137813,
"bot-variants": {
"primary": "BOT_VARIANT_ENV_VALUE_FROM_ENV",
"others": [
"OTHER_BOT_VARIANT_ENV_VALUE_FROM_ENV",
"SECOND-VARIANT",
"THIRD-VARINT"
]
}
}
]
}
Explanation:
-
server_id
: The unique identifier for the Discord server where this configuration applies. Each Discord server (guild) has a distinctserver_id
that allows bots to recognize and interact with it appropriately. -
bot-variants.primary
: Specifies the bot variant designated as the primary handler for commands in the specified server. This bot will actively process commands, ensuring that only one bot responds to user inputs, preventing command overlap. This value is equal to the ENV Value:BOT_VARIANT
-
bot-variants.others
: Lists the bot variants present in the server that should not process commands. These bots will remain in the server but will ignore command inputs, allowing for their presence without causing interference or duplicate responses. These values are equal to the ENV Values:BOT_VARIANT
Please go ahead and explore. There are more things that can be done. If you cannnot do something, just go ahead and open up an issue.