What Makes Sourcehut CI So Good

I’m not in any way an expert in CI systems, I’ve only used four such systems in my whole career: Jenkins, Gitlab CI, Sourcehut Builds and recently also Github Actions. I’ve been praising Sourcehut Builds to my coworkers for a long time but I always assumed that it’s not that special, just that I had a bad experience with Gitlab CI and Jenkins. That is, until I tried Github Actions and started to appreciate Sourcehut Builds even more.

What's Sourcehut

Sourcehut is a free (as in freedom) software forge that resemble the working methods in large FOSS projects like the Linux kernel and PostgreSQL. Sourcehut is different from most other software forges by supporting stuff like mailing lists instead of the now abundant workflow of GitHub PRs.

Each CI system has its own pros and cons. The actions system in Github Actions let me reuse other people’s scripts with just two lines of YAML. I also really enjoy the ability to use any Docker image in Gitlab CI which let me use the distribution I want without requiring a change from the runner. But I think there are some things that every CI system should have that I really can’t understand how people lives without, which make me come back to Sourcehut every time.

Submitting YAML files manually

Many times I commit some YAML file for the CI system just to fix some minor error. Sometimes I just want to tinker a bit with the CI before I know how it should really looks like. In those cases I have two options:

Well, not with Sourcehut. Sourcehut lets you submit a YAML file straight from the web interface, and even resubmit an existing YAML file with some modifications. This feature is not a game changer but it is a lot nicer playing with the CI like that, a slightly smaller context switch each time.

A YAML file is not tied to a single repository

Some of you might have wondered how exactly can you submit a YAML straight to the CI system. After all, in most systems, the YAML file is supposed to belong to a repo in order to run. In Sourcehut, of course, you can still have, and probably should have, the YAML file in a repo. But a YAML file is not necessarily tied to any repo, it doesn’t even assume its in a repo. Every repository you want to use in your build, you need to specify explicitly in the sources section. There isn’t any implicit default repo that you are put inside or anything like that, you will always be in your user home directory with all of the repos under it. You might not see a use for it now, but in Frida for example, the main repo is just a collection of submodules. This makes it a great fit for Frida for example, as it’s already what is being done but without the support of the CI.

Investigating failures with an SSH connection

This is I think the killer feature of Sourcehut Builds. The ability to debug CI failures without rerunning it or by trying to mimic it locally saves me so much time and frustration. After every failed run, you have 10 minutes to log into your CI machine, if you do, you will have a total of 4 hours to run whatever you want and investigate what happens on the actual machine of the CI system.

No magic involved

Not exactly a feature but maybe even more important than an SSH connection, is that there is no magic involved. The image I get is simply a clean image of the distribution I choose with the packages2 I choose and nothing else. It runs in a VM and not in an OCI container, which reduces some weirdness with application containers. It also lets me more easily reproduce and debug3 the environment locally, which is also a big win if I ever need it.


Sourcehut Builds is not perfect, and there are different valid approaches to CI but I think Sourcehut can teach the old, existing CI systems a thing or two about about user experience.

  1. Depending on the operating system you want of course, it will not always be possible. ↩︎

  2. Instead of magic scripts like setup-python (in GitHub Actions) ↩︎

  3. Docker containers might be easier to set up but very often they can leak information from the host like uids. It is also harder to investigate when almost all of the container images are minimized to contain the bare minimum, do we really not have a few bytes to spare to get a proper shell in there? ↩︎