Selçuk Karayel’s Yudum.NET rebuild puts the IRC server, account and channel services, website, browser gateway and Lua runtime in one Go binary. The goal is to make a person’s identity, messages and permissions consistent across raw IRC, browser and website clients. The trade-off is fewer separate state and synchronization paths in exchange for a larger, shared failure domain.
Why make one process responsible for identity?
The central design constraint is that a person should remain the same person regardless of how they connect. In a split design, an IRC daemon, services daemon and website can each own or cache part of a user’s state. That creates boundaries where identities, permissions or message history can drift unless the components exchange updates reliably.
As an Amazon Associate I earn from qualifying purchases.
Karayel instead describes the services as ordinary Go packages that use the IRC server’s in-memory user and channel state and the same database as the web-facing parts. The intended result is one account resolver and shared records rather than separate copies that need to be synchronized. This is the author’s account of the implementation, not an independently inspected codebase.
| Design choice | What it simplifies | What it costs |
|---|---|---|
| One process with shared server state and database | Services do not need a separate server-to-server protocol, and there are fewer independently maintained views of account and channel state. | A fault or resource problem in the process can affect several functions at once; services cannot be scaled or deployed independently in the same way as separate components. |
| Separate IRC daemon, services and web components | Components can have distinct deployment, scaling and failure boundaries. | They need explicit interfaces and coordination, including keeping separate representations of identity and state aligned. |
This comparison is architectural reasoning, not a measured comparison of deployments. Karayel names the downside plainly: “The cost is a single failure domain.” He reports using a short-lived bridge process that opens the same port with SO_REUSEPORT while a replacement binary starts, keeping the HTTP side available during deploys. That describes one deployment technique; it does not remove the broader shared-process failure boundary.
#1 Best Overall
How the same account works across IRC and the web
The authentication mechanism varies by client, but the account it resolves to is shared. Karayel’s account model describes raw IRC clients authenticating through SASL PLAIN or EXTERNAL, or through NickServ; the website uses a session cookie; and the browser app receives a short-lived token. Each route is said to reach the same account resolver.
Names are normalized before being used as map or database keys. This matters because case-folding behavior can differ across browsers, Go and SQL; without a consistent normalization rule, two spellings of a name could be treated as different keys in one layer and equivalent in another.
Message delivery follows the recipient
The reported delivery rule depends on whether the recipient is connected, not on which client the sender used. A connected recipient gets a live protocol message and the stored copy is marked read. If the recipient is offline, the message is stored unread for a later visit. The repost of Karayel’s article says offline history is retained only between mutual friends.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →This separates a client’s transport from the account’s message record: changing from IRC to the browser does not, by itself, create a different recipient identity. The account and message behavior described here are the author’s reported design.
One source of shared records, with layers that point inward
The project’s package structure is described as a dependency direction: handlers call content logic, content logic calls the data layer, named veri, and lower layers do not call back upward. The author describes veri as the sole owner of shared records such as accounts, settings and messages. That boundary helps prevent multiple application layers from becoming competing owners of the same data.
In a codebase of this scale, this is an organizational constraint as much as a runtime choice. Karayel reports roughly 300,000 lines of Go, excluding 265 test files, plus about 13,000 lines of sandboxed Lua. These are the author’s approximate project counts, not independently verified measurements.
Rank #2
- Color-Coded Tabs: Highlight the most important sections with our colored tabs for the IRC 2021
- Easy Navigation: Our color-coded tabs have large font and are printed on both sides so you can easily navigate the IRC 2021 Code Book
- Alignment Card Included: Our tabs are easy to install in alignment using our tabs alignment system. Each tab includes the location and page number for super easy installation
- Repositionable Design: If you misalign the tab no problem! The tabs are repositionable but also once they are folded, stick securely so navigating the IRC 2021 is easy and efficient
- Laminated Durable Tabs: The tabs are laminated with 3 mil film for durability and stiffness to withstand frequent use
SQLite: separate reads from the single writer
Karayel describes SQLite as a single-writer database. The initial setup used one connection for both reads and writes, with SetMaxOpenConns(1). In the author’s stress test with 32 concurrent requests, about half of the waiting time was attributed to waiting for that connection. Reads queued behind other reads as well as writes, so merely issuing read-only work did not avoid the bottleneck.
Recommended Free Tools
The reported redesign uses one writer connection for writes and transactions, and a separate pool of read connections opened in WAL mode with query_only(ON). The separation addresses connection queueing; it does not make SQLite a multi-writer database. The write path still needs to respect its single-writer constraint.
Per-connection page caches also affected memory. Karayel says an earlier setup with 16 connections and 32 MB of cache per connection pushed memory toward 915 MB. The reported adjustment used smaller per-connection caches and shared mmap. These figures describe the author’s configuration and experience, not a general SQLite benchmark or a guarantee about another workload.
Backpressure: do not let a slow client hold up a channel
Each IRC connection reportedly has a bounded outbound queue, configurable by connection class. When the server broadcasts, it attempts a non-blocking send into each member’s queue instead of waiting for that client to read. If the queue is full, the lagging client is disconnected with “SendQ exceeded.” Karayel summarizes the policy as: “The server never waits for a client.”
This is a deliberate choice about who absorbs overload. A slow reader does not make the broadcaster wait indefinitely, but that reader can be disconnected and must reconnect. Queue bounds therefore protect the rest of the channel at the expense of a client that cannot keep up.
Keep Lua hooks out of the sender’s hot path
The Lua runtime is described as not goroutine-safe, so access is guarded by one lock. Initially, hooks ran synchronously on the sending connection’s loop. A script making an outbound HTTP call could hold the lock for seconds, delaying work for users in other channels while the runtime was unavailable.
Rank #3
The reported fix is a bounded, ordered worker queue drained by one worker. The sender enqueues work instead of executing the script inline. If the queue is full, the message is omitted from script processing and a count is recorded; per-account bot-command rate limits further constrain abuse. The queue preserves order for work it accepts, while its bound means the system can shed script work rather than allow a slow bot to stall message handling. As Karayel puts it, “A user’s message is never delayed by a bot.”
Go in the browser: shared implementation, different constraints
The browser programs are compiled to WebAssembly with TinyGo. Karayel reports avoiding reflection-heavy packages and using the browser’s JSON.parse through syscall/js. Explicitly sized unsigned integer types address the fact that WebAssembly’s int is 32-bit. Goroutines are cooperative in this environment, so network work uses event-loop callbacks and code must yield rather than assume a goroutine behaves like a native Go thread.
The implementation also has a strict Content-Security-Policy and a UI event-delegation layer. The author’s reported browser artifact sizes are 5.8 MB for webchat, or 1.9 MB gzipped, and 1.5 MB for the site, or 0.5 MB gzipped. These are the project’s stated build sizes; the article does not provide a comparison against another browser stack.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsGateway transport and real client addresses
The repost describes HTTP long-polling as the production browser-to-gateway transport. It mentions WebSocket and WebRTC data channels as alternatives, without reporting comparative performance results. The gateway uses WEBIRC so the IRC server sees the browser client’s real IP address rather than only the gateway’s address.
Calls, voice rooms and streaming are separate media paths
The same repost describes peer-to-peer WebRTC calls, moderated voice rooms whose state is held by the server, and one-to-many streaming over WHIP/WHEP. These are reported features, but no comparative throughput, latency or capacity results are published for them.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Keep game rules authoritative on the server
The described game engine separates rules, drawing and bridge packages. The server validates moves and computes the view each seat is allowed to see. In a card game, an opponent’s hand is represented to a player only as a count; spectators do not receive hidden game state. The browser renders its permitted view and submits a move selected from the legal moves supplied by the server.
This arrangement makes the client responsible for presentation and input, not for deciding whether a move is valid or what private state another player may see. It applies the same shared-state principle to games: authoritative rules and access to hidden information remain on the server.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWhat the reported deployment figures establish—and what they do not
Karayel’s September 30, 2026 article reports the figures below. They are project-specific statements by the author, not independently verified tests.
| Reported item | Author’s figure | Qualification |
|---|---|---|
| Go codebase | About 300,000 lines | Excludes 265 test files; approximate count reported by Karayel. |
| Sandboxed Lua | About 13,000 lines | Approximate project count reported by Karayel. |
| Deployment host | One VPS with 6 vCPUs and 12 GB RAM | Reported deployment configuration. |
| Statically linked binary | 35 MB | Reported without cgo. |
| Webchat WASM | 5.8 MB; 1.9 MB gzipped | Project build sizes reported by the author. |
| Site WASM | 1.5 MB; 0.5 MB gzipped | Project build sizes reported by the author. |
| Resident memory | About 550 MB RSS | Reported project figure; workload and measurement procedure are not specified in the article. |
| Earlier SQLite cache setup | Memory approached 915 MB | Reported for 16 connections with 32 MB of cache per connection, before the described cache and mmap adjustment. |
| SQLite connection stress test | 32 concurrent requests; roughly half of waiting time attributed to the single connection | Author-reported test of the initial one-connection setup, not an independent benchmark. |
The article does not publish an independent benchmark, a user count, or a completed load-test result for several thousand concurrent browser clients. The larger gateway test is described as still underway, so the deployment figures should not be read as evidence that this concurrency target has been reached.
When this architecture is—and is not—a fit
The strongest case for this approach is a system where several interfaces genuinely need the same live account, permissions and message state, and where the team can maintain clear internal ownership boundaries. Direct calls and shared records avoid a separate services protocol and the synchronization work that comes with multiple copies of state.
The counterweight is operational concentration. Separate components offer more independent deployment and scaling options, and can limit which failures spread. In one process, isolation has to be designed inside the application: database access paths, bounded client queues and deferred bot execution are examples of the boundaries Karayel describes. None of them removes the single failure domain.
The title’s “28-year-old” wording is not supported with a timeline in the article’s body. The evidence describes a rebuild of Yudum.NET and its architecture, but does not establish the network’s historical age. The system is therefore best understood as one developer’s reported design and operating experience, not proof that a single process is always preferable or that the stated scale has been independently demonstrated.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




