<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Omarchy | AkitaOnRails.com</title><link>https://www.akitaonrails.com/en/tags/omarchy/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 25 Oct 2026 15:19:05 +0000</lastBuildDate><atom:link href="https://www.akitaonrails.com/en/tags/omarchy/index.xml" rel="self" type="application/rss+xml"/><item><title>Linux users: always choose BTRFS, not EXT4</title><link>https://www.akitaonrails.com/en/2026/10/12/linux-users-always-choose-btrfs-not-ext4/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/12/linux-users-always-choose-btrfs-not-ext4/</guid><pubDate>Mon, 12 Oct 2026 23:00:00 -0300</pubDate><description>&lt;p&gt;This post is a direct sequel to the &lt;a href="https://www.akitaonrails.com/en/2026/10/06/disaster-on-my-nas-how-i-almost-lost-90-tb-of-data/"&gt;disaster on my NAS&lt;/a&gt;. Summary for newcomers: my Synology, with eight drives in SHR (single parity), lost two drives in one strike during an upgrade. I survived thanks to an SHR implementation detail, bought a QNAP in a hurry, spent a week copying and verifying 91 TB, and lost not a single file by accident. The new QNAP runs ZFS in RAID-6; the rebuilt Synology now runs SHR-2.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post is a direct sequel to the <a href="/en/2026/10/06/disaster-on-my-nas-how-i-almost-lost-90-tb-of-data/">disaster on my NAS</a>. Summary for newcomers: my Synology, with eight drives in SHR (single parity), lost two drives in one strike during an upgrade. I survived thanks to an SHR implementation detail, bought a QNAP in a hurry, spent a week copying and verifying 91 TB, and lost not a single file by accident. The new QNAP runs ZFS in RAID-6; the rebuilt Synology now runs SHR-2.</p>
<p>Underneath this whole story there&rsquo;s a decision almost nobody makes consciously: <strong>the filesystem</strong>. The Synology used btrfs all along. The QNAP uses ZFS. And your Linux machine, most likely, came from the factory with ext4 without anyone asking you anything. That&rsquo;s what this is about.</p>
<h2>Where the two came from<span class="hx:absolute hx:-mt-20" id="where-the-two-came-from"></span>
    <a href="#where-the-two-came-from" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ext4 is the end of a dynasty of over three decades. ext (extended filesystem) was born with Linux itself, ext2 became the standard in the 90s, ext3 added a journal in 2001 so you wouldn&rsquo;t need an epic fsck after every power loss, and ext4 arrived in 2008 with extents, delayed allocation and volumes up to 1 exbibyte. The design goal was always the same: be the default filesystem, fast, simple and predictable. It&rsquo;s excellent at that. And it stopped there.</p>
<p>btrfs was born in 2007, at Oracle, with Chris Mason, with a completely different goal: be Linux&rsquo;s answer to ZFS. Instead of writing data over data, it&rsquo;s copy-on-write: every write goes to a new block and the pointers are updated cascading up the tree. That single decision is the mother of everything that matters in it.</p>
<p>What each one delivers, in a list:</p>
<p><strong>ext4:</strong></p>
<ul>
<li>journaling (consistent metadata after a crash)</li>
<li>extents and delayed allocation (good performance)</li>
<li>mature, stable, everywhere, every tool works</li>
</ul>
<p><strong>btrfs:</strong></p>
<ul>
<li>copy-on-write on everything</li>
<li>data and metadata checksums on every block</li>
<li>instant, cheap snapshots</li>
<li>independent subvolumes inside the same volume</li>
<li>transparent compression (zstd, lzo, zlib)</li>
<li>native RAID and scrub (verification sweep)</li>
<li>snapshot send/receive for incremental backup</li>
<li>reflinks (copies that don&rsquo;t duplicate blocks)</li>
</ul>
<p>The list already answers the title&rsquo;s question. Let&rsquo;s go piece by piece.</p>
<h2>Even NTFS and APFS have passed ext4<span class="hx:absolute hx:-mt-20" id="even-ntfs-and-apfs-have-passed-ext4"></span>
    <a href="#even-ntfs-and-apfs-have-passed-ext4" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>And if the comparison with btrfs seems unfair, look sideways. NTFS was born in 1993, with Windows NT, already with metadata journaling and ACLs, and back in the 2000s it gained a log of every change on the volume plus shadow copies (Windows&rsquo; &ldquo;Previous Versions&rdquo;). APFS, which Apple launched in 2017 made for flash, is copy-on-write like btrfs: native snapshots (it&rsquo;s what Time Machine uses for local restores), instant file clones that share blocks, volumes sharing the space of the same container, and per-file encryption.</p>
<p>Read the ext4 list again and compare: no snapshots, no data checksums, no CoW, no compression. Windows&rsquo; and Mac&rsquo;s filesystems, which nobody considers examples of sophistication, protect your data better than Linux&rsquo;s default, whose last big feature came out in 2008. btrfs is what puts Linux in the same generation as the other two, instead of a decade behind.</p>
<h2>Why btrfs is far superior<span class="hx:absolute hx:-mt-20" id="why-btrfs-is-far-superior"></span>
    <a href="#why-btrfs-is-far-superior" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>What copy-on-write is, for those who never stopped to think about it<span class="hx:absolute hx:-mt-20" id="what-copy-on-write-is-for-those-who-never-stopped-to-think-about-it"></span>
    <a href="#what-copy-on-write-is-for-those-who-never-stopped-to-think-about-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In classic filesystems, writing is destructive by definition: updating a block means writing the new content over the old one, in the same place on disk. If the machine dies mid-write, the file ends up half old, half new. The ext3/ext4 journal covers that for <strong>metadata</strong> (the directory structure doesn&rsquo;t corrupt), but your data itself is left to luck.</p>
<p>Copy-on-write inverts the order: <strong>nothing is ever overwritten</strong>. Writing to a file allocates a new block, writes the new content there, and only when everything is safely on disk does the filesystem flip the pointers to the new version, atomically. At any instant, you have either the whole old version or the whole new version. Never a mix of the two.</p>
<p>What that buys in practice:</p>
<ul>
<li><strong>Nearly free snapshots.</strong> The old blocks already persist by CoW&rsquo;s nature; a snapshot is just the filesystem holding the root pointer of that instant, pure accounting.</li>
<li><strong>Power loss doesn&rsquo;t corrupt.</strong> An interrupted write leaves the previous version intact, because it was never touched. For anyone who has lost a VM image or a database to a mid-write crash, this is worth the whole filesystem.</li>
<li><strong>Verification becomes possible.</strong> Since each block is written once and never touched again, keeping its checksum forever makes sense. It&rsquo;s the base of the corruption protection I detail further down.</li>
</ul>
<p>The cost exists and I pay it knowingly: random-write-heavy files (VM disks, databases) fragment and duplicate blocks, because each rewrite becomes a new block. For those cases you disable CoW per directory with <code>chattr +C</code>, which must be set <strong>before</strong> the file is created. In my layout, the VM image made with the right <code>+C</code> stayed healthy; the one made without became the textbook fragmentation case.</p>
<h3>Snapshots are the feature that changes your life<span class="hx:absolute hx:-mt-20" id="snapshots-are-the-feature-that-changes-your-life"></span>
    <a href="#snapshots-are-the-feature-that-changes-your-life" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A btrfs snapshot is an instant photo of a subvolume, and it costs almost nothing, because CoW already keeps the old blocks while someone references them. Creating a snapshot is a seconds operation, not hours. In practice: before every upgrade, the system takes a photo. If the upgrade breaks, you don&rsquo;t &ldquo;uninstall packages&rdquo;: you boot back into the previous photo and you&rsquo;re done. The boot recovery section, further down, shows this happening for real.</p>
<h3>Subvolumes are the right way to organize the disk<span class="hx:absolute hx:-mt-20" id="subvolumes-are-the-right-way-to-organize-the-disk"></span>
    <a href="#subvolumes-are-the-right-way-to-organize-the-disk" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A subvolume is an independent namespace inside the same filesystem, with its own snapshot policy. And it has a killer property: <strong>snapshots are not recursive</strong>. A child subvolume inside another is automatically left out of the parent&rsquo;s snapshot.</p>
<p>I use this for everything. On my desktop, the cache directories that can be re-downloaded (mise, rustup, npm, opencode, AI caches) are becoming nested subvolumes inside <code>@home</code>: they stay in the same place for any program, but out of every snapshot. That separation alone takes 165 GiB out of snapshot scope, and the big caches (Hugging Face, yay, uv, pip) already live outside the system volume, with symlinks pointing to them: minus 148 GiB of snapshot, part already migrated and part in progress. The snapshot stays small, the restore stays fast, and whatever can be re-downloaded from the internet never enters the photo.</p>
<p>The real cost, measured on the new QNAP (ZFS, but the CoW math is the same): 27 hourly snapshots of a folder with almost 80 TB, and nearly all of them consume megabytes, because between one hour and the next almost nothing changed. Cheap snapshots are what let this routine exist without guilt.</p>
<p><img src="/2026/10/12/usuarios-linux-sempre-escolham-btrfs-nao-ext4/qnap-snapshot-manager.png" alt="QNAP Snapshot Manager with 27 hourly snapshots of the CHAD folder, most consuming between 3 and 300 MB"  loading="lazy" /></p>
<h3>Reflink deduplication<span class="hx:absolute hx:-mt-20" id="reflink-deduplication"></span>
    <a href="#reflink-deduplication" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>First, the caveat that matters: btrfs has no native online deduplication like ZFS (which keeps a dedup table in RAM and charges dearly for it). What it has are two practical things: <strong>reflink</strong> and offline dedup. Reflink is a copy that shares blocks: <code>cp --reflink=auto</code> creates a new file that points to the same blocks as the original, instant and free, and each one starts diverging only where written. In the era of dozens of checkouts, worktrees and similar builds, that saves a mountain of blocks. For retroactive dedup there are userspace tools like <a href="https://github.com/markfasheh/duperemove"target="_blank" rel="noopener">duperemove</a> and <a href="https://github.com/Zygo/bees"target="_blank" rel="noopener">bees</a>.</p>
<h3>Real corruption protection<span class="hx:absolute hx:-mt-20" id="real-corruption-protection"></span>
    <a href="#real-corruption-protection" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every btrfs block, data or metadata, carries a checksum. When the filesystem reads and the checksum doesn&rsquo;t match, it knows the block rotted, and if there&rsquo;s a second copy (RAID or metadata DUP) it self-heals. ext4 checks no data at all: bit rot passes silently until you open the file years later.</p>
<p>Two pieces of my configuration show what that buys in practice, and what ext4 simply doesn&rsquo;t offer. The first is metadata in DUP mode. On ext4, each structure on the volume exists only once: a well-placed bad sector corrupts the directory table and the whole drive stops mounting. On btrfs, even with a single drive, every metadata block exists duplicated. The bad sector keeps existing, but the checksum flags the rotten block on read and the second copy answers in its place, without you noticing. It&rsquo;s the difference between losing the volume and noting a warning in the log.</p>
<p>The second is the monthly scrub. ext4 never re-reads anything to check health: if a block rots, you find out the day someone tries to open that specific file, maybe years later, when there&rsquo;s no fixing it anymore. The scrub is a scheduled sweep that re-reads the whole volume validating checksums, and finds the rot while it&rsquo;s still small and recoverable. When the <code>btrfs device stats</code> counter leaves zero, it&rsquo;s the siren to replace the drive before the disaster, not after.</p>
<h3>Transparent compression, measured<span class="hx:absolute hx:-mt-20" id="transparent-compression-measured"></span>
    <a href="#transparent-compression-measured" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every mount on my desktop uses <code>compress=zstd:1</code>. Level 1 costs a few percentage points of one CPU core, and btrfs detects what doesn&rsquo;t compress (model blob, video) and writes it raw, at no cost. The result, measured this week on my two new drives:</p>
<p><img src="/2026/10/12/usuarios-linux-sempre-escolham-btrfs-nao-ext4/btrfs-compressao-economia.png" alt="Compression savings table: 2.2 TB of data taking 1.6 TB on disk, with 35% savings on the system, 39% on Docker layers and zero on AI model weights"  loading="lazy" /></p>
<p>That&rsquo;s <strong>630 GB of free space</strong> on 2.2 TB: 15% more drive, paying nothing. On the initial migration the gain was even bigger, 45% on the system volume, because there was more text and less binary. Notice the table&rsquo;s details: programs and libraries compress well, Docker layers compress even better (39%), text logs compress 4.5x, and AI model weights compress nothing, which is expected and costs nothing. Source code, which is what we produce the most in the AI era, compresses beautifully.</p>
<h2>Synology uses btrfs, QNAP uses ZFS<span class="hx:absolute hx:-mt-20" id="synology-uses-btrfs-qnap-uses-zfs"></span>
    <a href="#synology-uses-btrfs-qnap-uses-zfs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Being fair to ZFS: for a big NAS it&rsquo;s superior, and it&rsquo;s what I chose for the QNAP. Native checksums and self-healing, mature RAIDZ, excellent send/receive. The price is complexity and resources: ZFS wants RAM for the ARC cache (my QNAP has 7 GB for a 174 TB pool, and I feel the lack), its online deduplication would need about 190 GB of RAM just for the table on my volume, and its provisioning model gave me a free scare when the snapshot was refused with 20 TB free (the thick vs thin story is in the NAS article).</p>
<p>btrfs is the right balance for a consumer machine. Light, native in the kernel, does almost everything ZFS does without demanding a storage administrator. Desktop, laptop, homelab, small or medium NAS: btrfs. Synology proved it in practice, twice: the btrfs volume survived readable with two drives out, and its snapshots saved 11 albums I deleted by mistake in the middle of the cleanup, byte by byte.</p>
<blockquote>
  <p>Big, serious NAS, with RAM to spare: ZFS. Everything else: btrfs. And for a personal Linux machine, it&rsquo;s not even a discussion.</p>

</blockquote>
<h2>Boot recovery via snapshot<span class="hx:absolute hx:-mt-20" id="boot-recovery-via-snapshot"></span>
    <a href="#boot-recovery-via-snapshot" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The feature that has saved me for real, told on both machines.</p>
<p>On the desktop, <a href="https://omarchy.org"target="_blank" rel="noopener">Omarchy</a> configures <a href="https://snapper.io/"target="_blank" rel="noopener">snapper</a> to take a snapshot before every update and <code>limine-snapper-sync</code> publishes each snapshot as a boot entry in <a href="https://github.com/limine-bootloader/limine"target="_blank" rel="noopener">Limine</a>. New kernel won&rsquo;t come up? In the boot menu you pick yesterday&rsquo;s snapshot and the machine comes back as if nothing happened. On my machine the scheduled routine runs via <a href="https://github.com/teejee2008/timeshift"target="_blank" rel="noopener">Timeshift</a> on cron (every boot and hourly), with snapper covering the update points: the way back is the same mechanism. (The gotcha: each snapshot entry carries the kernel image along, so a small ESP fills up fast. My 1 GB one already refused a kernel update for lack of space; the system stayed bootable on the old kernel, which is the right behavior.)</p>
<p>On the server, which runs <a href="https://get.opensuse.org/microos/"target="_blank" rel="noopener">openSUSE MicroOS</a>, it&rsquo;s even stronger: the whole system is transactional btrfs, and every update is a new snapshot. Last week, kernel 7.2.9 took down the NVMe controller silently, twice, in the middle of the nightly backup. The fix was a <code>transactional-update rollback</code> and a reboot back to 7.2.6, which ran the whole load (754 GiB of backup reads with concurrent download) without a hiccup. A kernel regression became a scheduled reboot, not a recovery all-nighter. One documented caveat: <code>/etc</code> lives inside the snapshot, so the rollback undoes configuration changes along with it. After any rollback, check your units again.</p>
<h2>Maintenance is not optional (and the deleted file that won&rsquo;t go away)<span class="hx:absolute hx:-mt-20" id="maintenance-is-not-optional-and-the-deleted-file-that-wont-go-away"></span>
    <a href="#maintenance-is-not-optional-and-the-deleted-file-that-wont-go-away" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A modern CoW filesystem delivers a lot, but it charges two routines ext4 never asked for.</p>
<p>The first is the scrub, which already appeared here: re-read everything and check checksums, monthly, on all machines. It&rsquo;s bit-rot detection in action, and without it the checksum only warns you about the rot when you try to read the file. The second point is subtler: <strong>a snapshot pins the blocks of deleted files</strong>. When you delete a file inside a snapshotted subvolume, the space doesn&rsquo;t come back, because the block stays referenced by the photo. That&rsquo;s exactly what happened on my NAS: the 2.14 TB cleanup I ran on the Synology only freed space for real after the old snapshots were removed; until then, the blocks stayed pinned.</p>
<p>The treatment is simple routine. Retention has to be automatic, with snapper or Timeshift deleting the old snapshots per policy (on the QNAP, the Snapshot Manager&rsquo;s retention policy plays the same role). Space that doesn&rsquo;t come back after deleting old snapshots is usually over-allocated chunks: a <code>btrfs balance start -dusage=50</code> returns the little-used pieces to the free pool (in my house I don&rsquo;t blindly schedule balance, I monitor the unallocated space and act when it gets tight). And on the restic side, <code>forget</code> alone only removes the snapshot&rsquo;s reference: the repository space is only reclaimed with <code>prune</code> along, <code>forget --prune</code>.</p>
<h2>House cleaning in the AI coding era<span class="hx:absolute hx:-mt-20" id="house-cleaning-in-the-ai-coding-era"></span>
    <a href="#house-cleaning-in-the-ai-coding-era" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the part almost nobody connects with filesystems: the agent era produces garbage at industrial speed. I know because I measured.</p>
<ul>
<li><strong>Rust is the biggest disk polluter in the dev world.</strong> Every build leaves behind 100 to 180 MB test binaries, and they accumulate with each edit. On my desktop, the <code>target/</code> directories added up to <strong>920 GiB</strong>. ai-memory alone accounted for 704 GiB. The hygiene tool I was using is <a href="https://github.com/holmgr/cargo-sweep"target="_blank" rel="noopener">cargo-sweep</a>, weekly. A reader pointed out that the project declares itself unmaintained, and its own README points to <a href="https://github.com/dnlmlr/cargo-clean-all"target="_blank" rel="noopener">cargo-clean-all</a>, which works differently: instead of pruning old artifacts inside one <code>target/</code>, it finds every Rust project under a directory and deletes the whole <code>target/</code> of the ones you filter, for example <code>cargo clean-all --keep-days 7 ~</code> to clean only what hasn&rsquo;t been compiled in a week.</li>
<li><strong>Docker is right behind.</strong> On my machine I found 1.26 TB of build cache plus 938 GB of images. A single cleanup recovered about 600 GB. On the server, the weekly cleanup collects 0.6 to 4.5 GB every Sunday.</li>
<li><strong>AI and package caches bloat quietly.</strong> The Hugging Face cache had 86 GB until I deleted three dead models and it dropped to 21. Pacman had 22 GB of outdated packages. yay, uv and pip, another 125 GB.</li>
<li><strong>And agents create temporary directories without asking permission.</strong> A complex project with several branches means worktrees, and each release worktree has its own <code>CARGO_TARGET_DIR</code> full of test binaries. On ai-memory that has already blown up the disk, and it became a mandatory rule in the project&rsquo;s AGENTS.md: after every release, <code>cargo clean</code> in each created worktree and removal of finished worktrees, no exceptions.</li>
</ul>
<p>The solution is to automate the sweeping. My minimal example, a user timer that runs on the 1st and 15th at dawn, with Nice and idle I/O:</p>
<ul>
<li>deletes <code>target/</code> directories of projects idle for more than 14 days</li>
<li>cleans the yay cache</li>
<li>prunes only Docker build cache older than 30 days, never images or volumes</li>
</ul>
<p>And the part that became standard in my house: <strong>instruct the agents to clean up what they create</strong>. Three real rules from my projects, for you to copy:</p>
<blockquote>
  <p><strong>In the desktop&rsquo;s AGENTS.md:</strong> &ldquo;Never run broad cleanups like <code>docker system prune</code> without explicit user authorization after a read-only inventory. Cleanup uses an exact list of IDs; idle, old or unreferenced does not mean disposable.&rdquo;</p>

</blockquote>
<blockquote>
  <p><strong>In the homelab&rsquo;s CLAUDE.md:</strong> &ldquo;Before finishing any task, remove the temporary things the task created, and only those. Never delete what you didn&rsquo;t create or can&rsquo;t attribute to the task. When in doubt, list it for the owner.&rdquo;</p>

</blockquote>
<blockquote>
  <p><strong>In ai-memory&rsquo;s AGENTS.md:</strong> &ldquo;<code>target/</code> grows without limit: every edit to a shared crate leaves behind a copy of each 100-180 MB test binary (seen at 157 GiB). Weekly <code>cargo sweep --time 7</code>, and mandatory <code>cargo clean</code> after every release.&rdquo;</p>

</blockquote>
<h2>And the real backup: restic<span class="hx:absolute hx:-mt-20" id="and-the-real-backup-restic"></span>
    <a href="#and-the-real-backup-restic" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A snapshot lives on the same drive, so a snapshot is not a backup: if the drive dies, the snapshot dies with it. The last item in the kit is <a href="https://restic.net/"target="_blank" rel="noopener">restic</a>, which for me is the best backup system on Linux today.</p>
<p>restic is a single open source binary, written in Go, that does deduplicated, encrypted and versioned backup to practically any destination: another directory, another NAS via SFTP or REST, S3, Glacier. The central trick is content-defined chunking: it slices each file into variable-size blocks defined by the content, hashes each block and only writes to the repository the blocks that don&rsquo;t exist there yet. That&rsquo;s why the delta is cheap: today&rsquo;s backup carries the blocks that changed since yesterday, not the files that changed. Editing a 100 GB database in the middle costs a few megabytes of backup, not 100 GB again. Each run becomes a repository snapshot, a restore point you browse with <code>restic mount</code> as if it were a filesystem, and <code>restic check</code> audits the whole repository&rsquo;s integrity whenever you ask.</p>
<p>Configuration matters more than the tool, so here&rsquo;s ours, mistakes included. On the desktop, the repository lives on the NAS and retention is <code>keep-daily 7, keep-weekly 4, keep-monthly 6, keep-yearly 1</code>. On the server, backup runs daily at dawn to the repository on the QNAP, covering <code>/etc</code>, <code>/usr/local/bin</code>, <code>/home</code> and the container volumes, with the password off the machine and <code>pg_dump</code> before the databases, because a filesystem snapshot doesn&rsquo;t guarantee consistency for a database that&rsquo;s writing. The first full load was 729 GiB in under an hour, and restic crossed unharmed, on retries, the window in which the NFS mount went read-only by mistake during the migration.</p>
<p>The most important part of the configuration is what does <strong>not</strong> go into the backup. Our exclusions, all with a reason:</p>
<ul>
<li>AI model caches (Immich, Hugging Face, EasyOCR): if lost, download again;</li>
<li>Prometheus metrics: history that regenerates itself;</li>
<li>the Fulcrum database: reindexes from bitcoind;</li>
<li>the decision classifiers&rsquo; weights: re-downloadable by revision hash (and this exclusion&rsquo;s glob goes inside quotes inside the bash array, because unquoted it becomes a backup source instead of an exclusion);</li>
<li><code>node_modules</code>, <code>target/</code>, cargo registry, rustup toolchains: pure build artifacts.</li>
</ul>
<p>And one retention lesson to close. When we shortened the server policy to &ldquo;yesterday, 2 dailies, 2 weeklies and 1 monthly&rdquo;, the correct translation to flags is <code>--keep-daily 3 --keep-weekly 3 --keep-monthly 2</code>, not 2/2/1: restic&rsquo;s levels overlap, and yesterday&rsquo;s snapshot is also the newest of this week and this month, so each number needs to be one more than the older points you want to keep. The detail caught us off guard: the script had a literal 2/2/1, and with it the monthly level would never hold anything older than last night. In practice, the intention was to keep 5 restore points, and 2/2/1 delivers only 3: yesterday, plus one daily, plus one weekly. We erred, measured, corrected.</p>
<p>A humility note from the disaster: the old repositories were left on the Synology by my decision (almost 2 TB of abandoned history, because the content was already re-covered on the new QNAP). A backup repository ages too, and revisiting its scope is part of the hygiene.</p>
<h2>Conclusion: in the AI era, disk is not a detail<span class="hx:absolute hx:-mt-20" id="conclusion-in-the-ai-era-disk-is-not-a-detail"></span>
    <a href="#conclusion-in-the-ai-era-disk-is-not-a-detail" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agents coding all day change the storage math at both ends. On the volume end: builds, caches, worktrees and models fill the disk much faster than any human habit ever did, and without a cleanup routine you find out when it blows up. On the safety end: the more generated code, the more you need a cheap way back, because not every agent change is a good one.</p>
<p>btrfs covers both. Transparent compression gives back 15% of disk for free, and source code is exactly the kind of data that compresses the most. Snapshots and subvolumes give you instant rollback on the system and isolation for what doesn&rsquo;t need protection. Checksums and scrub watch the health of blocks that ext4 simply ignores. ext4 had its 15 years of well-deserved reign. In 2026, choosing it on a new Linux is giving up protection you&rsquo;ll need, sooner or later. Choose btrfs and set up the cleanup today.</p>
]]></content:encoded><category>linux</category><category>storage-and-backup</category><category>homelab</category><category>omarchy</category></item><item><title>I Built a Waybar Widget for Omarchy to Monitor LLM Plan Usage: ai-usagebar</title><link>https://www.akitaonrails.com/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/</guid><pubDate>Sun, 24 May 2026 00:01:00 -0300</pubDate><description>&lt;p&gt;Anyone following the blog already knows I use a whole bunch of different LLM vendors. The main ones are Claude and GPT, via Claude Code and Codex. I use each one&amp;rsquo;s harness because I&amp;rsquo;m locked into their subscription plans (Pro, Plus, Max), which come out way cheaper than paying per-token credits like OpenRouter. Even so, I also use OpenRouter to reach other models for testing, and I even have a Z.AI GLM subscription for small stuff.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Anyone following the blog already knows I use a whole bunch of different LLM vendors. The main ones are Claude and GPT, via Claude Code and Codex. I use each one&rsquo;s harness because I&rsquo;m locked into their subscription plans (Pro, Plus, Max), which come out way cheaper than paying per-token credits like OpenRouter. Even so, I also use OpenRouter to reach other models for testing, and I even have a Z.AI GLM subscription for small stuff.</p>
<p>The problem with juggling several plans is keeping track of how much I&rsquo;ve burned on each. I&rsquo;d been using <a href="https://github.com/mryll/claudebar"target="_blank" rel="noopener">claudebar</a>, a Waybar widget that shows your Anthropic plan usage. I like it, but I wanted to see all my vendors in one place, glance at it and know where I stand. And I didn&rsquo;t want to clutter my Waybar with a separate widget per vendor. So I built my own: <strong><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a></strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-waybar.png" alt="Waybar widget showing “cld 29% · 1h 12m” in the top-right corner, with the tooltip open showing the Claude Max 20x plan: Session 29%, Weekly 47%, Sonnet only 0%, Extra usage $0.00 against a $1100 limit, and the last-updated time."  loading="lazy" /></p>
<p>It&rsquo;s a Rust port of claudebar, drop-in compatible, extended to four vendors: Anthropic Claude, OpenAI Codex/ChatGPT, Z.AI (GLM), and OpenRouter. It keeps the same flags (<code>--icon</code>, <code>--format</code>, <code>--tooltip-format</code>, etc.), the same minimalist Pango-bordered tooltip, and the same Omarchy theme auto-detection. The difference is that now all four vendors show up in the same place, instead of 865 lines of bash babysitting just one.</p>
<h2>How it authenticates with each vendor<span class="hx:absolute hx:-mt-20" id="how-it-authenticates-with-each-vendor"></span>
    <a href="#how-it-authenticates-with-each-vendor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the part worth explaining, because each vendor does it differently. Claude and Codex use OAuth: their official CLIs (<code>claude</code> and <code>codex</code>) already wrote the credentials to disk when you logged in, and ai-usagebar reads those same files. No environment variable needed, the token even refreshes itself.</p>
<p>Z.AI and OpenRouter use API keys, so for those you need to set a key (via env var or inline in the config).</p>
<table>
  <thead>
      <tr>
          <th>Vendor</th>
          <th>Method</th>
          <th>What you need to do</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Anthropic</td>
          <td>OAuth, reads from <code>~/.claude/.credentials.json</code></td>
          <td>Run <code>claude</code> once to log in. Token refreshes itself.</td>
      </tr>
      <tr>
          <td>OpenAI</td>
          <td>OAuth, reads from <code>~/.codex/auth.json</code></td>
          <td>Run <code>codex login</code> once. Token refreshes itself.</td>
      </tr>
      <tr>
          <td>Z.AI</td>
          <td>API key (<code>ZAI_API_KEY</code> or <code>[zai] api_key</code> in config)</td>
          <td>Set either one.</td>
      </tr>
      <tr>
          <td>OpenRouter</td>
          <td>API key (<code>OPENROUTER_API_KEY</code> or <code>[openrouter] api_key</code>)</td>
          <td>Set either one.</td>
      </tr>
  </tbody>
</table>
<h2>The interface beyond Waybar<span class="hx:absolute hx:-mt-20" id="the-interface-beyond-waybar"></span>
    <a href="#the-interface-beyond-waybar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Besides the widget on the bar, there&rsquo;s a tabbed TUI (<code>ai-usagebar-tui</code>) to see everything at once. Navigate with Tab / h / l between vendors, auto-refresh every 60s. You can open it by clicking the Waybar widget, or run it straight from the terminal (more on that in the next section).</p>
<p>The OpenRouter tab shows credit balance, today/week/month spend, and the tier:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-openrouter.png" alt="ai-usagebar-tui on the OpenRouter tab: credit-balance gauge at 98% in red ($13.67 left of $900), usage-by-period block (today/week/month), paid tier."  loading="lazy" /></p>
<p>And there&rsquo;s a settings overlay to pick the primary vendor and paste the API keys without editing the config by hand:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-settings.png" alt="Settings overlay floating over the TUI: primary-vendor radio (Anthropic selected), masked Z.AI API key (•••), masked OpenRouter API key (•••), Save button, key hints in the footer."  loading="lazy" /></p>
<h2>Not on Omarchy or Hyprland? Run it as a standalone TUI<span class="hx:absolute hx:-mt-20" id="not-on-omarchy-or-hyprland-run-it-as-a-standalone-tui"></span>
    <a href="#not-on-omarchy-or-hyprland-run-it-as-a-standalone-tui" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The Waybar widget is optional. The two binaries are independent, so if you don&rsquo;t run Omarchy, or Hyprland, or Waybar (or you just prefer to check usage now and then instead of having it on the bar all the time), <code>ai-usagebar-tui</code> works as a fully standalone terminal app:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-usagebar-tui    <span class="c1"># opens in your current terminal</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It runs in any terminal emulator (Kitty, Alacritty, Foot, Ghostty, etc.), works even over a plain SSH session, and doesn&rsquo;t depend on a compositor or any window-manager feature. All the controls and the settings overlay work the same. Same four vendors, same tabs:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-openai.png" alt="ai-usagebar-tui on the OpenAI tab running in a terminal: Codex 5h and weekly gauges, Credits block with message-count ranges, Claude / OpenAI / GLM (Z.AI) / OpenRouter tabs at the top, key hints in the footer."  loading="lazy" /></p>
<p>Typical use off Omarchy: a quick check before starting a long session (&ldquo;am I close to my Claude weekly limit?&rdquo;), a monitor in a tmux pane while you code, or a shell-only tool on a remote machine (install the binary and that&rsquo;s it, no Waybar or Hyprland dependency). The TUI is the canonical way to see all four vendors at once, whether or not you ever set up the widget.</p>
<h2>Install<span class="hx:absolute hx:-mt-20" id="install"></span>
    <a href="#install" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On Arch there&rsquo;s an AUR package, two flavors:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yay -S ai-usagebar-bin    <span class="c1"># prebuilt binary from GitHub Releases (~5s)</span>
</span></span><span class="line"><span class="cl">yay -S ai-usagebar        <span class="c1"># compiles from source (~30-60s)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Or straight from source:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cargo build --release
</span></span><span class="line"><span class="cl">sudo make install                  <span class="c1"># → /usr/local/bin</span>
</span></span><span class="line"><span class="cl"><span class="c1"># or</span>
</span></span><span class="line"><span class="cl">make install <span class="nv">PREFIX</span><span class="o">=</span><span class="nv">$HOME</span>/.local   <span class="c1"># → ~/.local/bin</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The recommended Waybar config is a single module you scroll to cycle through vendors, with click to open the TUI:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsonc" data-lang="jsonc"><span class="line"><span class="cl"><span class="s2">&#34;custom/aibar&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;ai-usagebar --format &#39;{vendor_short} {session_pct}% · {session_reset}&#39;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;return-type&#34;</span><span class="p">:</span> <span class="s2">&#34;json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;interval&#34;</span><span class="p">:</span> <span class="mi">300</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;signal&#34;</span><span class="p">:</span> <span class="mi">13</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;tooltip&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-click&#34;</span><span class="p">:</span> <span class="s2">&#34;ai-usagebar-tui&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-scroll-up&#34;</span><span class="p">:</span>   <span class="s2">&#34;ai-usagebar --cycle-next&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-scroll-down&#34;</span><span class="p">:</span> <span class="s2">&#34;ai-usagebar --cycle-prev&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you&rsquo;d rather see all four vendors at once, you can use one module per vendor. The <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">README</a> has the full config detail, format placeholders, and the variations.</p>
<h2>Why I built it<span class="hx:absolute hx:-mt-20" id="why-i-built-it"></span>
    <a href="#why-i-built-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This looked like a Saturday-night little project, so I just did it. And it was: porting claudebar to Rust and adding the extra vendors I wanted was painless. I came out of one night with a widget that does exactly what I needed and is more reliable (tested, modular) than the original shell script.</p>
<p>If you use other vendors I didn&rsquo;t cover, or you hit a bug, send an issue or pull request: <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">github.com/akitaonrails/ai-usagebar</a>. It&rsquo;s MIT.</p>
]]></content:encoded><category>ai-usagebar</category><category>omarchy</category><category>developer-tools</category><category>llms</category></item><item><title>NW-Omarchy: Bringing Omarchy to X11 with XLibre</title><link>https://www.akitaonrails.com/en/2026/05/01/nw-omarchy-xlibre-inaugural/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/05/01/nw-omarchy-xlibre-inaugural/</guid><pubDate>Fri, 01 May 2026 18:00:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/launcher-drun.png" alt="NW-Omarchy launcher: super&amp;#43;space opens rofi with every .desktop on the system, icons rendered through the Papirus theme" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;This post inaugurates an experimental project I&amp;rsquo;ve been hacking on for the past few weeks: &lt;a href="https://github.com/akitaonrails/NW-Omarchy"target="_blank" rel="noopener"&gt;NW-Omarchy&lt;/a&gt;. The pitch is easy to explain and stubborn enough to be worth defending: take the opinionated, pretty look-and-feel of &lt;a href="https://omarchy.org/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt; (which is Hyprland, meaning Wayland) and bring all of that to the X11 world, as a parallel session you pick at SDDM. Your Hyprland session stays untouched. When you want to try X11, pick &lt;code&gt;nw-bspwm&lt;/code&gt; at login and land in something that looks like the same Omarchy with different parts underneath.&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/launcher-drun.png" alt="NW-Omarchy launcher: super&#43;space opens rofi with every .desktop on the system, icons rendered through the Papirus theme"  loading="lazy" /></p>
<p>This post inaugurates an experimental project I&rsquo;ve been hacking on for the past few weeks: <a href="https://github.com/akitaonrails/NW-Omarchy"target="_blank" rel="noopener">NW-Omarchy</a>. The pitch is easy to explain and stubborn enough to be worth defending: take the opinionated, pretty look-and-feel of <a href="https://omarchy.org/"target="_blank" rel="noopener">Omarchy</a> (which is Hyprland, meaning Wayland) and bring all of that to the X11 world, as a parallel session you pick at SDDM. Your Hyprland session stays untouched. When you want to try X11, pick <code>nw-bspwm</code> at login and land in something that looks like the same Omarchy with different parts underneath.</p>
<p>The obvious question is &ldquo;why bother&rdquo;. Red Hat already announced in 2025 that upstream <code>xorg-server</code> is gone from RHEL 10, and the corporate Linux narrative shifted to &ldquo;use Wayland and move on&rdquo;. As usual, in open source we don&rsquo;t have to agree. There&rsquo;s XLibre, a fork of xorg-server picking up active maintenance, and there are plenty of people with old hardware, legacy drivers, or legacy software for which Wayland still isn&rsquo;t a viable path. NW-Omarchy is for that scenario: give that gear a graceful second wind and, while you&rsquo;re at it, make it pretty.</p>
<h2>What XLibre is and why it matters<span class="hx:absolute hx:-mt-20" id="what-xlibre-is-and-why-it-matters"></span>
    <a href="#what-xlibre-is-and-why-it-matters" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>XLibre is a fork of xorg-server that started in 2025, after it became clear upstream had no energy left to evolve. X.Org itself was only taking critical security patches, and the historical primary funder of new development (Red Hat) <a href="https://www.redhat.com/en/blog/rhel-10-plans-wayland-and-xorg-server"target="_blank" rel="noopener">announced it was stepping out</a> of new X-server work as part of the RHEL 10 plans. XLibre took the codebase and went back to cleanups, security fixes, modernization and driver-ABI bumps. The first public release was <a href="https://www.phoronix.com/news/XLibre-25.0-Released"target="_blank" rel="noopener">XLibre 25.0</a>, and the project lives at <a href="https://github.com/X11Libre/xserver"target="_blank" rel="noopener">github.com/X11Libre/xserver</a>.</p>
