Daisuke Maki
and 1 contributors


Morris - An IRC Bot Based On Moose/AnyEvent


    # If you just want to start using Morris, please checkout 
    # misc/sample.conf in the distro for a sample config file, 
    # which is the best way to figure out how to configure Morris.

    use Morris;

    my $morris = Morris->new(
        connections => [
            Morris::Connection->new( ... )

    # or when you instantiate from a config file
    my $config = read_config_file( $config_file );
    my $morris = Morris->new_from_config( $config );


The configuration file shipped with Morris is written in Config::General syntax, but since our underlying config read is Config::Any, we support any format supported by Config::Any family. Our docs will be written in Config::General format, but you may choose whichever format you like.


Morris is a simple IRC bot. Its architecture is loosely depicted below:

                                             ---| Morris::Plugin::Foo |
                    ----------------------   |  -----------------------
                 ---| Morris::Connection |---|--| Morris::Plugin::Bar |
    ----------   |  ----------------------   |  -----------------------
    | Morris |---|                           ---| Morris::Plugin::Baz |
    ----------   |  ----------------------      -----------------------
                 ---| Morris::Connection |...

What this means is that you can have multiple Morris::Connection objects, which in turn represent single client-to-server connection. For each connection, you can define plugins that react to events or do other intersting stuff with that connection.

For example, if you have a connection to freenode, EFnet, and your own private IRC server. You can define difference plugin sets for each connection, and have Morris act differently depending on which connection you are using.

Morris uses a simple plugin mechanism to add extra capabilities (if you're familiar with how Plagger works, it's similar to it).

Plugins are loaded on demand based on the config file specification, and are initialized with the parameters in the config file. After that, they are given a chance to register hooks to Morris (actually, Morris::Connection, since Morris' main features revolve around Morris::Connection, and so plugins are also registered on a per-connection base)


Morris expects to have a configuration file with at least the following specifications:

      <Connection YourConnectionName>
        Network YourNetworkName
        ... plugins ...

      <Network YourNetworkName>
        ... network config ...

Network CLAUSE

The Network clause defines how to connect to a certain IRC network. Normally you need to set the following fields:

    <Network YourNetworkName>
      Server         irc.freenode.net # the host name to connect to
      Port           6667             # Port number. Defaults to 6667
      Username       YourUsername     # Username to connect as
      Nickname       YourNickname     # Nick name to use
      # If the server is password protected, specify a password
      # Password       YourPassword

The same Network definition may be re-used between multiple Connection clauses. This will allow multiple bots (if the network allows such thing)

Note that The above information may be overridden on a per-connection basis (so to allow multiple, differently named bots on a same network). However, it is recommended that you keep the "master" configuration for a Network separate from a Connection

Connection CLAUSE

The Connection clause defines the actual connection and the plugins that are supposed to be registered to that connection.

The Connection name is just a symbolic name to differentiate from other connections, so as long as its unique, you can use whatever you like.

You can skip defining Plugin clauses, but that will just create a bot that connect to a network, but does nothing.


The Plugin clause is where all the plugins are defined, and it must be found inside a Connection clause. Multiple plugin sections are allowed.

The order of initialization is NOT guaranteed.

Plugins should be specified without the preceeding Morris::Plugin:: part from their module name.

    <Plugin Join> # Loads Morris::Plugin::Join

If you would like to explicitly specify a fully qualified plugin name, you should prefix it with a single '+', like so:

    <Plugin +My::Other::Plugin>

Here's the current list of plugins:


Enables a database handle, so that other DB-dependent plugins can use it. On its own, it doesn't do anything


Add ability to remember certain key = value combinations.


Automatically join a channel on connect


Log every privmsg to a database


Enable AnyEvent::MP for Morris.


Automatically give out oper to matched users.


When a URL-like string pattern appears in a privmsg, attemps to fetch it and display some information about it (like title, or image size, if it's a image)


Remember phrases, and display them in a weird fashin.


When a string like morris++ or morris-- is found, remembers that and keeps tab of the target's reputation


Allows Yahoo! Search to run.



new_from_config (\%config)

Instantiate a new morris instance


Starts the servicing.


Why do you care? I originally wanted to write a Moose-based IRC bot for practice/toying with, and just thought something starting with "Moo.." would be good. Turns out using the name 'Morris' sounds like I'm refering to a person, which gives me a warm and fuzzy feeling.

...or something like that. No, there's no real reason.


Daisuke Maki <daisuke@endeworks.jp>


This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html