There is a particular kind of frustration that every Linux power user knows intimately, and it arrives at the moment you realise you have to reinstall. You have spent months, perhaps years, getting your desktop exactly the way you like it. Your window manager rules are perfect. Your bar widgets are in the right order. Your keybindings are muscle memory. Your theme matches your wallpaper matches your terminal font matches your mood. And then something happens. Maybe the hard drive fails. Maybe you want to set up a second machine. Maybe you try a different distribution and then come crawling back. Whatever the cause, you are now staring at a fresh install and the prospect of doing it all again, from memory, and you know you will forget half of it.
I run Omarchy, which is a rather wonderful opinionated Arch Linux distribution built around Hyprland. It gives you a beautiful, functional desktop out of the box. But of course, being a Linux user, I could not leave it alone. I swapped packages in and out, added third-party shell plugins, customised my keybindings, built a hybrid-graphics power management setup for my Dell Precision, installed a Hyprland overview plugin called GloView, and generally fiddled with everything until the desktop was mine. The problem was that all of this lived in my head and in scattered config files across my home directory. If I lost the machine, I would lose the knowledge of how to put it back together.
So I built something to fix this, and I want to tell you about it because I think the approach is worth stealing. It is called omarchy-setup, it lives on GitHub at https://github.com/mightywomble/omarchy_setup, and it does something I have wanted for years: it lets me rebuild my entire desktop configuration from a single JSON file, through either a graphical wizard or a command-line script, on any fresh Omarchy machine.
Let me explain what it actually does, because the devil is in the detail and the detail is rather fun.
At its heart, omarchy-setup is a snapshot of one machine’s customisations, stored in a git repository, combined with a script called apply.sh that can replay those customisations on any other machine. The snapshot includes config files for Hyprland, custom themes, dotfiles like .bashrc and git config and starship and btop, a list of third-party shell plugins with their git URLs, a list of packages to install from the official Arch repos, a list of packages to install from the AUR, and a list of default Omarchy packages that I removed because I did not want them. Everything is version-controlled, everything is text, and everything can be reapplied with a single command.
The script organises all of this into ten categories that always run in a fixed order, because some of them depend on others. The packages category removes the default packages I do not want. The install category installs the packages I do want, from both official repos and the AUR, and then does clever things like adding my user to the docker group and enabling the docker, tailscaled, and displaylink services automatically. The webapps category removes the web application launcher entries that Omarchy ships with, because I prefer native apps. The plugins category installs my fifteen chosen shell plugins from their git sources. The theme category installs and activates my custom themes. The gloview category installs the GloView Hyprland overview plugin from the AUR. The hyprland and keybindings categories apply my window manager config and then reload Hyprland live. The dotfiles category copies in my shell and tool configurations. The barconfig category applies my bar layout and restarts the shell. Everything runs in that order, every time, because the bar config references plugin IDs that must already be installed, and the keybindings reference a confirm-close script that must already be on disk.
Now, you could just run all of that with a single command, apply.sh –all, and it would do everything. But where is the fun in that? The interesting part is the flexibility. You can run apply.sh –only plugins,theme to apply just those two categories. You can run apply.sh –cli to get an interactive yes-or-no prompt for each category. You can run apply.sh –list to see what the categories are. And you can run apply.sh with no arguments at all, and if you are in a graphical session, something rather special happens.
It launches a wizard. A proper, graphical, GTK4 and libadwaita wizard that reads your active Omarchy theme colours at runtime and styles itself to match, so it looks like it belongs on your desktop rather than like a generic application that wandered in from another operating system. This wizard is the part I am most pleased with, and it is a five-page journey through your configuration.

