Skip to content
BotServBotServ
IRCBotOllamaAIChatClassic

IRC Bot with Ollama

Build an IRC bot with Ollama. Add AI to IRC channels with commands, moderation, and practical examples.

S

schutzgeist

7 min read
IRC Bot with Ollama

IRC Bot with Ollama

What This Article Covers

  • Building an IRC bot that uses Ollama as its AI backend.
  • Integrating the bot into IRC channels.
  • How commands, moderation, and automation work.
  • Practical examples: FAQ bots, channel support, and logging.
  • Best practices for network etiquette, security, and rate limiting.

Introduction: IRC Bots with Ollama Explained

IRC is the classic chat protocol: simple, fast, and running since 1988. An IRC bot powered by Ollama brings modern AI to this timeless platform. The bot joins a channel, answers questions, executes commands, and handles moderation, all backed by a local language model.

This article is for anyone wanting to extend IRC with AI capabilities. For background on IRC bots, see IRC Bots, and for Ollama setup, see Ollama. Basic Python knowledge is helpful; you can find it at IRC-Coding.de.

Why Use an IRC Bot with Ollama?

IRC is minimal by design: text in, text out. An AI bot can answer questions in channels, run commands, and moderate conversations. Unlike Discord or Matrix, IRC is straightforward enough that a basic bot can be written in 50 lines of Python.

How It Works: IRC Bot with Ollama in Brief

The bot connects to an IRC server, joins a channel, and listens for messages. When it sees a command starting with ! or a mention of its name, it calls Ollama and posts the response back.

The core idea: IRC is simple; AI makes it intelligent.

Who Should Read This?

  • IRC users wanting to add AI to their channels.
  • Retro computing enthusiasts combining IRC with modern AI.
  • Developers building lightweight bots.
  • Community admins automating IRC channels.

Some familiarity with Python and IRC basics is helpful.

Key Terms

  • IRC - Internet Relay Chat. Use case: the protocol itself.
  • Channel - A chat room in IRC. Use case: where the bot lives.
  • Nickname - A username. Use case: the bot’s name.
  • irc / pydle - Python libraries. Use case: building the bot.
  • Ollama - Local model server. Use case: the AI backend.
  • PRIVMSG - A message in IRC. Use case: how the bot communicates.
  • IRC Bot Basics - Core bot concepts. Use case: getting started.

Setup: Creating Your IRC Bot

Bot with pydle (Python)

# bot.py
import asyncio
import aiohttp
from pydle import Client

OLLAMA_URL = "http://ollama:11434"
IRC_SERVER = "irc.libera.chat"
IRC_PORT = 6697
IRC_CHANNEL = "#mein-channel"
BOT_NICK = "KI-Bot"

async def call_ollama(prompt, system=None):
    """Call Ollama"""
    messages = []
    if system:
        messages.append({"role": "system", "content": system})
    messages.append({"role": "user", "content": prompt})

    async with aiohttp.ClientSession() as session:
        async with session.post(
            f"{OLLAMA_URL}/api/chat",
            json={
                "model": "llama3.1",
                "messages": messages,
                "stream": False
            },
            timeout=aiohttp.ClientTimeout(total=60)
        ) as response:
            data = await response.json()
            return data["message"]["content"]

class KIBot(Client):
    async def on_connect(self):
        """Upon connection"""
        await self.join(IRC_CHANNEL)
        print(f"Bot online in {IRC_CHANNEL}")

    async def on_message(self, target, source, message):
        """On incoming message"""
        # Ignore our own messages
        if source == self.nickname:
            return

        # Handle commands
        if message.startswith("!"):
            await self.handle_command(target, source, message)

        # Handle mentions
        elif self.nickname.lower() in message.lower():
            await self.handle_mention(target, source, message)

    async def handle_command(self, target, source, message):
        """Process a command"""
        parts = message[1:].split()
        command = parts[0].lower()
        args = " ".join(parts[1:])

        if command == "ask":
            # !ask How does X work?
            answer = await call_ollama(
                args,
                system="You are a helpful IRC bot. Keep answers brief."
            )
            await self.message(target, f"{source}: {answer}")

        elif command == "summarize":
            # !summarize (uses last N messages)
            # Implementation: gather message history
            await self.message(target, f"{source}: Summarizing...")

        elif command == "help":
            await self.message(target,
                "Commands: !ask <question>, !summarize, !help"
            )

    async def handle_mention(self, target, source, message):
        """Process a mention"""
        # Remove nickname from message
        question = message.replace(self.nickname, "").strip()

        answer = await call_ollama(
            question,
            system="You are a helpful IRC bot. Keep answers brief."
        )

        await self.message(target, f"{source}: {answer}")

# Start the bot
bot = KIBot(BOT_NICK, realname="KI Bot")
bot.run(IRC_SERVER, tls=True, tls_verify=False)

Running the Bot

pip install pydle aiohttp

export OLLAMA_URL="http://localhost:11434"
python bot.py

Implementing Commands

COMMANDS = {
    "ask": "Ask the AI a question",
    "summarize": "Summarize recent messages",
    "translate": "Translate text",
    "weather": "Get weather info",
    "help": "Show help"
}

async def handle_command(self, target, source, message):
    parts = message[1:].split()
    command = parts[0].lower()
    args = " ".join(parts[1:])

    if command == "ask":
        answer = await call_ollama(args, system="Keep your answer brief.")
        await self.message(target, f"{source}: {answer}")

    elif command == "translate":
        answer = await call_ollama(
            f"Translate to English: {args}",
            system="Translate only."
        )
        await self.message(target, f"{source}: {answer}")

    elif command == "weather":
        # Call weather API
        weather = await get_weather(args)
        await self.message(target, f"{source}: {weather}")

    elif command == "help":
        cmds = ", ".join(f"!{k}" for k in COMMANDS)
        await self.message(target, f"Commands: {cmds}")

