CINXE.COM
splitbrain.org - blog
<?xml version="1.0" encoding="UTF-8"?> <!-- generator="FeedCreator 1.8" --> <?xml-stylesheet href="https://www.splitbrain.org/lib/exe/css.php?s=feed" type="text/css"?> <rss version="2.0"> <channel xmlns:g="http://base.google.com/ns/1.0"> <title>splitbrain.org - blog</title> <description>electronic brain surgery since 2001</description> <link>https://www.splitbrain.org/</link> <lastBuildDate>Thu, 20 Feb 2025 09:30:33 +0000</lastBuildDate> <generator>FeedCreator 1.8</generator> <image> <url>https://www.splitbrain.org/_media/wiki/favicon.ico</url> <title>splitbrain.org</title> <link>https://www.splitbrain.org/</link> </image> <item> <title>FrameWork 13 (Intel Ultra) & ArchLinux</title> <link>https://www.splitbrain.org/blog/2025-02/17-framework_13_intel_core_ultra_archlinux</link> <description> <h1 class="sectionedit1" id="framework_13_intel_ultra_archlinux">FrameWork 13 (Intel Ultra) &amp; ArchLinux</h1> <div class="level1"> <p> My trusty <a href="https://www.splitbrain.org/blog/2014-03/08-lenovo_thinkpad_x240_xubuntu" class="urlextern" title="https://www.splitbrain.org/blog/2014-03/08-lenovo_thinkpad_x240_xubuntu">Thinkpad</a> is now over a decade old and I was eyeing a <a href="https://frame.work/" class="urlextern" title="https://frame.work/">Framework Laptop</a> for a while now. So when the opportunity arose to get it as a work laptop I couldn&#039;t refuse <img src="https://www.splitbrain.org/lib/images/smileys/wink.svg" class="icon smiley" alt=";-)" /> </p> <p> I picked the Intel Ultra Core 165H model with 96GB of RAM and a 4TB NVME disk. This beast should have plenty of power for the foreseeable future. </p> <blockquote><div class="no"> Of course Framework announced that they would release a new generation on February 25th just a couple of days after my order <img src="https://www.splitbrain.org/lib/images/smileys/facepalm.svg" class="icon smiley" alt="m(" />.</div></blockquote> <p> Below are my notes on how to set it up on Arch Linux. I might extend the post over the coming weeks… </p> <hr /> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;FrameWork 13 (Intel Ultra) &amp; ArchLinux&quot;,&quot;hid&quot;:&quot;framework_13_intel_ultra_archlinux&quot;,&quot;codeblockOffset&quot;:0,&quot;secid&quot;:1,&quot;range&quot;:&quot;1-719&quot;} --> <h2 class="sectionedit2" id="hardware">Hardware</h2> <div class="level2"> <p> I got the DIY version which means some slight assembly is required. The <a href="https://guides.frame.work/Guide/Framework+Laptop+13+(Intel+Core+Ultra+Series+1)+DIY+Edition+Quick+Start+Guide/332?lang=en" class="urlextern" title="https://guides.frame.work/Guide/Framework+Laptop+13+(Intel+Core+Ultra+Series+1)+DIY+Edition+Quick+Start+Guide/332?lang=en">installation guide</a> is great and reminded me a lot of the <a href="https://www.splitbrain.org/blog/2018-10/14-back_to_the_future" class="urlextern" title="https://www.splitbrain.org/blog/2018-10/14-back_to_the_future">Prusa</a> assembly guides (including helpful user comments on each step). It took me and Kaddi about 20 minutes to assemble. </p> <p> <a href="https://www.splitbrain.org/_detail/blog/2025-02/framework/pxl_20250214_112415649.jpg?id=blog%3A2025-02%3A17-framework_13_intel_core_ultra_archlinux" class="media" title="blog:2025-02:framework:pxl_20250214_112415649.jpg"><img src="https://www.splitbrain.org/_media/blog/2025-02/framework/pxl_20250214_112415649.jpg?w=400&amp;tok=c99314" class="media" loading="lazy" title="Start of Assembly" alt="Start of Assembly" width="400" /></a> <a href="https://www.splitbrain.org/_detail/blog/2025-02/framework/pxl_20250214_114340274.jpg?id=blog%3A2025-02%3A17-framework_13_intel_core_ultra_archlinux" class="media" title="blog:2025-02:framework:pxl_20250214_114340274.jpg"><img src="https://www.splitbrain.org/_media/blog/2025-02/framework/pxl_20250214_114340274.jpg?w=400&amp;tok=14ed0c" class="media" loading="lazy" title="First Boot" alt="First Boot" width="400" /></a> </p> <p> When buying the laptop, you can pick each individual component. Here&#039;s what I selected: </p> <ul> <li class="level1"><div class="li"> DIY Edition</div> </li> <li class="level1"><div class="li"> Intel Core</div> </li> <li class="level1"><div class="li"> System: Ultra 7 165H</div> </li> <li class="level1"><div class="li"> Display: 2.8K Display (the “non-retina” display is not available for the Intel Core models)</div> </li> <li class="level1"><div class="li"> Storage: WD_BLACK™ SN850X NVMe™- M.2 2280 - 4TB</div> </li> <li class="level1"><div class="li"> Operating System: none</div> </li> <li class="level1"><div class="li"> Bezel: black</div> </li> <li class="level1"><div class="li"> Keyboard: German</div> </li> <li class="level1"><div class="li"> Power Adapter: none</div> </li> <li class="level1"><div class="li"> Expansion Cards: 2x USB-C, 1x USB-A, 1x HDMI</div> </li> </ul> <p> If this hadn&#039;t been a company laptop I probably would have bought RAM and storage somewhere else to save some money, but it was easier this way. </p> <p> I did not get their power supply and instead bought a <a href="https://www.amazon.de/dp/B0CLL3TQWT?tag=splitbrain-21" class="interwiki iw_amazon_de" title="https://www.amazon.de/dp/B0CLL3TQWT?tag=splitbrain-21">uGreen Nexode 65W Power Supply</a> which is absolutely tiny. </p> <p> I also ordered a <a href="https://www.cushcase.com/collections/framework-laptop-13-sleeve-cases/products/framework-laptop-13-sleeve-case-pioneer-canvas-special-edition" class="urlextern" title="https://www.cushcase.com/collections/framework-laptop-13-sleeve-cases/products/framework-laptop-13-sleeve-case-pioneer-canvas-special-edition">laptop sleeve from CushCase</a> but it hasn&#039;t arrived, yet. I&#039;ll add a picture when it does. </p> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Hardware&quot;,&quot;hid&quot;:&quot;hardware&quot;,&quot;codeblockOffset&quot;:0,&quot;secid&quot;:2,&quot;range&quot;:&quot;720-2303&quot;} --> <h2 class="sectionedit3" id="references">References</h2> <div class="level2"> <p> For the remaining setup I relied heavily on these sources: </p> <ul> <li class="level1"><div class="li"> <a href="https://0daysto.live/posts/arch_linux_framework_setup/" class="urlextern" title="https://0daysto.live/posts/arch_linux_framework_setup/">Arch Linux on Framework Laptop Setup</a></div> </li> <li class="level1"><div class="li"> <a href="https://www.youtube.com/watch?v=kXqk91R4RwU&amp;list=PLTVYP5rabVCyDEkdPKxWQB7ujXAKtLxf4" class="urlextern" title="https://www.youtube.com/watch?v=kXqk91R4RwU&amp;list=PLTVYP5rabVCyDEkdPKxWQB7ujXAKtLxf4">Arch Linux: An 𝔼𝕟𝕔𝕣𝕪𝕡𝕥𝕖𝕕 Guide</a> (YouTube)</div> </li> <li class="level1"><div class="li"> <a href="https://wiki.archlinux.org/title/Framework_Laptop_13" class="urlextern" title="https://wiki.archlinux.org/title/Framework_Laptop_13">FrameWork Laptop 13 - ArchWiki</a></div> </li> <li class="level1"><div class="li"> <a href="https://wiki.archlinux.org/title/HiDPI#Xfce" class="urlextern" title="https://wiki.archlinux.org/title/HiDPI#Xfce">HiDPI XFCE - ArchWiki</a></div> </li> </ul> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;References&quot;,&quot;hid&quot;:&quot;references&quot;,&quot;codeblockOffset&quot;:0,&quot;secid&quot;:3,&quot;range&quot;:&quot;2304-2814&quot;} --> <h2 class="sectionedit4" id="bios_update">Bios Update</h2> <div class="level2"> <p> Before installing the <abbr title="Operating System">OS</abbr> I wanted to update the BIOS. To get the current version, press F2 during boot, then go to Setup Utility → Main → InsydeH2O Version. Mine said <code>KFM30.03.01</code>. Which the Framework people call just <code>03.01</code>. </p> <p> To update you can use an UEFI shellscript. You can find the zip file here: <a href="https://knowledgebase.frame.work/en_us/framework-laptop-bios-and-driver-releases-intel-core-ultra-series-1-H1nZQdxYR#:~:text=Linux/Other/UEFI%20Shell%20update" class="urlextern" title="https://knowledgebase.frame.work/en_us/framework-laptop-bios-and-driver-releases-intel-core-ultra-series-1-H1nZQdxYR#:~:text=Linux/Other/UEFI%20Shell%20update">Linux/Other/UEFI Shell update</a>. </p> <blockquote><div class="no"> TBH I found their BIOS upgrade guide a mess and no comparison to their assembly guide. Framework should really improve this.</div></blockquote> <p> To use the EFI Shell update, a FAT formatted USB stick with a GPT partition is needed: </p> <pre class="code bash">$<span class="sy0">&gt;</span> <span class="kw2">sudo</span> <span class="kw2">gdisk</span> <span class="sy0">/</span>dev<span class="sy0">/</span>sde p <span class="co0"># to print current partitition table</span> d <span class="co0"># delete existing partitition</span> n <span class="co0"># for new partition</span> <span class="br0">&#91;</span>enter<span class="br0">&#93;</span> <span class="co0"># for partition number 1</span> <span class="br0">&#91;</span>enter<span class="br0">&#93;</span> <span class="co0"># for start sector default</span> <span class="br0">&#91;</span>enter<span class="br0">&#93;</span> <span class="co0"># for end sector default</span> ef00 <span class="co0"># for efi partition type</span> <span class="kw2">w</span> <span class="co0"># for writing table to disk</span> $<span class="sy0">&gt;</span> <span class="kw2">sudo</span> mkfs.vfat <span class="sy0">/</span>dev<span class="sy0">/</span>sde1 $<span class="sy0">&gt;</span> <span class="kw2">sudo</span> <span class="kw2">mount</span> <span class="sy0">/</span>dev<span class="sy0">/</span>sde1 <span class="sy0">/</span>mnt $<span class="sy0">&gt;</span> <span class="kw3">cd</span> <span class="sy0">/</span>mnt $<span class="sy0">&gt;</span> <span class="kw2">sudo</span> <span class="kw2">unzip</span> ~<span class="sy0">/</span>temp<span class="sy0">/</span>00-today<span class="sy0">/</span>Framework_Laptop_13_Intel_Core_Ultra_Series1_capsule_signed_allsku_3.03_3.04_EFI.zip $<span class="sy0">&gt;</span> <span class="kw3">cd</span> $<span class="sy0">&gt;</span> <span class="kw2">sudo</span> <span class="kw2">umount</span> <span class="sy0">/</span>mnt</pre> <p> Now you can boot from that stick and the update should happen automatically. It should update first to 3.03, then to 3.04. </p> <p> <a href="https://www.splitbrain.org/_detail/blog/2025-02/framework/pxl_20250214_135504202.jpg?id=blog%3A2025-02%3A17-framework_13_intel_core_ultra_archlinux" class="media" title="blog:2025-02:framework:pxl_20250214_135504202.jpg"><img src="https://www.splitbrain.org/_media/blog/2025-02/framework/pxl_20250214_135504202.jpg?w=400&amp;tok=4a2946" class="mediacenter" loading="lazy" title="BIOS Update in progress" alt="BIOS Update in progress" width="400" /></a> </p> <p> That seemed to work fine until the whole process somehow got stuck and did the same thing again and again. It would apply some update named “Port01: 270 → Port01: 270”, show “Update complete!!”, reboot and do the same thing again. </p> <p> At some point I removed the USB stick and saw that the update to 3.03 had been applied, but 3.04 was nowhere to be seen. </p> <p> I created a <a href="https://community.frame.work/t/bios-upgrade-intel-core-ultra-is-stuck-on-retimer-270/64560" class="urlextern" title="https://community.frame.work/t/bios-upgrade-intel-core-ultra-is-stuck-on-retimer-270/64560">forum post asking for help</a> and moved on to install the <abbr title="Operating System">OS</abbr>. </p> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Bios Update&quot;,&quot;hid&quot;:&quot;bios_update&quot;,&quot;codeblockOffset&quot;:0,&quot;secid&quot;:4,&quot;range&quot;:&quot;2815-4802&quot;} --> <h1 class="sectionedit5" id="boot_media">Boot Media</h1> <div class="level1"> <p> First step is preparing the bootable USB stick with the current ArchLinux ISO. I used Balena Etcher to “burn” the stick. </p> <p> Once booted, I changed to a German keyboard layout with <code>loadkeys de</code>. </p> <p> To connect to the internet, simply use <code>iwctl</code>: </p> <pre class="code">#&gt; iwctl device list station wlan0 scan station wlan0 get-networks station wlan0 connect YOURNETWORK</pre> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Boot Media&quot;,&quot;hid&quot;:&quot;boot_media&quot;,&quot;codeblockOffset&quot;:1,&quot;secid&quot;:5,&quot;range&quot;:&quot;4803-5187&quot;} --> <h1 class="sectionedit6" id="encrypted_file_system">Encrypted File System</h1> <div class="level1"> <p> One thing mandated by my company is that all work related stuff has to be stored on an encrypted device. In the past I used ecryptFS to encrypt my home directory. But since I was starting from scratch here, I wanted to properly encrypt the whole root partition. </p> <p> I decided for the following layout: </p> <ul> <li class="level1"><div class="li"> 1GB EXT4 mounted to <code>/boot</code></div> </li> <li class="level1"><div class="li"> 1GB FAT32 mounted to <code>/efi</code></div> </li> <li class="level1 node"><div class="li"> ~3.6TB LUKS2 encrypted</div> <ul> <li class="level2"><div class="li"> EXT4 mounted to <code>/</code></div> </li> </ul> </li> </ul> <p> The boot and EFI partitions are quite spacious, but better safe than sorry later. </p> <p> Note that I decided against any LVM setup here. The only reason I can see to do so is if I wanted to have different partitions inside the LUKS container, but I prefer one huge root partition so I kept things simple here. </p> <p> To create the partition table <code>gdisk</code> is used: </p> <pre class="code">#&gt; gdisk /dev/nvme01n1 n # new partition [enter] # partition number [enter] # first available sector +1g # last sector (at 1GB after the first) [enter] # type Linux Filesystem n # new partition [enter] # partition number [enter] # first available sector +1g # last sector (at 1GB after the first) ef00 # type EFI system partition n # new partition [enter] # partition number [enter] # first available sector [enter] # last available sector [enter] # type Linux Filesystem p # print current setup Disk /dev/nvme0n1: 7814037168 sectors, 3.6 TiB Model: WD_BLACK SN850X 4000GB Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): F6D832C4-EE21-4995-A468-59BD03C351F7 Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 7814037134 Partitions will be aligned on 2048-sector boundaries Total free space is 3693 sectors (1.8 MiB) Number Start (sector) End (sector) Size Code Name 1 2048 2099199 1024.0 MiB 8300 Linux filesystem 2 2099200 4196351 1024.0 MiB EF00 EFI system partition 3 4196352 7814035455 3.6 TiB 8300 Linux filesystem w # write to disk y # confirm</pre> <p> Next the encryption for partition 3 is set up. I made sure to use the newer LUKS2 format, but kept everything else at its defaults: </p> <pre class="code bash">cryptsetup luksFormat <span class="re5">--type</span> luks2 <span class="sy0">/</span>dev<span class="sy0">/</span>nvme0n1p3 cryptsetup open <span class="sy0">/</span>dev<span class="sy0">/</span>nvme0n1p3 luks</pre> <p> The opened encrypted block device is now available as <code>/dev/mapper/luks</code>. Time to create the file systems: </p> <pre class="code bash">mkfs.ext4 <span class="sy0">/</span>dev<span class="sy0">/</span>nvme0n1p1 <span class="co0"># boot partition</span> mkfs.fat <span class="re5">-F32</span> <span class="sy0">/</span>dev<span class="sy0">/</span>nvme0n1p2 <span class="co0"># efi partition</span> mkfs.ext4 <span class="sy0">/</span>dev<span class="sy0">/</span>mapper<span class="sy0">/</span>luks <span class="co0"># root partition</span></pre> <p> Finally the file systems can be mounted. </p> <pre class="code">mount /dev/mapper/luks /mnt mkdir /mnt/efi mount /dev/nvme0n1p2 /mnt/efi mkdir /mnt/boot mount /dev/nvme0n1p1 /mnt/boot</pre> <blockquote><div class="no"> <a href="https://troete.rechenkugel.de/@mortzu/114020235098677397" class="urlextern" title="https://troete.rechenkugel.de/@mortzu/114020235098677397">@mortzu on Mastodon</a> points out that the encrypted device should be opened with <a href="https://wiki.archlinux.org/title/Dm-crypt/Specialties#Discard/TRIM_support_for_solid_state_drives_(SSD)" class="urlextern" title="https://wiki.archlinux.org/title/Dm-crypt/Specialties#Discard/TRIM_support_for_solid_state_drives_(SSD)">TRIM support</a> to reduce wear on the SSD. The same ArchWiki page also recommends <a href="https://wiki.archlinux.org/title/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance" class="urlextern" title="https://wiki.archlinux.org/title/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance">disabling work queues</a> on SSDs.<br/> Both changes can easily be enabled after the fact:<br/> <pre class="code">#&gt; cryptsetup --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent refresh luks #&gt; cryptsetup luksDump /dev/nvme0n1p3 |grep Flags Flags: allow-discards no-read-workqueue no-write-workqueue</pre> </div></blockquote> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Encrypted File System&quot;,&quot;hid&quot;:&quot;encrypted_file_system&quot;,&quot;codeblockOffset&quot;:1,&quot;secid&quot;:6,&quot;range&quot;:&quot;5188-8841&quot;} --> <h2 class="sectionedit7" id="bootstrapping">Bootstrapping</h2> <div class="level2"> <p> Now the base ArchLinux system can be installed. Only the bare minimum here: </p> <pre class="code">pacstrap /mnt base linux linux-firmware mkinitcpio vim dhcpcd wpa_supplicant intel-ucode iwd grub</pre> <p> A file system table can be auto generated. Disabling access times improves performance and reduces wear on the SSD: </p> <pre class="code bash">genfstab <span class="re5">-pU</span> <span class="sy0">/</span>mnt <span class="sy0">|</span> <span class="kw2">sed</span> <span class="st_h">'s/relatime/noatime/'</span> <span class="sy0">&gt;&gt;</span> <span class="sy0">/</span>mnt<span class="sy0">/</span>etc<span class="sy0">/</span>fstab</pre> <p> Time to chroot into the new system: </p> <pre class="code">arch-chroot /mnt</pre> <p> First set the timezone, hardware clock and hostname: </p> <pre class="code bash"><span class="kw2">ln</span> <span class="re5">-s</span> <span class="sy0">/</span>usr<span class="sy0">/</span>share<span class="sy0">/</span>zoneinfo<span class="sy0">/</span>Europe<span class="sy0">/</span>Berlin <span class="sy0">/</span>etc<span class="sy0">/</span>localtime hwclock <span class="re5">--systohc</span> <span class="re5">--utc</span> <span class="kw3">echo</span> ni <span class="sy0">&gt;</span> <span class="sy0">/</span>etc<span class="sy0">/</span><span class="kw2">hostname</span></pre> <p> Uncomment <code>en_US.UTF-8 UTF-8</code> in <code>/etc/locale.gen</code> and generate, then set up the locale </p> <pre class="code bash">locale-gen <span class="kw3">echo</span> <span class="st_h">'LANG=en_US.UTF-8'</span> <span class="sy0">&gt;&gt;</span> <span class="sy0">/</span>etc<span class="sy0">/</span>locale.conf</pre> <p> Don&#039;t forget to keep the German keyboard layout. The following sets <code>/etc/vconsole.conf</code> as well as the xorg default for later. </p> <pre class="code bash">localectl set-x11-keymap de</pre> <p> Set up the hosts file: </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/17-framework_13_intel_core_ultra_archlinux?codeblock=11" title="Download Snippet" class="mediafile mf_">/etc/hosts</a></dt> <dd><pre class="file">127.0.0.1 localhost ni ::1 localhost</pre> </dd></dl> <p> And create a root password: </p> <pre class="code">passwd</pre> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Bootstrapping&quot;,&quot;hid&quot;:&quot;bootstrapping&quot;,&quot;codeblockOffset&quot;:6,&quot;secid&quot;:7,&quot;range&quot;:&quot;8842-9988&quot;} --> <h2 class="sectionedit8" id="grub_setup">Grub Setup</h2> <div class="level2"> <p> As the bootloader I used grub. To make it aware of the encrypted root disk some adjustments need to be made. </p> <p> First we need to make sure the initramfs can decrypt our file system. This is done by adding the <code>encrypt</code> hook after the <code>block</code> hook in <code>/etc/mkinitcpio.conf</code>. </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/17-framework_13_intel_core_ultra_archlinux?codeblock=13" title="Download Snippet" class="mediafile mf_conf">/etc/mkinitcpio.conf</a></dt> <dd><pre class="file">HOOKS=(base udev autodetect keyboard modconf block encrypt filesystems fsck)</pre> </dd></dl> <p> Be sure to recreate the initramfs after the change. </p> <pre class="code">mkinitcpio -p linux</pre> <p> Next we need the UUID of the encrypted partition: </p> <pre class="code">#&gt; blkid -o value -s UUID /dev/nvme0n1p3 ce7318b0-4302-442c-aaff-6e9c26f7547e</pre> <p> Now the grub configuration can be adjusted. Find and edit the appropriate options in <code>/etc/default/grub</code> </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/17-framework_13_intel_core_ultra_archlinux?codeblock=14" title="Download Snippet" class="mediafile mf_">/etc/default/grub</a></dt> <dd><pre class="code file ini"><span class="re1">GRUB_CMDLINE_LINUX</span><span class="sy0">=</span><span class="st0">&quot;cryptdevice=UUID=ce7318b0-4302-442c-aaff-6e9c26f7547e:luks&quot;</span> <span class="re1">GRUB_ENABLE_CRYPTODISK</span><span class="sy0">=</span><span class="re2">y</span> <span class="re1">GRUB_TERMINAL_OUTPUT</span><span class="sy0">=</span><span class="re2">gfxterm</span> <span class="re1">GRUB_GFXMODE</span><span class="sy0">=</span><span class="re2">800x600</span></pre> </dd></dl> <p> The first line tells the kernel to decrypt our root partition. The second tells grub about it. The last two lines simply reduce the graphics resolution so you don&#039;t have to squint at tiny pixels in your boot loader. </p> <p> Next the bootloader can be installed: </p> <pre class="code bash"><span class="kw2">mkdir</span> <span class="sy0">/</span>boot<span class="sy0">/</span>grub grub-mkconfig <span class="re5">-o</span> <span class="sy0">/</span>boot<span class="sy0">/</span>grub<span class="sy0">/</span>grub.cfg grub-install <span class="re5">--target</span>=x86_64-efi <span class="re5">--efi-directory</span>=<span class="sy0">/</span>efi <span class="re5">--removable</span></pre> <p> With all this done, it&#039;s time to reboot. Exit the chroot environment, unmount the disks and reboot (remove the USB stick). </p> <pre class="code bash"><span class="kw3">exit</span> <span class="kw2">umount</span> <span class="sy0">/</span>mnt<span class="sy0">/</span>efi <span class="sy0">/</span>mnt<span class="sy0">/</span>boot <span class="sy0">/</span>mnt reboot</pre> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Grub Setup&quot;,&quot;hid&quot;:&quot;grub_setup&quot;,&quot;codeblockOffset&quot;:13,&quot;secid&quot;:8,&quot;range&quot;:&quot;9989-11503&quot;} --> <h2 class="sectionedit9" id="xfce_xorg_ui_scaling">XFCE &amp; XOrg &amp; UI Scaling</h2> <div class="level2"> <p> Once successfully booted and logged in, I needed network access again. It can be done the same way as in the install environment above. In theory you can simply enable both services at boot, but I will use the graphical network manager once X is up, so this is only temporary: </p> <pre class="code">systemctl start iwd dhcpcd iwctl</pre> <p> You should also create a local user now and add it to sudoers. </p> <p> Time to install a bunch of packages. I am using XFCE for decades now and am perfectly happy with it. The same goes for Xorg. At some point in the future I might make the switch to Wayland, but for now I don&#039;t have any compelling reason. </p> <p> One thing that threw me off, was that you should NOT install the <code>xf86-video-intel</code> package. It will not work with the modern hardware. </p> <pre class="code">#&gt; pacman -S xorg mesa mesa-utils xfce4 xfce4-goodies lightdm lightdm-gtk-greeter light-locker gnome-keyring ttf-dejavu ttf-liberation ttf-droid ttf-ubuntu-font-family ttf-roboto noto-fonts noto-fonts-emoji ttf-bitstream-vera pulseaudio pulseaudio-alsa alsa-utils pavucontrol networkmanager network-manager-applet nm-connection-editor networkmanager-openvpn openvpn gigolo gvfs gvfs-smb bind-tools colord xiccd #&gt; systemctl enable NetworkManager lightdm #&gt; systemctl start NetworkManager lightdm</pre> <p> You should now have a running XFCE desktop you can login to. Running at a ridiculous resolution of 2880&times;1920. Time to do some tweaking. </p> <blockquote><div class="no"> Proper “retina” style scaling is still a major <abbr title="Pain in the Ass">PITA</abbr> on Linux. The tweaks below are the best I could achieve so far. Individual tools might still trip over the settings.</div></blockquote> <p> First download the color profile for the screen: </p> <pre class="code">$&gt; wget --user-agent=&quot;Mozilla/5.0&quot; https://www.notebookcheck.net/uploads/tx_nbc2/BOE0CB4.icm</pre> <p> Then open the Settings Manager and adjust some settings: </p> <ul> <li class="level1 node"><div class="li"> Appearance</div> <ul> <li class="level2 node"><div class="li"> Settings</div> <ul> <li class="level3"><div class="li"> Window Scaling: 2</div> </li> </ul> </li> </ul> </li> <li class="level1 node"><div class="li"> Window Manager</div> <ul> <li class="level2 node"><div class="li"> Style</div> <ul> <li class="level3"><div class="li"> Theme: Default-xhdpi</div> </li> </ul> </li> </ul> </li> <li class="level1 node"><div class="li"> Display</div> <ul> <li class="level2 node"><div class="li"> General</div> <ul> <li class="level3"><div class="li"> Scale: 0.75</div> </li> </ul> </li> </ul> </li> <li class="level1 node"><div class="li"> Color Profiles</div> <ul> <li class="level2"><div class="li"> Select the Monitor</div> </li> <li class="level2 node"><div class="li"> Click Add</div> <ul> <li class="level3"><div class="li"> Browse for the downloaded BOE0CB4.icm and add it</div> </li> <li class="level3"><div class="li"> Select BOE0CB4 from the list</div> </li> </ul> </li> </ul> </li> <li class="level1 node"><div class="li"> Mouse and Touchpad</div> <ul> <li class="level2"><div class="li"> Select the Touchpad Device</div> </li> <li class="level2 node"><div class="li"> Buttons and Feedback</div> <ul> <li class="level3 node"><div class="li"> Pointer Speed</div> <ul> <li class="level4"><div class="li"> Acceleration: 8.0</div> </li> </ul> </li> </ul> </li> <li class="level2 node"><div class="li"> Touchpad</div> <ul> <li class="level3"><div class="li"> Tap touchpad to click: enable</div> </li> <li class="level3"><div class="li"> Click Method: Click 1,2 or 3 fingers…</div> </li> </ul> </li> </ul> </li> </ul> <p> The above will first set the scaling to <code>2x</code>, then zoom out slightly again via xrandr. Feel free to play with the settings according to your preferences. </p> <p> However some programs may still not pick up the correct scaling. In my case IntelliJ Idea failed to understand the settings. The solution was to set the <code>GDK_SCALE</code> env variable. </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/17-framework_13_intel_core_ultra_archlinux?codeblock=17" title="Download Snippet" class="mediafile mf_xprofile">~/.xprofile</a></dt> <dd><pre class="code file bash"><span class="kw3">export</span> <span class="re2">GDK_SCALE</span>=<span class="nu0">2</span></pre> </dd></dl> <p> More issues can potentially pop up with every single program you run <img src="https://www.splitbrain.org/lib/images/smileys/doubt.svg" class="icon smiley" alt=":-/" />. To make Gimp correctly scale the UI, I had to install <code>gimp-devel</code> from AUR. With Release Candidate 3 having been released just a week ago this will hopefully not be needed for much longer. </p> <p> One issue I couldn&#039;t fix yet is that the mouse pointer size is quite tiny. And the size setting has absolutely no effect. I assume this is a bug that will be fixed in future updates. </p> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;XFCE &amp; XOrg &amp; UI Scaling&quot;,&quot;hid&quot;:&quot;xfce_xorg_ui_scaling&quot;,&quot;codeblockOffset&quot;:17,&quot;secid&quot;:9,&quot;range&quot;:&quot;11504-14707&quot;} --> <h2 class="sectionedit10" id="external_displays">External Displays</h2> <div class="level2"> <p> When you connect the laptop to an external non-retina display, you need to further downscale everything again. Luckily this is simple to do in the <em>Settings Manager</em> under <em>Display</em> → <em>General</em> → <em>Scale</em> where you can set a scale for each individual monitor. For non-retina monitors setting the scale to <code>0.5</code> will undo all the previous enlargements. </p> <p> Under <em>Advanced</em> you can save different display settings as profiles and have them applied automatically when you connect a new display. </p> <p> If the profile auto-selection fails sometimes, you can manually trigger it by running: </p> <pre class="code">xrandr --auto</pre> <blockquote><div class="no"> When connecting an external display via USB-C (opposed to using the HDMI expansion card) you need to make sure your cable is actually capable of doing video transfer. Chances are high that none of your existing cables are. When buying, either look for “Thunderbolt”, “USB Gen 4.0” or descriptors like “4K” or “8k”. Buying USB-Cables is a mess.</div></blockquote> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;External Displays&quot;,&quot;hid&quot;:&quot;external_displays&quot;,&quot;codeblockOffset&quot;:18,&quot;secid&quot;:10,&quot;range&quot;:&quot;14708-15696&quot;} --> <h2 class="sectionedit11" id="auto_login">Auto Login</h2> <div class="level2"> <p> Since booting up already requires to unlock the encrypted root disk and this is a single user system, there is no reason to have lightdm ask me for a password for logging into my xsession. Instead I simply enable it&#039;s auto login feature: </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/17-framework_13_intel_core_ultra_archlinux?codeblock=18" title="Download Snippet" class="mediafile mf_conf">/etc/lightdm/lightdm.conf</a></dt> <dd><pre class="code file ini"><span class="re0"><span class="br0">&#91;</span>Seat:*<span class="br0">&#93;</span></span> <span class="re1">autologin-user</span><span class="sy0">=</span><span class="re2">andi</span> <span class="re1">autologin-user-timeout</span><span class="sy0">=</span><span class="re2">0</span></pre> </dd></dl> <p> To make that work, my user needs to be in a <code>autologin</code> group: </p> <pre class="code">sudo groupadd -r autologin sudo usermod -aG autologin andi</pre> <p> One issue I ran into is that gnome-keyring is usually unlocked by the user password. With auto-login that doesn&#039;t exist anymore. But again with the whole disk encrypted, additional encryption for gnome-keyring is superfluous. </p> <p> To create a password-less keyring, I logged out and connected via SSH. Then deleted <code>~/.local/share/keyrings</code> and rebooted. When I started Chrome (which uses the keyring) I was asked to create a new one and give it a password. I chose an empty one and confirmed that I am fine with unencrypted data. </p> <blockquote><div class="no"> Apparently the only way to change the password of an existing keyring is to use the graphical tool Seahorse. It&#039;s super weird to me that there is no (documented) way to do it from the command line. But I guess it&#039;s a Gnome tool, so they expect you to run their full suite of <abbr title="Graphical User Interface">GUI</abbr> tools…</div></blockquote> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Auto Login&quot;,&quot;hid&quot;:&quot;auto_login&quot;,&quot;codeblockOffset&quot;:18,&quot;secid&quot;:11,&quot;range&quot;:&quot;15697-17010&quot;} --> <h2 class="sectionedit12" id="energy_management">Energy Management</h2> <div class="level2"> <p> I didn&#039;t do much for energy management yet except installing and enabling the recommended tools. Seems to work fine. </p> <pre class="code bash"><span class="kw2">sudo</span> pacman <span class="re5">-S</span> thermald tlp ethtool smartmontools <span class="kw2">sudo</span> systemctl <span class="kw3">enable</span> thermald tlp <span class="kw2">sudo</span> systemctl start thermald tlp</pre> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Energy Management&quot;,&quot;hid&quot;:&quot;energy_management&quot;,&quot;codeblockOffset&quot;:19,&quot;secid&quot;:12,&quot;range&quot;:&quot;17011-17299&quot;} --> <h2 class="sectionedit13" id="bluetooth">Bluetooth</h2> <div class="level2"> <p> Getting Bluetooth to work was super easy. Just install the requirements and start the daemon. </p> <pre class="code">sudo pacman -S bluez bluez-utils blueman pulseaudio-bluetooth sudo systemctl enable bluetooth sudo systemctl start bluetooth</pre> <p> This was enough to pair my <a href="https://www.splitbrain.org/blog/2021-10/15-noise_cancelling_headphones_compared" class="wikilink1" title="blog:2021-10:15-noise_cancelling_headphones_compared" data-wiki-id="blog:2021-10:15-noise_cancelling_headphones_compared">Sony headphones</a> but the actual audio connection wouldn&#039;t work until after a reboot 🤷♂️. </p> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Bluetooth&quot;,&quot;hid&quot;:&quot;bluetooth&quot;,&quot;codeblockOffset&quot;:20,&quot;secid&quot;:13,&quot;range&quot;:&quot;17300-17734&quot;} --> <h2 class="sectionedit14" id="fingerprint_sensor">Fingerprint Sensor</h2> <div class="level2"> <p> The Framework 13 has a built-in fingerprint reader: </p> <pre class="code">Bus 003 Device 003: ID 27c6:609c Shenzhen Goodix Technology Co.,Ltd. Goodix Fingerprint USB Device</pre> <p> It should work fine with the fprint daemon, but since I am logging into Xorg automatically and the LUKS passphrase is queried long before the system and fprint are initialized, there&#039;s not much sense in setting that up. </p> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Fingerprint Sensor&quot;,&quot;hid&quot;:&quot;fingerprint_sensor&quot;,&quot;codeblockOffset&quot;:20,&quot;secid&quot;:14,&quot;range&quot;:&quot;17735-18142&quot;} --> <h2 class="sectionedit15" id="bios_update_again">BIOS Update again</h2> <div class="level2"> <p> With the system running and no answer to my forum post, I decided to tackle the BIOS update again. This time not using the EFI shell but doing it from the installed system. </p> <p> First install the needed packages and check the firmware version. </p> <pre class="code">$&gt; sudo pacman -S dmidecode fwupd $&gt; sudo dmidecode -s bios-version 03.03</pre> <p> Then basically </p> <pre class="code">$ fwupdmgr get-devices $ fwupdmgr refresh $ fwupdmgr get-updates $ sudo fwupdmgr update</pre> <p> Reboot and the familiar update screen will pop up again. However this time it worked. As confirmed after booting into Arch again: </p> <pre class="code">$ sudo dmidecode -s bios-version 03.04</pre> <p> I think something in the update process did not like that there was only an UEFI partition on the USB stick but not on the main disk, yet. </p> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;BIOS Update again&quot;,&quot;hid&quot;:&quot;bios_update_again&quot;,&quot;codeblockOffset&quot;:20,&quot;secid&quot;:15,&quot;range&quot;:&quot;18143-18924&quot;} --> <h2 class="sectionedit16" id="sensors">Sensors</h2> <div class="level2"> <p> When using the <code>sensors</code> command from the <code>lm_sensors</code> package, a whole bunch of them are reported. </p> <pre class="file">ucsi_source_psy_USBC000:004-isa-0000 Adapter: ISA adapter in0: 20.00 V (min = +5.00 V, max = +38.80 V) curr1: 2.25 A (max = +3.16 A) ucsi_source_psy_USBC000:001-isa-0000 Adapter: ISA adapter in0: 0.00 V (min = +0.00 V, max = +0.00 V) curr1: 0.00 A (max = +0.00 A) iwlwifi_1-virtual-0 Adapter: Virtual device temp1: +55.0°C spd5118-i2c-14-50 Adapter: SMBus I801 adapter at efa0 temp1: +50.5°C (low = +0.0°C, high = +55.0°C) (crit low = +0.0°C, crit = +85.0°C) coretemp-isa-0000 Adapter: ISA adapter Package id 0: +56.0°C (high = +110.0°C, crit = +110.0°C) Core 0: +52.0°C (high = +110.0°C, crit = +110.0°C) Core 1: +51.0°C (high = +110.0°C, crit = +110.0°C) Core 2: +52.0°C (high = +110.0°C, crit = +110.0°C) Core 3: +52.0°C (high = +110.0°C, crit = +110.0°C) Core 4: +51.0°C (high = +110.0°C, crit = +110.0°C) Core 5: +52.0°C (high = +110.0°C, crit = +110.0°C) Core 6: +52.0°C (high = +110.0°C, crit = +110.0°C) Core 7: +52.0°C (high = +110.0°C, crit = +110.0°C) Core 8: +57.0°C (high = +110.0°C, crit = +110.0°C) Core 12: +51.0°C (high = +110.0°C, crit = +110.0°C) Core 16: +54.0°C (high = +110.0°C, crit = +110.0°C) Core 20: +51.0°C (high = +110.0°C, crit = +110.0°C) Core 24: +51.0°C (high = +110.0°C, crit = +110.0°C) Core 28: +50.0°C (high = +110.0°C, crit = +110.0°C) Core 32: +55.0°C (high = +110.0°C, crit = +110.0°C) Core 33: +55.0°C (high = +110.0°C, crit = +110.0°C) BAT1-acpi-0 Adapter: ACPI interface in0: 16.21 V curr1: 1.96 A acpi_fan-acpi-0 Adapter: ACPI interface fan1: 0 RPM power1: 0.00 W cros_ec-isa-0000 Adapter: ISA adapter fan1: 0 RPM local_f75397@4c: +44.9°C cpu_f75303@4d: +47.9°C battery_temp@b: +39.9°C ddr_f75303@4d: +42.9°C peci-temp: +54.9°C ucsi_source_psy_USBC000:003-isa-0000 Adapter: ISA adapter in0: 5.00 V (min = +5.00 V, max = +5.00 V) curr1: 0.00 A (max = +3.00 A) spd5118-i2c-14-52 Adapter: SMBus I801 adapter at efa0 temp1: +49.2°C (low = +0.0°C, high = +55.0°C) (crit low = +0.0°C, crit = +85.0°C) ucsi_source_psy_USBC000:002-isa-0000 Adapter: ISA adapter in0: 0.00 V (min = +0.00 V, max = +0.00 V) curr1: 680.00 mA (max = +0.00 A) nvme-pci-a900 Adapter: PCI adapter Composite: +45.9°C (low = -5.2°C, high = +89.8°C) (crit = +93.8°C) acpitz-acpi-0 Adapter: ACPI interface temp1: +54.8°C temp2: +47.9°C temp3: +42.9°C temp4: +44.9°C temp5: +40.0°C acpi_fan-acpi-0 Adapter: ACPI interface fan1: N/A power1: N/A</pre> <p> I asked in a <a href="https://community.frame.work/t/sensors-explanation/64784" class="urlextern" title="https://community.frame.work/t/sensors-explanation/64784">forum thread</a> about what the different values represent. It seems most important are the <code>coretemp</code> values (with <code>Package id 0</code> being the overall processor temperature as reported by the CPU itself) and the values in <code>cros_ec</code> which are sensors near components on the motherboard, including the current fan speed. </p> <p> You can easily add any of those sensors to an XFCE panel using the <code>xfce4-sensors-plugin</code>. </p> <div class="inline dataplugin_entry blogtags sectionedit17"><dl><dt class="tags">Tags<span class="sep">: </span></dt><dd class="tags"><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dframework" title="Show pages matching 'framework'" class="wikilink1">framework</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dlaptop" title="Show pages matching 'laptop'" class="wikilink1">laptop</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dnotebook" title="Show pages matching 'notebook'" class="wikilink1">notebook</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Darchlinux" title="Show pages matching 'archlinux'" class="wikilink1">archlinux</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dhowto" title="Show pages matching 'howto'" class="wikilink1">howto</a></dd></dl></div><!-- EDIT{&quot;target&quot;:&quot;plugin_data&quot;,&quot;hid&quot;:&quot;data_entry&quot;,&quot;secid&quot;:17,&quot;range&quot;:&quot;22458-22548&quot;} --><dl class="blogrelated"><dt>Similar posts:</dt><dd><ul> <li class="level1"><a href="https://www.splitbrain.org/blog/2019-01/03-one_mix_yoga_2" class="wikilink1" title="blog:2019-01:03-one_mix_yoga_2" data-wiki-id="blog:2019-01:03-one_mix_yoga_2">One-Mix Yoga 2</a></li> <li class="level1"><a href="https://www.splitbrain.org/blog/2018-06/21-thinkpad_x240_arch_linux" class="wikilink1" title="blog:2018-06:21-thinkpad_x240_arch_linux" data-wiki-id="blog:2018-06:21-thinkpad_x240_arch_linux">Thinkpad X240 Arch Linux</a></li> <li class="level1"><a href="https://www.splitbrain.org/blog/2014-03/08-lenovo_thinkpad_x240_xubuntu" class="wikilink1" title="blog:2014-03:08-lenovo_thinkpad_x240_xubuntu" data-wiki-id="blog:2014-03:08-lenovo_thinkpad_x240_xubuntu">Lenovo Thinkpad X240 &amp; Xubuntu</a></li> </ul> </dd></dl> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Sensors&quot;,&quot;hid&quot;:&quot;sensors&quot;,&quot;codeblockOffset&quot;:20,&quot;secid&quot;:16,&quot;range&quot;:&quot;18925-&quot;} --><p align="right"><a href="https://www.splitbrain.org/blog/2025-02/17-framework_13_intel_core_ultra_archlinux#comments">Add or read comments to this article &raquo;&raquo;</a></p><p><small>Copyright © 2025 Andreas Gohr<br />This feed is for personal, non commercial use in the subscriber's feedreader only.<br />All contents (especially texts and images) are protected by copyright law and may not be republished outside of splitbrain.org without prior consent. Texts may be quoted in extracts under fair use policy. [digital fingerprint: sb97741286f601b4a0d496dc8bae242e6d]</small></p></description> <author>andi@undisclosed.example.com (andi)</author> <pubDate>Thu, 20 Feb 2025 07:44:57 +0000</pubDate> </item> <item> <title>Gnome Keyring SSH Agent on Arch XFCE</title> <link>https://www.splitbrain.org/blog/2025-02/19-gnome_keyring_ssh_agent_archlinux_xfce</link> <description> <h1 class="sectionedit1" id="gnome_keyring_ssh_agent_on_arch_xfce">Gnome Keyring SSH Agent on Arch XFCE</h1> <div class="level1"> <p> I have been using <a href="https://www.funtoo.org/Funtoo:Keychain" class="urlextern" title="https://www.funtoo.org/Funtoo:Keychain">Keychain</a> for years to automatically start an SSH agent and unlock my SSH keys. </p> <p> But when I was <a href="https://www.splitbrain.org/blog/2025-02/17-framework_13_intel_core_ultra_archlinux" class="wikilink1" title="blog:2025-02:17-framework_13_intel_core_ultra_archlinux" data-wiki-id="blog:2025-02:17-framework_13_intel_core_ultra_archlinux">setting up my new Laptop</a> and fiddling with unlocking the Gnome Keyring, I was wondering why I wasn&#039;t using it for my SSH keys as well. </p> <p> It took me a while to get it to work. My first issue was, that even after removing Keychain, something was starting an SSH agent and I wasn&#039;t sure where it came from. </p> <p> It turns out, that XFCE starts an SSH agent by default. There are <a href="https://docs.xfce.org/xfce/xfce4-session/advanced#ssh_and_gpg_agents" class="urlextern" title="https://docs.xfce.org/xfce/xfce4-session/advanced#ssh_and_gpg_agents">ways to disable this behaviour</a> using xconf-query. But the easiest way is to go to <em>Session and Startup</em> → <em>Advanced</em> → <em>Launch GNOME services on startup</em> and tick the checkbox. </p> <p> This disables the automated starting of a normal SSH agent by XFCE itself. This will also start the Gnome Keyring daemon by default, but upstream recently changed it&#039;s default behaviour to not start the SSH agent with it. </p> <p> Theoretically there&#039;s an entry labelled “SSH Key Agent (GNOME Keyring: SSH Agent)” under <em>Session and Startup</em> → <em>Application Autostart</em> but for me that did nothing. </p> <p> What worked for me was starting the ssh agent component using a user systemd unit (I was not even aware that this is a thing before). </p> <pre class="code">systemctl --user enable gcr-ssh-agent.socket systemctl --user start gcr-ssh-agent.socket</pre> <p> This starts the agent and should theoretically register an environment variable telling SSH about the agent. Again this did not work for me. So I register it my self in my <code>.xprofile</code>: </p> <dl class="code"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/19-gnome_keyring_ssh_agent_archlinux_xfce?codeblock=0" title="Download Snippet" class="mediafile mf_xprofile">~/.xprofile</a></dt> <dd><pre class="code bash"><span class="co0"># register gnome keyring ssh manager</span> <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re5">-e</span> <span class="re1">$XDG_RUNTIME_DIR</span><span class="sy0">/</span>gcr<span class="sy0">/</span><span class="kw2">ssh</span> <span class="br0">&#93;</span>; <span class="kw1">then</span> <span class="kw3">export</span> <span class="re2">SSH_AUTH_SOCK</span>=<span class="re1">$XDG_RUNTIME_DIR</span><span class="sy0">/</span>gcr<span class="sy0">/</span><span class="kw2">ssh</span> <span class="kw1">fi</span></pre> </dd></dl> <p> Now, when you connect to an SSH server, a graphical dialog will pop up to unlock your key, with an option to save the password in the keyring. </p> <p> This really should not be that difficult and I suspect there&#039;s something buggy that prevents this all working out of the box. </p> <div class="inline dataplugin_entry blogtags sectionedit2"><dl><dt class="tags">Tags<span class="sep">: </span></dt><dd class="tags"><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Darchlinux" title="Show pages matching 'archlinux'" class="wikilink1">archlinux</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dxfce" title="Show pages matching 'xfce'" class="wikilink1">xfce</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dssh" title="Show pages matching 'ssh'" class="wikilink1">ssh</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dhowto" title="Show pages matching 'howto'" class="wikilink1">howto</a></dd></dl></div><!-- EDIT{&quot;target&quot;:&quot;plugin_data&quot;,&quot;hid&quot;:&quot;data_entry&quot;,&quot;secid&quot;:2,&quot;range&quot;:&quot;2146-2218&quot;} --><dl class="blogrelated"><dt>Similar posts:</dt><dd><ul> <li class="level1"><a href="https://www.splitbrain.org/blog/2025-02/17-framework_13_intel_core_ultra_archlinux" class="wikilink1" title="blog:2025-02:17-framework_13_intel_core_ultra_archlinux" data-wiki-id="blog:2025-02:17-framework_13_intel_core_ultra_archlinux">FrameWork 13 (Intel Ultra) &amp; ArchLinux</a></li> <li class="level1"><a href="https://www.splitbrain.org/blog/2019-01/03-one_mix_yoga_2" class="wikilink1" title="blog:2019-01:03-one_mix_yoga_2" data-wiki-id="blog:2019-01:03-one_mix_yoga_2">One-Mix Yoga 2</a></li> <li class="level1"><a href="https://www.splitbrain.org/blog/2018-06/21-thinkpad_x240_arch_linux" class="wikilink1" title="blog:2018-06:21-thinkpad_x240_arch_linux" data-wiki-id="blog:2018-06:21-thinkpad_x240_arch_linux">Thinkpad X240 Arch Linux</a></li> </ul> </dd></dl> </div> <p align="right"><a href="https://www.splitbrain.org/blog/2025-02/19-gnome_keyring_ssh_agent_archlinux_xfce#comments">Add or read comments to this article &raquo;&raquo;</a></p><p><small>Copyright © 2025 Andreas Gohr<br />This feed is for personal, non commercial use in the subscriber's feedreader only.<br />All contents (especially texts and images) are protected by copyright law and may not be republished outside of splitbrain.org without prior consent. Texts may be quoted in extracts under fair use policy. [digital fingerprint: sb97741286f601b4a0d496dc8bae242e6d]</small></p></description> <author>andi@undisclosed.example.com (andi)</author> <pubDate>Wed, 19 Feb 2025 17:13:13 +0000</pubDate> </item> <item> <title>Fish Shell</title> <link>https://www.splitbrain.org/blog/2025-02/16-fish_shell</link> <description> <h1 class="sectionedit1" id="fish_shell">Fish Shell</h1> <div class="level1"> <p> I am using Bash as my shell for as long as I am using Linux. </p> <p> Over the years I had customized it quite a lot by making my <code>.bashrc</code> load a whole bunch of scripts from a <code>~/.bashrc.d</code> directory. It worked fine but of course there is only so much you can do with simple aliases and function definitions… </p> <p> I saw many of my friends switch to zsh, but every time I looked into it I was overwhelmed by its configuration and I wasn&#039;t convinced by the “just use oh-my-zsh” argument. </p> <p> <img src="https://www.splitbrain.org/_media/blog/2025-02/fish_logo.svg?w=200&amp;tok=ad67c8" class="mediaright" align="right" loading="lazy" title="Fish Shell" alt="Fish Shell" width="200" /> When I stumbled on <a href="https://fishshell.com/" class="urlextern" title="https://fishshell.com/">Fish</a> I was intrigued by it&#039;s features and easy configuration approach. I gave it a few halfhearted tries in the past but having to port over my collection of accumulated Bash configs was always holding me back from switching for reals. </p> <p> This weekend I finally got around to properly switch to Fish. Fish already has the same concept for customizing that I used in Bash by providing a <code>~/.config/fish/conf.d</code> directory from which any <code>.fish</code> file is loaded automatically. So I spent some time to port over by bash scripts. </p> <p> Initially I used ChatGPT to help me with the porting, but after a few scripts I quickly got the knack of it myself. It&#039;s different but not overly complicated. </p> <hr /> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Fish Shell&quot;,&quot;hid&quot;:&quot;fish_shell&quot;,&quot;codeblockOffset&quot;:0,&quot;secid&quot;:1,&quot;range&quot;:&quot;1-1303&quot;} --> <h2 class="sectionedit2" id="prompt_setup">Prompt Setup</h2> <div class="level2"> <p> I spent most of the time fiddling with my prompt setup. Here&#039;s what I got so far: </p> <p> <img src="https://www.splitbrain.org/_media/blog/2025-02/fishprompt.png" class="mediacenter" loading="lazy" alt="" /> </p> <p> The left hand side shows: </p> <ul> <li class="level1"><div class="li"> The time when the prompt was shown. I sometimes uses this when I have to book my time at work and need to figure out when I started on a particular task.</div> </li> <li class="level1"><div class="li"> The current user. Normally in green, but highlighted in red when I&#039;m root</div> </li> <li class="level1"><div class="li"> The hostname. White for the local machine, highlighted in magenta when on a remote host (this of course depends on me being logged into a machine with my fish setup)</div> </li> <li class="level1"><div class="li"> The current path. Only the last three segments are shown in full, if it gets longer the initial segments are abbreviated.</div> </li> <li class="level1"><div class="li"> The last non-zero return code is shown in red</div> </li> </ul> <p> Fish also supports a right hand side prompt. I configured this to show: </p> <ul> <li class="level1"><div class="li"> The currently activated Python virtual environment (if any)</div> </li> <li class="level1"><div class="li"> The current git branch and dirty status (if any)</div> </li> </ul> <p> Finally there&#039;s a greeting message. Here I simply highlight if I working local or remotely again. I might add other info here later. </p> <p> The code for all of this wasn&#039;t too terrible to come up with. </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/16-fish_shell?codeblock=0" title="Download Snippet" class="mediafile mf_fish">.config/fish/conf.d/30-prompt.fish</a></dt> <dd><pre class="code file fish">set -g VIRTUAL_ENV_DISABLE_PROMPT true set -g __fish_git_prompt_showdirtystate true set -g __fish_git_prompt_showcolorhints true set -g __fish_git_prompt_showupstream auto set -g __fish_git_prompt_char_stateseparator '' &nbsp; function fish_prompt --description 'Write out the prompt' set -l last_pipestatus $pipestatus set -lx __fish_last_status $status # Export for __fish_print_pipestatus. set -l normal (set_color normal) set -q fish_color_status or set -g fish_color_status red &nbsp; # Get the current time in HHMM format set -l current_time (date '+%H%M') set -l time_color (set_color brblue) &nbsp; # Highlight root with bright red background set -l suffix '&gt;' set -l user_color (set_color $fish_color_user) if fish_is_root_user set user_color $normal (set_color -b brred) set suffix '#' end &nbsp; # On remote connections color the host name set -l host_color $normal if set -q SSH_TTY set host_color $normal (set_color -b magenta) end &nbsp; # Write pipestatus set -l bold_flag --bold set -q __fish_prompt_status_generation; or set -g __fish_prompt_status_generation $status_generation if test $__fish_prompt_status_generation = $status_generation set bold_flag end set __fish_prompt_status_generation $status_generation set -l status_color (set_color $fish_color_status) set -l statusb_color (set_color $bold_flag $fish_color_status) set -l prompt_status (__fish_print_pipestatus &quot;[&quot; &quot;]&quot; &quot;|&quot; &quot;$status_color&quot; &quot;$statusb_color&quot; $last_pipestatus) &nbsp; echo -n -s $time_color $current_time $normal echo -n -s $user_color (whoami) $host_color '@' (prompt_hostname) ':' $normal echo -n -s (set_color $fish_color_cwd) (prompt_pwd --full-length-dirs 3) $normal echo -n -s $prompt_status echo -n -s $suffix &quot; &quot; end &nbsp; function fish_right_prompt --description 'Right side prompt for Python venv and Git' set -l normal (set_color normal) &nbsp; # Show active Python virtual environment, if any if set -q VIRTUAL_ENV set -l venv (basename &quot;$VIRTUAL_ENV&quot;) set -l venv_color (set_color cyan) echo -n -s &quot;($venv_color$venv$normal)&quot; end &nbsp; # Show Git branch and status set -l git_info (fish_vcs_prompt) if test -n &quot;$git_info&quot; echo -n -s &quot;$git_info&quot; end end &nbsp; function fish_greeting set -l normal (set_color normal) &nbsp; set -l greeting_color (set_color cyan) set -l login_type &quot;💻 Local session on&quot; &nbsp; # Detect if logged in via SSH if set -q SSH_TTY set greeting_color (set_color brmagenta) set login_type &quot;🔮 SSH session on&quot; end &nbsp; # Get system information set -l host (prompt_hostname) # Get system hostname &nbsp; # Display greeting with system information echo -e &quot;$greeting_color$login_type $host$normal&quot; echo end</pre> </dd></dl> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Prompt Setup&quot;,&quot;hid&quot;:&quot;prompt_setup&quot;,&quot;codeblockOffset&quot;:0,&quot;secid&quot;:2,&quot;range&quot;:&quot;1304-5348&quot;} --> <h2 class="sectionedit3" id="daily_temp_dir">Daily Temp Dir</h2> <div class="level2"> <p> I am still using the <a href="https://www.splitbrain.org/blog/2008-02/27-keeping_your_home_directory_organized" class="urlextern" title="https://www.splitbrain.org/blog/2008-02/27-keeping_your_home_directory_organized">daily temp dir mechanism</a> I blogged about 17 years ago. Porting it to Fish was straight forward: </p> <dl class="file"> <dt><a href="https://www.splitbrain.org/_export/code/blog/2025-02/16-fish_shell?codeblock=1" title="Download Snippet" class="mediafile mf_fish">.config/fish/conf.d/80-tools.fish</a></dt> <dd><pre class="code file fish"># Daily temp dir set -gx TD &quot;$HOME/temp/$(date +'%Y-%m-%d')&quot; &nbsp; function td set td $TD if test -n &quot;$argv[1]&quot; set td &quot;$HOME/temp/$(date -d &quot;$argv[1] days&quot; +'%Y-%m-%d')&quot; else ln -s -f -T $td &quot;$HOME/temp/00-today&quot; end mkdir -p $td cd $td end</pre> </dd></dl> <div class="inline dataplugin_entry blogtags sectionedit4"><dl></dl></div><!-- EDIT{&quot;target&quot;:&quot;plugin_data&quot;,&quot;hid&quot;:&quot;data_entry&quot;,&quot;secid&quot;:4,&quot;range&quot;:&quot;5914-5959&quot;} --> </div> <!-- EDIT{&quot;target&quot;:&quot;section&quot;,&quot;name&quot;:&quot;Daily Temp Dir&quot;,&quot;hid&quot;:&quot;daily_temp_dir&quot;,&quot;codeblockOffset&quot;:1,&quot;secid&quot;:3,&quot;range&quot;:&quot;5349-&quot;} --><p align="right"><a href="https://www.splitbrain.org/blog/2025-02/16-fish_shell#comments">Add or read comments to this article &raquo;&raquo;</a></p><p><small>Copyright © 2025 Andreas Gohr<br />This feed is for personal, non commercial use in the subscriber's feedreader only.<br />All contents (especially texts and images) are protected by copyright law and may not be republished outside of splitbrain.org without prior consent. Texts may be quoted in extracts under fair use policy. [digital fingerprint: sb97741286f601b4a0d496dc8bae242e6d]</small></p></description> <author>andi@undisclosed.example.com (andi)</author> <pubDate>Sun, 16 Feb 2025 14:26:07 +0000</pubDate> </item> <item> <title>The Enshittification of IKEA</title> <link>https://www.splitbrain.org/blog/2025-02/10-the_enshittification_of_ikea</link> <description> <h1 class="sectionedit1" id="the_enshittification_of_ikea">The Enshittification of IKEA</h1> <div class="level1"> <p> Remember when IKEA was good? I know, everyone joked about the labyrinthine shop layout and how you ended up with more in your big blue plastic bag than you had planned, but overall it was good. You got decent stuff for affordable prices and the shopping was a family experience. Complete with either a full meal or at least a snack at the end (or even both). </p> <p> Nowadays every single aspect of IKEA sucks. </p> <hr /> <p> Not only have prices increased over the years but the quality seems to have gone down as well. With everything made from real wood getting flimsier and flimsier and real wood products becoming rarer. </p> <p> Availability sucks, too. Back in the day you browsed through the (paper) catalog beforehand and you could be pretty sure to be able to just go to your nearest IKEA and just pick it up. Nowadays it&#039;s entirely random what is and what is not available. </p> <p> IKEA used to be really good at systems. You could start small and over the years add to and reconfigure your furniture. By simply staying in the same system like “IVAR”, “Hemnes” or “Pax” you could recombine and extend everything into near endless possibilities. </p> <p> Today products seem to be introduced and discontinued on a weekly basis. You might have bought something last week only to find that the same color is no longer available this week. You want to replace one of your broken coffee mugs? Sorry we don&#039;t have those anymore. </p> <p> Even when you order stuff online, it is not unusual that parts of your desired furniture are unavailable. Sure you can buy your whole kitchen at IKEA, but you might end up with a kitchen missing the countertops for a couple of months. </p> <p> Back in the store, even when you found what you wanted, you still have to deal with the checkouts. Regardless of the time and day of the week, most checkouts are closed. Even most of the self service checkouts will be closed in favor of their new method where you need to use their app to scan all the products. It doesn&#039;t speed up anything – on the contrary: people are slower on their phones than with a dedicated bar code scanner. But of cause corporate can now track individuals with each purchase… </p> <p> How about Food? Everyone&#039;s favorite meatball dish has been through many, many iterations over the years, with the meatballs having reduced in size and the side veggies seeming to change every year. It&#039;s still your best choice with other options having decreased in quality much more in my opinion. Hot dogs have doubled in price, but you can order by touchscreen now. Progress! </p> <p> Worst annoyance in the restaurant are the drink dispensers where they changed machines with 5 nozzles and 5 buttons to ones with a single nozzle and a shitty touchscreen. Not only are drinks now cross contaminated, queues are also longer. Because where the old machines let two, sometimes three people pour drinks simultaneously, now everyone has to wait in line. It doesn&#039;t help that the touchscreens are unresponsive crap. But I bet the data collection is great. </p> <p> And then finally there&#039;s the service. You think you can just pickup a new trap for your sink because it&#039;s common between all IKEA sinks? Maybe in the past. Now it&#039;s a replacement part that has to be ordered and is a whopping 40 EUR plus shipping (while a similar one, but of course not fitting for an IKEA sink, costs 10 EUR at the hardware store). </p> <p> And god help you, if you need to return something. Be prepared to spend literal hours in the service area after you dutifully got a number from another touchscreen device. Said device will ask you about your type of required service and based on that put you in a different range of numbers. Only that all of them are serviced by the same staff. It has no purpose other than more data tracking. </p> <p> Of course the service area is totally understaffed. Be happy if half the service desks are staffed. Naturally you can also book appointments online, because that improves the data tracking and again connects identities to purchases. And of course those online appointments are handled by the same staff, making wait times for everyone else even longer. </p> <p> Oh did I mention that you will stand while waiting for service? Not because IKEA doesn&#039;t have any idea how to make a space comfortable, but because they want you to give up. And when you finally do, they will know that they were successful, because they have that number and the reason you provided when you touched that virtual button. An hour ago, when – still reminiscent of an IKEA long gone – you expected some actual service… </p> <div class="inline dataplugin_entry blogtags sectionedit2"><dl><dt class="tags">Tags<span class="sep">: </span></dt><dd class="tags"><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Drant" title="Show pages matching 'rant'" class="wikilink1">rant</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Denshittification" title="Show pages matching 'enshittification'" class="wikilink1">enshittification</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dikea" title="Show pages matching 'ikea'" class="wikilink1">ikea</a><span class="sep">, </span><a href="https://www.splitbrain.org/tags?dataflt%5B0%5D=tags_%3Dtracking" title="Show pages matching 'tracking'" class="wikilink1">tracking</a></dd></dl></div><!-- EDIT{&quot;target&quot;:&quot;plugin_data&quot;,&quot;hid&quot;:&quot;data_entry&quot;,&quot;secid&quot;:2,&quot;range&quot;:&quot;4569-4652&quot;} --><dl class="blogrelated"><dt>Similar posts:</dt><dd><ul> <li class="level1"><a href="https://www.splitbrain.org/blog/2023-04/04-solar" class="wikilink1" title="blog:2023-04:04-solar" data-wiki-id="blog:2023-04:04-solar">Solar</a></li> <li class="level1"><a href="https://www.splitbrain.org/blog/2016-11/21-my_3d_printer_sucks" class="wikilink1" title="blog:2016-11:21-my_3d_printer_sucks" data-wiki-id="blog:2016-11:21-my_3d_printer_sucks">My 3D Printer sucks</a></li> <li class="level1"><a href="https://www.splitbrain.org/blog/2016-07/08-pokemon_go" class="wikilink1" title="blog:2016-07:08-pokemon_go" data-wiki-id="blog:2016-07:08-pokemon_go">Pokémon GO</a></li> </ul> </dd></dl> </div> <p align="right"><a href="https://www.splitbrain.org/blog/2025-02/10-the_enshittification_of_ikea#comments">Add or read comments to this article &raquo;&raquo;</a></p><p><small>Copyright © 2025 Andreas Gohr<br />This feed is for personal, non commercial use in the subscriber's feedreader only.<br />All contents (especially texts and images) are protected by copyright law and may not be republished outside of splitbrain.org without prior consent. Texts may be quoted in extracts under fair use policy. [digital fingerprint: sb97741286f601b4a0d496dc8bae242e6d]</small></p></description> <author>andi@undisclosed.example.com (andi)</author> <pubDate>Mon, 10 Feb 2025 17:50:34 +0000</pubDate> </item> <item> <title>Lego Advent Calendar</title> <link>https://www.splitbrain.org/blog/2024-12/26-lego_advent_calendar</link> <description> <h1 class="sectionedit1" id="lego_advent_calendar">Lego Advent Calendar</h1> <div class="level1"> <p> Every year, my lovely wife prepares a custom advent calendar for me. And, because I loved it as a kid and still do, she puts Lego in it. Everyday, I get a few more pieces and build a new model. At the last day I get the manual and build the actual set. It&#039;s great fun. </p> <p> This year&#039;s set was <a href="https://brickset.com/sets/60431-1/Space-Explorer-Rover-and-Alien-Life" class="urlextern" title="https://brickset.com/sets/60431-1/Space-Explorer-Rover-and-Alien-Life">Set 60431: Space Explorer and Alien Life</a>. </p> <p> Here are all the things I built: </p> <div id="plugin__gallery_e6d4" class="plugin-gallery align-full"><div class="gallery-page" id="gallery__e6d4_0" style="grid-template-columns: repeat(auto-fill, minmax(150px, 1fr))"><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241201_145539451.portrait.original.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 1: Owl" data-caption="&lt;b&gt;Day 1: Owl&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241201_145539451.portrait.original.jpg?w=750&amp;h=1000&amp;tok=20587a"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241201_145539451.portrait.original.jpg?w=300&amp;h=300&amp;tok=619eb8" alt="pxl_20241201_145539451.portrait.original.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241202_081658950.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 2: Satellite Antenna" data-caption="&lt;b&gt;Day 2: Satellite Antenna&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241202_081658950.portrait.jpg?w=750&amp;h=1000&amp;tok=b0e44c"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241202_081658950.portrait.jpg?w=300&amp;h=300&amp;tok=5fef6e" alt="pxl_20241202_081658950.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241203_120734492.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 3: Helicopter" data-caption="&lt;b&gt;Day 3: Helicopter&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241203_120734492.portrait.jpg?w=750&amp;h=1000&amp;tok=75755c"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241203_120734492.portrait.jpg?w=300&amp;h=300&amp;tok=fae07b" alt="pxl_20241203_120734492.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241205_074936954.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 4: One-Wheel" data-caption="&lt;b&gt;Day 4: One-Wheel&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241205_074936954.portrait.jpg?w=750&amp;h=1000&amp;tok=d8695d"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241205_074936954.portrait.jpg?w=300&amp;h=300&amp;tok=362e94" alt="pxl_20241205_074936954.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241205_080238790.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 5: Rocket-Ship" data-caption="&lt;b&gt;Day 5: Rocket-Ship&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241205_080238790.portrait.jpg?w=1333&amp;h=1000&amp;tok=5112b8"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241205_080238790.portrait.jpg?w=300&amp;h=300&amp;tok=bcb347" alt="pxl_20241205_080238790.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241206_075111350.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 6: Rocket Glider" data-caption="&lt;b&gt;Day 6: Rocket Glider&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241206_075111350.portrait.jpg?w=1333&amp;h=1000&amp;tok=57f2e1"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241206_075111350.portrait.jpg?w=300&amp;h=300&amp;tok=6c606f" alt="pxl_20241206_075111350.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241207_093602695.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 7: Research Station" data-caption="&lt;b&gt;Day 7: Research Station&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241207_093602695.jpg?w=1333&amp;h=1000&amp;tok=0d0f79"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241207_093602695.jpg?w=300&amp;h=300&amp;tok=a74553" alt="pxl_20241207_093602695.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241208_132053563.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 8: Speed Boat" data-caption="&lt;b&gt;Day 8: Speed Boat&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241208_132053563.portrait.jpg?w=1333&amp;h=1000&amp;tok=6a2862"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241208_132053563.portrait.jpg?w=300&amp;h=300&amp;tok=3e4dab" alt="pxl_20241208_132053563.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241209_083302647.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 9: Satellite" data-caption="&lt;b&gt;Day 9: Satellite&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241209_083302647.portrait.jpg?w=1333&amp;h=1000&amp;tok=0d1fcd"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241209_083302647.portrait.jpg?w=300&amp;h=300&amp;tok=3b2a1e" alt="pxl_20241209_083302647.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241210_185244409.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 10: Alien Drag Racer" data-caption="&lt;b&gt;Day 10: Alien Drag Racer&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241210_185244409.portrait.jpg?w=1333&amp;h=1000&amp;tok=669aed"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241210_185244409.portrait.jpg?w=300&amp;h=300&amp;tok=e7647f" alt="pxl_20241210_185244409.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241211_184555846.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 11: Rocket Train" data-caption="&lt;b&gt;Day 11: Rocket Train&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241211_184555846.portrait.jpg?w=1333&amp;h=1000&amp;tok=5ae53a"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241211_184555846.portrait.jpg?w=300&amp;h=300&amp;tok=9e73d7" alt="pxl_20241211_184555846.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241212_145857389.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 12: Mr. Potato Head" data-caption="&lt;b&gt;Day 12: Mr. Potato Head&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241212_145857389.portrait.jpg?w=1333&amp;h=1000&amp;tok=1fce8d"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241212_145857389.portrait.jpg?w=300&amp;h=300&amp;tok=508f7b" alt="pxl_20241212_145857389.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241213_144749873.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 13: Space Hearse" data-caption="&lt;b&gt;Day 13: Space Hearse&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241213_144749873.portrait.jpg?w=1333&amp;h=1000&amp;tok=743741"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241213_144749873.portrait.jpg?w=300&amp;h=300&amp;tok=2fe1b1" alt="pxl_20241213_144749873.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241214_154004939.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 14: Sand Speeder" data-caption="&lt;b&gt;Day 14: Sand Speeder&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241214_154004939.portrait.jpg?w=1333&amp;h=1000&amp;tok=5b0e53"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241214_154004939.portrait.jpg?w=300&amp;h=300&amp;tok=3debf2" alt="pxl_20241214_154004939.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241215_164123665_2.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 15: Helicopter" data-caption="&lt;b&gt;Day 15: Helicopter&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241215_164123665_2.jpg?w=1333&amp;h=1000&amp;tok=18b6d0"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241215_164123665_2.jpg?w=300&amp;h=300&amp;tok=46ad7c" alt="pxl_20241215_164123665_2.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241216_155257163.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 16: Speed Boat 2" data-caption="&lt;b&gt;Day 16: Speed Boat 2&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241216_155257163.portrait.jpg?w=1333&amp;h=1000&amp;tok=3c2b8d"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241216_155257163.portrait.jpg?w=300&amp;h=300&amp;tok=abb0a3" alt="pxl_20241216_155257163.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241217_190813581.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 17: Robosaurus" data-caption="&lt;b&gt;Day 17: Robosaurus&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241217_190813581.portrait.jpg?w=1333&amp;h=1000&amp;tok=54ec5e"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241217_190813581.portrait.jpg?w=300&amp;h=300&amp;tok=6911f6" alt="pxl_20241217_190813581.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241218_180425566.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 18: Royal Coach" data-caption="&lt;b&gt;Day 18: Royal Coach&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241218_180425566.jpg?w=1333&amp;h=1000&amp;tok=98fcd9"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241218_180425566.jpg?w=300&amp;h=300&amp;tok=3a2f0c" alt="pxl_20241218_180425566.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241219_144250977.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 19: Safari Buggy" data-caption="&lt;b&gt;Day 19: Safari Buggy&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241219_144250977.portrait.jpg?w=1333&amp;h=1000&amp;tok=19c971"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241219_144250977.portrait.jpg?w=300&amp;h=300&amp;tok=9ee8a8" alt="pxl_20241219_144250977.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241220_171353151.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 20: We need to go higher" data-caption="&lt;b&gt;Day 20: We need to go higher&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241220_171353151.portrait.jpg?w=750&amp;h=1000&amp;tok=3fd59e"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241220_171353151.portrait.jpg?w=300&amp;h=300&amp;tok=a40996" alt="pxl_20241220_171353151.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241221_162656761.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 21: Guarded Space Transport" data-caption="&lt;b&gt;Day 21: Guarded Space Transport&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241221_162656761.portrait.jpg?w=1333&amp;h=1000&amp;tok=1d941e"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241221_162656761.portrait.jpg?w=300&amp;h=300&amp;tok=a14379" alt="pxl_20241221_162656761.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241222_221054245.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 22: Wingmen" data-caption="&lt;b&gt;Day 22: Wingmen&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241222_221054245.portrait.jpg?w=1333&amp;h=1000&amp;tok=b8a34f"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241222_221054245.portrait.jpg?w=300&amp;h=300&amp;tok=030ff1" alt="pxl_20241222_221054245.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241223_115645866.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 23: Mech Warrior" data-caption="&lt;b&gt;Day 23: Mech Warrior&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241223_115645866.portrait.jpg?w=750&amp;h=1000&amp;tok=cb63b5"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241223_115645866.portrait.jpg?w=300&amp;h=300&amp;tok=170bc0" alt="pxl_20241223_115645866.portrait.jpg" loading="lazy" /></a></figure><figure class="gallery-image"><a href="https://www.splitbrain.org/_detail/blog/2024-12/lego/pxl_20241223_130342286.portrait.jpg?id=blog%3A2024-12%3A26-lego_advent_calendar" title="Day 24: Space Rover" data-caption="&lt;b&gt;Day 24: Space Rover&lt;/b&gt;" class="lightbox JSnocheck" rel="lightbox[gal-511133cb40d4ab3d4ad7b3da9020]" data-url="/_media/blog/2024-12/lego/pxl_20241223_130342286.portrait.jpg?w=1333&amp;h=1000&amp;tok=dd9520"><img width="300" height="300" src="/_media/blog/2024-12/lego/pxl_20241223_130342286.portrait.jpg?w=300&amp;h=300&amp;tok=edc265" alt="pxl_20241223_130342286.portrait.jpg" loading="lazy" /></a></figure></div></div><div class="inline dataplugin_entry blogtags sectionedit2"><dl></dl></div><!-- EDIT{&quot;target&quot;:&quot;plugin_data&quot;,&quot;hid&quot;:&quot;data_entry&quot;,&quot;secid&quot;:2,&quot;range&quot;:&quot;520-565&quot;} --> </div> <p align="right"><a href="https://www.splitbrain.org/blog/2024-12/26-lego_advent_calendar#comments">Add or read comments to this article &raquo;&raquo;</a></p><p><small>Copyright © 2025 Andreas Gohr<br />This feed is for personal, non commercial use in the subscriber's feedreader only.<br />All contents (especially texts and images) are protected by copyright law and may not be republished outside of splitbrain.org without prior consent. Texts may be quoted in extracts under fair use policy. [digital fingerprint: sb97741286f601b4a0d496dc8bae242e6d]</small></p></description> <author>andi@undisclosed.example.com (andi)</author> <pubDate>Thu, 26 Dec 2024 13:57:40 +0000</pubDate> </item> </channel> </rss>