Case study of an amateur plugin author

In 2024 I was looking for work. I decided to offer my services as a community consultant. Mostly, though, people were interested in technical help getting their Discourse sites fixed or updated. One potential client asked if I could add a contact form for people who didn’t have an account to send feedback. I looked around and concluded it wasn’t possible. But I had plenty of spare time and followed the plugin developer tutorial to see what I could do. Eventually I got a contact form plugin developed and signed the client.[1]

Just so everyone is clear on this: I’m not a frontend programmer! It’s been 13 years since I was a professional programmer of any type. I know how to make an HTML form and that’s pretty much the extent of my knowledge. So I struggled through the Ember and Handlebars section of the tutorial and cobbled together a hack that worked well enough. Fortunately I was comfortable with templating systems having used them on a previous job.

I found a job with the OpenSSL Foundation[2] and mostly gave up my clients. But the client I built the plugin for kept me on retainer because he really appreciated my work. (I’ve done several unrelated projects for him.) In order to earn my retainer, I decided to upgrade his Discourse server. This is what I saw:

Only this was on my client’s site because I was stupid and had installed, but not enabled, the contact plugin on my staging site. So I quickly entered safe mode and disabled the plugin. Last weekend I spent some time figuring out what had gone wrong and how I could fix it for my client.

After some searching, I found Deprecating .hbs file extension in themes and plugins:

In the latest version of Discourse, using .hbs files in themes and plugins is deprecated. Support for this file format will be removed after the next ESR release.

This was in March and that means I ought to have had until basically the end of September to fix it if I were on the ESR release. But my Discourse configuration uses “tests-passed”[3] and so I got the error a few months early, I guess.

Since I’m going to have to fix it anyway (or disappoint my client) I jumped into the instructions: Automatically updating themes and plugins to .gjs file format. First step was to install a development environment since I’d changed laptops since the last time I tried this.[4] When I finally got Discourse running and verified that my plugin was broken locally, I ran the lint process[5]:

$ pnpm eslint --fix .

/Users/jericson/src/discourse-contact-plugin/assets/javascripts/discourse/components/contact-form.js
   1:8   error  Use Glimmer components(@glimmer/component) instead of classic components(@ember/component)          ember/no-classic-components
   3:16  error  Native JS classes should be used instead of classic classes                                         ember/no-classic-classes
   3:16  error  Please switch to a tagless component by setting `tagName: ''` or converting to a Glimmer component  ember/require-tagless-components
  20:3   error  Use the @action decorator instead of declaring an actions hash                                      ember/no-actions-hash

✖ 4 problems (4 errors, 0 warnings)

While it’s annoying to have to change my plugin, at least the lint process helped me clean up and modernize my code. The automated script fell over trying to convert to .gjs, however. So I decided to try out https://ask.discourse.com/

I have 12 questions over there. I would not share them with a human because they are just the flailings of increasingly frustrated programmer. At one point the bot suggested a “more robust modern approach” to one of my subproblems that included . . . a .js file and a .hbs file.

Still from 8½ in which the director has tossed away the critic’s negative review of 8½.

I know why this happens. It’s trained on Meta Discourse discussions and there are still a lot of posts that have Handlebars code, including part two of the official plugin developer tutorial. That stuff will get updated over time, but I worry it will take a bit longer because the official advice for getting help with the upgrade is to ask the chat bot rather than ask on Meta Discourse.

I guess I shouldn’t complain; it did help me sort out my code and probably with less friction than asking humans.

Platform stability

So I work for OpenSSL Foundation now. You probably know about OpenSSL because of Heartbleed. It’s used everywhere. The most popular version to download is 1.1.1 which reached end-of-life in 2023. The next most popular is 3.0, which was released in 2021, but is still supported as a Long Term Support (LTS) release. Next is 3.5, which is our latest LTS. Those three releases account for almost 2/3 of downloads from GitHub.

That’s a bit disappointing because 3.5 has some cool new features. But ultimately the features people care most about are some combination of SSL/TLS and cryptographic primitives. Unless you are excited about post-quantum cryptographic algorithms, you are going to put off the pain of upgrading as long as possible.

OpenSSL is way lower down in the stack than Discourse, of course. But the principle is the same. Unless there’s a new feature, people aren’t interested in breaking upgrades. I know y’all are excited about the new features that have been added to Discourse. I get wanting to change an API in order to get some optimizations later. I just worry that moving too quickly will hurt Discourse as a platform on which communities are built.