The first page is called My Defaults, and it presents all ten categories as toggle switches, pre-enabled, each with a description of what it does. This is the opinionated setup, your pre-configured defaults captured from your machine. You can toggle categories on or off, select all or none, and beneath the category list there is a features card with two additional toggles. One controls the SUPER+W confirm-before-close behaviour, where a zenity dialog asks you before closing the focused window, and the other controls whether Ollama and GPU models should be installed. These are features that are bundled inside categories but not obvious from the category name alone, so they get their own toggles so you can opt in or out explicitly.
The second page is the Plugins page, and this is where things get properly useful. It merges the full Omarchy plugin catalogue with your currently installed plugin state, presenting every available shell plugin in a searchable list. Each plugin shows its name, its id, its kind badges showing whether it is a bar widget or an overlay or a service, a first-party tag if it is an official Omarchy plugin, and an enable toggle. The fifteen plugins from your plugins.txt defaults are pinned to the top so you can see what you already have, and below them you can search the entire catalogue, toggle plugins on and off, and even add a new plugin by pasting in a git URL. The search filters in real time as you type, and because it is reading from the live plugin catalogue, you are always seeing what is actually available, not a stale snapshot.
The third page is Packages, and it is the one I spent the most time getting right. At the top, it lists your opinionated package defaults from the three text files, grouped and badged. Official packages from packages-added.txt get a green pacman badge. AUR packages from packages-aur.txt get a purple aur badge. Removed packages from packages-removed.txt get a red removed badge. Each package has its own toggle switch, defaulting to on, so if there is a package you do not actually want on this particular machine, you just toggle it off and it will be skipped. Beneath your configured packages, there is a search box where you can search the official Arch repositories and the AUR simultaneously, with an Include AUR toggle so you can choose whether to see community packages. The search results show repo badges, with AUR packages highlighted in the accent colour, and each result has an Add button so you can throw extra packages into your configuration. The search runs in a background thread with a three-second timeout, so if the AUR RPC API is being slow, a pulsing progress bar appears to let you know something is happening rather than the window freezing and you wondering if the application has crashed. I learned that lesson the hard way.

The fourth page is GPU Models, and this is the page that surprised me with how well it turned out. If you have an NVIDIA GPU, it detects your card and VRAM via nvidia-smi and displays a banner telling you exactly how much video memory you have and what size of language model will fit. Then you can search the Ollama model library, and each result shows the model name, available parameter sizes as badges, capability badges like vision or tools or thinking, the description, and the download count. Crucially, each model gets a VRAM compatibility badge. A green badge that says it fits your VRAM, a yellow badge that says it is tight and might need partial CPU offload, or a red badge that says it is too large. This means you can browse models and immediately see which ones will actually run well on your hardware without trial and error. You select the ones you want with a Pull button, and they get added to your configuration.
The fifth and final page is Review and Save. It shows a summary of everything you have selected, organised into sections. Your categories, your feature toggles, your ollama models, your plugin changes showing the delta between what is currently enabled and what you want enabled, your extra packages from the search, and your configured packages with counts showing how many out of the total will be installed or removed, plus a list of anything you toggled off. At the bottom of the screen, in the navigation bar, there are three buttons. Back, which takes you to the previous page. Save config, which opens a file dialog and writes a JSON file to disk. And Apply now, which starts life as a red, disabled button, because you cannot apply a configuration that does not exist yet. The moment you save a config file, the Apply button turns green and becomes clickable, and pressing it launches a terminal window that runs apply.sh with your saved config file, so you can watch the installation happen in real time.

