please identify a list of all IRC numeric c2s and s2c codes that exist in common/standard irc usage, and identify which we have implemented and which we have not #52

Closed
opened 2026-03-07 15:18:37 +01:00 by sneak · 12 comments
Owner
No description provided.
sneak added the bot label 2026-03-07 15:18:37 +01:00
clawbot was assigned by sneak 2026-03-07 15:18:37 +01:00
Collaborator

IRC Numeric Code Audit — neoirc Implementation Status

This audit catalogs all standard IRC numeric reply codes from RFC 1459, RFC 2812, and common extensions, then checks which are implemented/handled in the neoirc codebase.

Summary

Server-side (Go): Only 3 numeric codes are generated: 372, 375, 376 (MOTD delivery). No other numerics are sent by the server.

CLI client (neoirc-cli): The handleDefaultEvent catches all unrecognized commands (including numerics) and displays them generically. No specific numeric handling beyond what the default case provides.

Web SPA client (app.jsx): Explicitly handles 375, 372, 376 (renders to Server tab). All other commands (including numerics) fall to a default case that renders to the Server tab.

C2S Commands implemented: PRIVMSG, NOTICE, JOIN, PART, NICK, TOPIC, QUIT, PING/PONG

C2S Commands NOT implemented: MODE, KICK, INVITE, WHO, WHOIS, WHOWAS, LIST (server-side; CLI has local /list via REST), NAMES (server-side; CLI has local /names via REST), OPER, AWAY, USERHOST, ISON, KILL, WALLOPS, SQUIT, CONNECT, DIE, RESTART, REHASH, STATS, LINKS, TIME, ADMIN, INFO, SERVLIST, SQUERY, LUSERS, VERSION, TRACE


Connection Registration Numerics (001–005)

Code Name RFC Description Implemented?
001 RPL_WELCOME 2812 Welcome to the IRC network Not sent
002 RPL_YOURHOST 2812 Your host is running version... Not sent
003 RPL_CREATED 2812 This server was created... Not sent
004 RPL_MYINFO 2812 Server name, version, available modes Not sent
005 RPL_ISUPPORT Modern Server capabilities (CHANTYPES, PREFIX, etc.) Not sent

Lusers / Server Info Numerics (200–299)

Code Name RFC Description Implemented?
200 RPL_TRACELINK 2812 Link trace info
201 RPL_TRACECONNECTING 2812 Connecting trace
202 RPL_TRACEHANDSHAKE 2812 Handshake trace
203 RPL_TRACEUNKNOWN 2812 Unknown connection trace
204 RPL_TRACEOPERATOR 2812 Operator trace
205 RPL_TRACEUSER 2812 User trace
206 RPL_TRACESERVER 2812 Server trace
208 RPL_TRACENEWTYPE 2812 New type trace
211 RPL_STATSLINKINFO 2812 Stats link info
212 RPL_STATSCOMMANDS 2812 Stats commands
219 RPL_ENDOFSTATS 2812 End of STATS
221 RPL_UMODEIS 2812 User mode string
242 RPL_STATSUPTIME 2812 Server uptime
243 RPL_STATSOLINE 2812 O-line info
251 RPL_LUSERCLIENT 2812 Current user/invisible/server count
252 RPL_LUSEROP 2812 IRC operator count
253 RPL_LUSERUNKNOWN 2812 Unknown connection count
254 RPL_LUSERCHANNELS 2812 Channel count
255 RPL_LUSERME 2812 This server's client/server count
256 RPL_ADMINME 2812 Admin info intro
257 RPL_ADMINLOC1 2812 Admin location 1
258 RPL_ADMINLOC2 2812 Admin location 2
259 RPL_ADMINEMAIL 2812 Admin email
263 RPL_TRYAGAIN 2812 Try again (server too busy)
265 RPL_LOCALUSERS Modern Current/max local users
266 RPL_GLOBALUSERS Modern Current/max global users

WHO / WHOIS / WHOWAS Numerics (301–319)

Code Name RFC Description Implemented?
301 RPL_AWAY 2812 User is away (message)
302 RPL_USERHOST 2812 USERHOST reply
303 RPL_ISON 2812 ISON reply
305 RPL_UNAWAY 2812 You are no longer marked away
306 RPL_NOWAWAY 2812 You are now marked away
311 RPL_WHOISUSER 2812 WHOIS user info
312 RPL_WHOISSERVER 2812 WHOIS server info
313 RPL_WHOISOPERATOR 2812 WHOIS operator status
314 RPL_WHOWASUSER 2812 WHOWAS user info
315 RPL_ENDOFWHO 2812 End of WHO list
317 RPL_WHOISIDLE 2812 WHOIS idle time
318 RPL_ENDOFWHOIS 2812 End of WHOIS
319 RPL_WHOISCHANNELS 2812 WHOIS channel list

Channel / Topic / Names / List Numerics (321–369)

Code Name RFC Description Implemented?
321 RPL_LISTSTART 2812 Start of LIST reply
322 RPL_LIST 2812 Channel list entry
323 RPL_LISTEND 2812 End of LIST
324 RPL_CHANNELMODEIS 2812 Channel mode string
329 RPL_CREATIONTIME Modern Channel creation timestamp
331 RPL_NOTOPIC 2812 No topic set
332 RPL_TOPIC 2812 Channel topic text
333 RPL_TOPICWHOTIME Modern Topic set by (nick, timestamp)
341 RPL_INVITING 2812 Invitation sent confirmation
346 RPL_INVITELIST 2812 Invite list entry
347 RPL_ENDOFINVITELIST 2812 End of invite list
348 RPL_EXCEPTLIST 2812 Ban exception list entry
349 RPL_ENDOFEXCEPTLIST 2812 End of exception list
351 RPL_VERSION 2812 Server version reply
352 RPL_WHOREPLY 2812 WHO list entry
353 RPL_NAMREPLY 2812 NAMES list (nicks in channel)
364 RPL_LINKS 2812 LINKS reply entry
365 RPL_ENDOFLINKS 2812 End of LINKS
366 RPL_ENDOFNAMES 2812 End of NAMES list
367 RPL_BANLIST 2812 Ban list entry
368 RPL_ENDOFBANLIST 2812 End of ban list
369 RPL_ENDOFWHOWAS 2812 End of WHOWAS

MOTD Numerics (371–376)

Code Name RFC Description Implemented?
371 RPL_INFO 2812 INFO reply line
372 RPL_MOTD 2812 MOTD body line Server sends, both clients handle
374 RPL_ENDOFINFO 2812 End of INFO
375 RPL_MOTDSTART 2812 Start of MOTD Server sends, both clients handle
376 RPL_ENDOFMOTD 2812 End of MOTD Server sends, both clients handle
381 RPL_YOUREOPER 2812 You are now an IRC operator
382 RPL_REHASHING 2812 Server rehashing config
391 RPL_TIME 2812 Server time reply

Error Reply Numerics (400–502)

Code Name RFC Description Implemented?
401 ERR_NOSUCHNICK 2812 No such nick/channel (HTTP 404 used instead)
402 ERR_NOSUCHSERVER 2812 No such server
403 ERR_NOSUCHCHANNEL 2812 No such channel (HTTP 404 used instead)
404 ERR_CANNOTSENDTOCHAN 2812 Cannot send to channel (HTTP 403 used instead)
405 ERR_TOOMANYCHANNELS 2812 Too many channels joined
406 ERR_WASNOSUCHNICK 2812 No WHOWAS info
407 ERR_TOOMANYTARGETS 2812 Too many targets
409 ERR_NOORIGIN 2812 No origin in PING/PONG
411 ERR_NORECIPIENT 2812 No recipient given (HTTP 400 used instead)
412 ERR_NOTEXTTOSEND 2812 No text to send (HTTP 400 used instead)
421 ERR_UNKNOWNCOMMAND 2812 Unknown command (HTTP 400 used instead)
422 ERR_NOMOTD 2812 MOTD file missing
431 ERR_NONICKNAMEGIVEN 2812 No nickname given (HTTP 400 used instead)
432 ERR_ERRONEUSNICKNAME 2812 Invalid nickname (HTTP 400 used instead)
433 ERR_NICKNAMEINUSE 2812 Nickname already in use (HTTP 409 used instead)
436 ERR_NICKCOLLISION 2812 Nick collision (server-to-server)
441 ERR_USERNOTINCHANNEL 2812 User not in channel (for KICK)
442 ERR_NOTONCHANNEL 2812 You're not on that channel (HTTP 403 used instead)
443 ERR_USERONCHANNEL 2812 User already on channel (INVITE)
451 ERR_NOTREGISTERED 2812 Not registered (HTTP 401 used instead)
461 ERR_NEEDMOREPARAMS 2812 Not enough parameters (HTTP 400 used instead)
462 ERR_ALREADYREGISTRED 2812 Already registered
464 ERR_PASSWDMISMATCH 2812 Password mismatch (HTTP 401 used instead)
465 ERR_YOUREBANNEDCREEP 2812 You are banned
467 ERR_KEYSET 2812 Channel key already set
471 ERR_CHANNELISFULL 2812 Channel is full (+l)
472 ERR_UNKNOWNMODE 2812 Unknown mode character
473 ERR_INVITEONLYCHAN 2812 Invite-only channel (+i)
474 ERR_BANNEDFROMCHAN 2812 Banned from channel (+b)
475 ERR_BADCHANNELKEY 2812 Bad channel key (+k)
476 ERR_BADCHANMASK 2812 Bad channel mask
481 ERR_NOPRIVILEGES 2812 No IRC operator privileges
482 ERR_CHANOPRIVSNEEDED 2812 You're not a channel operator
483 ERR_CANTKILLSERVER 2812 Cannot kill a server
491 ERR_NOOPERHOST 2812 No O-lines for your host
501 ERR_UMODEUNKNOWNFLAG 2812 Unknown user MODE flag
502 ERR_USERSDONTMATCH 2812 Can't change mode for others

