RSSAmplifier

Blog

Simon Shine

Recent content on Simon Shine

simonshine.dkRSS feed ↗59 posts

Latest posts

Git config-based hooks with hk-nix

hk is a fast, modern git hook manager and project linter configured in Pkl . hk-nix is to hk what lefthook-nix is to lefthook: you install hk with Nixpkgs, declare your hooks in Nix, pin every tool with Nix, and the hooks install themselves whenever you enter the devshell . It is the same stack I previously built with lefthook , with a nicer configuration language and one fewer workaround.…

Using sops-nix templates to support passwords in legacy configs

Note: This article builds on my dendritic sops-nix flake template . Nix is littered with alternative solutions to things. Most people who use Nix to manage their irssi configuration would use the home-manager irssi extensions . But I have a principle that I’ve held onto: I like to keep program configuration non-nixified so that they can still hypothetically be used outside of Nix. The…

Authenticating Tailscale non-interactively via API with sops-nix

For the past three years I’ve connected my Nix machines using Tailscale by running sudo tailscale login once per machine. I’ve known that you can actually log onto a Tailnet with an API key . Why bother? Running sudo tailscale login takes ten seconds, your browser’s password manager kicks in, you’re done. This is actually simple and ships almost out of the box, if you…

A dendritic sops-nix flake template

This tutorial sets up a flake using flake-parts, import-tree, devshell and sops-nix. You can see the template here: https://github.com/sshine/nix-sops-flake-template Unlike agenix/ragenix, the sops-nix NixOS module does not require importing a Nix file describing recipients, so it composes cleanly inside flake-parts modules without triggering IFDs . 1. A dendritic flake ¶ This flake…

Dendritic flake partitions

tl;dr ¶ Some of my sandboxed CLI agents aren’t in nixpkgs, so they ride along as flake inputs. They’re heavy, and were polluting the flake.lock of every machine that consumes the flake. flake-parts partitions move those inputs into a nested flake that’s only evaluated when you actually build the thing. Because my flake is dendritic ( import-tree ), I tuck that nested flake…

Managing Secrets privately with sops-nix

tl;dr ¶ I want to commit my secrets encrypted to git with sops-nix I want to publish my infra-as-code, but don’t want to publish my git secrets So I put my secrets in a private git+file flake input Motivation ¶ I run Kubernetes clusters managed declaratively with Talos Linux and kubenix . I want to publish the entire repository that defines the cluster. It includes commands that…

Is the novelty budget dead?

Michael Snoyman wrote a thinkpiece called The Boring Haskell Manifesto (2019) about how to adopt Haskell into your organization, and how to make your organization productive with Haskell for non-wizards. The article introduced me to the concept of a “ novelty budget ” (Mark Wotton, 2018): the limit your project has on new, cool stuff. If you exceed your novelty budget you impose too…

NixOS runners on Forgejo Actions

Note: You can see the project in action here: https://git.shine.town/infra/runners I decided to bootstrap a Kubernetes cluster with Talos and kubenix during my vacation. A lot of experience came out of that, and I’m trying to unpack it gradually. One of the things I host on this cluster is Forgejo , which is Codeberg ’s fork of Gitea. Forgejo has Forgejo Actions which is a CI system…

Three levels of Nix

When using Nix to orchestrate a new project, I find myself choosing between these three levels: 1. Just a shell.nix ¶ This is good for starting on, it’s easy to sell to colleagues or project owners you’re not close with or already bought on the idea of Nix. It leaves a very small footprint in terms of lines of code: Every lines in this file is worth its own weight, since it…

Vendored theme workflow after one month

It’s exactly one month since I wrote: Vendoring Hugo themes with Nix and Git calendar Feb 7, 2026 I read an interesting article, The Rust Calling Convention We Deserve by Miguel Young de la Sota, and I couldn’t help but think that the website was really nicely made: Inspirational use of CSS3, a personal font choice, and proper underlines under hyperlinks.

Using lefthook and treefmt with Nix