<p>XLibre&rsquo;s technical pitch is being a drop-in replacement for xorg-server. Same X11 protocol, same client API (libxcb/libx11), same dependency graph in pacman. Your xterm, your Firefox, your Steam, your favorite emulator for arcade machines from the 90s, none of them know the X server changed. Distros already shipping XLibre as default or tier-one:</p>
<ul>
<li><strong>Artix Linux</strong> (<a href="https://linuxiac.com/artix-linux-2026-04-released-with-xlibre-as-default-x-serve/"target="_blank" rel="noopener">2026.04+</a>) ships it as the default X server.</li>
<li><strong>Fedora</strong> has an <a href="https://fedoraproject.org/wiki/Changes"target="_blank" rel="noopener">open Change proposal</a> to migrate.</li>
<li><strong>Arch Linux</strong> has an official binary repo at <code>x11libre.net/repo/arch_based/</code>. That&rsquo;s exactly what NW-Omarchy uses.</li>
</ul>
<p>Comparing what&rsquo;s still alive:</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>xorg-server</th>
          <th>XLibre</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Last non-security release</td>
          <td>21.1 (2022)</td>
          <td>25.0 (2025)</td>
      </tr>
      <tr>
          <td>Active codebase work</td>
          <td>none</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>Driver ABI</td>
          <td>frozen</td>
          <td>bumped (<code>X-ABI-VIDEODRV_VERSION=28.0</code> in 25.0)</td>
      </tr>
      <tr>
          <td>Stated future</td>
          <td>&ldquo;use Wayland&rdquo;</td>
          <td>continued X server evolution</td>
      </tr>
      <tr>
          <td>Coexists with <code>xorg-xwayland</code></td>
          <td>yes</td>
          <td>yes</td>
      </tr>
  </tbody>
</table>
<p>If your reason for staying on X11 is any of the classics (legacy proprietary Nvidia driver, vintage Intel GPU, Optimus laptop with quirky muxing, dependency on <code>xdotool</code>/<code>wmctrl</code>/<code>xprop</code>/<code>xinput</code> for accessibility or remap tools, <code>ssh -X</code> to run a remote app, clipboard with no permission prompt, screen reader that needs to read input from any window), XLibre is the path that keeps that stack under active maintenance.</p>
<h2>Why this project exists<span class="hx:absolute hx:-mt-20" id="why-this-project-exists"></span>
    <a href="#why-this-project-exists" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I run Omarchy on my Thinkpad T14 Gen 6 (<a href="/en/2026/04/18/omarchy-on-thinkpad-t14-gen-6/">wrote about it here</a>) and I genuinely like it. DHH did serious curation work: a single coherent theme across everything (terminal, launcher, top bar, lockscreen), consistent shortcuts, visual choices that don&rsquo;t tire your eyes. It&rsquo;s opinionated the right way, and it spares you the fatigue of configuring everything from scratch.</p>
<p>The catch is that Omarchy is Hyprland, Hyprland is Wayland-only, and Wayland still has scenarios where it&rsquo;s the wrong tool for the job. Older machines with legacy Nvidia drivers, environments leaning on software with deep X11 integration, situations where you want <code>ssh -X</code> and don&rsquo;t want to learn <code>waypipe</code>, or just machines you want to keep running without swapping half the stack. For those cases, I wanted Omarchy&rsquo;s aesthetic and workflow on top of X11. It didn&rsquo;t exist. So I built it.</p>
<p>The name NW-Omarchy is short for &ldquo;Not Wayland Omarchy&rdquo;. It&rsquo;s deliberately a sidecar: runs alongside, doesn&rsquo;t replace. You install it on top of an existing Omarchy install, it creates a separate SDDM session called <code>nw-bspwm</code>, and nothing in your Hyprland setup gets touched. Want to go back to Hyprland? Pick Hyprland at SDDM next login. Want to uninstall? There&rsquo;s an uninstall script that reverses exactly what got installed, based on a manifest that tracks every action.</p>
<h2>What changes in the stack (Wayland → X11)<span class="hx:absolute hx:-mt-20" id="what-changes-in-the-stack-wayland--x11"></span>
    <a href="#what-changes-in-the-stack-wayland--x11" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Hyprland is compositor + WM in the same binary. In the X11 world, those two functions come as separate pieces, and each has a well-known substitute. The translation work was mapping every Omarchy component to its X11 equivalent, then making sure the keyboard shortcuts, theming, and behavior stayed as close as possible.</p>
<table>
  <thead>
      <tr>
          <th>Function</th>
          <th>Omarchy/Wayland</th>
          <th>NW-Omarchy/X11</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Window manager</td>
          <td>Hyprland</td>
          <td><a href="https://github.com/baskerville/bspwm"target="_blank" rel="noopener">bspwm</a></td>
      </tr>
      <tr>
          <td>Hotkey daemon</td>
          <td>Hyprland built-in</td>
          <td><a href="https://github.com/baskerville/sxhkd"target="_blank" rel="noopener">sxhkd</a></td>
      </tr>
      <tr>
          <td>Compositor</td>
          <td>Hyprland built-in</td>
          <td><a href="https://github.com/yshui/picom"target="_blank" rel="noopener">picom</a> (upstream v13)</td>
      </tr>
      <tr>
          <td>Top bar</td>
          <td>Waybar</td>
          <td><a href="https://github.com/polybar/polybar"target="_blank" rel="noopener">polybar</a></td>
      </tr>
      <tr>
          <td>App launcher</td>
          <td>Walker</td>
          <td><a href="https://github.com/davatorium/rofi"target="_blank" rel="noopener">rofi</a></td>
      </tr>
      <tr>
          <td>Notifications</td>
          <td>Mako</td>
          <td><a href="https://github.com/dunst-project/dunst"target="_blank" rel="noopener">dunst</a></td>
      </tr>
      <tr>
          <td>Idle/lock</td>
          <td>hypridle / hyprlock</td>
          <td>xidlehook + xss-lock + i3lock-color</td>
      </tr>
      <tr>
          <td>Nightlight</td>
          <td>hyprsunset</td>
          <td>redshift</td>
      </tr>
      <tr>
          <td>Clipboard history</td>
          <td>walker <code>-m clipboard</code></td>
          <td><a href="https://github.com/cdown/clipmenu"target="_blank" rel="noopener">clipmenu</a> (rofi-backed)</td>
      </tr>
      <tr>
          <td>Screenshots</td>
          <td>hyprshot</td>
          <td>maim + slop + xclip</td>
      </tr>
      <tr>
          <td>Color picker</td>
          <td>hyprpicker</td>
          <td>xcolor</td>
      </tr>
  </tbody>
</table>
<p><strong>bspwm</strong> is a minimalist tiling window manager. The WM itself only responds to commands over a socket, and <code>bspwmrc</code> is literally a shell script. Keybindings live in a separate daemon, <strong>sxhkd</strong>, which reads a plain text file. That separation is classic X11: each piece does one thing.</p>
<p><strong>picom</strong> is the compositor that gives you blur, shadows, rounded corners, fade-in/out, and per-window opacity rules. NW-Omarchy uses upstream v13 (released February 2026), not the old <code>picom-ftlabs-git</code> fork, <a href="https://github.com/yshui/picom/issues"target="_blank" rel="noopener">abandoned since 2024</a>. The visual effects Omarchy has under Hyprland (rounded corners, fade on open/close, blur on rofi and dunst) all come from picom in NW-Omarchy.</p>
<p><strong>polybar</strong> replaces waybar. Same visual layout: Omarchy logo on the left, date in the middle, audio/wifi/bluetooth/battery indicators on the right. Same nerd-font icons. Left click opens the same TUIs (wiremix, impala, bluetui), right click opens the GUI variants. Scroll on audio adjusts volume, middle click mutes. Practical parity.</p>
<p><strong>rofi</strong> replaces walker. <code>super + space</code> opens the full launcher with every <code>.desktop</code> on the system plus icons. <code>super + shift + space</code> opens a cheat-sheet of the pinned apps, with the chord shown next to each name. Useful for remembering &ldquo;what was the chord for Signal again&rdquo;.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/launcher-cheatsheet.png" alt="Pinned-apps cheat-sheet: super&#43;shift&#43;space opens rofi with each app and its chord, parsed straight from sxhkdrc"  loading="lazy" /></p>
<p>For a user who isn&rsquo;t going to crack open <code>~/.config</code> to customize anything, the difference between the two sessions is cosmetic at homeopathic levels. The same Omarchy shortcuts (over 70 bindings) are wired up, the same menus pop up, the same logo sits in the bar, the same nerd-font icons.</p>
<h2>The theme system is the same<span class="hx:absolute hx:-mt-20" id="the-theme-system-is-the-same"></span>
    <a href="#the-theme-system-is-the-same" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This was the most fun part to build, and the part that surprises people most. Omarchy has a centralized theme system: each theme lives at <code>~/.local/share/omarchy/themes/&lt;name&gt;/</code>, ships a <code>colors.toml</code> with a universal palette (<code>accent</code>, <code>background</code>, <code>foreground</code>, <code>color0..15</code>), and <code>omarchy-theme-set &lt;name&gt;</code> re-renders each app&rsquo;s config to match. The active theme lives at <code>~/.config/omarchy/current/theme/</code>, and every app imports its colors from there.</p>
<p>NW-Omarchy plugs into that same pipeline. I added <code>.tpl</code> templates for bspwm, polybar, rofi and dunst that follow the Omarchy convention, and <code>omarchy-theme-set-templates</code> regenerates everything on every theme change. The result is that all 19 themes Omarchy ships work as-is in NW-Omarchy, with zero porting work. Catppuccin, gruvbox, kanagawa, nord, tokyo-night, all of them. The wallpaper changes along with the theme via an inotify daemon (<code>nw-omarchy-bg-watch</code>).</p>
<p>A few examples in action:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/theme-ristretto.png" alt="Ristretto theme: warm color curves on the wallpaper, polybar and bspwm border picking up the same palette"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/theme-lumon.png" alt="Lumon theme: Severance reference, cold corporate palette, “United in Severance”"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/theme-everforest.png" alt="Everforest theme: moss-green tones, wallpaper of misty tree-tops"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/theme-retro-82.png" alt="Retro-82 theme: synthwave, pink grid on dark background, neon details"  loading="lazy" /></p>
<p>When Omarchy adds a new theme via <code>omarchy-theme-update</code>, NW-Omarchy gets it for free. No extra work, no rebuild, nothing for me to republish.</p>
<h2>System menu and TUIs<span class="hx:absolute hx:-mt-20" id="system-menu-and-tuis"></span>
    <a href="#system-menu-and-tuis" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Omarchy&rsquo;s system menu (the <code>super + alt + space</code> one that opens the hierarchical menu with Hardware, Setup, Update, etc.) has a 1-to-1 port in NW-Omarchy. Same tree, same navigation. Where Omarchy calls <code>walker --dmenu</code>, I call <code>rofi -dmenu</code>. The rest of the code is identical, and most of the helpers the menu invokes (<code>omarchy-pkg-add</code>, <code>omarchy-theme-set</code>, <code>omarchy-update</code>, etc.) have nothing Wayland-specific in them and run straight on X11.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/system-menu.png" alt="nw-omarchy-menu open: the Omarchy system menu tree, arrow-key navigation, same look"  loading="lazy" /></p>
<p>The TUIs too: wiremix for audio, impala for wifi, bluetui for bluetooth, btop for system resources. They all open as a centered floating window, same as Omarchy under Hyprland. bspwm has a rule (<code>bspc rule -a</code>) that recognizes the <code>org.nw-omarchy.&lt;cmd&gt;</code> class and applies <code>state=floating center=on rectangle=900x600</code> automatically.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/01/nw-omarchy/wifi-tui.png" alt="Impala TUI running as a centered floating window via super&#43;ctrl&#43;w, palette following the active theme"  loading="lazy" /></p>
<h2>What&rsquo;s there and what isn&rsquo;t<span class="hx:absolute hx:-mt-20" id="whats-there-and-what-isnt"></span>
    <a href="#whats-there-and-what-isnt" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Honesty first: there are Hyprland features that are Wayland-only and don&rsquo;t come back. Per-monitor fractional scaling is gone, X11 only does integer scaling per output, so mixed-DPI setups look off. HDR doesn&rsquo;t exist on X11. Tear-free rendering by design needs Wayland; on X11 you need picom + vsync and a cooperative GPU, and even then you get close to Wayland without quite matching it. Workspace swipe with live preview during the gesture is also gone, because bspwm has no in-progress switch state, so the gesture fires a discrete command only on completion (you go to the next workspace, but you don&rsquo;t see the preview slide). And the Wayland-specific daemons (voxtype, walker preview pane, hyprsunset, hypridle) become <code>redshift</code> and <code>xss-lock</code>, with no preview pane in rofi.</p>
<p>If any of those points is a deal-breaker for you, stay on Omarchy/Hyprland. SDDM picks between the two sessions every login, so they coexist without resentment.</p>
<p>On the other hand, what X11 has going for it still applies. <code>xdotool</code>, <code>wmctrl</code>, <code>xprop</code> and <code>xinput</code> keep working for automation, key remapping, screen readers, AutoKey, kanata, xkeysnail. <code>xclip</code>, <code>xsel</code> and clipmenu do straightforward clipboard plumbing, no permission dialog. <code>ssh -X</code> keeps working: you run Firefox on a remote box and the window pops up locally. Legacy Nvidia, vintage Intel and quirky Optimus drivers are all first-class on X11. The tiling WM ecosystem is mature (bspwm, i3, awesome, openbox, xmonad, dwm) and configs port between them with little pain. And the predictable input model, where any client can read any event, is bad for security but excellent for accessibility and productivity tooling.</p>
<p>For older hardware, that&rsquo;s the difference between &ldquo;live machine&rdquo; and &ldquo;machine sitting in a corner&rdquo;.</p>
<h2>Install<span class="hx:absolute hx:-mt-20" id="install"></span>
    <a href="#install" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Prerequisite: Arch Linux with Omarchy already installed. NW-Omarchy runs on top of it, doesn&rsquo;t replace it.</p>
<p>One-liner install:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/akitaonrails/NW-Omarchy/master/boot.sh <span class="p">|</span> bash</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>boot.sh</code> runs preflight (checks Arch, Omarchy, git), clones the repo to <code>~/.local/share/nw-omarchy</code>, and runs the full install pipeline: packages, the <code>nw-bspwm</code> session, configs in <code>~/.config</code>, and the XLibre swap as the last step. It asks for confirmation once before touching anything. Skip the prompt with:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/akitaonrails/NW-Omarchy/master/boot.sh <span class="p">|</span> bash -s -- --yes</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>When it finishes, reboot. The X server swap (xorg-server → XLibre) only takes effect on the next session. At SDDM you&rsquo;ll see a session picker. We also swapped Omarchy&rsquo;s SDDM theme for one with a selector, because the vanilla Omarchy theme has the session name hard-coded in the QML with no UI to change it. Pick <code>nw-bspwm</code> and you&rsquo;re in.</p>
<p>If you&rsquo;d rather clone and run by hand to inspect first:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/akitaonrails/NW-Omarchy.git ~/.local/share/nw-omarchy
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ~/.local/share/nw-omarchy
</span></span><span class="line"><span class="cl">./install.sh           <span class="c1"># dry-run, prints what it would do</span>
</span></span><span class="line"><span class="cl">./install.sh --apply   <span class="c1"># actually run it</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Upgrade<span class="hx:absolute hx:-mt-20" id="upgrade"></span>
    <a href="#upgrade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When a new release ships, the path is:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nw-omarchy-upgrade --check    <span class="c1"># checks current vs latest, exits</span>
</span></span><span class="line"><span class="cl">nw-omarchy-upgrade            <span class="c1"># yay -Syu, fetch latest tag, migrations, install</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The script runs <code>yay -Syu</code> (or <code>pacman -Syu</code> if you don&rsquo;t have yay), compares the local tag to the remote, and if there&rsquo;s a new release does <code>git fetch &amp;&amp; git checkout v&lt;latest&gt;</code>, runs the migrations between the current and new versions, and re-applies <code>install.sh --apply</code>. All idempotent. Re-running on an already-current machine is a no-op.</p>
<h2>Uninstall<span class="hx:absolute hx:-mt-20" id="uninstall"></span>
    <a href="#uninstall" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you tried it and didn&rsquo;t like it, uninstall this way:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">~/.local/share/nw-omarchy/uninstall.sh --apply</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The uninstaller reads <code>~/.local/state/nw-omarchy/manifest.tsv</code> and replays it in reverse: removes only the packages it installed (<code>pkg-skip</code> rows are left alone; packages that were already on the system stay on the system), restores original configs from <code>~/.local/state/nw-omarchy/backups/</code>, deletes the <code>nw-bspwm</code> session entry, wipes the state dir. Your Hyprland session keeps working as before. Nothing under <code>~/.config/hypr/</code> or <code>~/.local/share/omarchy/</code> gets touched at any point during install or uninstall.</p>
<p>To revert specifically XLibre back to xorg-server (without uninstalling anything else), pacman handles it on its own:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S xorg-server xorg-server-common xf86-input-libinput</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The package <code>provides</code>/<code>conflicts</code> graph handles the rest of the swap atomically.</p>
<h2>Status: experimental, feedback welcome<span class="hx:absolute hx:-mt-20" id="status-experimental-feedback-welcome"></span>
    <a href="#status-experimental-feedback-welcome" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The current version is at 1.0 but the project is still young, in polish phase. The big items are in place: binding parity, menu parity, theme parity, TUI parity, doctor for health-checking the install, manifest for clean uninstall. What&rsquo;s left is polish, edge cases, working through varied hardware, listening to feedback from anyone running it on a different machine than mine (Thinkpad T14 Gen 6).</p>
<p>If you try it and hit something (something that doesn&rsquo;t work, configuration that&rsquo;s missing, behavior that differs from Omarchy in a way that breaks flow), open an issue here:</p>
<p><a href="https://github.com/akitaonrails/NW-Omarchy/issues"target="_blank" rel="noopener">github.com/akitaonrails/NW-Omarchy/issues</a></p>
<p>Repros, stack traces, output of <code>nw-omarchy-doctor</code>, anything helps. PRs are welcome too.</p>
<p>Defending X11 in 2026 is a pragmatic argument. The transition to Wayland takes time, plenty of hardware and plenty of software still live comfortably on this side of the fence, and the open source community can support more than one path at a time. XLibre is the bet on keeping the X server alive a few more years. NW-Omarchy is my bet that you can make this older stack look as pretty as the newer one, without compromising any of what makes X11 still worth the trip.</p>
<p>If you&rsquo;re on a new machine, modern GPU, 4K HiDPI display, wanting HDR, stay on Omarchy/Hyprland. If you&rsquo;re on an older box, or you simply prefer the X11 ecosystem for any of the reasons above, give NW-Omarchy a shot.</p>
]]></content:encoded><category>omarchy</category><category>linux</category></item><item><title>Omarchy on the Thinkpad T14 Gen 6: Mini-Review and Full Setup</title><link>https://www.akitaonrails.com/en/2026/04/18/omarchy-on-thinkpad-t14-gen-6/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/04/18/omarchy-on-thinkpad-t14-gen-6/</guid><pubDate>Sat, 18 Apr 2026 08:30:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/closed-lid.jpg" alt="Thinkpad T14 Gen 6 closed, next to its USB-C charger" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;I bought a Lenovo Thinkpad T14 Gen 6 and installed Omarchy on it. It&amp;rsquo;s not my main machine, and it&amp;rsquo;s not supposed to be. It&amp;rsquo;s a companion: a notebook I can open on the 3D printing office desk, SSH into the desktop, fire up Claude Code, access files on the NAS, debug the network through ethernet without hunting for a USB dongle and a long cable. This article covers the hardware choice, the Omarchy setup on top, the customizations specific to a laptop and to this Thinkpad in particular, and the architecture decisions that might not be obvious.&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/closed-lid.jpg" alt="Thinkpad T14 Gen 6 closed, next to its USB-C charger"  loading="lazy" /></p>
<p>I bought a Lenovo Thinkpad T14 Gen 6 and installed Omarchy on it. It&rsquo;s not my main machine, and it&rsquo;s not supposed to be. It&rsquo;s a companion: a notebook I can open on the 3D printing office desk, SSH into the desktop, fire up Claude Code, access files on the NAS, debug the network through ethernet without hunting for a USB dongle and a long cable. This article covers the hardware choice, the Omarchy setup on top, the customizations specific to a laptop and to this Thinkpad in particular, and the architecture decisions that might not be obvious.</p>
<h2>Mini-review of the Thinkpad T14 Gen 6<span class="hx:absolute hx:-mt-20" id="mini-review-of-the-thinkpad-t14-gen-6"></span>
    <a href="#mini-review-of-the-thinkpad-t14-gen-6" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/open-lid-turned-off.jpg" alt="Thinkpad T14 Gen 6 open with the screen off, showing the keyboard and the Intel Core Ultra 5 sticker"  loading="lazy" /></p>
<p>Let&rsquo;s get this out of the way: this isn&rsquo;t the notebook of my dreams. If I were picking by looks, I&rsquo;d grab an Asus Zenbook S 14 with an OLED screen. If I were picking by portability, the Thinkpad T14s with the aluminum shell, which is lighter and much better looking. The regular T14 has a 14&quot; 1920x1200 IPS panel, 400 nits, 60Hz, no HDR. It gets the job done, but it&rsquo;s a far cry from the Zenbook&rsquo;s screen. The shell is plastic with a rubberized finish, which makes it scratch-resistant but not premium. Reviews from <a href="https://www.notebookcheck.net/AMD-Ryzen-AI-meets-classic-ThinkPad-Lenovo-ThinkPad-T14-Gen-6-AMD-laptop-review.1222690.0.html"target="_blank" rel="noopener">NotebookCheck</a> and <a href="https://www.xda-developers.com/lenovo-thinkpad-t14-gen-6-review/"target="_blank" rel="noopener">XDA Developers</a> land on the same verdict: good price, good connectivity, fine performance for office work, but the screen is dated.</p>
<p>What makes up for it:</p>
<ul>
<li>Port selection. Full-size HDMI. Gigabit ethernet. USB-A, USB-C Thunderbolt 4, charges over USB-C (not a proprietary charger). For a debug companion, this is exactly what I wanted. The Zenbook S 14, being thinner, cuts ports.</li>
<li>Fingerprint sensor that actually works on Linux (Goodix MOC, works with libfprint on kernel 6.11+). I use this, details later.</li>
<li>Thinkpad keyboard. 1.5mm key travel, trackpoint, classic layout. It&rsquo;s not the best keyboard in the world in 2026, but it&rsquo;s reliable and durable.</li>
<li>Rugged shell. It will fall, it will scratch, it will travel in a backpack. If I put a Zenbook OLED or a Macbook Pro on the 3D printing office desk next to the printer with PLA dust in the air, I&rsquo;d be nervous. The Thinkpad can take a beating.</li>
</ul>
<p>If I wanted a gaming machine, I&rsquo;d get an Asus Zephyrus G14, my favorite gaming notebook. If I wanted a creative work machine, I&rsquo;d get the <a href="https://www.asus.com/laptops/for-home/zenbook/zenbook-duo-ux8406/"target="_blank" rel="noopener">Asus Zenbook Duo (UX8406)</a> with two vertical OLED screens, great for video editing and 3D modeling. I can afford any Macbook Pro or Mac Studio, and I chose not to go that way. I&rsquo;ll explain in the next section.</p>
<h2>My use case<span class="hx:absolute hx:-mt-20" id="my-use-case"></span>
    <a href="#my-use-case" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/open-lid-fastfetch.jpg" alt="Thinkpad open on a 3D printing office bench, with fastfetch showing Omarchy in the terminal"  loading="lazy" /></p>
<p>My main PC is a desktop with Ryzen 9 7950X3D, 96 GB of RAM, RTX 5090 with 32 GB. That&rsquo;s where I work, experiment with local models, run containers, edit the blog. For gaming, I have a separate mini-PC with an RTX 4090. Those two cover 100% of what I need to do at home.</p>
<p>The notebook exists to cover the remaining 1%: sitting on the couch, taking it to the 3D printing office, taking it to the kitchen, short trips. It&rsquo;s not meant to replace the desktop. It&rsquo;s meant to give me remote access to the desktop when I&rsquo;m away from it.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/ssh-to-remote-desktop-on-left.png" alt="Hyprland with two terminals side by side: left is an SSH session on the main desktop (96 GB, RTX 5090), right is the Thinkpad itself. Same UI, two machines."  loading="lazy" /></p>
<p>In practice it looks like this: open the notebook, split the Hyprland layout, left pane SSHs into the main desktop, right pane is the notebook itself. Same Omarchy on both, same keybindings, same bash. The notebook becomes an extension of the desktop, not a parallel environment I have to re-learn in my head every time I switch.</p>
<h3>SSH from outside the house: Tailscale<span class="hx:absolute hx:-mt-20" id="ssh-from-outside-the-house-tailscale"></span>
    <a href="#ssh-from-outside-the-house-tailscale" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Inside the local network, SSH is trivial, the notebook talks to the desktop through the internal IP. Outside the house is another story. My home IP is dynamic, opening port 22 to the internet is a terrible idea, and even with DDNS and port forwarding you&rsquo;re putting SSH on the public internet for any scanner to find.</p>
<p>The solution I use is <a href="https://tailscale.com/"target="_blank" rel="noopener">Tailscale</a>. For those who don&rsquo;t know: Tailscale is a mesh VPN built on WireGuard that creates a private network between your devices (the &ldquo;tailnet&rdquo;). Each machine runs the agent, authenticates once, and gets a fixed IP on the private network (something like 100.x.y.z). Traffic between your own devices goes peer-to-peer, encrypted by WireGuard. It doesn&rsquo;t route through Tailscale&rsquo;s central server, they only coordinate NAT traversal. Result: from my notebook in a café anywhere in the world, I run <code>ssh hal9000</code> and land on my home desktop as if I were on the same network.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/tailscale-machines.png" alt="Tailscale admin panel showing my two tailnet machines, hal9000 (desktop) and hal9666 (thinkpad), both with SSH enabled"  loading="lazy" /></p>
<p>More sophisticated options exist: <a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/"target="_blank" rel="noopener">Cloudflare Tunnel</a> with Zero Trust to expose services publicly with SSO auth, self-hosted headscale, raw WireGuard with manual config, Nebula, OpenVPN. Each has its use case. If you need to expose services to third parties, control granular per-identity access, or run the whole infrastructure at home without depending on anyone, those options win. In my case, it&rsquo;s just notebook talking to desktop, for short periods (it&rsquo;s not a full week of work, it&rsquo;s a weekend debug session), so free Tailscale covers it. The free tier accepts up to 100 devices and 3 users, way more than I need.</p>
<p>Setup is as simple as it gets:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># On Arch/Omarchy</span>
</span></span><span class="line"><span class="cl">sudo pacman -S tailscale
</span></span><span class="line"><span class="cl">sudo systemctl <span class="nb">enable</span> --now tailscaled.service
</span></span><span class="line"><span class="cl">sudo tailscale up --ssh</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The <code>--ssh</code> flag enables <a href="https://tailscale.com/kb/1193/tailscale-ssh/"target="_blank" rel="noopener">Tailscale SSH</a>, which authenticates via tailnet identity instead of a local SSH key. Once you log in through the browser to tailscale, each registered machine can SSH into the others based on ACL policy defined in the admin panel. Zero key management.</p>
<p>I repeat the same on the desktop, log in with the same account, done. Both machines show up in the panel (hal9000 and hal9666 in the screenshot above, both with SSH enabled). From the notebook: <code>ssh hal9000</code>. From the desktop to the notebook: <code>ssh hal9666</code>. No port forwarding, no public IP, no port 22 exposed to the internet. If the notebook is stolen, I remove it from the tailnet with one click.</p>
<p>A practical detail: since the tailnet gives stable names, I added entries to <code>~/.ssh/config</code> to use these short names:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Host hal9000
  HostName hal9000
  User akitaonrails</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now <code>ssh hal9000</code> works from anywhere that has Tailscale connected. It&rsquo;s the closest thing to &ldquo;it just works&rdquo; I&rsquo;ve seen for remote SSH.</p>
<h3>Why not a Mac<span class="hx:absolute hx:-mt-20" id="why-not-a-mac"></span>
    <a href="#why-not-a-mac" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I have no use for macOS. As a dev, I live better in native Linux. Every tool I need has a first-class Linux version, and on macOS I&rsquo;d get a second-class version via Homebrew. I don&rsquo;t do iOS, so I don&rsquo;t need XCode. For mobile I use Flutter or Hotwire Native, which run on any OS. iTerm2 and Ghostty on Mac are fine, but Alacritty, Kitty and Ghostty itself on Linux work just as well. Every good piece of software lands on Linux first and gets ported afterwards. Arch with AUR covers everything in a single <code>yay</code>.</p>
<p>For creative work, I haven&rsquo;t done it professionally in years. DaVinci Resolve Studio on Linux is better than Final Cut Pro. Krita or Affinity Photo replace Photoshop for most cases. Clip Studio Paint on Android is better than Procreate. I simply don&rsquo;t have a workflow that depends on Apple, and the App Store annoys me.</p>
<p>For gaming, Mac is terrible. Apple Silicon has a decent GPU for some things, but the native macOS game library is pathetic compared to Windows or Linux. Game Porting Toolkit exists, CrossOver exists, but for anyone who games seriously, it doesn&rsquo;t cut it. I won&rsquo;t be gaming on the Thinkpad, I have the main desktop and the mini-PC with the RTX 4090 for that. But if I ever feel like running Hollow Knight or some indie on a train, I just install Steam and let Proton handle it. Linux became a real gaming platform in the last few years, with Proton/DXVK running almost the entire Steam catalog (check <a href="https://www.protondb.com/"target="_blank" rel="noopener">ProtonDB</a>). I recently wrote about <a href="/en/2026/04/11/emulation-distrobox-with-claude-code/">running my emulation library in distrobox</a> without polluting the host system. With Mac, those options don&rsquo;t exist.</p>
<p>Another argument that always shows up: &ldquo;but a Mac Mini M4 or a Mac Studio with 128GB of unified memory runs large models locally, it&rsquo;s a ChatGPT replacement.&rdquo; I already tested that thesis and wrote a <a href="/en/2026/04/05/testing-llms-open-source-and-commercial-can-anyone-beat-claude-opus/">detailed benchmark</a>. The conclusion: expensive local hardware to run LLMs is a weekend hobby, not a production tool. The open source models that fit don&rsquo;t deliver the quality Claude Opus delivers. I have a <a href="/en/2026/03/31/migrating-my-home-server-with-claude-code/">home server with AMD Strix Halo and 96 GB of unified RAM</a>, I ran models for dozens of hours, and in my real coding flow they&rsquo;re fine for simple tasks. For complex tasks, Claude Opus. Before spending $4000 on a Mac Studio justifying it with local models, actually test it first. You&rsquo;ll probably end up paying for Opus again.</p>
<h2>Why Omarchy<span class="hx:absolute hx:-mt-20" id="why-omarchy"></span>
    <a href="#why-omarchy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I&rsquo;ve been using Omarchy on the desktop for months and documented the path in a <a href="/en/tags/omarchy/">series of articles</a>. <a href="/en/2025/08/29/new-omarchy-2-0-install/">Omarchy 2.0</a> has its own installer with LUKS, Btrfs, Limine, snapper and SDDM already configured. I wrote about <a href="/en/2025/09/12/omarchy-2-0-install-with-the-omarchy-iso/">using the official ISO</a>, about <a href="/en/2025/09/07/omarchy-2-0-zsh-configs/">ZSH customizations</a> with atuin, starship, secrets properly organized, about <a href="/en/2025/09/07/omarchy-2-0-mise-to-organize-dev-environments/">Mise for multiple languages</a>, about <a href="/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/">LazyVim and LazyExtras</a>, about <a href="/en/2025/09/09/omarchy-2-0-understanding-ssh-and-yubikeys/">SSH and Yubikeys</a>, about <a href="/en/2025/09/09/omarchy-2-0-tuis/">modern TUIs</a>. There&rsquo;s also <a href="/en/2026/01/21/omarchy-3-dual-gpu-setup-with-amd-and-nvidia/">Omarchy 3 with dual GPU AMD + NVIDIA</a> and <a href="/en/2026/01/09/omarchy-3-one-of-the-best-coding-agents-crush/">Crush</a> as a coding agent.</p>
<p>For those who don&rsquo;t know: Omarchy is plain Arch Linux with a cosmetic layer on top of Hyprland/Wayland. Pre-configured with sane defaults. I could build all of it from scratch, I&rsquo;ve done it several times in my life, but why redo work someone already did well? I install Omarchy, I stack the tweaks that are mine on top, and I have customized Arch in a fraction of the time.</p>
<p>A point I raise every time I recommend Omarchy: the documentation is excellent. There&rsquo;s an <a href="https://manuals.omamix.org/2/the-omarchy-manual"target="_blank" rel="noopener">official manual</a> covering everything from installation to theme customization, keybindings, Hyprland, Waybar, the works. If you&rsquo;re coming from Ubuntu or Fedora and are wary of Arch, this manual handles most of the doubts. If you&rsquo;ve never touched Hyprland, open it and read around. It&rsquo;s not a README dumped on GitHub, it&rsquo;s a real manual with chapters and an index.</p>
<p>The story of this article starts in a previous thread. I recently migrated my home server, swapping an old Ubuntu box for a <a href="/en/2026/03/31/migrating-my-home-server-with-claude-code/">Minisforum MS-S1 running openSUSE MicroOS configured with Claude Code</a>. That was the first serious experiment of letting Claude Code drive an entire infra migration, with containers, NFS, services, networking. It worked. And it left an idea in the air: why not use the same approach to configure a new notebook?</p>
<p>That&rsquo;s what I did. I grabbed the Thinkpad, downloaded the latest Omarchy ISO, burned it to a flash drive, installed it over Windows. From zero to working desktop in under an hour. From there on, it&rsquo;s all tweaking, which I documented as I went.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/open-lid-claude-terminal.jpg" alt="Claude Code running on the Thinkpad terminal, ready to start configuring the notebook"  loading="lazy" /></p>
<p>I&rsquo;ll detail the two layers of customization: what any notebook needs, and what&rsquo;s specific to this Thinkpad.</p>
<h2>Laptop-specific configs<span class="hx:absolute hx:-mt-20" id="laptop-specific-configs"></span>
    <a href="#laptop-specific-configs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A notebook has problems a desktop doesn&rsquo;t: battery, suspend, lid, brightness, trackpad. Those are the parts Omarchy default doesn&rsquo;t cover the way I want.</p>
