Michael Vorburger.ch Blog

Linuxes

2026

Parallelizing Agentic Coding: Supercharging AI Workflows with Terminal Notifications

March 30, 2026

Parallelizing Agentic Coding: Supercharging AI Workflows with Terminal Notifications

The real power of AI-assisted development isn’t just having an agent write code for you; it’s the ability to parallelize your workflow. When you assign a complex, multi-step refactoring task or a deep codebase investigation to a tool like the Gemini CLI, you shouldn’t just sit there watching the terminal output scroll by. You should be switching to another pane to write documentation, review PRs, or tackle another problem entirely while the agent grinds away in the background.

2025

NixOS Testing

October 12, 2025

NixOS Testing

I’ve continued to dabble with NixOS since attending NixCon 2025.

Today I finally got around to learning how to do testing of NixOS configurations; and it’s actually pretty cool!!

First install nix, if you haven’t already. Then, as explored in my LearningLinux repo here, put this into a hello.nix file:

{ pkgs, ... }:
{
  environment.systemPackages = with pkgs; [
    hello
  ];
}

and then this into a test.nix file:

{
  nodes = {
    machine1 = { pkgs, ... }: { };
    machine2 = { pkgs, ... }: { };
    machine3 = import ./hello.nix;
  };

  testScript = ''
    start_all()
    for m in [machine1, machine2, machine3]:
      m.systemctl("start network-online.target")
      m.wait_for_unit("network-online.target")

    machine1.succeed("ping -c 1 machine2")
    machine2.succeed("ping -c 1 machine1")

    machine3.succeed("hello")
    machine2.fail("hello")
  '';
}

and then put this into a flake.nix file:

Fun with Pseudo-Terminals (PTY) & TTY ("Teletypewriter") over `socat` & `websocat`

May 25, 2025

Fun with Pseudo-Terminals (PTY) & TTY (“Teletypewriter”) over socat & websocat

In the context of Enola.dev #1368, I recently learned a few things related to openpty and how to execute a program under a “pseudo (virtual) terminal” so that it e.g. prints ANSI color codes, and allows interactive control, like a Shell or Editor requires.

socat

socat, the “better netcat++” is one way do this. In one Terminal, run:

socat file:/dev/tty,raw,echo=0 tcp-listen:12345

In another Terminal, run:

Switching from NetworkManager to systemd-networkd on Fedora Linux 41 Workstation

April 12, 2025

Switching from NetworkManager to systemd-networkd on Fedora Linux 41 Workstation

TL;DR

This blog post documents how to switch from NetworkManager to systemd-networkd on Fedora Linux 41 Workstation.

Background

I have always been using NetworkManager on Fedora Linux Workstation. But sometimes my computer would refuse to enter suspend mode, or not work when resuming (“waking up”) from suspension.

journalctl -k showed that it was because of: “Freezing user space processes failed after 20.004 seconds (14 tasks refusing to freeze, wq_busy=0):” with all in state:D:

2024

Visual Studio Code 'launch-failed' code '159' Crash Fixed

December 29, 2024

Visual Studio Code ’launch-failed’ code ‘159’ Crash Fixed

Recently my Visual Studio Code on Fedora Linux 41 Workstation failed to start, saying: “The window terminated unexpectedly (reason ’launch-failed’ code ‘159’)”.

I initially attempted to solve this by starting it with code --verbose --wait, but that just showed some error messages which didn’t mean all that much to me.

Google Gemini was kind enough to walk me through debugging this using the following steps:

Pass through" a physical disk in Virtual Machine Manager

May 31, 2024

Pass through" a physical disk in Virtual Machine Manager

Here is how to “pass through” an actual physical disk from a Linux (workstation) host into a (Linux) virtual machine, using the Virtual Machine Manager (VMM) UI with click-click.

One reason why one might want to do this could be e.g. to explore running TrueNAS in a VM.

Steps

  1. Open VM’s settings via menu Edit > Virtual Machine Details

  2. Click Add Hardware (lower left)

2023

Linux "tainted" local HW clock

March 31, 2023

Linux “tainted” local HW clock

While I was setting up a new laptop, I noticed that systemd status printed Tainted: local-hwclock, see:

$ systemctl status
● laptop
    State: running
    Units: 500 loaded (incl. loaded aliases)
     Jobs: 0 queued
   Failed: 0 units
    Since: Sat 2023-04-01 20:31:56 CEST; 1h 36min left
  systemd: 253.2-1.fc38
  Tainted: local-hwclock
   CGroup: /
...

The reason for that is further explained by this:

$ timedatectl
               Local time: sam 2023-04-01 19:02:13 CEST
           Universal time: sam 2023-04-01 17:02:13 UTC
                 RTC time: sam 2023-04-01 19:02:13
                Time zone: Europe/Zurich (CEST, +0200)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: yes

