IRCv3 Support

Comprehensive implementation status of IRC protocol features in repartee, covering RFC 2812 core protocol and IRCv3 capability extensions.

Capability Negotiation

repartee implements the full IRCv3 capability negotiation framework including CAP LS 302 with multiline parsing, CAP REQ/ACK/NAK, and CAP NEW/DEL for runtime capability changes.

FeatureStatusNotes
CAP LS 302DoneMultiline parsing, field3/field4 handling
CAP REQ/ACK/NAKDoneRequest + detect acceptance
CAP ENDDoneProperly closes negotiation
CAP NEW/DELDoneRuntime capability changes via cap-notify

Tier 1 -- Must Have

CapabilityStatusSpecNotes
multi-prefixDone3.1All mode prefixes per user in NAMES
extended-joinDone3.1JOIN includes account + realname
ircnet.com/extended-joinDone--IRCnet ircd 2.12 vendor extension: JOIN also carries <uid> <ip> <netjoin>. Takes precedence when both variants are acked
server-timeDone3.2@time tag used as message timestamp
account-tagDone3.2User account in message tags
cap-notifyDone3.2Server-side capability change notifications
away-notifyDone3.1Real-time away status changes
account-notifyDone3.1Account login/logout notifications
chghostDone3.2Real-time ident/hostname changes
SASL EXTERNALDone3.1CertFP-based authentication via client TLS certificate (client_cert_path PEM chain + key)
SASL ECDSA-NIST256P-CHALLENGEDone--NIST P-256 public-key challenge-response
SASL SCRAM-SHA-512 / 256 / 1Done3.1RFC 5802/7677 salted challenge-response with server signature verification
SASL OAUTHBEARERDone--RFC 7628 OAuth 2.0 bearer token authentication (explicit opt-in via sasl_mechanism = "OAUTHBEARER")
SASL mechanism selectionDone--Auto-detect strongest: EXTERNAL > ECDSA-NIST256P-CHALLENGE > SCRAM-SHA-512 > SCRAM-SHA-256 > SCRAM-SHA-1 > PLAIN

Tier 2 -- High Value

CapabilityStatusSpecNotes
echo-messageDone3.2Server echoes own messages back; local echo suppressed
labeled-responseDone3.2Request/response correlation (@label) for commands and batches (ACK, BATCH)
invite-notifyDone3.2Channel members see invites
batchDone3.2NETSPLIT/NETJOIN summary messages; carries multiline, chathistory, search, and labeled-response batches
userhost-in-namesDone3.2nick!user@host parsing in NAMES
no-implicit-namesDone--Suppresses automatic NAMES on JOIN (no-implicit-names, draft/no-implicit-names, soju.im/no-implicit-names)
message-tagsDone3.2Tags extracted, stored in buffer and DB; also carries client tags on TAGMSG
draft/chathistoryDone--Server/bouncer history: TARGETS, scroll-back paging, reconnect gap-fill, BETWEEN, AROUND (see below)
draft/event-playbackDone--Requests JOIN/PART/mode replay inside CHATHISTORY batches
draft/multilineDone--Long/paste messages framed as one BATCH; inbound reassembly (see below)
draft/read-markerDone--Cross-client read state synchronization via MARKREAD (draft/read-marker and soju.im/read)
draft/message-redactionDone--Message deletion (REDACT) via /redact <target> <msgid> [reason]
draft/account-registrationDone--In-band REGISTER and VERIFY flows via /account
draft/metadata-2Done--Conversation metadata (pin, mute, block) and subscriptions via /bmeta
draft/extended-isupportDone--Extended RPL_ISUPPORT parameter negotiation (ISUPPORT)
draft/channel-contextDone--Channel context client tag (+draft/channel-context / channel-context)
+typing client tagDone--Ratified typing indicator on TAGMSG. Send + receive, status-line item in TUI and web UI (see below)

Tier 3 & Bouncer Extensions

CapabilityStatusNotes
msgidDoneRead from message-tags; drives CHATHISTORY deduplication, redaction, and reconnect anchors
monitor / extended-monitorDoneOnline/offline nick watching via /monitor (add, remove, clear, list, status, show) plus away/account/host/realname notifications (extended-monitor / draft/extended-monitor)
setnameDoneReal-time realname changes (SETNAME via /setname <real name>)
draft/webpush / soju.im/webpushDoneBrowser WebPush VAPID key retrieval and subscription lifecycle over IRC
soju.im/bouncer-networksDoneBouncer network discovery (BOUNCER LISTNETWORKS), live updates (soju.im/bouncer-networks-notify), network management (/bouncer), and BOUNCER BIND
soju.im/searchDoneServer-side full-text message search (SEARCH via /bsearch)
soju.im/client-certDonePinning and generating TLS client certificates on Soju accounts (CERTFP via /bcert)
replyNot StartedMessage threading via +draft/reply

