Properties
category: feature tags: [agents, irc, supervisor] last_updated: 2026-03-20 confidence: high
Directed Message Routing
Event-driven delivery of IRC messages to specific agents, replacing poll-only communication.
Problem
Agents only see IRC messages when the supervisor's 30-second heartbeat prompts them to read_messages. If the PM or EM posts a message mentioning an agent by nick, it sits unread until the next poll. This creates up to 30 seconds of latency on directed communication and makes the system feel unresponsive.
The IrcWatcher already has an event-driven IRC connection that fires instantly on PRIVMSG. It currently only handles TASK: prefixes. It should also route messages that mention a specific agent.
Design
Extend IrcWatcher to detect nick mentions and notify the supervisor, which immediately sends the message content to the targeted agent.
Detection
A message is "directed" if it contains @AgentName where AgentName is a currently active agent nick. The watcher already has access to a callback — add a second callback for directed messages alongside the existing on_task.
class IrcWatcher: def __init__( self, server: str, port: int, nick: str, channels: list[str], on_task: Callable[[str, str, str], None], on_mention: Callable[[str, str, str, str], None], # on_mention(channel, sender, mentioned_nick, full_message) ) -> None:
Routing
In _handle_message, after the existing TASK: check:
- Scan the message for
@{nick}where nick is in the set of active agent names - If found, call
on_mention(channel, sender_nick, mentioned_nick, message) - A message can match both
TASK:and@mention— that's fine, they serve different purposes
The supervisor registers on_mention and calls agent.send() with the message content, bypassing the poll loop:
def _on_mention(self, channel: str, sender: str, target_nick: str, message: str) -> None: agent = self.agents.get(target_nick) if agent: asyncio.get_running_loop().create_task( agent.session.send( f"[IRC {channel}] <{sender}> {message}\n\n" "Respond in the appropriate channel." ) )
Active nick registry
The IrcWatcher needs to know which nicks are active to avoid matching mentions of non-agent names. The supervisor already tracks this in self.agents (keyed by name). Add a method to update the watcher's nick set:
# On IrcWatcher def update_active_nicks(self, nicks: set[str]) -> None: self._active_nicks = nicks # Supervisor calls this after spawn/kill/shift-change self._watcher.update_active_nicks(set(self.agents.keys()))
Deduplication
Without guard, an agent could receive the same message twice: once via directed routing, once via the next heartbeat's read_messages. Two options:
- Track delivered message timestamps per agent. The supervisor records the timestamp of the last directed delivery. The heartbeat prompt changes to "Check your IRC channels for messages since {timestamp}."
- Accept duplicates. Agents are LLMs — seeing a message twice is redundant but not harmful. The simpler option for MVP.
Recommendation: Accept duplicates for MVP. Add dedup later if it becomes noisy.
Channels to watch
The watcher currently joins only #standup-{slug}. For mention routing to work across channels, it should also join #project-{slug} and any #work-{task_id} channels that get created. The supervisor should call watcher.join_channel() when creating work channels for new tasks.
Scope
In scope
- Extend
IrcWatcher._handle_messagewith nick-mention detection - Add
on_mentioncallback toIrcWatcher.__init__ - Add
update_active_nicks()method - Wire
Supervisor._on_mentionto callagent.send() - Update active nicks on spawn/kill/shift-change
- Join
#project-{slug}in addition to#standup-{slug}on startup - Tests for mention detection regex
Out of scope
- DM (private message) routing — agents only operate in channels for now
- Message deduplication — accept duplicates for MVP
- Priority/interruption — directed messages queue behind any in-progress
send() - Rate limiting — a burst of mentions could queue many
send()calls
Files to change
supervisor/src/minsky_supervisor/irc_watcher.py— add mention detection,on_mentioncallback,update_active_nicks()supervisor/src/minsky_supervisor/supervisor.py— wire_on_mention, callupdate_active_nicks()after agent lifecycle changes, join#project-{slug}supervisor/tests/test_irc_watcher.py— add mention detection tests
