Claude Discord
Self-hostable Claude bots that live in a private Discord server. One process is one bot, with its own token, working directory, persona and conversation state, and several of them in the same guild can hand work to each other.
A Discord guild turns out to be a reasonable place to keep a coding agent. It already has rooms to separate work, clients on every device, and a built-in answer to who is allowed to talk. So one process is one bot: its own Discord application token, its own working directory, its own persona. Inside a channel it keeps a live Claude session rather than starting cold on each message, which is what makes a room read like a conversation instead of a queue of one-shot prompts.
Run more than one instance in the same guild and the server becomes a small workspace of agents. They appear in the member list, mention each other by name, and a bot pulled into a room by a peer answers there. Two of them left alone will keep replying, so a bot-to-bot exchange stops after six consecutive turns, pauses, and pings its owner; any human message resets the count.
How a message becomes a reply
- One process per bot: token, working directory, persona and conversation state all belong to the instance, so adding a second bot is running the same code against a second Discord application.
- Three gates before the model: an integrity check drops the bot's own messages, webhook-forged ones and Discord system messages; a fail-closed allowlist refuses to start without a valid owner user ID; and an engagement rule decides whether a message deserves an answer at all, replying to mentions everywhere, to anything in a channel it has chosen to watch, and to peer bots under a cooldown.
- A live session per channel: each channel holds its own
ClaudeSDKClient. An LRU pool keeps three warm at roughly 190 MB each and tears down the least recently used one under memory pressure, never a session with a turn still running. - It manages its own presence: an in-process MCP server hands the model tools for Discord itself, reading any channel's history, starting and stopping watching channels (the set survives restarts), posting into another room, and creating, renaming, moving or deleting channels.
- Restarts resume, not repeat: recent channel history is replayed and split at a persisted watermark, so everything at or before the last reply is labelled background and only what arrived after it is treated as work. Without the split a restarted bot answered days-old requests instead of the message that tagged it.
- Replies land in the message that announced them: a "working" placeholder is edited into the answer as it arrives, split at Discord's 2,000-character limit and attached as a file past 6,000.
/stopinterrupts the running turn and keeps the session, so the context survives the cancel. - Subscription auth, not an API key: the backend is the Python Claude Agent SDK driving the same
claudeCLI, authenticated with an OAuth token fromclaude setup-token, so turns bill against a Claude plan rather than per-token API credit.
Running your own
Python · discord.py · Claude Agent SDK. Each instance is a single process on a host you control, with an in-process MCP server for the Discord tools; sessions run with permissions bypassed inside the working directory, so that directory is code you are handing to a model.