← All docs

Freeq Feature List

This document catalogs every feature implemented in Freeq, organized by category. Features unique to Freeq (not present in classic IRC) are marked with 🆕. Features that extend or modify standard IRC behavior are marked with 🔧. Standard IRC features are unmarked.


1. IRC Protocol — Core

Connection & Registration

Feature Status Notes
NICK / USER registration ✅ Standard IRC registration flow
NICK change after registration ✅ Broadcasts :old NICK :new to user + shared channels + S2S
PING / PONG keepalive ✅ Both client→server and server→client
QUIT with reason broadcast ✅ Broadcasts to all shared channels
Connection timeout detection ✅ 90s ping interval, 180s timeout
Rate limiting (token bucket) ✅ 10 cmd/sec; exempt during registration
ERR_UNKNOWNCOMMAND (421) ✅ For unrecognized commands

Channels

Feature Status Notes
JOIN (single and multi-channel) ✅ JOIN #a,#b with per-channel keys
PART (single and multi-channel) ✅
PRIVMSG to channels ✅
PRIVMSG to users (PM) ✅
NOTICE to channels and users ✅
CTCP ACTION (/me) ✅ Via \x01ACTION ...\x01
TOPIC query and set ✅ RPL_TOPIC (332), RPL_TOPICWHOTIME (333), RPL_NOTOPIC (331)
NAMES (353/366) ✅ With @ and + prefixes for ops/voiced
LIST (322/323) ✅ Channel list with member counts and topics
WHO (352/315) ✅ Per-channel and global, shows DID/handle for authenticated users
AWAY (301/305/306) ✅ Sets/clears away, RPL_AWAY on PM
MOTD (375/372/376) ✅ On registration + standalone command
KICK ✅ With reason, proper numeric errors
INVITE ✅ RPL_INVITING (341), notifies target

Channel Modes

Mode Status Notes
+o / -o (channel operator) ✅
+v / -v (voice) ✅
+b / -b (ban) ✅ Hostmask + DID wildcard matching
+i / -i (invite-only) ✅
+t / -t (topic lock) ✅ Only ops can set topic when enabled
+k / -k (channel key) ✅ Password required to join
+n / -n (no external messages) ✅ Non-members can't send to channel
+m / -m (moderated) ✅ Only ops/voiced can speak
MODE query (324) ✅ Lists current channel modes
Ban list query (+b no arg) ✅ RPL_BANLIST (367), RPL_ENDOFBANLIST (368)

User Modes

Feature Status Notes
User mode query (221) ✅ Returns + (no user modes implemented)

WHOIS

Feature Status Notes
RPL_WHOISUSER (311) ✅
RPL_WHOISSERVER (312) ✅
RPL_ENDOFWHOIS (318) ✅
RPL_WHOISACCOUNT (330) 🆕 Shows authenticated DID
Custom 671: AT Protocol handle 🆕 Shows resolved Bluesky handle
Custom 672: iroh endpoint 🆕 Shows P2P iroh endpoint ID
RPL_WHOISCHANNELS (319) ✅ For remote S2S users

Informational Commands

Feature Status Notes
VERSION (351) ✅ Server version and feature summary
TIME (391) ✅ Server UTC time
LUSERS (251-255) ✅ User/channel/server counts, local + remote
ADMIN (256-259) ✅ Server admin info
INFO (371/374) ✅ Server description and links
USERHOST (302) ✅ Up to 5 nicks, with op status
ISON (303) ✅ Online presence check

Missing Standard IRC Commands

Feature Status Notes
OPER (server operator) ✅ OPER <name> <password> + auto-OPER via --oper-dids
WALLOPS ❌ Not implemented
LINKS ❌ Not implemented
STATS ❌ Not implemented
Channel modes: +s / +p (secret/private) ❌ Not implemented
Channel modes: +l (user limit) ❌ Not implemented
Hostname cloaking ✅ 🆕 freeq/plc/xxxxxxxx for DID users, freeq/guest for guests
Reverse DNS lookup ❌
K-line / G-line (server bans) ❌

2. IRCv3 Capabilities