Now, the JSON file is the really clever part, because it is what makes the whole thing reproducible across machines. When you save a configuration, it writes a JSON file that looks something like this. It has a categories array listing which categories to run. It has a plugins object with enable and disable arrays listing plugin IDs to turn on or off, and an add array for new plugins with their git URLs. It has a packages object with pacman and aur arrays for extra packages you found through search. It has a configured_packages object listing which packages from your text files should actually be processed, so anything you toggled off is simply absent from the list. And it has a features object with confirm_close and ollama_install booleans, plus an ollama_models array listing the model tags to pull.
The beauty of this is that the JSON file is your configuration in portable form. You can commit it to a git repository, copy it to a USB stick, put it in a gist, send it to yourself in an email, whatever you like. Then on a fresh machine, you clone the omarchy-setup repository, drop your JSON file somewhere, and run apply.sh –myconfig followed by the path to your file. The script validates the JSON, extracts the categories, runs them in the correct fixed order so dependencies are respected, applies the plugin deltas via the omarchy plugin commands, installs the extra packages via pacman and yay, honours the configured_packages filtering so toggled-off packages are skipped, respects the feature toggles so confirm-close and ollama can be enabled or disabled, and pulls the ollama models you selected. Everything is idempotent, so running it twice does not break anything, and every file write backs up the existing destination first with a timestamp, so nothing is ever silently overwritten.
Example JSON output
{
"categories": [
"packages",
"install",
"webapps",
"plugins",
"theme",
"gloview",
"hyprland",
"keybindings",
"dotfiles",
"barconfig",
"gpu"
],
"plugins": {
"enable": [],
"disable": [],
"add": []
},
"packages": {
"pacman": [],
"aur": []
},
"configured_packages": {
"added": [
"ansible",
"discord",
"docker",
"helm",
"kdeconnect",
"kubectl",
"nextcloud-client",
"tailscale",
"terraform",
"tokodon",
"zenity"
],
"aur": [
"displaylink",
"element-desktop",
"microsoft-edge-stable-bin",
"onlyoffice-bin",
"opencode-bin",
"stirling-pdf-desktop-bin",
"termix-bin",
"vacuumtube-bin",
"visual-studio-code-bin",
"ytmdesktop-bin",
"zen-browser-bin"
],
"removed": [
"chromium",
"libreoffice-fresh",
"localsend",
"moonlight-qt",
"nvim",
"obs-studio",
"obsidian",
"omacalc",
"omacut",
"omarchy-nvim",
"omawrite",
"pinta",
"xournalpp"
]
},
"features": {
"confirm_close": true,
"ollama_install": true
},
"ollama_models": [
"qwen2.5:3b"
]
}
This is the bit that I think is worth stealing even if you do not use Omarchy. The idea of capturing your post-install customisations as text files in a git repo, wrapping them in a script that can replay them, and then generating a portable JSON config that encodes your choices so they can be replayed on another machine, is broadly applicable. You could do this for any Linux distribution. The categories would be different, the package manager would be different, the config locations would be different, but the architecture is the same. Snapshot your customisations, script their reapplication, generate a portable config, replay it elsewhere.
There is a parallel here that I want to draw, because it helped me think about what this tool is doing. Garuda Linux, which is another Arch-based distribution with a gaming and enthusiast focus, ships with a rather nice post-install assistant. When you first boot Garuda, it presents you with a welcome screen that lets you install additional software, configure your system, and generally customise things through a guided interface. It is friendly, it is approachable, and it solves the same problem of what happens after the installer finishes and you are staring at a fresh desktop wondering what to do next. The difference is that Garuda’s assistant is primarily a first-run experience. It helps you set up a machine once. What I wanted, and what omarchy-setup does, is to capture the result of that setup so it can be replayed. It is the difference between a recipe and a photograph of the finished dish. Garuda’s assistant is the recipe. Omarchy-setup is the photograph, and the JSON file is the negative from which you can print more copies.
I should be honest about how this was built, because I think it matters. This was vibe coded. I built it conversationally with an AI agent, describing what I wanted in natural language and letting the agent write the code while I directed the architecture, tested the results, and refined the behaviour. I did not sit down with a text editor and write the Python and bash from scratch. I sat down with a conversation and described the thing I wanted to exist, and then we built it together, iteratively, over the course of an afternoon.
I want to explain why I think that is a good thing, because there is a lot of anxiety about AI-assisted coding and I think some of it is misplaced. The code that resulted from this process is about nineteen hundred lines of Python and around four hundred and fifty lines of bash. It is not trivial. It does real work. It handles background threading for async searches, it parses HTML from the Ollama website with regex because there is no public API, it reads theme colours from TOML files and generates CSS at runtime, it validates JSON with jq, it manages temporary files and traps for cleanup. The AI did not hallucinate this from nothing. I described each component, I reviewed what it produced, I tested it by running the wizard and clicking through the pages, I found bugs like the GLib critical error from passing arguments incorrectly to GApplication, I found the TypeError where a signal handler signature did not match, I found the package search hanging for eighty-three seconds because yay -Sa is catastrophically slow and replaced it with a direct call to the AUR JSON RPC API that takes two hundred milliseconds. Each of those was a real debugging session where the AI and I worked together to find and fix the problem.
The reason this is good is that it let me build something I would never have built otherwise. I am not a professional Python developer. I could have written the bash script on my own, eventually, with some swearing. I would not have written a GTK4 graphical wizard with libadwaita styling and async search and VRAM compatibility calculations. That would have been weeks of learning APIs and reading documentation and making mistakes, and I would have given up or settled for a simpler tool. Instead, I got to focus on the design and the user experience and the architecture, which are the parts I actually care about, while the agent handled the boilerplate and the API wrangling. The result is a more ambitious tool than I would have built alone, and it works, and I understand it because I was in the loop for every decision.
Now, how could it be better? I want to be honest about that too. The testing is manual right now. There is no automated test suite that verifies the wizard builds, that the JSON schema is valid, that the apply.sh –myconfig path handles edge cases. That should exist. The HTML parsing for the Ollama model search is fragile and will break if Ollama changes their website structure, and a proper API or a cached model list would be more robust. The wizard is Omarchy-specific in its plugin and theme handling, and making it more distribution-agnostic would let other people adapt it. There is no automated collect script that snapshots your current customisations back into the repository, so updating it when you change something is manual. The system-level power management tweaks, the NVIDIA RTD3 configuration, the udev rules for runtime power management, the kernel command line parameters for iGPU power saving, those live in system files outside the home directory and are not captured by the snapshot, so they need to be reapplied manually on a fresh machine. Packaging this as a proper Arch package rather than a git clone would be nicer. All of these are real improvements that would make it more robust and more broadly useful, and they are the kind of thing where community contribution could help enormously, which is part of why it is on GitHub.

