- Install Node.js (if you have a package manager, use that instead to install this)
- Make sure to install at least v22.13 of Node.js
- Install pnpm v12 or newer, it switches to the version pinned in
package.jsonautomatically
- Install Ollama (ditto)
- Pull (download) a model, e.g
ollama pull orcaorollama pull llama2 - Start Ollama by running
ollama serve - Create a Discord bot
- The bot only uses slash commands, so you don't need to enable any privileged gateway intents under Application » Bot
- Invite the bot to a server
- Go to Application » OAuth2 » URL Generator
- Enable
bot - Enable Send Messages, Read Messages/View Channels, and Read Message History
- Under Generated URL, click Copy and paste the URL in your browser
- Rename
.env.exampleto.envand edit the.envfile- You can get the token from Application » Bot » Token, never share this with anyone
- Make sure to change the model if you aren't using
orca - Ollama URL can be kept the same unless you have changed the port
- You can use multiple Ollama servers at the same time by separating the URLs with commas
- Set the channels to the channel IDs, comma separated, or leave it empty to allow all channels (threads inside a listed channel are allowed too, and DMs are always allowed)
- In Discord, go to User Settings » Advanced, and enable Developer Mode
- Right click on a channel you want to use, and click Copy Channel ID
- You can edit the system message the bot uses, or disable it entirely
/chatsends each prompt asName: prompt, using the sender's server nickname or display name, so the model knows who is talking/chathistory is saved in an SQLite database atCHAT_HISTORY_DB(default./data/chat-history.db, relative to the folder you start the bot from), so conversations survive restarts. Each user has their own history in each channel, limited to their last 50 messages, and/clearhistorydeletes yours in the current channel- While
/chat,/generateor/text2imgruns, its reply shows a red Stop button that only the person who ran the command can press. Stopping cancels the request, so Ollama stops generating and the server is freed for the next request. A streamed reply keeps the text generated so far, and a stopped/chatisn't saved to the history./text2imginterrupts its image only once AUTOMATIC1111 reports it as the one rendering, which needs AUTOMATIC1111 1.8 or newer started without--nowebui, and the Stable Diffusion server stays busy until it has finished with the stopped job /chatand/generateanswers end with buttons showing Ollama's stats for that answer: the model, response tokens, generation speed, prompt tokens, model load time and total time. Clicking one shows a breakdown only you can see. SetSHOW_STATS=falseto hide the buttons
- Install the required dependencies with
pnpm i - Start the bot with
pnpm start - You can interact with the bot with its slash commands:
/chat,/generate,/text2img,/modelsand/clearhistory - Install Stable Diffusion
- Run the script
./webui.sh --api --listen
- Install Docker
- You need Docker Engine 20.10 or newer with Docker Compose v2
- Repeat steps 2—7 from the other setup instructions
- The compose file sets
OLLAMAtohttp://host.docker.internal:11434, which points the container at the Ollama running on your computer - On Linux, Ollama only listens on
127.0.0.1by default, so the container can't reach it. Start it withOLLAMA_HOST=0.0.0.0 ollama serve, or, if Ollama runs as a systemd service, runsudo systemctl edit ollama, addEnvironment="OLLAMA_HOST=0.0.0.0"under[Service]and restart it. Docker Desktop on Windows and macOS doesn't need this - For
/text2img, setSTABLE_DIFFUSION=http://host.docker.internal:7860in.env, becauselocalhostinside the container is the container itself
- The compose file sets
- Start the bot with
make compose-upif you have Make installed- Otherwise, try
docker compose -p discord-ai upinstead - If you run the image with plain
docker runinstead of Compose, add--add-host=host.docker.internal:host-gatewayand-e OLLAMA=http://host.docker.internal:11434, which Compose otherwise sets for you
- Otherwise, try
- You can interact with the bot with its slash commands:
/chat,/generate,/text2img,/modelsand/clearhistory /chathistory is stored in thechat-historyvolume mounted at/app/data, so it survives restarts, rebuilds andmake compose-down- Keep
CHAT_HISTORY_DBinside./data(the default) so the database is saved in that volume - To delete the stored history, run
docker compose -p discord-ai down -v
- Keep
Every pull request and every push to main runs these GitHub Actions checks:
check:pnpm test:prettier,pnpm test:lint,pnpm test:tsc,pnpm testandpnpm buildon Node.js 22, 24 and 26docker: builds the Docker image without pushing it anywhere, then checks that the container refuses to start without a tokencodeql: CodeQL code scanning, which also runs weekly
Run the same checks locally before opening a pull request:
pnpm install --frozen-lockfile
pnpm test:prettier && pnpm test:lint && pnpm test:tsc && pnpm test && pnpm buildThe repository admin can comment /review on a pull request to get an AI code review from an OpenRouter model. It uses the free nvidia/nemotron-3-ultra-550b-a55b:free model unless the OPENROUTER_MODEL repository variable names another one, and requests to paid models are billed to the OpenRouter account that owns the OPENROUTER_API_KEY secret. Any text after the command is passed to the reviewer as extra instructions, for example /review focus on attachment handling. The review is posted as one comment, which later runs update in place. Findings that point at a line shown in the diff are also posted as inline comments, and a later run replaces them unless someone has replied.