#nix

Musik im Terminal: cava, roon-tui und ncmpcpp — deklarativ, monochrom, vim-navigiert

Drei Musik-Tools, ein Flake: cava visualisiert den Sound in einem 8-stufigen Orange-Gradienten mit gepatchten ▄-Blöcken, roon-tui steuert den Roon Core mit vim-Keybindings und einem monochromen Theme, und ncmpcpp ist der MPD-Fallback mit derselben Navigation. Dazu ein Overlay, das roon-tuis hartkodierte Farben und Keybindings per sed/substituteInPlace umschreibt, ein RoonBridge- und squeezelite-Setup, das sowohl bit-perfektes ALSA als auch PipeWire für cava bedient, und ein Musik-Profil, das zur Build-Zeit zwischen Roon und MPD wählt. Alles in einer tmux-Session, die cava im oberen Split und den Player darunter startet.

Musik auf der Workstation ist für mich kein Nebenbei — sie läuft den ganzen Tag, und das Setup soll sich so anfühlen wie der Rest des Desktops: deklarativ, monochrom mit orangen Akzenten, vim-navigiert. Drei Tools teilen sich die Bühne: cava visualisiert den Sound, roon-tui steuert den Roon Core, und ncmpcpp ist der MPD-Fallback, wenn Roon nicht läuft. Alle drei leben in fr0st , alle drei sind per Overlay auf dasselbe Theme und dieselben Keybindings gepatcht, und alle drei starten in einer tmux-Session , die cava im oberen Split und den Player darunter aufbaut.

cava (oben, ▄-Blöcke im Orange-Gradient) und roon-tui (unten, monochrom mit orangen Akzenten und ▮-Progressbar) in einer tmux-Session auf Workspace 9.

Ein Tastendruck, ein fertiger Workspace — tmux, sesh und ein Hyprland-Prompt

tmux gibt mir persistente Sessions, sesh macht sie zu einem deklarativen Session-Manager — und ein Hyprland-Keybind öffnet sie per rofi. Vordefinierte Projekt-Layouts in Nix, ein Window-Pool-Trick, der wiederholte Fensternamen erlaubt, eine Wildcard-Vorlage für jeden Projektordner, und SUPER+s als Tür ins Ganze. Wie aus „erst mal die Panes aufbauen" ein einziger Tastendruck wurde.

Jedes Projekt, das ich anfasse, will dieselbe Bühne: mehrere Shell Fenster, vielleicht ein AI-Agent, daneben Git und Datei-Browser, vielleicht noch eine Live-Preview. Das von Hand aufzubauen — tmux new, splitten, cd, Tools starten — dauert jedes Mal eine Minute, die ich nicht habe. Also habe ich es in fr0st deklariert: tmux für die persistente Bühne, sesh als Session-Manager darüber, und einen Hyprland-Keybind, der das Ganze per rofi aufruft. Ein Tastendruck, ein fertiger Workspace.

choom: Terminal-Sharing à la tmate, aber schlank — und auf dem Weg zu E2E

tmate ist genial und gefährlich zugleich: ein voller tmux-Fork in ~50k Zeilen C, der auf dem Relay als root läuft. Vor einer Weile habe ich eine schlanke Python-Reimplementierung gebaut, die nur den Sharing-Kern behält. Jetzt habe ich sie nach Rust portiert — eine einzige statische ~4-MB-Binary, unprivilegiertes SSH-Relay, kompromisslos auf Sicherheit getrimmt. Was choom kann, wie man meinen öffentlichen Server choom.sh nutzt, warum „trust the operator" bauartbedingt gilt — und wie ein E2E-Client das aufbricht.