Common Extensions / Modern IRC Numerics

Code Name Source Description Implemented?
004 RPL_MYINFO Modern Server info with modes
005 RPL_ISUPPORT Modern ISUPPORT tokens (NETWORK, CHANTYPES, etc.)
276 RPL_WHOISCERTFP IRCv3 Client TLS certificate fingerprint
330 RPL_WHOISACCOUNT Services Logged-in account name (WHOIS)
338 RPL_WHOISACTUALLY Modern Actual IP/host (WHOIS)
354 RPL_WHOSPCRPL WHOX Extended WHO reply
396 RPL_VISIBLEHOST Modern Displayed hostname
670 RPL_STARTTLS IRCv3 STARTTLS success
691 ERR_STARTTLS IRCv3 STARTTLS failure
730 RPL_MONONLINE IRCv3 MONITOR target online
731 RPL_MONOFFLINE IRCv3 MONITOR target offline
732 RPL_MONLIST IRCv3 MONITOR list entry
733 RPL_ENDOFMONLIST IRCv3 End of MONITOR list
734 ERR_MONLISTFULL IRCv3 MONITOR list full
900 RPL_LOGGEDIN IRCv3 SASL Logged in (SASL)
901 RPL_LOGGEDOUT IRCv3 SASL Logged out (SASL)
902 ERR_NICKLOCKED IRCv3 SASL Nick locked (SASL)
903 RPL_SASLSUCCESS IRCv3 SASL SASL auth success
904 ERR_SASLFAIL IRCv3 SASL SASL auth failed
905 ERR_SASLTOOLONG IRCv3 SASL SASL message too long
906 ERR_SASLABORTED IRCv3 SASL SASL aborted
907 ERR_SASLALREADY IRCv3 SASL Already authenticated
908 RPL_SASLMECHS IRCv3 SASL Available SASL mechanisms

Design Notes

neoirc deliberately uses HTTP status codes instead of IRC error numerics for error conditions:

IRC Numeric neoirc HTTP Equivalent Used For
401 ERR_NOSUCHNICK HTTP 404 User/channel not found
403 ERR_NOSUCHCHANNEL HTTP 404 Channel not found
404 ERR_CANNOTSENDTOCHAN HTTP 403 Not a channel member
421 ERR_UNKNOWNCOMMAND HTTP 400 Unknown command
432 ERR_ERRONEUSNICKNAME HTTP 400 Invalid nick format
433 ERR_NICKNAMEINUSE HTTP 409 Nick already taken
442 ERR_NOTONCHANNEL HTTP 403 Not a member of channel
451 ERR_NOTREGISTERED HTTP 401 Unauthorized
461 ERR_NEEDMOREPARAMS HTTP 400 Missing required fields

This is architecturally intentional — since neoirc uses HTTP as transport, HTTP status codes are the natural error signaling mechanism.

Score: 3 of ~120 standard numerics implemented

The MOTD numerics (372, 375, 376) are the only ones generated server-side. Several IRC features that would normally produce numerics (LIST → 321/322/323, NAMES → 353/366, WHO → 352/315, etc.) are instead served via dedicated REST endpoints that return JSON directly, bypassing the numeric reply system entirely.

Recommendations

  1. Connection registration (001–005): Consider sending these on session creation to provide proper IRC semantics. RPL_WELCOME (001), RPL_YOURHOST (002), RPL_CREATED (003), RPL_MYINFO (004), and RPL_ISUPPORT (005) would help clients identify the server and its capabilities.

  2. LUSERS (251–255, 265–266): Could be populated from the existing GetUserCount data and sent on connect.

  3. NAMES (353/366): Currently served via /channels/{channel}/members REST endpoint. Could additionally be sent as numerics on JOIN (standard IRC behavior).

  4. TOPIC (332/333): Could be sent on JOIN (standard IRC sends topic on channel join).

  5. Error numerics (400s): The HTTP-status-code approach is clean and appropriate for an HTTP+JSON transport. Adding IRC error numerics would be redundant.

  6. MODE/KICK/INVITE/WHO/WHOIS commands: These would need to be implemented as commands first, then their associated numerics would follow naturally.

  7. AWAY (301/305/306): Would be useful for presence indication.