Feature Status Notes
CAP LS / REQ / ACK / NAK / END ✅ IRCv3 capability negotiation
sasl capability ✅ With ATPROTO-CHALLENGE mechanism
message-tags capability ✅ Tag-aware routing per client
server-time capability ✅ Timestamps on history replay
batch capability ✅ History wrapped in chathistory batch
multi-prefix capability ✅ Shows all prefix chars in NAMES
echo-message capability ✅ Echoes own messages to negotiated clients
TAGMSG (tags-only messages) ✅ With fallback for plain clients
iroh=<id> CAP advertisement 🆕 Transport discovery via CAP LS
SASL AUTHENTICATE * abort ✅ Cleanly aborts SASL negotiation

| account-notify capability | ✅ | Broadcasts ACCOUNT on auth to shared channels |
| extended-join capability | ✅ | JOIN includes account + realname |
| draft/chathistory capability | ✅ | On-demand CHATHISTORY LATEST/BEFORE/AFTER |

Missing IRCv3 Extensions

Feature Status Notes
away-notify ✅ Broadcasts AWAY changes to shared channel members
msgid (message IDs) ✅ 🆕 ULID on every PRIVMSG/NOTICE, stored in DB, included in history replay
account-tag ✅ Outbound PRIVMSG/NOTICE include account=<did> for authenticated senders, gated on cap
labeled-response ❌
invite-notify ❌
chghost ❌
cap-notify ❌
setname ❌
standard-replies ❌

3. Authentication — SASL ATPROTO-CHALLENGE 🆕

Feature Status Notes
Challenge-response SASL flow ✅ Custom ATPROTO-CHALLENGE mechanism
Cryptographically random nonce (32 bytes) ✅ Per challenge
Challenge single-use enforcement ✅ Consumed on take, replay blocked
Configurable challenge timeout ✅ Default 60s, --challenge-timeout-secs
JSON-encoded challenges ✅ Deviation from binary: for debuggability
RPL_LOGGEDIN (900) ✅
RPL_SASLSUCCESS (903) ✅
ERR_SASLFAIL (904) ✅
Guest fallback (no SASL) ✅ Standard IRC clients work unmodified

Verification Methods

Method Status Notes
crypto (DID document key signature) ✅ Signs raw challenge bytes
pds-session (app password Bearer JWT) ✅ Verifies via PDS getSession
pds-oauth (DPoP-bound access token) ✅ DPoP proof forwarded to PDS

Key Types

Key Type Status Notes
secp256k1 ✅ MUST per spec — compressed SEC1 encoding
ed25519 ✅ SHOULD per spec
Multibase/multicodec parsing ✅ z prefix (base58btc), proper varint codecs

DID Resolution

Feature Status Notes
did:plc resolution (plc.directory) ✅
did:web resolution ✅ Including path-based DIDs
Handle resolution (.well-known/atproto-did) ✅
PDS endpoint extraction from DID doc ✅ AtprotoPersonalDataServer service type
PDS URL verification (claimed vs doc) ✅ Prevents spoofing
Authentication key extraction ✅ From authentication + assertionMethod
Static resolver (testing) ✅ In-memory DID document map

4. DID-Aware IRC Features 🆕

Feature Status Notes
DID-based bans (MODE +b did:plc:xyz) ✅ Identity-based, survives nick changes
DID-based invites ✅ Stored by DID, survive reconnect
Nick ownership (DID binding) ✅ Persisted across restarts
Nick enforcement at registration ✅ Non-owners renamed to GuestXXXX
Persistent DID-based channel ops ✅ Auto-op on rejoin by DID, persisted in DB
Channel founder (first authenticated user) ✅ Can't be de-opped, persisted in DB
DID in WHOIS output ✅ Numeric 330
AT handle in WHOIS output ✅ Resolved asynchronously from DID doc
Auto-op on empty channel rejoin ✅ First user joining empty+zero-ops channel gets ops

5. Transport Stack

TCP / TLS (Standard)

Feature Status Notes
Plain TCP (port 6667) ✅
TLS (port 6697) ✅ rustls with configurable cert/key
Auto-detect TLS by port (client) ✅ Port 6697 → TLS
Self-signed cert support (client) ✅ --tls-insecure flag

WebSocket 🆕

