Skip to content
yor42Public

About

A Discord LLM chat bot that supports any OpenAI compatible API (OpenAI, xAI, Mistral, Groq, OpenRouter, Ollama, LM Studio and more)

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

663 Commits

Folders and files

Repository files navigation

llmcord

A Discord character bot for small group skits. Channels can belong to a world or a hub. Worlds have their own lore and home characters; a hub can invite characters from selected worlds without mixing their private world lore. Every channel can add local lore and a cast. Threads inherit their parent channel's space and lore, while keeping their own cast and conversation branches.

Documentation

Start with the documentation index. It links to getting started, the server guide, lore and memory, Raspberry Pi deployment, architecture, and verification.

GitHub CI and container releases explains automatic Python/browser/security checks, native ARM64/AMD64 container verification, weekly dependency updates, and publishing versioned images to GHCR.

Set up

For native Raspberry Pi hosting with Google AI Studio and Gemini 3.8 Flash, use the Pi hosting and live-testing guide and config-gemini.yaml.

  1. Use Python 3.12 or 3.13 and install the pinned packages: python -m pip install -r requirements.txt.
  2. Copy config-example.yaml to config.yaml. Set the dialogue, director, and memory model profiles and model names. Only profiles selected for those roles need credentials. For Ollama or another OpenAI-compatible server, set provider: compatible and its base_url.
  3. Set DISCORD_BOT_TOKEN and the API key environment variable for each selected cloud profile. Keep tokens out of the YAML file and version control.
  4. In the Discord developer portal, enable Message Content Intent. Invite the bot with permissions to read and send messages, read history, use application commands, and manage webhooks in the channels where characters will speak. Give it access to threads that will host scenes.
  5. Run python llmcord.py. Set discord.development_guild_id in config.yaml while testing to sync slash commands quickly to one server.

The database is created at data/llmcord.sqlite3 by default. Run python -m unittest discover -s tests -v for offline tests. Docker users need private config.yaml and .env files and can run docker compose up --build; the application code is included in the image, while configuration and data are mounted separately. A model server on the Docker host may need host.docker.internal in its base_url.

Set up a server

For three channels, #world-a, #world-b, and #hub:

  1. /admin space create world A, /admin space create world B, /admin space create hub Hub.
  2. Bind each text channel using /admin space bind (options channel and space).
  3. /admin space allow_world Hub A and /admin space allow_world Hub B.
  4. Import cards with /admin character import, giving the home world. JSON and PNG V2/V3 cards work; PNGs supply the avatar. The examples/cards directory has two small example cards.
  5. Set a channel's default cast with /admin cast default and comma-separated names in characters. Members can use /cast set, /cast add, and /cast remove to change the active cast in a channel or thread. A hub's /summon can invite any eligible guest for one turn without changing that cast.
  6. Mention the bot or reply to one of its character lines to begin. /admin ambient on is an optional admin setting per channel. Ambient participation waits for at least two human messages and a 120-second cooldown, and the director can stay silent. Test explicit turns first.

World channels only admit their home world's characters. Hub channels admit characters from linked worlds, but only active cast members join ambiently (and, for a member who uses step in, that member's favorites). Threads inherit their parent channel's space, lore, and ambient setting; they keep separate casts and message histories.

Memory and lore

Character prompts include the card, relevant character and home-world lore, the current hub and channel lore, and branch history. A hub guest does not receive another guest's world lore. Character encounters are scoped to a space. A person's memories can follow the same character between its home world and a hub only after /memory opt_in. /memory list, /memory forget, and /memory opt_out give that person control; opting out erases their personal facts.

The bot extracts short scene facts after replies. A repeated fact in two separate scenes becomes durable lore in that channel or thread only. Admins can use /admin lore add, /admin lore edit, /admin lore pin, /admin lore delete, and /admin lore promote to control shared facts and explicitly copy them into a channel, world, or hub. Administrators can use /context to see which lore and memories informed a saved character line.

Replies to an older character line branch from that line's saved parent chain. A new mention can also use up to 12 recent human messages from the last 10 minutes as group context. /scene reset starts the next invitation without the channel's recent context. Admins can use /admin scene delete to remove a stored message and everything after it in its branch (Discord messages stay). Conversation text and response traces expire after 90 days by default; change history_retention_days in config.yaml. Durable lore and opted-in personal facts stay until removed with their controls. Application logs do not include raw chat transcripts.

Model providers