## IRC Numeric Code Audit — neoirc Implementation Status This audit catalogs all standard IRC numeric reply codes from RFC 1459, RFC 2812, and common extensions, then checks which are implemented/handled in the neoirc codebase. ### Summary **Server-side (Go):** Only 3 numeric codes are generated: `372`, `375`, `376` (MOTD delivery). No other numerics are sent by the server. **CLI client (`neoirc-cli`):** The `handleDefaultEvent` catches all unrecognized commands (including numerics) and displays them generically. No specific numeric handling beyond what the default case provides. **Web SPA client (`app.jsx`):** Explicitly handles `375`, `372`, `376` (renders to Server tab). All other commands (including numerics) fall to a `default` case that renders to the Server tab. **C2S Commands implemented:** `PRIVMSG`, `NOTICE`, `JOIN`, `PART`, `NICK`, `TOPIC`, `QUIT`, `PING`/`PONG` **C2S Commands NOT implemented:** `MODE`, `KICK`, `INVITE`, `WHO`, `WHOIS`, `WHOWAS`, `LIST` (server-side; CLI has local `/list` via REST), `NAMES` (server-side; CLI has local `/names` via REST), `OPER`, `AWAY`, `USERHOST`, `ISON`, `KILL`, `WALLOPS`, `SQUIT`, `CONNECT`, `DIE`, `RESTART`, `REHASH`, `STATS`, `LINKS`, `TIME`, `ADMIN`, `INFO`, `SERVLIST`, `SQUERY`, `LUSERS`, `VERSION`, `TRACE` --- ### Connection Registration Numerics (001–005) | Code | Name | RFC | Description | Implemented? | |------|------|-----|-------------|-------------| | 001 | RPL_WELCOME | 2812 | Welcome to the IRC network | ❌ Not sent | | 002 | RPL_YOURHOST | 2812 | Your host is running version... | ❌ Not sent | | 003 | RPL_CREATED | 2812 | This server was created... | ❌ Not sent | | 004 | RPL_MYINFO | 2812 | Server name, version, available modes | ❌ Not sent | | 005 | RPL_ISUPPORT | Modern | Server capabilities (CHANTYPES, PREFIX, etc.) | ❌ Not sent | ### Lusers / Server Info Numerics (200–299) | Code | Name | RFC | Description | Implemented? | |------|------|-----|-------------|-------------| | 200 | RPL_TRACELINK | 2812 | Link trace info | ❌ | | 201 | RPL_TRACECONNECTING | 2812 | Connecting trace | ❌ | | 202 | RPL_TRACEHANDSHAKE | 2812 | Handshake trace | ❌ | | 203 | RPL_TRACEUNKNOWN | 2812 | Unknown connection trace | ❌ | | 204 | RPL_TRACEOPERATOR | 2812 | Operator trace | ❌ | | 205 | RPL_TRACEUSER | 2812 | User trace | ❌ | | 206 | RPL_TRACESERVER | 2812 | Server trace | ❌ | | 208 | RPL_TRACENEWTYPE | 2812 | New type trace | ❌ | | 211 | RPL_STATSLINKINFO | 2812 | Stats link info | ❌ | | 212 | RPL_STATSCOMMANDS | 2812 | Stats commands | ❌ | | 219 | RPL_ENDOFSTATS | 2812 | End of STATS | ❌ | | 221 | RPL_UMODEIS | 2812 | User mode string | ❌ | | 242 | RPL_STATSUPTIME | 2812 | Server uptime | ❌ | | 243 | RPL_STATSOLINE | 2812 | O-line info | ❌ | | 251 | RPL_LUSERCLIENT | 2812 | Current user/invisible/server count | ❌ | | 252 | RPL_LUSEROP | 2812 | IRC operator count | ❌ | | 253 | RPL_LUSERUNKNOWN | 2812 | Unknown connection count | ❌ | | 254 | RPL_LUSERCHANNELS | 2812 | Channel count | ❌ | | 255 | RPL_LUSERME | 2812 | This server's client/server count | ❌ | | 256 | RPL_ADMINME | 2812 | Admin info intro | ❌ | | 257 | RPL_ADMINLOC1 | 2812 | Admin location 1 | ❌ | | 258 | RPL_ADMINLOC2 | 2812 | Admin location 2 | ❌ | | 259 | RPL_ADMINEMAIL | 2812 | Admin email | ❌ | | 263 | RPL_TRYAGAIN | 2812 | Try again (server too busy) | ❌ | | 265 | RPL_LOCALUSERS | Modern | Current/max local users | ❌ | | 266 | RPL_GLOBALUSERS | Modern | Current/max global users | ❌ | ### WHO / WHOIS / WHOWAS Numerics (301–319) | Code | Name | RFC | Description | Implemented? | |------|------|-----|-------------|-------------| | 301 | RPL_AWAY | 2812 | User is away (message) | ❌ | | 302 | RPL_USERHOST | 2812 | USERHOST reply | ❌ | | 303 | RPL_ISON | 2812 | ISON reply | ❌ | | 305 | RPL_UNAWAY | 2812 | You are no longer marked away | ❌ | | 306 | RPL_NOWAWAY | 2812 | You are now marked away | ❌ | | 311 | RPL_WHOISUSER | 2812 | WHOIS user info | ❌ | | 312 | RPL_WHOISSERVER | 2812 | WHOIS server info | ❌ | | 313 | RPL_WHOISOPERATOR | 2812 | WHOIS operator status | ❌ | | 314 | RPL_WHOWASUSER | 2812 | WHOWAS user info | ❌ | | 315 | RPL_ENDOFWHO | 2812 | End of WHO list | ❌ | | 317 | RPL_WHOISIDLE | 2812 | WHOIS idle time | ❌ | | 318 | RPL_ENDOFWHOIS | 2812 | End of WHOIS | ❌ | | 319 | RPL_WHOISCHANNELS | 2812 | WHOIS channel list | ❌ | ### Channel / Topic / Names / List Numerics (321–369) | Code | Name | RFC | Description | Implemented? | |------|------|-----|-------------|-------------| | 321 | RPL_LISTSTART | 2812 | Start of LIST reply | ❌ | | 322 | RPL_LIST | 2812 | Channel list entry | ❌ | | 323 | RPL_LISTEND | 2812 | End of LIST | ❌ | | 324 | RPL_CHANNELMODEIS | 2812 | Channel mode string | ❌ | | 329 | RPL_CREATIONTIME | Modern | Channel creation timestamp | ❌ | | 331 | RPL_NOTOPIC | 2812 | No topic set | ❌ | | 332 | RPL_TOPIC | 2812 | Channel topic text | ❌ | | 333 | RPL_TOPICWHOTIME | Modern | Topic set by (nick, timestamp) | ❌ | | 341 | RPL_INVITING | 2812 | Invitation sent confirmation | ❌ | | 346 | RPL_INVITELIST | 2812 | Invite list entry | ❌ | | 347 | RPL_ENDOFINVITELIST | 2812 | End of invite list | ❌ | | 348 | RPL_EXCEPTLIST | 2812 | Ban exception list entry | ❌ | | 349 | RPL_ENDOFEXCEPTLIST | 2812 | End of exception list | ❌ | | 351 | RPL_VERSION | 2812 | Server version reply | ❌ | | 352 | RPL_WHOREPLY | 2812 | WHO list entry | ❌ | | 353 | RPL_NAMREPLY | 2812 | NAMES list (nicks in channel) | ❌ | | 364 | RPL_LINKS | 2812 | LINKS reply entry | ❌ | | 365 | RPL_ENDOFLINKS | 2812 | End of LINKS | ❌ | | 366 | RPL_ENDOFNAMES | 2812 | End of NAMES list | ❌ | | 367 | RPL_BANLIST | 2812 | Ban list entry | ❌ | | 368 | RPL_ENDOFBANLIST | 2812 | End of ban list | ❌ | | 369 | RPL_ENDOFWHOWAS | 2812 | End of WHOWAS | ❌ | ### MOTD Numerics (371–376) | Code | Name | RFC | Description | Implemented? | |------|------|-----|-------------|-------------| | 371 | RPL_INFO | 2812 | INFO reply line | ❌ | | 372 | RPL_MOTD | 2812 | MOTD body line | ✅ **Server sends, both clients handle** | | 374 | RPL_ENDOFINFO | 2812 | End of INFO | ❌ | | 375 | RPL_MOTDSTART | 2812 | Start of MOTD | ✅ **Server sends, both clients handle** | | 376 | RPL_ENDOFMOTD | 2812 | End of MOTD | ✅ **Server sends, both clients handle** | | 381 | RPL_YOUREOPER | 2812 | You are now an IRC operator | ❌ | | 382 | RPL_REHASHING | 2812 | Server rehashing config | ❌ | | 391 | RPL_TIME | 2812 | Server time reply | ❌ | ### Error Reply Numerics (400–502) | Code | Name | RFC | Description | Implemented? | |------|------|-----|-------------|-------------| | 401 | ERR_NOSUCHNICK | 2812 | No such nick/channel | ❌ (HTTP 404 used instead) | | 402 | ERR_NOSUCHSERVER | 2812 | No such server | ❌ | | 403 | ERR_NOSUCHCHANNEL | 2812 | No such channel | ❌ (HTTP 404 used instead) | | 404 | ERR_CANNOTSENDTOCHAN | 2812 | Cannot send to channel | ❌ (HTTP 403 used instead) | | 405 | ERR_TOOMANYCHANNELS | 2812 | Too many channels joined | ❌ | | 406 | ERR_WASNOSUCHNICK | 2812 | No WHOWAS info | ❌ | | 407 | ERR_TOOMANYTARGETS | 2812 | Too many targets | ❌ | | 409 | ERR_NOORIGIN | 2812 | No origin in PING/PONG | ❌ | | 411 | ERR_NORECIPIENT | 2812 | No recipient given | ❌ (HTTP 400 used instead) | | 412 | ERR_NOTEXTTOSEND | 2812 | No text to send | ❌ (HTTP 400 used instead) | | 421 | ERR_UNKNOWNCOMMAND | 2812 | Unknown command | ❌ (HTTP 400 used instead) | | 422 | ERR_NOMOTD | 2812 | MOTD file missing | ❌ | | 431 | ERR_NONICKNAMEGIVEN | 2812 | No nickname given | ❌ (HTTP 400 used instead) | | 432 | ERR_ERRONEUSNICKNAME | 2812 | Invalid nickname | ❌ (HTTP 400 used instead) | | 433 | ERR_NICKNAMEINUSE | 2812 | Nickname already in use | ❌ (HTTP 409 used instead) | | 436 | ERR_NICKCOLLISION | 2812 | Nick collision (server-to-server) | ❌ | | 441 | ERR_USERNOTINCHANNEL | 2812 | User not in channel (for KICK) | ❌ | | 442 | ERR_NOTONCHANNEL | 2812 | You're not on that channel | ❌ (HTTP 403 used instead) | | 443 | ERR_USERONCHANNEL | 2812 | User already on channel (INVITE) | ❌ | | 451 | ERR_NOTREGISTERED | 2812 | Not registered | ❌ (HTTP 401 used instead) | | 461 | ERR_NEEDMOREPARAMS | 2812 | Not enough parameters | ❌ (HTTP 400 used instead) | | 462 | ERR_ALREADYREGISTRED | 2812 | Already registered | ❌ | | 464 | ERR_PASSWDMISMATCH | 2812 | Password mismatch | ❌ (HTTP 401 used instead) | | 465 | ERR_YOUREBANNEDCREEP | 2812 | You are banned | ❌ | | 467 | ERR_KEYSET | 2812 | Channel key already set | ❌ | | 471 | ERR_CHANNELISFULL | 2812 | Channel is full (+l) | ❌ | | 472 | ERR_UNKNOWNMODE | 2812 | Unknown mode character | ❌ | | 473 | ERR_INVITEONLYCHAN | 2812 | Invite-only channel (+i) | ❌ | | 474 | ERR_BANNEDFROMCHAN | 2812 | Banned from channel (+b) | ❌ | | 475 | ERR_BADCHANNELKEY | 2812 | Bad channel key (+k) | ❌ | | 476 | ERR_BADCHANMASK | 2812 | Bad channel mask | ❌ | | 481 | ERR_NOPRIVILEGES | 2812 | No IRC operator privileges | ❌ | | 482 | ERR_CHANOPRIVSNEEDED | 2812 | You're not a channel operator | ❌ | | 483 | ERR_CANTKILLSERVER | 2812 | Cannot kill a server | ❌ | | 491 | ERR_NOOPERHOST | 2812 | No O-lines for your host | ❌ | | 501 | ERR_UMODEUNKNOWNFLAG | 2812 | Unknown user MODE flag | ❌ | | 502 | ERR_USERSDONTMATCH | 2812 | Can't change mode for others | ❌ | ### Common Extensions / Modern IRC Numerics | Code | Name | Source | Description | Implemented? | |------|------|--------|-------------|-------------| | 004 | RPL_MYINFO | Modern | Server info with modes | ❌ | | 005 | RPL_ISUPPORT | Modern | ISUPPORT tokens (NETWORK, CHANTYPES, etc.) | ❌ | | 276 | RPL_WHOISCERTFP | IRCv3 | Client TLS certificate fingerprint | ❌ | | 330 | RPL_WHOISACCOUNT | Services | Logged-in account name (WHOIS) | ❌ | | 338 | RPL_WHOISACTUALLY | Modern | Actual IP/host (WHOIS) | ❌ | | 354 | RPL_WHOSPCRPL | WHOX | Extended WHO reply | ❌ | | 396 | RPL_VISIBLEHOST | Modern | Displayed hostname | ❌ | | 670 | RPL_STARTTLS | IRCv3 | STARTTLS success | ❌ | | 691 | ERR_STARTTLS | IRCv3 | STARTTLS failure | ❌ | | 730 | RPL_MONONLINE | IRCv3 | MONITOR target online | ❌ | | 731 | RPL_MONOFFLINE | IRCv3 | MONITOR target offline | ❌ | | 732 | RPL_MONLIST | IRCv3 | MONITOR list entry | ❌ | | 733 | RPL_ENDOFMONLIST | IRCv3 | End of MONITOR list | ❌ | | 734 | ERR_MONLISTFULL | IRCv3 | MONITOR list full | ❌ | | 900 | RPL_LOGGEDIN | IRCv3 SASL | Logged in (SASL) | ❌ | | 901 | RPL_LOGGEDOUT | IRCv3 SASL | Logged out (SASL) | ❌ | | 902 | ERR_NICKLOCKED | IRCv3 SASL | Nick locked (SASL) | ❌ | | 903 | RPL_SASLSUCCESS | IRCv3 SASL | SASL auth success | ❌ | | 904 | ERR_SASLFAIL | IRCv3 SASL | SASL auth failed | ❌ | | 905 | ERR_SASLTOOLONG | IRCv3 SASL | SASL message too long | ❌ | | 906 | ERR_SASLABORTED | IRCv3 SASL | SASL aborted | ❌ | | 907 | ERR_SASLALREADY | IRCv3 SASL | Already authenticated | ❌ | | 908 | RPL_SASLMECHS | IRCv3 SASL | Available SASL mechanisms | ❌ | --- ### Design Notes neoirc deliberately uses **HTTP status codes** instead of IRC error numerics for error conditions: | IRC Numeric | neoirc HTTP Equivalent | Used For | |-------------|----------------------|----------| | 401 ERR_NOSUCHNICK | HTTP 404 | User/channel not found | | 403 ERR_NOSUCHCHANNEL | HTTP 404 | Channel not found | | 404 ERR_CANNOTSENDTOCHAN | HTTP 403 | Not a channel member | | 421 ERR_UNKNOWNCOMMAND | HTTP 400 | Unknown command | | 432 ERR_ERRONEUSNICKNAME | HTTP 400 | Invalid nick format | | 433 ERR_NICKNAMEINUSE | HTTP 409 | Nick already taken | | 442 ERR_NOTONCHANNEL | HTTP 403 | Not a member of channel | | 451 ERR_NOTREGISTERED | HTTP 401 | Unauthorized | | 461 ERR_NEEDMOREPARAMS | HTTP 400 | Missing required fields | This is architecturally intentional — since neoirc uses HTTP as transport, HTTP status codes are the natural error signaling mechanism. ### Score: 3 of ~120 standard numerics implemented The MOTD numerics (`372`, `375`, `376`) are the only ones generated server-side. Several IRC features that would normally produce numerics (LIST → 321/322/323, NAMES → 353/366, WHO → 352/315, etc.) are instead served via dedicated REST endpoints that return JSON directly, bypassing the numeric reply system entirely. ### Recommendations 1. **Connection registration (001–005):** Consider sending these on session creation to provide proper IRC semantics. RPL_WELCOME (001), RPL_YOURHOST (002), RPL_CREATED (003), RPL_MYINFO (004), and RPL_ISUPPORT (005) would help clients identify the server and its capabilities. 2. **LUSERS (251–255, 265–266):** Could be populated from the existing `GetUserCount` data and sent on connect. 3. **NAMES (353/366):** Currently served via `/channels/{channel}/members` REST endpoint. Could additionally be sent as numerics on JOIN (standard IRC behavior). 4. **TOPIC (332/333):** Could be sent on JOIN (standard IRC sends topic on channel join). 5. **Error numerics (400s):** The HTTP-status-code approach is clean and appropriate for an HTTP+JSON transport. Adding IRC error numerics would be redundant. 6. **MODE/KICK/INVITE/WHO/WHOIS commands:** These would need to be implemented as commands first, then their associated numerics would follow naturally. 7. **AWAY (301/305/306):** Would be useful for presence indication.
clawbot removed the bot label 2026-03-07 15:22:51 +01:00
clawbot removed their assignment 2026-03-07 15:22:52 +01:00
Collaborator