<h3>Power management with TLP<span class="hx:absolute hx:-mt-20" id="power-management-with-tlp"></span>
    <a href="#power-management-with-tlp" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Omarchy defaults to <code>power-profiles-daemon</code>. I swapped it for TLP, which gives granular control over CPU scaling, battery thresholds and dynamic profiles based on AC vs battery.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S tlp tlp-rdw
</span></span><span class="line"><span class="cl">sudo systemctl mask power-profiles-daemon.service
</span></span><span class="line"><span class="cl">sudo systemctl <span class="nb">enable</span> --now tlp.service</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The <code>mask</code> is necessary because upower pulls <code>power-profiles-daemon</code> back in if you just <code>disable</code> it.</p>
<p>Charge thresholds: 60% to start, 85% to stop. The notebook spends most of its time plugged in on the office desk, and keeping the battery at 100% 24/7 wrecks capacity over time. With 60/85, the battery spends most of its time in the healthy lithium range and still has decent usable capacity.</p>
<p>Profiles: <code>balanced</code> with <code>balance_power</code> on battery, <code>performance</code> on AC. TLP&rsquo;s <code>low-power</code> was too aggressive on the Core Ultra 5 235U, window and terminal response became noticeable. Balanced gives the best consumption/responsiveness ratio for normal use.</p>
<p>There&rsquo;s a gotcha: <code>tlp auto</code> after <code>tlp ac</code> doesn&rsquo;t always re-apply the battery profile. I wrote a small script bound to <code>Super+Ctrl+P</code> that reads the current state and calls <code>tlp bat</code> or <code>tlp ac</code> explicitly:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">profile</span><span class="o">=</span><span class="k">$(</span>cat /sys/firmware/acpi/platform_profile 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> unknown<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">on_ac</span><span class="o">=</span><span class="k">$(</span>cat /sys/class/power_supply/AC*/online 2&gt;/dev/null <span class="p">|</span> head -1 <span class="o">||</span> <span class="nb">echo</span> 0<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$profile</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;performance&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$on_ac</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;1&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    sudo /usr/bin/tlp auto &gt;/dev/null
</span></span><span class="line"><span class="cl">    <span class="nv">label</span><span class="o">=</span><span class="s2">&#34;Plugged in — back to AC auto&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">    sudo /usr/bin/tlp bat &gt;/dev/null
</span></span><span class="line"><span class="cl">    <span class="nv">label</span><span class="o">=</span><span class="s2">&#34;On battery — normal profile&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">fi</span>
</span></span><span class="line"><span class="cl">  notify-send -t <span class="m">2000</span> <span class="s2">&#34;Performance mode: off&#34;</span> <span class="s2">&#34;</span><span class="nv">$label</span><span class="s2">&#34;</span> 2&gt;/dev/null <span class="o">||</span> <span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  sudo /usr/bin/tlp ac &gt;/dev/null
</span></span><span class="line"><span class="cl">  notify-send -t <span class="m">2000</span> <span class="s2">&#34;Performance mode: on&#34;</span> <span class="s2">&#34;Forcing AC profile&#34;</span> 2&gt;/dev/null <span class="o">||</span> <span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In waybar, a custom module <code>custom/perf</code> shows the current state (󰓅 PERF, 󰌪 ECO, or empty for balanced) and accepts a click to toggle. The output script is tiny:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="nv">p</span><span class="o">=</span><span class="k">$(</span>cat /sys/firmware/acpi/platform_profile 2&gt;/dev/null<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="s2">&#34;</span><span class="nv">$p</span><span class="s2">&#34;</span> in
</span></span><span class="line"><span class="cl">  performance<span class="o">)</span> <span class="nb">printf</span> <span class="s1">&#39;󰓅 PERF&#39;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="cl">  low-power<span class="o">)</span>   <span class="nb">printf</span> <span class="s1">&#39;󰌪 ECO&#39;</span>  <span class="p">;;</span>
</span></span><span class="line"><span class="cl">  balanced<span class="p">|</span><span class="s2">&#34;&#34;</span><span class="o">)</span> <span class="nb">printf</span> <span class="s1">&#39;&#39;</span>       <span class="p">;;</span>
</span></span><span class="line"><span class="cl">  *<span class="o">)</span>           <span class="nb">printf</span> <span class="s1">&#39;%s&#39;</span> <span class="s2">&#34;</span><span class="nv">$p</span><span class="s2">&#34;</span> <span class="p">;;</span>
</span></span><span class="line"><span class="cl"><span class="k">esac</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Suspend, hibernate, and the lid<span class="hx:absolute hx:-mt-20" id="suspend-hibernate-and-the-lid"></span>
    <a href="#suspend-hibernate-and-the-lid" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is what changed compared to the notebooks I used in 2015. The T14 Gen 6 closes the lid, suspends, and wakes up when you open it. No bug, no weird delay, no needing to log in again mid graphical session. Hyprlock kicks in after the suspend, accepts fingerprint or password, and brings me back to the desktop in seconds. This is the behavior Apple has had for years and that on Linux used to be an adventure. In 2026, on modern hardware with kernel 6.11+, it just works.</p>
<p>Mem sleep mode is s2idle (no deep sleep). Hibernation is enabled via a ~30 GB Btrfs swapfile and <code>resume=/dev/mapper/root resume_offset=...</code> on the Limine kernel cmdline. I rarely use it, but it&rsquo;s there.</p>
<p>Hypridle has aggressive timeouts for a laptop:</p>
<ul>
<li>2.5 min → screensaver</li>
<li>5 min → lock</li>
<li>5.5 min → DPMS off + keyboard backlight off</li>
</ul>
<p>After lock, another 5 min and the screen turns off completely. On unlock, it restores screen and keyboard brightness to the previous level. These timings are much shorter than on the desktop (20-40 min there). The battery difference over a day is measurable.</p>
<h3>Brightness and keyboard backlight<span class="hx:absolute hx:-mt-20" id="brightness-and-keyboard-backlight"></span>
    <a href="#brightness-and-keyboard-backlight" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><code>brightnessctl</code> controls both. Fn+Space toggles the keyboard backlight across three levels. Hypridle saves the current level before turning off and restores it on resume. Command I use in the script:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brightnessctl -sd <span class="s1">&#39;*::kbd_backlight&#39;</span> <span class="nb">set</span> <span class="m">0</span>    <span class="c1"># save and turn off</span>
</span></span><span class="line"><span class="cl">brightnessctl -rd <span class="s1">&#39;*::kbd_backlight&#39;</span>          <span class="c1"># restore</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Touchpad<span class="hx:absolute hx:-mt-20" id="touchpad"></span>
    <a href="#touchpad" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In <code>hypr/input.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>touchpad {
    natural_scroll = true
    clickfinger_behavior = true
    disable_while_typing = true
    scroll_factor = 0.4
}
gesture = 3, horizontal, workspace</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>clickfinger_behavior</code> swaps the 2-finger click as right-click (more comfortable than hitting the lower-right zone). <code>disable_while_typing</code> is basic palm rejection. Three-finger horizontal swipes switch workspaces, the most useful gesture in Hyprland.</p>
<h2>Thinkpad-specific configs<span class="hx:absolute hx:-mt-20" id="thinkpad-specific-configs"></span>
    <a href="#thinkpad-specific-configs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is what&rsquo;s specific to this model. Some things modern Linux handles on its own, others need explicit configuration.</p>
<h3>Fingerprint sensor<span class="hx:absolute hx:-mt-20" id="fingerprint-sensor"></span>
    <a href="#fingerprint-sensor" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Goodix MOC <code>27c6:6594</code>, works with libfprint 1.94.9+ on kernel 6.11+. Package is <code>fprintd</code>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S fprintd
</span></span><span class="line"><span class="cl">fprintd-enroll                        <span class="c1"># right index finger by default</span>
</span></span><span class="line"><span class="cl">fprintd-enroll -f left-index-finger   <span class="c1"># other finger</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>To make <code>sudo</code> accept fingerprint, I added <code>auth sufficient pam_fprintd.so</code> above the <code>pam_unix.so</code> line in <code>/etc/pam.d/sudo</code>. With <code>sufficient</code>, if the fingerprint passes, it authenticates directly. If it fails or I hit ESC, it falls back to the password prompt. This is genuinely worth it: dozens of times a day, <code>sudo pacman -Syu</code> or <code>sudo systemctl restart something</code>, and I just touch the sensor.</p>
<p>On hyprlock, I use hyprlock&rsquo;s native configuration, not PAM:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>auth {
    fingerprint {
        enabled = true
        ready_message = Scan fingerprint or type password
        present_message = Scanning...
        retry_delay = 250
    }
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The PAM path gives a double prompt. Configured natively, hyprlock accepts fingerprint or password, whichever succeeds first unlocks.</p>
<p>On SDDM (initial login), I kept password only. The reason: the login password unlocks the GNOME keyring, and the fingerprint can&rsquo;t provide plaintext for that. Once the keyring is unlocked, hyprlock can use fingerprint without issues.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/sudo-asks-for-fingerprinting.png" alt="sudo prompt asking for fingerprint read"  loading="lazy" /></p>
<p>In practice, sudo looks like that. Touch the sensor, authenticate, move on.</p>
<h3>Brazilian Thinkpad keyboard<span class="hx:absolute hx:-mt-20" id="brazilian-thinkpad-keyboard"></span>
    <a href="#brazilian-thinkpad-keyboard" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The Brazilian Thinkpad keyboard has an annoying quirk. The <code>/?</code> key sits where the right Ctrl would be (keycode 97), not in the traditional ABNT2 AB11 position (keycode 89). If you use the standard <code>br(abnt2)</code> layout, that key is inaccessible. It literally prints nothing.</p>
<p>The solution is the <code>br(thinkpad)</code> variant that exists in <code>/usr/share/X11/xkb/symbols/br</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>xkb_symbols &#34;thinkpad&#34; {
    include &#34;br(abnt2)&#34;
    name[Group1]=&#34;Portuguese (Brazil, IBM/Lenovo ThinkPad)&#34;;
    key &lt;RCTL&gt; { [ slash, question, degree, questiondown ] };
};</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In <code>hypr/input.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>kb_layout = br
kb_variant = thinkpad
kb_model = thinkpad60</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And system-wide for TTY/X11:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo localectl set-keymap br-abnt2
</span></span><span class="line"><span class="cl">sudo localectl set-x11-keymap br thinkpad thinkpad60</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I wrote a small Python that reads raw scancodes from <code>/dev/input/event*</code> to diagnose these quirks. Useful when a key decides not to work and you need to find out if it&rsquo;s hardware, kernel, or xkb.</p>
<h3>Input method: fcitx5<span class="hx:absolute hx:-mt-20" id="input-method-fcitx5"></span>
    <a href="#input-method-fcitx5" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Alongside the layout I install fcitx5. Input method, for those who don&rsquo;t know, is the layer that turns a key sequence into characters. It handles deadkeys (tilde for nasalization, acute accent, circumflex), composing characters that aren&rsquo;t on the keyboard (ç, Ç, uppercase accented letters), emoji support. In Qt or GTK apps, the input method also drives context menus for cedilla and accents.</p>
<p>Packages:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S --needed fcitx5 fcitx5-configtool fcitx5-gtk fcitx5-qt</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And the environment variables for toolkits to find fcitx5. I created <code>~/.config/environment.d/fcitx.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>INPUT_METHOD=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx
SDL_IM_MODULE=fcitx</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>systemd&rsquo;s <code>environment.d</code> is loaded before graphical sessions, so Brave, Alacritty, VS Code and any GTK/Qt app pick it up automatically. I enable autostart in Hyprland:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>exec-once = fcitx5 -d</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Typing <code>~a</code> produces <code>ã</code>, <code>'e</code> produces <code>é</code>, <code>ç</code> works as it should in every app. On a Brazilian Thinkpad keyboard, this is the difference between typing Portuguese naturally or hunting for each character.</p>
<h3>SOF audio<span class="hx:absolute hx:-mt-20" id="sof-audio"></span>
    <a href="#sof-audio" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Realtek ALC3306/ALC287 codec via Sound Open Firmware. Without <code>sof-firmware</code>, the kernel module loads but the DSP never boots and PipeWire silently falls back to <code>auto_null</code>. Result: you think the speaker is on mute, but actually PipeWire has no device at all.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S --needed sof-firmware alsa-ucm-conf pipewire pipewire-pulse wireplumber</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you need to force SOF instead of legacy HDA:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;options snd-intel-dspcfg dsp_driver=3&#34;</span> <span class="p">|</span> sudo tee /etc/modprobe.d/alsa.conf</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Reload without reboot:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo modprobe -r snd_sof_pci_intel_mtl
</span></span><span class="line"><span class="cl">sudo modprobe snd_sof_pci_intel_mtl
</span></span><span class="line"><span class="cl">systemctl --user restart wireplumber pipewire pipewire-pulse</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Firmware updates via fwupd<span class="hx:absolute hx:-mt-20" id="firmware-updates-via-fwupd"></span>
    <a href="#firmware-updates-via-fwupd" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/bios-update.jpg" alt="Lenovo firmware update (ME Corp) running on boot"  loading="lazy" /></p>
<p><code>fwupdmgr update</code> works, but with Limine there&rsquo;s a gotcha: fwupd tries to write to <code>/boot/EFI/systemd/</code> or <code>/boot/EFI/arch/</code>, which don&rsquo;t exist. The workaround:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo mkdir -p /boot/EFI/arch
</span></span><span class="line"><span class="cl">sudo fwupdmgr update -y --no-reboot-check
</span></span><span class="line"><span class="cl">fwupdmgr get-history  <span class="c1"># should show &#34;Success&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>HiDPI / fractional scaling<span class="hx:absolute hx:-mt-20" id="hidpi--fractional-scaling"></span>
    <a href="#hidpi--fractional-scaling" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>14&quot; panel at 1920x1200, Hyprland&rsquo;s free resolution. Omarchy&rsquo;s auto 1.5x felt too chunky. I pinned it at 1.333x:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>env = GDK_SCALE,1
monitor=,preferred,auto,1.3333,vrr,2</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Effective 1440x900. GTK with <code>GDK_SCALE=1</code> renders 1:1 with Hyprland (no double magnification). VRR mode 2 only in fullscreen, because LCD panels tend to flicker on static content with VRR active.</p>
<p>Brave and Chromium flags to render well at this scale:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>--ozone-platform=wayland
--enable-features=WaylandFractionalScaleV1,UseOzonePlatform,VaapiVideoDecoder,VaapiVideoEncoder
--enable-gpu-rasterization</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>VAAPI makes a real difference on YouTube battery life.</p>
<h2>Tuning Omarchy to be mine<span class="hx:absolute hx:-mt-20" id="tuning-omarchy-to-be-mine"></span>
    <a href="#tuning-omarchy-to-be-mine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Omarchy comes with good defaults. What I adjust stacks on top of them, without touching <code>~/.local/share/omarchy/</code> (which is clobbered by <code>omarchy-update</code>). All customization lives in <code>~/.config/</code>.</p>
<h3>Infra: Btrfs, snapshots, Snapper<span class="hx:absolute hx:-mt-20" id="infra-btrfs-snapshots-snapper"></span>
    <a href="#infra-btrfs-snapshots-snapper" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Omarchy already ships with Btrfs and separate subvolumes:</p>
<table>
  <thead>
      <tr>
          <th>Subvolume</th>
          <th>Mount</th>
          <th>In snapshots?</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>@</code></td>
          <td><code>/</code></td>
          <td>yes</td>
      </tr>
      <tr>
          <td><code>@home</code></td>
          <td><code>/home</code></td>
          <td>no</td>
      </tr>
      <tr>
          <td><code>@log</code></td>
          <td><code>/var/log</code></td>
          <td>no</td>
      </tr>
      <tr>
          <td><code>@pkg</code></td>
          <td><code>/var/cache/pacman/pkg</code></td>
          <td>no</td>
      </tr>
  </tbody>
</table>
<p><code>@home</code> separated means <code>~/.cache</code>, <code>~/.config/BraveSoftware</code>, etc. don&rsquo;t bloat root snapshots. Snapshot is for system, not profile.</p>
<p>Swap: 4 GB zram at priority 100 (hit first), plus a 30 GB swapfile at priority 0 (enables hibernation, sized to match RAM).</p>
<p>The snapshot stack: Snapper takes a snapshot before and after every <code>pacman -Syu</code> via snap-pac. <code>limine-snapper-sync</code> writes those snapshots into the Limine menu, so you can boot into a previous snapshot to roll back. If something breaks after an update, you hold a key on boot, pick the pre-update snapshot, boot read-only to verify, and if it&rsquo;s good, run <code>snapper rollback</code>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/btrfs-snapshots-config.png" alt="Btrfs subvolumes separated so root snapshots don’t balloon with user cache"  loading="lazy" /></p>
<p>Omarchy leaves <code>snapper-cleanup.timer</code> and <code>snapper-boot.timer</code> disabled by default. I enabled both and configured retention to fit on a 1 TB SSD without blowing up:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>TIMELINE_LIMIT_HOURLY=10
TIMELINE_LIMIT_DAILY=0
TIMELINE_LIMIT_WEEKLY=1
TIMELINE_LIMIT_MONTHLY=1
NUMBER_LIMIT=50</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A detail that costs debug time if you forget: Docker and Ollama write gigabytes into <code>/var/lib/docker</code> and <code>/var/lib/ollama</code>. If that falls inside <code>@</code>, snapshots go catastrophic. Each Docker image or Ollama model downloaded triples in size. I created nested subvolumes for both, with <code>chattr +C</code> to disable CoW:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo btrfs subvolume create /var/lib/docker
</span></span><span class="line"><span class="cl">sudo chattr +C /var/lib/docker
</span></span><span class="line"><span class="cl">sudo btrfs subvolume create /var/lib/ollama</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This has to be done BEFORE Docker or Ollama writes any data. If they already have data there, you need to migrate.</p>
<h3>NFS to the Synology NAS<span class="hx:absolute hx:-mt-20" id="nfs-to-the-synology-nas"></span>
    <a href="#nfs-to-the-synology-nas" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>My Synology exposes three volumes. On the desktop, I mount them the usual way. On the notebook, it has to be more defensive. The notebook moves around, forgets networks, connects to public WiFi. Notebook&rsquo;s fstab:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>nfs4  _netdev,noauto,nofail,x-systemd.automount,x-systemd.idle-timeout=10min,x-systemd.mount-timeout=15s,noatime,nodiratime,nconnect=4,actimeo=10,soft,timeo=30,retrans=2</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Critical difference vs the desktop: <code>soft</code> with short timeouts (doesn&rsquo;t hang forever), <code>x-systemd.idle-timeout=10min</code> (auto-unmount when idle), no <code>network-online.target</code> in the require (doesn&rsquo;t slow boot). Practical result: <code>cd /mnt/gigachad</code> at home mounts lazily, away from home it fails fast without locking the shell.</p>
<p>Another important detail: my user on the notebook has UID 1026, which matches the share permissions on the Synology. Linux defaults to creating users at 1000, the Synology enforces identity via UID on the wire. If the UIDs don&rsquo;t match, you can&rsquo;t read the files, or worse, you write as nobody. I ran the <code>usermod</code>/<code>groupmod</code> from a TTY (with the user logged out) to remap the user to 1026/1026 and did <code>chown -R</code> on <code>/home</code>.</p>
<h3>Public WiFi hardening<span class="hx:absolute hx:-mt-20" id="public-wifi-hardening"></span>
    <a href="#public-wifi-hardening" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The notebook will leave the house. In an airport or café, I don&rsquo;t want to announce hostname, don&rsquo;t want a trackable MAC, don&rsquo;t want a service listening on an open port.</p>
<p><code>/etc/NetworkManager/conf.d/00-macrandomize.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>[device]
wifi.scan-rand-mac-address=yes

[connection]
wifi.cloned-mac-address=stable
ethernet.cloned-mac-address=stable
connection.stable-id=${CONNECTION}/${BOOT}

ipv6.ip6-privacy=2
ipv6.addr-gen-mode=stable-privacy</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Random MAC per scan (passive anti-fingerprinting). Stable cloned MAC per SSID (captive portals don&rsquo;t re-prompt you every time) but different MACs between networks. IPv6 with temporary addresses and interface ID derived from a stable secret, not from the MAC (no EUI-64 leak).</p>
<p><code>/etc/systemd/resolved.conf.d/hardening.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>[Resolve]
LLMNR=no
MulticastDNS=no</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Kills hostname broadcast on LLMNR and mDNS. I also disable avahi:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo systemctl disable --now avahi-daemon.service avahi-daemon.socket</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>UFW firewall:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ufw default deny incoming
</span></span><span class="line"><span class="cl">sudo ufw default allow outgoing
</span></span><span class="line"><span class="cl">sudo ufw --force enable</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>SSH server is already off by default on Omarchy. Nothing listening. Even if the firewall leaks, there&rsquo;s no surface.</p>
<p>All of it rolls into a single initial setup ritual.</p>
<h3>SSH agent persistence (keyring + keychain)<span class="hx:absolute hx:-mt-20" id="ssh-agent-persistence-keyring--keychain"></span>
    <a href="#ssh-agent-persistence-keyring--keychain" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>If you use SSH seriously, you want to type the passphrase once per boot and have <code>ssh</code>, <code>git push</code>, <code>scp</code> stay silent for the rest of the day. On current Arch there&rsquo;s a catch: <code>gnome-keyring</code> 50 dropped its SSH component, and the replacement (<code>gcr-ssh-agent</code>) is a plain in-memory agent with no passphrase persistence. The &ldquo;remember this key&rdquo; checkbox you saw in old guides simply doesn&rsquo;t exist anymore.</p>
