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.
| Feature | Status | Notes |
|---|
CAP LS 302 | Done | Multiline parsing, field3/field4 handling |
CAP REQ/ACK/NAK | Done | Request + detect acceptance |
CAP END | Done | Properly closes negotiation |
CAP NEW/DEL | Done | Runtime capability changes via cap-notify |
Tier 1 -- Must Have
| Capability | Status | Spec | Notes |
|---|
multi-prefix | Done | 3.1 | All mode prefixes per user in NAMES |
extended-join | Done | 3.1 | JOIN includes account + realname |
ircnet.com/extended-join | Done | -- | IRCnet ircd 2.12 vendor extension: JOIN also carries <uid> <ip> <netjoin>. Takes precedence when both variants are acked |
server-time | Done | 3.2 | @time tag used as message timestamp |
account-tag | Done | 3.2 | User account in message tags |
cap-notify | Done | 3.2 | Server-side capability change notifications |
away-notify | Done | 3.1 | Real-time away status changes |
account-notify | Done | 3.1 | Account login/logout notifications |
chghost | Done | 3.2 | Real-time ident/hostname changes |
| SASL EXTERNAL | Done | 3.1 | CertFP-based authentication via client TLS certificate |
| SASL SCRAM-SHA-256 | Done | 3.1 | RFC 5802/7677 challenge-response with server signature verification |
| SASL mechanism selection | Done | -- | Auto-detect best: EXTERNAL > SCRAM-SHA-256 > PLAIN |
Tier 2 -- High Value
| Capability | Status | Spec | Notes |
|---|
echo-message | Done | 3.2 | Server echoes own messages back; local echo suppressed |
invite-notify | Done | 3.2 | Channel members see invites |
batch | Done | 3.2 | NETSPLIT/NETJOIN produce summary messages; carries multiline + chathistory batches |
userhost-in-names | Done | 3.2 | nick!user@host parsing in NAMES |
message-tags | Done | 3.2 | Tags extracted, stored in buffer and DB; also carries client tags on TAGMSG |
draft/chathistory | Done | -- | Server/bouncer history: scroll-back paging + reconnect gap-fill (see below) |
draft/event-playback | Done | -- | Requests JOIN/PART/mode replay inside CHATHISTORY batches |
draft/multiline | Done | -- | Long/paste messages framed as one BATCH; inbound reassembly (see below) |
+typing client tag | Done | -- | Ratified typing indicator on TAGMSG. Send + receive, status-line item in TUI and web UI (see below) |
Tier 3 -- Nice to Have
| Capability | Status | Notes |
|---|
msgid | Done | Read from message-tags; drives CHATHISTORY deduplication and reconnect anchors |
monitor | Not Started | Nick online/offline tracking |
labeled-response | Not Started | Match responses to requests |
reply | Not Started | Message threading via +draft/reply |
setname | Not Started | Real-time realname changes |
Server-side history (draft/chathistory)
When the server or bouncer (soju, ergo, …) advertises draft/chathistory, repartee requests history over the wire and folds it into the same SQLite-backed backlog it keeps locally — so you no longer have to drop into the read-only log browser to read older messages.
- Scroll-back paging -- scrolling a channel or query toward the top pages older messages with
CHATHISTORY BEFORE 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 -- after a reconnect,
CHATHISTORY AFTER/LATEST fills the gap since the last message you saw, so nothing is missed across a blip. Multi-page gaps keep paginating until caught up.
- Quiet ingest -- history batches are stored and rendered in place without re-triggering notifications or activity counters.
- Deduplication -- rows are de-duplicated by
msgid (with a millisecond-timestamp fallback for msgid-less servers), so overlapping pages and live/history races don't double up. draft/event-playback is requested alongside so JOIN/PART/mode changes replay inside the batch, and encrypted logs are decrypted on these reads.
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
| Feature | Status | Notes |
|---|
| PASS | Done | Server password sent before registration |
| NICK | Done | Nickname setting + ERR_NICKNAMEINUSE retry |
| USER | Done | Username/realname registration |
| OPER | Done | IRC operator login |
| QUIT | Done | Disconnect with message |
| USER MODE | Done | +i, +w, etc. |
Channel Operations
| Feature | Status | Notes |
|---|
| JOIN | Done | Multiple channels, keys |
| PART | Done | Leave with reason |
| CHANNEL MODE | Done | +beiklmnostRIv and prefix modes |
| TOPIC | Done | Get/set, RPL_TOPIC/RPL_TOPICWHOTIME |
| NAMES | Done | RPL_NAMREPLY with prefix parsing, multi-prefix, userhost-in-names |
| LIST | Done | Channel listing |
| INVITE | Done | Invite user + notification |
| KICK | Done | Kick with reason |
Messaging & Queries
| Feature | Status | Notes |
|---|
| PRIVMSG | Done | Channel + private, CTCP ACTION |
| NOTICE | Done | Server + user notices |
| TAGMSG | Done | Tag-only message; carries the +typing client tag. Never stored or displayed |
| WHO / WHOX | Done | Basic WHO (352) + WHOX (354) with account tracking; SID/UID-aware on ircu-family and IRCnet (see below) |
| WHOIS | Done | Full multi-line WHOIS display |
| WHOWAS | Done | Offline user lookup |
| AWAY | Done | Set/unset + RPL_AWAY display |
| WALLOPS | Done | Wall message display |
CTCP
| Feature | Status | Notes |
|---|
| ACTION | Done | Send + receive |
| VERSION | Done | Auto-response |
| PING | Done | Auto-response |
| TIME | Done | Auto-response |
| FINGER | Done | Auto-response |
| SOURCE | Done | Auto-response |
ISUPPORT (005)
| Feature | Status | Notes |
|---|
| Token collection | Done | Raw tokens stored on Connection |
| Structured parsing | Done | PREFIX, CHANMODES, NETWORK, STATUSMSG, WHOX, EXTBAN, CASEMAPPING |
| Behavior adaptation | Done | Updated on each RPL_ISUPPORT, NETWORK drives label |
Custom Extensions
| Feature | Status | Notes |
|---|
| WHOX | Done | Extended 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). |
| Extban | Done | $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
| Capability | Reason |
|---|
metadata / metadata-notify | Rarely deployed |
sts | Strict Transport Security -- out of scope for now |
zcrypt | Niche, 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.