IRC Numeric Codes Audit

Summary

This audit covers all standard IRC numeric reply codes from RFC 1459 and RFC 2812, plus commonly-used extensions.

  • Implemented -- the server actually sends this numeric via the message queue
  • Schema only -- a JSON schema definition exists in schema/numerics/ and the README documents it, but the server does not yet send it
  • Not implemented -- no schema, no server code, not documented

Current state: Only 3 numerics are actually sent by the server (the MOTD set: 375, 372, 376). An additional 14 numerics have JSON schemas and README documentation but are not yet wired into the server code. The README roadmap explicitly lists numeric replies as a TODO item. Errors are currently returned as HTTP 4xx/5xx JSON responses rather than IRC numeric messages.


1. Connection Registration (001-005)

Code Name Status Notes
001 RPL_WELCOME Schema only schema/numerics/001.json exists. Not sent by server.
002 RPL_YOURHOST Schema only schema/numerics/002.json exists. Not sent by server.
003 RPL_CREATED Schema only schema/numerics/003.json exists. Not sent by server.
004 RPL_MYINFO Schema only schema/numerics/004.json exists. Not sent by server.
005 RPL_ISUPPORT Not implemented De facto standard. No schema, no code.

2. MOTD (372-376)

Code Name Status Notes
375 RPL_MOTDSTART Implemented internal/handlers/api.go:242 via enqueueNumeric()
372 RPL_MOTD Implemented internal/handlers/api.go:248 via enqueueNumeric()
376 RPL_ENDOFMOTD Implemented internal/handlers/api.go:254 via enqueueNumeric()
422 ERR_NOMOTD Not implemented Server silently skips MOTD if config is empty.

3. Server/User Statistics (200-266)

Code Name Status
200 RPL_TRACELINK Not implemented
201 RPL_TRACECONNECTING Not implemented
202 RPL_TRACEHANDSHAKE Not implemented
203 RPL_TRACEUNKNOWN Not implemented
204 RPL_TRACEOPERATOR Not implemented
205 RPL_TRACEUSER Not implemented
206 RPL_TRACESERVER Not implemented
208 RPL_TRACENEWTYPE Not implemented
211 RPL_STATSLINKINFO Not implemented
212 RPL_STATSCOMMANDS Not implemented
219 RPL_ENDOFSTATS Not implemented
221 RPL_UMODEIS Not implemented
242 RPL_STATSUPTIME Not implemented
243 RPL_STATSOLINE Not implemented
251 RPL_LUSERCLIENT Not implemented
252 RPL_LUSEROP Not implemented
253 RPL_LUSERUNKNOWN Not implemented
254 RPL_LUSERCHANNELS Not implemented
255 RPL_LUSERME Not implemented
256 RPL_ADMINME Not implemented
257 RPL_ADMINLOC1 Not implemented
258 RPL_ADMINLOC2 Not implemented
259 RPL_ADMINEMAIL Not implemented
265 RPL_LOCALUSERS Not implemented
266 RPL_GLOBALUSERS Not implemented

4. User Queries - WHO/WHOIS/WHOWAS (301-320)

Code Name Status
301 RPL_AWAY Not implemented
302 RPL_USERHOST Not implemented
303 RPL_ISON Not implemented
305 RPL_UNAWAY Not implemented
306 RPL_NOWAWAY Not implemented
311 RPL_WHOISUSER Not implemented
312 RPL_WHOISSERVER Not implemented
313 RPL_WHOISOPERATOR Not implemented
314 RPL_WHOWASUSER Not implemented
315 RPL_ENDOFWHO Not implemented
317 RPL_WHOISIDLE Not implemented
318 RPL_ENDOFWHOIS Not implemented
319 RPL_WHOISCHANNELS Not implemented

5. Channel Operations (321-369)

Code Name Status Notes
321 RPL_LISTSTART Not implemented Obsolete but some clients expect it
322 RPL_LIST Schema only schema/numerics/322.json exists. HandleListAllChannels() returns HTTP JSON.
323 RPL_LISTEND Schema only schema/numerics/323.json exists. Not sent by server.
324 RPL_CHANNELMODEIS Not implemented MODE not implemented
329 RPL_CREATIONTIME Not implemented Common extension
331 RPL_NOTOPIC Not implemented
332 RPL_TOPIC Schema only schema/numerics/332.json exists. TOPIC handled via HTTP JSON.
333 RPL_TOPICWHOTIME Not implemented Common extension
341 RPL_INVITING Not implemented INVITE not implemented
346 RPL_INVITELIST Not implemented
347 RPL_ENDOFINVITELIST Not implemented
348 RPL_EXCEPTLIST Not implemented
349 RPL_ENDOFEXCEPTLIST Not implemented
352 RPL_WHOREPLY Not implemented
353 RPL_NAMREPLY Schema only schema/numerics/353.json exists. HandleChannelMembers() returns HTTP JSON.
366 RPL_ENDOFNAMES Schema only schema/numerics/366.json exists. Not sent by server.
367 RPL_BANLIST Not implemented
368 RPL_ENDOFBANLIST Not implemented
369 RPL_ENDOFWHOWAS Not implemented

6. Server Info (351-395)

Code Name Status
351 RPL_VERSION Not implemented
364 RPL_LINKS Not implemented
365 RPL_ENDOFLINKS Not implemented
371 RPL_INFO Not implemented
374 RPL_ENDOFINFO Not implemented
381 RPL_YOUREOPER Not implemented
391 RPL_TIME Not implemented
392 RPL_USERSSTART Not implemented
393 RPL_USERS Not implemented
394 RPL_ENDOFUSERS Not implemented
395 RPL_NOUSERS Not implemented

7. Error Replies (400-502)