<p>The combination that works has three pieces:</p>
<ol>
<li><code>gcr-ssh-agent.socket</code> managed by systemd serves <code>SSH_AUTH_SOCK</code> at <code>$XDG_RUNTIME_DIR/gcr/ssh</code></li>
<li><code>pam_gnome_keyring</code> on SDDM login unlocks the keyring with the login password (used by GUI apps like Brave, not by SSH)</li>
<li><code>keychain</code> (wrapper) keeps an <code>ssh-agent</code> alive across logouts, overrides <code>SSH_AUTH_SOCK</code> to point at that persistent agent, and caches the PID in <code>~/.keychain/&lt;host&gt;-sh</code></li>
</ol>
<p>First, install the keyring:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S --needed gnome-keyring seahorse keychain</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then edit <code>/etc/pam.d/sddm</code> so the login password unlocks the keyring automatically. Add at the top:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>-auth      optional    pam_gnome_keyring.so</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And at the end:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>-session   optional    pam_gnome_keyring.so    auto_start</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The leading hyphen (<code>-auth</code>, <code>-session</code>) marks it optional, so if the module fails to load, login doesn&rsquo;t break.</p>
<p>Pin <code>SSH_AUTH_SOCK</code> for graphical and TTY sessions via <code>~/.config/environment.d/ssh-agent.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>SSH_AUTH_SOCK=%t/gcr/ssh</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>%t</code> resolves to <code>$XDG_RUNTIME_DIR</code>, something like <code>/run/user/1026</code>. Enable the gcr socket and user linger (so user daemons survive logout):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">systemctl --user <span class="nb">enable</span> --now gcr-ssh-agent.socket
</span></span><span class="line"><span class="cl">sudo loginctl enable-linger <span class="nv">$USER</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, in <code>~/.config/bash/init.sh</code>, keychain starts or reuses the agent:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="nb">command</span> -v keychain <span class="p">&amp;</span>&gt;/dev/null <span class="o">&amp;&amp;</span> <span class="o">[[</span> -r ~/.ssh/id_ed25519 <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  <span class="nb">eval</span> <span class="s2">&#34;</span><span class="k">$(</span>keychain --eval --quiet ~/.ssh/id_ed25519<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>--eval</code> emits shell assignments (<code>SSH_AUTH_SOCK</code>, <code>SSH_AGENT_PID</code>) pointing to keychain&rsquo;s agent, overriding the gcr path set by environment.d. <code>--quiet</code> silences the banner once the key is loaded.</p>
<p>Flow in practice: boot → first terminal → keychain prompts for the passphrase once → key stays loaded. Logout → login again → new shells reattach to the same agent (via <code>~/.keychain/&lt;host&gt;-sh</code>) → zero prompts. <code>ssh-add -l</code> confirms the key is there, <code>echo $SSH_AUTH_SOCK</code> confirms it&rsquo;s at keychain&rsquo;s path.</p>
<p>When you&rsquo;ll re-enter the passphrase: reboot, <code>ssh-add -D</code>, or <code>keychain --clear</code>. In normal use, once a day.</p>
<h3>Bash instead of ZSH<span class="hx:absolute hx:-mt-20" id="bash-instead-of-zsh"></span>
    <a href="#bash-instead-of-zsh" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>On the desktop I use ZSH. On the notebook I went with Bash to align with Omarchy&rsquo;s default, without having to maintain a parallel stack of modular layers. <code>~/.bashrc</code> is a symlink to <code>~/.config/bash/bashrc</code>, which sources Omarchy&rsquo;s defaults first and then stacks my customizations:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">source</span> ~/.local/share/omarchy/default/bash/rc
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.config/bash/envs.sh
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.config/bash/aliases.sh
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.config/bash/mounts.sh
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.config/bash/init.sh
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.config/bash/secrets    <span class="c1"># gitignored, chmod 600</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>envs.sh</code> has what&rsquo;s mine: OpenRouter base URL, Ollama pointing to the LAN GPU box (192.168.0.14), AWS region, Hugo analytics, zoxide and SSH agent configs. <code>aliases.sh</code> has TLP shortcuts, an alias for <code>shell-gpt</code> via Docker, and functions to harden PATH when running <code>makepkg</code> or <code>yay</code> (prevents binary injection via a malicious user config).</p>
<p><code>init.sh</code> does the integration work. Atuin with a manual bind for Ctrl-R (so the up arrow keeps bash&rsquo;s default history-search, which I use more). Keychain loading <code>~/.ssh/id_ed25519</code> once per boot and reusing it across shells (no need to re-authenticate SSH every time). Blesh if installed (ZSH-style autosuggestions for Bash). And a function that has PROMPT_COMMAND set the window title to the current pwd and the running command:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">__title_idle<span class="o">()</span> <span class="o">{</span> <span class="nb">printf</span> <span class="s1">&#39;\033]2;%s\007&#39;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">PWD</span><span class="p">/#</span><span class="nv">$HOME</span><span class="p">/~</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">__title_busy<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">  <span class="nb">local</span> <span class="nv">cmd</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">BASH_COMMAND</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="o">[[</span> <span class="s2">&#34;</span><span class="nv">$cmd</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;__title_&#34;</span>* <span class="o">||</span> <span class="s2">&#34;</span><span class="nv">$cmd</span><span class="s2">&#34;</span> <span class="o">==</span> *<span class="s2">&#34;PROMPT_COMMAND&#34;</span>* <span class="o">]]</span> <span class="o">&amp;&amp;</span> <span class="k">return</span>
</span></span><span class="line"><span class="cl">  <span class="nb">printf</span> <span class="s1">&#39;\033]2;%s — %s\007&#39;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">PWD</span><span class="p">/#</span><span class="nv">$HOME</span><span class="p">/~</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$cmd</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> -n <span class="s2">&#34;</span><span class="si">${</span><span class="nv">PROMPT_COMMAND</span><span class="p">-</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  <span class="nv">PROMPT_COMMAND</span><span class="o">=</span><span class="s2">&#34;__title_idle; </span><span class="si">${</span><span class="nv">PROMPT_COMMAND</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  <span class="nv">PROMPT_COMMAND</span><span class="o">=</span><span class="s2">&#34;__title_idle&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="nb">trap</span> <span class="s1">&#39;__title_busy&#39;</span> DEBUG</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Idle, the title shows just the pwd. With a command running, <code>trap DEBUG</code> catches the <code>BASH_COMMAND</code> and updates the title. Waybar&rsquo;s <code>hyprland/window</code> picks that up and displays it.</p>
<p>For the modern Rust toolbelt, the list:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pacman -S --needed <span class="se">\
</span></span></span><span class="line"><span class="cl">  eza bat fd ripgrep sd git-delta dust procs bottom duf tokei hyperfine <span class="se">\
</span></span></span><span class="line"><span class="cl">  zoxide atuin tldr starship</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>eza</code> replaces <code>ls</code>. <code>bat</code> replaces <code>cat</code> with syntax highlighting. <code>fd</code> replaces <code>find</code>. <code>ripgrep</code> replaces <code>grep</code>. <code>sd</code> replaces <code>sed</code>. <code>delta</code> plugs into git for colored side-by-side diff. <code>dust</code> for visual <code>du</code>. <code>procs</code> for <code>ps</code>. <code>btm</code> (bottom) for <code>top</code>. <code>duf</code> for <code>df</code>. <code>tokei</code> counts lines of code. <code>hyperfine</code> for command benchmarking. <code>zoxide</code> is <code>cd</code> with memory (very useful). <code>atuin</code> is shell history with encrypted sync (I point it to my home server via <code>sync_address = &quot;http://192.168.0.90:8888&quot;</code>). <code>starship</code> is the prompt. <code>tldr</code> is a man page in 10 lines.</p>
<p>The <code>atuin key</code> has to be backed up offline. If you lose it, you lose the encrypted history. I saved mine in my self-hosted Bitwarden (Vaultwarden), documented in the <a href="/en/2025/09/10/omarchy-2-0-bitwarden-self-hosted-vaultwarden/">Bitwarden self-hosted article</a>.</p>
<p>Git pipes diff through delta:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>[core]        pager = delta
[interactive] diffFilter = delta --color-only
[delta]       navigate side-by-side line-numbers hyperlinks, light=false
[merge]       conflictstyle = zdiff3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Hyprland and Waybar<span class="hx:absolute hx:-mt-20" id="hyprland-and-waybar"></span>
    <a href="#hyprland-and-waybar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Visual and UX customizations on top of the default.</p>
<p>In <code>hypr/looknfeel.conf</code>, smaller gaps (2/5 vs the default 5/10), slide animation between workspaces, VFR on (reduces consumption when the screen is static), <code>allow_session_lock_restore</code> (if hyprlock crashes, it goes back to the lock screen instead of dumping you on the desktop).</p>
<p>In <code>hypr/bindings.conf</code>:</p>
<table>
  <thead>
      <tr>
          <th>Binding</th>
          <th>Action</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>Super+B</code></td>
          <td>Brave</td>
      </tr>
      <tr>
          <td><code>Super+L</code></td>
          <td>Lock screen (default was layout toggle)</td>
      </tr>
      <tr>
          <td><code>Super+Ctrl+L</code></td>
          <td>Layout toggle (moved here)</td>
      </tr>
      <tr>
          <td><code>Super+Ctrl+P</code></td>
          <td>Toggle TLP perf mode</td>
      </tr>
  </tbody>
</table>
<p>On Waybar, three custom modules I recommend:</p>
<p><strong>Window title</strong>: the <code>hyprland/window</code> module shows what&rsquo;s focused. In bash, PROMPT_COMMAND updates the title to something like &ldquo;~/Projects/blog — hugo server&rdquo;. So in waybar the directory and running command show up, without me needing to look at the terminal.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/hypr---window-title-on-waybar.png" alt="Waybar showing workspaces on the left and the focused window title with the pwd and the running command"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/hypr---another-window-title-on-waybar.png" alt="Another example of the window title on waybar, this time showing “Claude Code”"  loading="lazy" /></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsonc" data-lang="jsonc"><span class="line"><span class="cl"><span class="s2">&#34;hyprland/window&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34;{title}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;max-length&#34;</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;rewrite&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;(.{47}).+&#34;</span><span class="p">:</span> <span class="s2">&#34;$1…&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>Perf mode</strong>: <code>custom/perf</code> runs a script that reads TLP state and shows an icon:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsonc" data-lang="jsonc"><span class="line"><span class="cl"><span class="s2">&#34;custom/perf&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.config/scripts/perf-waybar.sh&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;interval&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34;{}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-click&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.config/scripts/perf-toggle.sh&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Empty for balanced, 󰓅 PERF for performance, 󰌪 ECO for low-power. Click toggles. Useful to quickly see what mode the machine is in.</p>
<p><strong>Claudebar</strong>: I integrated <a href="https://github.com/alfredopiquet/claudebar"target="_blank" rel="noopener">claudebar</a> as a custom module that shows the Claude Code session usage % and extra spend inline in waybar. No need to open another window.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/hypr---power-profile-and-claudebar-next-to-traybar.png" alt="Claudebar showing 9%, 1h16m remaining and $1120.74 extra spend, followed by the PERF indicator and the tray"  loading="lazy" /></p>
<p>The clock:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsonc" data-lang="jsonc"><span class="line"><span class="cl"><span class="s2">&#34;clock&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34;{:L%A %d %B - %H:%M}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;format-alt&#34;</span><span class="p">:</span> <span class="s2">&#34;{:L%A W%V %Y - %H:%M}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Shows &ldquo;Thursday 17 April - 14:32&rdquo; by default, click toggles to &ldquo;Thursday W16 2026 - 14:32&rdquo; with the ISO week number, useful for planning articles and tasks.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/18/thinkpad/hypr---better-date-time-on-waybar-center.png" alt="Waybar clock in the center with date and time"  loading="lazy" /></p>
<h3>Self-hosted Atuin<span class="hx:absolute hx:-mt-20" id="self-hosted-atuin"></span>
    <a href="#self-hosted-atuin" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Atuin runs on my home server at 192.168.0.90:8888. I made a separate account for the notebook (<code>akitaonrails-thinkpad</code>), I don&rsquo;t mix history with the desktop on purpose. <code>atuin sync</code> runs every 5 minutes and all history is encrypted before going to the server. The server doesn&rsquo;t see the commands, only encrypted bytes.</p>
<h2>Conclusion: picking a notebook for Linux<span class="hx:absolute hx:-mt-20" id="conclusion-picking-a-notebook-for-linux"></span>
    <a href="#conclusion-picking-a-notebook-for-linux" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>One thing I learned on this journey: picking a notebook to run Linux comfortably is not trivial. You have to check the <a href="https://wiki.archlinux.org/title/Laptop"target="_blank" rel="noopener">ArchWiki</a> for your specific model before buying. The <a href="https://wiki.archlinux.org/title/Lenovo_ThinkPad_T14s_%28AMD%29_Gen_6"target="_blank" rel="noopener">T14s Gen 6 AMD page</a>, for example, catalogs every hardware quirk and how to work around it. Without that reference, you discover the problems during install.</p>
<p>Rule I follow: never buy a freshly-released model. Let 6 to 12 months go by after launch. That gives the community time to iron out bugs, drivers to land mainline, the ArchWiki to have a decent page, libfprint to include the fingerprint sensor, and the kernel to cover WiFi and the IR camera. Buying on day one means signing up as a beta tester.</p>
<p>Brands with a decent Linux track record: Lenovo (especially Thinkpad, they ship Ubuntu and Fedora pre-loaded), Dell (the XPS and Latitude lines), Asus (Zenbook and ROG have reasonable support), Framework (built for Linux from the factory). Any recent Mac is cut off from Linux mainline or runs through Asahi with caveats.</p>
<p>The Thinkpad T14 Gen 6 isn&rsquo;t the prettiest notebook I could have bought. But it&rsquo;s rugged, it has the right ports, the fingerprint sensor works, and the plastic shell lets it fall, get scratched, travel in a backpack without making me nervous. To serve as a remote debug companion, it&rsquo;s what I needed. If that&rsquo;s your use case too, I recommend it. If you want OLED and metal, go Zenbook or T14s. Every premium comes with a compromise, no Linux notebook in 2026 is perfect.</p>
<p>Everything I described here is versioned in a private repo of mine. If I need to reinstall tomorrow, I run half a dozen steps in order and I&rsquo;m back at the same place. That&rsquo;s the whole point of keeping config in Git: notebook is commodity, config is mine.</p>
]]></content:encoded><category>omarchy</category><category>linux</category><category>hardware</category><category>reviews</category></item><item><title>Omarchy 3: Dual GPU Setup with AMD and NVIDIA</title><link>https://www.akitaonrails.com/en/2026/01/21/omarchy-3-dual-gpu-setup-with-amd-and-nvidia/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/01/21/omarchy-3-dual-gpu-setup-with-amd-and-nvidia/</guid><pubDate>Wed, 21 Jan 2026 15:29:35 -0300</pubDate><description>&lt;p&gt;Another post just so I don&amp;rsquo;t forget these details when configuring &lt;a href="https://omarchy.org/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hyprland doesn&amp;rsquo;t play nice with NVIDIA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can use it. But there are several little problems, particularly with &lt;a href="https://github.com/basecamp/omarchy/issues/1147"target="_blank" rel="noopener"&gt;Hyprlock&lt;/a&gt;, and particularly with DPMS where I leave my computer idle, it locks itself, and after a timeout turns off the monitors to save power, avoid burn-in, etc.&lt;/p&gt;
&lt;p&gt;When I try to wake it from sleep, Hyprlock crashed and I have to jump to another TTY to restart it. I even wrote a &lt;code&gt;~/.local/bin/hypr_unlock.sh&lt;/code&gt; script like this:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Another post just so I don&rsquo;t forget these details when configuring <a href="https://omarchy.org/"target="_blank" rel="noopener">Omarchy</a>:</p>
<blockquote>
  <p>Hyprland doesn&rsquo;t play nice with NVIDIA</p>

</blockquote>
<p>You can use it. But there are several little problems, particularly with <a href="https://github.com/basecamp/omarchy/issues/1147"target="_blank" rel="noopener">Hyprlock</a>, and particularly with DPMS where I leave my computer idle, it locks itself, and after a timeout turns off the monitors to save power, avoid burn-in, etc.</p>
<p>When I try to wake it from sleep, Hyprlock crashed and I have to jump to another TTY to restart it. I even wrote a <code>~/.local/bin/hypr_unlock.sh</code> script like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">hyprctl --instance <span class="m">0</span> <span class="s1">&#39;keyword misc:allow_session_lock_restore 1&#39;</span>
</span></span><span class="line"><span class="cl">hyprctl --instance <span class="m">0</span> <span class="s1">&#39;dispatch exec hyprlock&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>But then I unlock and see that my Brave crashed too. NVIDIA really doesn&rsquo;t like the monitor being turned off while it&rsquo;s active. People said this happened in Hyprlock 0.9.1, but I&rsquo;m already on 0.9.2 and it still crashes. I tried enabling services like nvidia-suspend/resume/hibernate, but nothing worked either.</p>
<p>At the end of the day I decided it&rsquo;s not worth fighting with this: I have an <strong>AMD 7850X3D</strong>, and this CPU has an iGPU (integrated GPU), an AMD Raphael, which for things like rendering a window manager is more than powerful enough.</p>
<p>First, detect the GPUs:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">❯ ls /dev/dri/by-path
</span></span><span class="line"><span class="cl">Permissions Size User Date Modified Name
</span></span><span class="line"><span class="cl">lrwxrwxrwx     - root <span class="m">21</span> Jan 15:22   pci-0000:01:00.0-card -&gt; ../card1
</span></span><span class="line"><span class="cl">lrwxrwxrwx     - root <span class="m">21</span> Jan 15:22   pci-0000:01:00.0-render -&gt; ../renderD128
</span></span><span class="line"><span class="cl">lrwxrwxrwx     - root <span class="m">21</span> Jan 15:22   pci-0000:1a:00.0-card -&gt; ../card2
</span></span><span class="line"><span class="cl">lrwxrwxrwx     - root <span class="m">21</span> Jan 15:22   pci-0000:1a:00.0-render -&gt; ../renderD129</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>To find out which is AMD and which is NVIDIA, just run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">❯ lspci <span class="p">|</span> grep -i vga
</span></span><span class="line"><span class="cl">01:00.0 VGA compatible controller: NVIDIA Corporation GB202 <span class="o">[</span>GeForce RTX 5090<span class="o">]</span> <span class="o">(</span>rev a1<span class="o">)</span>
</span></span><span class="line"><span class="cl">1a:00.0 VGA compatible controller: Advanced Micro Devices, Inc. <span class="o">[</span>AMD/ATI<span class="o">]</span> Raphael <span class="o">(</span>rev c9<span class="o">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done. From the PCI ID we know card1 is NVIDIA and card2 is AMD. Now I need to configure my <code>~/.config/hypr/hyprland.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">....
</span></span><span class="line"><span class="cl"><span class="c1"># NVIDIA environment variables</span>
</span></span><span class="line"><span class="cl"><span class="nv">env</span> <span class="o">=</span> NVD_BACKEND,direct
</span></span><span class="line"><span class="cl"><span class="c1">#env = LIBVA_DRIVER_NAME,nvidia</span>
</span></span><span class="line"><span class="cl"><span class="nv">env</span> <span class="o">=</span> LIBVA_DRIVER_NAME,radeonsi
</span></span><span class="line"><span class="cl"><span class="c1">#env = __GLX_VENDOR_LIBRARY_NAME,nvidia</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Comment these out when using AMD as primary</span>
</span></span><span class="line"><span class="cl"><span class="c1">#env = __NV_PRIME_RENDER_OFFLOAD,1</span>
</span></span><span class="line"><span class="cl"><span class="c1">#env = __VK_LAYER_NV_optimus,NVIDIA_only</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># card1=nvidia, card2=amdgpu (verify with: cat /sys/class/drm/card*/device/uevent)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># AMD first for iGPU primary:</span>
</span></span><span class="line"><span class="cl"><span class="nv">env</span> <span class="o">=</span> AQ_DRM_DEVICES,/dev/dri/card2:/dev/dri/card1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">env</span> <span class="o">=</span> ELECTRON_OZONE_PLATFORM_HINT,auto</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I left the NVIDIA-specific settings commented out; none of them can be active. But the most important line is <code>AQ_DRM_DEVICES</code>, which lists the order for Hyprland to pick the GPU. Card2/AMD has to come first. Done, just reboot and move the HDMI cables to the iGPU output.</p>
<p>With that, I can now choose to offload only some apps to the NVIDIA using Prime. For that, I first created the script <code>~/.local/bin/nvidia-load.sh</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="nv">__NV_PRIME_RENDER_OFFLOAD</span><span class="o">=</span><span class="m">1</span> <span class="nv">__VK_LAYER_NV_optimus</span><span class="o">=</span>NVIDIA_only <span class="nv">__GLX_VENDOR_LIBRARY_NAME</span><span class="o">=</span>nvidia <span class="s2">&#34;</span><span class="nv">$@</span><span class="s2">&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, I configured some bindings in <code>~/.config/hypr/bindings.conf</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl"><span class="nv">bindd</span> <span class="o">=</span> SUPER SHIFT, B, Blender, exec, ~/.local/bin/nvidia-load.sh blender
</span></span><span class="line"><span class="cl"><span class="nv">bindd</span> <span class="o">=</span> SUPER SHIFT, L, Bambu Studio, exec, ~/.local/bin/nvidia-load.sh bambu-studio
</span></span><span class="line"><span class="cl"><span class="nv">bindd</span> <span class="o">=</span> SUPER SHIFT, P, Blender, exec, ~/.local/bin/nvidia-load.sh plasticity
</span></span><span class="line"><span class="cl">...</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This way, only Blender, Plasticity, and Bambu Studio, which primarily use the NVIDIA to render 3D in real time. All the other apps open on the AMD iGPU.</p>
<p>AI tools like ComfyUI, Ollama, or LM Studio automatically recognize the NVIDIA and pick it. And with that I also have more free VRAM to load LLMs.</p>
<p>If you&rsquo;re going to use XLibre/X.org, you can stay on NVIDIA just fine. But if you&rsquo;re going to use Wayland, NVIDIA still isn&rsquo;t fully stable, particularly with Hyprland. It&rsquo;s less of a headache to drop in a second AMD GPU just for this.</p>
]]></content:encoded><category>omarchy</category><category>hardware</category><category>linux</category></item><item><title>Omarchy 3 - One of the Best Coding Agents Out There: Crush</title><link>https://www.akitaonrails.com/en/2026/01/09/omarchy-3-one-of-the-best-coding-agents-crush/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/01/09/omarchy-3-one-of-the-best-coding-agents-crush/</guid><pubDate>Fri, 09 Jan 2026 20:01:04 -0300</pubDate><description>&lt;p&gt;Last year I was recommending &lt;a href="https://aider.chat/"target="_blank" rel="noopener"&gt;Aider&lt;/a&gt; as the go-to coding agent. But it kind of stopped in time. Compared to the Cursors and Windsurfs of the world, it fell pretty far behind.&lt;/p&gt;
&lt;p&gt;Lucky for us, the open source side is cooking up new options. DHH decided to bring &lt;a href="https://opencode.ai/"target="_blank" rel="noopener"&gt;OpenCode&lt;/a&gt; into Omarchy 3.x.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://x.com/dhh/status/2007589042485883374"target="_blank" rel="noopener"&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109200839_screenshot-2026-01-09_20-08-17.png" alt="dhh opencode" loading="lazy" /&gt;&lt;/a&gt;
After I ran the upgrade (just &lt;code&gt;omarchy-update&lt;/code&gt;) I noticed I also got the option to install the one I&amp;rsquo;m starting to play with now, &lt;a href="https://github.com/charmbracelet/crush"target="_blank" rel="noopener"&gt;&lt;strong&gt;CRUSH&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Last year I was recommending <a href="https://aider.chat/"target="_blank" rel="noopener">Aider</a> as the go-to coding agent. But it kind of stopped in time. Compared to the Cursors and Windsurfs of the world, it fell pretty far behind.</p>
<p>Lucky for us, the open source side is cooking up new options. DHH decided to bring <a href="https://opencode.ai/"target="_blank" rel="noopener">OpenCode</a> into Omarchy 3.x.</p>
<p><a href="https://x.com/dhh/status/2007589042485883374"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109200839_screenshot-2026-01-09_20-08-17.png" alt="dhh opencode"  loading="lazy" /></a>
After I ran the upgrade (just <code>omarchy-update</code>) I noticed I also got the option to install the one I&rsquo;m starting to play with now, <a href="https://github.com/charmbracelet/crush"target="_blank" rel="noopener"><strong>CRUSH</strong></a>.</p>
<p>Crush is from the same crew that&rsquo;s been cranking out a bunch of libraries to make TUI (Terminal User Interface) development easier, like <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener">BubbleTea</a> and <a href="https://github.com/charmbracelet/gum"target="_blank" rel="noopener">Gum</a>. I&rsquo;d recommend digging into those repos too. Building terminal apps is way more interesting these days, especially dev tools or anything Linux-flavored.</p>
<p>It&rsquo;s a really well-built TUI. Here&rsquo;s what it looks like:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109202710_screenshot-2026-01-09_20-26-58.png" alt="Crush UI"  loading="lazy" /></p>
<p>For a first pass I ran it on this little blog project, which is a static site generated with <a href="https://akitaonrails.com/2025/09/10/meu-novo-blog-como-eu-fiz/"target="_blank" rel="noopener">Hugo</a>.</p>
<p>Since I already have the env vars set up for <a href="https://openrouter.ai/docs/quickstart"target="_blank" rel="noopener">OpenRouter</a>, I didn&rsquo;t even need to configure anything. Just <code>crush</code> inside the project directory.</p>
<p>The first thing it did was analyze my project. It&rsquo;s small, so it was quick. I have no idea how it handles giant projects. But it goes scanning through the source code and at the end writes everything down in an <a href="https://github.com/akitaonrails/akitaonrails.github.io/blob/master/AGENTS.md"target="_blank" rel="noopener">AGENTS.md</a> file. And I was impressed by how good of a job it did summarizing the project. Take a look at this snippet:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109201559_screenshot-2026-01-09_20-15-47.png" alt="agents.md"  loading="lazy" />
I didn&rsquo;t even know I had the option of running <code>scripts/dev.sh new-post</code> to automatically create the timestamped subdirectory for a new post. I&rsquo;d been doing that by hand every single time 😅.</p>
<p>I knew my <a href="https://github.com/akitaonrails/akitaonrails.github.io/blob/master/scripts/generate_index.rb"target="_blank" rel="noopener"><code>scripts/generate_index.rb</code></a> script was kind of a mess, so I asked Crush if it could refactor it:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109201839_screenshot-2026-01-09_20-18-30.png" alt="refactor generate_index"  loading="lazy" />
And in the end it refactored the thing nicely, no new bugs introduced, no rewriting stuff that didn&rsquo;t need rewriting. It really nailed refactoring only what needed to be touched. It changed things like using <code>Dir.glob</code> instead of <code>Find.find</code>, switched to symbols instead of strings (more idiomatic), that kind of thing.</p>
<p>I liked that it ran the modified version and checked that it still worked the way it was supposed to.</p>
<p>Then I asked it to do the same thing with <a href="https://github.com/akitaonrails/akitaonrails.github.io/blob/master/scripts/dev.sh"target="_blank" rel="noopener"><code>scripts/dev.sh</code></a>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109202153_screenshot-2026-01-09_20-21-44.png" alt="refactor dev.sh"  loading="lazy" />
And in this case it actually found a bug I hadn&rsquo;t noticed. Again, it edited the shell script to make it safer, separated constants out, improved error checking, and so on.</p>
<p>Here&rsquo;s the <a href="https://github.com/akitaonrails/akitaonrails.github.io/commit/440470b09e822af0dc23a7c6aec73b4ead89caf7"target="_blank" rel="noopener">commit with the changes</a>. Take a look. It really didn&rsquo;t add any unnecessary code. Everything still works the way it did before, but now it&rsquo;s more organized. And on top of that it caught a bug I had missed.</p>
<p>For this little example I picked the <strong>Claude Opus 4.5</strong> model. All the code came out of it. Crush is just the agent that talks to the model and feeds it the right context.</p>
<p>So far I&rsquo;ve only done easy, dumb stuff. The docs say it integrates with LSPs and MCPs to get even more context about the code, but I haven&rsquo;t tested that yet.</p>
<p>Either way, I figured I&rsquo;d write a quick post just to say that these new options like Crush and OpenCode are already plenty good for daily use. Worth trying on your own project.</p>
<h3>Second Test<span class="hx:absolute hx:-mt-20" id="second-test"></span>
    <a href="#second-test" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Since Crush did fine with that basic web test, I figured I&rsquo;d throw it last year&rsquo;s challenge. I&rsquo;d built a tiny command-line project that&rsquo;s a basic chat, written from scratch, talking directly to the llama.cpp library, with CUDA, in Zig — which is a low-level language, still experimental and unfinished. The whole point of the challenge is that almost nobody uses it, so there&rsquo;s barely any documentation or examples. The LLM has to actually sweat to make it work.</p>
<p>Unlike a web page with React and Tailwind — which has thousands of forum posts, tutorials, blog posts and everything else — Zig has almost nothing. The only popular app I know of that uses Zig is Ghostty.</p>
<p>To make it worse, a new version came out recently, 0.15, which changed a whole bunch of the IO API (in preparation for better Async IO support). New versions of Llama, Cuda, etc. also dropped. So the idea was to use Crush with Claude Opus to see if it could refactor, fix bugs, update the APIs, and get to the point of compiling a working binary.</p>
<p>In short: <strong>it pulled it off!</strong></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109211613_screenshot-2026-01-09_21-15-57.png" alt="crush - qwen-cli-zig"  loading="lazy" />
On the first refactoring pass, it burned only USD 5.64 of credit on my Anthropic account. It managed to take the spaghetti monolith (which I&rsquo;d written that way on purpose as a challenge) and split it into smaller files like <code>chat.zig</code> and <code>llama.zig</code>.</p>
<p>It managed to map the C functions from Llama as Zig functions. It managed to figure out that things like ArrayList changed in the new Zig. It managed to figure out that all the IO APIs changed in 0.15. And it managed to modify the right places.</p>
<p>It ran <code>zig build</code>, checked the errors and made fixes that actually made sense, until it produced the final binary.</p>
<p>You can check the <a href="https://github.com/akitaonrails/qwen-cli-zig/pull/1/files"target="_blank" rel="noopener">Pull Request</a> with everything it did. It was a pretty reasonable amount of change and didn&rsquo;t leave the project broken.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109212115_screenshot-2026-01-09_21-21-03.png" alt="llama.cpp externs"  loading="lazy" />
The fact that it managed to consult the Zig 0.15 documentation, and also correctly infer which new Llama.cpp functions it should make extern, was pretty impressive.</p>
<p>Anyway, on the first pass it got to the point where it compiles. But that doesn&rsquo;t mean it works. And sure enough, when I tried to run it, it ended in a segmentation fault:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109213331_screenshot-2026-01-09_21-33-22.png" alt="qwen-cli-zig segmentation fault"  loading="lazy" /></p>
<p>So I asked Crush to run it and look at the error. It found the bug and made the necessary changes. It found a wrong struct and even caught a memory leak. It fixed both and now the program runs the way it should:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109213702_screenshot-2026-01-09_21-36-23.png" alt="qwen-cli-zig"  loading="lazy" />
Like I said, it&rsquo;s a goofy little chat program that uses Llama.cpp directly to load the Qwen3 model and open a chat for me to talk to. It&rsquo;s just an exercise — a chat like this already exists, all you have to do is use Ollama. But I wanted to build one from scratch, low level, as an exercise for LLMs. Up to last year, no LLM I tested could finish this program properly. But now one finally did.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260109213930_screenshot-2026-01-09_21-39-22.png" alt="crush explanation of the crash"  loading="lazy" /></p>
<p>And as you can see, in the end I spent almost 8 bucks to refactor it, fix the bugs, and get this program working properly. Not cheap, but at least it wasn&rsquo;t credits thrown out the window like it was a year ago. I haven&rsquo;t tested it with local LLMs yet, to see if Crush can land on similar results.</p>
<p>But the fact that it can deal with a language as obscure as Zig has me genuinely excited to play with this more. The tooling and LLMs have finally hit a point where they&rsquo;re actually practical to use. I&rsquo;m not saying it solves everything, but compared to a year ago, it&rsquo;s a real leap.</p>
<p>I&rsquo;d recommend giving Crush a spin with other models too. I only played with Opus a little, but other models can give you different results depending on the kind of problem you&rsquo;re trying to crack.</p>
]]></content:encoded><category>omarchy</category><category>coding-agents</category><category>llms</category></item><item><title>Omarchy 2.0 - LazyVim Basics</title><link>https://www.akitaonrails.com/en/2025/09/12/omarchy-2-0-lazyvim-basics/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/12/omarchy-2-0-lazyvim-basics/</guid><pubDate>Fri, 12 Sep 2025 15:00:00 -0300</pubDate><description>&lt;p&gt;Damn it, I said the previous post would be the last one in the &lt;a href="https://www.akitaonrails.com/en/tags/omarchy/"&gt;Omarchy&lt;/a&gt; series, but I figured this was a good chance to evangelize a bit about Vim too. I&amp;rsquo;ve already recommended following &lt;a href="https://www.youtube.com/@EustaquioRangel"target="_blank" rel="noopener"&gt;@Taq&amp;rsquo;s channel&lt;/a&gt;, where he explains in much more depth how NeoVim works. There&amp;rsquo;s also &lt;a href="https://github.com/ThePrimeagen/vim-be-good"target="_blank" rel="noopener"&gt;Primeagen&amp;rsquo;s &amp;ldquo;vim-be-good&amp;rdquo; tutorial&lt;/a&gt;. That second one in particular is an interactive tutorial inside NeoVim itself, to practice navigation - which many people find hard at first.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Damn it, I said the previous post would be the last one in the <a href="/en/tags/omarchy/">Omarchy</a> series, but I figured this was a good chance to evangelize a bit about Vim too. I&rsquo;ve already recommended following <a href="https://www.youtube.com/@EustaquioRangel"target="_blank" rel="noopener">@Taq&rsquo;s channel</a>, where he explains in much more depth how NeoVim works. There&rsquo;s also <a href="https://github.com/ThePrimeagen/vim-be-good"target="_blank" rel="noopener">Primeagen&rsquo;s &ldquo;vim-be-good&rdquo; tutorial</a>. That second one in particular is an interactive tutorial inside NeoVim itself, to practice navigation - which many people find hard at first.</p>
<p>I&rsquo;ll do only this one article about it and I don&rsquo;t intend to cover more than the tip of the iceberg. The idea is to serve whoever is coming from other editors like Sublime Text or VS Code and can&rsquo;t even start navigating or even quit Vim lol 🤣.</p>
<h3>Initial Commands<span class="hx:absolute hx:-mt-20" id="initial-commands"></span>
    <a href="#initial-commands" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>As I said in the <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/"target="_blank" rel="noopener">previous post about LazyVim</a>, I&rsquo;ll assume you already understand at least how to install support for your language with <strong>LazyExtras</strong> and already learned to version things using <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/"target="_blank" rel="noopener"><strong>Mise</strong></a>.</p>
<p>Without even getting into LazyVim, the first thing to know is that it installs all the relevant configurations in the <code>~/.config/nvim</code> directory. Normally you don&rsquo;t need to touch anything there. Leave files like <code>lazyvim.json</code> alone. Notice that it does the same thing as any NPM out there: there&rsquo;s a <code>lazy-lock.json</code> file that declares the version/commit of each installed plugin. LazyVim does something similar to an <code>npm install</code>. Just a curiosity so you know how it organizes itself.</p>
<p>If you need to customize something, it&rsquo;s usually going to be in the <code>~/.config/nvim/lua/config</code> directory. That&rsquo;s where I added Mise support, for example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">~/.config/nvim
</span></span><span class="line"><span class="cl">❯ cat lua/config/mise.lua
</span></span><span class="line"><span class="cl">-- Prepend mise shims to PATH
</span></span><span class="line"><span class="cl">vim.env.PATH <span class="o">=</span> vim.env.HOME .. <span class="s2">&#34;/.local/share/mise/shims:&#34;</span> .. vim.env.PATH</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>They&rsquo;ll always be scripts written in Lua. And you don&rsquo;t even need to know Lua deeply. At a glance it&rsquo;s a very simple language, not very different from Python or Javascript and any programmer should be able to read any snippet without any problem. Besides, in most cases you&rsquo;ll be copying configurations you got from the documentation, wiki or ChatGPT itself, so you just need to know that things go in this location.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912110425_screenshot-2025-09-12_11-04-07.png" alt="primeiros passos"  loading="lazy" /></p>
<p>Understand that NeoVim has the concept of the &ldquo;<strong>Leader</strong>&rdquo; key, a key that precedes hotkeys for other commands (there&rsquo;s also <strong>localleader</strong> which is backslash <strong>\</strong>). This is configurable but in LazyVim the Leader is the <strong>&ldquo;Space&rdquo;</strong> key. In a lot of documentation we&rsquo;ll see people saying <em>&ldquo;press Leader-w&rdquo;</em>, which means <strong>Space+w</strong> and now you know what that means.</p>
<p>To open a file there are at least 3 different ways, 2 of them shown in the image above:</p>
<blockquote>
  <p><strong>Space+E</strong> opens <strong>NeoTree</strong>, which is that sidebar on the left that looks like Windows Explorer. You can navigate with the keyboard or even with the mouse. Find your file and press &ldquo;Enter&rdquo; to open it, then &ldquo;Space+E&rdquo; again to hide the sidebar. If you want to know how to create a new file, a new subdirectory, rename things and so on, type <strong>?</strong> (question mark) to see this help:</p>

