1. 37
    1. 26

      actively hostile to 3rd party clients/general hackery

      It’s good to see that noted, but “actively hostile” is a bit of an understatement; it’s against the Discord ToS to even acknowledge the existence of 3rd-party clients on Discord, and you can get permabanned for it.

      I think part of the problem is IRC already works completely perfectly for people like me, and despite several attempts to do so, I’ve never been able to wrap my head around what it is about Discord/Slack/whatever that appeals to people who hate IRC. I read thru the “Desirable Discord features” section and my reaction to each thing is either “I’m glad we don’t have that” or “meh; don’t care even a little bit”. The notable exception is that I understand that setting up a bouncer is a bit of a pain for new users, but I did that several decades ago so I don’t personally care; and supposedly ircv3 solves this. (but again, I don’t actually care enough to look into it!)

      So when people like me try to improve the situation, it ends up being ineffective because there’s just this huge gap we aren’t even capable of perceiving much less bridging.

      I’m not seriously considering moving Lobsters chat to Discord

      Thank you!

      1. 11

        I think part of the problem is IRC already works completely perfectly for people like me, and despite several attempts to do so, I’ve never been able to wrap my head around what it is about Discord/Slack/whatever that appeals to people who hate IRC.

        I don’t think Discord primarily appeals to people who hate IRC; I think it appeals to people who never used IRC and whose experience of computing was such that all the places they wanted to chat in were already using Discord. Often this is people who were too young to have been using IRC on desktop computers in the 90s and 2000s, and who started using any kind of chat in the context of video game voice chat with added text, which is what Discord was originally designed to do in the mid 2010s.

        If you’ve never used IRC and only ever used Discord, because all the communities you ever cared about used Discord to chat as a default and none of them used IRC, then I think the limitations of IRC will be very apparent - It has no good mobile clients, if you don’t set up and maintain a bouncer yourself you’ll miss messages, you can’t embed images or do seamless voice chat or react with fun emojis.

        To be clear I think it is extremely bad that Discord is so popular, because it is controlled by one company that is inherently hostile to users. But it is definitely true that purely as a chat protocol Discord is manifestly better than IRC, in every way other than that the Discord company will eventually fuck over its users after huge portions of the population have become reliant on it (it is already fucking over some users).

        I really want there to be a good free software alternative to Discord, precisely because Discord the chat app is in fact so good and useful and because you need something really good to kill the existing network effect of Discord. Matrix is doing its best and I sincerely hope they succeed, but the fact is that way more people are using Discord than Matrix right now and everyone complains about the Matrix-Discord bridge being unreliable just as they do about the Matrix-IRC bridge.

        If I had Elon Musk money I would buy Discord and hire the entire Matrix core team to be in charge of turning it into the world’s best Matrix solution. Unfortunately I am less rich than that.

        1. 3

          I think the main reason that Discord is as popular and prevalent as it is is that it’s so incredibly easy to just set up a new server with all the bells and whistles. That is the main reason why a self-hosted discord will never take off: nobody wants to go through the time and effort to set up and maintain their own server, when you could just click a few buttons to set it up and have to never worry about maintenance.

          The protocol is secondary in this regard, i think. I’m not saying it’s trivial to build something like what discord has, but it is doable. What’s significantly more challenging is funding a seemingly unlimited service that allows for not just chat, but file uploads, voice/video chat, et cetera for free. And as much as it sucks, I don’t know if an open source model is going to realistically allow for something like that in the word that we live in.

        2. 9

          I think I would’ve said the same until pretty recently. I first used IRC in late ‘92 or early ‘93; though I only regularly using it starting in 2001. More recently I spent a 4.5 years at a company that used Slack well, and about two years ago stared using Discord for a video game and a local friend group. There are a couple things in the features listed that are explicitly for new users, but all the rest are things I’ve taken to over the last few years.

          As an example, I thought emoji reactions were juvenile and tacky, I resented seeing them and avoided using them. After being exposed to them for a few months I learned they’re actually a really nice way of expressing things that would be body language in an offline conversation. They improve humor, appreciation, empathy, camaraderie. When I use IRC that stuff isn’t absent, but it feels muted, less rewarding. I list a bunch of popular chat systems at the bottom of the post and I think all of them have it because it improves communication. IRC has had a similar feature in emotes longer than any of those have existed, but it doesn’t work nearly as well and I’ve seen it dwindle to nothing over the last 20y. Emotes are missing that extra bit of polish and design to go from “no, IRC can do that!” to ubiquitous value.

          1. 3

            it’s against the Discord ToS to even acknowledge the existence of 3rd-party clients on Discord, and you can get permabanned for it.

            Does that mean you can be permabanned for bringing up the ToS? :D

            Do you have a source for that claim?

            1. 9

              Do you have a source for that claim?

              Mainly from firsthand discussions, but there is also this:

              https://cadence.moe/blog/2020-06-06-why-you-shouldnt-trust-discord#untrustworthy-staff

              Discord does not go out of their way to detect client mods, so you can usually get away with them unless you’re doing something like mass joining servers faster than a human could. However, you will most likely be banned or reprimanded if a staff member happens to see you publicly post a screenshot from an obviously modified client.

              I saw an exchange where a staff member saw a modified screenshot, and banned the person’s entire account, then unbanning it after 2 minutes, as a joke. I don’t think this is a very funny joke, and it shouldn’t be taken lightly. This shows that staff have the power to do whatever they want, and there don’t seem to be any review processes about reasonable use of power.

              1. 6

                I have been threatened with a Discord account ban for bringing up the existence of a modified official client in the Discord official support server.

                Modified, here, means that I used Electron’s devtools to fix a bug in my local copy of Discord so it didn’t eat my battery.

            2. 18

              Sorry I’m late to the party! Libera has a good relationship with Lobsters so thankfully (though sadly) none of this is a real surprise.

              Ultimately, Libera is about supporting communities and projects, not inherently about IRC itself, so we understand that there are a bunch of projects who are looking elsewhere, and it pains us that we’re not able to provide for the needs of all these projects, particularly those projects that are newer, and so don’t have established norms and information to help get new users online.

              I know of course that it was mentioned in the document, but it’s true: irc as an ecosystem is always looking for people to help improve, mostly on the client side! It feels to me that by the time someone has gained the experience needed to write a good irc client, they’ve mostly internalised the sharp edges of the software they’ve used, and mostly are doomed to remake new versions of it.

              We’re desperately in need of someone who can write a really good, ideally free software client. IRCCloud, while non-free SaaS, has shown that it’s entirely possible to make a client with good user experience if this is what we want.

              If anyone wants to know any more, chat about IRC, or Libera.Chat in particular - drop me a message! I’m here, but also on irc as kline. You can find me in #lobsters (of course!), #libera, or best is to /query kline direct to open a direct message with me.

              1. 4

                Thanks for all your work on Libera. In my mind Libera is exemplary of how user-first free software projects operate at best.

                I see that Libera has adopted a few of the extensions from ircv3. Is there interest in eventually adopting the chat history extension once it’s standardized? Would this require upstream support first?

                1. 5

                  We keep an eye on chathistory but there are some snags. It requires that we hold a lot more data, and how we do that in a way that is sensible and private isn’t straightforward, but we have been thinking about how it might be solved. We’re open to it, and just thinking about the different ways it could work.

                  For example, a general position held by IRC users is that if you say something when someone’s not around, they won’t ever see it. This is one of the issues that we had with the matrix bridge - it was possible for users to retroactively see discussions they weren’t part of.

                  The same would be true of chathistory, and it changes the character of IRC enormously. Now, it’s no longer the case that what you said to a particular audience will stay in that audience. What you said about that less-than-perfect friend you know from another channel might suddenly be sent to them if they joined your channel some time later, entirely innocently.

                  1. 2

                    With Matrix, I found it very frustrating that certain features like edits and reacts could not be disabled on a per-channel basis. Maybe chathistory needs to work that way; it could be available if the ops of a channel collectively agree to turn it on, but then it’s their responsibility to communicate the implications of their choice to the community (ideally it would be the community itself making the decision).

                    1. 4

                      Yes, when (if?) we implement it, it’ll certainly be on a per-channel basis. We’ll probably also make it very clear to users joining that chathistory is on for the channel - even if their client doesn’t support it - and that anything they say may be relayed again in future.

                    2. 1

                      While this is true, I think it’s an established norm in nearly every other piece of group chat software. At least, the ones that don’t try to offer E2E encrypted messaging.

                      If enough people feel that this is a problem, perhaps there can be an unlogged mode that channel admins can set?

                      1. 1

                        It’s different here because you’re (potentially) talking about changing the established norm for existing communities that have existed since the 1990s. Supporting it for new channels, sure; seems fine as long as it’s clear to users, but for existing channels there will be very wildly varying degrees of acceptance for it.

                  2. 2

                    IRCCloud, while non-free SaaS, has shown that it’s entirely possible to make a client with good user experience if this is what we want.

                    There’s https://convos.chat/ as something like a self-hosted IRCCloud (with built-in bouncer, fancy interface etc.)

                    1. 1

                      We’re desperately in need of someone who can write a really good, ideally free software client. IRCCloud, while non-free SaaS, has shown that it’s entirely possible to make a client with good user experience if this is what we want.

                      That would be so great! Totally willing to financially support such a client.

                    2. 8

                      My experiences using IRC back in the day always were very very shit (disastrously bad clients, nobody I knew online) so I’m really glad stuff like Discord exists.

                      1. 7

                        What I like about IRC clients, though they have a learning curve, is that mine consumes approximately 1000x less memory than Slack or Discord do. Now, I could just buy more memory of course. But using IRC feels like being on the right side of history. To me, bloat is a bigger issue than usability. That also means you’re only gonna see a certain kind of people in IRC nowadays. But that’s ok.

                        1. 5

                          I don’t mind a learning curve, but it should have some kind of payoff.

                      2. 4

                        Great writeup! And good notes for our own team to reference in the stuff we’re building.

                        But don’t forget in the Discord downsides that you can buy almost all private messages ever sent on Discord for $5, which I would say is not exactly great.

                        1. 2

                          If I’m reading this article correctly, those are messages sent on servers, not private (direct) messages.

                          That being said, yeah, Discord is a privacy nightmare. Not only does every user have full access to the message history on the servers they’re on (unless a particular server disables history outright, which is crap too), but your identity is linked between different servers too.

                          I like how easy it is to keep identities separate on IRC.

                          1. 1

                            Ah, I must not have read that thoroughly! Thanks.

                            But yeah. Discord is generally deeply uncomfortable structureally. Also, maybe I misremember this one, but I seem to remember that your admins can read the private messages you have between users on “their server”, and that the UI doesn’t make this clear is a “decision”

                            1. 4

                              Also, maybe I misremember this one, but I seem to remember that your admins can read the private messages you have between users on “their server”, and that the UI doesn’t make this clear is a “decision”

                              No, they can’t. In theory, Discord can, but any direct correspondence between users isn’t visible to “server” admins, because it takes place outside of those “servers”.

                              1. 1

                                Slack does offer (paid) workspace admins the option of that.

                              2. [Comment removed by author]

                          2. 3

                            This is a great comparison! Been thinking a lot about chat applications lately, and there really is a huge empty void for FOSS and FOSS-adjacent communities that have ethical concerns about Discord. The fact that IRC is still the only really viable option in 2024 feels so silly. I really like IRC, but it’s old and clunky and doesn’t have a lot of features people have come to rely upon, and it really is difficult for the uninitiated to get started with it when Discord is so easy. Unfortunately, there isn’t really a FOSS alternative that I can wholeheartedly recommend. Matrix is the most obvious alternative, but the more I use it the more pessimistic I become. I certainly wouldn’t want to move an existing IRC community over to it.

                            1. 4

                              Zulip is great

                            2. 2

                              I’ll just be blunt:

                              I used to be rather more involved in the lobsters IRC–met some great folks there–and in order to do that, I had to display the minimum number of brain cells required to navigate freenode (now Libera) and get setup. In exchange, I was given access to something with great hackability, something I could access from motor coaches via TUIs and tmux as well as from a web interface), and without the distractions of blinking emoji and images and voice and all sorts of other silliness.

                              (And before anybody gets too grumpy about weird tech stacks/gatekeeping…back when Lobsters was first starting out it was full of BSD and BSD-adjacent folks, though I don’t know if they moved on or have just faded into the background noise floor of the site.)

                              I’m glad to hear that pushcx doesn’t seem super excited about a switch to Discord.

                              The comedy option, of course, would be to stand up baby’s first chat server and co-host it here, using the same auth as the site. This would be a trivial workload at our scale for, say, a Phoenix app.

                              1. 1

                                Mulling it over a little further for LobstersChat:

                                • No permanent storage or database (ape IRC in this regard)
                                • Don’t display anything if you’re not logged in, so that drops potential concurrent users significantly and simplifies fanout
                                • One room to start, add more later, is trivial again if you don’t worry about permanent state
                                • Maybe a database table (could totally just be sqlite) for mod actions (e.g., “this user is muted, this user is banned”), use ConnCache or whatever your cache of choice is in Elixir for a write-through cache to further reduce DB hits when handling message sends (which are laughably infrequent anyways)
                                • Use Phoenix LiveView so you’re not fucking around APIs and SPA bullshit.

                                Like, this is literally the “Hello, world” of Phoenix LiveView for the last few years.

                                1. 1

                                  Hell, here’s your first cut, hastily adapted from here and hacked up with bit of Claude and some elbow grease because Claude doesn’t Elixir super well yet:

                                  Application.put_env(:example, Example.Endpoint,
                                    http: [ip: {127, 0, 0, 1}, port: 5001],
                                    server: true,
                                    live_view: [signing_salt: "aaaaaaaa"],
                                    secret_key_base: String.duplicate("a", 64),
                                    pubsub_server: Example.PubSub
                                  )
                                  
                                  Mix.install([
                                    {:plug_cowboy, "~> 2.5"},
                                    {:jason, "~> 1.0"},
                                    {:phoenix, "~> 1.7.2", override: true},
                                    {:phoenix_live_view, "~> 0.18.18"},
                                    {:phoenix_pubsub, "~> 2.1"}
                                  ])
                                  
                                  defmodule Example.ErrorView do
                                    def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
                                  end
                                  
                                  defmodule Example.ExampleLive do
                                    use Phoenix.LiveView, layout: {__MODULE__, :live}
                                    @topic "chat"
                                    def mount(_params, _session, socket) do
                                      if connected?(socket), do: Phoenix.PubSub.subscribe(Example.PubSub, @topic)
                                      # we could pull the username from params, then check that it's signed, and redirect otherwise
                                      {:ok, socket
                                            |> assign(username: "VvV", message: "")
                                            |> stream(:messages, [])}
                                    end
                                  
                                    def render("live.html", assigns) do
                                      ~H"""
                                      <script src="https://cdn.jsdelivr.net/npm/phoenix@1.7.2/priv/static/phoenix.min.js"></script>
                                      <script src="https://cdn.jsdelivr.net/npm/phoenix_live_view@0.18.18/priv/static/phoenix_live_view.min.js"></script>
                                      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
                                      <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
                                      <script>
                                        let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
                                        liveSocket.connect()
                                      </script>
                                      <h1>Lobsters chat</h1>
                                      <%= @inner_content %>
                                      """
                                    end
                                  
                                    def render(assigns) do
                                      ~H"""
                                      <div class="container">
                                        <div class="row">
                                          <div class="col-md-8 offset-md-2">
                                            <h2 class="text-center mb-4">Chat Room</h2>
                                            <div id="chat-messages" class="border p-3 mb-3" style="height: 400px; overflow-y: auto;">
                                              <div id="messages" phx-update="stream">
                                                <%= for {id, message} <- @streams.messages do %>
                                                  <div id={id} class="mb-2">
                                                    <small class="text-muted">
                                                    <b> <%= message.username %> </b>
                                                    <%= message.timestamp %>
                                                    </small>
                                                    <p class="mb-1"><%= message.content %></p>
                                                  </div>
                                                <% end %>
                                              </div>
                                            </div>
                                            <form phx-submit="send" class="d-flex">
                                              <input type="text" name="message" value={@message} placeholder="Type your message..." class="form-control me-2" phx-change="change" />
                                              <button type="submit" class="btn btn-primary">Send</button>
                                            </form>
                                          </div>
                                        </div>
                                      </div>
                                      """
                                    end
                                  
                                    def handle_event("send", %{"message" => message}, socket) when message != "" do
                                      message = %{id: System.unique_integer([:positive]), username: socket.assigns.username, content: message, timestamp: NaiveDateTime.local_now()}
                                      Phoenix.PubSub.broadcast(Example.PubSub, @topic, {:new_message, message})
                                      {:noreply, assign(socket, :message, "")}
                                    end
                                  
                                    def handle_event("send", _params, socket), do: {:noreply, socket}
                                    def handle_event("change", %{"message" => message}, socket), do:
                                      {:noreply, assign(socket, :message, message)}
                                  
                                    def handle_info({:new_message, message}, socket), do:
                                      {:noreply, stream_insert(socket, :messages, message)}
                                  end
                                  
                                  defmodule Example.Router do
                                    use Phoenix.Router
                                    import Phoenix.LiveView.Router
                                  
                                    pipeline :browser, do: plug(:accepts, ["html"])
                                    scope "/", Example do
                                      pipe_through(:browser)
                                      live("/", ExampleLive, :index)
                                    end
                                  end
                                  
                                  defmodule Example.Endpoint do
                                    use Phoenix.Endpoint, otp_app: :example
                                    socket("/live", Phoenix.LiveView.Socket)
                                    plug(Example.Router)
                                  end
                                  
                                  {:ok, _} = Supervisor.start_link([Example.Endpoint,{Phoenix.PubSub, name: Example.PubSub},], strategy: :one_for_one)
                                  Process.sleep(:infinity)
                                  
                                  1. 1

                                    Run it with elixir <whatever the file is>.exs.

                                    To solve the username problem, in production, I’d tweak this so that the params has a signed time-limited token–use a preshared key from an env var to validate it here–and then I’d do a redirect from the Rails app to this, which uses the logged-in user session to generate a signed url that this app would ingest and go “oh, the mothership said this is friendlysock, I’ll let that user in”. And, I just wouldn’t show anything to users without that token.

                                    Not perfect, but it gets you a decent amount of the way to IRC using Lobsters auth and it took me about half an hour of futzing to make.

                                    (And if you haven’t looked into LiveView by now, folks, you’re missing out.)

                              2. 2

                                I so wished that IRCv3 was something widely supported in terms of networks, servers and clients. I think it’s a great initiative and I hope that it succeeds before IRC is completely dead. It’s saddening that the times of Usenet/NNTP and IRC being main ways of communicating passed and now people have to choose into which corporation’s silo they walk into.

                                1. 2

                                  Apparently libera.chat does support parts of ircv3: https://ircv3.net/support/networks

                                  Unfortunately the parts they support don’t seem to be particularly appealing, and they aren’t addressing the parts that necessitate the use of a bouncer, which is (in my mind) the main appeal of ircv3. But I’m curious what others think; if there are other parts of the protocol worth keeping an eye on. I guess the accounts stuff looks pretty reasonable?

                                  1. 7

                                    libera 100% needs to incorporate CHATHISTORY. I run https://pico.sh and ask users to navigate to our IRC channel. There are so many people that join/leave because they show up to a channel with 0 chats and think it’s dead.

                                    Discord/slack/etc are stickier because when you join a server it keeps you logged in and you can see previous chats.

                                    Asking users to setup a bouncer is a huge wall to overcome for newbies, especially when these other chat apps are so seamless.

                                    Further, getting push notifications is also a major problem, something that is automatic with other chat apps.

                                    Private channels is also a massive pain to manage on libera. There are so many flags and things to “get right” that makes it prohibitive to use in any meaningful way especially compared to how stupid simple it is in slack/discord.

                                    1. 1

                                      Further, getting push notifications is also a major problem, something that is automatic with other chat apps.

                                      I don’t understand what this means; don’t other apps have the same problem of needing to keep a socket open to be notified of what happens? Or is it just that mobile apps for Discord etc can reuse an existing Google-provided socket rather than needing a Discord-specific one? To me this feels like bad design to send everything thru a single point of failure, and it only works with proprietary operating systems anyway.

                                      Private channels is also a massive pain to manage on libera. There are so many flags and things to “get right” that makes it prohibitive to use in any meaningful way especially compared to how stupid simple it is in slack/discord.

                                      This isn’t really a libera issue, is it? As far as I can tell it’s just that many clients do a bad job of supporting it.

                                      1. 6

                                        I don’t understand what this means; don’t other apps have the same problem of needing to keep a socket open to be notified of what happens?

                                        Mobile platforms generally follow a model where apps can be killed when they’re not foreground. iOS makes this a requirement, Android is a bit more flexible in that it allows background services. The typical model for idle flows is:

                                        1. App enters a quiescent state where it can be killed
                                        2. App may be killed by OS.
                                        3. A single connection is kept open to a notification service (with long timeouts).
                                        4. Notification service receives notification, restarts app.
                                        5. App connects to service and gets updates.

                                        This means that a hundred apps can all be in the waiting-for-notifications state but the number that are actually consuming RAM can be zero. Some apps put actual data in the message, Signal just sends a 1-bit notification saying ‘now is a good time to poll for events’.

                                        The notification service also performs buffering so that devices that drop off the network and reappear can be receive all queued notifications when they reconnect.

                                        1. 6

                                          Or is it just that mobile apps for Discord etc can reuse an existing Google-provided socket rather than needing a Discord-specific one?

                                          Yes, push notifications are centralised - the client app tells Android to listen to incoming notifications from Google, then it tells the server to send notifications to Google, and the app is no longer involved in the notification process.

                                          To me this feels like bad design to send everything thru a single point of failure, and it only works with proprietary operating systems anyway.

                                          Sending everything though a single point of failure is a downside, yes. And giving Google existential control over an important feature that communication apps are supposed to have is a big downside. However, power-drain constraints mean it’s a lot better for one service to poll one server occasionally, instead of a bunch of apps polling a bunch of different servers without coordination. And for better or worse, huge numbers of people feel that it’s an acceptable trade-off.

                                          1. 3

                                            However, power-drain constraints mean it’s a lot better for one service to poll one server occasionally, instead of a bunch of apps polling a bunch of different servers without coordination.

                                            Yeah. And recently the UnifiedPush project has been gaining some traction as an alternative to Google’s proprietary push service. Mostly on Android still, but it’s not platform-specific and a Linux device could run a UnifiedPush distributor just as well. The apps making use of this so far are mostly Matrix clients and Fediverse apps.

                                  2. 1

                                    I remember a while ago I asked you about setting up an “unofficial” discord… I did then promptly forgot to share it here/IRC

                                    But it’s there if you want to post the invite link! I don’t even have an IRC client installed any more…

                                    1. 1

                                      I’d be interested in hearing opinions on bridging software. I’ve used matterbridge in the past and it’s done a good enough job. If you’re willing to do public logging it also gives you a way to preserve/export chat history, or at least make it Google searchable.

                                      1. 1

                                        Without support from Libera, bridging is always going to suck very badly because it has to go thru a bot account. The old Matrix bridge (formerly supported by Libera) allowed the bridge to create one account per Matrix user, but that’s not something that user-operated bridges can do.

                                        You can work around the problem client-side (and I do) but it’s a terrible experience for people whose clients don’t have this feature: https://git.sr.ht/~technomancy/erc-bridge-nicks (I had to write it myself, not that it was difficult)

                                      2. 1

                                        There’s stuff like rocket.chat which seems to be a FOSS discord clone. I found about it because of https://blender.chat.

                                        I think discord is good. They have actually been innovating a fair bit when it comes to structuring real time conversations. Like you can start a thread from a single message. This has been replicated in Matrix as well. I haven’t found it particularly groundbreaking but it shows they are trying new things.

                                        But their policy towards 3rd party clients is a dealbreaker for me. I never use it in a serious capacity because of that. Oftentimes projects will have their support forums on discord so I hop onto it when I need to but that’s it for me.