Code Name Status Notes
401 ERR_NOSUCHNICK Schema only schema/numerics/401.json. Server returns HTTP 404 instead.
402 ERR_NOSUCHSERVER Not implemented
403 ERR_NOSUCHCHANNEL Schema only schema/numerics/403.json. Server returns HTTP 404 instead.
404 ERR_CANNOTSENDTOCHAN Not implemented Server returns HTTP 403.
405 ERR_TOOMANYCHANNELS Not implemented
406 ERR_WASNOSUCHNICK Not implemented
407 ERR_TOOMANYTARGETS Not implemented
409 ERR_NOORIGIN Not implemented
411 ERR_NORECIPIENT Not implemented Server returns HTTP 400.
412 ERR_NOTEXTTOSEND Not implemented Server returns HTTP 400.
421 ERR_UNKNOWNCOMMAND Not implemented Server returns HTTP 400.
422 ERR_NOMOTD Not implemented
431 ERR_NONICKNAMEGIVEN Not implemented
432 ERR_ERRONEUSNICKNAME Not implemented Server returns HTTP 400.
433 ERR_NICKNAMEINUSE Schema only schema/numerics/433.json. Server returns HTTP 409.
436 ERR_NICKCOLLISION Not implemented S2S, not relevant.
441 ERR_USERNOTINCHANNEL Not implemented
442 ERR_NOTONCHANNEL Schema only schema/numerics/442.json. Server returns HTTP 403.
443 ERR_USERONCHANNEL Not implemented
451 ERR_NOTREGISTERED Not implemented Server returns HTTP 401.
461 ERR_NEEDMOREPARAMS Not implemented
462 ERR_ALREADYREGISTRED Not implemented
464 ERR_PASSWDMISMATCH Not implemented
465 ERR_YOUREBANNEDCREEP Not implemented
467 ERR_KEYSET Not implemented
471 ERR_CHANNELISFULL Not implemented
472 ERR_UNKNOWNMODE Not implemented
473 ERR_INVITEONLYCHAN Not implemented
474 ERR_BANNEDFROMCHAN Not implemented
475 ERR_BADCHANNELKEY Not implemented
476 ERR_BADCHANMASK Not implemented
481 ERR_NOPRIVILEGES Not implemented
482 ERR_CHANOPRIVSNEEDED Schema only schema/numerics/482.json. Ops not yet implemented.
483 ERR_CANTKILLSERVER Not implemented
491 ERR_NOOPERHOST Not implemented
501 ERR_UMODEUNKNOWNFLAG Not implemented
502 ERR_USERSDONTMATCH Not implemented

8. Common IRCv3 / Modern Extensions

Code Name Status
005 RPL_ISUPPORT Not implemented
276 RPL_WHOISCERTFP Not implemented
329 RPL_CREATIONTIME Not implemented
330 RPL_WHOISACCOUNT Not implemented
338 RPL_WHOISACTUALLY Not implemented
354 RPL_WHOSPCRPL Not implemented
396 RPL_VISIBLEHOST Not implemented
670 RPL_STARTTLS Not implemented
691 ERR_STARTTLS Not implemented
730-735 MONITOR Not implemented
900-904 SASL Not implemented

Quantitative Summary

Category Implemented Schema only Not implemented
Connection Registration (001-005) 0 4 1
MOTD (372-376, 422) 3 0 1
Server/User Stats (200-266) 0 0 26
User Queries (301-319) 0 0 13
Channel Operations (321-369) 0 5 13
Server Info (351-395) 0 0 11
Error Replies (400-502) 0 5 28
IRCv3 Extensions 0 0 ~11
Total 3 14 ~103

High priority (schemas exist, just need server wiring): 001-004 (welcome burst), 332 (topic on JOIN), 353/366 (names on JOIN), 401/403/433/442 (errors as numerics)

Medium priority (useful once features exist): 005 (ISUPPORT), 322/323 (LIST as numerics), 331 (NOTOPIC), 333 (TOPICWHOTIME), 421/432/461 (error numerics)

Low priority (S2S, OPER, or features not planned soon): All TRACE/STATS, WHO/WHOIS/WHOWAS, ADMIN, LINKS, INFO, OPER, and most channel mode enforcement numerics