Warning: The system is configured to read the RTC time in the local time zone.
         This mode cannot be fully supported. It will create various problems
         with time zone changes and daylight saving time adjustments. The RTC
         time is never updated, it relies on external facilities to maintain it.
         If at all possible, use RTC in UTC by calling
         'timedatectl set-local-rtc 0'.

As it says, this is fixed by doing:

2022

Fedora Upgrades

October 1, 2022

Fedora Upgrades

Following Fedora Docs’ DNF System Upgrade works reasonably well.

Here are how I resolve a few issues I run into every time I upgrade.

“The password you use to log in to your computer no longer matches that of your login keyring.”

With Automatic Login, the error message above appears e.g. when using GNOME Tweaks to auto-start Brave.

Work around it by using the Passwords and Keys (Seahorse) app to delete the Brave Safe Storage. This will break Brave’s Saved Passwords and Sync; to fix that, go to brave://sync-internals to Disable Sync (Clear Data), close Brave, and set up Sync again.

Fish is a **GREAT** interactive shell, but... not yet suitable for scripting! :-((

September 11, 2022

Fish is a GREAT interactive shell, but… not yet suitable for scripting! :-((

I almost :) started writing some shell scripts in Fish instead of Bash, but then discovered https://github.com/fish-shell/fish-shell/issues/510.

This seems like a massive feature gap in Fish, at least to me. I CANNOT LIVE without set -e in Bash. ALL my scripts everywhere have that (code search seems to miss a lot of them).

Fish is great as an interactive Shell, but without this feature, I cannot start using it for more scripting.

How to launch a CLI tool in a new terminal window

September 10, 2022

How to launch a CLI tool in a new terminal window

Here is one way to run a CLI process in a new window, make closing that window kill that process, yet wait for the user when said process exits, e.g. not to loose some start-up error message:

gnome-terminal -- bash -c 'ls / ; read -p "Press Enter to close..."'

I used this as follows for qemu-system-x86_64 in this script:

export KERNEL
gnome-terminal -- bash -c '\
  qemu-system-x86_64 \
    (...)
    -serial stdio  -nographic  -display none \
    -kernel "$KERNEL" ; \
  read -p "QEMU has exited - press any key to close this window..."'

Note the export - that’s needed for those environment variables to work as arguments to the process in the gnome-terminal.

Linux Kernel Random Number Entropy

September 9, 2022

Linux Kernel Random Number Entropy

The Linux Kernel uses “entropy” to generate random numbers:

$ cat /proc/sys/kernel/random/entropy_avail
256

$ cat /proc/sys/kernel/random/poolsize
256

$ cat /proc/sys/kernel/random/write_wakeup_threshold
256

This 256 seems to have recently changed.

Older blog posts state that 256 available entropy is too low.

I doubt that on modern 2022 Kernels, such as a 5.17 from Fedora 34 or a 5.18 in Fedora 36, this is still accurate. It now actually remains at 256 forever, even with keyboard and mouse and disk events; even a restart does not budge it.

Debugging Linux Start-Up Speed Performance Issues

September 9, 2022

Debugging Linux Start-Up Speed Performance Issues

Today while LearningLinux I noticed that my ArchLinux VMs started as fast as always, but it seemed to take longer and longer for sshd to be ready. This clarified what was happening:

$ systemd-analyze
Startup finished in 1.270s (kernel) + 42.586s (userspace) = 43.857s
graphical.target reached after 42.585s in userspace.

$ systemd-analyze blame
41.769s pacman-init.service
29.292s reflector-init.service
 1.198s systemd-networkd-wait-online.service
  601ms dev-vda2.device
  393ms ldconfig.service
  360ms sshdgenkeys.service
  234ms systemd-networkd.service
  168ms systemd-tmpfiles-setup.service
  155ms systemd-timesyncd.service
  145ms systemd-resolved.service
  102ms systemd-udev-trigger.service
   94ms systemd-logind.service
   93ms systemd-udevd.service
   82ms systemd-machine-id-commit.service
   79ms systemd-journal-catalog-update.service
   69ms user@1000.service
   54ms systemd-tmpfiles-setup-dev.service
   43ms systemd-journald.service
   42ms systemd-journal-flush.service
   37ms systemd-tmpfiles-clean.service
   37ms sys-kernel-tracing.mount
   36ms kmod-static-nodes.service
   36ms dev-mqueue.mount
   36ms modprobe@configfs.service
   36ms sys-kernel-debug.mount
   36ms modprobe@drm.service
   35ms dbus.service
   35ms modprobe@fuse.service
   35ms dev-hugepages.mount


$ systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

graphical.target @42.585s
└─multi-user.target @42.585s
  └─sshd.service @42.585s
    └─pacman-init.service @814ms +41.769s
      └─basic.target @811ms
        └─sockets.target @811ms
          └─dbus.socket @810ms
            └─sysinit.target @805ms
              └─systemd-update-done.service @798ms +5ms
                └─ldconfig.service @404ms +393ms
                  └─local-fs.target @402ms
                    └─run-user-1000.mount @20.308s
                      └─local-fs-pre.target @402ms
                        └─systemd-tmpfiles-setup-dev.service @346ms +54ms
                          └─systemd-sysusers.service @314ms +30ms
                            └─systemd-firstboot.service @293ms +20ms
                              └─systemd-remount-fs.service @258ms +29ms
                                └─systemd-journald.socket @242ms
                                  └─-.mount @237ms
                                    └─-.slice @237ms

Huh, so critical-chain shows that sshd was blocked by pacman-init… we can see that from the Before=sshd.service here:

Fedora Silverblue

August 16, 2022

Fedora Silverblue

See also remaining ToDo (private).

OSTree

rpm-ostree install kitty
rpm-ostree status
systemctl reboot

Flatpack

As per https://github.com/vorburger/vorburger-dotfiles-bin-etc#on-fedora-silverblue, Apps from Flatpack will have certain limitations, such as that:

Troubleshooting

The blocked updates of 2022-08

As per https://fedoramagazine.org/manual-action-required-to-update-fedora-silverblue-kinoite-and-iot-version-36/, after running e.g. rpm-ostree install kitty as e.g. in my ostree-install-gui.sh, rpm-ostree status shows what’s currently running, and what it should boot into on the next systemctl reboot:

$ rpm-ostree status
State: idle
Warning: failed to finalize previous deployment
         error: Bootloader write config: grub2-mkconfig: Child process exited with code 1
         check `journalctl -b -1 -u ostree-finalize-staged.service`
Deployments:
● fedora:fedora/36/x86_64/silverblue
                  Version: 36.1.5 (2022-05-04T18:42:06Z)

But beware that that Warning on top means that install won’t work! The following workaround did the trick for me:

DAppNode

March 13, 2022

DAppNode

https://dappnode.io

ToDo

  1. ipfs.dappnode with HTTPS? See https://github.com/dappnode/DAppNode/issues/406, and below.
  2. Fix http://alice.eth etc. as it’s still NOK when now that IPFS works, see https://github.com/dappnode/DAppNode/issues/492
  3. Install http://dappnode.local/#/installer/prysm.dnp.dappnode.eth
  4. http://dappnode.local/#/installer More packages to install?
  5. http://dappnode.local/#/community => https://sourcecred.dappnode.io/#/explorer PAN?
  6. DAppNode DApp list
  7. Configure /etc/wireguard/wg0.conf to “route” / “lookup” (?) ONLY .eth and .dappnode domain names through that VPN? Test by shutdown DAppNode.
  8. (Re-)install and configure http://dappnode.local/#/packages/rotki.dnp.dappnode.eth/info
  9. git server (local at first, then on IPFS); e.g. on https://github.com/linuxserver?
  10. Backups, for git server and other, on IPFS

Use

  • brave://settings/ipfs
  • brave://ipfs-internals/
  • If using Brave Local IPFS Node:
    • http://127.0.0.1:45005/webui
    • brave://settings/ipfs/peers

Manage & Maintenance

Set up

As per official documentation, and then:

2021

Exploring Fedora CoreOS

April 12, 2021

Exploring Fedora CoreOS

See https://docs.fedoraproject.org/en-US/fedora-coreos!

First Steps

Following https://docs.fedoraproject.org/en-US/fedora-coreos/getting-started/ :

podman run --pull=always --rm -v $HOME/.local/share/libvirt/images/:/data -w /data \
    quay.io/coreos/coreos-installer:release download -s stable -p qemu -f qcow2.xz --decompress

qemu-img create -f qcow2 -b \
    ~/.local/share/libvirt/images/fedora-coreos-33.20210328.3.0-qemu.x86_64.qcow2 \
    ~/.local/share/libvirt/images/my-first-fcos-vm.qcow2 20G
ls -lh ~/.local/share/libvirt/images/

podman run --interactive --rm quay.io/coreos/butane:release \
    --pretty --strict <first.bu >first.ign
bat first.ign

qemu-kvm -m 2048 -cpu host -nographic \
    -drive if=virtio,file=$HOME/.local/share/libvirt/images/my-first-fcos-vm.qcow2 \
    -fw_cfg name=opt/com.coreos/config,file=first.ign \
    -nic user,model=virtio,hostfwd=tcp::2222-:22

ssh-keygen -R "[localhost]:2222"
ssh -o StrictHostKeyChecking=accept-new -p 2222 core@localhost

pstree
systemctl status
systemctl --type=service --state=active
hostnamectl

podman run --rm -it hello-world

Automatic Updates

See https://docs.fedoraproject.org/en-US/fedora-coreos/update-streams/, and https://docs.fedoraproject.org/en-US/fedora-coreos/tutorial-updates/ :