dkit
An offline toolbox for Discord bot developers.
dkit decodes snowflake IDs, translates permission and gateway-intent bitfields
in both directions, and builds OAuth2 invite URLs — from your terminal, with no
network access and no bot token.
$ dkit snowflake 175928847299117063
175928847299117063
Created 2016-04-30T11:18:25.796Z
Unix ms 1462015105796
Discord ms 41944705796
Worker ID 1
Process ID 0
Increment 7
Why dkit?
Every Discord bot developer hits the same small, annoying questions. When was
this user created? Which permissions are in 274878286912? What integer do I
pass for these three intents? Why is the gateway closing my connection with
4014?
The usual answers are a random web calculator, a REPL session with a bitshift
you half-remember, or a scroll through the docs. dkit answers them in one
command instead, and it does so:
- Entirely offline. No network calls, ever.
dkitnever asks for a bot token, so you can safely run it on a shared machine or paste its output into an issue. - Honestly sourced. Every bit position lives in a JSON data file that records the official documentation URL it came from and the date it was last verified. Nothing is remembered from folklore — see Data and provenance.
- Dependency-free. Standard library only, so
pip install dkit-clipulls in nothing else and nothing breaks next year. - Scriptable.
--jsonon any command gives you machine-readable output with stable keys, and exit codes you can branch on. - Correct about big numbers. Permissions already exceed 32 bits and are
approaching 64.
dkituses Python's arbitrary-precision integers throughout and emits permission values as JSON strings, exactly as the Discord API does, so nothing is silently truncated by a 53-bit float somewhere downstream.
Install
Requires Python 3.10 or newer.
pip install dkit-cli
From a checkout:
git clone https://github.com/Bytewave1/dkit
cd dkit
pip install .
Both give you a dkit command. You can also run it as python -m dkit.
Usage
$ dkit --help
usage: dkit [-h] [--json] [--no-color] [--version] <command> ...
An offline toolbox for Discord bot developers.
positional arguments:
<command>
snowflake decode snowflake IDs, or build one from a date
perms decode a permissions integer, or build one from names
invite build an OAuth2 invite URL for your bot
intents convert gateway intent names to the integer and back
options:
-h, --help show this help message and exit
--version print the version and exit
global options:
--json print machine-readable JSON instead of text
--no-color disable ANSI colors (also honours the NO_COLOR environment
variable)
Every command works entirely offline: dkit never performs network requests
and never asks for a bot token.
run 'dkit <command> --help' for the options of a single command
Global flags
| Flag | Effect |
|---|---|
--json |
Print machine-readable JSON instead of text |
--no-color |
Disable ANSI colors (NO_COLOR is honoured too) |
--version |
Print the version and exit |
Global flags work on either side of the command name: dkit --json perms 8 and
dkit perms 8 --json are equivalent.
Exit codes
| Code | Meaning |
|---|---|
0 |
Success |
2 |
Usage error or invalid input |
Warnings (privileged intents, ADMINISTRATOR, unrecognised bits) go to
stderr in text mode and into the warnings array in --json mode, so
stdout always stays parseable.
dkit snowflake — decode IDs, or build one from a date
$ dkit snowflake 175928847299117063
175928847299117063
Created 2016-04-30T11:18:25.796Z
Unix ms 1462015105796
Discord ms 41944705796
Worker ID 1
Process ID 0
Increment 7
Several IDs at once, and hexadecimal input, both work:
$ dkit snowflake 175928847299117063 80351110224678912
The reverse direction gives you the lowest snowflake for a point in time, which
is what you want for before/after pagination:
$ dkit snowflake --from-date 2016-04-30T11:18:25Z
2016-04-30T11:18:25.000Z
Snowflake 175928843960320000
Unix ms 1462015105000
Discord ms 41944705000
lowest snowflake for this millisecond (worker, process and increment are all zero)
Timestamps are ISO-8601. A trailing Z is accepted, an explicit offset such as
+02:00 is respected, and a timestamp without an offset is read as UTC.
dkit perms — permissions integer ↔ names
$ dkit perms 274878286912
Permissions 274878286912
hex 0x000000400005cc40 (8 of 52 known permissions)
ADD_REACTIONS 0x0000000000000040 [T/V/S]
VIEW_CHANNEL 0x0000000000000400 [T/V/S]
SEND_MESSAGES 0x0000000000000800 [T/V/S]
EMBED_LINKS 0x0000000000004000 [T/V/S]
ATTACH_FILES 0x0000000000008000 [T/V/S]
READ_MESSAGE_HISTORY 0x0000000000010000 [T/V/S]
USE_EXTERNAL_EMOJIS 0x0000000000040000 [T/V/S]
SEND_MESSAGES_IN_THREADS 0x0000004000000000 [T]
[T/V/S] are the channel types the permission applies to (Text, Voice, Stage);
[2FA] marks permissions that require the server owner to have two-factor
authentication enabled when server-wide 2FA is on.
And the other way around:
$ dkit perms --names SEND_MESSAGES,MANAGE_ROLES
Permissions 268437504
hex 0x0000000010000800
SEND_MESSAGES 0x0000000000000800 [T/V/S]
MANAGE_ROLES 0x0000000010000000 [2FA, T/V/S]
Names are case-insensitive, and typos get a suggestion rather than a shrug:
$ dkit perms --names SEND_MESSAGE
error: unknown permission name: 'SEND_MESSAGE'
did you mean SEND_MESSAGES, SEND_TTS_MESSAGES or SEND_VOICE_MESSAGES?
$ echo $?
2
dkit invite — build an OAuth2 invite URL
$ dkit invite --client-id 157730590492196864 \
--perms SEND_MESSAGES,EMBED_LINKS,READ_MESSAGE_HISTORY
Invite URL
https://discord.com/oauth2/authorize?client_id=157730590492196864&scope=bot%20applications.commands&permissions=83968
Client ID 157730590492196864
Scopes bot, applications.commands
Permissions 83968
- SEND_MESSAGES
- EMBED_LINKS
- READ_MESSAGE_HISTORY
- The client ID must be numeric; anything else is rejected before a URL is built.
--permstakes names or an integer.--scopesdefaults tobot,applications.commandsand is validated against the official scope list, with suggestions for near-misses.- Scopes are joined with
%20, matching the documented encoding.
dkit intents — intent names ↔ integer, with privileged warnings
$ dkit intents GUILDS,GUILD_MESSAGES,MESSAGE_CONTENT
Intents 33281
hex 0x8201 (3 of 21 known intents)
GUILDS 1 << 0 21 events
GUILD_MESSAGES 1 << 9 4 events
MESSAGE_CONTENT 1 << 15 no events [privileged]
Privileged intents in this value:
- MESSAGE_CONTENT
These must be enabled for your application in the Discord Developer Portal
(https://discord.com/developers/applications) under Bot -> Privileged Gateway Intents
before they can be passed in IDENTIFY. Passing one that is not enabled
closes the gateway connection with close code 4014.
Apps above 10,000 users additionally need approval to keep using them.
The same command decodes an integer — it detects which direction you meant:
$ dkit intents 33281
The three privileged intents are GUILD_MEMBERS, GUILD_PRESENCES and
MESSAGE_CONTENT. MESSAGE_CONTENT is listed with "no events" because it
gates message content across the API rather than mapping to gateway events.
JSON output
$ dkit --json perms --names SEND_MESSAGES,MANAGE_ROLES
{
"value": "268437504",
"hex": "0x0000000010000800",
"bit_count": 2,
"permissions": [
{
"name": "SEND_MESSAGES",
"bit": 11,
"value": "2048",
"hex": "0x0000000000000800",
"description": "Allows for sending messages in a channel and creating threads in a forum (does not allow sending messages in threads)",
"channel_types": ["T", "V", "S"]
},
{
"name": "MANAGE_ROLES",
"bit": 28,
"value": "268435456",
"hex": "0x0000000010000000",
"description": "Allows management and editing of roles",
"channel_types": ["T", "V", "S"],
"requires_2fa": true
}
],
"names": ["SEND_MESSAGES", "MANAGE_ROLES"],
"unknown_bits": [],
"warnings": [],
"source": {
"source": "https://github.com/discord/discord-api-docs/blob/main/developers/topics/permissions.mdx",
"source_rendered": "https://discord.com/developers/docs/topics/permissions",
"last_verified": "2026-10-20"
}
}
Every payload carries the source of the data it used, so output pasted into a
bug report says where its numbers came from. unknown_bits is non-empty when a
value contains a bit dkit has no name for yet — a good sign the data file
needs refreshing.
Data and provenance
No Discord constant is hard-coded in logic. They all live in
src/dkit/data/:
| File | Contents | Official source |
|---|---|---|
permissions.json |
52 permission flags, bits 0–52 | topics/permissions |
intents.json |
21 gateway intents, privileged flags, associated events | events/gateway |
snowflake.json |
Discord epoch and the snowflake bit layout | reference#snowflakes |
oauth2.json |
Authorization URL and the 29 OAuth2 scopes | topics/oauth2 |
Each file records a source URL and a last_verified date. Two details worth
knowing, both faithful to the official tables:
- Permission bit 47 is unassigned and is intentionally absent.
- Intent bits 17–19 and 22–23 are unassigned and are intentionally absent.
Values are stored as bit positions; dkit derives each value as 1 << bit,
and the test suite asserts that the hex field in each file agrees with its
bit. See CONTRIBUTING.md for how to
refresh them.
Contributing
Contributions are very welcome, and the project is deliberately easy to extend: adding a command means adding one file and registering it in one place.
git clone https://github.com/Bytewave1/dkit
cd dkit
pip install -e ".[dev]"
python -m pytest # 150 tests
ruff check . && ruff format --check .
- CONTRIBUTING.md walks through adding a command and updating the data files.
- docs/ISSUES.md has eight ready-to-file "good first issue" ideas if you want somewhere to start.
Please keep the two ground rules: no runtime dependencies, and no network access at runtime.
License
MIT.
dkit is an unofficial tool and is not affiliated with or endorsed by Discord.
"Discord" is a trademark of Discord Inc.
Metadata
Release files for dkit-cli 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| dkit_cli-0.1.0.tar.gz | 45.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dkit_cli-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 76.5 kB
Release files / dkit_cli-0.1.0.tar.gz
| Download URL | dkit_cli-0.1.0.tar.gz |
|---|---|
| Size | 45.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3923e6e71a08ff80cb699dbcb3759b0ea2d6f97131d1de3e0778318a78ea566a
|
|
BLAKE2b-256 checksum How to use checksums |
1b2740b0ebded40daacea4702dff4277859c39f099d871d219d9ffe397f4cd95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Release files / dkit_cli-0.1.0-py3-none-any.whl
| Download URL | dkit_cli-0.1.0-py3-none-any.whl |
|---|---|
| Size | 31.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
503e96045da6fb5d05eb79906398bfa35103a52a75a3f4009d07367ad02a4bc9
|
|
BLAKE2b-256 checksum How to use checksums |
e520d910a77df7ff5cc89fdd1397260c81e16d6c9c69681e11507ca536d55799
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Security for dkit-cli 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.