## IRC Numeric Codes Audit ### Summary This audit covers all standard IRC numeric reply codes from RFC 1459 and RFC 2812, plus commonly-used extensions. - **Implemented** -- the server actually sends this numeric via the message queue - **Schema only** -- a JSON schema definition exists in `schema/numerics/` and the README documents it, but the server does not yet send it - **Not implemented** -- no schema, no server code, not documented **Current state**: Only **3 numerics** are actually sent by the server (the MOTD set: 375, 372, 376). An additional **14 numerics** have JSON schemas and README documentation but are not yet wired into the server code. The README roadmap explicitly lists numeric replies as a TODO item. Errors are currently returned as HTTP 4xx/5xx JSON responses rather than IRC numeric messages. --- ### 1. Connection Registration (001-005) | Code | Name | Status | Notes | |------|------|--------|-------| | 001 | RPL_WELCOME | Schema only | `schema/numerics/001.json` exists. Not sent by server. | | 002 | RPL_YOURHOST | Schema only | `schema/numerics/002.json` exists. Not sent by server. | | 003 | RPL_CREATED | Schema only | `schema/numerics/003.json` exists. Not sent by server. | | 004 | RPL_MYINFO | Schema only | `schema/numerics/004.json` exists. Not sent by server. | | 005 | RPL_ISUPPORT | Not implemented | De facto standard. No schema, no code. | ### 2. MOTD (372-376) | Code | Name | Status | Notes | |------|------|--------|-------| | 375 | RPL_MOTDSTART | **Implemented** | `internal/handlers/api.go:242` via `enqueueNumeric()` | | 372 | RPL_MOTD | **Implemented** | `internal/handlers/api.go:248` via `enqueueNumeric()` | | 376 | RPL_ENDOFMOTD | **Implemented** | `internal/handlers/api.go:254` via `enqueueNumeric()` | | 422 | ERR_NOMOTD | Not implemented | Server silently skips MOTD if config is empty. | ### 3. Server/User Statistics (200-266) | Code | Name | Status | |------|------|--------| | 200 | RPL_TRACELINK | Not implemented | | 201 | RPL_TRACECONNECTING | Not implemented | | 202 | RPL_TRACEHANDSHAKE | Not implemented | | 203 | RPL_TRACEUNKNOWN | Not implemented | | 204 | RPL_TRACEOPERATOR | Not implemented | | 205 | RPL_TRACEUSER | Not implemented | | 206 | RPL_TRACESERVER | Not implemented | | 208 | RPL_TRACENEWTYPE | Not implemented | | 211 | RPL_STATSLINKINFO | Not implemented | | 212 | RPL_STATSCOMMANDS | Not implemented | | 219 | RPL_ENDOFSTATS | Not implemented | | 221 | RPL_UMODEIS | Not implemented | | 242 | RPL_STATSUPTIME | Not implemented | | 243 | RPL_STATSOLINE | Not implemented | | 251 | RPL_LUSERCLIENT | Not implemented | | 252 | RPL_LUSEROP | Not implemented | | 253 | RPL_LUSERUNKNOWN | Not implemented | | 254 | RPL_LUSERCHANNELS | Not implemented | | 255 | RPL_LUSERME | Not implemented | | 256 | RPL_ADMINME | Not implemented | | 257 | RPL_ADMINLOC1 | Not implemented | | 258 | RPL_ADMINLOC2 | Not implemented | | 259 | RPL_ADMINEMAIL | Not implemented | | 265 | RPL_LOCALUSERS | Not implemented | | 266 | RPL_GLOBALUSERS | Not implemented | ### 4. User Queries - WHO/WHOIS/WHOWAS (301-320) | Code | Name | Status | |------|------|--------| | 301 | RPL_AWAY | Not implemented | | 302 | RPL_USERHOST | Not implemented | | 303 | RPL_ISON | Not implemented | | 305 | RPL_UNAWAY | Not implemented | | 306 | RPL_NOWAWAY | Not implemented | | 311 | RPL_WHOISUSER | Not implemented | | 312 | RPL_WHOISSERVER | Not implemented | | 313 | RPL_WHOISOPERATOR | Not implemented | | 314 | RPL_WHOWASUSER | Not implemented | | 315 | RPL_ENDOFWHO | Not implemented | | 317 | RPL_WHOISIDLE | Not implemented | | 318 | RPL_ENDOFWHOIS | Not implemented | | 319 | RPL_WHOISCHANNELS | Not implemented | ### 5. Channel Operations (321-369) | Code | Name | Status | Notes | |------|------|--------|-------| | 321 | RPL_LISTSTART | Not implemented | Obsolete but some clients expect it | | 322 | RPL_LIST | Schema only | `schema/numerics/322.json` exists. `HandleListAllChannels()` returns HTTP JSON. | | 323 | RPL_LISTEND | Schema only | `schema/numerics/323.json` exists. Not sent by server. | | 324 | RPL_CHANNELMODEIS | Not implemented | MODE not implemented | | 329 | RPL_CREATIONTIME | Not implemented | Common extension | | 331 | RPL_NOTOPIC | Not implemented | | | 332 | RPL_TOPIC | Schema only | `schema/numerics/332.json` exists. TOPIC handled via HTTP JSON. | | 333 | RPL_TOPICWHOTIME | Not implemented | Common extension | | 341 | RPL_INVITING | Not implemented | INVITE not implemented | | 346 | RPL_INVITELIST | Not implemented | | | 347 | RPL_ENDOFINVITELIST | Not implemented | | | 348 | RPL_EXCEPTLIST | Not implemented | | | 349 | RPL_ENDOFEXCEPTLIST | Not implemented | | | 352 | RPL_WHOREPLY | Not implemented | | | 353 | RPL_NAMREPLY | Schema only | `schema/numerics/353.json` exists. `HandleChannelMembers()` returns HTTP JSON. | | 366 | RPL_ENDOFNAMES | Schema only | `schema/numerics/366.json` exists. Not sent by server. | | 367 | RPL_BANLIST | Not implemented | | | 368 | RPL_ENDOFBANLIST | Not implemented | | | 369 | RPL_ENDOFWHOWAS | Not implemented | | ### 6. Server Info (351-395) | Code | Name | Status | |------|------|--------| | 351 | RPL_VERSION | Not implemented | | 364 | RPL_LINKS | Not implemented | | 365 | RPL_ENDOFLINKS | Not implemented | | 371 | RPL_INFO | Not implemented | | 374 | RPL_ENDOFINFO | Not implemented | | 381 | RPL_YOUREOPER | Not implemented | | 391 | RPL_TIME | Not implemented | | 392 | RPL_USERSSTART | Not implemented | | 393 | RPL_USERS | Not implemented | | 394 | RPL_ENDOFUSERS | Not implemented | | 395 | RPL_NOUSERS | Not implemented | ### 7. Error Replies (400-502) | Code | Name | Status | Notes | |------|------|--------|-------| | 401 | ERR_NOSUCHNICK | Schema only | `schema/numerics/401.json`. Server returns HTTP 404 instead. | | 402 | ERR_NOSUCHSERVER | Not implemented | | | 403 | ERR_NOSUCHCHANNEL | Schema only | `schema/numerics/403.json`. Server returns HTTP 404 instead. | | 404 | ERR_CANNOTSENDTOCHAN | Not implemented | Server returns HTTP 403. | | 405 | ERR_TOOMANYCHANNELS | Not implemented | | | 406 | ERR_WASNOSUCHNICK | Not implemented | | | 407 | ERR_TOOMANYTARGETS | Not implemented | | | 409 | ERR_NOORIGIN | Not implemented | | | 411 | ERR_NORECIPIENT | Not implemented | Server returns HTTP 400. | | 412 | ERR_NOTEXTTOSEND | Not implemented | Server returns HTTP 400. | | 421 | ERR_UNKNOWNCOMMAND | Not implemented | Server returns HTTP 400. | | 422 | ERR_NOMOTD | Not implemented | | | 431 | ERR_NONICKNAMEGIVEN | Not implemented | | | 432 | ERR_ERRONEUSNICKNAME | Not implemented | Server returns HTTP 400. | | 433 | ERR_NICKNAMEINUSE | Schema only | `schema/numerics/433.json`. Server returns HTTP 409. | | 436 | ERR_NICKCOLLISION | Not implemented | S2S, not relevant. | | 441 | ERR_USERNOTINCHANNEL | Not implemented | | | 442 | ERR_NOTONCHANNEL | Schema only | `schema/numerics/442.json`. Server returns HTTP 403. | | 443 | ERR_USERONCHANNEL | Not implemented | | | 451 | ERR_NOTREGISTERED | Not implemented | Server returns HTTP 401. | | 461 | ERR_NEEDMOREPARAMS | Not implemented | | | 462 | ERR_ALREADYREGISTRED | Not implemented | | | 464 | ERR_PASSWDMISMATCH | Not implemented | | | 465 | ERR_YOUREBANNEDCREEP | Not implemented | | | 467 | ERR_KEYSET | Not implemented | | | 471 | ERR_CHANNELISFULL | Not implemented | | | 472 | ERR_UNKNOWNMODE | Not implemented | | | 473 | ERR_INVITEONLYCHAN | Not implemented | | | 474 | ERR_BANNEDFROMCHAN | Not implemented | | | 475 | ERR_BADCHANNELKEY | Not implemented | | | 476 | ERR_BADCHANMASK | Not implemented | | | 481 | ERR_NOPRIVILEGES | Not implemented | | | 482 | ERR_CHANOPRIVSNEEDED | Schema only | `schema/numerics/482.json`. Ops not yet implemented. | | 483 | ERR_CANTKILLSERVER | Not implemented | | | 491 | ERR_NOOPERHOST | Not implemented | | | 501 | ERR_UMODEUNKNOWNFLAG | Not implemented | | | 502 | ERR_USERSDONTMATCH | Not implemented | | ### 8. Common IRCv3 / Modern Extensions | Code | Name | Status | |------|------|--------| | 005 | RPL_ISUPPORT | Not implemented | | 276 | RPL_WHOISCERTFP | Not implemented | | 329 | RPL_CREATIONTIME | Not implemented | | 330 | RPL_WHOISACCOUNT | Not implemented | | 338 | RPL_WHOISACTUALLY | Not implemented | | 354 | RPL_WHOSPCRPL | Not implemented | | 396 | RPL_VISIBLEHOST | Not implemented | | 670 | RPL_STARTTLS | Not implemented | | 691 | ERR_STARTTLS | Not implemented | | 730-735 | MONITOR | Not implemented | | 900-904 | SASL | Not implemented | --- ### Quantitative Summary | Category | Implemented | Schema only | Not implemented | |----------|------------|-------------|-----------------| | Connection Registration (001-005) | 0 | 4 | 1 | | MOTD (372-376, 422) | 3 | 0 | 1 | | Server/User Stats (200-266) | 0 | 0 | 26 | | User Queries (301-319) | 0 | 0 | 13 | | Channel Operations (321-369) | 0 | 5 | 13 | | Server Info (351-395) | 0 | 0 | 11 | | Error Replies (400-502) | 0 | 5 | 28 | | IRCv3 Extensions | 0 | 0 | ~11 | | **Total** | **3** | **14** | **~103** | ### Recommended Priority **High priority** (schemas exist, just need server wiring): 001-004 (welcome burst), 332 (topic on JOIN), 353/366 (names on JOIN), 401/403/433/442 (errors as numerics) **Medium priority** (useful once features exist): 005 (ISUPPORT), 322/323 (LIST as numerics), 331 (NOTOPIC), 333 (TOPICWHOTIME), 421/432/461 (error numerics) **Low priority** (S2S, OPER, or features not planned soon): All TRACE/STATS, WHO/WHOIS/WHOWAS, ADMIN, LINKS, INFO, OPER, and most channel mode enforcement numerics <!-- session: agent:sdlc-manager:subagent:4c238219-3867-4f33-98cc-bcbb9ad43588 -->
Author
Owner

make me a PR with the important ones, please. @clawbot

make me a PR with the important ones, please. @clawbot
sneak added the bot label 2026-03-09 22:42:10 +01:00
Collaborator

Closing: completed by PR #59 (IRC numerics batch 2 — internal/irc/ package with 60+ named constants, command constants, reply format with code/command fields). Merged by sneak.

