Skip to content

Your GitHub Actions Workflow is a Waste of Time

Once

Over the years, I’ve experimented with almost every flavor of development environment. I’ve gone from manually provisioning tools on a Mac—hoping I’d remember every brew install six months later—to exploring Docker, Nix, and remote environments.

My journey has touched it all: asdf, Brew, Docker, Nix, and Devbox. I’ve jumped between terminal emulators and multiplexers like Tmux, Kitty, WezTerm, and Zellij.

My latest setup is built for speed, reproducibility, and a “keyboard-first” philosophy. It lives entirely in the terminal across two environments: my local iMac and an OCI Ampere VPS.

  • Terminal: Ghostty
  • Multiplexer: Zellij
  • Environment Management: Devenv
  • Editor: Doom Emacs

Achieving CI Parity with Self-Hosted Runners

Section titled “Achieving CI Parity with Self-Hosted Runners”

If you haven’t switched to a self-hosted GitHub runner yet, do it for your own sanity. You can thank me later.

By running your CI on your own hardware (like an OCI Ampere instance), you eliminate the overhead of public runners and gain full control over the environment. When paired with Devenv, your CI environment becomes an exact mirror of your local machine.

  1. Navigate to your GitHub repository Settings.
  2. Go to Actions -> Runners.
  3. Click New self-hosted runner and follow the configuration steps for your OS.
  4. Update your workflow .yml file to use the self-hosted label.

By moving to a self-hosted ARM64 runner, my feedback loop became incredibly tight. My tests now finish in 24 seconds, and the entire image creation process takes just 1 minute and 22 seconds.

Here is what the streamlined job looks like:

jobs:
test:
runs-on:
- self-hosted
- Linux
- ARM64
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Run tests
id: run_tests
run: devenv shell clojure -X:test

Because I’m using devenv shell, I don’t have to worry about whether the CI runner has Clojure, the right JDK, or specific libraries installed. If it works in my local terminal, it works in the CI. Period.

The way we use GitHub Actions today is often redundant. We spend an enormous amount of time writing complex YAML configurations to install dependencies, manage versions, and configure caching—essentially re-architecting our entire development environment for every single commit.

Provisioning and caching are solved problems. If you are using tools like Devenv or Nix, you’ve already defined exactly what your project needs to run. By moving to a self-hosted runner, you stop fighting the CI and start using it as a natural extension of your workstation. You gain:

  • Total Parity: If the code runs in your local devenv shell, it will run in CI. No exceptions.
  • Instant Caching: Since the runner is persistent, you don’t need to upload or download massive cache blobs; the dependencies are already there.
  • Minimal Configuration: Your workflow files shrink from dozens of lines of setup boilerplate to a single command.

It’s time to stop treating CI like a special snowflake and start treating it like the high-performance terminal it should be. Stop provisioning twice, stop waiting for public runners, and start shipping faster.

Would you like to have a follow-up on this topic? What are your thoughts? I’d love to hear your experiences.