Rewrite the description of the JSON Schema directory from scratch, without tables, as a reader of the files needs it. Describe the envelope as the server sends it: the reply name in `command` and the number in `code`. Drop the federation section, which describes nothing the server does. List where the schema files disagree with the server, compared file by file with the HTTP API, so a reader is not misled; the files themselves are unchanged. Part of #190. Model: fable-5-1 (writing); opus-5-5 (rework)
7.6 KiB
Message schemas
This directory holds JSON Schema files (draft 2020-12) for the messages that the
neoirc HTTP API carries. message.json describes the envelope every message
uses. commands/ has files for some of the IRC commands. numerics/ has files
for some of the numeric replies. README.md at the repository root documents
the protocol.
The envelope
Every message is one JSON object. These are the fields it can have:
command: the IRC command name, such asPRIVMSG, or the name of a numeric reply, such asRPL_WELCOME. Always present.code: the number of a numeric reply, such as1forRPL_WELCOME. Absent on other messages.id: the message's UUID, assigned by the server.from: the sender's nick, or the server name on a server message.to: the target, such as a channel name starting with#or a nick.params: other parameters, in order, as an array of strings.KICKevents and many numeric replies have it. The server ignoresparamssent by a client.body: an array of strings. It is never a bare string. In aPRIVMSGorNOTICE, each string is one line of text.ts: when the server stored the message, as an RFC 3339 time in UTC, such as2026-10-27T12:00:00.123Z.meta: an object of extra data, such as a hashcash stamp inmeta.hashcash. A hashcash stamp is a short string that takes a computer some work to make. A channel with mode+Hneeds one in everyPRIVMSG. The server relays themetaof aPRIVMSGorNOTICEunchanged. It drops themetaof every other command.
A PRIVMSG as the IRC listener sends it, and as the HTTP API sends it without
id, ts and meta:
IRC: :alice!alice@* PRIVMSG #general :hello world
JSON: {"command": "PRIVMSG", "from": "alice", "to": "#general", "body": ["hello world"]}
A numeric reply has its name in command and its number in code. This 353
reply lists the members of #general, again without id, ts and meta:
{"command": "RPL_NAMREPLY", "code": 353, "from": "neoirc", "to": "alice",
"params": ["=", "#general"], "body": ["@op1!op1@host1 alice!alice@host2"]}
A body with two strings is a two-line message:
{"command": "PRIVMSG", "to": "#general", "body": ["line one", "line two"]}
Files
Commands, in commands/:
PRIVMSG.json: a message to a channel or a user.NOTICE.json: a notice. A client must not answer a notice automatically.JOIN.json: a user joined a channel.PART.json: a user left a channel.QUIT.json: a user left the server.NICK.json: a user changed nick.TOPIC.json: a channel topic was set.MODE.json: a channel mode was changed.KICK.json: a channel operator removed a user from a channel.PING.json: a check that the server still answers.PONG.json: the answer to aPING.PUBKEY.json: an announcement of a user's public signing key. The server has no such command. It answers aPUBKEYwithERR_UNKNOWNCOMMAND(421).
Numeric replies, in numerics/:
001.json:RPL_WELCOME, which welcomes a new user.002.json:RPL_YOURHOST, the server's name and version.003.json:RPL_CREATED, the date the server started.004.json:RPL_MYINFO, the server's version and its lists of modes.322.json:RPL_LIST, one channel in the answer toLIST.323.json:RPL_LISTEND, the end of the answer toLIST.332.json:RPL_TOPIC, a channel's topic.353.json:RPL_NAMREPLY, a channel's members.366.json:RPL_ENDOFNAMES, the end of the member list.372.json:RPL_MOTD, one line of the message of the day.375.json:RPL_MOTDSTART, the start of the message of the day.376.json:RPL_ENDOFMOTD, the end of the message of the day.401.json:ERR_NOSUCHNICK, the nick does not exist.403.json:ERR_NOSUCHCHANNEL, the channel does not exist.433.json:ERR_NICKNAMEINUSE, the nick is taken.442.json:ERR_NOTONCHANNEL, the user is not on that channel.482.json:ERR_CHANOPRIVSNEEDED, the user is not a channel operator.
Where the files differ from the server
Where a schema file and the server disagree, the server is right:
message.jsonand the numeric files put the three-digit code incommandand have nocodefield. The server puts the reply's name incommandand its number incode.message.jsonallows an object asbody. The server reads only arrays of strings. APRIVMSGwith an object getsERR_NOTEXTTOSEND(412).message.jsonsaystois a channel or a nick. AWALLOPSmessage has*there.message.jsonallowsmetaon every message. The server keepsmetaonly on aPRIVMSGorNOTICE.message.jsondescribes signature fields inmeta. The server never checks a signature.message.jsondoes not describemeta.hashcash. The server reads it in aPRIVMSGto a channel with mode+H.JOIN.jsonhas nobody. A client'sJOINcan carry the channel key inbody. When a user joins, the server'sJOINevent repeats the channel name there.JOIN.jsonallows a channel name of any length. The server allows at most 63 characters after the#. It answers a longer name withERR_NOSUCHCHANNEL(403).KICK.jsonputs the kicked nick inparams. The server reads a client'sKICKfrombody: the nick, then an optional reason.MODE.jsonputs the mode change inparams. The server usesbodyinstead. A client sends the change and any value as separate strings, such as"+o"and"bob". The server'sMODEevent has one string such as"+o bob", or the change and its value as two strings, such as"+k"and"secret".NOTICE.jsonallows*asto. The server answers that withERR_NOSUCHNICK(401).NOTICE.jsonhas an example notice from the server to*. The server sends no such notice.PING.jsonandPONG.jsondescribe a token that thePONGrepeats. The server ignores thebodyof aPING. It answers the HTTP request itself with{"command": "PONG", "from": "<server name>"}.PING.jsonandPONG.jsonalso describe messages between servers. The server does not connect to other IRC servers.PUBKEY.jsondescribes a command the server does not have.QUIT.jsonsays only the server sendsQUIT. A client can send it too, to end its session. The client'sQUITcan carry a reason inbody.TOPIC.jsonsays aTOPICwithout abodyqueries the topic. Over the HTTP API aTOPICwithout abodygetsERR_NEEDMOREPARAMS(461).TOPIC.jsonsays an empty array clears the topic. The server answers[]withERR_NEEDMOREPARAMS(461). Abodyof[""]clears the topic.003.jsondescribes the server's creation date. The server sends the date it last started.004.jsonhas example mode lists. The server sends an empty string as the user modes andikmnostlas the channel modes.322.jsonsaysLISTgets one reply per channel. The server leaves out each secret channel that the user is not on.353.jsonsaysbodylists nicks. Over the HTTP API the server listsnick!user@hostin place of each nick, such as@op1!op1@host1.353.jsonsays the first parameter marks a channel as public, private or secret. The server always sends=, the mark for a public channel.376.jsongives the text asEnd of /MOTD command. The server adds a full stop.401.jsongives the text asNo such nick/channel. For aPRIVMSGorNOTICEto an unknown nick, the server sendsNo such nick.433.jsonhas an example with*asto. Over the HTTP API the server sends433only in answer to aNICK, with the user's nick asto.
The server also accepts some messages that the files do not allow, such as a
channel name without its #.