If you use Omarchy and you want to try it, you can clone it from https://github.com/mightywomble/omarchy_setup. Run apply.sh with no arguments to launch the wizard, or apply.sh –cli if you are over SSH, or apply.sh –all if you just want everything. Save a config file, stick it in your dotfiles repository, and the next time you install Omarchy on a new machine, you are one command away from having your desktop back. If you do not use Omarchy but you like the architecture, I think the pattern is worth borrowing. Snapshot your config, script the replay, generate a portable JSON, and never set up a machine from scratch again.
The code is open, it is on GitHub, and it is vibe coded and proud of it. Have at it.
A Retrospective, a Few Weeks On
I have been living with this tool for a little while now, long enough to have used it in anger rather than just in the warm glow of having built it, and I want to share what that has taught me because it is not entirely what I expected.
During that time i’ve been distro hopping a lot, its a thing I do when i find a Linux i like, i need to double check the other thing isn’t better..Its a process
The first thing that surprised me is how quickly the wizard became the way I interact with my own configuration, not just a nice-to-have graphical front end. I assumed I would use the command-line flags for serious work and the wizard for showing off. In practice, the wizard is where I go when I want to think about my setup, because thinking about your setup is fundamentally a visual and tactile act. You want to see the toggles, flip them, watch the summary update, feel the shape of your configuration change. A JSON file is a splendid artefact but a dreadful thinking tool. The wizard lets you reason about the machine you want to build and then hands you the JSON at the end, which is the right way round. I had the architecture backwards in my head before I used it.
The second thing is that the JSON file has become a dotfile in its own right, and that shift in mental category matters more than I anticipated. I keep my omarchy-config.json in my dotfiles repository alongside my .bashrc and my git config and my starship prompt, and it gets the same treatment, the same version history, the same careful commits when I change it. It is no longer a thing the wizard produces for convenience. It is a source of truth. When I rebuilt my laptop last week, I did not run the wizard at all. I cloned the repo, ran apply.sh –myconfig with my committed JSON, went to make a cup of tea, and came back to a desktop that was mine. That is the whole point, and it works, and the fact that it works on the first try still feels slightly miraculous.

The third thing is about the vibe coding, and it is a reflection I want to share honestly. What I have noticed, living with code that I wrote conversationally with an AI, is that I understand it differently than code I wrote by hand. When I write a function myself, I understand it by remembering the struggle of writing it, the false starts, the syntax error I could not find for an hour. When the agent writes the function and I review it, I understand it by reading it and explaining it back to myself, which is a different and in some ways deeper kind of understanding, because I am engaging with what the code does rather than the pain of producing it. I know what every part of the wizard does. I could not necessarily reproduce it from a blank screen without the agent, but I can modify it, debug it, extend it, and reason about its behaviour, and for a tool that I maintain rather than teach, that is the understanding that actually matters. The worry that vibe coding produces code you do not understand is, I think, a confusion between understanding by authorship and understanding by stewardship. This tool is mine by stewardship, and that is enough.
There is a fourth thing, and it is the one I did not expect at all. Building this tool made me configure my machine more, not less. I had a set of customisations that were frozen in amber because changing them meant remembering to update the snapshot, and the snapshot was manual, and manual things do not get done. Once the wizard existed, once toggling a plugin or adding a package was a matter of flipping a switch and saving a config, I started experimenting again. I tried new plugins. I swapped my browser. I added Ollama models and then removed some and tried others. The tool that was meant to freeze my configuration in a reproducible state actually made my configuration more alive, because it lowered the cost of change. That is the real lesson, I think. The reason we do not customise our machines more aggressively is not that we do not care, it is that the cost of capturing and reproducing the change is too high. Bring that cost down, and the fiddling returns, and the fiddling is the fun part.
I do not know whether omarchy-setup will be useful to anyone else. It is specific to my distribution and my hardware and my taste, and that is rather the point. But the pattern, the idea that your post-install configuration should be a portable, version-controlled, replayable artefact, and that you should be able to produce and modify it through a pleasant interface rather than by editing text files and hoping you remembered everything, that pattern is general. I hope someone steals it. I hope someone steals it and makes it better and makes it work for their distribution and their desktop and their weird little setup that nobody else has. That would be the best possible outcome, and it is why the code is open and the repository is public.
Build the thing. Ship the thing. Let me know if you do.