Feature Status Notes
WebSocket IRC transport (/irc) ✅ IRC-over-WS, not a new protocol
Text frame ↔ IRC line bridging ✅ One line per frame, \r\n handling
--web-addr opt-in ✅ Zero-cost when disabled
HTML test client ✅ test-client.html

Iroh QUIC Transport 🆕

Feature Status Notes
Iroh endpoint for IRC connections ✅ ALPN: freeq/iroh/1
Persistent secret key (iroh-key.secret) ✅ Stable endpoint ID across restarts
Iroh endpoint stored in SharedState ✅ Proper lifetime (no mem::forget)
NAT hole-punching + relay fallback ✅ Via iroh's infrastructure
Transport-agnostic handler ✅ All transports → handle_generic()
Iroh ID in CAP LS for auto-discovery ✅ iroh=<endpoint-id>
Client auto-upgrade to iroh ✅ Probes CAP LS, reconnects via iroh
Configurable iroh UDP port ✅ --iroh-port
Connection held alive for session ✅ Explicit close with CONNECTION_CLOSE frame
Bridge task abort on disconnect ✅ Clean cleanup

6. End-to-End Encryption (E2EE) 🆕

Feature Status Notes
AES-256-GCM channel encryption ✅ Per-channel passphrase
HKDF-SHA256 key derivation ✅ Channel-name-salted
Wire format: ENC1:<nonce>:<ciphertext> ✅ Version-tagged, base64 encoded
Server-transparent relay ✅ Server sees ciphertext only
/encrypt and /decrypt commands ✅ TUI commands
Unicode passphrase support ✅
Tamper detection (GCM auth tag) ✅

DID-Based E2EE (ENC2) 🆕

Feature Status Notes
Identity-bound group encryption ✅ Key derived from sorted member DIDs
Wire format: ENC2:<epoch>:<nonce>:<ct> ✅ Epoch tracks membership changes
Group key rotation on member change ✅ New epoch = new key
ECDH DM encryption (secp256k1) ✅ Pairwise key from DID document keys
Wire format: ENC2:dm:<nonce>:<ct> ✅ DM variant
DID-sorted deterministic derivation ✅ Same members = same key regardless of order

7. Peer-to-Peer Encrypted DMs 🆕

Feature Status Notes
Client-side iroh endpoint for DMs ✅ ALPN: freeq/p2p-dm/1
Direct encrypted QUIC connections ✅ Server-free
/p2p start/id/connect/msg commands ✅ TUI commands
Newline-delimited JSON wire format ✅ Not IRC protocol
Dedicated p2p:<id> TUI buffers ✅
Iroh endpoint ID in WHOIS (672) ✅ For peer discovery

8. Server-to-Server Federation (S2S) 🆕

Feature Status Notes
Iroh QUIC-based S2S links ✅ ALPN: freeq/s2s/1
--s2s-peers CLI option ✅ Connect to peers on startup
Incoming S2S acceptance (when iroh enabled) ✅
ALPN-based routing (client vs S2S) ✅
Origin tracking (loop prevention) ✅ origin field in S2S messages
Newline-delimited JSON S2S protocol ✅
Auto-reconnection with exponential backoff ✅ 1s→60s cap, connect_peer_with_retry()
Diagnostic logging (byte/message counts) ✅ Which side ended link, close reasons

What Syncs

Feature Status Notes
PRIVMSG relay ✅ Channel messages, enforces +n/+m
JOIN / PART / QUIT propagation ✅ Membership tracking per origin server
NICK change propagation ✅ Updates remote_members map in all channels
TOPIC sync ✅ Enforces +t on incoming S2S topics
MODE sync (real-time) ✅ +t/+i/+n/+m/+k broadcast via S2S Mode message
MODE sync (SyncResponse) ✅ Full state replacement (not additive)
Remote member tracking ✅ remote_members with DID, handle, is_op
SyncRequest / SyncResponse ✅ Initial state exchange with rich nick_info
NAMES includes remote members ✅ With op status from home server + DID-based
WHOIS for remote users ✅ Shows DID, handle, origin
DID-based ops sync ✅ Union merge
Founder sync (first-write-wins) ✅ No timestamp dependency
ChannelCreated propagation ✅ Founder + DID ops + created_at
Ban sync (S2S) ✅ 🆕 S2sMessage::Ban variant, authorized set/remove, SyncResponse carries bans
Invite sync (S2S) ✅ 🆕 S2sMessage::Invite variant, relays invite tokens to peers
S2S Join enforcement ✅ 🆕 Incoming S2S Joins check bans (nick + DID) and +i (invite only)
Policy sync (S2S) ✅ 🆕 S2sMessage::PolicySync for channel policy documents