</blockquote>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912142438_neotree.gif" alt="NeoTree"  loading="lazy" /></p>
<p>The third way is manually with the <strong>:e</strong> command followed by the file name in the local directory. It has autocomplete too, this is the fastest way, if you know what you&rsquo;re looking for.</p>
<p>Whenever you want to cancel anything or close &ldquo;floating windows&rdquo; (pop-ups, dialog boxes). Just press &ldquo;Esc&rdquo;. Esc is fundamental in NeoVim.</p>
<p>Once a file is open, it sits in the <strong>Buffer</strong>. Think of Buffer as &ldquo;Open Tabs&rdquo; in your VS Code. To navigate through Buffers (like alt+tab between your already-opened files) it&rsquo;s simple:</p>
<ul>
<li><strong>]+b</strong> for next &ldquo;tab&rdquo; (next Buffer)</li>
<li><strong>[+b</strong> previous Buffer</li>
<li><strong>Space+bd</strong> to &ldquo;close the tab&rdquo; (close the Buffer)</li>
<li><strong>Space+bo</strong> to stay where you are and close the other buffers</li>
</ul>
<p>Open as many files as you want. If one of them is one of those huge logs you opened by accident, <code>Space+bd</code> to close it and done.</p>
<p>Speaking of closing, <strong>how do you exit NeoVim?</strong> There are several ways:</p>
<ul>
<li><strong>Space+q</strong></li>
<li><strong>:q</strong></li>
<li><strong>:q!</strong></li>
</ul>
<p>The difference: the first is the custom way in LazyVim. The second is the standard way using the &ldquo;commands&rdquo; feature that always starts with &ldquo;colon&rdquo;. And the third is if you modified something in the file but want to cancel, exit without saving anything, hence the exclamation mark.</p>
<p>Normally I use <strong>:wq</strong> which means &ldquo;write&rdquo; and &ldquo;quit&rdquo;. So it first saves the changes to the file and then quits the program. It&rsquo;s useful when I&rsquo;m just quickly editing a config file.</p>
<h3>Basic Navigation<span class="hx:absolute hx:-mt-20" id="basic-navigation"></span>
    <a href="#basic-navigation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Now I have a file open. How do I navigate through it? First, how do I go to the end of the file and then back to the beginning? This is something I use a lot, just type <strong>Shift+g</strong> to go to the end of the file and then <strong>gg</strong> to go back to the beginning. Simple as that.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912143147_home-end.gif" alt="home-end"  loading="lazy" /></p>
<p>Now let&rsquo;s learn several commands at once:</p>
<ul>
<li>Type <strong>v</strong>. This starts the <strong>&ldquo;visual mode&rdquo;</strong> which, in practice, means starting to select from wherever your cursor is.</li>
<li>Type <strong>j</strong>. Which is the equivalent of &ldquo;arrow down&rdquo; to go to the line below. You&rsquo;ve probably heard that in Vim you navigate with &ldquo;hjkl&rdquo; which are, respectively, left, down, up, right.</li>
<li>Type <strong>x</strong>. Which is the equivalent of &ldquo;cut&rdquo; and putting the content in the clipboard. Having done that, typing <strong>p</strong> gives you &ldquo;paste&rdquo;.</li>
<li>Type <strong>u</strong>. Which is the most-used command: <strong>Undo</strong> or undoing the last modification.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912143741_marcar-apagar.gif" alt="marcar-apagar"  loading="lazy" /></p>
<p>All of this works in what&rsquo;s called <strong>&ldquo;command mode&rdquo;</strong>, which is the default mode Vim opens every file in. In this mode you can&rsquo;t type any text. As you can see, each letter by itself is a command, like &ldquo;x&rdquo; for cut or &ldquo;p&rdquo; for paste.</p>
<p>To type, you first need to press <strong>i</strong> (just the lowercase &ldquo;i&rdquo; letter), which then switches from command mode to <strong>&ldquo;edit mode&rdquo;</strong>. Now just type your text normally, like in any editor. When you want some command, just press <strong>ESC</strong> to go back to command mode. We&rsquo;ll be doing this all the time, which is why a lot of people remap the &ldquo;caps lock&rdquo; key on the keyboard to be ESC so it&rsquo;s easy to just tap with your left pinky.</p>
<h3>Combining Commands<span class="hx:absolute hx:-mt-20" id="combining-commands"></span>
    <a href="#combining-commands" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p>Still in command mode, how do we navigate through the file more easily?</p>

</blockquote>
<p>Beyond the &ldquo;hjkl&rdquo; keys, we can navigate more easily using <strong>b</strong> for &ldquo;previous word&rdquo; or <strong>w</strong> for next word:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912144226_words.gif" alt="words"  loading="lazy" /></p>
<p>Command mode lets you combine commands, so we can do:</p>
<ul>
<li><strong>dw</strong> to delete the next word</li>
<li><strong>db</strong> to delete the previous word</li>
<li><strong>d4w</strong> to delete the next 4 words</li>
<li><strong>d4j</strong> to delete the next 4 lines down</li>
</ul>
<p><a href="https://github.com/ThePrimeagen/vim-be-good"target="_blank" rel="noopener">Primeagen&rsquo;s tutorial</a> has several exercises for this kind of navigation, I recommend practicing. In VS Code everyone is used to first grabbing the mouse, marking the block they want to delete visually, then pressing delete or backspace. In Vim, we look at where the cursor is, press ESC to be in command mode, and type the operation and the location. Test all the combinations you can imagine.</p>
<p>This is the <strong>paradigm shift</strong> that bothers the lazy. But once you&rsquo;ve learned this, you&rsquo;ll find it annoying to use an editor that forces you to use the mouse for basic things.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912144801_change.gif" alt="change in place"  loading="lazy" /></p>
<p>Now it gets more interesting: <em>what if instead of deleting a word, I want to replace the word where my cursor is with another word?</em></p>
<p>In a normal editor, you&rsquo;d mark it with the mouse (or use some combination like &ldquo;ctrl+shift+arrow&rdquo;), and type over it or delete the word.</p>
<p>In LazyVim there are plugins configured for more interesting things. In the video above see how I&rsquo;m replacing words <em>&ldquo;in-place&rdquo;</em>. You do this with the <strong>ciw</strong> command.</p>
<ul>
<li><strong>ciw</strong> deletes the entire word under the cursor and opens edit mode for you to type the replacement</li>
<li><strong>ce</strong> deletes from the cursor to the end of the word (preserves the beginning of the word) and also opens for you to type in its place</li>
<li><strong>Shift-c</strong> (capital C) deletes everything from your cursor to the end of the entire line and opens for you to type.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912145439_bloco.gif" alt="Mudar Bloco Vertical"  loading="lazy" /></p>
<p>But that still doesn&rsquo;t look thaaaat cool. What if you want to change only the first letter of several lines at the same time, for example, in the text of the video above, I want to change only the hyphen (&quot;-&quot;) of each tag line?</p>
<p>I said before that pressing <strong>v</strong> in command mode starts visual mode and you can select from there. But there&rsquo;s <strong>Ctrl+v</strong> which opens vertical block selection mode.</p>
<p>In this mode we use the &ldquo;hjkl&rdquo; keys normally, like <strong>j</strong> to go down, but instead of marking the next entire line, it marks only the character right below your cursor. Now I can delete with <strong>d</strong> and type <strong>Shift-i</strong> (capital &ldquo;I&rdquo;) to enter edit mode at the beginning of the block and replace with whatever I want.</p>
<p>LazyVim has plugins for comments, but this is another alternative if you want to add &ldquo;//&rdquo; or &ldquo;#&rdquo; at the beginning of several lines to comment out, for example. In this case, read about the <a href="https://github.com/folke/ts-comments.nvim"target="_blank" rel="noopener"><strong>ts-comments</strong></a> plugin for better options for commenting. To start a new comment block, type <strong>gco</strong> to add a comment below.</p>
<p><em>&ldquo;Block mode&rdquo;</em> as I showed above, is one of the things I use the most in code.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912150112_search-replace.gif" alt="Search and Replace"  loading="lazy" /></p>
<p>But only that is very little. What if you want to replace <strong>ALL IDENTICAL WORDS</strong> in the text at once. In the example video above, I want to replace &ldquo;domínio&rdquo; with &ldquo;DOMAIN&rdquo; and &ldquo;Cloudflare&rdquo; with &ldquo;AWS Amazon&rdquo;, how do I do that? This is &ldquo;Search and Replace&rdquo; that exists in every editor and in Vim it&rsquo;s very easy:</p>
<p>We type <strong>:%s/domínio/DOMAIN/</strong>.</p>
<p>If you&rsquo;re a programmer you&rsquo;ve probably seen this syntax before. It&rsquo;s the <strong>REGEX MATCH</strong> syntax. Yes, you have to know Regex (and no, it&rsquo;s not PCRE nor Unicode, it&rsquo;s NeoVim&rsquo;s own Regex dialect, but it&rsquo;s similar).</p>
<p>As I said before, &ldquo;colon&rdquo; opens the command-typing box, <strong>&quot;%s&quot;</strong> starts &ldquo;search with regex&rdquo; and between the slashes &ldquo;//&rdquo; first goes what you&rsquo;re looking for and then what you want to replace it with.</p>
<p>But that&rsquo;s the way in pure NeoVim; in LazyVim, there&rsquo;s the <a href=""><strong>grug-far</strong></a> plugin and you activate it with the <strong>SPACE+sr</strong> command:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912150648_screenshot-2025-09-12_15-06-32.png" alt="grug-far"  loading="lazy" /></p>
<p>Now yes, more like VS Code, right? Use whichever you find easier.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>As I said, this is only the tip of the tip of the iceberg, the bare minimum of the bare minimum to at least start editing simple config files without opening Nano or VS Code just for that.</p>
<p>Read the LazyVim documentation. Check out the <a href="https://www.lazyvim.org/keymaps"target="_blank" rel="noopener">keymaps</a> to discover other commands. Pay attention to every letter you press in command mode, LazyVim shows the available options. For example, let&rsquo;s say I pressed <strong>g</strong> (goto), it will show a help in the bottom-right corner:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912151849_screenshot-2025-09-12_15-18-38.png" alt="ajuda"  loading="lazy" /></p>
<p>This way you can always discover new commands or remember commands you rarely use. That&rsquo;s why I recommend LazyVim, which comes well configured to help you. The plugin that provides this feature is <a href="https://github.com/folke/which-key.nvim"target="_blank" rel="noopener"><strong>which-key</strong></a>, in case you want the same thing in a NeoVim you configured from scratch.</p>
<p>There are several <a href="https://vim.rtorr.com/"target="_blank" rel="noopener"><strong>Cheatsheets</strong></a> out there with tables of important command combinations. Worth exploring.</p>
<p>And there&rsquo;s more: LazyVim comes with dozens of <a href="https://www.lazyvim.org/plugins"target="_blank" rel="noopener">plugins</a> for formatting, linting, integrated LSP, integrated GIT, and much more. There&rsquo;s no way I can document each one here. Each of them has its own documentation on the LazyVim.org plugins page.</p>
<p>Again, don&rsquo;t forget to call <strong>:LazyExtras</strong> and install the optional plugins for your languages.</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>tutorials</category></item><item><title>Omarchy 2.0 - Recommended for Beginners?</title><link>https://www.akitaonrails.com/en/2025/09/12/omarchy-2-0-recommended-for-beginners/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/12/omarchy-2-0-recommended-for-beginners/</guid><pubDate>Fri, 12 Sep 2025 12:00:00 -0300</pubDate><description>&lt;p&gt;The most important video on my &lt;a href="https://www.youtube.com/@Akitando"target="_blank" rel="noopener"&gt;YouTube channel&lt;/a&gt; is &amp;ldquo;Don&amp;rsquo;t Outsource Your Decisions&amp;rdquo;:&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/D3L8IOncLkg"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;The questions I get the most, literally every single day, come in this format: &lt;em&gt;&amp;ldquo;Akita, should I go to college?&amp;rdquo;&lt;/em&gt;, &lt;em&gt;&amp;ldquo;Akita, what do you think I should study?&amp;rdquo;&lt;/em&gt; and variations of that.&lt;/p&gt;
&lt;p&gt;Dude, I don&amp;rsquo;t know you, I will never know nor will I ever be interested in knowing who you are, what you aim for, your aspirations, ambitions, tastes, preferences. Nothing. Neither me nor &lt;strong&gt;ANYONE ELSE&lt;/strong&gt;. Only you know what&amp;rsquo;s best for you. If you don&amp;rsquo;t know, go find out. That&amp;rsquo;s what &lt;strong&gt;LIVING&lt;/strong&gt; means.&lt;/p&gt;</description><content:encoded><![CDATA[<p>The most important video on my <a href="https://www.youtube.com/@Akitando"target="_blank" rel="noopener">YouTube channel</a> is &ldquo;Don&rsquo;t Outsource Your Decisions&rdquo;:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/D3L8IOncLkg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>The questions I get the most, literally every single day, come in this format: <em>&ldquo;Akita, should I go to college?&rdquo;</em>, <em>&ldquo;Akita, what do you think I should study?&rdquo;</em> and variations of that.</p>
<p>Dude, I don&rsquo;t know you, I will never know nor will I ever be interested in knowing who you are, what you aim for, your aspirations, ambitions, tastes, preferences. Nothing. Neither me nor <strong>ANYONE ELSE</strong>. Only you know what&rsquo;s best for you. If you don&rsquo;t know, go find out. That&rsquo;s what <strong>LIVING</strong> means.</p>
<p>What you won&rsquo;t admit is that you want someone you consider more important or relevant to approve your choice and tell you that you got it right.</p>
<p>Never expect that from me, I will never validate you.</p>
<p>I will always say: <strong>FIGURE IT OUT</strong>. That&rsquo;s how I became who I am. I never followed anyone, I never asked anyone what I should do. I just went there and did it. Fell on my face, got up, tried again. That&rsquo;s life.</p>
<p>Let me show you what actually <strong>BOTHERS</strong> me:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912124608_screenshot-2025-09-12_12-45-47.png" alt="pergunta idiota"  loading="lazy" /></p>
<p>Let&rsquo;s check the <a href="https://learn.omacom.io/2/the-omarchy-manual/93/security"target="_blank" rel="noopener">manual</a>?</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912124657_screenshot-2025-09-12_12-46-45.png" alt="Manual"  loading="lazy" /></p>
<p>DHH took the trouble to write a manual. It has a section called &ldquo;Security&rdquo;. A quick Google search would have found it. Or this other gem:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912124836_screenshot-2025-09-12_12-48-24.png" alt="devops"  loading="lazy" /></p>
<p>How do you want to become a &ldquo;DEVOPS&rdquo; (who has to know EVERYTHING about Linux) starting like this? Already off to a bad start. Park your butt in the chair, roll up your sleeves, and test them one by one, and learn.</p>
<h3>Linux for Beginners?<span class="hx:absolute hx:-mt-20" id="linux-for-beginners"></span>
    <a href="#linux-for-beginners" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>That said, watch my video. But since I&rsquo;ve been talking a lot about <a href="/en/tags/omarchy/">Omarchy</a> already, I&rsquo;ll say that yes, this is what I use in my day to day and it&rsquo;s the only one I&rsquo;ll recommend for the near future (I may change my mind later). Having used distros ever since Linux was invented in the early 90s, I know there are dozens of distros and even I don&rsquo;t have the patience to try them all.</p>
<p><em>Why Omarchy?</em></p>
<p>First, because it made the right choice of base distro: <strong>Arch Linux</strong>. I consider it the best distro out there today for two reasons: it has very little &ldquo;bloat&rdquo; (it doesn&rsquo;t install a bunch of stuff you&rsquo;ll never use, like Ubuntu, Fedora, Mint, Deepin, or any of those other &ldquo;beginner-friendly&rdquo; distros).</p>
<p>Second, Arch Linux has the AUR, which is a repository of user-made packages that has basically everything. You don&rsquo;t need to go hunting for third-party repositories or install things manually. With a single command, <code>yay</code>, you install everything. There&rsquo;s none of that <code>apt-repository add</code> nonsense or having to <code>make install</code> or anything like that. The AUR manages all of it for you.</p>
<p>Third, it installs Hyprland (which I was already using and liked), with very good configs, and a very good package selection. Everything I would install manually myself. So it&rsquo;s a thousand times easier to get what would take me much more work to do on my own. Check my <a href="/en/tags/omarchy/">series of posts about Omarchy</a> to see those options.</p>
<h3>Linux for Beginners?<span class="hx:absolute hx:-mt-20" id="linux-for-beginners-1"></span>
    <a href="#linux-for-beginners-1" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><em>Beginner at what?</em></p>
<p>I hate this question. If you&rsquo;re really an amateur user, not a programmer, maybe you&rsquo;re an accountant, maybe you&rsquo;re just a teenage gamer. The first question I ask is: <em>why do you want to use Linux?</em></p>
<p>Let&rsquo;s say it&rsquo;s because you heard it&rsquo;s more secure (and it actually is). Then it doesn&rsquo;t matter, any distro will do. Install Ubuntu, install Manjaro, install Garuda. It makes no difference, because you&rsquo;ll never deal with anything under the hood. You&rsquo;ll open Chrome, open Steam, and that&rsquo;s it. The rest is going to be web apps.</p>
<p>Let&rsquo;s say it&rsquo;s just for gaming, then install <a href="https://bazzite.gg/"target="_blank" rel="noopener">Bazzite</a> on your mini-PC or handheld. Or just install your games on a separate Windows box just for gaming like I did. Whatever.</p>
<p>Or just stick with Windows or macOS. If you&rsquo;re a total amateur, you&rsquo;re probably going to use the same weak password for everything, and click on WhatsApp links without checking who they&rsquo;re from. It literally makes no difference which OS you use. No security from any OS will protect you from your bad habits and ignorance.</p>
<p>If you&rsquo;re a beginner at programming or tech, then I have no mercy: learn Linux properly. You want to be a professional, be a professional, learn the right way: learn to have 100% control over your own machine. There&rsquo;s no step-by-step or tutorial for that. It&rsquo;s something you&rsquo;re going to do continuously for the rest of your life. I&rsquo;ve been in this field for over 30 years and I still learn new things every day.</p>
<h3>Hardware<span class="hx:absolute hx:-mt-20" id="hardware"></span>
    <a href="#hardware" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The <strong>BIGGEST</strong> problem anyone is going to face, with ANY distro, is going to be hardware support. And that&rsquo;s why you shouldn&rsquo;t just follow what someone recommends to you:</p>
<p><strong>Nobody has the same PC as you.</strong></p>
<p>What&rsquo;s your notebook? A Lenovo? A Dell? A Positivo? From what year? Which model?</p>
<p>Everything varies: which Wi-Fi and Bluetooth device? Which graphics card? Which firmware is running? With which power profile support? Do you need FIDO2 devices for things like a fingerprint reader? Hardware keys? Does your machine have TPU? Will you need Secure Boot?</p>
<p>I don&rsquo;t know. You are the one who has to know.</p>
<p>A practical example, I have an <strong>Asus Zephyrus G14</strong> notebook that I use with Windows because it only lives in my workshop to run Bambu Studio to control my X1C 3D Printer. I haven&rsquo;t gotten around to installing Omarchy on it, but let&rsquo;s say I wanted to. Would it work?</p>
<p>Fortunately there&rsquo;s <a href="https://wiki.archlinux.org/title/ASUS_ROG_Zephyrus_G16_%282023%29_GU603"target="_blank" rel="noopener">a page on the ArchWiki</a> dedicated to this model. It looks like everything works &ldquo;out-of-the-box&rdquo;. But if it were the <a href="https://wiki.archlinux.org/title/ASUS_ROG_Zephyrus_G14_%282022%29_GA402"target="_blank" rel="noopener">previous year&rsquo;s version</a> I&rsquo;d have to check extra items. There are Wi-Fi issues, for example.</p>
<p>Each different machine will have different problems.</p>
<h3>Live Env and Ventoy<span class="hx:absolute hx:-mt-20" id="live-env-and-ventoy"></span>
    <a href="#live-env-and-ventoy" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><em>&ldquo;So what do I do, you [censored]?&rdquo;</em></p>
<p>That&rsquo;s why pretty much every good distro offers an installation ISO that comes with a live environment. I&rsquo;ve seen a lot of people on Windows who have trouble knowing what to do with an ISO. It&rsquo;s very simple.</p>
<p><img src="https://etcher.balena.io/images/Etcher_steps.gif" alt="Balena Etcher"  loading="lazy" /></p>
<p>The easiest program to use is <a href="https://etcher.balena.io/"target="_blank" rel="noopener">Balena Etcher</a>. You download the file with the <code>.iso</code> extension, whether from Ubuntu, Mint, Elementary, etc (ALWAYS FROM THE OFFICIAL SITE!!!!). Open Balena and there are only 2 steps: select the image (the ISO file), select the drive (your pen drive, careful not to pick your HD!), and done.</p>
<p>Now just boot your PC and go into the BIOS to select the pen drive to boot from, or use a key like F12 (varies from BIOS to BIOS) to have UEFI select your pen drive.</p>
<p>That will boot the Live Environment straight from the pen drive.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912120806_try-ubuntu-install-ubuntu-800x530.jpeg" alt="Try Ubuntu"  loading="lazy" /></p>
<p>Most distros start by opening a &ldquo;Welcome&rdquo; screen similar to the one above. This installer app is called <a href="https://calamares.io/"target="_blank" rel="noopener"><strong>Calamares</strong></a> and everyone with a graphical installer uses it. That&rsquo;s why it looks similar across all of them. It&rsquo;s the same step-by-step. If you&rsquo;ve installed one distro, you&rsquo;ve installed them all.</p>
<p>But you don&rsquo;t have to follow Calamares. You can close it. And now you&rsquo;re already in the graphical environment of the distro you chose to install. <strong>USE IT.</strong> Try to configure your Wi-Fi, try to pair your Bluetooth headphones or mouse, try to turn on the webcam, put in a micro-SD card and see if it shows up. Try to browse the web and feel the performance.</p>
<p>If at this point you can do all the basic things, it means the chances that everything will work are high. If at this point you already start having problems, like not being able to connect to your Wi-Fi, that distro is probably going to give you a headache. Start by going to Google and see if somebody has already solved the problem for your notebook or PC model, <strong>before</strong> continuing with Calamares.</p>
<p>Let&rsquo;s say you decided to take the day to test several distros to see which one runs best on your machine. Great call, but you&rsquo;ve probably figured out that it&rsquo;s going to be a huge pain to have several pen drives, one for each distro. Or having to keep going back to Windows and using Balena to overwrite a new distro on your only pen drive.</p>
<p>You don&rsquo;t need to do that.</p>
<p>You just have to first download and install <a href="https://www.ventoy.net/en/index.html"target="_blank" rel="noopener"><strong>Ventoy</strong></a> on your pen drive. Check the <a href="https://www.ventoy.net/en/doc_start.html"target="_blank" rel="noopener">documentation</a> on their site, but it&rsquo;s ridiculously simple.</p>
<p><img src="https://www.ventoy.net/static/img/screen/screen_uefi_en.png?v=4" alt="Ventoy Menu"  loading="lazy" /></p>
<p>After installing it on your pen drive, now just copy <strong>ALL THE ISOS</strong> you want at once onto the pen drive. When you boot from it, you&rsquo;ll enter the Ventoy menu, which lets you pick any of the ISOs you copied there. If you didn&rsquo;t like the current distro, just reboot into Ventoy again and pick another ISO. It&rsquo;s that simple.</p>
<p><img src="https://www.ventoy.net/static/img/ventoy2disk_en.png" alt="Ventoy"  loading="lazy" /></p>
<h3>Distrobox<span class="hx:absolute hx:-mt-20" id="distrobox"></span>
    <a href="#distrobox" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Let&rsquo;s say you&rsquo;re a programmer, or a devops, or any tech professional. Your concern isn&rsquo;t so much the graphical interface (which you can test with Ventoy), but whether the OS infrastructure is going to work with your development requirements.</p>
<p>Let&rsquo;s say you use Fedora. I wonder, if I go to Mint, will it have the K8s packages the way I need them? Does it support the Java version I use? If I build a <code>.deb</code> package on my Fedora, will it install properly on Ubuntu?</p>
<p>Having to dual boot or install a VM feels too heavy, too much work, just to test 2 command lines, for example.</p>
<p><img src="https://user-images.githubusercontent.com/598882/144294862-f6684334-ccf4-4e5e-85f8-1d66210a0fff.png" alt="Distrobox"  loading="lazy" /></p>
<p>That&rsquo;s what <a href="https://distrobox.it/"target="_blank" rel="noopener"><strong>Distrobox</strong></a> is for. It needs Docker or Podman already installed on your machine. But after that you just do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">distrobox create -n debian-test --init --image debian:latest --additional-packages <span class="s2">&#34;build-essential&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Once the box is created you just enter it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">distrobox enter debian-test</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done, you&rsquo;re inside Debian, super fast. Since it&rsquo;s a Docker container, you can map directories on your local machine into the container, so everything stays integrated. And the most important thing: it loads super fast, because it&rsquo;s just a Docker container.</p>
<p>The <a href="https://distrobox.it/#quick-start"target="_blank" rel="noopener">Quick Start</a> guide explains all of that and has this video with a tour to demonstrate how it works:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/Q2PrISAOtbY"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Seriously. With Distrobox there&rsquo;s no excuse not to test another distro in 2 minutes. Stop wasting time sending DMs to &ldquo;influencers&rdquo;. See for yourself! If you&rsquo;re not capable of doing that, maybe you&rsquo;re in the wrong profession.</p>
<p>Every &ldquo;dev&rdquo; or tech professional, whether devops, cybersec, data analyst, blah blah blah, whatever the trendy title is these days, <strong>MUST</strong> have control over their own machine. <strong>MUST</strong> know how to deal with security (that&rsquo;s why I wrote posts about Vaultwarden, Cloudflare, SSH, etc).</p>
<p><strong>IT&rsquo;S YOUR RESPONSIBILITY!</strong></p>
<p>Don&rsquo;t outsource your responsibility to others. Don&rsquo;t look for validation. Be <strong>promiscuous</strong> and test whichever distros you want, and do whatever you want on those distros: they are yours! There&rsquo;s no such thing as a &ldquo;distro for beginners&rdquo;, &ldquo;distro for devs&rdquo;, &ldquo;distro for devops&rdquo;. A distro is a distro. Linux is Linux. It&rsquo;s all the same, what varies is <strong>your skill</strong>. If you don&rsquo;t have the skill: earn it! Learn! Break your head over it! Pull all-nighters tuning configs! Read the official documentation! Don&rsquo;t waste time thinking you&rsquo;re going to learn on social media. You won&rsquo;t.</p>
<p>I&rsquo;ve been using Linux since the early 90s and I don&rsquo;t stick with Slackware just because it was the first one I learned and I feel a need to validate my first choice. I use whichever ones I want. Right now, I had my own Hyprland setup, and I decided I wanted to learn and use Omarchy. I spent the week banging my head against it, and wrote half a dozen blog posts. And now I&rsquo;ve learned. I know Omarchy: one more for the collection.</p>
]]></content:encoded><category>omarchy</category><category>linux</category><category>tutorials</category></item><item><title>Omarchy 2.0 - Install with the Omarchy ISO</title><link>https://www.akitaonrails.com/en/2025/09/12/omarchy-2-0-install-with-the-omarchy-iso/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/12/omarchy-2-0-install-with-the-omarchy-iso/</guid><pubDate>Fri, 12 Sep 2025 10:00:00 -0300</pubDate><description>&lt;p&gt;To wrap up the &lt;a href="https://www.akitaonrails.com/en/tags/omarchy/"&gt;Omarchy&lt;/a&gt; series for now, I think I still owe a quick word on installing via the official Omarchy ISO.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912093827_screenshot-2025-09-12_09-38-05.png" alt="ISO" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Just head to the &lt;a href="https://omarchy.org/"target="_blank" rel="noopener"&gt;official site&lt;/a&gt; and click &amp;ldquo;ISO&amp;rdquo; to download. Use Rufus or Balena Etcher on Windows (or &lt;a href="https://github.com/ifd3f/caligula"target="_blank" rel="noopener"&gt;Caligula&lt;/a&gt; on Linux) to burn it to a USB stick and boot from it. From there, follow the step-by-step and in less than 5 minutes you&amp;rsquo;ll have everything installed.&lt;/p&gt;</description><content:encoded><![CDATA[<p>To wrap up the <a href="/en/tags/omarchy/">Omarchy</a> series for now, I think I still owe a quick word on installing via the official Omarchy ISO.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912093827_screenshot-2025-09-12_09-38-05.png" alt="ISO"  loading="lazy" /></p>
<p>Just head to the <a href="https://omarchy.org/"target="_blank" rel="noopener">official site</a> and click &ldquo;ISO&rdquo; to download. Use Rufus or Balena Etcher on Windows (or <a href="https://github.com/ifd3f/caligula"target="_blank" rel="noopener">Caligula</a> on Linux) to burn it to a USB stick and boot from it. From there, follow the step-by-step and in less than 5 minutes you&rsquo;ll have everything installed.</p>
<p><img src="https://learn.omacom.io/u/configurator-iGH96F.png" alt="Omarchy install"  loading="lazy" /></p>
<p>As I explained in the <a href="https://akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/"target="_blank" rel="noopener">first article</a>, I did it differently: I installed pure <a href="https://archlinux.org/download/"target="_blank" rel="noopener">Arch Linux</a>, Desktop style, with Hyprland + SDDM. Then I installed Omarchy using the manual command line:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://omarchy.org/install <span class="p">|</span> bash</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You can do it either way. The second gives you more control, but after gaining more experience and reading the install scripts, I recommend downloading the Omarchy ISO itself. It really is easier.</p>
<h3>Limine vs Grub<span class="hx:absolute hx:-mt-20" id="limine-vs-grub"></span>
    <a href="#limine-vs-grub" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The reason I went the manual route was because I wasn&rsquo;t sure if Omarchy supported BTRFS rollback via snapshots. I had heard that the <a href="https://codeberg.org/Limine/Limine"target="_blank" rel="noopener">Limine</a> bootloader didn&rsquo;t support that. But I was wrong: Omarchy installs Limine with <strong>Snapper</strong> support (which is similar to Timeshift, the one I usually use). Read <a href="https://wiki.archlinux.org/title/Limine"target="_blank" rel="noopener">ArchWiki section 6.2</a>. So this should be a superior option to my GRUB+Timeshift setup that I talked about in the first article.</p>
<p>Since I already installed it manually, I&rsquo;ll keep things as they are because in practice it&rsquo;s the same thing. But if I were installing again, I&rsquo;d go with Limine+Snapper just to try it out.</p>
<p>This means there&rsquo;s support for snapshotting your entire filesystem with BTRFS before a package update, and if something goes wrong, you can reboot and roll back to a previous snapshot. That gives you peace of mind so you don&rsquo;t lose a whole day trying to fix something if an important system package ships buggy or corrupted. That&rsquo;s the most important feature.</p>
<h3>SDDM vs UWSM<span class="hx:absolute hx:-mt-20" id="sddm-vs-uwsm"></span>
    <a href="#sddm-vs-uwsm" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Another thing I noticed was the login manager. On pure Arch, it installs Hyprland by default with <a href="https://wiki.archlinux.org/title/SDDM"target="_blank" rel="noopener">SDDM</a>, the same one KDE uses.</p>
<p>Omarchy uses UWSM, which auto-logs you in with your user at boot. So there&rsquo;s no login screen, it just opens Hyprland automatically.</p>
<p><em>&ldquo;But isn&rsquo;t that insecure??&rdquo;</em></p>
<p>No, because the Omarchy ISO pre-configures your SSD with LUKS, below the filesystem.</p>
<p>For those who don&rsquo;t know, <a href="https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system"target="_blank" rel="noopener">LUKS</a> stands for <strong>Linux Unified Key Setup</strong>, which provides full-disk encryption. Its advantage over Windows BitLocker is that it&rsquo;s <strong>filesystem-agnostic</strong>. In other words, it works with BTRFS or EXT4 or any other, because in the boot sequence, after the bootloader (whether Limine or Grub), it loads <strong>before</strong> the filesystem. It&rsquo;s a block-level encryptor.</p>
<p><img src="https://learn.omacom.io/u/arch-encryption-urjrDm.png" alt="install luks"  loading="lazy" /></p>
<p>So when you boot your system, it first asks for the passphrase to decrypt your disk. Then the filesystem opens and the Linux kernel can continue the normal boot with the disk unlocked. So you are <strong>always</strong> forced to type your strong user passphrase at boot to decrypt the disk.</p>
<p>That&rsquo;s why typing a password again at a login manager would be redundant and unnecessary, and I imagine that&rsquo;s why they chose UWSM instead of SDDM.</p>
<p>Especially on a laptop, or in situations where other people live with you, it&rsquo;s <strong>essential</strong> to make sure your disk is encrypted, no matter the operating system. Say you go out to work or travel and your laptop gets stolen. Without encryption, it&rsquo;s game over, regardless of whether you have a login manager. It doesn&rsquo;t protect your data. Anyone can just pull the SSD from your laptop, plug it into another computer, and boom, they can copy everything by booting as root.</p>
<p>With encryption, without the passphrase to decrypt it, accessing your data is impossible. Truly impossible, because on any modern computer from the last 15 years, the CPU ships with hardware-accelerated instructions for AES 256 encryption.</p>
<p>Getting a bit more nerdy: the decryption key <strong>is not your passphrase</strong>. During the install process, a new stronger and more secure key is generated using a <strong>key derivation</strong> process (KDF - Key Derivation Function), nowadays using Argon2id, previously PBKDF2. I explain this in this video:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/HCHqtpipwu4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>So when you type your passphrase, what actually happens is it decrypts that secure key, and it&rsquo;s with that secure key that your disk is encrypted. That&rsquo;s why you can&rsquo;t brute-force decrypt your data.</p>
<p>Plus, AES 256 is one of those encryption algorithms that&rsquo;s <strong>quantum resistant</strong>. Even if a quantum computer were possible (it isn&rsquo;t), not even that could decrypt your disk. That&rsquo;s the level of security.</p>
<p><em>&ldquo;But won&rsquo;t it be slower?&rdquo;</em></p>
<p>No. It&rsquo;s practically imperceptible, because AES, as I said, is hardware-accelerated by your CPU and doesn&rsquo;t depend on operating system software. In day-to-day use, you&rsquo;ll barely notice. Performance is practically the same. There&rsquo;s no reason not to enable encryption, especially on a laptop.</p>
<p>In my personal case, where I installed it on a desktop PC that I control myself on a secure local network, because I know how to implement network security, it&rsquo;s not an issue. My most important data lives on my NAS (which is encrypted), in backups (which are encrypted). I don&rsquo;t have sensitive data on this PC, and the little I do have sits in files encrypted by <a href="https://veracrypt.io/en/Downloads.html"target="_blank" rel="noopener">Veracrypt</a> on a separate sub-volume.</p>
<p>That&rsquo;s why I didn&rsquo;t enable LUKS on my PC. And I kept the SDDM that pure Arch installed. Except it&rsquo;s <strong>REALLY</strong> ugly by default, so here&rsquo;s a small tip: install either the <a href="https://github.com/MarianArlt/sddm-sugar-dark"target="_blank" rel="noopener">sddm-sugar-dark</a> theme or <a href="https://github.com/simonesestito/dark-arch-sddm"target="_blank" rel="noopener">dark-arch-sddm</a>. I prefer the second one because it&rsquo;s more minimalist and looks like this:</p>
<p><img src="https://github.com/simonesestito/dark-arch-sddm/raw/master/base/screenshot.png" alt="dark arch sddm"  loading="lazy" /></p>
<p>I customized it and swapped the Arch logo for the Omarchy one, and that was it.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I&rsquo;ll say it again: only after installing manually did I see how Omarchy installs things, and today I prefer the Omarchy way. If I were installing from scratch, I&rsquo;d use the Omarchy ISO and keep it with Limine+Snapper and Hyprland+UWSM, with snapshot rollback support, full disk encryption, and automatic login into Hyprland.</p>
<p>You can tell the people behind Omarchy have experience and have already picked components that make sense to work together in the most convenient and secure way possible. I was worried that, being a new distro, maybe they hadn&rsquo;t given this much thought, but I&rsquo;m happy to say I was wrong.</p>
<p>Use the official Omarchy ISO.</p>
]]></content:encoded><category>omarchy</category><category>linux</category><category>tutorials</category></item><item><title>Omarchy 2.0 - Bitwarden Self-Hosted / VaultWarden</title><link>https://www.akitaonrails.com/en/2025/09/10/omarchy-2-0-bitwarden-self-hosted-vaultwarden/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/10/omarchy-2-0-bitwarden-self-hosted-vaultwarden/</guid><pubDate>Wed, 10 Sep 2025 20:00:00 -0300</pubDate><description>&lt;p&gt;Continuing the &lt;a href="https://www.akitaonrails.com/en/tags/omarchy/"&gt;Omarchy series&lt;/a&gt; and doing a cross-over with the &lt;a href="https://www.akitaonrails.com/en/tags/homeserver/"&gt;home server series&lt;/a&gt;, let&amp;rsquo;s talk about Password Managers and 2FA. Anyone who follows me knows I talk often about personal digital security, the importance of paying attention to links so you don&amp;rsquo;t fall for scams, phishing, or accidentally install malware.&lt;/p&gt;
&lt;p&gt;More important: having a strong, random, exclusive and different password for &lt;strong&gt;EACH&lt;/strong&gt; site, app or service you use. Never, ever, reuse a password. Why? Because every day one of these sites gets breached and passwords get leaked. If you search for yourself on &lt;a href="https://haveibeenpwned.com/"target="_blank" rel="noopener"&gt;Have I Been Pwned&lt;/a&gt; you&amp;rsquo;ll surely find accounts of yours that have already leaked. And if you share that same password across 10 other sites, someone has probably already gotten into your account by now.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Continuing the <a href="/en/tags/omarchy/">Omarchy series</a> and doing a cross-over with the <a href="/en/tags/homeserver/">home server series</a>, let&rsquo;s talk about Password Managers and 2FA. Anyone who follows me knows I talk often about personal digital security, the importance of paying attention to links so you don&rsquo;t fall for scams, phishing, or accidentally install malware.</p>
<p>More important: having a strong, random, exclusive and different password for <strong>EACH</strong> site, app or service you use. Never, ever, reuse a password. Why? Because every day one of these sites gets breached and passwords get leaked. If you search for yourself on <a href="https://haveibeenpwned.com/"target="_blank" rel="noopener">Have I Been Pwned</a> you&rsquo;ll surely find accounts of yours that have already leaked. And if you share that same password across 10 other sites, someone has probably already gotten into your account by now.</p>
<p>Watch my video about security:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/s7ldn31OEFc"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Being too lazy to use a password manager is just a dumb excuse from lazy people. And a programmer has zero right to use that excuse.</p>
<h3>Omarchy 1Password<span class="hx:absolute hx:-mt-20" id="omarchy-1password"></span>
    <a href="#omarchy-1password" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Anyone who has followed DHH since the early days when Macs were the best platform for developers remembers he was always a fan of 1Password, one of the apps that worked best on iPhones.</p>
<p>I migrated back to Android and Linux many years ago, in 2015. I used <strong>1Password</strong>, but on Android the app was horrendous, ugly, and painful to use. That&rsquo;s why I gave up on it and kept bouncing between several other apps. Google Authenticator, Lastpass (which I don&rsquo;t recommend).</p>
<p>I know there are several other open source ones that people prefer, but I ended up settling on Bitwarden, which is <strong>BEAUTIFUL</strong> both on Android and as a browser extension. On top of that, it has open components and allows <strong>self-hosting</strong>.</p>
<p>More than that, it doesn&rsquo;t make it hard to export all the data from your account and import it somewhere else. Unlike apps like Twilio Authy, which locks you out of everything and is why I stopped using it.</p>
<p>Bitwarden has a secure random password generator, supports <strong>2FA TOTP</strong>, lets you store secure notes (mini texts) and a lot more. The apps integrate with phone biometrics, so it&rsquo;s very convenient to use.</p>
<p>I still keep my Bitwarden inside Samsung&rsquo;s <a href="https://www.samsung.com/global/sustainability/popup/popup_doc/AYUqoB6qDDMAIx_C/"target="_blank" rel="noopener">Secure Vault</a>, the <strong>Samsung Knox Vault</strong>. So there are 2 layers of security. And when I need to walk around somewhere suspicious, I don&rsquo;t take my main phone, only a burner phone with nothing important logged in.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910193713_bitwarden-generator.png" alt="Bitwarden Generator"  loading="lazy" /></p>
<p>Look how beautiful it is. I like it and I&rsquo;ve been using it for a few years now. My passwords range from 21 to 42 random characters, a different one for each site. I&rsquo;ve updated all the passwords for everything more than once in the past few years, and all accounts have 2FA/TOTP registered inside Bitwarden too, which is how I managed to drop Authy.</p>
<h3>Installing VaultWarden Self-Hosted<span class="hx:absolute hx:-mt-20" id="installing-vaultwarden-self-hosted"></span>
    <a href="#installing-vaultwarden-self-hosted" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>More important, the time has come to host my own Bitwarden server, <a href="https://github.com/dani-garcia/vaultwarden"target="_blank" rel="noopener"><strong>vaultwarden</strong></a>, which is an open source alternative, code open on GitHub, so you can poke around yourself to learn or even contribute to it. Again, I bring everything up with Docker Compose on my Home Server, so I just needed to add this snippet to my file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">vaultwarden</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">vaultwarden/server:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">vaultwarden</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">DOMAIN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://bitwarden.fabioakita.dev&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SIGNUPS_ALLOWED</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;false&#34;</span><span class="w">          </span><span class="c"># set to true only to create first user</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">WEBSOCKET_ENABLED</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ADMIN_TOKEN</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;iA...Q9&#34;</span><span class="w">  </span><span class="c"># for /admin</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># SMTP (recommended)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SMTP_HOST</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;smtp.gmail.com&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SMTP_PORT</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;587&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SMTP_SECURITY</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;starttls&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SMTP_USERNAME</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;boss@akitaonrails.com&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SMTP_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;xxx&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">SMTP_FROM</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;boss@akitaonrails.com&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/home/akitaonrails/vaultwarden/data:/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;9999:80&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">healthcheck</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">test</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;CMD&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;wget&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;-q&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;-O&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;-&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;http://localhost/health&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">interval</span><span class="p">:</span><span class="w"> </span><span class="l">30s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">timeout</span><span class="p">:</span><span class="w"> </span><span class="l">5s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">retries</span><span class="p">:</span><span class="w"> </span><span class="m">5</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Important:</p>
<ul>
<li>Create a long, random <code>ADMIN_TOKEN</code>. Use Bitwarden itself for that, keep it secret.</li>
<li>Set <code>SIGNUPS_ALLOWED</code> to <code>true</code> only once, log into the local site and create your new account. Then change it back to <code>false</code> in the file and restart the container. That way nobody else will be able to create any new accounts.</li>
<li>It&rsquo;s recommended to configure a GMAIL SMTP to send notification emails. For that, you need to create an app password in Google.</li>
</ul>
<p>To create a password exclusively for vaultwarden, go to <a href="https://myaccount.google.com/apppasswords"target="_blank" rel="noopener">Google App Passwords</a> and generate a new exclusive secret password:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910194453_screenshot-2025-09-10_16-34-48.png" alt="App Password"  loading="lazy" /></p>
<p>It will only show you that password once. Copy and paste it straight into the docker compose yaml. With email properly configured, every time someone logs in, it sends an email notification. That&rsquo;s good to make sure nobody shady is messing with your server:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910201642_screenshot-2025-09-10_20-16-25.png" alt="notification"  loading="lazy" /></p>
<p>Now I just need to bring up the container:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose -f utils-docker-compose.yml up -d</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Routing the Cloudflared tunnel<span class="hx:absolute hx:-mt-20" id="routing-the-cloudflared-tunnel"></span>
    <a href="#routing-the-cloudflared-tunnel" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>As I already showed in the <a href="https://akitaonrails.com/en/2025/09/09/accessing-my-home-server-with-a-real-domain/"target="_blank" rel="noopener">Cloudflared post</a> now I want to be able to access it remotely, via secure tunnel, using a public URL like <code>https://bitwarden.fabioakita.dev</code>. To do that we have to edit that <code>/etc/cloudflared/config.yml</code> file and add this to the end of it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">hostname</span><span class="p">:</span><span class="w"> </span><span class="l">bitwarden.fabioakita.dev</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">service</span><span class="p">:</span><span class="w"> </span><span class="l">http://192.168.0.200:9999</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">originRequest</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">httpHostHeader</span><span class="p">:</span><span class="w"> </span><span class="l">bitwarden.fabioakita.dev</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">http2Origin</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">service</span><span class="p">:</span><span class="w"> </span><span class="l">http_status:404</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then we have to restart the service and also add the route manually:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo cloudflared tunnel route dns homelab bitwarden.fabioakita.dev
</span></span><span class="line"><span class="cl">sudo systemctl restart cloudflared</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And done! It might take up to 5 minutes for DNS to sync and all that, but then just hop into your browser and you&rsquo;ll see this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910194927_screenshot-2025-09-10_19-49-14.png" alt="VaultWarden Login"  loading="lazy" /></p>
<p>If that <code>SIGNUPS_ALLOWED</code> is <code>true</code> there will also be a link to &ldquo;Create new account&rdquo;. In my case I already did that and turned it off, so there&rsquo;s only login.</p>
<h3>Importing your Data<span class="hx:absolute hx:-mt-20" id="importing-your-data"></span>
    <a href="#importing-your-data" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Before moving on, let&rsquo;s open the Bitwarden extension - which is still logged into the cloud version at bitwarden.com - and export all my data:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910195209_bitwarden-export.png" alt="Export Vault"  loading="lazy" /></p>
<p>Just authenticate, then on the bottom icon bar you&rsquo;ll find &ldquo;Settings&rdquo;, then &ldquo;Vault Options&rdquo; and finally &ldquo;Export vault&rdquo;. Leave the default JSON format (it will be an <strong>encrypted JSON</strong>) and download that file somewhere safe.</p>
<p>Now we can log back into our self-hosted version at <code>https://bitwarden.fabioakita.dev</code> and go through the same menu, but choose &ldquo;Import&rdquo;:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910195410_screenshot-2025-09-10_19-53-56.png" alt="Import"  loading="lazy" /></p>
<p>And done! Now my self-hosted version is <strong>identical</strong> to the cloud version I had been using until now.</p>
<h3>Logging into the new self-hosted server<span class="hx:absolute hx:-mt-20" id="logging-into-the-new-self-hosted-server"></span>
    <a href="#logging-into-the-new-self-hosted-server" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Now just log out of both the mobile App and the browser extension. Then on the login screen you&rsquo;ll see the following option:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910195632_bitwarden-login.png" alt="Login self-hosted"  loading="lazy" /></p>
