Skip to main content

waken-discord

CI License: MIT

Discord Source/Output for Waken -- "nginx for AI agents." Unlike a Target adapter (waken-claude, waken-gemini, ...), Discord here is a channel: DiscordSource turns incoming Discord messages into waken Events, and DiscordOutput posts a Target's Response back to the channel it came from.

Install

pip install waken-discord

Needs a Discord bot application (Discord Developer Portal -> New Application -> Bot):

  • DISCORD_BOT_TOKEN -- the bot token from the Bot page.
  • The Message Content privileged gateway intent, enabled on that same Bot page (under "Privileged Gateway Intents"). This is a real, commonly missed step -- without it, Discord silently delivers every message with content as an empty string (except direct @mentions of the bot), no matter what the bot process itself requests.
  • The bot invited to your server with, at minimum, the bot scope and the Send Messages/Read Message History permissions.

Usage

from waken import Runtime
from waken_claude import ClaudeAdapter
from waken_discord import DiscordOutput, DiscordSource

runtime = Runtime()
runtime.target("claude", ClaudeAdapter())
runtime.source("discord", DiscordSource(target="claude"))
runtime.output("discord", DiscordOutput())
runtime.run()

DiscordSource/DiscordOutput both resolve DISCORD_BOT_TOKEN from the environment by default, or accept it as a constructor argument. Every incoming message becomes an Event(source="discord", target="claude", payload={"prompt": text}, session_id=runtime.session("discord", external_key=str(channel_id)), metadata={"channel_id": channel_id}) -- follow-up messages in the same channel resume the same waken session. DiscordOutput reads event.metadata["channel_id"] back off to know where to send the reply.

Messages from bots -- including DiscordOutput's own replies -- are filtered out before dispatch, otherwise a reply posted back into the channel would re-trigger DiscordSource and loop forever.

Design notes

A gateway connection for DiscordSource, REST-only for DiscordOutput. Discord bots receive messages over a persistent gateway WebSocket -- there's no webhook equivalent of "a message was posted" a bot can subscribe to instead, so DiscordSource holds that connection open, the same shape as waken-slack's Socket Mode connection: a background task started in start(), closed in stop().

Sending a message, however, is a plain REST call authenticated by the bot token -- it needs no gateway connection at all. DiscordOutput doesn't spin up a second discord.Client (which would mean logging in twice and paying for a connection it'd never use) to get one. Instead it talks directly to discord.http.HTTPClient, the lightweight, gateway-free HTTP client that discord.py itself builds internally and hangs every Client's own REST calls off of. It isn't re-exported from discord/__init__.py or documented as public API the way discord.Client is, but it's the only thing the library ships that fits "REST send, no gateway" -- there's no separate public discord.RESTClient. It ships under the same py.typed package as everything else, so it stays fully type-checked here regardless.

discord.Client.start(), not .run(). Client.run() is documented as "a blocking call that abstracts away the event loop initialisation from you" and calls asyncio.run(...) itself -- it wants to own the whole process's event loop, the same way Client.run()/SlackSource's SocketModeHandler.start_async() would. waken's Runtime already owns the loop this Source runs inside, so DiscordSource.start() instead schedules the lower-level client.start(token) coroutine (a shorthand for login() + connect(), and just a plain coroutine with no loop management of its own) as a background asyncio.Task, and awaits client.close() + that task on stop() -- the recipe discord.py itself documents for running inside an already-running event loop.

Why discord.py, not one of its forks. discord.py went through a period of being unmaintained a few years back, which is what spawned pycord/nextcord/disnake in the first place -- but it later resumed active maintenance, and remains, by a wide margin, the most widely used library in this space (checked directly against all three forks' PyPI release cadence and GitHub activity before picking it, not from memory).

Development

git clone https://github.com/WakenHQ/waken-discord
cd waken-discord
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest

Tests mock discord.py's Client and discord.http.HTTPClient entirely -- no network access, real gateway connection, or Discord bot token needed to run the suite.

License

MIT

Metadata

Release files for waken-discord 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for waken-discord 0.1.0
File Size Uploaded
waken_discord-0.1.0.tar.gz 10.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for waken-discord 0.1.0
File Interpreter ABI Platform
waken_discord-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 19.0 kB

Release files / waken_discord-0.1.0.tar.gz

Download URL waken_discord-0.1.0.tar.gz
Size 10.3 kB
Tags Source
SHA-256 checksum
How to use checksums
13dc275e4fcdf1f9245ff412027d4698d9b95daacb238e253d7a51338aecfed4
BLAKE2b-256 checksum
How to use checksums
79134494c8d4d4d917500dd7a4ab4fd613a702fbf273ac47d8313313d018beb2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / waken_discord-0.1.0-py3-none-any.whl

Download URL waken_discord-0.1.0-py3-none-any.whl
Size 8.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ec6b795bdda11cc85f5acb343d1a9adfd07d71a14b30ffc59267213e707578c8
BLAKE2b-256 checksum
How to use checksums
a5f0c968a3c89cb378d61b9c371da524466abc3cfebbcbc47002f45207e457eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page