CRDT State Layer (Automerge)

Feature Status Notes
Flat-key Automerge document ✅ Avoids nested-map conflicts
Channel membership CRDT ✅ member:{channel}:{nick}
Topic CRDT (LWW) ✅
Ban CRDT (add/remove) ✅
Nick ownership CRDT ✅
Founder CRDT (first-write-wins) ✅ Conditional put, deterministic convergence
DID ops CRDT (grant/revoke) ✅
Sync message generation/receipt ✅ Automerge sync protocol
Save/load from bytes ✅
🆕 Live CRDT sync via S2S ✅ CrdtSync message type; mutations written to CRDT alongside in-memory state; Automerge sync messages exchanged on link establishment and after each remote sync

S2S Limitations (see also docs/s2s-audit.md)

Limitation Notes
ChannelCreated race in narrow window Both servers may create simultaneously
Rogue server can add did_ops Authorization-on-write not implemented

9. Persistence (SQLite)

Feature Status Notes
--db-path opt-in ✅ In-memory by default
WAL mode ✅ Good concurrent read performance
Message history storage ✅ All channel messages
Channel state persistence ✅ Topics, modes (+t/+i/+k/+n/+m), keys
Ban persistence ✅ Hostmask and DID bans
DID-nick identity bindings ✅ Survive restarts
DID-based ops persistence ✅ did_ops_json column
Founder persistence ✅ founder_did column
History replay on JOIN ✅ Last 100 messages with server-time + batch
Message pruning ✅ --max-messages-per-channel config
Idempotent DB migration ✅ ALTER TABLE ADD COLUMN on startup
Graceful persistence failures ✅ Logged, don't crash server
Load persisted state on startup ✅ Channels, bans, messages, identities

Persistence Gaps

Gap Notes
No --message-retention-days Only count-based pruning
No full-text search SQLite FTS5 not wired up

10. REST API 🆕

Endpoint Status Notes
GET /api/v1/health ✅ Server stats
GET /api/v1/channels ✅ List all channels
GET /api/v1/channels/{name}/history ✅ Paginated, ?limit=N&before=T
GET /api/v1/channels/{name}/topic ✅
GET /api/v1/channels/{name}/pins ✅ 🆕 Pinned messages for a channel
GET /api/v1/channels/{name}/events ✅ 🆕 SSE event stream
GET /api/v1/channels/{name}/audit ✅ 🆕 Channel audit log
GET /api/v1/channels/{name}/agent-capabilities ✅ 🆕 Agent capabilities
GET /api/v1/channels/{name}/approvals ✅ 🆕 Pending approvals
GET /api/v1/channels/{name}/budget ✅ 🆕 Channel budget info
GET /api/v1/channels/{name}/spend ✅ 🆕 Channel spend info
GET /api/v1/users/{nick} ✅ Online status, DID, handle
GET /api/v1/users/{nick}/whois ✅ + channels
GET /api/v1/signing-key ✅ 🆕 Server ed25519 public key
GET /api/v1/signing-keys/{did} ✅ 🆕 Per-DID client signing key
GET /api/v1/verify/{msgid} ✅ 🆕 Verify message signature
GET /api/v1/actors/{did} ✅ 🆕 Actor identity info
GET /api/v1/keys/{did} ✅ 🆕 E2EE public keys for a DID
POST /api/v1/keys ✅ 🆕 Upload E2EE public keys
POST /api/v1/upload ✅ 🆕 Upload media to PDS (auth required)
GET /api/v1/blob ✅ 🆕 PDS blob proxy with Range support
GET /api/v1/og ✅ 🆕 OpenGraph link preview
GET /api/v1/actions/{id} ✅ 🆕 One task and every event of it
GET /api/v1/agents/manifests ✅ 🆕 List agent manifests
GET /api/v1/agents/manifests/{did} ✅ 🆕 Get agent manifest
GET /api/v1/agents/spawned ✅ 🆕 List spawned agents
CORS support ✅ Configurable allowed origins
Security headers ✅ CSP, HSTS, X-Frame-Options, etc.