Practical Example 1: FAQ Bot

import chromadb

class IRCFAQBot(KIBot):
    def __init__(self):
        super().__init__(BOT_NICK)
        self.chroma = chromadb.HttpClient(host="chromadb", port=8000)
        self.collection = self.chroma.get_collection("faq")

    async def handle_command(self, target, source, message):
        if message.startswith("!faq"):
            question = message[4:].strip()

            # RAG: Search for similar documents
            results = self.collection.query(
                query_texts=[question],
                n_results=3
            )
            context = "\n".join(results["documents"][0])

            answer = await call_ollama(
                f"Context:\n{context}\n\nQuestion: {question}",
                system="Answer based on context. Keep it brief."
            )

            await self.message(target, f"{source}: {answer}")
        else:
            await super().handle_command(target, source, message)

Practical Example 2: Moderation

async def on_message(self, target, source, message):
    if source == self.nickname:
        return

    # AI analyzes message
    analysis = await call_ollama(
        f"Analyze: {message}\n"
        "Categories: ok, spam, toxic\n"
        "Reply: CATEGORY",
        system="You are an IRC moderator."
    )

    if "spam" in analysis.lower() or "toxic" in analysis.lower():
        # Remove message (bot needs op privileges)
        await self.kick(target, source, "Rule violation")
        await self.message(target, f"⚠️ {source} was warned")

Practical Example 3: Channel Logging with AI Summary

class LoggingBot(KIBot):
    def __init__(self):
        super().__init__(BOT_NICK)
        self.log = []

    async def on_message(self, target, source, message):
        # Log message
        self.log.append({
            "time": asyncio.get_event_loop().time(),
            "user": source,
            "message": message
        })

        await super().on_message(target, source, message)

    async def daily_summary(self):
        """Generate daily summary"""
        log_text = "\n".join(
            f"{e['user']}: {e['message']}" for e in self.log[-500:]
        )

        summary = await call_ollama(
            f"Summarize the latest IRC messages:\n{log_text}",
            system="Create a brief summary."
        )

        await self.message(IRC_CHANNEL, f"Daily summary:\n{summary}")
        self.log = []

Practical Example 4: n8n Trigger

elif command == "workflow":
    # !workflow name param1 param2
    parts = args.split()
    wf_name = parts[0] if parts else "default"
    wf_params = " ".join(parts[1:])

    async with aiohttp.ClientSession() as session:
        async with session.post(
            f"http://n8n:5678/webhook/{wf_name}",
            json={"params": wf_params, "user": source}
        ) as r:
            result = await r.text()

    await self.message(target, f"{source}: {result}")

IRC Netiquette

# Rate-limiting: don't send too fast
async def message(self, target, text):
    # IRC has rate limits
    await asyncio.sleep(1)  # 1 second between messages
    await super().message(target, text)

# Split long messages
async def send_long(self, target, text, max_len=400):
    for i in range(0, len(text), max_len):
        await self.message(target, text[i:i+max_len])

Security Considerations

  • Bot password: Set a password for registered nicks via NickServ.
  • Op privileges minimal: The bot should have only the permissions it needs.
  • Prompt injection: Users can send injections. See Prompt Injection.
  • Flooding: Don’t send too many messages too quickly. Servers will kick bots.
  • Logging: Audit bot actions. See Audit Logging.

Common Pitfalls

  • Flooding: IRC servers kick bots that send too fast. Implement rate-limiting.
  • Long messages: IRC has a 512-byte limit per line. Split messages into chunks.
  • Nick collision: Your bot’s nickname must be available. Register with NickServ.
  • SSL/TLS: Many IRC servers require TLS. Set tls=True in pydle.
  • Encoding: IRC uses Latin-1 or UTF-8. Watch out for encoding issues.
  • Ollama too slow: Large models take time. Use smaller models (8B) for real-time responses.

Further Reading

Key Takeaways:

  • IRC + Ollama: Classic chat with modern AI.
  • pydle for Python bots, simple and powerful.
  • Commands with !, mentions for chat.
  • Follow rate-limiting and netiquette.
  • Local AI: no data leaves your server, no API costs.

FAQ

How do I create an IRC bot?

With pydle (Python): inherit the client class, implement on_connect and on_message, then start the bot. Alternatively, use irc, sopel, or write your own socket implementation.

IRC or Discord for bots?

IRC for simplicity, privacy, and retro appeal. Discord for features, communities, and modern tooling. IRC bots are significantly simpler to build.

Which Python library for IRC?

pydle for modern async bots. irc for classic bots. sopel for ready-made bot frameworks. pyrcb for simple applications.

How do I implement commands?

Check for messages starting with !: !ask, !help, !summarize. Parse the command and its arguments, then execute the action.

How do I prevent flooding?

Rate-limiting: use asyncio.sleep(1) between messages. IRC servers kick bots that send too fast.

Do I need SSL/TLS?

Recommended. Many IRC servers require TLS (port 6697). pydle supports TLS with tls=True.

What does it cost?

Free. IRC servers are public (Libera.Chat, OFTC). Ollama is open source. Only hardware costs for running your bot.

Is the bot secure?

Yes, if you keep the password safe, grant minimal permissions, and prevent prompt injection. IRC is unencrypted in channels (TLS only protects the connection to the server).

Resources and Further Reading

Back to Blog
Share:

Related Posts