In my recent attempts to modernize my CI pipelines, I’ve experimented with and subsequently let go of pre-commit . The reason why I didn’t stick with pre-commit is that pre-commit drags in several software runtimes and toolchains when building it from scratch. When Nix fails to build something from nixpkgs, it’s an omen of too many chefs . Alternatives I’m aware of:…

Dendritic Nix With nixos-shell

tl;dr ¶ I’m refactoring my system flake using The Dendritic Pattern I’m testing the system flake using nixos-shell I’ll completely wipe my laptop’s NixOS installation when ready Table of contents ¶ Motivation (some ranting) What is a dendritic flake? What is nixos-shell? The bootstrap Motivation (some ranting) ¶ Last week I experimented with nixos-anywhere ,…

Learning about AutoAgents by benchmarking Claude Code vs. OpenCode

tl;dr ¶ I’m extending AutoAgents so that it supports Z.ai , a frontier AI company Z.ai’s GLM-5 model might or might not compete with Claude Opus 4.5 at a very competitive price. I’m testing both the OpenCode CLI vs. Claude Code CLI, and Z.ai’s GLM-5 against Claude Opus 4.5. Claude is considerably faster, but neglects testing. OpenCode’s tests were not end-to-end.…

nixos-anywhere on Hetzner

tl;dr: ¶ I installed NixOS using nixos-anywhere for the first time. Along the way I also finally tried (and succeeded) to use disko and deploy-rs . Deploying from MacBook’s aarch64-darwin to the VM’s x86-64 required a few tweaks. Tonight I wanted to try and run OpenClaw. I thought I would give it a persistent VM and that it should run NixOS, of course. I already run several NixOS…

Vaultwarden on NixOS

This post is about self-hosting Vaultwarden , an unofficial Bitwarden server, so that you can have self-hosted password management. Bitwarden clients on computers and phones can be configured to use a custom server. I found a few blog posts that deserve some credit; sadly, none of them provide the simplest possible configuration, or every piece of information I needed. Vaultwarden NixOS -…

A git primer for future colleagues

You become a git expert when you learn about git reflog . Not because it’s an advanced feature. But because it gives you the confidence that whatever command you run can be reverted. Once you can undo any git command, your willingness to experiment increases significantly, and you become the export. Besides that, git reflog is not the most useful command, since it’s mostly for when you…

Vendoring Hugo themes with Nix and Git