Server-side history (draft/chathistory)

When the server or bouncer (soju, lurker, ergo, …) advertises draft/chathistory, repartee requests history over the wire — so you no longer have to drop into the read-only log browser to read older messages.

  • Conversation discovery (CHATHISTORY TARGETS) -- on bouncer-backed connections, repartee discovers active channels and direct-message queries automatically on connect and loads their recent backlog (display.backlog_lines). Opening an empty query buffer on a bouncer also fetches its recent history on demand.
  • Scroll-back paging (CHATHISTORY BEFORE) -- scrolling a channel or query toward the top pages older messages and prepends them to the live view (irssi/WeeChat/The Lounge style). In the web UI the scroll position is anchored so loading older pages never makes the view jump, and the viewport auto-fills on a fresh connect so scroll-back is reachable even before the window overflows.
  • Reconnect gap-fill (CHATHISTORY AFTER / LATEST) -- after a reconnect, fills the gap since the last message you saw, so nothing is missed across a blip. Multi-page gaps keep paginating until caught up.
  • Bounded ranges & context (CHATHISTORY BETWEEN / AROUND) -- /bsearch between queries bounded time ranges on servers with draft/chathistory, and /bsearch context <row> fetches surrounding context for any search hit via CHATHISTORY AROUND.
  • Storage model -- direct IRC connections fold history into the local SQLite backlog, while bouncer-backed connections keep history server-owned in memory without duplicating messages into local SQLite logs.
  • Quiet ingest & deduplication -- history batches are rendered in place without re-triggering notifications or activity counters, and rows are de-duplicated by msgid (with a millisecond-timestamp fallback for msgid-less servers). draft/event-playback is requested alongside so JOIN/PART/mode changes replay inside the batch.

Multiline messages (draft/multiline)

