POE::Component::IRC::Plugin is new functionality built into POE::Component::IRC that enables and encourages modular IRC bot writing. The following is example implements the rot13 bot in a plugin.

package Rot13;
use strict qw(subs vars refs);    # Make sure we can't mess up
use warnings FATAL => 'all';
use POE::Component::IRC::Plugin qw( :ALL );

# Plugin object constructor
sub new {
  my ($package) = shift;
  return bless {}, $package;
}

sub PCI_register {
  my ($self, $irc) = splice @_, 0, 2;
  $irc->plugin_register($self, 'SERVER', qw(public));
  return 1;
}

# This is method is mandatory but we don't actually have anything to do.
sub PCI_unregister {
  return 1;
}

sub S_public {
  my ($self, $irc) = splice @_, 0, 2;

  # Parameters are passed as scalar-refs including arrayrefs.
  my ($nick)    = (split /!/, ${$_[0]})[0];
  my ($channel) = ${$_[1]}->[0];
  my ($msg)     = ${$_[2]};
  if (my ($rot13) = $msg =~ /^rot13 (.+)/) {
    $rot13 =~ tr[a-zA-Z][n-za-mN-ZA-M];

    # Send a response back to the server.
    $irc->yield(privmsg => $channel => $rot13);
    return PCI_EAT_PLUGIN;    # We don't want other plugins to process this
  }
  return PCI_EAT_NONE; # Default action is to allow other plugins to process it.
}

It is perfectly possible to have POE sessions in plugin objects. This code provides a template for doing so:

package POE -Plugin-Template;
use POE;
use POE::Component::IRC::Plugin qw( :ALL );

sub new {
  my ($package) = shift;
  my $self = bless {@_}, $package;
  $self->{SESSION_ID} =
    POE::Session->create(object_states => [$self => [qw(_start)],],)->ID();
  return $self;
}

sub PCI_register {
  my ($self, $irc) = splice @_, 0, 2;
  $self->{irc} = $irc;
  $irc->plugin_register($self, 'SERVER', qw(blah blah blah));
  return 1;
}

sub PCI_unregister {
  my ($self, $irc) = splice @_, 0, 2;
  delete $self->{irc};

  # Plugin is dying make sure our POE session does as well.
  $poe_kernel->refcount_decrement($self->{SESSION_ID}, __PACKAGE__);
  return 1;
}

sub _start {
  my ($kernel, $self) = @_[KERNEL, OBJECT];
  $self->{SESSION_ID} = $_[SESSION]->ID();

  # Make sure our POE session stays around. Could use aliases but that is so messy :)
  $kernel->refcount_increment($self->{SESSION_ID}, __PACKAGE__);
}