OpenShockBot is a safety-focused, self-hostable Discord bot for controlling OpenShock shockers. It is an independent community project and is not affiliated with or endorsed by OpenShock.
Warning
OpenShock controls physical hardware. Use this software only with informed, ongoing consent. Configure conservative limits, keep a physical emergency stop accessible, and follow the OpenShock safety rules.
/openshock shock,vibrate,sound, and safety-orientedstopcommands- Independently configurable reaction controls on messages from linked targets: ⚡ shock, 🌊 vibrate, 🔊 sound
- Per-target pause state
- Personal block and allow rules
- Central-account onboarding for multiple consenting Discord targets
- Open-to-everyone and allow-list access modes
- Per-actor/per-target cooldowns
- Bot-wide and per-target intensity/duration ceilings
- Self-service safety limits, per-reaction toggles/defaults, and cooldown configuration
- SQLite audit log of sent, denied, and failed controls
- Private recent-activity history
- Async OpenShock API access
- Secrets loaded from environment variables, never from tracked configuration
This is an alpha. Persistent button panels, context menus, presets, and reaction aggregation are planned next; see the roadmap.
- Python 3.11 or newer
- A Discord application and bot token
- An OpenShock API token
- An OpenShock shocker UUID
- Open the Discord Developer Portal and create an application named OpenShockBot.
- Open Bot, create the bot if needed, and copy its token into
DISCORD_BOT_TOKENin.env. Never paste that token into chat, an issue, or a commit. - Enable Developer Mode in Discord under User Settings → Advanced. Right-click your user and
choose Copy User ID; put it in
BOT_OWNER_IDS. - Under OAuth2 → URL Generator, select the
botandapplications.commandsscopes. - Give the bot
View Channels,Send Messages,Read Message History, andAdd Reactions. - Open the generated URL and add the bot to your server.
OpenShockBot does not need Discord's privileged Message Content intent.
- Create a dedicated central OpenShock account for the bot operator.
- In the OpenShock web app, create an API token under Settings → API Tokens.
- Copy it into
OPENSHOCK_TOKENin.env. - For the first target, either set
DEFAULT_TARGET_DISCORD_IDandDEFAULT_SHOCKER_IDin.env, or use the consent-based linking flow after the bot starts.
Do not collect users' OpenShock API tokens in Discord. Instead, each additional target creates an OpenShock share code for the central account. The operator redeems it in the OpenShock web app, then runs:
/openshock links
/openshock link target:@member shocker_id:<choose an owned or shared shocker>
The target receives a DM and must run /openshock accept-link. They may decline with
/openshock decline-link, and either the target or a bot owner can later use /openshock unlink.
New consented links begin paused and allow-list-only, with shock reactions disabled. The target
reviews /openshock status, configures their access rules, and explicitly resumes when ready.
Reactions on a linked member's Discord messages resolve through that message author, so each
member's reaction controls reach only their own assigned shocker.
OpenShock owners retain their server-side share limits, pause control, and ability to revoke the share. OpenShockBot also revalidates central-account access before activating a pending link.
For a simple single-user setup:
- Copy the first shocker's UUID.
- Set
DEFAULT_TARGET_DISCORD_IDandDEFAULT_SHOCKER_IDin.env.
Do not commit the API token. OpenShock requires applications to send a meaningful User-Agent;
the default is set in .env.example.
git clone https://github.com/YOUR-USERNAME/OpenShockBot.git
cd OpenShockBot
cp .env.example .env
# Edit .env with your private values.
python -m venv .venv
source .venv/bin/activate
pip install -e .
openshockbotSlash commands registered globally can take a little while to appear after the bot's first start.
The repository includes a hardened user-level systemd unit for the checkout location used by this server.
mkdir -p ~/.config/systemd/user
ln -s ~/Documents/OpenShockBot/deploy/openshockbot.service \
~/.config/systemd/user/openshockbot.service
systemctl --user daemon-reload
systemctl --user enable --now openshockbot
systemctl --user status openshockbotFollow live logs with:
journalctl --user -u openshockbot -fIf the bot must continue after the account logs out, an administrator can enable lingering once:
sudo loginctl enable-linger "$USER"After changing .env, restart with systemctl --user restart openshockbot.
- Keep the OpenShock physical emergency stop accessible and leave the shocker unworn.
- Start the bot and wait for its log to say that it logged into Discord.
- In Discord, run
/openshock statusand confirm your personal ceilings, cooldown, and access mode. - Run
/openshock soundagainst your linked Discord user. Confirm the intended shocker beeps. - Run
/openshock vibrateat the lowest practical intensity and minimum duration while the shocker is still unworn. - Test
/openshock pause, a blocked user, cooldown behavior, and/openshock stopbefore any worn use.
Do not begin with a shock command. Any later worn test should use explicit consent and the lowest personal limits that can verify operation.
Each linked Discord user owns their target configuration:
everyone: anyone may control the target except personally blocked users.allowlist: only explicitly allowed users may control the target.- The target may pause itself at any time.
- A
stoprequest is always accepted by the bot for a linked target, including while paused. - Effective intensity and duration are the lowest applicable bot-wide and target-specific limits.
Reaction controls use the target's stored per-action intensity and duration. A reaction only triggers when it is newly added; Discord does not generate another add event while the same reaction remains.
Each reaction type has an independent toggle, intensity, and duration. Configure one with:
/openshock reaction-config action:Shock enabled:False intensity:1 duration:0.3
New and migrated targets have shock reactions disabled at 1% for 0.3 seconds until the target explicitly enables them. Sound and vibrate inherit the previous reaction defaults during migration. The shared cooldown, access rules, pause state, and personal and bot-wide safety ceilings apply to every reaction type.
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
ruff check .
ruff format --check .
mypy
pytestSee CONTRIBUTING.md before opening a pull request. Security issues involving tokens, authorization bypasses, or unsafe control behavior should follow SECURITY.md.
MIT. Contributions are welcome.