<p>On the web extension the window doesn&rsquo;t let you see that option, use the mouse scroll and scroll to the bottom of the window and you&rsquo;ll see that small option. Choose &ldquo;self-hosted&rdquo; and a window will open to type the URL <code>https://bitwarden.fabioakita.dev</code> and done!</p>
<p>From here on the usage is exactly the same as before. The interface is the same, the options are the same. Configure <strong>biometrics</strong>, PIN, lock timeout and everything else the way you like it.</p>
<p>Do the same on the mobile app and done!</p>
<p>On this new account we created on the self-hosted server, don&rsquo;t forget to enable 2FA too, which is the &ldquo;Authenticator App&rdquo; option under &ldquo;Settings/Security&rdquo;:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910200009_screenshot-2025-09-10_19-59-55.png" alt="2FA"  loading="lazy" /></p>
<p>For all other accounts, we can register the 2FA inside Bitwarden. But for the master account of Bitwarden/Vaultwarden itself, we need to use a second app just for that.</p>
<p>I don&rsquo;t know if it&rsquo;s the best, but I&rsquo;ve been enjoying using <a href="https://getaegis.app/"target="_blank" rel="noopener">Aegis Authenticator</a> on my Android:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910203243_hero.7C782sEM.png" alt="Aegis"  loading="lazy" /></p>
<p>It&rsquo;s open source, the code is on <a href="https://github.com/beemdevelopment/aegis"target="_blank" rel="noopener">GitHub</a>, so it seems minimally trustworthy. I also keep it inside the Samsung Knox Vault. I only need it when I have to re-login into Bitwarden/Vaultwarden. To log into Google, Steam or any other account, the 2FA for each one lives inside Vaultwarden itself:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910200449_2fa.png" alt="2FA"  loading="lazy" /></p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Now all that&rsquo;s left is to log in with my old account at <strong>bitwarden.com</strong>, which is the &ldquo;official&rdquo; cloud version, and delete my account, to make sure nobody else has access.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250910200615_screenshot-2025-09-10_20-06-04.png" alt="Deletar"  loading="lazy" /></p>
<p>And there, <strong>PERMANENTLY DELETED</strong>! My accounts no longer exist on some random server I don&rsquo;t control, even if they were encrypted.</p>
<p>I&rsquo;m pretty happy with this solution. Now my Vaultwarden is in a container, the home server data gets automatic backups to my NAS, everything is encrypted and access only happens via Cloudflare&rsquo;s secure tunnel. The risk is very low and nobody has a chance of getting access to my data, because it&rsquo;s no longer in the &ldquo;cloud&rdquo;.</p>
<p>My data is mine alone.</p>
]]></content:encoded><category>omarchy</category><category>homelab</category><category>containers</category><category>security</category></item><item><title>Omarchy 2.0 - Understanding SSH and Yubikeys</title><link>https://www.akitaonrails.com/en/2025/09/09/omarchy-2-0-understanding-ssh-and-yubikeys/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/09/omarchy-2-0-understanding-ssh-and-yubikeys/</guid><pubDate>Tue, 09 Sep 2025 12:00:00 -0300</pubDate><description>&lt;p&gt;This post has nothing directly to do with Omarchy, but I decided to include it in the &lt;a href="https://www.akitaonrails.com/en/tags/omarchy/"&gt;same series&lt;/a&gt; because it&amp;rsquo;s an important tip for programmers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every programmer needs to know how to manage their SSH keys.&lt;/strong&gt; At the very least because every GitHub account requires one.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-09_12-19-38.png" alt="GitHub SSH" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Every time you run &lt;code&gt;git push&lt;/code&gt; to one of your repositories, it will ask for the passphrase of that key:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;❯ git push origin master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Enter passphrase &lt;span class="k"&gt;for&lt;/span&gt; key &lt;span class="s1"&gt;&amp;#39;/home/akitaonrails/.ssh/id_ed25519&amp;#39;&lt;/span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What does this mean?&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post has nothing directly to do with Omarchy, but I decided to include it in the <a href="/en/tags/omarchy/">same series</a> because it&rsquo;s an important tip for programmers.</p>
<p><strong>Every programmer needs to know how to manage their SSH keys.</strong> At the very least because every GitHub account requires one.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-09_12-19-38.png" alt="GitHub SSH"  loading="lazy" /></p>
<p>Every time you run <code>git push</code> to one of your repositories, it will ask for the passphrase of that key:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">❯ git push origin master
</span></span><span class="line"><span class="cl">Enter passphrase <span class="k">for</span> key <span class="s1">&#39;/home/akitaonrails/.ssh/id_ed25519&#39;</span>:</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>What does this mean?</p>
<p>SSH is a set of tools, both client and server, to create a secure, encrypted connection over the internet. It has several uses and I explained how to do SSH Proxy in this video:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/T-jHuFnxZ2k"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>The whole process starts by installing SSH on your machine, and on Omarchy/ArchLinux you just do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yay -S openssh</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you&rsquo;ve never created a key pair (yes, it&rsquo;s a pair), just run this command:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh-keygen -t ed25519 -a 100 -C &#34;your_email@example.com&#34; -f ~/.ssh/id_ed25519</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>ED25519</strong> is a public-key algorithm, meaning it creates a pair of keys: a private one that <strong>must never leave your machine</strong>, and a public one that can be exposed on the open internet (the one you register on your GitHub account, for example). I explained public keys in this other video:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/HCHqtpipwu4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>ED25519 is a more modern algorithm than the old RSA (which I think is still the default in ssh-keygen if you don&rsquo;t make an explicit choice — it&rsquo;s still secure, but elliptic curve is even more secure).</p>
<p>It&rsquo;s based on elliptic curve cryptography (ECC). For the paranoid, yes, it&rsquo;s even considered <strong>quantum-resistant</strong>, meaning that even if a quantum computer became feasible, it wouldn&rsquo;t be able to break an ED25519 key.</p>
<p>Two files will be created after running <code>ssh-keygen</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>.rw-------   464 akitaonrails 14 Nov  2017  󰌆 id_ed25519
.rw-r--r--   108 akitaonrails 14 Nov  2017  󰷖 id_ed25519.pub</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Pay attention to the permissions of these files. It&rsquo;s important that the <code>~/.ssh</code> directory and the private key files inside it always have <code>600</code> permission, meaning read-write only for your user, and no permission for groups or any other user. Nobody else should even be able to list the directory.</p>
<p>The <code>*.pub</code> files, which are the public keys, have <code>644</code> permission, which is read-write for you and read-only for other groups and users. As I said, the public key can be exposed publicly. Mine, for example, is this one:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>❯ cat id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEWG5bHK02sMqilMiYu67xqdaBsk3TtCQ564bcJibDiO akitaonrails@Miner42.local</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>ED25519 has another advantage: it&rsquo;s orders of magnitude more secure than RSA and still provides a much shorter public key, which makes copy-pasting it around much easier.</p>
<p>A private key has an envelope in this format:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>-----BEGIN RSA PRIVATE KEY-----
MIIEpA ...
...
XfI0X....
...
... nQ5w==
-----END RSA PRIVATE KEY-----</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Repeating: <strong>THIS FILE MUST NEVER LEAVE YOUR MACHINE</strong>. Never leave it lying around on a pen drive, for example. And always make sure the permission is <code>chmod 600</code> as I explained.</p>
<h3>Yubikey 5<span class="hx:absolute hx:-mt-20" id="yubikey-5"></span>
    <a href="#yubikey-5" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The most secure form, one that many companies even enforce, is the use of a <strong>HARDWARE-KEY</strong>. The private key is never written to your local machine; instead, it&rsquo;s generated inside secure hardware from which it&rsquo;s impossible to read that private key. Examples are Yubikey or FIDO2.</p>
<p>About Yubikey, be careful, you want the newer <strong>Yubikey Series 5</strong> models:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/yubikey.webp" alt="Yubikey 5"  loading="lazy" /></p>
<p>If you have the old one — usually the blue one — it&rsquo;s the Security Key v4.3.1 and only supports <strong>U2F (FIDO U2F)</strong> but not <strong>FIDO2/WebAuthn</strong>, and no <strong>PIV/OpenPGP/OTP</strong> applets. To be sure, install these packages on your Arch:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S yubikey-manager libfido2</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then check with this command:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">❯ ykman info
</span></span><span class="line"><span class="cl">WARNING: PC/SC not available. Smart card <span class="o">(</span>CCID<span class="o">)</span> protocols will not <span class="k">function</span>.
</span></span><span class="line"><span class="cl">Device type: FIDO U2F Security Key
</span></span><span class="line"><span class="cl">Firmware version: 4.3.1
</span></span><span class="line"><span class="cl">Enabled USB interfaces: FIDO
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">Applications
</span></span><span class="line"><span class="cl">Yubico OTP   Not available
</span></span><span class="line"><span class="cl">FIDO U2F     Enabled
</span></span><span class="line"><span class="cl">FIDO2        Not available
</span></span><span class="line"><span class="cl">OATH         Not available
</span></span><span class="line"><span class="cl">PIV          Not available
</span></span><span class="line"><span class="cl">OpenPGP      Not available
</span></span><span class="line"><span class="cl">YubiHSM Auth Not available</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>See how it finds the Yubikey connected via USB but everything shows up as &ldquo;Not available&rdquo;. That&rsquo;s the wrong model — this Yubikey only works as Two-Factor Authentication on websites. It&rsquo;s not useless, but for our case it doesn&rsquo;t work because:</p>
<ul>
<li>it has no PIV applet, so it can&rsquo;t act as a smartcard</li>
<li>it has no OpenPGP applet, so it can&rsquo;t store GPG or SSH private keys</li>
<li>it has no FIDO2, so you can&rsquo;t run <code>ssh-keygen -t ed25519-sk</code>.</li>
</ul>
<p>A new one, on Mercado Livre today, costs around BRL 800. If you&rsquo;re going to use it for work per the company&rsquo;s security policy, they should provide it or reimburse you. But even for personal use, I recommend investing a bit more in security.</p>
<p>With a Yubikey 5 in hand, the procedure is as follows. Start by making sure you have the packages on your machine:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S yubikey-manager yubico-piv-tool opensc</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Initialize the PIV application by changing the PIN:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ykman piv reset                # wipes PIV, careful
ykman piv access change-pin    # default PIN is 123456
ykman piv access change-puk    # default PUK is 12345678</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Generate a new key pair <strong>inside</strong> the Yubikey:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ykman piv keys generate 9a pubkey.pem</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Extract only the public key to your local <code>~/.ssh</code> directory:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh-keygen -D /usr/lib/opensc-pkcs11.so -e &gt; ~/.ssh/id_yubikey.pub</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The contents of that <code>~/.ssh/id_yubikey.pub</code> file is what you&rsquo;ll add to the <code>~/.ssh/authorized_keys</code> file on the remote server you want to connect to via SSH. To open an SSH connection to it, plug the Yubikey into the USB port and run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh -I /usr/lib/opensc-pkcs11.so your-user@server</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It will ask for your PIN and authorize the connection. If you don&rsquo;t want to keep typing that <code>-I</code> every time, just edit <code>~/.ssh/config</code> with this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># ~/.ssh/config
Host server
  PKCS11Provider /usr/lib/opensc-pkcs11.so
  User your-user</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>HOWEVER</strong></p>
<p>This procedure uses the key generator inside the Yubikey, which only supports <strong>RSA (1024–2048)</strong> or <strong>ECC (P-256, P-384)</strong>. If you want to generate an ED25519 key, the flow is different, we have to run it like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh-keygen -t ed25519-sk -a 100 -C &#34;you@example.com&#34; -f ~/.ssh/id_ed25519_sk</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The <code>id_ed25519_sk</code> file that it generates on your local machine is <strong>not the private key</strong>, it&rsquo;s just a &ldquo;stub&rdquo; that points to your Yubikey. So the key stays stored in the hardware and never passes through your machine.</p>
<p>To add your public key to the remote server, just manually append it to the <code>~/.ssh/authorized_keys</code> file as we did before, or run this command to log in with your password and it will add the public key for you:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub your-user@server</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>To use your key to log in now, just do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh -i ~/.ssh/id_ed25519_sk your-user@server</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This only works because the Yubikey 5 has FIDO2 support. The old ones don&rsquo;t, which is why you can&rsquo;t do this with them.</p>
<p>Oh, and on your home server or any other server, <strong>AFTER</strong> adding your key to <code>authorized_keys</code>, I recommend <strong>DISABLING</strong> the password login option (so that no bot keeps trying to brute-force its way in). On the server, edit:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># /etc/ssh/sshd_config
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM no
...
PubkeyAuthentication yes</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In other words, turn off all login options and leave only public-key. Now just restart the service:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo systemctl restart sshd</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>SSH-Agent<span class="hx:absolute hx:-mt-20" id="ssh-agent"></span>
    <a href="#ssh-agent" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>To be clear: the most secure way to manage private keys is via an external security hardware device, in this case the Yubikey 5.</p>