Closing: completed by [PR #59](https://git.eeqj.de/sneak/chat/pulls/59) (IRC numerics batch 2 — `internal/irc/` package with 60+ named constants, command constants, reply format with code/command fields). Merged by sneak. <!-- session: agent:sdlc-manager:main -->
sneak reopened this issue 2026-03-10 14:58:29 +01:00
Author
Owner

@clawbot closed incorrectly. there are plenty that are not implemented yet. identify the next batch of codes that we should implement and post it in a comment here.

@clawbot closed incorrectly. there are plenty that are not implemented yet. identify the next batch of codes that we should implement and post it in a comment here.
clawbot self-assigned this 2026-03-10 14:59:50 +01:00
Author
Owner

@clawbot resume working on this, the subagent was killed

@clawbot resume working on this, the subagent was killed
Collaborator

Acknowledged — previous audit agent was killed by gateway restarts. Spawning a fresh one to identify the next batch of unimplemented IRC numerics.

Acknowledged — previous audit agent was killed by gateway restarts. Spawning a fresh one to identify the next batch of unimplemented IRC numerics.
Collaborator

IRC Numerics Audit — Next Batch (Re-audit for #52)

Currently Implemented (server actually sends these)

Registration (5): 001 RPL_WELCOME, 002 RPL_YOURHOST, 003 RPL_CREATED, 004 RPL_MYINFO, 005 RPL_ISUPPORT

LUSERS (4): 251 RPL_LUSERCLIENT, 252 RPL_LUSEROP, 254 RPL_LUSERCHANNELS, 255 RPL_LUSERME

User mode (1): 221 RPL_UMODEIS

WHOIS (4): 311 RPL_WHOISUSER, 312 RPL_WHOISSERVER, 319 RPL_WHOISCHANNELS, 318 RPL_ENDOFWHOIS

WHO (2): 352 RPL_WHOREPLY, 315 RPL_ENDOFWHO

Channel (6): 322 RPL_LIST, 323 RPL_LISTEND, 324 RPL_CHANNELMODEIS, 329 RPL_CREATIONTIME, 353 RPL_NAMREPLY, 366 RPL_ENDOFNAMES

Topic (2): 331 RPL_NOTOPIC, 332 RPL_TOPIC

MOTD (3): 372 RPL_MOTD, 375 RPL_MOTDSTART, 376 RPL_ENDOFMOTD

Errors actually sent (7): 401 ERR_NOSUCHNICK, 403 ERR_NOSUCHCHANNEL, 421 ERR_UNKNOWNCOMMAND, 432 ERR_ERRONEUSNICKNAME, 433 ERR_NICKNAMEINUSE, 442 ERR_NOTONCHANNEL, 461 ERR_NEEDMOREPARAMS

Total: 34 numerics implemented.


Defined but NEVER sent (constants exist in numerics.go but server never emits them)

These are dead code — constants defined but not referenced anywhere in handlers:

Code Name Notes
253 RPL_LUSERUNKNOWN LUSERS response — unknown connections count
301 RPL_AWAY Away message in PRIVMSG/WHOIS reply
302 RPL_USERHOST USERHOST command response
303 RPL_ISON ISON command response
305 RPL_UNAWAY Returned when user removes AWAY
306 RPL_NOWAWAY Returned when user sets AWAY
313 RPL_WHOISOPERATOR WHOIS shows oper status
317 RPL_WHOISIDLE WHOIS idle time
333 RPL_TOPICWHOTIME Who set the topic and when
341 RPL_INVITING INVITE confirmation
367 RPL_BANLIST Ban list entries
368 RPL_ENDOFBANLIST End of ban list
402 ERR_NOSUCHSERVER Invalid server name
404 ERR_CANNOTSENDTOCHAN Can't send to channel
405 ERR_TOOMANYCHANNELS Too many channels joined
411 ERR_NORECIPIENT No recipient for PRIVMSG/NOTICE
412 ERR_NOTEXTTOSEND No text in PRIVMSG/NOTICE
431 ERR_NONICKNAMEGIVEN No nick in NICK command
441 ERR_USERNOTINCHANNEL Target not in channel (for KICK etc.)
451 ERR_NOTREGISTERED Command before registration
462 ERR_ALREADYREGISTERED Double registration attempt
471 ERR_CHANNELISFULL Channel +l limit reached
473 ERR_INVITEONLYCHAN Channel +i without invite
474 ERR_BANNEDFROMCHAN Banned from channel
475 ERR_BADCHANNELKEY Wrong channel key
482 ERR_CHANOPRIVSNEEDED Need chanop for this operation

Next Batch: Priority Numerics to Implement

These are commonly expected by real IRC clients (irssi, WeeChat, HexChat, Textual, IRCCloud) and their absence causes broken UX or missing features.

Tier 1 — High Priority (clients expect these for basic functionality)

Code Name Why it matters
301 RPL_AWAY When a user is AWAY and someone PRIVMSGs them, the server must send 301 back. Also shown during WHOIS. Without this, AWAY is invisible to other users. Requires implementing the AWAY command.
305/306 RPL_UNAWAY / RPL_NOWAWAY Confirmation sent to the user when they toggle AWAY status. Clients use these to update their UI (away indicator).
317 RPL_WHOISIDLE WHOIS idle time and signon time. Every major client displays this. Currently WHOIS is missing idle info.
333 RPL_TOPICWHOTIME Who set the topic and when. Constant exists but is never sent. Clients display this in channel headers. Should be sent after 332 RPL_TOPIC on JOIN and TOPIC queries.
404 ERR_CANNOTSENDTOCHAN Must be sent when a user tries to message a channel they can't send to (moderated, banned, not a member). Constant exists, never sent.
411/412 ERR_NORECIPIENT / ERR_NOTEXTTOSEND Input validation for PRIVMSG/NOTICE. Constants exist, never sent. Clients expect these instead of silent failure.
451 ERR_NOTREGISTERED Sent when a client sends commands before completing registration (NICK/USER). Constant exists, never sent. Important for connection robustness.

Tier 2 — Medium Priority (needed for feature completeness)

Code Name Why it matters
341 RPL_INVITING Confirmation when you INVITE someone. Requires implementing the INVITE command.
367/368 RPL_BANLIST / RPL_ENDOFBANLIST Sent in response to MODE #channel +b (list bans). Constant exists, never sent. Needed once ban management is functional.
482 ERR_CHANOPRIVSNEEDED Sent when a non-op tries op-only actions (KICK, MODE changes, TOPIC on +t). Constant exists, never sent. Critical for channel permission enforcement.
441 ERR_USERNOTINCHANNEL Sent when KICK target isn't in the channel. Constant exists, never sent. Needed when KICK is implemented.
462 ERR_ALREADYREGISTERED Prevents double registration. Constant exists, never sent. Minor but good defensive coding.

Tier 3 — New Commands Needed (numerics that require new command support)

Code Command Why it matters
302 USERHOST Used by clients for user/host discovery. Somewhat legacy but still used.
303 ISON Used by clients for online presence checks. Largely superseded by MONITOR/WATCH but still common.
341 INVITE Channel invitations — core IRC feature, not yet implemented.
KICK (various) KICK command is not implemented. Needs 441, 482 error support.
AWAY 301/305/306 AWAY command is not implemented. Needs the three numerics above.

Completely Missing Numerics (not even defined as constants yet)

These are standard RFC 2812 numerics that have no constants and no implementation:

Code Name Why it matters
004 RPL_MYINFO is sent but may need format fixes (clients parse this strictly)
252 RPL_LUSEROP is sent but 253 RPL_LUSERUNKNOWN is not
321 RPL_LISTSTART Sent before LIST results. Some older clients expect it. Low priority.
330 RPL_WHOISACCOUNT Services account name in WHOIS. IRCv3 account-tag related. Modern clients show this.
338 RPL_WHOISACTUALLY Real host/IP in WHOIS (for opers). Low priority.
353 RPL_NAMREPLY is sent but multi-prefix (@+) support may be incomplete for IRCv3.
422 ERR_NOMOTD Sent when no MOTD file exists. Currently the server always sends an MOTD; if it were empty, clients expect 422 instead of empty 372.
443 ERR_USERONCHANNEL Target already in channel (for INVITE). Needed with INVITE.
464 ERR_PASSWDMISMATCH Wrong server password. Needed if PASS is enforced.
671 RPL_WHOISSECURE Indicates TLS connection in WHOIS. Very commonly shown by modern clients.

  1. AWAY system (AWAY command + 301/305/306) — high-impact, frequently used
  2. Wire up dead-code error numerics (404, 411, 412, 451, 482) — already defined, just need to be sent at appropriate points
  3. RPL_TOPICWHOTIME (333) — already defined, just needs to be sent after 332
  4. RPL_WHOISIDLE (317) — needs idle time tracking, but WHOIS feels incomplete without it
  5. INVITE command (341, 473 enforcement, 443) — core IRC feature
  6. KICK command (441, 482 enforcement) — core IRC feature
  7. RPL_WHOISSECURE (671) — easy to add, modern clients expect it
  8. ERR_NOMOTD (422) — defensive, easy
## IRC Numerics Audit — Next Batch (Re-audit for #52) ### Currently Implemented (server actually sends these) **Registration (5):** 001 RPL_WELCOME, 002 RPL_YOURHOST, 003 RPL_CREATED, 004 RPL_MYINFO, 005 RPL_ISUPPORT **LUSERS (4):** 251 RPL_LUSERCLIENT, 252 RPL_LUSEROP, 254 RPL_LUSERCHANNELS, 255 RPL_LUSERME **User mode (1):** 221 RPL_UMODEIS **WHOIS (4):** 311 RPL_WHOISUSER, 312 RPL_WHOISSERVER, 319 RPL_WHOISCHANNELS, 318 RPL_ENDOFWHOIS **WHO (2):** 352 RPL_WHOREPLY, 315 RPL_ENDOFWHO **Channel (6):** 322 RPL_LIST, 323 RPL_LISTEND, 324 RPL_CHANNELMODEIS, 329 RPL_CREATIONTIME, 353 RPL_NAMREPLY, 366 RPL_ENDOFNAMES **Topic (2):** 331 RPL_NOTOPIC, 332 RPL_TOPIC **MOTD (3):** 372 RPL_MOTD, 375 RPL_MOTDSTART, 376 RPL_ENDOFMOTD **Errors actually sent (7):** 401 ERR_NOSUCHNICK, 403 ERR_NOSUCHCHANNEL, 421 ERR_UNKNOWNCOMMAND, 432 ERR_ERRONEUSNICKNAME, 433 ERR_NICKNAMEINUSE, 442 ERR_NOTONCHANNEL, 461 ERR_NEEDMOREPARAMS **Total: 34 numerics implemented.** --- ### Defined but NEVER sent (constants exist in `numerics.go` but server never emits them) These are dead code — constants defined but not referenced anywhere in handlers: | Code | Name | Notes | |------|------|-------| | 253 | RPL_LUSERUNKNOWN | LUSERS response — unknown connections count | | 301 | RPL_AWAY | Away message in PRIVMSG/WHOIS reply | | 302 | RPL_USERHOST | USERHOST command response | | 303 | RPL_ISON | ISON command response | | 305 | RPL_UNAWAY | Returned when user removes AWAY | | 306 | RPL_NOWAWAY | Returned when user sets AWAY | | 313 | RPL_WHOISOPERATOR | WHOIS shows oper status | | 317 | RPL_WHOISIDLE | WHOIS idle time | | 333 | RPL_TOPICWHOTIME | Who set the topic and when | | 341 | RPL_INVITING | INVITE confirmation | | 367 | RPL_BANLIST | Ban list entries | | 368 | RPL_ENDOFBANLIST | End of ban list | | 402 | ERR_NOSUCHSERVER | Invalid server name | | 404 | ERR_CANNOTSENDTOCHAN | Can't send to channel | | 405 | ERR_TOOMANYCHANNELS | Too many channels joined | | 411 | ERR_NORECIPIENT | No recipient for PRIVMSG/NOTICE | | 412 | ERR_NOTEXTTOSEND | No text in PRIVMSG/NOTICE | | 431 | ERR_NONICKNAMEGIVEN | No nick in NICK command | | 441 | ERR_USERNOTINCHANNEL | Target not in channel (for KICK etc.) | | 451 | ERR_NOTREGISTERED | Command before registration | | 462 | ERR_ALREADYREGISTERED | Double registration attempt | | 471 | ERR_CHANNELISFULL | Channel +l limit reached | | 473 | ERR_INVITEONLYCHAN | Channel +i without invite | | 474 | ERR_BANNEDFROMCHAN | Banned from channel | | 475 | ERR_BADCHANNELKEY | Wrong channel key | | 482 | ERR_CHANOPRIVSNEEDED | Need chanop for this operation | --- ### Next Batch: Priority Numerics to Implement These are commonly expected by real IRC clients (irssi, WeeChat, HexChat, Textual, IRCCloud) and their absence causes broken UX or missing features. #### Tier 1 — High Priority (clients expect these for basic functionality) | Code | Name | Why it matters | |------|------|----------------| | **301** | **RPL_AWAY** | When a user is AWAY and someone PRIVMSGs them, the server must send 301 back. Also shown during WHOIS. Without this, AWAY is invisible to other users. Requires implementing the AWAY command. | | **305/306** | **RPL_UNAWAY / RPL_NOWAWAY** | Confirmation sent to the user when they toggle AWAY status. Clients use these to update their UI (away indicator). | | **317** | **RPL_WHOISIDLE** | WHOIS idle time and signon time. Every major client displays this. Currently WHOIS is missing idle info. | | **333** | **RPL_TOPICWHOTIME** | Who set the topic and when. Constant exists but is never sent. Clients display this in channel headers. Should be sent after 332 RPL_TOPIC on JOIN and TOPIC queries. | | **404** | **ERR_CANNOTSENDTOCHAN** | Must be sent when a user tries to message a channel they can't send to (moderated, banned, not a member). Constant exists, never sent. | | **411/412** | **ERR_NORECIPIENT / ERR_NOTEXTTOSEND** | Input validation for PRIVMSG/NOTICE. Constants exist, never sent. Clients expect these instead of silent failure. | | **451** | **ERR_NOTREGISTERED** | Sent when a client sends commands before completing registration (NICK/USER). Constant exists, never sent. Important for connection robustness. | #### Tier 2 — Medium Priority (needed for feature completeness) | Code | Name | Why it matters | |------|------|----------------| | **341** | **RPL_INVITING** | Confirmation when you INVITE someone. Requires implementing the INVITE command. | | **367/368** | **RPL_BANLIST / RPL_ENDOFBANLIST** | Sent in response to `MODE #channel +b` (list bans). Constant exists, never sent. Needed once ban management is functional. | | **482** | **ERR_CHANOPRIVSNEEDED** | Sent when a non-op tries op-only actions (KICK, MODE changes, TOPIC on +t). Constant exists, never sent. Critical for channel permission enforcement. | | **441** | **ERR_USERNOTINCHANNEL** | Sent when KICK target isn't in the channel. Constant exists, never sent. Needed when KICK is implemented. | | **462** | **ERR_ALREADYREGISTERED** | Prevents double registration. Constant exists, never sent. Minor but good defensive coding. | #### Tier 3 — New Commands Needed (numerics that require new command support) | Code | Command | Why it matters | |------|---------|----------------| | **302** | **USERHOST** | Used by clients for user/host discovery. Somewhat legacy but still used. | | **303** | **ISON** | Used by clients for online presence checks. Largely superseded by MONITOR/WATCH but still common. | | **341** | **INVITE** | Channel invitations — core IRC feature, not yet implemented. | | **KICK** | (various) | KICK command is not implemented. Needs 441, 482 error support. | | **AWAY** | **301/305/306** | AWAY command is not implemented. Needs the three numerics above. | #### Completely Missing Numerics (not even defined as constants yet) These are standard RFC 2812 numerics that have no constants and no implementation: | Code | Name | Why it matters | |------|------|----------------| | **004** | — | RPL_MYINFO is sent but may need format fixes (clients parse this strictly) | | **252** | — | RPL_LUSEROP is sent but 253 RPL_LUSERUNKNOWN is not | | **321** | **RPL_LISTSTART** | Sent before LIST results. Some older clients expect it. Low priority. | | **330** | **RPL_WHOISACCOUNT** | Services account name in WHOIS. IRCv3 `account-tag` related. Modern clients show this. | | **338** | **RPL_WHOISACTUALLY** | Real host/IP in WHOIS (for opers). Low priority. | | **353** | — | RPL_NAMREPLY is sent but multi-prefix (`@+`) support may be incomplete for IRCv3. | | **422** | **ERR_NOMOTD** | Sent when no MOTD file exists. Currently the server always sends an MOTD; if it were empty, clients expect 422 instead of empty 372. | | **443** | **ERR_USERONCHANNEL** | Target already in channel (for INVITE). Needed with INVITE. | | **464** | **ERR_PASSWDMISMATCH** | Wrong server password. Needed if PASS is enforced. | | **671** | **RPL_WHOISSECURE** | Indicates TLS connection in WHOIS. Very commonly shown by modern clients. | --- ### Recommended Implementation Order 1. **AWAY system** (AWAY command + 301/305/306) — high-impact, frequently used 2. **Wire up dead-code error numerics** (404, 411, 412, 451, 482) — already defined, just need to be sent at appropriate points 3. **RPL_TOPICWHOTIME (333)** — already defined, just needs to be sent after 332 4. **RPL_WHOISIDLE (317)** — needs idle time tracking, but WHOIS feels incomplete without it 5. **INVITE command** (341, 473 enforcement, 443) — core IRC feature 6. **KICK command** (441, 482 enforcement) — core IRC feature 7. **RPL_WHOISSECURE (671)** — easy to add, modern clients expect it 8. **ERR_NOMOTD (422)** — defensive, easy <!-- audit by clawbot for issue #52, 2026-03-10 -->
Author
Owner

ok, constants defined but never sent aren't dead code - the module exists as a complete spec reference for anything implementing irc, not just our server. make a PR to add everything in "Completely Missing Numerics" to that module as it should be absolutely spec-complete based on the RFC, and move it from internal/ to pkg/ to indicate its external usefulness/usability.

then make me an issue for adding "Tier 1 — High Priority", and spawn a worker to begin making a PR for it.

ok, constants defined but never sent aren't dead code - the module exists as a complete spec reference for anything implementing irc, not just our server. make a PR to add everything in "Completely Missing Numerics" to that module as it should be absolutely spec-complete based on the RFC, and move it from internal/ to pkg/ to indicate its external usefulness/usability. then make me an issue for adding "Tier 1 — High Priority", and spawn a worker to begin making a PR for it.
Collaborator

Acting on your instructions:

  1. Worker dispatched to add all missing RFC numerics to the module and move it from internal/irc/ to pkg/irc/ (PR incoming)
  2. Created issue #70 for Tier 1 implementation (AWAY system, WHOISIDLE, TOPICWHOTIME, error numerics)
  3. Worker dispatched for #70 — Tier 1 IRC numerics implementation
Acting on your instructions: 1. **Worker dispatched** to add all missing RFC numerics to the module and move it from `internal/irc/` to `pkg/irc/` (PR incoming) 2. **Created [issue #70](https://git.eeqj.de/sneak/chat/issues/70)** for Tier 1 implementation (AWAY system, WHOISIDLE, TOPICWHOTIME, error numerics) 3. **Worker dispatched** for [#70](https://git.eeqj.de/sneak/chat/issues/70) — Tier 1 IRC numerics implementation
Collaborator

Status update: All requested work from this issue has been completed.

  1. PR #71 — merged (complete IRC numerics module, moved to pkg/irc/, IRCMessageType custom type with full API, tests)
  2. Issue #70 — created for Tier 1 implementation
  3. PR #72merge-ready (AWAY system, WHOISIDLE, TOPICWHOTIME, error numerics)

This issue can be closed once PR #72 is merged and you're satisfied with coverage. Let me know if you want more batches identified.

Status update: All requested work from this issue has been completed. 1. ✅ [PR #71](https://git.eeqj.de/sneak/chat/pulls/71) — merged (complete IRC numerics module, moved to `pkg/irc/`, `IRCMessageType` custom type with full API, tests) 2. ✅ [Issue #70](https://git.eeqj.de/sneak/chat/issues/70) — created for Tier 1 implementation 3. ✅ [PR #72](https://git.eeqj.de/sneak/chat/pulls/72) — `merge-ready` (AWAY system, WHOISIDLE, TOPICWHOTIME, error numerics) This issue can be closed once PR #72 is merged and you're satisfied with coverage. Let me know if you want more batches identified.
Collaborator

Closing — all requested work from this audit is complete:

  1. PR #71 — merged (complete IRC numerics module, moved to pkg/irc/)
  2. PR #72 — merged (Tier 1 numerics: AWAY system, WHOISIDLE, TOPICWHOTIME, error numerics)
  3. Issue #70 — closed (Tier 1 implementation tracked and completed)

Future batches can be tracked in new issues if needed.

Closing — all requested work from this audit is complete: 1. ✅ [PR #71](https://git.eeqj.de/sneak/chat/pulls/71) — merged (complete IRC numerics module, moved to `pkg/irc/`) 2. ✅ [PR #72](https://git.eeqj.de/sneak/chat/pulls/72) — merged (Tier 1 numerics: AWAY system, WHOISIDLE, TOPICWHOTIME, error numerics) 3. ✅ [Issue #70](https://git.eeqj.de/sneak/chat/issues/70) — closed (Tier 1 implementation tracked and completed) Future batches can be tracked in new issues if needed.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/chat#52