11. Rich Media (IRCv3 Tags) 🆕

Feature Status Notes
Media attachment tags ✅ content-type, media-url, media-alt, etc.
Multipart/alternative semantics ✅ Tags for rich clients, body for plain clients
Link preview tags ✅ text/x-link-preview content type
Reaction tags (+react) ✅ With TAGMSG, fallback ACTION for plain clients
Media upload to AT Protocol PDS ✅ Blob upload + record pinning
blue.irc.media custom lexicon ✅ Prevents blob GC, doesn't pollute feed
Optional cross-post to Bluesky feed ✅
OpenGraph link preview fetching ✅ HTML parsing, 64KB limit
CDN URL generation (bsky.app) ✅
DPoP nonce retry for PDS uploads ✅ Up to 3 attempts
Tag escaping/unescaping (IRCv3 spec) ✅ \:, \s, \\, \r, \n

11.5. Message Signing 🆕

Feature Status Notes
Client-side ed25519 session keys ✅ Per-session keypair, registered via MSGSIG command
Client message signing (+freeq.at/sig) ✅ Non-repudiation — client signs every PRIVMSG
Server signature verification ✅ Verifies client sigs, relays unchanged
Server fallback signing ✅ Server signs if client doesn't support signing
Public key endpoint (server) ✅ GET /api/v1/signing-key
Public key endpoint (per-DID) ✅ GET /api/v1/signing-keys/{did}
Signature verification endpoint ✅ GET /api/v1/verify/{msgid}
S2S signature preservation ✅ msgid + sig carried across federation

11.6. Message Editing & Deletion 🆕

Feature Status Notes
Message editing (+draft/edit=<msgid>) ✅ Server verifies authorship, stores with replaces_msgid
Message deletion (+draft/delete=<msgid>) ✅ Soft delete via TAGMSG (deleted_at timestamp)
Author or ops can delete ✅ Permission-checked
Edits update in-memory history ✅ Broadcasts to channel
Deleted messages excluded from history ✅ Excluded from CHATHISTORY and JOIN replay

11.7. Pinned Messages 🆕

Feature Status Notes
PIN <channel> <msgid> command ✅ Ops can pin messages
UNPIN <channel> <msgid> command ✅ Ops can unpin messages
PINS <channel> command ✅ List pinned messages
REST API (GET /api/v1/channels/{name}/pins) ✅ Web client support
Duplicate pin prevention ✅

12. OAuth 2.0 (AT Protocol) 🆕

Feature Status Notes
Browser-based OAuth login ✅ Opens system browser
Authorization server discovery ✅ Protected resource metadata → AS metadata
Pushed Authorization Request (PAR) ✅ Required by Bluesky
PKCE (S256) ✅
DPoP key generation (P-256 / ES256) ✅
DPoP proof creation (RFC 9449) ✅ With ath claim
DPoP nonce discovery and retry ✅
Token exchange ✅
Token refresh ✅ PdsSessionSigner with RwLock interior mutability
Session caching to disk ✅ ~/.config/freeq-tui/<handle>.session.json
Cached session validation ✅ Probes PDS on reuse
Restrictive file permissions (0600) ✅
Handle → DID → PDS resolution ✅

13. TUI Client

Buffers & Navigation

Feature Status Notes
Multi-buffer UI (status + channels + PMs) ✅
Buffer switching (Ctrl-N/P, Alt-N/P, Shift-Tab) ✅
Auto-buffer creation on JOIN/PM ✅
P2P DM dedicated buffers ✅ p2p:<short-id>
Unread indicator (●) ✅
PageUp/PageDown scroll ✅
Channel member list in buffer ✅

Input Editing