draft/multiline lets a genuinely multi-line message travel as a single logical message instead of N separate lines.

  • Outbound -- a pasted or composed multi-line message is framed as one BATCH of type draft/multiline, honouring the server's advertised max-bytes/max-lines limits, and paste-coalesced so a paste is one message rather than a flood. This is E2E-safe: an encrypted multi-line message stays a single RPE2E unit.
  • Inbound -- incoming multiline batches are reassembled into one message for display and storage; oversized or inconsistent batches are rejected and FAIL BATCH MULTILINE_* errors are surfaced rather than swallowed.
  • TUI compose -- press Alt+Enter to add a line break in the composer and send the whole block as one multiline message.
  • Web -- the web composer sends multi-line input as one \n-preserving message when the cap is active (and still falls back to line-by-line sending when it isn't).

Typing indicators (+typing)

repartee implements the ratified +typing client tag. It rides on TAGMSG and needs only message-tags, so there is no separate capability to negotiate and nothing to configure to get it working.

  • States -- active (you are composing), paused (text is still in the input but you have stopped for a moment), and done (the input is empty again). active and paused render identically; the distinction is not surfaced.
  • Timing -- notifications are throttled to one every 3 s per target. A received active expires after 6 s and a paused after 30 s, so a peer that crashes mid-sentence never leaves a stuck indicator. Sending a real message retracts the indicator implicitly -- no done is sent after it.
  • What counts as typing -- non-empty text that isn't a /command. A /me (or /action ) draft is a message, so it does announce typing.
  • Send/receive are separate -- [typing] show controls whether you see other people; send_channels and send_queries independently control whether you announce your own, in channels and in private queries respectively. All three default to on.
  • Compatibility -- repartee only ever sends the ratified +typing, but still accepts the pre-ratification +draft/typing on receive. The tag is suppressed on servers that block it via ISUPPORT CLIENTTAGDENY, and is never sent on an unregistered connection.
  • Never noisy -- a TAGMSG never opens a buffer, never lands in your log or scrollback, and never bumps an activity or unread counter. Replayed history batches and your own echo-message reflections are ignored, and ignore-list rules apply. Typing state is dropped on PART, QUIT, KICK, nick change, netsplit and disconnect.
  • Flood-safe -- typing frames are charged against the same flood budget as everything else and are skipped when headroom runs low, so an indicator can never get you flooded off.
  • Scripting -- hook api.on("irc.typing", ...) to observe or suppress typing notifications. See the Lua API reference.

The indicator is rendered by the typing status-line item (in the default [statusbar] items list), in both the TUI and the web UI: alice is typing…, alice and bob are typing…, alice, bob and 2 others are typing….

RFC 2812 -- Core Protocol

Connection Registration

FeatureStatusNotes
PASSDoneServer password sent before registration
NICKDoneNickname setting + ERR_NICKNAMEINUSE retry
USERDoneUsername/realname registration
OPERDoneIRC operator login
QUITDoneDisconnect with message
USER MODEDone+i, +w, etc.
SETNAMEDoneLive realname update via setname capability (/setname)

Channel Operations

FeatureStatusNotes
JOINDoneMultiple channels, keys
PARTDoneLeave with reason
CHANNEL MODEDone+beiklmnostRIv and prefix modes
TOPICDoneGet/set, RPL_TOPIC/RPL_TOPICWHOTIME
NAMESDoneRPL_NAMREPLY with prefix parsing, multi-prefix, userhost-in-names
LISTDoneChannel listing
INVITEDoneInvite user + notification
KICKDoneKick with reason
REDACTDoneMessage deletion via draft/message-redaction (/redact)

Messaging & Queries

FeatureStatusNotes
PRIVMSGDoneChannel + private, CTCP ACTION
NOTICEDoneServer + user notices
TAGMSGDoneTag-only message; carries the +typing client tag. Never stored or displayed
WHO / WHOXDoneBasic WHO (352) + WHOX (354) with account tracking; SID/UID-aware on ircu-family and IRCnet (see below)
WHOISDoneFull multi-line WHOIS display
WHOWASDoneOffline user lookup
MONITOR / ISONDoneMONITOR (/monitor) + ISON (irc.ison Lua event) nick availability tracking
AWAYDoneSet/unset + RPL_AWAY display + per-network manual /away on bouncers
WALLOPSDoneWall message display

CTCP

FeatureStatusNotes
ACTIONDoneSend + receive
VERSIONDoneAuto-response
PINGDoneAuto-response
TIMEDoneAuto-response
FINGERDoneAuto-response
SOURCEDoneAuto-response

ISUPPORT (005)

FeatureStatusNotes
Token collectionDoneRaw tokens stored on Connection (plus draft/extended-isupport)
Structured parsingDonePREFIX, CHANMODES, NETWORK, STATUSMSG, WHOX, EXTBAN, CASEMAPPING, MONITOR, SAFERATE, UTF8ONLY, CLIENTTAGDENY, CHATHISTORY, draft/ICON, FILEHOST
Behavior adaptationDoneUpdated on each RPL_ISUPPORT; NETWORK drives label, SAFERATE adapts flood control, draft/ICON exposes network icon (/server icon), FILEHOST powers /upload

Custom Extensions

FeatureStatusNotes
WHOXDoneExtended WHO with field selectors, token matching, account field. Auto-detect via ISUPPORT WHOX token. Auto-WHO on channel join populates NickEntry. Full parity on ircu-family and IRCnet ircd (see below).
ExtbanDone$a:account -- account-based bans/exempts/invites. /ban -a account shorthand. ISUPPORT EXTBAN awareness.

WHOX on ircu-family and IRCnet

/who -- and the nick-list metadata the automatic join-time WHO feeds -- understands the SID/UID-aware replies these ircds send, so away state, account names, ident and real hostnames populate correctly instead of coming back blank.

  • Field selector per lineage -- the portable selector %tcuihnfar is used everywhere; IRCnet ircd 2.12 (detected by the ISUPPORT IDCHAN token) gets %tcuihnfaUr, adding the U (user UID) field. The extra field is never sent to other ircds, which would silently shift the reply layout.
  • Reply layout disambiguated by arity -- a 10-argument 354 is the portable layout, an 11-argument one is IRCnet's (with the UID). An account of "0" means "not logged in".
  • Plain WHO (352) now updates state too -- previously it only printed a line, so on servers without WHOX the join-time WHO was wasted and away/host/ident never landed in the nick list.
  • Trailing-parameter fix -- IRCnet sends :<hop> <sid> <realname> where the RFC says :<hop> <realname>, so a stray 4-character SID used to render glued to the realname. The hopcount is now stripped everywhere and the SID only on IRCnet-lineage servers, both defensively.

Skipped

CapabilityReason
stsStrict Transport Security -- out of scope for now
zcryptNiche, rarely used
Note: All new protocol handling includes tests. Message tags propagate to the scripting API and storage layer. The capability negotiation framework is extensible for future additions.