in which more paths are charted towards code independence

As the ninth anniversary approaches of the last project repository I created on Github, it's been so encouraging to see more and more projects migrate away from Microsoft Github. I love seeing the rise of Codeberg, not the least because it's a democratically-run non-profit which isn't subject to the whims of the extractive arm of an unaccountable exploitative mega-corporation.

If you're currently hosting a project on Github and you recognize the harm of Microsoft's monopoly, it's undeniable that Codeberg is your quickest and easiest offramp to an empowering and pro-user place. But at the same time, I don't see Codeberg as the be-all and end-all of Github replacements, for a couple reasons. Most obviously, putting all your eggs in one basket isn't ideal, even if it's a much better basket than the one we used to have. We shouldn't replace Github with one site at all; we need the strength and resilience that only comes with diversity1.

But beyond that, I'm reminded me of the way that some dominant ideas can become so dominant that it becomes difficult to even imagine alternatives to them. Forgejo (the software behind Codeberg) is unapologetically a Github clone. For most people in software development, Github has been synonymous with development workflows for so long that other ways of thinking have not only languished, but have started to feel nearly inconceivable. Even for people who want very much to get away from Microsoft, the design decisions made for Github follow you around from Gitlab to Bitbucket to Codeberg/Forgejo2.

This is a pattern you see over and over with open source alternatives to dominant systems; for a long time GNOME and KDE were just trying really hard to build the exact same thing as Windows, but without Microsoft. Mastodon is trying really hard to be Twitter without Twitter. When a company dominates the market, they capture not only their own users but even the imaginations of people actively resisting them. It usually takes a great deal of time and effort to carve out new patterns of thinking.

If you just want to get off Github, that's fine; you should do that first, and you don't need to tackle the job of learning a new flow right away. But I want to make space for people to think about alternatives. What does a post-github world look like? What other flows could we use to support project development and contribution? When people talk about moving off Github, the first objection is always "but everyone has an account there already!" And this is a fair point; no one wants to create Yet Another Account. I'm only really willing to consider alternatives that don't require creating another account, especially not in a distributed system where each project might be on its own server.

bright neon sign saying 'telephones'

Let's start by going back to the basics. Simon Tatham has written up a guide describing how he uses Git without any forge-like software involved. He keeps his repositories on his own server with nothing but a read-only gitweb rendering their contents as HTML. If you want to contribute a patch, you can publish your own clone on your host of choice and let him know (via email, chat, social media, or whatever) which branch to pull from. This method works best for projects with a single maintainer and a small community. It's a good starting place for most projects. Then when you have more going on, you might want to add a little more structure to help keep track of things.

And then there's projects like Radicle offer a flow that manages to work in a peer-to-peer way with no server involved. Being fully peer-to-peer, your machine gets all the data synced locally, so it works great when offline too, and you don't have to create yet another account on another system. This is a bold vision of how the future of development might look.

But when I was searching for an alternative for Fennel I went looking to the past instead. Back when I was fresh out of university and an enthusiastic Subversion user, I set up an instance of Trac, a web-based version control, ticket, and wiki system. I used it for all my projects, but it was mostly just a personal organization tool as at the time I did not have any projects that got more than one or two patches from other contributors. Then in 2007 I switched from Subversion to Git, and had to drop Trac. A few months later in a moment of weakness, I started putting my projects on Github.

Over the years I lost track of Trac, largely due to the fact that since it was made by fans of Subversion, it took them several years to add support for Git, by which time most people had switched away from it. But Trac offered something really special. The individual features around ticket reporting and wiki pages are impressive, but most of all, I see Trac as the pinnacle of web app design from the golden age of progressive enhancement.

What does that mean exactly? Well, a few years after Trac dropped off my radar, we saw the rise of React, GraphQL, and the Single-Page App (SPA). While there are certain type of sites for which the SPA interaction style makes sense, these technologies saw mass adoption across every single kind of web app, regardless of whether they were a good fit. As the software industry is largely driven by trends and fashion, React's "cool factor" led to a mass amnesia regarding how to make normal, well-designed web apps made of HTML with a sprinkling of scripting on top and everything became one big tangled, brittle mass of Javascript that completely keeled over when scripting wasn't available. But Trac got it right: the server generates HTML (quickly3!) and sends it to you, and in a few cases uses some optional scripting to get things like live previews.

bike lane