Es gibt diesen einen Moment beim Remote-Support, den jeder kennt: Jemand sitzt vor einem kaputten Terminal, beschreibt am Telefon umständlich, was auf dem Schirm steht, und tippt dann doch wieder das Falsche. Was ich in dem Moment will, ist keine 478-MB-Electron-Bildschirm-Sharing-Software — ich will sein Terminal sehen, am besten mitschreiben können, und zwar in dem Augenblick, in dem es brennt. Genau dafür gibt es tmate . tmate ist großartig. tmate ist aber auch ein Stück Software, dem ich nicht mehr blind vertrauen wollte. Dieser Beitrag erzählt, warum ich mir stattdessen mein eigenes Werkzeug gebaut habe — choom1 —, was es kann, wie man es benutzt, und wo die Grenze liegt.

fr0st — mein NixOS-Flake von der Wurzel bis zum Wallpaper

Sechs Maschinen, zwei Betriebssysteme, ein Repository: fr0st ist mein persönliches flake-parts-Flake, das ThinkPads, einen Desktop, ein MacBook und VMs aus derselben Quelle deklariert. Eine ausführliche Tour durch die Architektur — die lib.system-Fabrik, die rekursive Modul-Discovery mit eigenem Options-Namespace, die Profile-Komposition, das Single-User-Identitätsmodell, Secure Boot via Lanzaboote, verschlüsselte Roots via disko, Remote-Installs mit nixos-anywhere, das SOPS-Schlüsselregister, eigene Pakete und Overlays, und am Ende der Desktop, den das alles ergibt.

Mein Lab ist ein GitOps-Monorepo, aus dem Flux Kubernetes-Cluster reconciled. Aber die Maschinen, von denen aus ich auf dieses Lab schaue — die ThinkPads, der Desktop, das MacBook, ein paar VMs —, haben ihre eigene deklarative Wurzel. Sie heißt fr0st, ist ein flake-parts -Flake, und dieser Beitrag nimmt sie von der Wurzel bis zum Wallpaper auseinander.

Frost auf dem Asphalt, der graue Himmel vor dir

Das Repo ist öffentlich über meinen Radicle -Seed-Node erreichbar:

1# klassisch:
2git clone https://seed.this-is-fine.io/zVi9VheaDwbEgCUQUQ9sLwpHuaMo.git ~/.config/nix
3# oder via Radicle:
4rad clone rad:zVi9VheaDwbEgCUQUQ9sLwpHuaMo

Stöbern lässt es sich im Web unter radicle.network/nodes/seed.this-is-fine.io .

Mein WeeChat-Setup: Deklarativ mit Nix, eingeklinkt am Bouncer

Wie ich meinen IRC-Client WeeChat reproduzierbar über ein Nix-Home-Manager-Modul ausrolle und mich darüber in einem Rutsch über meinen Bouncer in alle IRC-Netze klinke

Mal etwas, das nichts mit dem Lab zu tun hat: mein IRC-Client. Ich nutze seit Jahren WeeChat , und wie bei fast allem auf meinen Maschinen gilt auch hier — nichts wird von Hand zusammengeklickt, alles ist reproduzierbar. WeeChat samt Konfiguration kommt deshalb aus einem Home-Manager -Modul und verbindet sich ausschließlich mit meinem Bouncer.

WeeChat als Nix-Modul#

Der Client soll auf jeder meiner Maschinen identisch dastehen — gleiche Plugins, gleiche Skripte, gleiche Tastenbelegung. Genau dafür ist Nix gemacht. Mein Modul baut WeeChat über pkgs.weechat.override mit exakt den Bausteinen, die ich brauche, und nicht mehr:

1weechat = pkgs.weechat.override {
2  configure = { availablePlugins, ... }: {
3    plugins = [ (availablePlugins.python.withPackages (_ps: [ ])) ];
4    scripts = with pkgs.weechatScripts; [ autosort weechat-grep ];
5  };
6};

Das Python-Plugin und die beiden Skripte — autosort zum automatischen Einsortieren der Buffer und weechat-grep zum Durchsuchen der Logs — sind damit Teil des Build-Outputs, nicht etwas, das ich nach der Installation noch nachziehen müsste.