Zed statt VS Code
Ich habe heute zum ersten Mal ernsthaft Zeit in die Konfiguration von Zed gesteckt. Bisher bin ich mit dem Editor nie warm geworden, jetzt gefällt er mir.
Ich habe heute zum ersten Mal ernsthaft Zeit in die Konfiguration von Zed gesteckt. Bisher bin ich mit dem Editor nie warm geworden, jetzt gefällt er mir.
Mein Server baut sich seit Teil 2 selbst aus Git und kennt seit Teil 3 seine Secrets. In diesem Teil geht es (endlich) darum, wie ich eine eigene Webseite ausliefere. Meine CI baut die Seite und lädt das Ergebnis per rsync hoch. Dafür bekommt sie einen eigenen SSH-Zugang mit Zugriff auf genau ein Verzeichnis.
Mein Server holt sich seine Konfiguration jetzt selbst aus Git. Als Nächstes sind die Passwörter und Tokens dran, die die meisten Dienste brauchen und die nicht im Klartext in ein Repo gehören. Mit sops-nix liegen sie verschlüsselt direkt neben der Konfiguration, und nur der Server und ich können sie lesen.
Heute Nacht hat sich mein Server plötzlich nicht mehr aktualisiert. Jede Stunde kam eine Notification mit dem Fehler No such file or directory. Der Pfad dahinter beginnt mit /nix/store/, und git fetch brach damit jedes Mal ab.
Schuld war ein Pfad in der /etc/nixos/.git/config. Beim ersten Klonen hat mein Service dort per git config core.sshCommand den Wert von ${pkgs.openssh}/bin/ssh eingetragen, also etwas wie /nix/store/98xy…-openssh-10.5p1/bin/ssh.
Nix legt jedes Paket in einem eigenen Verzeichnis unter /nix/store ab, mit einem Hash im Namen. Ein Update überschreibt nichts, die alte Version bleibt liegen, bis die Garbage Collection (nix-gc) aufräumt. Die löscht alles, worauf nichts mehr verweist: kein Systemstand, den Nix aufbewahrt, und kein anderes Paket. Dafür sieht Nix nur in die Dateien, die es selbst verwaltet. Die .git/config gehört nicht dazu, und mit einem Cronjob, einem Skript oder einer Dotfile wäre derselbe Fehler aufgetreten. Nach dem Update auf openssh 10.6p1 war die alte Version für Nix überflüssig, und um Mitternacht räumte die Garbage Collection auf.
Die Lösung: Ich setze GIT_SSH_COMMAND jetzt als environment am Service. Die Variable hat Vorrang vor core.sshCommand, und weil sie in der Systemkonfiguration steht, hält Nix das Paket am Leben:
systemd.services.nixos-auto-rebuild = {
environment.GIT_SSH_COMMAND =
"${pkgs.openssh}/bin/ssh -i /root/.ssh/infra-pull";
};Einem Nix-Profi wäre das vermutlich nicht passiert. Ich habe danach meine Nix-Konfiguration nochmal gewissenhaft nach ähnlichen Stellen durchgesehen. In der Serie hatte ich es übrigens schon richtig: Dort steht nur ssh, das über path aufgelöst wird.
Wenn ich auf meinem Server etwas ändern will, bearbeite ich eine Datei, committe und pushe. Spätestens eine Stunde später läuft die neue Konfiguration, ohne dass ich mich auf dem Server anmelde.
Meinen Server beschreibe ich komplett in einem Git-Repo, und er baut sich daraus selbst neu. Möglich macht das NixOS, und in dieser Reihe zeige ich, wie ich dahin gekommen bin. Den Anfang macht eine leere Hetzner-VM, die per nixos-anywhere zu NixOS wird.
Gestern habe ich im Homelab und auf meinem Server Uptime Kuma installiert. Das Tool prüft in festen Abständen, ob Webseiten und Dienste erreichbar sind, und meldet sich, wenn nicht.
Und was soll ich sagen, es tut genau das, was es soll, sieht gut aus und bringt jede Menge Integrationen mit: Sehr viele Messenger, diverse Push Services und weit mehr Anbieter, als mir bisher bekannt waren. Bei mir überwachen sich Homelab und Server gegenseitig. Auf dem Server schaut es zusätzlich nach miniflux und linkding, im Homelab vor allem nach Home Assistant.
Welche Art von Check ich nutze, hängt vom Dienst ab: Wo es einen Health-Endpoint gibt, frage ich den per HTTP ab. Sonst reicht ein TCP-Check auf den Port, und für reine Geräte ein simpler Ping.
Auch bei Ready for Review läuft es jetzt, zusammen mit einem selbst gehosteten ntfy-Server, der die Alarme als Push-Nachricht verschickt. So kriegen wir mit, wenn etwas down ist.
Klare Empfehlung.
Bei einem Codeblock im Artikel weiß man nie, ob der Code tatsächlich läuft. Für Web Components robust schreiben wollte ich vierzehn Beispiele, die man im Browser ausprobieren kann. Der Code im Text sollte genau der sein, der dort läuft.
Web Components tun an ein paar Stellen nicht das, was man erwartet. Der constructor sieht ein Attribut einmal als "Ada" und einmal als null. Eine Komponente bleibt leer, ohne dass die Seite einen Fehler zeigt. Ein padding am <slot> bewirkt nichts. Das sind keine Browser-Bugs, das ist so spezifiziert, und es gilt in jedem Browser.
Die Umfrage State of Devs 2026 beschreibt den Beruf gleich im ersten Satz des Überblicks so:
It is an uncertain time to be a developer.
Zwei Zahlen zeigen, was damit gemeint ist. Beim Thema KI liegen die Lager fast gleichauf: 49 % der Befragten sehen sie positiv, 42 % negativ. Fragt man aber, ob KI der eigenen psychischen Verfassung guttut, fällt das Urteil einseitiger aus: 46 % verneinen, nur 23 % bejahen.
Die Sorge um den Job hat ebenfalls Gründe. Ein Viertel der Befragten wurde schon einmal entlassen, knapp jeder Zehnte in den letzten neun Monaten, und mehr als ein Viertel rechnet damit, in den nächsten fünf Jahren den Beruf wechseln zu müssen.
Dass KI die Community spaltet, höre und merke ich seit Monaten. Genauso die Angst, dass Softwareentwicklung kein sicherer Beruf mehr ist. Neu ist nur, dass es jetzt in Zahlen dasteht.
Am Wochenende habe ich auf meinem Server Linkding installiert. Es macht genau eine Sache, Links verwalten, und die macht es gut.
Gestern kurz nach fünf, las ich eine Nachricht von einem guten Bekannten:
Hallo, könntest du bitte für Sophia abstimmen? Sie ist die Tochter von engen Freunden von mir, und dieser Sieg ist für ihre Familie sehr wichtig! Es geht um ein Stipendium für ihre Ausbildung. Vielen, vielen Dank im Voraus für deine Unterstützung! 🙏
Dazu ein Link, und ich hielt mich nicht an das, was ich selbst in der Familie oft genug gepredigt habe: Keine Links anklicken, egal von wem. Ich habe draufgetippt. Die Seite lud nicht. Was ich erst als Konfigurationsproblem abtat, geriet in Vergessenheit. So wichtig war mir die Wahl ja auch nicht.
Etwas später am Morgen kam dann seine Entschuldigung. Der Account meines Bekannten war "gehackt" worden, die Nachricht ging an seine ganze Kontaktliste. Also schaute ich mir die Nachricht nochmal an, und ja, viel offensichtlicher geht es nicht.
Was ich nicht zu sehen bekam, beschreibt Malwarebytes: Der Link führt nicht zu einer Abstimmung, sondern in WhatsApps eigene Funktion für verknüpfte Geräte. Man wird aufgefordert, einen Code einzugeben oder eine Verbindung zu bestätigen, und autorisiert damit ein fremdes Gerät auf dem eigenen Account. Ein Passwort wird nirgends abgefragt. Man richtet den Zugriff selbst ein.
Bei mir ist er nie so weit gekommen, und hier wollte ich dann doch wissen, wieso ich verschont wurde. Fündig wurde ich im Log von NextDNS: Blocked, Newly Registered Domain. Den Haken hatte ich vor Monaten gesetzt und seitdem nicht mehr angesehen. Er blockt jede Domain, die jünger als 30 Tage ist.
Genau von diesen jungen Domains lebt die Masche: eine frische Domain pro Welle, verbrannt nach ein paar Tagen, damit keine Blockliste sie kennt, wenn die erste Nachricht rausgeht.
Ich habe einfach nur Glück gehabt.
Schon seit ein paar Wochen lese ich mehrere Artikel zum selben Thema: AI;DR gibt dem Muster einen Namen: Jemand lässt ein Sprachmodell eine Frage beantworten und reicht die Antwort ungelesen weiter, in einen Slack-Thread, ein Issue, einen Pull Request. Das erinnert mich ein wenig an Let me Google that for you, und auch wenn ich das schon verwendet habe, verstehe ich jeden, der das als sehr unhöflich empfindet. Hier fasst dontpastetheai.com das Richtige in einem einzigen Satz zusammen, No AI Fridays geht noch einen Schritt weiter und führt einen KI-freien Tag pro Woche ein.
Am schärfsten formuliert es Niklas Gruhn:
I don't need a meat proxy in between.
Sein Beispiel ist das Code-Review: Ticket in Claude Code kopieren, Ergebnis ungelesen als PR aufmachen, die Anmerkungen der Reviewer wieder reinkopieren, bis es durchgeht. Funktioniert, aber wer ist hier verantwortlich? Liegt die Arbeit dann nicht nur bei den Reviewern?
Ich kenne das andersherum. Jemand hinterlässt Anmerkungen an meinem Code und kann auf Nachfrage nicht sagen, was er meint. Eine Runde später kommt dann, die KI habe das falsch verstanden.
"Verstanden" hat da leider niemand etwas: Ein Modell setzt fort, was im Kontext steht, und wenn die Hälfte fehlt, kommt eben etwas anderes heraus. "Falsch verstanden" macht daraus ein Missgeschick, für das niemand etwas kann.
Ein Review ist aber kein Kommentar, sondern eine Zusage: Ich habe das gelesen, ich halte es für richtig, ich bin der Meinung, dass das produktiv gehen sollte. Diese Verbindlichkeit kann mir kein Modell abnehmen, egal welches. Wer sie nicht mitliefert, hätte mir auch gleich den Prompt schicken können.
Lea Verou argumentiert, dass beim Dark Mode zwei Zustände genügen, das Sichtbare und sein Gegenteil. "System" gehört unter die Haube, nicht in den Header.
Users cannot meaningfully express intent about problems they don't currently have.
Wer Dark Mode immer will, hat ihn längst im System stehen. Der Schalter muss ihn bloß nicht kaputtmachen.
Bei mir klickte sich ein Knopf im Header durch alle drei Zustände. Angefasst habe ich ihn nie. Jetzt sind es zwei, und der zweite Klick gibt wieder ans System ab.
Im Nachtrag braucht sie dann gar keinen Schalter mehr. So konsequent war ich heute nicht.
Seit ich über 1Passwords Omarchy-Investment geschrieben habe, evaluiere ich hier Alternativen. Passwörter sind in aller Regel schnell migriert. Bei den Passkeys hatte ich mich schon damit abgefunden, sie überall neu anzulegen, weil die nun mal am Anbieter hängen.
Tun sie seit iOS 26 nicht mehr. Ricky Mondello, der bei Apple an dem Thema arbeitet, erklärt das so:
Your credentials are yours to take and manage in whatever software you want.
Also ausprobiert. In 1Password auf Export getippt, den neuen Passwort-Manager als Ziel auswählen, Face ID, und keine Minute später lagen die Passkeys samt Schlüsselmaterial dort. Nichts daran war kompliziert. Möglich machen das zwei FIDO-Standards, Credential Exchange Format und Protocol: eins fürs Datenformat, eins für den verschlüsselten Transfer. Beide Seiten müssen sie unterstützen. Ich wusste nur nicht, dass es das schon gibt.
Am Mac geht das nicht immer, da können dann womöglich nur die Zugangsdaten übertragen werden. Ausgerechnet das Telefon, auf dem ich meine Tresore am wenigsten anfassen will, ist das einzige Gerät, das den Umzug kann.