tl;dr: ¶ I forked the git repo for my Hugo theme and pushed my feature to a branch I refactored the blog repo’s Nix code to be multi-file and flake-based I switched my Nix-vendored theme to use this git repo/branch I made it possible to use the git repo checked out locally for rapid prototyping I retained the possibility to use the Nix-vendored theme (same branch, but committed and…

Speeding up CI more with Nix

Recently I wrote Speeding up CI with Nix . I improved a 2m30s build to 1m30s after it had recently deteriorated to 10m30s. I have another repository that would benefit from Nix. Not because of speedups, but because it fails to install Chinese fonts properly. My Typst résumé’s CI failed to render Chinese fonts for the longest time; for that reason, I never actually made use of the PDFs that I…

Speeding up CI with Nix

In the article Maintaining libraries with Claude I update the CI pipeline to release the package automatically on Hackage and GitHub when pushing a version tag. I added a git hook, check-cabal-sync.sh , that checks the version in package.yaml against the version in evm-opcodes.cabal, as well as the version in the git tag, to ensure I ran hpack before releasing; otherwise Hackage upload will fail.…

zsh config for NixOS + nix-darwin

tl;dr: ¶ I’m taking Nix more seriously on my MacBook I want to share my zsh config across all systems Because my zsh config was NixOS-only, I’ve had to refactor it Why ¶ I’ve been running NixOS for 3 years now. During this whole time I’ve also owned a MacBook. And while I started installing Nix on my MacBook, I didn’t really appreciate it until installing…

Maintaining libraries with Claude

tl;dr ¶ Claude bumps the versions. Claude finds missing opcodes. Claude finds even more missing opcodes I didn’t know about. Claude correctly handles compiler warnings that indicate cascading changes. Claude correctly handles what files are auto-generated and how to regenerate them. Stretch Goal #1: Release via CI to Hackage and GitHub Stretch Goal #2: Validate hpack pre-push The goal…

Using NixOS for Exam Computers

I used NixOS to define two exam computers for a programming exam. One in a presentation room with an examiner and a censor, connected to a projector. Another one in an adjacent preparation room, just connected to the internet. Both computers had the same software development environments, and a system user for each student. The presentation computer was connected to a projector with screen…

Kubernetes-valgfaget der ikke blev til noget

Planen var at stoppe som underviser på fuldtid og have et enkelt valgfag som timelærer. Valgfaget blev desværre aflyst efter det var blevet godkendt og var blevet valgt af de studerende, for at spare på eksterne timer. Det var lidt ærgerligt, da jeg havde været transparent omkring planen af hensyn til at give god tid til at finde min afløser. Titlen skulle have været “Cloud Native…

End of teaching retrospective

I quit my teacher job. Unlike most of my teaching blog posts, this entry is not in Danish. I want to write a retrospective blog post about having been a CS teacher for two years, having been on paternity leave, and picking up consulting again, but via an agency instead of freelance, which I had done in the years prior, and not primarily focusing on embedded Rust. I switched the consulting agency…

Funktionel datamodellering

I Om at blive rekursivt beruset med monoider modellerer jeg superdrinks som en monoid og viser hvordan man kan programmere med dem ved hjælp af simple algebraiske datatyper. Og i Design Patterns i popkultur fandt jeg et eksempel på et design pattern: PPAP kan modelleres som et frit magma : en algebraisk struktur lukket under komposition, men uden kommutativitet, idempotens, eller…

Animating the NixOS logo

I really like NixOS. I also like to draw the NixOS logo. While there are SVGs and PNGs at github:nixos/branding , the logo is very geometric and should be easily expressed as a program. My first attempt with turtle graphics was an experiment to work with HTML Canvas via Wasm. It works by instructing a small robot turtle, Bob, to walk and paint in the shape of a λ; you then repeat that six times:

Design Patterns i popkultur

Jeg har, som mange andre, været grebet af sangen PPAP: Jeg har ikke kunnet lade sangen slippe, fordi PIKOTARO tydeligvis formidler abstrakt algebra: Studiet af algebraiske strukturer, hvor man betragter sammensætningen af matematiske objekter, der ikke nødvendigvis er tal. Abstrakt algebra finder bred anvendelse i programmering. Vi kalder det et designmønster , fordi det er et abstrakt mønster som…

JSON Schema in Haskell using AutoDoCodec

In April 2022 I made a review of Haskell libraries for JSON Schema . The outcome of my research was that there weren’t really any good libraries for dealing with JSON Schema from within Haskell. That was a surprising disappointment, because Haskell often has very good libraries (although they may be hard to use). The reason is that the JSON Schema specification itself isn’t very…

Just: En bedre Makefile

Har du nogensinde arbejdet på et softwareprojekt og set en fil kaldet Makefile ? Makefiles bruges traditionelt til at automatisere kompileringsprocesser, men mange udviklere bruger dem også til at køre almindelige projektkommandoer som: make test make deploy make start Men der findes et bedre alternativ: Justfile Problemet med Makefiles til projektkommandoer ¶ Makefiles blev oprindeligt…

Claude Code og git-bug: Når AI har brug for issue tracking

Jeg prøvede for nyligt at kombinere Claude Code med issue tracking. Som udvikler er det en udfordring at holde styr på bugs, opgaver og ideer i sine projekter. Vi mennesker bruger grafiske issue tracking-værktøjer som Jira og GitHub Projects. Personligt har jeg været glad for Linear.app , som er gratis op til 250 tickets. Claude Code har sit eget ad-hoc to-do-system, men den er sessionsbundet, og…

Hvordan understøtter man europæisk cloud i undervisningen?

tl;dr (den ultra korte version): ¶ I de tekniske fag på Erhvervsakademi København kunne man… afskaffe brugen af Azure Web Apps, Azure Managed MySQL på 2. semester introducere Docker Compose og Linux på 2. semester i stedet driftssætte via Docker Compose på Linux på en VPS på 3. semester En opsummering af artiklen nedenfor: ¶ Ved at undervise i cloud-agnostisk teknologi som ikke…

Hvorfor blev jeg datamatiker-lærer?

Artiklen her er introen til min daværende blog, datamatik.blog, som jeg drev i 2025 mens jeg var datamatiker-lærer på KEA, Københavns Erhvervsakademi. Jeg tror måske jeg følte, jeg skulle forsvare at gå ned i løn og undervise på en kort videregående uddannelse. Hej, jeg hedder Simon Shine, og jeg er en programmør født i 1985. Jeg er også datamatiker-lærer på Erhvervsakademi København , fusionen…

Om at blive rekursivt beruset med monoider

Disclaimer: Jeg er ikke mixolog. Dette er ikke professionel cocktailrådgivning! Lyt i stedet: Podcast-afsnittet Haskell Weekly, Episode 26: Recursive Monoids . Jeg læste engang, at man kunne modellere cocktails som monoider . Det er et virkelig cool eksempel på funktionsorienteret modellering, som jeg gerne vil uddybe. Først vil jeg demonstrere min uvidenhed og antage, at cocktailopskrifter er…

Deploying a Rust web service on NixOS

I have a small Rust web service that serves HTTP on a port. In order to run this in production, I want to compile and install the web service binary on my server, run it as a non-interactive user on a local port, and expose the web service via an nginx reverse proxy I will use a subdirectory of an already existing website, such as a Hugo static website . A web service package derivation ¶ In…

Corne Split Keyboard Layout

I min barsel har jeg leget med et Corne v3 split keyboard, som jeg har købt på Taobao. Det har 46 taster. Til sammenligning har min MacBook Pro med dansk layout 79 taster. De knapper man mister vs. de knapper man får ¶ Man fristes til at fokusere på alle de knapper, man mister, frem for alle de knapper man får. Især får man noget som alle tastaturer burde have: Ekstra knapper til…

Packaging open-source projects with Nix

Introduction ¶ Problem: You run NixOS and want to download, compile and run some project on GitHub. While most projects come with a README that tell you what packages to apt-get install if you run Ubuntu, they often don’t explain how to do the same on NixOS. This makes NixOS a harder Linux distro to use, because you need to be able to write Nix to run certain programs.

Hvad er "datamatik"?

datamatik , sb. (læren om) hensigtsmæssig behandling af data på edb-systemer [1966] I dette første blogindlæg vil jeg sætte spørgsmålstegn ved bloggens navn. Ordet “datamat” er en anakronisme: Opfundet i 1960’erne, da referencer til computere blev almindelige, og dansk populærkultur endnu ikke var opslugt af amerikansk engelsk. Det hedder “computer” nu, med mindre man…

Setting up a Hugo static website with Nix

tl;dr ¶ See the tutorial code at https://github.com/nix-tools/nix-hugo This tutorial… Provides a development environment for running interactively Provides a derivation for deployment on NixOS Deploys to a webserver using just , ssh and scp Step 0: Prerequisites ¶ You have Nix installed (required) You have flakes enabled (required) You have nix-direnv enabled (recommended) Step 1: A…

Minimal Sufficient Groups

This is a programming interview question I got some years ago. The problem ¶ When a certain company creates a new project, they enumerate the skills required for the project, and they form a project group where each of those skills are represented. Project groups have two rules: Sufficient: Each required skill should be represented with at least one group member. Minimal: Each group member…

Why you should be careful with the Default trait/typeclass

You heard it. Default considered harmful! tl;dr: Default has no defining or testable properties Default is not even guaranteed to be the same between runs Defaults are context-specific: One type does not always have one default Defaults are useful for transitive derivation, but context drift risks causing errors Your Default instance is dangerous if you cannot carelessly replace it with any other…

A review of JSON Schema libraries for Haskell

Update 2025-07-26: This review is obsolete. Consider using AutoDoCodec . JSON Schema is a JSON format that describes JSON formats. It is mostly used to validate that a JSON value has the correct format, but it can also be used to generate random values that fit a schema definition. This may be useful for testing. The latest version of JSON Schema is called “Draft 2020-12”, and the way…

Has-style traits in Rust

I recently experimented with Rust trait instances on bounded generic types . This is the fancy way of saying impl<T: SomeTrait> AnotherTrait for T , i.e. any number of AnotherTrait instances created as a result of the presence of a SomeTrait instance. Here is a similar but slightly more complicated example of that. I have a number of things that all have a common base set of properties. I&rsquo;d…

Writing code on doors

Did you ever see pseudo-code in job ads that looked like if ( $you .like_to_work( $here ) === True) { $job .apply(); } and thought to yourself a bunch of things about variables not being in scope, and whether their actual code has utterly specific library functions? Did you ever try to design an authentic piece of pseudo-code and found how difficult it is to remain concise enough to get the point…

A Terraform DNS moment

tl;dr: I stuck the IPv4 and IPv6 address of my VPS into an SPF record field text. I manage my DNS with Terraform. This means that past domain registration and changing nameservers, I manage DNS with the Terraform command-line interface and git. Today I experienced a moment of happiness when two pieces of personal infrastructure fitted. The scenario: I&rsquo;m setting up a send-only email server on…

Fiat Currencies Are Not One Thing

When we discuss the potential future usefulness of cryptocurrency, we compare against existing use-cases of fiat currency. Given a particular fiat currency &ndash; its name, its unit, and its exchange rate &ndash; our language enforces us to think of it as one currency. This is a misconception that will lead to poorly designed alternatives with strong, but unaligned monetary properties at the…

Jq Hack 2 Curling the Right Binary on Github

Something I see quite often is a combination of grep and cut to extract URLs from JSON objects, for example: $ curl -s https://api.github.com/repos/go-gitea/gitea/releases/latest \ | grep browser_download_url \ | cut -d '"' -f 4 \ | grep '\linux-amd64$' \ | wget -i - This is neat because grep and cut are almost always available on Linux. And the approach works for all kinds of plaintext documents…

Why rewriting version control history matters

Life is understood backwards, but must be lived forwards. &mdash; Søren Kierkegaard A summary on good commit messages &para; Because version control systems, like git and GitHub, are at the heart of modern software development workflows, most workflows are heavily impacted by and defined in terms of how to operate and cooperate around version control. Making use of issue trackers, pull requests,…

Efficient Probability Testing

I want share two open-source contributions that were lost on their original audience, yet has taught me something about testing functions that use randomness. I once had a task at work where a website displayed a banner ad from a selection of banner ads with some internal logic related to categories, weights and fallback banners. Since the result was random, how do you test the selection…

Baking metaphors in the imperative/declarative programming debate

tl;dr: Cake recipes contain both declarative and imperative parts. Declarative syntax is better for describing the problem domain. Each programming paradigm has its place in software architecture. Baking metaphors &para; An argument is floating around that imperative programming is easier, more natural for humans for the same reason that baking recipes are imperative. Here is a pie recipe for…

Extracting the KUBECONFIG for a DigitalOcean Kubernetes cluster from a Terraform .tfstate

When provisioning a Kubernetes cluster from DigitalOcean with Terraform, the .tfstate contains a field called raw_config that authenticates kubectl . It can elegantly be extracted with jq : $ jq -r '.resources[] | select(.type == "digitalocean_kubernetes_cluster") | .instances[].attributes.kube_config[].raw_config' \ terraform.tfstate apiVersion : v1 kind : Config clusters : - cluster :…