Speaking of which, there’s a really useful slide deck called Gardening Platforms written by Alex Komoroske. Slide 90 starts a section called “Platform + Ecosystem” that explains how platforms must coevolve with their ecosystems. In this case, Discourse is the platform which supports an ecosystem of plugin and theme designers, hosting services, the Meta Discourse community and even the communities built on Discourse. An important insight on the speaker’s notes from slide 98:

But they aren’t independent; they’re relate symbiotically.

Actions happening in one influence the other, and vice versa. Think of it as feedback loops connecting them in both directions.

They aren’t rigidly tied together, it’s more like a rubber band linking them. It’s a gravitational pull.

If a platform and an ecosystem move too quickly relative to each other, the bond breaks to disastrous effect. I trust Discourse to do right by the ecosystem. It just for me weekends like last weaken that trust.


  1. I’m moderately proud of my work even though it ended up being a fairly static site. ↩︎

  2. Foreshadowing! ↩︎

  3. That needs to be updated too ↩︎

  4. Redis and Rails were harder to get installed than I remembered. ↩︎

  5. Not before spending a lot of time failing to grab eslint.config.mjs, however. ↩︎

I think you got the error because of this bug, not because your plugin needed an update right now

I went though the same thing with many plugins I had written. I didn’t have the bandwidth to modernize them to the Discourse standard. I have a data science-type job so while I know software engineering concepts, I don’t keep up-to-date with the specifics of web dev stuff. In the end I didn’t update my site for 8 months because it relied on these depreciated plugins.

I don’t want to trivialize your struggle, but basically I think with the advent of agentic coding, this development pace has become a non-problem. What would have taken me a week or two to fix and get right took a $20 Claude Code subscription and a couple minutes per plugin. Not only that, but I was also able to optimize them for performance. After using agentic coding for a few work and hobby projects, I don’t think I will ever code something from scratch again in my life. It’s like the technological difference between writing and delivering a letter by hand versus sending an email. It’s a bit sad but yet at the same it feels like you’ve been gifted god-level powers.

Does seem likely. Getting on the latest ESR (and being a bit more vigilant testing) seems like a good plan from now on.

I don’t think pace of development is a problem per se. It’s the pace of everything. Why hasn’t the plugin tutorial been updated for instance? It’s a mine waiting to blow up in the face of some poor sap who wants to build a plugin. It’ll work for the moment, but eventually they will face the same problem I have. The fix isn’t to use AI to fix the plugin later, but to fix the instructions about making a plugin now. I mean, there’s no reason to still teach the old way of doing things, is there?

because we are a fairly small team maintaining a behemoth of a codebase and having to implement new features for paying clients, all the while providing support and keep things working for our open source community.

There is only so much we can do in a day, and documentation often trails behind.

I understand your frustrations very well, but I feel that point deserves a mention too.

Thanks for the detailed info @jericson. As you say, Discourse is in a very different position to OpenSSL both in terms of usage & position in the stack. It’s a constant balancing act of progress, customizability, and stability. There’s no perfect solution that will make everyone happy, but we’re always factoring in feedback from our customers & the open-source community. I really like the quote you shared:

:chefs_kiss:

As @moin mentioned, the experience you had with the .hbs deprecation was a bug on latest for about a week. Very sorry about that! While the use of .hbs is deprecated, it is still supported. Your .hbs code should be functional again now.

Thanks for calling this out. I’ve made a pass at cleaning up the remaining .hbs mentions in the docs:

Totally understand.[1] I really like Discourse and I wrote this post because I want Discourse to have continued success.

Something I’ve learned is that communities don’t care for change, but they are much more open to change if they feel they have agency. There innumerable ways to give people agency. For instance, the tutorial could be turned into wiki posts so that people like me can update them. Implementing the ESR plan helps too because it gives people the option to not make changes right away.[2] Being able to write up my experience and have it seen by people who manage the open source project helps too. Especially since the stuff I complained about got fixed overnight. :wink:

In “Listening to users considered harmful?”,[3] Kathy Sierra wrote:

Most of us realize that focus groups are notoriously ineffective for many things, but we still assume that listening to real feedback from real users is the best way to drive new products and services, as well as improve on what we have. But there’s a huge problem with that – people don’t necessarily know how to ask for something they’ve never conceived of! Most people make suggestions based entirely around incremental
improvements, looking at what exists and thinking about how it could be better. But that’s quite different from having a vision for something profoundly new.

True innovation will rarely come from what users say directly.

