IRC. Most of you know what it is. For those that don't, it stands for Internet Relay Chat - think of it as a geeky group-chat and you won't be too far off the mark.

There's a long tradition of using bots - automated processes - to provide various services in IRC channels. There are, for example, bots that help people access Paste Bin services in IRC channels so that they don't have to paste hundreds of lines of code into the channel, or there are bots which take messages for users that are currently offline then replay those messages when they come online. These bots are really useful because they simply and easily enhance a medium which is naturally used for communication without requiring any additional software to use. use IRC as an internal communication mechanism. They've written (and released under the GPL - thanks!) IRCCat which allows us to write simple bots to answer queries or perform commands given in IRC channels.

I've setup IRCCat and written a few simple scripts for it. It's pretty easy to get started. First you'll need to get Java and Ant setup. I'm on a Mac on OS X 10.4 so I already have Java, and MacPorts provides an Ant port which is easy to install.

After Java and Ant you'll need to clone the IRCCat source from GitHub.

git clone git://

Now you can compile and package the bot by running ant dist in the directory created by the git clone.

Once it's packaged create a directory called config/ and copy the example configuration from examples/irccat.xml there. We'll use this to setup the bot the way we want it to work.

The configuration file is reasonably well commented so open it up and run through each of the sections filling in the appropriate details.

  • Provide the details of the IRC server you'd like to connect to. I use an internal server but if you don't have one then there are plenty of IRC networks out there - a quick Google should get the details.
  • Tell the bot which username it should use.
  • Change the external scripts hook to scripts/run and up the max response lines to 30.
  • Choose which channels you'd like the bot to join. If they don't exist them they'll be created when the bot joins them (depending on IRC network policy).

With the configuration out of the way you can now launch your bot.

ant -Dconfgfile=./config/irccat.xml

If you're in one of the channels that you've asked the bot to connect to then you should see it join. If you're not in the channel, now would be a great time to join it. You can check the bot is working properly by asking it which channels it's running in. Type !channels into any of the channels that it's joined. It should response with a list of channels that it's currently active in.

CraigW: !channels
bot: I am in 2 channels: #foo #bar

There are a few built-in commands such as !channels. Built-in commands always start with an exclamation mark.

Command Description
!join #channel password Make the bot join another channel. Password is optional.
!part #channel Make the bot leave a channel
!channels List all channels the bot is in
!spam message Send message to all channels the bot is in
!exit Make the bot quit IRC and shutdown

The really interesting commands are the externals. Externals are called by starting a command with a question mark. You get to write external commands yourself and they can do anything you want.

Remember the configuration file had a cmdhandler value that I set to script/run? That's the first port of call for externals. I use this script to launch a router which loads and executes other commands stored in the scripts/ directory.

If you'd like to do the same thing as me, my script/run script looks like this:

# This script handles ?commands to irccat

exec ruby ./scripts/router "$@" 2>&1

That's executable (chmod +x script/run). The code in script/router looks like the following and does the routing to and invocation of the correct command.

#! /usr/bin/env ruby

COMMANDS = File.expand_path(File.dirname(__FILE__))
name, channel, username, command, arguments = *ARGV[0].split(/ /, 5)

command_script = File.join(COMMANDS, File.basename(command))

if File.exists?(command_script) && !%W(run router).include?(command)
  load command_script
  puts Command.execute(name, channel, username, arguments).strip
  desired_command = "#{command} #{arguments}".strip
  puts "Sorry #{name}, I don't understand `#{desired_command}`."

To write externals we now just need to write a short script that implements a Command class.

The name of the file which the command should be implemented in is based on what you'd like to type into the IRC channel. If you'd like to query SNMP on a certain host under a certain OID you might like to write something like ?snmp xeriom-vm-host-06 . The script name in this case would be script/snmp. Here's a very simple implementation of that commands which just executes snmpwalk and returns the results.

class Command
  class << self
    def execute(name, channel, username, arguments)
      hostname, oid, remainder = arguments.split(/ /, 3)
      `snmpwalk -c public -v 1 #{hostname} #{oid}`

Now entering ?snmp xeriom-vm-host-06 . in IRC will run this script and print the results straight back into the IRC channel the command was typed in. Note that there's no need to restart the bot for changes to take effect.

CraigW: ?snmp xeriom-vm-host-06 .
bot: SNMPv2-MIB::sysDescr.0 = STRING: Linux 2.6.24-17-xen #1 SMP Thu May 1 15:55:31 UTC 2008 x86_64

There's great potential in having such powerful scripts available directly in the same communication channel that you'd use to discuss development or customer relations - a simple command can quickly pull up customer records or statistics without the need to drop to the terminal and fire up the application console or load a web page.

Ruby vs Java

I've just found out that there's a Ruby port of IRCCat. I'll be swapping to use that since I find it easier to maintain and fork a Ruby project than a Java project. Your mileage may vary.

written by
Disagree? Found a typo? Got a question?
If you'd like to have a conversation about this post, email I don't bite.
You can verify that I've written this post by following the verification instructions:
curl -LO
curl -LO
gpg --verify query-your-applications-using-irc.html.orig{.asc,}