A Deep Dive Into My Dotfiles: Crafting a CLI-First Workflow
published:
In my last post, I mentioned that a primary reason for my blogging hiatus was a deep, obsessive dive into crafting my perfect development environment. Today, I want to take you on a guided tour of that project: my personal dotfiles repository.
This repository is more than just a collection of config files; it's the culmination of hundreds of hours spent refining a workflow that is fast, keyboard-driven, and tailored to my needs as a developer who lives on the command line.
The Philosophy: Automation and Control
The core philosophy behind my dotfiles is simple: automate everything possible
while maintaining full control over my environment. I wanted a setup that I
could replicate on any machine with a single command, ensuring consistency and
saving hours of manual configuration. This is achieved through a combination of
custom shell scripts (.deps for installing dependencies, .update for setup)
and GNU Stow for elegantly managing symlinks.
A Guided Tour of Key Components
Let's walk through some of the most important parts of my setup.
The Operating System: Arch Linux
The foundation of my setup is Arch Linux. I embrace its "do-it-yourself" ethos, as it forces a deeper understanding of the system and allows for a truly minimalist installation where I control every package. This lean and mean base is the perfect canvas for a custom environment.
My Hardware: Laptops and Desktops
My dotfiles are designed to be portable, and I use them across two main
machines. For on-the-go work, I use a ThinkPad X13 Gen 2i. It's a fantastic,
reliable laptop that's great for travel, and surprisingly power-efficient. My
Hyprland + Neovim workflow, even when interacting with tools like gemini-cli,
typically consumes a mere 3-5 watts. With its 54Wh battery, this translates to
excellent real-world endurance; I managed to code my entire migration from
Jekyll to Zola and write all my new articles on a single charge. This kind of
battery performance is a testament to the efficiency of a well-tuned Linux
system with a minimalist setup.
My main desktop PC, however, is where the real power is. It's an all-AMD build (X870E Nova WiFi motherboard), featuring a Ryzen 9 9950X3D CPU and a Radeon RX 7900 XTX GPU, with 64GB of RAM. I specifically chose this all-AMD setup for its excellent open-source driver support on Linux. There are no proprietary drivers to wrestle with, which makes for a stable, hassle-free experience, especially when running a cutting-edge setup like mine.
The Desktop: Hyprland on Wayland
For my graphical environment, I've fully committed to the Wayland ecosystem with Hyprland as my window manager. As a dynamic tiling Wayland compositor, it's incredibly fluid and highly customizable. My configuration is modular, sourcing separate files for monitors and workspaces to keep things organized.
At launch, a suite of exec-once commands brings the environment to life,
starting essentials like hyprpaper for wallpaper, waybar for my status bar,
swaync for notifications, and hypridle for idle management. I use the
dwindle layout, which provides a predictable and efficient tiling structure.
The entire setup is designed to be keyboard-driven, minimizing the need to ever
touch a mouse. I have a set of custom keybindings using $mod (the Super key)
for everything from launching applications to managing windows:
# Launch a browser
bind = $mod, b, exec, vieb
# Launch a terminal
bind = $mod, c, exec, alacritty
# Kill active window
bind = $mod, q, killactive,
# Toggle floating window
bind = $mod, v, togglefloating,
# Move focus with mod + hjkl keys
bind = $mod, h, movefocus, l
bind = $mod, l, movefocus, r
bind = $mod, k, movefocus, u
bind = $mod, j, movefocus, d
# Switch workspaces with mod + [0-9]
bind = $mod, 1, workspace, 1
bind = $mod, 2, workspace, 2
bind = $mod, 3, workspace, 3
This level of customization is what makes Hyprland so powerful. It allows me to
craft an environment that is a true extension of my workflow, where every action
is just a few keystrokes away. The theme is a simple adw-gtk3-dark with
Papirus icons, keeping things clean and focused.
The Editor: Neovim on a LazyVim Base
As an avid vim user for years, the natural evolution for me was
Neovim. My configuration, which you can find in the repo,
has been fully migrated to Lua. The foundation of my setup is
LazyVim, a fantastic Neovim distribution that
provides a sensible, feature-rich baseline with a focus on lazy-loading plugins
for optimal performance.
On top of this solid base, I layer my own customizations. A great example of
this is how I enable specific features and language support via my
lazyvim.json. This allows me to precisely tailor the editor to the languages
and tools I use most frequently:
{
"extras": [
"lazyvim.plugins.extras.coding.luasnip",
"lazyvim.plugins.extras.coding.yanky",
"lazyvim.plugins.extras.editor.telescope",
"lazyvim.plugins.extras.formatting.prettier",
"lazyvim.plugins.extras.lang.clangd",
"lazyvim.plugins.extras.lang.docker",
"lazyvim.plugins.extras.lang.git",
"lazyvim.plugins.extras.lang.json",
"lazyvim.plugins.extras.lang.markdown",
"lazyvim.plugins.extras.lang.php",
"lazyvim.plugins.extras.lang.python",
"lazyvim.plugins.extras.lang.rust",
"lazyvim.plugins.extras.lang.sql",
"lazyvim.plugins.extras.lang.vue",
"lazyvim.plugins.extras.lang.yaml",
"lazyvim.plugins.extras.linting.eslint"
]
}
This approach gives me the best of both worlds: a powerful, pre-configured setup from LazyVim that's easy to extend and personalize for my specific development needs, all while keeping the configuration clean and manageable.
The Shell and CLI Tools
The command line is my home. My shell of choice is Fish, prized for its smart autocompletions and user-friendly scripting. My setup is built around a suite of aliases and functions that accelerate common tasks, removing friction from my daily workflow. Every tool is chosen for its efficiency and command-line interface.
For example, I have a set of aliases to make Git interactions faster and more
fun. Instead of typing out a full commit command, I can just use g or gg,
which also pipes in a random quote from my quoty tool:
# Alias for quick and dirty git commit
function g
git commit -am "$(quoty)"
git pull --no-edit
git push
end
function gg
git add . && git commit -m "$(quoty)"
git pull --no-edit
git push
end
I also replace common commands with more modern, powerful alternatives. For
instance, ls is replaced with eza, a more feature-rich file lister:
# Replace default ls command with eza
function ls
eza --group-directories-first $argv
end
And of course, no terminal-centric user would be complete without ensuring every possible editor command opens their one true editor:
# I want v to open vi and vi to open vim
function n; nvim $argv; end
function v; nvim $argv; end
function vi; nvim $argv; end
# ...and so on
These small customizations, when combined, create a development environment that is not only powerful but also deeply personal and efficient. This CLI-first approach is a recurring theme throughout the repository.
Management with GNU Stow
Instead of having symlinks scattered everywhere, I use GNU Stow to manage my
dotfiles. This allows me to keep all my configurations neatly organized in a
version-controlled directory, and then "stow" them into their correct locations
in my home directory. It makes managing and updating the configurations
incredibly clean and simple.
Why This Matters
Investing time in your dotfiles is an investment in yourself. A well-crafted development environment reduces friction, automates mundane tasks, and ultimately makes the process of creating software more enjoyable and efficient. It's the digital equivalent of a perfectly organized workshop.
Final Thoughts
This dotfiles project was the creative outlet I needed during my break from writing. It allowed me to focus on building and refining the very tools I use to create. I encourage you to explore my dotfiles repository on GitHub. Feel free to take inspiration, fork it, and start your own journey toward crafting your perfect development environment.