As I said, I’m not a frontend developer. I don’t really understand why these changes were made or how they will benefit me.[4] And that’s ok if they will, eventually, make Discourse better.

Still, it can help people like me be onboard if I can see the vision a bit more clearly. For this change, the pitch is:

  1. a much better development experience
  2. will enable large performance improvements in future versions of Discourse

Sounds good, I guess? I didn’t particularly notice #1 and #2 could mean a lot of things. More effective for me would be something like (and I’m totally making this up):

  1. When we converted the official Discourse plugins we found that it shaved off X% lines of code. By putting the template in the same file as the JavaScript, the code is easier to understand and modify in the future.
  2. We set up a branch testing removing Handlebars completely and discovered that change made page loads X% faster. Not only that, we saw a potential optimization that could eliminate [some problem users have raised].

A little more detail with an eye to educating non-experts goes a long way toward maintaining trust. I might not like the changes, but how can I argue with fixing actual problems other users have faced?


  1. OpenSSL has a similar dynamic. We have a Corporation (~15 people) that sells support contracts and a Foundation (10 people, including me) that looks after non-commercial interests. Our documentation lags too. While writing the original post, I noticed we still have references to features that were removed last month. I’m working on a PR for that. And we made some changes that downstream projects have been highly critical of. ↩︎

  2. Less helpful for plugin authors who want to support communities that want to stay on the bleeding edge. But it’ll be great for me since I believe I’m the only person using my plugin. ↩︎

  3. Her blog is gone from the internet, but there is a PDF archive. ↩︎

  4. Not that I really matter that much in the grand scheme of things. I’m talking about me as a stand-in for other people who depend on Discourse. I do know me better than most, afterall! ↩︎

Why does it need to be a wiki for that? The developer documentation is managed via GitHub. I like the process where the changes are reviewed even more than a wiki.

I agree that the plugin documentation should be updated at this point. The goal of the “depreciation” time period where the plugins still work but the site puts up a warning that they will break soon is to give the plugin authors enough time to fix them. Yet in that time period, a team of full-time paid developers couldn’t update the core plugin development documentation. It’s an odd expectation to place on individual developers when a team can’t fully manage it in the same time period.

What that signals to me is that the speed of development is too fast and/or plugin authors are not a significant priority to Discourse. Personally, I feel it’s moreso the latter. I understand that something has to fall to the side, so this is an observation from me rather than a criticism. Discourse remains fully customizable via plugins and I appreciate the continued improvements.

All that said, I think we are at a moment where a step-by-step documentation guide for building a boilerplate plugin is an obsolete idea. A single context document for an agent to read and build a plugin skeleton is all that’s needed now for an amateur plugin author. In fact, for an opensource codebase like Discourse, documentation is not needed at all since the agents get context directly from the codebase itself. When I was working on my plugins, I saw Claude reading the existing plugins as a way to learn the design patterns. And I was even able to root out a bug in the core code Chat Pitchfork timeouts: replies silently create threads and auto-tracking bloats over time

Basically, for anyone reading this who aspires to be an amateur plugin author, the documentation may be out of date but it’s 1000x easier to build a plugin than it ever has been before.

Just to clarify on this point: the deprecation timeline for hbs has only started recently. The earliest we’ll consider dropping support is after the next ESR (end of July). So yes, we should’ve updated the documentation sooner, but this isn’t a case of ‘dropping support without enough warning’. .hbs is still supported, and there is plenty of time to make the necessary changes.

We maintain over 600 themes & plugins, so I can assure you that we “feel the pain” of these migrations as well. We do our best to make the changes as smooth as possible for everyone, and will continue learning from each change we make.

:100: Yup

We don’t quite have this yet. But we are starting to build up a directory of skills in the core repository. Plus, all the developer documentation markdown has been moved into the core repository, partly so that it’s easier for AI agents to reference.

I might be conflating things in my head since I fixed my plugins for both the Ember 6 upgrade (the big update blocker for me) and migrated from hbs at the same time. Sorry if I over-asserted!

But I think if Discourse did want to grow the user-made plugin ecosystem, a modern “vibecoding” tutorial would be useful. But then again, is it desirable to open the floodgates to a wave of vibecoded plugins? Hard to say :smile:

Ah! That helps. PR submitted.

I’m a fan of putting documentation on GitHub. It’s quite a bit more work to submit changes than editing a wiki post, but the review step is helpful. (And for plugin author documentation, requiring knowledge of Git isn’t that high a bar.)