Anyway, when I set up Fennel's Trac, I was mostly impressed with how easy it was to get going, but there were a handful of things that were weirdly off. The most glaring is that even in 2026, the default setup is still to use Subversion instead of Git. Support for Git is now built-in at least, but for some reason you still have to enable it in the config. An easy change, but a strange one.

Secondly, the format used for the wiki pages is ... somewhat dated. It's not bad or anything, but in 2026 using anything other than Markdown just feels pointlessly contrarian4. There does exist a plugin that lets you write in Markdown, but it only lets you create Markdown sections of pages that otherwise use the standard formatting. There's no way to use Markdown as the default formatter for wiki pages, issues, and comments. At least, there wasn't until I wrote my own plugin to do it based on the existing plugin.

The third problem is maybe the weirdest: the default setup has no way to create user accounts! It delegates login completely to Apache. In order to add a user, the admin has to SSH into the machine and edit an htpasswd file in a text editor. Needless to say, if you're using this for any kind of community project, (or if you don't use Apache) this is borderline useless. There are some plugins that add workable authentication systems, but all the existing ones either require all users to sign up for (you guessed it) Yet Another Account or require you to tie your logins to a huge company like Google or Github. Neither of those paths were acceptable to me.

When I set this up, I had just recently been working on Fedibot club, an unrelated project. For that, I had implemented a Fediverse-based OAuth system that allows users to specify their server where they already have an account, and use that existing account5 to log in. Rather than having a fixed set of servers that you're allowed to authenticate with, it dynamically registers an OAuth client for any new server it's never seen before6. So I took this exact flow and ported it to Trac. Despite somehow not really ever having written any Python before in my life, I found it surprisingly easy to implement, using an existing hard-coded OAuth plugin as a guide. It clocks in at 124 lines of code.

When I'm trying out a new system, sometimes I run into some issues and think, "OK, I can put some elbow grease into this and get something working" but I usually expect it'll be a little slipshod and require putting up with things getting janky or ongoing tweaks. I encountered a twofold surprise here: one being simply that the fixes were so easy for me to make as someone who knows nothing about either Trac or Python, and the second being that once those few fixes landed, that pretty much took care of everything, and the remaining things worked basically flawlessly. It's a little disappointing that these things couldn't be addressed upstream in the project, but hey, I'll take the win.

Anyway, whether you end up using Trac or not, I hope you can find something that works for your project. Good luck!


[1] I've seen a lot of my friends stand up their own little Forgejo servers, and I love this. However, I believe there's a big missed opportunity here too. If you don't have an account on Alex's Random Forgejo, you can use OAuth to log in with an account on another server, which is great.

However, users are limited just to servers where the site's admins have manually registered OAuth clients! Alex might allow users to log in using their Github account, and Alex might allow users to log in using their Codeberg account, but it's very unlikely Alex's Random Forgejo will allow users to log in with their account on Mel's Random Forgejo, so there is still some centralizing gravity at play. Fortunately this is very easy to fix! My implementation of OAuth login using dynamic client registration clocks in at around a hundred lines of code. If it weren't for Forgejo being implemented in Golang, I'd be inclined to give a shot at implementing it. Perhaps some enterprising reader would be up for it!

[2] But not Sourcehut! And I do like Sourcehut overall; they have the best CI of any system I've used, and page load times are unparalleled. Its email-based contribution flow can be kind of awkward, but I have to applaud them for trying something different..

[3] I run my Trac instance on my home server, which is a Core 2 Duo Thinkpad from 2010. Trac uses about 160MB of RAM, and loads pages in consistently less than 200 milliseconds; dramatically faster than Github. (Your experience might be slower than this due to more network hops, but outside extreme cases it should still be a good deal better than Github.) When I first got it set up, it felt slow due to an attack of scraper bots from LLM companies, but once I installed Iocaine that took care of it.

[4] Don't get me wrong; I'm not saying Markdown is good. It's a lot like English: I'm not using it because it's good; I'm using it because it's both tolerable and ubiquitous.

[5] As a grudging compromise, I've installed a Github OAuth plugin for users who don't have a Fediverse account, but like ... come on, people.

[6] If you're interested in reading more about how this works, I've got a fairly thorough write-up that should be useful to anyone hoping to build a similar system. It's easier than it sounds! I'd love to see more people using this strategy to break away from corporate monopolies.

« older | 2026-04-25T17:08:11Z