Discord
Give your agent a presence in a Discord server. It reads messages and replies through the same on_message handler as every other channel. Discord is free: no signup, no paid credit.
Three ways to connect
Pick based on how much branding you want and whether you want to create a bot:
| Method | What you get | Setup |
|---|---|---|
install_discord() |
Shared bot, two-way. Your custom name per server, shared avatar. | One click, no token. |
connect_discord(bot_token=…) |
Your own bot, two-way. Your own name and avatar. | ~5 min at discord.com/developers. |
connect_discord(webhook_url=…) |
Per-agent identity that posts to one channel. Outbound only, no bot. | Paste a channel webhook URL. |
A bot (the first two) can receive messages and reply, so on_message fires. A webhook is send-only: great for a distinct name and avatar per agent, but nothing routes back to your handler.
Option A: one-click shared bot
The fastest path. Caspian runs a shared Discord bot; install_discord() returns a connection with an authorize_url. Open that URL, pick a server, and authorize. The shared bot joins, takes the name you passed, and messages in that server reach your agent. No token to create.
from caspian_sdk import CommClient
client = CommClient()
conn = client.install_discord(display_name="Acme Support")
print("Authorize the bot here:", conn["authorize_url"])
# Open the link, choose your server, click Authorize.
@client.on_message
def handle(message):
message.reply(f"You said: {message.text}")
client.listen()import { CommClient } from "caspian-sdk";
const client = new CommClient();
const conn = await client.installDiscord({ displayName: "Acme Support" });
console.log("Authorize the bot here:", conn.authorize_url);
// Open the link, choose your server, click Authorize.
client.onMessage(async (message) => {
await message.reply(`You said: ${message.text}`);
});
await client.listen();The authorize flow
install_discord() returns immediately with the connection in a pending state. Hand the authorize_url to whoever owns the server:
- They open the link, Discord shows a server picker, they choose one and click Authorize.
- The shared bot joins that server and is renamed to your
display_namethere (a per-server nickname). - The connection flips to
activeon its own, no extra call. Messages in that server then hiton_message, andmessage.reply()answers in Discord.
display_name sets the bot's name; the avatar stays the shared one. Want your own avatar too? Use Option B.
Always set display_name to a name that fits the server. Never leave it as an infra name. If install_discord() returns a 400, the shared bot isn't configured on this gateway; use your own bot (Option B). A 409 on the callback means that server is already linked to another agent.
Option B: bring your own bot
For a fully branded bot with your own name and avatar. Create one at discord.com/developers, then pass its token to connect_discord().
- New Application → give it a name.
- Open the Bot tab → Reset Token → copy the token.
- Under Bot settings, enable Message Content Intent. Without it Discord strips message text and your agent sees empty inbound messages.
- Invite the bot to your server from the OAuth2 tab.
Message Content Intent is required for inbound. If it's off, the bot connects but every message arrives with no text. Enable it under Bot settings before connecting.
from caspian_sdk import CommClient
client = CommClient()
client.connect_discord(bot_token="MT2...your-bot-token")
@client.on_message
def handle(message):
message.reply(f"You said: {message.text}")
client.listen()import { CommClient } from "caspian-sdk";
const client = new CommClient();
await client.connectDiscord({ botToken: "MT2...your-bot-token" });
client.onMessage(async (message) => {
await message.reply(`You said: ${message.text}`);
});
await client.listen();A 409 means that bot token is already connected to another agent. Create a separate bot or use a different token.
Option C: channel webhook (no bot)
A Discord channel webhook lets your agent post to one channel under its own name and avatar, with zero bot setup. This is outbound only: the webhook can send but not receive, so on_message does not fire. Use it when you want a distinct per-agent identity for notifications or announcements.
In Discord: Server Settings → Integrations → Webhooks → New Webhook → Copy Webhook URL. Then:
client.connect_discord(
webhook_url="https://discord.com/api/webhooks/123/abc",
username="Acme Bot",
avatar_url="https://example.com/acme.png",
)await client.connectDiscord({
webhookUrl: "https://discord.com/api/webhooks/123/abc",
username: "Acme Bot",
avatarUrl: "https://example.com/acme.png",
});username and avatar_url set the identity each post appears under. Different agents can share one channel while each keeping its own face.
Rename after connecting
Change the shared bot's per-server nickname later without re-installing:
client.update_branding(conn["id"], display_name="Acme Helper")await client.updateBranding(conn.id, { displayName: "Acme Helper" });On long jobs, show a typing indicator with message.thinking() (Python) / message.thinking() (JS). Discord and Telegram render it, and it's a no-op elsewhere. Pull Discord etiquette into your system prompt with client.behavior_prompt().