Nati: wrapper-centric, HM-free desktop theme manager for NixOS

Hey everyone!

I’ve always cared about making my dotfiles user-friendly for newcomers, which meant multi-theme support was an absolute non-negotiable for me.

for the longest time, I used Home Manager like most people. That’s actually how my previous project, Juna (HM theming engine built around “polite guest” philosophy) was born, but over time, I started to notice more and more people migrating away from Home Manager in favor of NixOS binary wrappers (symlinkJoin + makeWrapper). Once you see the appeal of wrappers, it’s hard to go back, as Home Manager can feel like a messy abstraction over nix that hides lot of the underlying system from you.

I wanted to make jump away from Home Manager for months, but there was one massive blocker: nobody solved theming for wrapper-centric setups.

At first, I tried extending Juna to support wrappers, but it quickly became an ugly, overly complex hack. It just felt fundamentally wrong, so I scrapped that idea.

A couple of weeks ago, a new idea clicked. I decided to start fresh with a clean slate: a dedicated project to solve wrapper theming for good. I wrote a small, fast CLI in Zig to handle atomic symlinking and GTK/Dconf theme switching, and then began migrating my personal NixOS config from Home Manager to wrappers, one app at a time.

Every time I hit a new edge case during migration, I built a solution for it right inside my dotfiles. My config grew huge, but as I refined the patterns, I reached a point where everything clicked and I thought “Yeah, this is ready”. I extracted it out of my dotfiles, and Nati was born as standalon, third-party flake.

If you want to read about how Nati maintains Nix purity, checkout the full manifest spec, installation guide, and usage examples in the docs:

documentation: https://nati.gurjaka.dev

repository: https://codeberg.org/gurjaka/nati

1 Like

Have you seen hjem?, it provides atomic symlinking functionality and has existing nixos modules.

Yes, I have seen Hjem, but it serves different purpose. Nati was purely built for theming.

Yea yea, hjem is just general purpose, it could have helped with the symlinking is what I was thinking.

Yeah, that was also an option, but I don’t want to have unnecessary dependencies in my projects, especially when symlinking really is a simple syscall to linux. I had to write the cli tool even if I used something else for symlinking, so just implementing 2-3 new functions for atomic symlinking wasn’t really much of a work.

1 Like