Feature Status Notes
Emacs keybindings (default) ✅ Full readline-style
Vi mode (--vi) ✅ Normal + Insert modes
Kill ring (Ctrl-K/U/W/Y) ✅
Word motion (Alt-F/B/D) ✅
Case transforms (Alt-U/L/C) ✅
Transpose (Ctrl-T) ✅
Tab nick completion ✅
Input history (Up/Down) ✅

Display

Feature Status Notes
Status bar (transport, nick, auth, uptime) ✅
Transport badge (color-coded) ✅ Red=TCP, Green=TLS, Cyan=WS, Magenta=Iroh
Network info popup (/net) ✅
Debug mode (/debug) ✅ Raw IRC lines
Rich media display (🖼 badge) ✅ Image/video/audio formatting
E2EE status display ✅ 🔒 prefix on encrypted channels

Commands (45+ total)

/join, /part, /msg, /me, /topic, /mode, /op, /deop, /voice, /kick, /ban, /unban, /invite, /whois, /names, /who, /list, /away, /motd, /nick, /raw, /encrypt, /decrypt, /p2p start, /p2p id, /p2p connect, /p2p msg, /net, /debug, /quit, /help, /commands, plus MODE variants (+o/-o, +v/-v, +b/-b, +i/-i, +t/-t, +k/-k, +n/-n, +m/-m).


14. SDK

Feature Status Notes
(ClientHandle, Receiver<Event>) pattern ✅ Any UI/bot can consume
Pluggable ChallengeSigner trait ✅ KeySigner, PdsSessionSigner, StubSigner
PdsSessionSigner with token refresh ✅ RwLock interior mutability, new_with_refresh()
establish_connection() pre-TUI ✅ Connection errors before UI starts
Iroh auto-discovery (discover_iroh_id) ✅ Probe CAP LS for iroh upgrade
Tagged message sending ✅ send_tagged, send_media, send_reaction
P2P DM subsystem ✅ Full lifecycle management
E2EE encrypt/decrypt ✅ Library functions
DID resolution ✅ HTTP and static resolvers
Crypto key generation and signing ✅ secp256k1 + ed25519
PDS client (create session, verify) ✅
Bluesky profile fetching ✅ Public API, no auth needed
Media upload to PDS ✅ With DPoP retry
Link preview fetching ✅ OpenGraph parsing
🆕 Bot framework ✅ Command routing, permission levels (Anyone/Auth/Admin), auto-help
🆕 DID-based E2EE (ENC2) ✅ Group key + ECDH DM encryption
Echo bot example ✅ examples/echo_bot.rs
Framework bot example ✅ examples/framework_bot.rs — commands with permissions
IRC message parser with tag support ✅

15. Testing

Category Count Notes
SDK unit tests 35 IRC parsing, crypto, DID, media, auth
Server unit tests 33 Parsing, SASL, channel state, DB, CRDT
Integration tests 27 End-to-end auth flows, channel ops, persistence
S2S acceptance tests 39 16 single-server + 14 S2S + 9 netsplit/reconnect
Total 134

16. Configuration

Option Default Notes
--listen-addr 127.0.0.1:6667 Plain TCP
--tls-listen-addr 127.0.0.1:6697 TLS
--tls-cert / --tls-key None Enables TLS
--server-name freeq
--challenge-timeout-secs 60
--db-path None (in-memory)
--web-addr None Enables HTTP/WS
--iroh false Enables iroh
--iroh-port random
--s2s-peers empty Comma-separated endpoint IDs
--max-messages-per-channel None Message pruning
--plugin None Load a plugin by name (repeatable)
--plugin-dir None Directory of *.toml plugin configs

17. Plugin System 🆕

Feature Status Notes
Plugin trait with event hooks ✅ Extensible server behavior
PluginManager in SharedState ✅ Dispatches events to all loaded plugins
CLI activation (--plugin name:k=v) ✅ Inline config via key=value pairs
Directory loading (--plugin-dir) ✅ Each *.toml file = one plugin
TOML config format ✅ Supports multi-rule plugins
on_auth hook ✅ Override DID/handle after SASL auth
identity-override built-in plugin ✅ Match by handle or DID, replace display ID
Example: examples/plugins/kurt.toml ✅ TimeSync.bsky.social → 3|337
Supported by
Powered by