<p>But it&rsquo;s not mandatory. If you have a dedicated PC for work, with your Arch Linux or Omarchy installed, and you don&rsquo;t keep installing shady software — like pirated games — nor keep browsing sketchy sites and clicking on random links (malware risk), keeping your keys locally on your machine isn&rsquo;t entirely bad. I&rsquo;ve been using it this way for years and have never had problems — because I&rsquo;m paranoid about the security of my machine.</p>
<p>Remember, one of the most common types of malware are the ones that upload your files, or encrypt your files and then demand a cryptocurrency ransom to return them. The good old <strong>RANSOMWARE</strong>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/ransomware-message.jpg" alt="Ransomware"  loading="lazy" /></p>
<p>This exists not only on Windows but on Mac and Linux as well. And web browsers are the main vector, especially phishing emails with malicious links that you click on, or links that come through Discord, Telegram, or WhatsApp channels.</p>
<p><strong>NEVER CLICK ON LINKS</strong>. Copy the link, paste it into a terminal, and see what kind of link it is. If it&rsquo;s not an obviously official domain like &ldquo;whatspp.com&rdquo; or &ldquo;google.com&rdquo;, don&rsquo;t go forward.</p>
<p>With all that said. Let&rsquo;s say you created your keys locally and registered them in your server&rsquo;s <code>authorized_keys</code> and in your GitHub account. Now, every time you run <code>ssh</code> or <code>git push</code>, it will ask you to type your <strong>passphrase</strong> (which, if you&rsquo;re not silly, you made <strong>VERY LONG</strong>).</p>
<p>This is extremely inconvenient to keep typing all the time. That&rsquo;s why SSH has a feature to help: caching your authentication for a fixed period using ssh-agent.</p>
<p>Start by creating this user service for systemd:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="c"># ~/.config/systemd/user/ssh-agent.service</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">Unit</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">Description</span><span class="p">=</span><span class="nx">SSH</span> <span class="nx">Agent</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">Service</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">Type</span><span class="p">=</span><span class="nx">simple</span>
</span></span><span class="line"><span class="cl"><span class="nx">Environment</span><span class="p">=</span><span class="nx">SSH_AUTH_SOCK</span><span class="p">=</span><span class="err">%</span><span class="nx">t</span><span class="err">/</span><span class="nx">ssh-agent</span><span class="p">.</span><span class="nx">socket</span>
</span></span><span class="line"><span class="cl"><span class="nx">ExecStart</span><span class="p">=</span><span class="err">/</span><span class="nx">usr</span><span class="err">/</span><span class="nx">bin</span><span class="err">/</span><span class="nx">ssh-agent</span> <span class="nx">-D</span> <span class="nx">-a</span> <span class="err">$</span><span class="nx">SSH_AUTH_SOCK</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">Install</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">WantedBy</span><span class="p">=</span><span class="nx">default</span><span class="p">.</span><span class="nx">target</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Enable it with your user privileges (no sudo):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>systemctl --user enable --now ssh-agent.service</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Expose it in your <code>.bashrc</code> or <code>.zshrc</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># ~/.zshenv (or ~/.profile)</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">SSH_AUTH_SOCK</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$XDG_RUNTIME_DIR</span><span class="s2">/ssh-agent.socket&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now, every time you log into your system and start working, add your work key:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh-add -t 30m ~/.ssh/id_ed25519</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It will ask for your passphrase once, but for <strong>30 minutes</strong> (which is what the <code>-t 30m</code> option does), you won&rsquo;t need to re-type the passphrase and can comfortably keep accessing <code>ssh</code> or doing <code>git push</code>.</p>
<p>If you want to remove the cache from the agent before the timeout, you can do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ssh-add -d ~/.ssh/id_ed25519</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If your work routine involves using ssh, instead of manually running <code>ssh-add</code> you can add the following configuration to your <code>~/.ssh/config</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># ~/.ssh/config</span>
</span></span><span class="line"><span class="cl">Host *
</span></span><span class="line"><span class="cl">  AddKeysToAgent yes
</span></span><span class="line"><span class="cl">  IdentitiesOnly yes
</span></span><span class="line"><span class="cl">  IdentityFile ~/.ssh/id_ed25519</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And every time you open the terminal, it will ask you to type your passphrase. And that will last while your session is logged in.</p>
<p>Finally, the filename in the examples is always <code>id_ed25519</code>, but that has no relevance whatsoever — you can rename it however you want and even create multiple keys to use for separate services if you want to be extra secure. Just generate keys like <code>heroku_id_ed25519</code> or <code>google_cloud_id_ed25519</code> and so on. Create as many keys as you want or think necessary. This applies both to local keys and to keys on the Yubikey 5.</p>
<p>I think these are the aspects I consider most important to know about SSH keys. Did I forget anything else important? Feel free to share more tips in the comments below.</p>
]]></content:encoded><category>omarchy</category><category>security</category><category>linux</category></item><item><title>Omarchy 2.0 - TUIs (Terminal User Interface Apps)</title><link>https://www.akitaonrails.com/en/2025/09/09/omarchy-2-0-tuis/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/09/omarchy-2-0-tuis/</guid><pubDate>Tue, 09 Sep 2025 01:00:00 -0300</pubDate><description>&lt;p&gt;One of the most frustrating things for a Linux user is that there are very few well-made graphical apps. Look at Gimp or LibreOffice. They&amp;rsquo;re ugly, outdated, very similar to the first time I used them over 20 years ago.&lt;/p&gt;
&lt;p&gt;The more &amp;ldquo;modern&amp;rdquo; apps are basically canned web front-ends wrapped inside Electron. The problem? They&amp;rsquo;re &lt;strong&gt;HEAVY&lt;/strong&gt; and chew through RAM like there&amp;rsquo;s no tomorrow. Start opening Discord, Spotify, and a handful of these and see if your old 8GB notebook can keep up.&lt;/p&gt;</description><content:encoded><![CDATA[<p>One of the most frustrating things for a Linux user is that there are very few well-made graphical apps. Look at Gimp or LibreOffice. They&rsquo;re ugly, outdated, very similar to the first time I used them over 20 years ago.</p>
<p>The more &ldquo;modern&rdquo; apps are basically canned web front-ends wrapped inside Electron. The problem? They&rsquo;re <strong>HEAVY</strong> and chew through RAM like there&rsquo;s no tomorrow. Start opening Discord, Spotify, and a handful of these and see if your old 8GB notebook can keep up.</p>
<p>But, especially if you&rsquo;re a programmer, you should pay more attention to TUIs. At first, some will turn their nose up: <em>&ldquo;terminal apps are ugly, black and white, boxy, blegh&rdquo;</em></p>
<p>Twenty years ago, they&rsquo;d be right. But it&rsquo;s 2025 and today&rsquo;s terminals support 256 colors (more than enough), various resolutions and, most importantly, fonts, in particular <a href="https://www.nerdfonts.com/"target="_blank" rel="noopener">Nerd Fonts</a>, fonts that have icons inside. That&rsquo;s how a tool like <a href="https://github.com/eza-community/eza"target="_blank" rel="noopener">eza</a> works, which I use every day aliased to <code>ls</code> and looks like this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_16-50-25.png" alt="eza"  loading="lazy" /></p>
<p>And there&rsquo;s more: there are modern libraries, for several languages, like <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener"><strong>BubbleTea</strong></a>, a framework for building TUIs. Check their GitHub but they have the tools to make interfaces like this:</p>
<p><img src="https://camo.githubusercontent.com/e2b13cfb4ea64e98028ab21e0dca97a6af46d8eeb78ef092c5cd4669ea7b7bef/68747470733a2f2f73747566662e636861726d2e73682f627562626c657465612f627562626c657465612d6578616d706c652e676966" alt="BubbleTea"  loading="lazy" /></p>
<p>And if you just want a simple widget to complement a Bash script you&rsquo;re writing, they have <a href="https://github.com/charmbracelet/gum"target="_blank" rel="noopener"><strong>Gum</strong></a>, which lets you do interfaces like this:</p>
<p><img src="https://camo.githubusercontent.com/cea695e2df946b14838196a5cfb7d6608f03387ba42c7a7fb5afa6432371635c/68747470733a2f2f7668732e636861726d2e73682f7668732d31715935375272516c584375796473456744703638472e676966" alt="Gum"  loading="lazy" /></p>
<p>And to use it just install the binary and put lines like this in your script:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Gum examples</span>
</span></span><span class="line"><span class="cl">gum choose <span class="s2">&#34;fix&#34;</span> <span class="s2">&#34;feat&#34;</span> <span class="s2">&#34;docs&#34;</span> <span class="s2">&#34;style&#34;</span> <span class="s2">&#34;refactor&#34;</span> <span class="s2">&#34;test&#34;</span> <span class="s2">&#34;chore&#34;</span> <span class="s2">&#34;revert&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gum input --placeholder <span class="s2">&#34;scope&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gum confirm <span class="s2">&#34;Commit changes?&#34;</span> <span class="o">&amp;&amp;</span> git commit -m <span class="s2">&#34;</span><span class="nv">$SUMMARY</span><span class="s2">&#34;</span> -m <span class="s2">&#34;</span><span class="nv">$DESCRIPTION</span><span class="s2">&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And if you use <a href="https://akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener"><strong>Omarchy</strong></a> they ship an extra feature for TUIs. Just hit &ldquo;SUPER+ALT+SPACE&rdquo; to bring up the main menu, then pick &ldquo;INSTALL&rdquo; and &ldquo;TUI&rdquo;. Or simply open the terminal and run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$OMARCHY_PATH/bin/omarchy-tui-install</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-08_23-22-50.png" alt="omarchy-tui-install"  loading="lazy" /></p>
<p>It&rsquo;ll ask for a name for the App and the command line to run. You can also pick icons at <a href="https://dashboardicons.com/"target="_blank" rel="noopener">Dashboard Icons</a>. Once registered that way, when you call the Rofi launcher with &ldquo;SUPER+SPACE&rdquo; and type &ldquo;lazy&rdquo;, LazyDocker shows up as if it were a regular app:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/hdmi-a-3.png" alt="Rofi LazyDocker"  loading="lazy" /></p>
<p>And since Hyprland has no title bar or anything, TUI apps or web apps (there&rsquo;s <code>omarchy-webapp-install</code> too) open as if they were &ldquo;native&rdquo; apps:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-09_00-49-28.png" alt="tiles windows"  loading="lazy" /></p>
<p>Read the <a href="https://learn.omacom.io/2/the-omarchy-manual/59/tuis"target="_blank" rel="noopener">TUIs</a> and <a href="https://learn.omacom.io/2/the-omarchy-manual/63/web-apps"target="_blank" rel="noopener">Web-Apps</a> sections in the Omarchy manual.</p>
<p>Obviously, this is only for those who prefer the feeling of running &ldquo;Apps&rdquo;, but it&rsquo;s the same thing as opening a Terminal and simply typing <code>lazydocker</code> on the command line - which is my preference. What these Omarchy scripts do is create a <code>.desktop</code> file at <code>~/.local/share/applications</code>. The <code>LazyDocker.desktop</code> example generates this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>❯ cat ~/.local/share/applications/LazyDocker.desktop
[Desktop Entry]
Version=1.0
Name=LazyDocker
Comment=LazyDocker
Exec=alacritty --class TUI.tile -e lazydocker
Terminal=false
Type=Application
Icon=/home/akitaonrails/.local/share/applications/icons/LazyDocker.png
StartupNotify=true</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you don&rsquo;t want this launcher anymore, just delete the file or call the <code>$OMARCHY_PATH/bin/omarchy-tui-remove</code> script.</p>
<p>This feature is particularly interesting in Hyprland because, unlike GNOME or KDE, the window has no top title bar, so it doesn&rsquo;t give away that you&rsquo;re just opening a terminal or web browser. That&rsquo;s how it ships pre-configured with things like ChatGPT or Grok looking like &ldquo;native&rdquo; apps, when they&rsquo;re really just Chromium windows opening each one&rsquo;s URLs directly:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-09_00-54-52.png" alt="WebApps Omarchy"  loading="lazy" /></p>
<h2>Some TUIs I like<span class="hx:absolute hx:-mt-20" id="some-tuis-i-like"></span>
    <a href="#some-tuis-i-like" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In my opinion, since there are no pretty GUI apps for Linux, it&rsquo;s really better to use the respective web apps like Canva or ChatGPT that way, but more interesting is having actual TUIs. As I said, these days it&rsquo;s not hard to make pretty TUIs. For a programmer, the advantage is that you don&rsquo;t have to deal with front-end frameworks first, and second, you don&rsquo;t have to deploy anywhere on the internet.</p>
<p>TUIs are lightweight, use few machine resources, they&rsquo;re easy for any programmer to build, and you can have a home server or a server in some cloud, SSH in, and access the TUI, without having to deal with X11 or RDP or anything heavier just to get a GUI.</p>
<p>Some TUIs are obvious: in the <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/"target="_blank" rel="noopener">previous post</a> I already talked about <a href="https://www.lazyvim.org/"target="_blank" rel="noopener"><strong>LazyVim</strong></a> and how it&rsquo;s a text editor as competent and complete as VS Code, using only a fraction of the machine&rsquo;s resources. Everyone should know tools like HTOP or BTOP. Plus <a href="https://github.com/jesseduffield/lazygit"target="_blank" rel="noopener">LazyGit</a> or <a href="https://github.com/jesseduffield/lazydocker"target="_blank" rel="noopener">LazyDocker</a>. All of these already come in Omarchy.</p>
<p>But there&rsquo;s much more, for example, <a href="https://github.com/danvergara/dblab"target="_blank" rel="noopener"><strong>dblab</strong></a> which is a TUI database client for MySQL or Postgres:</p>
<p><img src="https://github.com/danvergara/dblab/raw/main/screenshots/dblab-cover.png" alt="dblab"  loading="lazy" /></p>
<p>Another similar one is <a href="https://github.com/jorgerojas26/lazysql"target="_blank" rel="noopener">LazySQL</a>, written in Go:</p>
<p><img src="https://github.com/jorgerojas26/lazysql/raw/main/images/lazysql.png" alt="LazySQL"  loading="lazy" /></p>
<p>Or if you prefer tools written in Rust, there&rsquo;s <a href="https://github.com/achristmascarl/rainfrog"target="_blank" rel="noopener"><strong>rainfrog</strong></a>:</p>
<p><img src="https://github.com/achristmascarl/rainfrog/raw/main/vhs/demo.gif" alt="rainfrog"  loading="lazy" /></p>
<p>For those who can&rsquo;t use CURL on the command line and prefer Postman to call and explore APIs, there&rsquo;s the TUI <a href="https://github.com/darrenburns/posting"target="_blank" rel="noopener"><strong>Posting</strong></a> that does the same thing:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/422760155-78359ab0-5e0c-4c0b-a60b-dce06b11bbf5.png" alt="Posting"  loading="lazy" /></p>
<p>For those of us who run lots of Docker containers, I already mentioned LazyDocker, but there&rsquo;s also <a href="https://github.com/mrjackwills/oxker"target="_blank" rel="noopener"><strong>oxker</strong></a>:</p>
<p><img src="https://github.com/mrjackwills/oxker/raw/main/.github/demo_01.webp" alt="oxker"  loading="lazy" /></p>
<p>If you use Discord, there&rsquo;s <a href="https://github.com/ayn2op/discordo"target="_blank" rel="noopener"><strong>discordo</strong></a>:</p>
<p><img src="https://github.com/ayn2op/discordo/raw/main/.github/preview.png" alt="Discordo"  loading="lazy" /></p>
<p>Anyone who does a lot of Linux ricing has had to burn ISOs to USB sticks dozens of times; for that there&rsquo;s <code>dd</code> on the command line, but there&rsquo;s a cooler TUI called <a href="https://github.com/ifd3f/caligula"target="_blank" rel="noopener"><strong>Caligula</strong></a>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2025/09/09/omarchy-2-0-tuis/caligula-burning.png" alt="Caligula burning a disk image in the terminal: a “Burning… 251.7 MB” bar at the top, a write-speed graph oscillating up to 32 MB/s over ~12 seconds, and a Stats panel showing input my_cool.img.lz4, output /dev/sdb, average write of 20.2 MB/s, and an ETA of 24 seconds."  loading="lazy" /></p>
<p>If your SSD is filling up and you have no idea where the hell all that space is going, there are several tools to analyze and show you. One of them is <a href="https://github.com/dundee/gdu"target="_blank" rel="noopener"><strong>gdu</strong></a>:</p>
<p><img src="https://camo.githubusercontent.com/d8fa7d2f7bdd10dce45a81c2accf26d597b300b82e01b97a1288ff2f1fe06c57/68747470733a2f2f61736369696e656d612e6f72672f612f3338323733382e737667" alt="gdu"  loading="lazy" /></p>
<p>And the last one I thought was cool out of nostalgia is <a href="https://github.com/andmarti1424/sc-im"target="_blank" rel="noopener"><strong>sc-im</strong></a>; think Excel as a TUI or - for those of us who came from the 80s - think Lotus 1-2-3 but with Vim keybindings:</p>
<p><img src="https://github.com/andmarti1424/sc-im/raw/main/screenshots/scim-plot-graph.gif?raw=true" alt="sc-im"  loading="lazy" /></p>
<p>Why open Google Spreadsheets just to make a Todo list if you can do it in the Terminal?? TUIs are exceptional!</p>
<p>If you want to discover more TUIs check out <a href="https://github.com/rothgar/awesome-tuis/?tab=readme-ov-file"target="_blank" rel="noopener"><strong>awesome-tuis</strong></a> on GitHub:</p>
<p><a href="https://github.com/rothgar/awesome-tuis/?tab=readme-ov-file"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2025/09/09/omarchy-2-0-tuis/awesome-tuis-banner.png" alt="awesome tuis"  loading="lazy" /></a>
Again: zero need for heavy web front-ends for simple things. Nothing beats the simplicity of a command line. And with libraries like BubbleTea or Gum, it&rsquo;s now very easy for anyone to make a pretty app. And with Hyprland and Omarchy, everything stays integrated side-by-side with any other GUI app.</p>
<p>Getting a bit philosophical, the history of GUIs starts with <em>skeuomorphic</em> graphical interfaces that try to imitate objects from our daily life, particularly looking pseudo-3D, like Windows 95 was. The 2000s arrived and they started migrating to <em>flat</em> or <em>minimalist</em> interfaces, completely removing the skeuomorphism, making everything flat. That came mainly from Windows 8&rsquo;s Metro. And I think that&rsquo;s converging toward a more TUI-like style, coming full circle, going back to how it was on 70s terminals. Personally, I find that fascinating.</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>linux</category></item><item><title>Omarchy 2.0 - Mise for Organizing Development Environments</title><link>https://www.akitaonrails.com/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/</guid><pubDate>Sun, 07 Sep 2025 16:40:00 -0300</pubDate><description>&lt;p&gt;Continuing my posts about &lt;a href="https://www.akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt;, here&amp;rsquo;s another introductory post, this time about &lt;a href="https://mise.jdx.dev/getting-started.html"target="_blank" rel="noopener"&gt;Mise-en-place&lt;/a&gt;, which already comes pre-installed. On Omarchy, if you press &amp;ldquo;Super+Alt+Space&amp;rdquo; the main menu will open. Pick &amp;ldquo;Install&amp;rdquo; and then &amp;ldquo;Development&amp;rdquo; and you&amp;rsquo;ll see several languages/frameworks you can install, like Ruby on Rails or Go.&lt;/p&gt;
&lt;p&gt;But you don&amp;rsquo;t need to use these menus. Let me explain.&lt;/p&gt;
&lt;p&gt;On a regular Arch Linux or Ubuntu, an amateur would install ruby or python doing something like this:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Continuing my posts about <a href="https://www.akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener">Omarchy</a>, here&rsquo;s another introductory post, this time about <a href="https://mise.jdx.dev/getting-started.html"target="_blank" rel="noopener">Mise-en-place</a>, which already comes pre-installed. On Omarchy, if you press &ldquo;Super+Alt+Space&rdquo; the main menu will open. Pick &ldquo;Install&rdquo; and then &ldquo;Development&rdquo; and you&rsquo;ll see several languages/frameworks you can install, like Ruby on Rails or Go.</p>
<p>But you don&rsquo;t need to use these menus. Let me explain.</p>
<p>On a regular Arch Linux or Ubuntu, an amateur would install ruby or python doing something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># arch
yay -S ruby python3
# ubuntu
apt install ruby python3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>This is the WRONG way.</strong></p>
<p>These commands will install the latest version of each language, and every time you update the system with <code>yay -Syu</code> or <code>apt upgrade</code>, they&rsquo;ll pull in even newer versions.</p>
<p>The thing is, if you develop real projects, <strong>you don&rsquo;t want the versions to change</strong>.</p>
<p>The version deployed on the cloud server and the version on your local machine <strong>MUST BE THE SAME</strong>.</p>
<p>If you&rsquo;re using Ruby v3.0.7 and Node.js 22.19.0, you can&rsquo;t be held hostage to the fact that when you update your system, out of nowhere Ruby 3.4.5 and Node 24.7.0 show up. Everything will start breaking and you&rsquo;ll be super confused without knowing why. This is the most basic mistake a junior developer makes.</p>
<p>To avoid this, every project you&rsquo;re working on MUST BE LOCKED TO FIXED VERSIONS.</p>
<p>The easiest way to do this in 2025 is using <strong>MISE</strong>. As I said, it already comes installed and activated on Omarchy, but if you&rsquo;re using another distro just install Mise manually:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S mise

# .bashrc
eval $(mise activate bash)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Adapt this for ZSH, Fish or whatever shell you&rsquo;re using, read the <a href="https://mise.jdx.dev/installing-mise.html"target="_blank" rel="noopener">documentation</a></p>
<p>Now navigate to your project directory, for example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>cd ~/Projects/AkitaOnRails.com</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And lock the versions:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise use ruby@3.2.3
mise use node@14.21.3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This will create a <code>.tool-versions</code> file that you should add to your repository&rsquo;s git:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>❯ cat .tool-versions
ruby 3.2.3
nodejs 14.21.3

❯ git add .tool-versions</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And done, every time you <code>cd</code> into the directory, Mise will activate exactly the right version for that project. Look:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ ruby -v
ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux]

AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ which ruby
/home/akitaonrails/.local/share/mise/installs/ruby/3.2.3/bin/ruby</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Notice that, if you&rsquo;re using the <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-zsh-configs/"target="_blank" rel="noopener">Starship</a> prompt I explained in the previous post, with a preset like Pure Prompt, it shows the version of each language in the prompt so it&rsquo;s easy to see if you&rsquo;re on the wrong version.</p>
<p>In this case, if you read carefully, you&rsquo;ve probably already noticed that <strong>YES, I&rsquo;M ON THE WRONG VERSION</strong> of Node.js. Look how the prompt says I&rsquo;m using Node 24.7.0 but the <code>.tool-versions</code> file asks for 14.21.3.</p>
<p>The reason it&rsquo;s &ldquo;missing&rdquo; is because this machine was recently installed, but the project is old.</p>
<p>So let&rsquo;s check:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ mise list
Tool    Version            Source                                              Requested
go      1.25.0             ~/.config/mise/config.toml                          latest
node    14.21.3 (missing)  /mnt/data/Projects/AkitaOnRails.com/.tool-versions  14.21.3
node    22.18.0
python  3.13.7
ruby    3.2.3              /mnt/data/Projects/AkitaOnRails.com/.tool-versions  3.2.3
ruby    3.4.5</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>See how in the <code>mise list</code> output it says 14.21.3 is &ldquo;missing&rdquo;. So let&rsquo;s install it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ mise use node@14.21.3
mise /mnt/data/Projects/AkitaOnRails.com/.tool-versions tools: node@14.21.3

AkitaOnRails.com [ master][$!?⇡][ v14.21.3][💎 v3.2.3]
❯</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>With the <code>mise use</code> command we can ask it to install and use a particular version. If it&rsquo;s not already installed, it will install it. Notice how after that the Starship prompt changed to reflect that we&rsquo;re now using 14.21.3. That&rsquo;s the right way.</p>
<p>If you&rsquo;re not necessarily in a project directory with locked versions, you can still run commands using a specific version, like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise exec ruby@3.2.1 -- ruby ...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Say you want to generate a Rails project on a specific Ruby version:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise exec ruby@3.2.3 -- rails new todo-exercise</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The same goes for generators in Node, like Next.js or any other framework.</p>
<p>I haven&rsquo;t checked whether LazyVim on Omarchy comes configured this way, but in case it doesn&rsquo;t, for NeoVim to support Mise you need to add this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="c1">-- Prepend mise shims to PATH</span>
</span></span><span class="line"><span class="cl"><span class="n">vim.env</span><span class="p">.</span><span class="n">PATH</span> <span class="o">=</span> <span class="n">vim.env</span><span class="p">.</span><span class="n">HOME</span> <span class="o">..</span> <span class="s2">&#34;/.local/share/mise/shims:&#34;</span> <span class="o">..</span> <span class="n">vim.env</span><span class="p">.</span><span class="n">PATH</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Just put this in <code>~/.config/nvim/lua/config/mise.lua</code> and it should load the correct path. To integrate with other editors, check <a href="https://mise.jdx.dev/ide-integration.html"target="_blank" rel="noopener">this documentation</a>. There are TONS of advanced options and it&rsquo;s worth reading about them in the <a href="https://mise.jdx.dev/dev-tools/"target="_blank" rel="noopener">Dev-Tools section</a>, but the basics are what I listed here.</p>
<h2>And databases??<span class="hx:absolute hx:-mt-20" id="and-databases"></span>
    <a href="#and-databases" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The same goes for databases. Every project should be locked to a specific version identical to what&rsquo;s running on the production server and should never depend on operating system packages. You can use mise for this but the most recommended option is to use Docker. Every project <strong>MUST</strong> have a <code>docker-compose.yml</code> to spin up only the databases. You don&rsquo;t need to spin up containers for languages, for that it&rsquo;s better to use Mise.</p>
<p>If you don&rsquo;t understand Docker, I made videos teaching it:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/85k8se4Zo70"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

</br>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/-yGHG3pnHLg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Adding up Mise + Docker Compose + LazyVim, that&rsquo;s everything you need to be a productive web developer, while also using your machine&rsquo;s resources efficiently. Every developer NEEDS to learn this combo of options. Omarchy already brings it all pre-installed, which is why it&rsquo;s been my recommendation for every beginner.</p>
<p>Don&rsquo;t worry: Arch Linux (with archinstall) is as easy to install as an Ubuntu or Linux Mint, and Omarchy&rsquo;s Hyprland is much prettier and smoother than MacOS. The best of both worlds. Learn it today!</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>containers</category></item><item><title>Omarchy 2.0 - LazyVim - LazyExtras</title><link>https://www.akitaonrails.com/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/</guid><pubDate>Sun, 07 Sep 2025 16:00:00 -0300</pubDate><description>&lt;p&gt;Continuing my series of tips about &lt;a href="https://akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt;, I decided to write about &lt;a href="https://www.lazyvim.org/"target="_blank" rel="noopener"&gt;LazyVim&lt;/a&gt;, which comes pre-installed.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/292349/213447056-92290767-ea16-430c-8727-ce994c93e9cc.png" alt="LazyVim" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Even if you don&amp;rsquo;t use Omarchy, I recommend &lt;a href="https://www.lazyvim.org/installation"target="_blank" rel="noopener"&gt;installing&lt;/a&gt; LazyVim. Just do this:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;# required
mv ~/.config/nvim{,.bak}
# optional but recommended
mv ~/.local/share/nvim{,.bak}
mv ~/.local/state/nvim{,.bak}
mv ~/.cache/nvim{,.bak}
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.git
nvim&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it. For those who don&amp;rsquo;t know, NeoVim is a more modern fork of the old Vim (hence the command is &lt;code&gt;nvim&lt;/code&gt;, leaving &lt;code&gt;vim&lt;/code&gt; reserved for the old one). It replaces the old VimScript with Lua scripts and has many optimizations and better quality-of-life features. These days, there&amp;rsquo;s no reason to keep using old Vim.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Continuing my series of tips about <a href="https://akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener">Omarchy</a>, I decided to write about <a href="https://www.lazyvim.org/"target="_blank" rel="noopener">LazyVim</a>, which comes pre-installed.</p>
<p><img src="https://user-images.githubusercontent.com/292349/213447056-92290767-ea16-430c-8727-ce994c93e9cc.png" alt="LazyVim"  loading="lazy" /></p>
<p>Even if you don&rsquo;t use Omarchy, I recommend <a href="https://www.lazyvim.org/installation"target="_blank" rel="noopener">installing</a> LazyVim. Just do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># required
mv ~/.config/nvim{,.bak}

# optional but recommended
mv ~/.local/share/nvim{,.bak}
mv ~/.local/state/nvim{,.bak}
mv ~/.cache/nvim{,.bak}

git clone https://github.com/LazyVim/starter ~/.config/nvim

rm -rf ~/.config/nvim/.git

nvim</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s it. For those who don&rsquo;t know, NeoVim is a more modern fork of the old Vim (hence the command is <code>nvim</code>, leaving <code>vim</code> reserved for the old one). It replaces the old VimScript with Lua scripts and has many optimizations and better quality-of-life features. These days, there&rsquo;s no reason to keep using old Vim.</p>
<p>Using Lua, you can configure Nvim any way you want. But configuring everything from scratch is a lot of work. It&rsquo;s a good exercise, but practically speaking, it&rsquo;s not worth it day to day. Better to install a pre-configured setup like the old <a href="https://www.lunarvim.org/"target="_blank" rel="noopener">LunarVim</a>, which I used before and even recommended in some Linux videos on my channel, or <a href="https://astronvim.com/"target="_blank" rel="noopener">AstroNvim</a>, or <strong>LazyVim</strong>, which is currently my favorite. Any of them is a good start and it comes down to personal preference.</p>
<p>Each plugin they install has many features and its own key combinations (hotkeys) that you need to read in the documentation to know what does what. I recommend going to the <a href="https://www.lazyvim.org/plugins"target="_blank" rel="noopener">plugins</a> section of the official site and reading them one by one. There&rsquo;s a lot of stuff you wouldn&rsquo;t even expect, and all of it is very useful.</p>
<p>LazyVim on its own already helps a lot because it opens pop-ups documenting some of the hotkeys. For example, what&rsquo;s called the <strong>Leader</strong> command in LazyVim is the &ldquo;space bar&rdquo;. When you press it, this context menu appears:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-44-17.png" alt="Leader context menu"  loading="lazy" /></p>
<p>From here, if you type, say, &ldquo;b&rdquo;, another context menu shows up:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-46-48.png" alt="Buffer context menu"  loading="lazy" /></p>
<p>And if you type &ldquo;b&rdquo; again, it switches to the next file already open in the Buffer. <strong>Buffer</strong> is the Vim name for where already-opened files live. Deleting from the Buffer is the equivalent of &ldquo;closing the file&rdquo;.</p>
<p>Next time, you won&rsquo;t need to look at the menus. Just type quickly in one go: &ldquo;Space+b+b&rdquo;. That&rsquo;s how you memorize the commands you use the most.</p>
<p>Some commands worth learning right away: <strong>Space+Space</strong> (twice), which opens the menu for opening files. Type a few letters of the file name and it filters dynamically:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-49-35.png" alt="find files"  loading="lazy" /></p>
<p>Or &ldquo;Space+e&rdquo; to open the NeoTree Explorer. Type &ldquo;?&rdquo; to open a popup with the commands you can use to create new subdirectories or files within the subdirectory:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-51-08.png" alt="NeoTree"  loading="lazy" /></p>
<p>Once you learn the other commands and plugins, you&rsquo;ll notice you don&rsquo;t even need to open NeoTree. It&rsquo;s more for when you want to explore visually. For day-to-day work, commands like &ldquo;:e&rdquo; should be enough. By the way, &ldquo;:&rdquo; (colon) is the command for executing NeoVim functions. For example &ldquo;:q&rdquo; is quit, &ldquo;:w&rdquo; is write, and &ldquo;:wq&rdquo; is write and quit at the same time.</p>
<p>If you want to learn NeoVim more deeply, I recommend the YouTube channel of my friend <a href="https://www.youtube.com/@EustaquioRangel"target="_blank" rel="noopener">Eustáquio Rangel</a>, a Linux, Rails, and Vim veteran who teaches NeoVim from scratch (without LazyVim).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_16-09-53.png" alt="TaQ"  loading="lazy" /></p>
<p>Now, let&rsquo;s say you&rsquo;ve already learned the basics of NeoVim and LazyVim, and now you want to start working on your PHP, Java, C#, Ruby, Python, or whatever projects. You&rsquo;ll notice that LazyVim doesn&rsquo;t have any functionality for any of them.</p>
<p>What do you do now? Install VS Code?? <strong>NO!!</strong></p>
<p>That&rsquo;s because you haven&rsquo;t run <a href="https://www.lazyvim.org/extras"target="_blank" rel="noopener">:LazyExtras</a> yet.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-35-36.png" alt="LazyExtras command"  loading="lazy" /></p>
<p>Type it exactly like that and watch this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-36-01.png" alt="Enabled Plugins"  loading="lazy" /></p>
<p>This window looks complicated but it&rsquo;s just a list of plugins split into sections. At the top you see the plugins already installed and enabled. If you don&rsquo;t want any of them, just use the arrows to move the cursor down to one of them and press &ldquo;x&rdquo; to unmark it. But leave that section as is. Let&rsquo;s scroll down to the &ldquo;Languages&rdquo; section:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-36-43.png" alt="Languages section"  loading="lazy" /></p>
<p>This is the section where all the languages you can enable support for live. Just scroll down with the arrows and mark with &ldquo;x&rdquo; which ones you want to install. And there&rsquo;s everything: Angular, Vue, Erlang, Elixir, Rust, Zig, Haskell, and much more.</p>
<p>Next to each language is the group of individual plugins it will install. To know what each one does, type their names into Google and find the documentation page, where you&rsquo;ll find hotkeys and extra configurations you can set.</p>
<p>With this you gain things like Linters, syntax highlighting, LSP, snippets, and much more.</p>
<p>And if you want to install additional plugins that aren&rsquo;t listed, you can add them manually. Read the <a href="https://www.lazyvim.org/configuration/plugins#-adding-plugins"target="_blank" rel="noopener">Adding Plugins</a> section in the documentation.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_16-05-15.png" alt="Linter"  loading="lazy" /></p>
<p>LazyVim + LazyExtras covers 90% of everything you need for day-to-day software development. It&rsquo;s lighter and faster than VS Code, uses way less memory, and will be much better especially on older machines. Don&rsquo;t be lazy about learning Vim. A real programmer shouldn&rsquo;t stick with VS Code just because they&rsquo;re too lazy to learn a few extra hotkeys.</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>tutorials</category></item><item><title>Omarchy 2.0 - ZSH Configs</title><link>https://www.akitaonrails.com/en/2025/09/07/omarchy-2-0-zsh-configs/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/09/07/omarchy-2-0-zsh-configs/</guid><pubDate>Sun, 07 Sep 2025 15:00:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;ve been really enjoying &lt;a href="https://omarchy.org/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt; as my desktop manager. Read &lt;a href="https://akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/"target="_blank" rel="noopener"&gt;my previous post&lt;/a&gt; to see how I installed it and tweaked it for my setup. Following that thread, Omarchy ships with Bash as the default shell. I prefer ZSH. Bash is perfectly usable, this is just personal preference. Some people prefer Fish or others. But Omarchy only ships with Bash for now, so I decided to modify the setup to support my ZSH.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve been really enjoying <a href="https://omarchy.org/"target="_blank" rel="noopener">Omarchy</a> as my desktop manager. Read <a href="https://akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/"target="_blank" rel="noopener">my previous post</a> to see how I installed it and tweaked it for my setup. Following that thread, Omarchy ships with Bash as the default shell. I prefer ZSH. Bash is perfectly usable, this is just personal preference. Some people prefer Fish or others. But Omarchy only ships with Bash for now, so I decided to modify the setup to support my ZSH.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-16-57.png" alt="My ZSH"  loading="lazy" /></p>
<p>If you want to switch to ZSH, it&rsquo;s easy, just do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yay -S zsh zoxide
</span></span><span class="line"><span class="cl">chsh -s <span class="k">$(</span>which zsh<span class="k">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Logout, login, and done. But now your shell will be empty. To grab my config do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/akitaonrails/omarchy-zsh.git ~/.config/zsh
</span></span><span class="line"><span class="cl">ln -s ~/.config/zsh/.zshrc ~/.zshrc </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There are two things you need to change. In <code>.zshrc</code> remove this line:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>source ~/.config/zsh/mounts</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s just for me to check my NFS mounts to my NAS. It&rsquo;s useless to you so you can remove it.</p>
<p>The second thing is to create a new file for secrets:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>touch ~/.config/zsh/secrets
chmod 600 ~/.config/zsh/secrets</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This is where you put stuff like your OpenAI or Google Cloud keys or anything like that. For example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># ~/.config/zsh/secrets
export OPENAI_API_KEY=&#34;sk-xx-v1-xxx...xxxxx&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That way your secrets stay separated from your configs and we can <code>git push</code> to a repository without worrying that something might leak in the future. Always keep secrets, passwords, and keys separated locally. This is already in <code>.gitignore</code> so you&rsquo;re safe.</p>
<p>As a bonus, in <code>~/.config/init</code> I added support for <a href="https://atuin.sh/"target="_blank" rel="noopener">Atuin</a>, a tool that syncs all the command history you ran in your shell to a &ldquo;cloud&rdquo; repository (read the docs, you can create your own local server too). The repository is encrypted, so it&rsquo;s safe even if your history contains secret keys in the commands.</p>
<p>Install it like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S atuin
atuin register -u &lt;your username&gt; -e &lt;your email&gt;
atuin import auto
atuin sync</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>As soon as you register, Atuin will generate a random encryption key. Make sure you store this key somewhere safe like 1Password, Bitwarden or another secure vault!! Without it you won&rsquo;t be able to decrypt on a new installation. If you forget, you can still view it before reinstalling, like:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>atuin key</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you reinstall your machine or set up a new one and want your history back, just install Atuin and run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>atuin login -u &lt;your username&gt;
atuin sync</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It will ask for your password and encryption key and bring all your history back.</p>
<p>With my config, just hit <code>Ctrl+R</code> to bring up the history search (which from now on will live in a sqlite on your machine). Read the <a href="https://docs.atuin.sh/"target="_blank" rel="noopener">documentation</a> for more features.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-17-20.png" alt="Ctrl&#43;R"  loading="lazy" /></p>
<p>DHH set up the <strong>Starship</strong> prompt using the old <code>PS1</code> variable style. But Starship already has several nice prompts that are easy to use as &ldquo;presets&rdquo;. I picked Pure Prompt, which I like, but there are plenty of others. If you want something flashier and more colorful, there&rsquo;s this <a href="https://starship.rs/presets/pastel-powerline"target="_blank" rel="noopener">Pastel Powerline</a>:</p>
<p><img src="https://starship.rs/presets/img/pastel-powerline.png" alt="Pastel Powerline"  loading="lazy" />
Pick your favorite on the <a href="https://starship.rs/presets/"target="_blank" rel="noopener">Presets page</a> and change <code>~/.config/zsh/prompt</code> on this line:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>starship preset bracketed-segments -o ~/.config/starship.toml</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, I left some ENVs in <code>~/.config/zsh/envs</code> that work for my Ollama tests and things like that, but it&rsquo;s good for you to know they&rsquo;re there so you don&rsquo;t find it weird if your Ollama is behaving strangely. Edit the <code>~/.config/zsh/envs</code> file to set the envs you prefer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># envs
export OPENAI_API_BASE=&#34;https://openrouter.ai/api/v1&#34;
export DEFAULT_MODEL=&#34;o1-mini&#34;;
export OLLAMA_API_BASE=http://127.0.0.1:11434
export OLLAMA_HOME=http://127.0.0.1:11434
export OLLAMA_MODELS=/mnt/gigachad/ollama/models</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Also modify the <code>~/.config/zsh/aliases</code> file to include aliases you prefer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># aliases
alias monhd=&#34;sudo ddcutil -d 1 setvcp 60 0x12&#34;
alias mondp=&#34;sudo ddcutil -d 1 setvcp 60 0x0F&#34;

alias sgpt=&#39;docker run --rm -e OPENAI_API_BASE=${OPENAI_API_BASE} -e OPENAI_API_KEY=${OPENROUTER_API_KEY} ghcr.io/tbckr/sgpt:latest txt &#39;

alias git=&#39;nocorrect git&#39;
git config --global alias.a &#39;add&#39;
git config --global alias.ps &#39;push&#39;
git config --global alias.pl &#39;pull&#39;
git config --global alias.l &#39;log&#39;
git config --global alias.c &#39;commit -m&#39;
git config --global alias.s &#39;status&#39;
git config --global alias.co &#39;checkout&#39;
git config --global alias.b &#39;branch&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The first two aliases are for my dual monitor setup where one of the monitors receives signal from both the HDMI input and the DisplayPort input (I have 2 GPUs). If you didn&rsquo;t know, you can control that from the shell. Read <a href="https://jeancharles.quillet.org/posts/2021-08-20-How-to-use-ddcutil-to-switch-input-of-a-Dell-screen.html"target="_blank" rel="noopener">this post about ddcutil</a></p>
<p>Next you get the <code>sgpt</code> command. Omarchy already ships with Docker installed. Now from the shell you can ask ChatGPT without having to open a web browser for it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sgpt &#34;what is the rsync syntax to sync two directories?&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Read the <a href="https://github.com/tbckr/sgpt"target="_blank" rel="noopener">SGPT documentation</a> to learn about other features or which LLMs you can choose.</p>
<p>At the end we have aliases for Git. Omarchy already has an alias making &ldquo;g&rdquo; mean &ldquo;git&rdquo; and with this one I added you can do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>git add . # old
g a . # new

git commit -m &#34;initial commit&#34; # old
g c &#34;initial commit&#34; # new

git commit --amend -m &#34;initial commit&#34;
g ca &#34;initial commit&#34;

git push origin master
g ps origin master

git pull origin master
g pl origin master

git log
g l

# and so on</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>More practical and less verbose. Add more aliases as your workflow demands in <code>~/.config/aliases</code>.</p>
<p>And I think that&rsquo;s it, now my Omarchy is organized the way I like. Make your own tweaks so everything fits your style too!</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>automation</category></item><item><title>Installing Omarchy 2.0 from Scratch - Personal Notes</title><link>https://www.akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/</guid><pubDate>Fri, 29 Aug 2025 16:00:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;ve been recommending DHH&amp;rsquo;s &lt;a href="https://omarchy.org/"target="_blank" rel="noopener"&gt;Omarchy 2.0&lt;/a&gt; to anyone who wants a lightweight, beautiful, and fully-equipped development environment. It&amp;rsquo;s a set of configs for Hyprland running on top of Arch Linux and it ships with smart defaults ready to use. Watch the &lt;a href="https://www.youtube.com/watch?v=TcHY0AEd2Uw"target="_blank" rel="noopener"&gt;video tour&lt;/a&gt; showing the main features.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250828_043020.jpg" alt="my omarchy" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;In my case, I spent 10 years using Manjaro GNOME as my daily driver. Manjaro is an Arch derivative. The reason was the easier install and the pre-made configs. But these days, with &lt;a href="TODO"&gt;archinstall&lt;/a&gt;, I don&amp;rsquo;t think it&amp;rsquo;s worth it anymore. I know there are other derivatives, but it&amp;rsquo;s better to stick with the original.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve been recommending DHH&rsquo;s <a href="https://omarchy.org/"target="_blank" rel="noopener">Omarchy 2.0</a> to anyone who wants a lightweight, beautiful, and fully-equipped development environment. It&rsquo;s a set of configs for Hyprland running on top of Arch Linux and it ships with smart defaults ready to use. Watch the <a href="https://www.youtube.com/watch?v=TcHY0AEd2Uw"target="_blank" rel="noopener">video tour</a> showing the main features.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250828_043020.jpg" alt="my omarchy"  loading="lazy" /></p>
<p>In my case, I spent 10 years using Manjaro GNOME as my daily driver. Manjaro is an Arch derivative. The reason was the easier install and the pre-made configs. But these days, with <a href="TODO">archinstall</a>, I don&rsquo;t think it&rsquo;s worth it anymore. I know there are other derivatives, but it&rsquo;s better to stick with the original.</p>
<p>For Ubuntu folks or those coming from Debian derivatives, Fedora, etc, there&rsquo;s a small learning curve on the package manager: Pacman and Yay instead of Apt or Dnf. But once you understand the AUR, you&rsquo;ll never want anything else. It has literally everything you need, without having to deal with third-party repositories.</p>
<p>I took a while to test Omarchy because I was already using Hyprland before Omarchy was created. DHH previously had Omakub, which was a set of scripts to customize Ubuntu into a good development environment. I liked it, but since I preferred Manjaro, I made a fork called Omakub-MJ. After that I decided to uninstall GNOME and GDM and install another set of scripts called <a href="https://www.ml4w.com/"target="_blank" rel="noopener">ML4W</a>, which makes Hyprland look great as well. So Omarchy wasn&rsquo;t that novel, for me.</p>
<p>The thing is, I&rsquo;d been using the same Manjaro for years. It had a ton of old configs and scripts all mixed up. My Manjaro GNOME no longer even had GNOME. My Hyprland was a Frankenstein. The only barrier was my <strong>QEMU/Libvirt</strong> setup to run Windows with <a href="https://akitaonrails.com/2023/02/01/akitando-137-games-em-maquina-virtual-com-gpu-passthrough-entendendo-qemu-kvm-libvirt/"target="_blank" rel="noopener">GPU passthrough</a>, which is what I used to edit videos back when I was still posting on my <a href="https://www.youtube.com/@Akitando"target="_blank" rel="noopener">YouTube channel</a>.</p>
<p>But since I stopped editing videos, that Windows isn&rsquo;t as important anymore. I had another Windows VM with GPU passthrough for games. But currently I have a separate mini-PC with Windows that I use just for games. I also had another VM with another Linux just for my AI experiments, but since then I migrated to running natively while isolating everything with Docker. In other words, my VMs are no longer important. Check my previous blog posts to learn about AI in Docker.</p>
<p>With the release of Omarchy 2.0, it looks like a good time to reinstall Arch from scratch with Omarchy on top and start over clean and beautiful.</p>
<h2>1 - My Setup<span class="hx:absolute hx:-mt-20" id="1---my-setup"></span>
    <a href="#1---my-setup" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250829_113734.jpg" alt="my PC"  loading="lazy" /></p>
<p>Every case will be different. This post&rsquo;s main purpose is to serve as my personal reference for the future, in case I need to reinstall everything again.</p>
<p>No, I&rsquo;m not going to use <strong>NixOS</strong>. I really don&rsquo;t think it&rsquo;s worth it. It only pays off if you&rsquo;re a computer lab admin or server infrastructure admin and your day-to-day involves rebuilding identical setups reliably. For a normal user who only reinstalls every 2 or 3 years, the learning curve and maintenance work aren&rsquo;t even remotely worth it. It&rsquo;s a waste of time. I&rsquo;d spend days learning now, finish the setup, go 2 years and I&rsquo;d already have forgotten everything. Arch Linux by itself is stable enough that I don&rsquo;t need this.</p>
<p>My setup is still the same from the days I was editing videos for the channel. It&rsquo;s a <strong>Ryzen 9 7850X3D</strong> with 16 cores, 32 threads, 5GHz peak. It&rsquo;s still an excellent CPU with power to spare for my use cases, which is why I don&rsquo;t see myself wanting to upgrade anytime soon. It&rsquo;s rare for me to saturate all those cores at those speeds at the same time. Better yet: it has an integrated AMD GPU which makes installing Linux a thousand times easier than if I had NVIDIA.</p>
<p>But I also have a separate discrete GPU, the <strong>NVIDIA RTX 4090</strong> (no, I don&rsquo;t need a 5090, it has the same amount of VRAM). It&rsquo;ll stay for secondary tasks and not for carrying my graphical environment. Things like Cycles rendering in Blender, or running LLMs with ollama and the like. Before I used GPU passthrough to a VM in QEMU/Libvirt to run Windows in parallel with Linux. Both to edit videos and to game.</p>
<p>Since I no longer edit videos, I don&rsquo;t need this complicated setup, so I won&rsquo;t bother installing Libvirt back. If I need Windows, I&rsquo;ll leave it in dual boot. If I need to edit video, these days we have DaVinci Resolve Studio which runs natively on Linux (a thousand times better than Adobe Premiere). For games I have a separate mini PC with an RTX 4060 hooked up to my TV. The best thing is to have a totally separate PC for games.</p>
<p>So this setup is meant to be pure Linux, with access to my <strong>Synology DS 1821+ NAS</strong> with 100TB. The only extra thing I&rsquo;ll need is to configure NFS mounts, as I&rsquo;ve already detailed in <a href="https://akitaonrails.com/en/2025/04/17/configuring-my-synology-nas-with-nfs-on-linux/"target="_blank" rel="noopener">this other post</a>.</p>
<p>One detail is that I have <strong>4 NVMEs</strong> in this PC. 2TB for my old Linux. 2 TB for dual boot/Windows VM. 2 TB just as a Steam drive and 1 TB for random stuff. Since I&rsquo;m wiping the Steam VM, I also no longer need to dedicate an entire NVME just for that. Instead, I&rsquo;ll make the new Linux&rsquo;s &ldquo;/home&rdquo; directory this entire 2 TB.</p>
<p>This will let me stop worrying about Docker filling my drive and freezing my entire system from lack of space. Last time I had &ldquo;solved&rdquo; this by making a <a href="https://akitaonrails.com/en/2025/04/17/configuring-my-synology-nas-with-nfs-on-linux/"target="_blank" rel="noopener">remote drive with iSCSI</a> on my NAS (which has infinite space). Since removing my Steam VM will give me 2TB back, I&rsquo;ll solve the problem locally and with fewer configurations.</p>
<p>RAM I have in spades, <strong>96GB of DDR5</strong>. With that, I also don&rsquo;t need to worry about a swap partition. Swap only matters if you have less than 32GB of RAM, if you&rsquo;re running lots of Docker and keep hitting the max RAM consumption very fast. Or if you&rsquo;re on a laptop and want the option of hibernation (being able to record RAM to disk, fully power off the machine, and come back later exactly where you left off — which is different from suspend, which still uses power).</p>
<p>If you want to hibernate, you need a bit more than the size of your RAM. So if you have 32GB, it&rsquo;s good to leave a margin, around 34GB or more of swap. Since my PC is a desktop at home, I don&rsquo;t need hibernation, just enable <strong>ZRAM</strong> for the rare cases where there&rsquo;s a spike over 96GB (which is super rare). Plus, it&rsquo;s easier for me to just bump up to 128GB of RAM if I really need it. Swap to compensate for RAM only pays off on laptops that don&rsquo;t have room for more real RAM.</p>
<h2>2 - Why Omarchy?<span class="hx:absolute hx:-mt-20" id="2---why-omarchy"></span>
    <a href="#2---why-omarchy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>As I said, I&rsquo;ve been an Arch user for a decade and I don&rsquo;t see any package repository bigger and more complete than the <strong>AUR</strong>. The only other repository that actually competes is NixOS&rsquo;s. But since Nix is ruled out for my use case, the AUR remains unbeatable.</p>
<p>Arch has Pacman as its package manager. To access the AUR you need a second manager. There are several like the old Pacaur, Paru, and many others. But the best, in my opinion, is Yay. It has exactly the same syntax as Pacman and replaces Pacman. In practice, we just use Yay for everything.</p>
<p>To search packages by name just do <code>yay -Ss spotify</code>.</p>
<p>To remove packages just do <code>yay -Rns spotify</code>.</p>
<p>To update all system packages just do <code>yay -Syu</code></p>
<p>To remove orphan packages that pile up over time just do <code>sudo pacman -Rns $(pacman -Qdtq)</code></p>
<p>And those are the commands I use 99% of the time.</p>
<p>I&rsquo;ve already used every type of desktop manager out there: GNOME (which behaves more like a Mac), KDE (which behaves more like Windows for power users), XFCE (which is GTK-based and lighter), Cinnamon (also GTK-based), i3 (which is a tiling window system), Sway (like i3, also tiling but if I&rsquo;m not mistaken was designed with Wayland in mind).</p>
<p>In practice, everyone uses apps in two ways: a full-screen window or 2 vertical windows splitting the monitor in the middle (editor on one side, browser on the other), or 3 windows (a vertical editor taking half the monitor, a browser taking 1/4, and a terminal taking another 1/4). Then we organize more open apps into virtual desktops/workspaces. That&rsquo;s the easiest way to work.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_12-12-58.png" alt="ideal layout"  loading="lazy" /></p>
<p>This means being able to drag floating windows is a waste of time. I prefer that windows already open sized into one of these layouts I mentioned above. You can configure GNOME or KDE to do that. But it smells like a kludge. Instead it really is better to use i3 or Sway.</p>
<p>Setting <a href="https://x.com/LundukeJournal/status/1942389827518808384"target="_blank" rel="noopener">controversies</a> aside (yes, I&rsquo;m a bit wary of Wayland and I like that XLibre exists). But it&rsquo;s a fact that <strong>X11</strong> is behind the times and is a very old and complicated architecture. Wayland really does have a better &ldquo;appeal,&rdquo; despite having taken a while to round off basic things like screen sharing (OBS, Zoom). But I&rsquo;ve been using Wayland for some years now without headaches. These days I&rsquo;d say it&rsquo;s pretty stable. I&rsquo;ve been using GNOME on Wayland for a long time. I don&rsquo;t stop using things because I&rsquo;m wary of them: with technology I&rsquo;ll always be absolutely promiscuous and use everything.</p>
<p>Knowing I&rsquo;ll use <strong>Wayland</strong> and knowing I want automatic window layouts, and don&rsquo;t need floating windows, the best is a desktop manager with a <strong>tiling windows</strong> system (tiles are &ldquo;azulejos&rdquo; and we&rsquo;re talking about tiles being side by side and never one on top of another), which organizes windows side by side in a smart and automatic way.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_12-19-25.png" alt="windows side by side"  loading="lazy" /></p>
<p>In this case we only have 2 options: <strong>Sway</strong> or <strong>Hyprland</strong> (either one is good). Hyprland, installed from scratch, is completely bare — it has absolutely nothing. We need to configure everything through files in <code>.config/hypr</code>. It&rsquo;s simple enough, but it&rsquo;s work.</p>
<p>The only good option for having a pre-configured and well-done Hyprland was <strong>ML4W</strong>, which I was already using. But now we have Omarchy, which installs and pre-configures everything to work smoothly on Hyprland. This is the best option we have today.</p>
<p>Besides configuring Hyprland to work with <strong>Waybar</strong>, Rofi, and other components, it has its own system for switching themes and styles to leave the system with the <em>&ldquo;look and feel&rdquo;</em> you want (and all the ones that come with it are super pretty), but it also installs things I&rsquo;ve been using for a long time like Neovim with the <strong>LazyVim</strong> package (in my opinion, the easiest way to make Neovim not fall short compared to VS Code), <strong>Mise</strong> (the best way to organize development environments to have multiple versions of your favorite programming language).</p>
<p>If you&rsquo;re installing a distro from scratch, the only two things you need to have are Mise and LazyVim. Plus Docker and LazyDocker. That&rsquo;s enough to start a productive development environment. And Omarchy already brings all of that pre-configured. No one &ldquo;needs&rdquo; Omarchy, but it already brings everything integrated and beautiful. So why bother doing everything from scratch to end up almost the same?</p>
<p>Also, this is Linux. Don&rsquo;t like one of the components? Just swap it out.</p>
<h2>3 - Back Up<span class="hx:absolute hx:-mt-20" id="3---back-up"></span>
    <a href="#3---back-up" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The vast majority of everything I have already lives on the remote server, my 100TB Synology NAS. That already helps a lot. Even so, there&rsquo;s still a good amount of stuff locally on my PC, so the first thing to do is copy everything to the NAS. If you don&rsquo;t have a NAS, then an external HD. Any server will do; the important thing is to guarantee you won&rsquo;t lose anything before installing a new OS from scratch.</p>
<p>Don&rsquo;t forget directories like <code>.config</code> or <code>.local</code>. It&rsquo;s better to do an <code>rsync -avz --progress .config /mnt/nas/backup/</code>, for example, and copy everything. Even what you think you won&rsquo;t need. Better to copy more than to be missing stuff. As a rule, the ideal is to copy everything in your <code>$HOME</code> to an external drive or NAS.</p>
<p>Just to make sure I won&rsquo;t forget anything important, I&rsquo;m also going to record a list of all the packages I have installed on my old system:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -Q &gt; pacotes.txt
flatpak list &gt; flatpak.txt</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Also making sure I won&rsquo;t lose old configs of services I made in systemd, so also copy everything from <code>/etc/systemd/system</code>. It&rsquo;s also worth recording things like <code>/etc/fstab</code>. Also don&rsquo;t forget to back up your SSH keys with <code>tar cvfz ssh.tgz ~/.ssh</code>!!</p>
<p>If, like me, you were using QEMU/Libvirt for VMs, it&rsquo;s good to save the configs of the virtual machines you used. Usually the tool to manage VMs is virsh, so I just did:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo virsh list --all
sudo virsh dumpxml &lt;vmname&gt; &gt; &lt;vmname&gt;.xml</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If I want to recreate the machines in the future, it will all be in the backup. In my case I keep all virtual drives on my NAS, but if yours are local, you also need to save those files that live in <code>/var/lib/libvirt/images/</code></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>rsync -avh --progress /var/lib/libvirt/images/ /backup/libvirt-images/</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>4 - Is Installing Arch Hard?<span class="hx:absolute hx:-mt-20" id="4---is-installing-arch-hard"></span>
    <a href="#4---is-installing-arch-hard" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Arch, less than Gentoo, has always had a reputation for being the most brutal Linux distro for a beginner to install. That&rsquo;s not a lie, but the truth is Arch is simultaneously the hardest distro and also the easiest.</p>
<p>Download <a href="https://archlinux.org/download/"target="_blank" rel="noopener">the official ISO</a> and burn it to a USB drive (on Windows, using <strong>Rufus</strong> or Balena Etcher). Now press F12 (depends on your BIOS) or configure the BIOS directly to boot from the USB drive. Doing that loads the Arch live environment, which is literally dropping into a command line. With no further help.</p>
<p>From this point you have to follow the <a href="https://wiki.archlinux.org/title/Installation_guide"target="_blank" rel="noopener">Installation Wiki</a> from the excellent ArchWiki and learn how to install a Linux from absolute scratch using only the command line, step by step, through trial and error (more erring than hitting the mark), and in the end you&rsquo;ll have a much better feel for how a Linux distro actually works.</p>
<p>I didn&rsquo;t make an Arch video but I did make videos of <a href="https://www.youtube.com/watch?v=iQkBbRPkASo"target="_blank" rel="noopener">Slackware</a> to explain how a package manager works. I also made a <a href="https://www.youtube.com/watch?v=cSyTjCUFx2A"target="_blank" rel="noopener">Gentoo</a> video to show how a distro that compiles everything from scratch works. And I made a video about how the <a href="https://www.youtube.com/watch?v=5F6BbhgvFOE"target="_blank" rel="noopener">Linux Boot Works</a> to understand where the kernel lives and how it&rsquo;s structured. But I didn&rsquo;t make an Arch video because I always left it as an exercise for beginners.</p>
<p>The manual way is viable, but if you&rsquo;re used to a graphical installer, like <strong>Calamaris</strong>, which most more popular distros like Ubuntu or Fedora have, you&rsquo;ll be totally lost. But here comes the bonus: you don&rsquo;t need to go through all of that to have Arch Linux on your machine.</p>
<p>For that there&rsquo;s <a href="https://wiki.archlinux.org/title/Archinstall"target="_blank" rel="noopener"><strong>archinstall</strong></a>.</p>
<p>When you boot the Arch USB and drop into the command line, just type archinstall and you&rsquo;re done — just follow the step by step it provides (which I consider even simpler than Calamaris) and it will install and configure everything automatically for you, the same way installing Fedora or any other distro is. Seriously, it shouldn&rsquo;t take more than 15 minutes.</p>
<p>archinstall looks like this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250828_045255.jpg" alt="archinstall"  loading="lazy" /></p>
<p>Just go into each of the items on the left and fill in your choices. Configure things like keyboard layout (I normally choose &lsquo;us-acentos&rsquo;). Edit the hostname of your machine. Choose &ldquo;NetworkManager&rdquo; in network configuration (it will configure both ethernet and wifi for you), add Bluetooth and Audio support (choose &ldquo;Pipewire&rdquo;). Choose the &ldquo;desktop&rdquo; type instead of &ldquo;minimal&rdquo; to already get the main packages needed for a desktop. Choose the timezone (&ldquo;America/Sao_Paulo&rdquo; in my case).</p>
<p>I also recommend choosing the Hyprland option, I think under Applications or Additional Packages. It will install SDDM to give you a graphical login.</p>
<p>Only two options need more attention: for bootloader, many will be tempted to use <strong>Limine</strong>, which is more modern and lightweight. But I still recommend using <strong>GRUB</strong>, I&rsquo;ll explain why in a moment.</p>
<p>The second important option is &ldquo;Disk Configuration&rdquo;. Don&rsquo;t worry, unlike fdisk, it&rsquo;s super intuitive. Just choose the correct drive where you want to install (if you have dual boot, careful not to wipe your Windows). Then let it do the automatic partition layout (only edit manually if you have some very special need). Most importantly, choose <a href="https://wiki.archlinux.org/title/Btrfs"target="_blank" rel="noopener"><strong>BTRFS</strong></a> instead of the traditional ext4.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250828_045312.jpg" alt="btrfs"  loading="lazy" /></p>
<p>Every Linux always formats its Linux partitions with ext4, which is the oldest, most stable, and best-documented file system. These days I recommend BTRFS; it&rsquo;s much more modern, safer (has better corruption protection systems), uses less space (learn about CoW - <strong>Copy on Write</strong>), and most importantly: it has cheap snapshot support (think of Apple Time Machine, only better). It has most of the features of a file system dedicated to a file server but is much simpler and more intuitive to use than the monster that is ZFS (I don&rsquo;t recommend it for normal users).</p>
<p>It has some maintenance needs that are worth reading about in the Wiki to learn. But overall it&rsquo;s plug and play, install and forget. In the next sections I&rsquo;ll show some things you need to know, but trust me: choose BTRFS.</p>
<p>I know Omarchy 2.0 has an option for a <a href="https://iso.omarchy.org/omarchy-online.iso"target="_blank" rel="noopener">pre-configured ISO</a> which I imagine is normal Arch with archinstall and Omarchy on top all at once. But I don&rsquo;t know if they allow this choice, which is why I preferred going straight to pure Arch first. In the end the effect is the same. Comment below later if the Omarchy ISO also has the same options. Just make sure in the end you have BTRFS. Future you will thank you.</p>
<h2>5 - Separate HOME<span class="hx:absolute hx:-mt-20" id="5---separate-home"></span>
    <a href="#5---separate-home" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>As I explained before, I used one of my 4 NVMEs as the Linux drive. But now I&rsquo;ve freed up another NVME and want to move my $HOME there and have 2 TB dedicated just to user space.</p>
<p>I won&rsquo;t explain how to partition and format that other drive. It&rsquo;s simple: just use <a href="https://wiki.archlinux.org/title/Fdisk"target="_blank" rel="noopener">fdisk</a> or later install <strong>Gparted</strong> which is the graphical version of the <a href="https://wiki.archlinux.org/title/Parted"target="_blank" rel="noopener">parted</a> tool that you can use from the command line. There are several options. The important thing is just to wipe my old Windows partition and also format it with BTRFS.</p>
<p>Each person will have different device and partition names than mine. To find out which are yours, use the <code>lsblk</code> command. See my example:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_12-54-42.png" alt="lsblk"  loading="lazy" /></p>
<p>In my example <code>nvme1n1</code> is the 1TB drive for random stuff. <code>nvme2n1</code> is my new Arch Linux. <code>nvme0n1</code> is the old Windows dual boot drive. <code>nvme3n1</code> is the Steam drive I formatted with BTRFS to become my new HOME drive.</p>
<p>If you didn&rsquo;t get it, HOME is the <code>/home/akitaonrails</code> directory. It will live on a separate drive. After archinstall finishes and I boot into the new Linux, I just do the following:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo mount -t btrfs /dev/nvme3n1p1 /mnt
sudo btrfs subvolume create /mnt/@home
rsync -aAXHv /home/ /mnt/@home/
sudo umount /mnt</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This mounts the new partition, then we use the &ldquo;btrfs&rdquo; command to create a new sub-volume called &ldquo;@home&rdquo; (again, read the BTRFS Wiki to understand concepts like sub-volumes).</p>
<p>The commands above create the sub-volume and copy everything from the old HOME to the new. Now we need <code>/home</code> to be mounted on this new partition at boot. For this we need to know the UUID of that partition:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>~ ❯ sudo blkid /dev/nvme3n1p1
/dev/nvme3n1p1: LABEL=&#34;HOME&#34; UUID=&#34;84e9a1b7-a30e-...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The <code>blkid</code> command returns the unique UUID of each partition and, with that, we can edit the <code>/etc/fstab</code> file using <code>sudo nvim</code> or <code>sudo nano</code> or the editor of your choice:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># /etc/fstab
...
# /dev/nvme2n1p2
# UUID=da3aea43-...-aeaf8c7224d7 /home      btrfs      rw,relatime,ssd,discard=async,space_cache=v2,subvol=/@home 0 0

# /dev/nvme3n1p1
UUID=84e9a1b7-...-7a6a17fd0395 /home      btrfs      rw,relatime,ssd,discard=async,space_cache=v2,subvol=/@home 0 0
...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>See how I commented out the old line that mounted <code>/home</code> and added a new line with the new UUID. The rest is all the same. And that&rsquo;s it, just boot and from now on my <code>/home</code> will mount on the new drive. Now I have 2 TB dedicated just to my junk downloads lol 🤣</p>
<p>But not only that, I also have space for big things like Docker images or LLM models, without risking filling the operating system drive and running the risk of it no longer booting due to lack of space — as has happened to me several times in the past. Always remember to do maintenance on Docker and LLMs and delete old things.</p>
<p>Speaking of which, BTRFS supports snapshots. And one of the basic mistakes is forgetting that Docker or LLM directories can end up in the snapshots and occupy space without you knowing. To avoid this it&rsquo;s better to mark those directories to not enter the snapshots. For that we have to tell BTRFS to ignore those directories.</p>
<p>The correct way is to create separate subvolumes for them. For this I&rsquo;ll mount that same partition on the separate drive where I mounted my $HOME:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>~ ❯ sudo mkdir /mnt/temp
~ ❯ sudo mount -o subvolid=5 -t btrfs /dev/nvme3n1p1 /mnt/temp

~ ❯ ls /mnt/temp
 @home   timeshift-btrfs

~ ❯ sudo btrfs subvolume create /mnt/temp/@docker
Create subvolume &#39;/mnt/temp/@docker&#39;

~ ❯ sudo btrfs subvolume create /mnt/temp/@ollama
Create subvolume &#39;/mnt/temp/@ollama&#39;

~ ❯ sudo umount /mnt/temp</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now just edit <code>/etc/fstab</code> to mount correctly just like we did with HOME:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># /etc/fstab
...
# /dev/nvme3n1p1
UUID=84e9a1b7-...-7a6a17fd0395 /home      btrfs      rw,relatime,ssd,discard=async,space_cache=v2,subvol=/@home 0 0
UUID=84e9a1b7-...-7a6a17fd0395 /var/lib/docker      btrfs      rw,relatime,ssd,discard=async,space_cache=v2,subvol=/@docker 0 0
UUID=84e9a1b7-...-7a6a17fd0395 /var/lib/ollama      btrfs      rw,relatime,ssd,discard=async,space_cache=v2,subvol=/@ollama 0 0
...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done, clean subvolumes. More important in my case: I moved directories that have a tendency to grow without control out of the operating system partition, making it harder to end up with an inaccessible system due to lack of space. Do the same with other similar directories, with things like Kubernetes, for example. Anything that keeps downloading large files, like system images.</p>
<p>Now just mount and bring things back:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># every time you edit fstab, run this:
sudo systemctl daemon-reload

# create the mount points
sudo mkdir /var/lib/docker
sudo mkdir /var/lib/ollama

# mount
sudo mount /var/lib/docker
sudo mount /var/lib/ollama

# copy the contents of the old directory back
sudo rsync -aHAX --inplace /var/lib/docker.old/ /var/lib/docker/
sudo systemctl start docker</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Besides space management, what&rsquo;s the other advantage of making separate subvolumes? Because the next section will be about making the system even more robust by adding snapshot and rollback capability to past snapshots. And the ideal is to keep huge files out of snapshots that will sit in the past. Docker images are easy to recover: just <code>docker pull</code> again, no need for backup.</p>
<h2>6 - Installing Omarchy<span class="hx:absolute hx:-mt-20" id="6---installing-omarchy"></span>
    <a href="#6---installing-omarchy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the easiest part. When you&rsquo;re done installing with archinstall, if you chose the Hyprland option, SDDM will appear for you to log in. And when you enter you&rsquo;ll be shocked at how <strong>raw</strong> Hyprland is. You basically can&rsquo;t do anything.</p>
<p>So this doesn&rsquo;t become an entire day of manual configuration, we&rsquo;ll use Omarchy. Hit &ldquo;Super Enter&rdquo; to open the terminal and don&rsquo;t mind how ugly things look right now. It&rsquo;ll get better.</p>
<p>In the terminal just do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>curl -fsSL https://omarchy.org/install | bash</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Just follow the on-screen instructions and let it do the rest. And that&rsquo;s it, done, there&rsquo;s no next step.</p>
<p>I HIGHLY recommend you read the <a href="https://learn.omacom.io/2/the-omarchy-manual"target="_blank" rel="noopener">OMARCHY ONLINE MANUAL</a> that DHH made. It&rsquo;s very clean, simple, and direct. All the keyboard shortcuts, for example, are in the <a href="https://learn.omacom.io/2/the-omarchy-manual/53/hotkeys"target="_blank" rel="noopener">HOTKEYS section</a>. Spend an hour reading the basics to be able to operate it. But by now you already have practically everything you need: Alacritty as terminal, Chromium as browser (you can install Brave if you prefer, as I do).</p>
<p>&ldquo;Super Alt Space&rdquo; opens the Omarchy main menu. &ldquo;Super Space&rdquo; opens Rofi to type the name of the app you want to open. &ldquo;Super Enter&rdquo; opens the terminal. &ldquo;Super B&rdquo; opens the browser and so on.</p>
<h2>7 - Customizing Omarchy<span class="hx:absolute hx:-mt-20" id="7---customizing-omarchy"></span>
    <a href="#7---customizing-omarchy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Omarchy is a customized Hyprland. We can edit whatever we want directly in <code>~/.config/hypr</code>. And since I was used to ML4W, I decided to tweak a bit to make it good for my setup. Your setup will vary depending on your needs.</p>
<p>Right after I finished installing Omarchy and tried to use Gparted to partition that second NVME of mine for HOME, it had an authentication problem. I don&rsquo;t remember if this was the solution but it&rsquo;s good to make sure you have Polkit installed:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># make sure polkit &#43; agent exist
sudo pacman -S --needed polkit polkit-gnome xorg-xhost

# Hyprland: export full env to systemd user bus once
dbus-update-activation-environment --systemd --all</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Back to it, the first thing I need to solve is that I have 2 monitors. An Asus 32&quot; 1440p 144fps as the main and another Samsung 24&quot; 4K 60fps vertical on the left side. The way to configure this in Hyprland is by editing a file like <code>~/.config/hypr/monitors.conf</code> which is normally loaded by <code>~/.config/hypr/hyprland.conf</code>.</p>
<p>Instead of doing this manually, I prefer to install:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S nwg-displays</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_13-46-04.png" alt="nwg-displays"  loading="lazy" /></p>
<p>Here I configure things like transform 90 degrees to rotate the vertical monitor, resolution scaling, 10-bit color support, etc.</p>
<p>It will save two files: <code>~/.config/monitors.conf</code> and <code>~/.config/workspaces.conf</code>. Omarchy doesn&rsquo;t load this second file, so we have to edit <code>~/.config/hypr/hyprland.conf</code> to look like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>...
# Change your own setup in these files (and overwrite any settings from defaults!)
source = ~/.config/hypr/monitors.conf
source = ~/.config/hypr/workspaces.conf`
...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I also took the opportunity to add some extra configurations in this file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>...
# animation
animations {
  enabled = yes
  bezier = easeOutQuint, 0.23, 1, 0.32, 1
  animation = workspaces, 1, 4, easeOutQuint, slide
  # optional extras:
  animation = specialWorkspace, 1, 4, easeOutQuint, slide
  animation = windows, 1, 4, easeOutQuint, popin 80%
  animation = fade, 1, 4, easeOutQuint
}

xwayland {
    force_zero_scaling = false # careful with mixing scaling wayland and x11
}

input {
  numlock_by_default = true
}

# dialogs/splash/utility ONLY
windowrulev2 = float,  xwayland:1, windowtype:^(dialog|splash|utility)$
windowrulev2 = center, xwayland:1, windowtype:^(dialog|splash|utility)$

# never center menus/tooltips
windowrulev2 = tile,   xwayland:1, windowtype:^(popup_menu|dropdown_menu|tooltip)$</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Some people don&rsquo;t like it but I like having a quick animation when I switch from one workspace to another, which is why I added the <code>animations</code> block.</p>
<p>When you use apps made for X11, they&rsquo;ll run on top of XWayland. One annoying thing is that some of them open &ldquo;dialog boxes,&rdquo; which are floating windows. And they can end up in places hard to click, especially on a multi-monitor setup. That&rsquo;s why I added blocks like <code>xwayland</code> and <code>windowrulev2</code> rules to force those dialog boxes to always appear centered on screen.</p>
<p>Finally, I have an 8bitdo numpad keyboard connected via Bluetooth, but it doesn&rsquo;t start up with numlock on. To fix this there&rsquo;s that <code>input</code> block.</p>
<p>Back to the monitor layout. After nwg-displays generated the files, I still had to modify a bit for my case, like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># ~/.config/monitors.conf
# Generated by nwg-displays on 2025-08-28 at 14:30:17. Do not edit manually.

#monitor=HDMI-A-3,2560x1440@143.97,1080x407,1.25,bitdepth,10
#monitor=DP-5,3840x2160@60.0,0x0,1.875,bitdepth,10
#monitor=DP-5,transform,1
#monitor=DP-1,0x0@60.0,-1x-1,1.0
#monitor=DP-1,disable

monitor=HDMI-A-3,2560x1440@143.97,2813x948,1.0,bitdepth,10
monitor=DP-5,3840x2160@60.0,1373x350,1.5,bitdepth,10
monitor=DP-5,transform,1
monitor = DP-1,disable</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The monitor file I didn&rsquo;t have to change anything, really, just remember to disable that DP-1 that appears on my main monitor (I think it&rsquo;s its DisplayPort, but I use HDMI, so I have to disable DP-1).</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># ~/.config/workspaces.conf
# Generated by nwg-displays on 2025-08-28 at 13:07:02. Do not edit manually.

workspace=5,monitor:DP-5,persistent:true
workspace=1,monitor:HDMI-A-3,persistent:true
workspace=2,monitor:HDMI-A-3,persistent:true
workspace=3,monitor:HDMI-A-3,persistent:true
workspace=4,monitor:HDMI-A-3,persistent:true</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This one I also didn&rsquo;t have to change much, in nwg-displays itself I said which workspaces I want on each monitor. In my personal preference I prefer to leave the vertical monitor only with workspace 5 and the others on the main monitor. The difference here was that I added those <code>persistent:true</code> options on all of them, to guarantee that everything will work correctly with the workspaces &ldquo;pinned&rdquo; in the right places. Workspaces in Hyprland are quite dynamic; it&rsquo;s worth reading the documentation later if you want more complicated cases.</p>
<p>This solves my two-monitor setup the way I prefer. Experiment with things like scaling until everything is okay for your setup.</p>
<p>Next I needed to solve the hotkeys (key bindings). I&rsquo;m used to some combinations that came from ML4W so I decided to copy them directly into <code>~/.config/hypr/bindings.conf</code>. First, switch chromium for Brave:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># Application bindings
$terminal = uwsm app -- alacritty
$browser = brave # omarchy-launch-browser
...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then I added a bunch of binds at the end of the same file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>unbind = SUPER, V
bind = SUPER, V, swapsplit
bind = SUPER, M, fullscreen, 1                                                           # Maximize Window
bind = SUPER, T, togglefloating                                                          # Toggle active windows into floating mode
bind = SUPER SHIFT, right, resizeactive, 100 0                                           # Increase window width with keyboard
bind = SUPER SHIFT, left, resizeactive, -100 0                                           # Reduce window width with keyboard
bind = SUPER SHIFT, down, resizeactive, 0 100                                            # Increase window height with keyboard
bind = SUPER SHIFT, up, resizeactive, 0 -100                                             # Reduce window height with keyboard

# Display
bind = SUPER SHIFT, mouse_down, exec, hyprctl keyword cursor:zoom_factor $(awk &#34;BEGIN {print $(hyprctl getoption cursor:zoom_factor | grep &#39;float:&#39; | awk &#39;{print $2}&#39;) &#43; 0.5}&#34;) # Increase display zoom
bind = SUPER SHIFT, mouse_up, exec, hyprctl keyword cursor:zoom_factor $(awk &#34;BEGIN {print $(hyprctl getoption cursor:zoom_factor | grep &#39;float:&#39; | awk &#39;{print $2}&#39;) - 0.5}&#34;) # Decrease display zoom
bind = SUPER SHIFT, Z, exec, hyprctl keyword cursor:zoom_factor 1 # Reset display zoom

# Workspaces
bind = SUPER, 1, workspace, 1 on HDMI-A-3 # Open workspace 1
bind = SUPER, 2, workspace, 2 on HDMI-A-3  # Open workspace 2
bind = SUPER, 3, workspace, 3 on HDMI-A-3 # Open workspace 3
bind = SUPER, 4, workspace, 4 on HDMI-A-3 # Open workspace 4
bind = SUPER, 5, workspace, 5 on DP-5 # Open workspace 5

bind = SUPER SHIFT, 1, movetoworkspace, 1  # Move active window to workspace 1
bind = SUPER SHIFT, 2, movetoworkspace, 2  # Move active window to workspace 2
bind = SUPER SHIFT, 3, movetoworkspace, 3  # Move active window to workspace 3
bind = SUPER SHIFT, 4, movetoworkspace, 4  # Move active window to workspace 4
bind = SUPER SHIFT, 5, movetoworkspace, 5  # Move active window to workspace 5

bind = SUPER, Tab, workspace, m&#43;1       # Open next workspace
bind = SUPER SHIFT, Tab, workspace, m-1 # Open previous workspace

bind = SUPER CTRL, 1, exec, $HOME/.config/hypr/moveTo.sh 1  # Move all windows to workspace 1
bind = SUPER CTRL, 2, exec, $HOME/.config/hypr/moveTo.sh 2  # Move all windows to workspace 2
bind = SUPER CTRL, 3, exec, $HOME/.config/hypr/moveTo.sh 3  # Move all windows to workspace 3
bind = SUPER CTRL, 4, exec, $HOME/.config/hypr/moveTo.sh 4  # Move all windows to workspace 4
bind = SUPER CTRL, 5, exec, $HOME/.config/hypr/moveTo.sh 5  # Move all windows to workspace 5</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Note that the last block of scripts needs a script to move all windows at once to another workspace. I copied this <a href="https://github.com/mylinuxforwork/dotfiles/blob/main/dotfiles/.config/hypr/scripts/moveTo.sh"target="_blank" rel="noopener">moveTo.sh</a> from ML4W&rsquo;s GitHub and placed it directly in <code>~/.config/hypr</code>. Don&rsquo;t forget to give execute permission with <code>chmod +x moveTo.sh</code> afterwards.
The various workspace ones below are how I prefer to move workspaces and move apps to different workspaces.</p>
<p>Omarchy already comes with &ldquo;SUPER J&rdquo; to change the orientation of windows, for example, if there are two horizontal windows one on top of the other, with SUPER J they become vertical, but &ldquo;SUPER V&rdquo; was missing which I added for &ldquo;swapsplit&rdquo; which is swapping windows&rsquo; places.</p>
<p>I also like &ldquo;SUPER M&rdquo; to temporarily make one of the windows full screen, and &ldquo;SUPER T&rdquo; to temporarily make a window floating (like a calculator, for example). I had to unbind the previous SUPER M that opened Spotify, but I barely use Spotify on desktop so I don&rsquo;t need it. When I want to open that app, I go to SUPER SPACE to open Rofi and type it there.</p>
<p>If you have questions about the default combinations, Omarchy has &ldquo;SUPER K&rdquo; to open a window with help for all of them.</p>
<p>I still haven&rsquo;t modified combinations for specific applications. The ones that come with Omarchy are already very useful, like SUPER A to open ChatGPT as if it were a separate app, or SUPER CTRL A to open Grok in a separate window. SUPER O to open Obsidian is also very useful for me. I recommend playing with these binds to make specific bindings and, again, reading the manual to learn everything else it already brings. But up to here it&rsquo;s enough to leave Hyprland the way I like to use it.</p>
<h2>8 - Timeshift, Snapshots and GRUB<span class="hx:absolute hx:-mt-20" id="8---timeshift-snapshots-and-grub"></span>
    <a href="#8---timeshift-snapshots-and-grub" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Remember I said to choose GRUB in archinstall? It&rsquo;s time now. The goal: let the system make periodic snapshots of itself, and in case you install some corrupted package or do things on your system that prevent it from booting, instead of having to resort to a USB drive to try to boot and diagnose the error, it&rsquo;s easier to just boot, choose a snapshot right before the destructive operation, and come back intact.</p>
<p>Before proceeding, an adjustment I think is important: my 4K monitor makes GRUB letters too small for me to read. I prefer bigger letters. Fortunately GRUB uses bitmap fonts so I can use any. I did the following:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo grub-mkfont -s 48 -o /boot/grub/fonts/caskaydia48.pf2 /usr/share/fonts/TTF/CaskaydiaMonoNerdFont-Regular.ttf</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This will generate a font in the format that GRUB can load. Choose any one you like; Omarchy already pre-installs several very good ones like JetBrains&rsquo;s. If size 48 is too big, lower it to 32, experiment until it&rsquo;s the way you like.</p>
<p>Then just edit <code>/etc/default/grub</code> to, at the end, have this line:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>GRUB_FONT=/boot/grub/fonts/caskaydia48.pf2</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And now just regenerate the bootloader:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo grub-mkconfig -o /boot/grub/grub.cfg</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Every time <code>yay -Syu</code> brings a kernel or driver update, GRUB will be regenerated with the same font. Look at how it turned out for me, I think it looks much better (this is a 4K monitor):</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250828_124009.jpg" alt="Grub Font"  loading="lazy" /></p>
<p>Now the entire reason for having chosen GRUB: allowing you to choose BTRFS snapshots to boot into the past, before some destructive operation, as shown in the photo above. For this we need the following:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>pacman -S timeshift grub-btrfs
yay -S timeshift-autosnap
systemctl enable --now grub-btrfs.service</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done. From now on, every time GRUB is rebuilt, it&rsquo;ll have a new option to choose snapshots. We just need to create those snapshots automatically, and for that we have the Timeshift app. Open it and follow its step by step. The important thing is to choose the BTRFS option (yes, you can use RSYNC if you&rsquo;re on ext4, but that occupies a lot of space, because it will literally keep making copies of your entire system&rsquo;s files. The beauty of BTRFS is that its snapshots don&rsquo;t duplicate files).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_15-37-52.png" alt="Timeshift Schedule"  loading="lazy" /></p>
<p>I leave it making snapshots and accumulating versions of the last hours, last days, last weeks, and months. If later on I remember <em>&ldquo;damn, there was that file I deleted last month but now I need it&rdquo;</em> just open Timeshift and browse a snapshot from last month. Like Mac folks do with Time Machine, but occupying almost no extra space.</p>
<p>Besides that, every package upgrade will generate a snapshot beforehand. That way, if by chance a corrupted package comes in or breaks some important config of yours, you can go back exactly to how it was before the update. And if it breaks catastrophically, where your Linux no longer boots, just go to the GRUB extra menu and boot from the previous snapshot, which worked. And everything comes back just like it was before.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_15-38-24.png" alt="Timeshift Snapshots"  loading="lazy" /></p>
<p>Nothing is more important for your system than having automatic snapshots that occupy almost no extra space. This alone makes BTRFS superior to any alternative.</p>
<p><strong>This does not replace external Backup!!</strong></p>
<p>This rollback and the ability to recover things easily is good for day-to-day accidents. But let&rsquo;s say your NVME breaks somehow, or your PC breaks somehow. That&rsquo;s what external backups are for (be it external HD, NAS, or Cloud). You want to be sure that, in a catastrophic situation, it&rsquo;s still possible to recover your files.</p>
<p>I have all the protection layers: local snapshots via BTRFS and Timeshift, backups done remotely to my NAS, and a backup of the most important parts of my NAS on <a href="https://aws.amazon.com/pt/s3/storage-classes/glacier/"target="_blank" rel="noopener">Amazon Glacier</a> which, unlike Amazon S3, is for keeping backups, where storage cost is ultra low but transfer cost is higher (S3 storage is more expensive but transfer is cheap, which is why it serves to serve website assets).</p>
<p>I like being prepared so that, in case my house catches fire, I don&rsquo;t lose anything important.</p>
<h2>9 - NFS on the NAS<span class="hx:absolute hx:-mt-20" id="9---nfs-on-the-nas"></span>
    <a href="#9---nfs-on-the-nas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Speaking of NAS, one thing I configured differently — since I primarily use Linux instead of Windows — was enabling the NFS server.</p>
<p>But beware that some NAS have a characteristic that can be annoying: your user on the NAS will have a UID and GID different from 1000!</p>
<p>When you create a user on any Linux, the default is to assign UID 1000 to the first user, 1001 to the second, and so on. But since on the Synology NAS the first user receives UID 1026, if I mount with NFS (which passes through UNIX permissions), I&rsquo;ll have authorization problems.</p>
<p>There are two solutions: try to change the UID on the NAS from 1026 to 1000. <a href="https://akitaonrails.com/en/2025/04/17/configuring-my-synology-nas-with-nfs-on-linux/"target="_blank" rel="noopener">I tried that</a> and I&rsquo;ll tell you up front it&rsquo;s a waste of time, you can end up breaking your NAS&rsquo;s configurations catastrophically.</p>
<p>It&rsquo;s much easier to change the user of your new local Linux to be 1026 and that&rsquo;s it. It&rsquo;s pretty easy.</p>
<p>First, we need to log out and leave Hyprland and go back to the SDDM login screen. Then we need to switch to another TTY with <strong>CTRL + ALT + F3</strong> (to go to tty3, for example). From there we have to log in as <strong>root</strong>.</p>
<p>Now we run: <code>systemctl isolate multi-user.target</code> to run in isolated recovery mode, where no other user has processes running. Since we&rsquo;re going to mess with the user, they can&rsquo;t be active.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>usermod -u 1026 akitaonrails
groupmod -g 1026 akitaonrails
chown -R 1026:1026 /home/akitaonrails</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>With the commands above we change from 1000 to 1026 and fix the permissions on the local files to reflect this change. Now yes, we can edit <code>/etc/fstab</code> to mount the shared directories on the NAS with NFS:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># NFS
192.168.0.x:/volume1/GIGACHAD /mnt/gigachad nfs4 _netdev,noauto,nofail,bg,x-systemd.automount,x-systemd.requires=network-online.target,x-systemd.after=network-online.target,x-systemd.idle-timeout=60s,noatime,nodiratime,async,rsize=65536,wsize=65536,actimeo=1  0 0
192.168.0.x:/volume1/TERACHAD /mnt/terachad nfs4 _netdev,noauto,nofail,bg,x-systemd.automount,x-systemd.requires=network-online.target,x-systemd.after=network-online.target,x-systemd.idle-timeout=60s,noatime,nodiratime,async,rsize=65536,wsize=65536,actimeo=1  0 0</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Don&rsquo;t forget to create the mount points:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mkdir /mnt/gigachad
mkdir /mnt/terachad</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done, just reboot and everything will work correctly. The file permissions on the NAS — which are UID 1026 and GID 1026 — will be accessible to the local user without problems.</p>
<h2>10 - Utilities<span class="hx:absolute hx:-mt-20" id="10---utilities"></span>
    <a href="#10---utilities" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here are the last small tips to keep everything in one place. The first is to replace the <code>ls</code> command with <code>eza</code> which offers a nicer face, with icons and everything, like this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_16-50-25.png" alt="eza"  loading="lazy" /></p>
<p>Just do <code>yay -S eza</code> and add this to your <code>.zshrc</code> or <code>.bashrc</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>alias ls=&#39;eza --icons --color=auto --group-directories-first&#39;
alias ll=&#39;eza -l --icons --color=auto --group-directories-first&#39;
alias la=&#39;eza -la --icons --color=auto --group-directories-first&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Second tip is to install <a href="https://atuin.sh/"target="_blank" rel="noopener">Atuin</a>. For anyone who deals with infra, this is extremely important: backup of all the command history you&rsquo;ve used in your terminal to this day.</p>
<p>Install with <code>yay -S atuin</code> and do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>atuin login
atuin sync</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Read the official site, but first you need to create an account and a secret encryption key — yes, you can run it locally on a server at your house, but their cloud option is pretty convenient and secure because it&rsquo;s all encrypted, so there&rsquo;s no problem if you upload passwords from your history.</p>
<p>Just put this in your <code>.zshrc</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>export ATUIN_NOBIND=true
eval &#34;$(atuin init zsh)&#34;
bindkey &#34;^R&#34; atuin-search

# incremental history search with arrow keys
bindkey &#34;^[[A&#34; history-beginning-search-backward
bindkey &#34;^[[B&#34; history-beginning-search-forward]]</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you&rsquo;re using ZSH, its autocomplete will work normally but, if you type CTRL+R, it will open the Atuin history. It will save all your commands in a SQLite and sync. That way you can sync several machines and servers you use day-to-day or, as in my case, recover the whole history on a new install.</p>
<p>And to make it better, we can configure it to auto-sync:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mkdir -p ~/.config/atuin
sed -i &#39;s/^#\?auto_sync.*/auto_sync = true/; s/^#\?sync_frequency.*/sync_frequency = &#34;30m&#34;/&#39; ~/.config/atuin/config.toml 2&gt;/dev/null || \
printf &#39;auto_sync = true\nsync_frequency = &#34;30m&#34;\n&#39; &gt;&gt; ~/.config/atuin/config.toml</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Third tip: since we have Docker already installed and configured, I like to use <a href="https://github.com/tbckr/sgpt"target="_blank" rel="noopener"><strong>SGPT</strong></a> on the command line for when I want to remember the syntax of some command I rarely use, instead of opening an app or browser. Just add this to my <code>.zshrc</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>export OPENROUTER_API_KEY=&#34;sk-or-v1-8b8...17&#34;
export OPENAI_API_KEY=&#34;sk-or-v1-db...f3&#34;
export OPENAI_API_BASE=&#34;https://openrouter.ai/api/v1&#34;

alias sgpt=&#39;docker run --rm -e OPENAI_API_BASE=${OPENAI_API_BASE} -e OPENAI_API_KEY=${OPENROUTER_API_KEY} ghcr.io/tbckr/sgpt:latest txt &#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I use <a href="https://openrouter.ai/"target="_blank" rel="noopener">OpenRouter</a> to have access to different commercial LLMs in a single API, but you can just use your OpenAI key. With this done, I&rsquo;d use it in the terminal similar to this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>~ ❯ sgpt &#34;what is the pacman command in Arch to find out if a particular file came from an installed package?&#34;
To find out if a particular file came from an installed package in Arch Linux, you can use the following pacman command:

``bash
pacman -Qo /path/to/file
``

Replace &#34;/path/to/file&#34; with the actual path to the file you want to check. This command will show the package which owns the file, or report that the file does not belong to any package if that is the case.</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you want, it supports sessions, so it&rsquo;ll remember the conversation on each new call. Read the project&rsquo;s Github.</p>
<p>Since I backed up my old <code>~/.config</code>, things like open tabs from my Brave browser opened normally in this new Omarchy install and I can keep doing my things exactly from the point I left off. I didn&rsquo;t lose anything. The same goes for all the other apps like emails that I back up locally via Thunderbird. I don&rsquo;t need to have it all downloaded again.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_15-59-34.png" alt="Audio Output"  loading="lazy" /></p>
<p>If, like me, you have several audio output devices, it&rsquo;s possible that right after finishing the install you&rsquo;ll notice that it seems there&rsquo;s no sound. But that&rsquo;s not a problem because it may just be that the output is pointing to the wrong device or the wrong profile. Use SUPER ALT SPACE to open the Omarchy menu, choose SETUP and AUDIO to open that program which is text mode (I like text mode programs).</p>
<p>In my case, I use a Topping D70 DAC to process my audio and the &ldquo;Default&rdquo; profile doesn&rsquo;t work but switching to &ldquo;Pro Audio&rdquo; worked. Also be careful that there&rsquo;s a global volume setting and individual volume control per program. Overall, thanks to Pipewire, everything should work normally.</p>
<p>I tested apps like Discord, Blender, Bambu Studio, VLC and everything worked perfectly. Only VLC needed codecs from a separate package:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S extra/vlc-plugin-ffmpeg</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Blender too, the best is to install from this package:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S blender-bin</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you use the normal &ldquo;blender&rdquo; package, some of its add-ons don&rsquo;t install right. I had this problem with MACHIN3Tools and MESHMachine, for example.</p>
<p>Speaking of Blender, it&rsquo;s an X11 app. Wayland runs X11 applications using an adapter layer called <strong>XWayland</strong>. I had several problems with menu and dialog box positioning, even adding <code>windowrule</code>. One thing that worked, I&rsquo;m not sure why, was installing Blender and Bambu Studio via Flatpak:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S flatpak
flatpak install org.blender.Blender
flatpak install com.bambulab.BambuStudio</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, if you&rsquo;re new to LazyVim, don&rsquo;t forget to run the <a href="https://www.lazyvim.org/extras"target="_blank" rel="noopener"><code>:LazyExtras</code></a> command to install extra plugins for your favorite languages, like LSP, Linter, syntax highlight, snippets, and more. Pure LazyVim is already complete but without support for many languages so as not to be unnecessarily heavy; you need to install them separately afterwards.</p>
<p>Also learn to use <a href="https://mise.jdx.dev/dev-tools/"target="_blank" rel="noopener"><strong>Mise-en-place</strong></a>. In the Omarchy menu there&rsquo;s an option to install support for various languages and it will use Mise, which is the correct way to manage your languages.</p>
<p>Mise is really easy, in general, from inside your project directory, just do something like:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise use ruby@3.4.3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>With this, only inside your project will Ruby 3.4.3 be available, but outside there can be another global version. Don&rsquo;t forget to activate it in your <code>.zshrc</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>eval &#34;$(mise activate zsh)&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Impressions and Conclusion<span class="hx:absolute hx:-mt-20" id="impressions-and-conclusion"></span>
    <a href="#impressions-and-conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Compared to my old Manjaro, there&rsquo;s a lot I no longer need to configure. For example, because of the amount of space Docker and LLMs needed, I had configured an iSCSI drive on my NAS just for that. But since I freed up 2 TB of local NVME, I no longer need to deal with that, I just use the new BTRFS sub-volumes I created above.</p>
<p>I also no longer need to configure QEMU/Libvirt because I no longer need to use Windows alongside Linux side by side. I kept the NVME with the Windows partitions and I can dual boot to it if I really need something. Overall I never need it, so it&rsquo;s one less complicated configuration.</p>
<p>I spent months using apps via Flatpak, with the aim of being more secure and isolated from the system. It&rsquo;s like running apps via Docker. But it&rsquo;s too annoying. Being isolated means it doesn&rsquo;t obey system themes, and in the end I&rsquo;m forced to keep opening permissions for the apps. And if it&rsquo;s going to keep opening them, it&rsquo;s easier to install natively via <code>yay</code> and everything works perfectly.</p>
<p>I think that completes my notes of everything I needed to do to leave Omarchy exactly the way I like. As I said repeatedly, what works for me doesn&rsquo;t mean it&rsquo;ll work for you. For that there&rsquo;s documentation like <a href="https://wiki.archlinux.org/title/Main_page"target="_blank" rel="noopener">ArchWiki</a> which is &ldquo;THE&rdquo; best place to learn everything about Linux. Use and abuse that documentation.</p>
<p>As you can see, there wasn&rsquo;t all that much I customized in Omarchy, which is why I like it: it already did 95% of the path for me, I just had to touch a few adjustments to leave it the way I need. And now without all the junk that piled up in my old Manjaro. I recommend everyone install Omarchy as a first Linux and learn to actually use it.</p>
]]></content:encoded><category>omarchy</category><category>linux</category><category>storage-and-backup</category></item></channel></rss>