The openai adapter uses Responses, anthropic uses Messages, and compatible uses an OpenAI-style chat endpoint. All prompt state comes from SQLite, so changing providers does not depend on provider-hosted conversation state. Image attachments are bounded by the configured count and size and require a dialogue profile with supports_images: true. Text attachments are supported. Replies stream through character webhooks and are split below Discord's message limit.

The offline suite covers spaces, lore isolation and promotion, branch histories, consent, director choices, card parsing, lorebook sync, and web authorization. The NiceGUI admin console also provides a full lore-rule editor, drag-and-drop transfers, customizable emotion avatars, and versioned prompt presets per server; see Admin console. Before using ambient mode in a real server, validate webhook permissions and identities, reply routing in channels and threads, and restart recovery in a private test channel. Those live Discord checks require your bot token and server and are not part of the offline suite.

Private admin dashboard on a Raspberry Pi 5

Use a 64-bit Raspberry Pi OS. Install Docker Engine and the Compose plugin following the Debian arm64 instructions. Install Tailscale on the Pi host and join the Pi and your admin devices to the same tailnet. Enable MagicDNS and HTTPS certificates in the tailnet.

  1. Copy config-example.yaml to config.yaml and .env.example to .env. Enter your Discord bot token, OAuth client ID and secret, model credentials, and the Pi's exact Tailscale HTTPS name in WEB_BASE_URL, such as https://my-pi.my-tailnet.ts.net. Keep .env private. Set LLMCORD_DATABASE_PATH for all services; it overrides the YAML database_path for every service.
  2. In the Discord developer portal, register the exact OAuth redirect https://my-pi.my-tailnet.ts.net/auth/callback for the same Discord application as the bot. Replace the example name with your Pi's actual HTTPS name. The dashboard requests identify and guilds; each page and change checks the user's server administrator permission with Discord.
  3. Run docker compose up --build -d. The migration service runs before the bot and web services and creates a dated SQLite backup when upgrading an existing database. Both services share ./data. The dashboard is published only on the Pi's 127.0.0.1:8080.
  4. On the Pi host, run sudo tailscale serve --bg 8080. Check tailscale serve status, then open WEB_BASE_URL from a tailnet device. Tailscale Serve provides the private HTTPS proxy; no public router port forwarding is needed.

In the dashboard, create worlds and a hub, link worlds to the hub, bind Discord text channels, import V2/V3 JSON or PNG character cards, choose default casts, and edit characters or channel lore. Card import has a preview; reusing a name requires explicit replacement. Characters always have a home world. The dashboard can also toggle ambient mode per channel; first check explicit conversations in a private Discord test channel.

Create a named guild lorebook and enable it for selected worlds or hubs, or create a channel lorebook for one bound channel and its threads. Import a JSON entry array, SillyTavern entries object/array, or RisuAI version-1 lorebook export. The preview lists adds, updates, removals, and conflicts. Locally edited imported entries require a keep/import choice. Handwritten lore remains separate. A hub guest receives books enabled for its own home world, hub books, and the current channel book; it does not receive another guest's world books. /context records activated entries and their source book on each saved response.

The World Info evaluator supports keyword and JavaScript regex matching, constants, secondary filters, ordering, probability, groups, recursion, timing, character filters, and Discord-applicable prompt positions. Rules tied to SillyTavern-only surfaces such as author-note slots, outlets, vectors, or automation IDs are preserved and flagged in the dashboard; they remain inactive until remapped. Behavior that depends on SillyTavern's exact prompt assembly may differ in Discord scenes, so review imported entries in a private test channel.

If Ollama runs on the Pi host rather than in the bot container, use http://host.docker.internal:11434/v1 as the compatible model base_url and configure Ollama to listen on a host-reachable interface. If it runs on another machine, use its reachable LAN or tailnet URL. localhost inside the bot container points to the container itself.

Acknowledgments and license

This project began as a fork of llmcord by jakobdylanc. The implementation has since been substantially reworked around character roleplay, worlds and hubs, lore and memory, and a private administration dashboard. We acknowledge the original project and its contributors for the foundation and inherited work.

The repository currently uses the MIT license; see LICENSE.md. The original copyright and complete MIT permission and warranty notice for inherited llmcord code are also preserved below.

Original llmcord MIT license notice
MIT License

Copyright (c) 2024 jakobdylanc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

About

A Discord LLM chat bot that supports any OpenAI compatible API (OpenAI, xAI, Mistral, Groq, OpenRouter, Ollama, LM Studio and more)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages