Documentation Index
Fetch the complete documentation index at: https://mintlify.com/shawal-mbalire/dotfiles/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This dotfiles configuration follows a modular, 12-factor design philosophy, making it easy to extend, customize, and maintain. All components are designed to be portable, configurable via environment variables, and version-controlled.
Design Philosophy
12-Factor Configuration
The configuration implements 12-factor app principles:
# From ~/.config/fish/config.fish
# 1. Configuration via environment variables
set -q EDITOR; or set -gx EDITOR /usr/bin/nvim
set -q GTK_THEME; or set -gx GTK_THEME BreezeDark
# 2. Explicit dependency declarations
test -d $HOME/.local/bin; and fish_add_path $HOME/.local/bin
# 3. Portable across environments
type -q zoxide; and zoxide init fish | source
Key benefits:
- Config: All settings via environment variables
- Dependencies: Explicit path management
- Dev/Prod Parity: Same config across machines
- Portability: Works on any Linux distribution
Modular Structure
Hyprland Modules
Hyprland configuration is split into focused modules:
~/.config/hypr/
├── hyprland.conf # Main config + variables
└── modules/
├── autostart.conf # Startup applications
├── displays.conf # Monitor configuration
├── env.conf # Environment variables
├── input.conf # Keyboard/mouse settings
├── keybindings.conf # All keybindings
├── look.conf # Appearance/animations
└── windows.conf # Window rules
Loading modules:
# In hyprland.conf
source = modules/displays.conf
source = modules/autostart.conf
source = modules/keybindings.conf
# ... etc
Benefits of Modular Design
- Focused editing - Only touch relevant files
- Easy backup - Back up specific modules
- Shareable - Share keybindings without sharing everything
- Maintainable - Clear organization
- Conflict-free - Multiple people can edit different modules
Adding New Hyprland Modules
Step 1: Create Module File
# Create a new module for workspace rules
touch ~/.config/hypr/modules/workspaces.conf
Step 2: Add Configuration
# In modules/workspaces.conf
########################
### WORKSPACE RULES ###
########################
# Pin applications to specific workspaces
windowrulev2 = workspace 1, class:^(kitty)$
windowrulev2 = workspace 2, class:^(firefox)$
windowrulev2 = workspace 3, class:^(Code)$
# Make certain workspaces use gaps
workspace = 1, gapsout:10, gapsin:5
workspace = 2, gapsout:0, gapsin:0
Step 3: Source Module
# In hyprland.conf
source = modules/workspaces.conf
Step 4: Reload Configuration
# Reload Hyprland (or log out and back in)
hyprctl reload
Extending Fish Configuration
Adding Functions
Create a new function file:
# Fish functions are auto-loaded from this directory
vim ~/.config/fish/functions/my_function.fish
Example function:
# ~/.config/fish/functions/mkcd.fish
function mkcd --description "Create directory and cd into it"
mkdir -p $argv[1]
and cd $argv[1]
end
Usage:
mkcd ~/new/project/directory
Adding Abbreviations
Edit config.fish:
# In ~/.config/fish/config.fish, in the interactive section
if status is-interactive
# Your custom abbreviations
abbr --add --global gc 'git commit -m'
abbr --add --global gco 'git checkout'
abbr --add --global gp 'git push origin'
abbr --add --global k 'kubectl'
abbr --add --global d 'docker'
abbr --add --global dc 'docker-compose'
end
Reload Fish:
source ~/.config/fish/config.fish
Adding Environment Variables
12-factor way (with defaults):
# In config.fish
# Set only if not already defined
set -q MY_APP_HOME; or set -gx MY_APP_HOME "$HOME/myapp"
set -q MY_API_KEY; or set -gx MY_API_KEY "default-key"
# Add to PATH if directory exists
test -d $MY_APP_HOME/bin; and fish_add_path $MY_APP_HOME/bin
Override externally:
# In your shell or ~/.profile
export MY_API_KEY="production-key-123"
Adding new tool initialization:
# In config.fish, interactive section
if status is-interactive
# Check if tool exists before initializing
type -q starship; and starship init fish | source
type -q direnv; and direnv hook fish | source
type -q mise; and mise activate fish | source
end
Creating Custom Modules
Example: Custom Waybar Module
1. Create script:
# ~/.config/hypr/scripts/custom_module.sh
#!/bin/bash
# Output JSON for Waybar
echo '{"text": "📊 Data", "tooltip": "Custom module", "class": "custom"}'
chmod +x ~/.config/hypr/scripts/custom_module.sh
2. Add to Waybar config:
// In ~/.config/waybar/config
"modules-right": [
"custom/mymodule",
"clock"
],
"custom/mymodule": {
"exec": "~/.config/hypr/scripts/custom_module.sh",
"interval": 10,
"return-type": "json"
}
3. Style it:
/* In ~/.config/waybar/style.css */
#custom-mymodule {
color: @blue;
font-weight: bold;
}
Create script:
# ~/.config/rofi/scripts/system-menu.sh
#!/bin/bash
options="Shutdown\nReboot\nLogout\nSuspend"
chosen=$(echo -e "$options" | rofi -dmenu -p "System")
case $chosen in
Shutdown)
systemctl poweroff
;;
Reboot)
systemctl reboot
;;
Logout)
hyprctl dispatch exit
;;
Suspend)
systemctl suspend
;;
esac
Add keybinding:
# In modules/keybindings.conf
bind = $mainMod SHIFT, X, exec, ~/.config/rofi/scripts/system-menu.sh
Version Control Best Practices
What to Commit
DO commit:
- Configuration files
- Scripts and functions
- Theme files
- Documentation
- Font configurations
- Keybinding definitions
DON’T commit:
- Cache files (
.cache/)
- Secret keys or tokens
- Machine-specific absolute paths
- Large binary files
- IDE project files (unless dotfiles-related)
Using .gitignore
# In ~/.gitignore or specific config dirs
# Cache
.cache/
*.cache
# Secrets
.env
*_secret
*_token
credentials.json
# Machine-specific
.uuid
# History/State
fish_history
.fish_history
atuin-history.db
# Logs
*.log
Branching for Customization
# Create a personal branch for machine-specific changes
git checkout -b $(hostname)
# Main branch: portable defaults
git checkout main
# Merge portable changes
git checkout $(hostname)
git merge main
Machine-Specific Configuration
Using Hostname Detection
# In config.fish
set HOSTNAME (hostname)
switch $HOSTNAME
case 'work-laptop'
set -gx EDITOR code
fish_add_path /opt/work/bin
case 'home-desktop'
set -gx EDITOR nvim
fish_add_path $HOME/projects/bin
end
Conditional Module Loading
# In hyprland.conf
# Load laptop-specific config if on laptop
source = modules/displays-laptop.conf # Only if file exists
Environment-Based Theming
# In config.fish
if test "$ENVIRONMENT" = "work"
set -gx GTK_THEME Adwaita # Professional look
else
set -gx GTK_THEME BreezeDark # Personal preference
end
Sharing Your Customizations
# Share just your keybindings
cp ~/.config/hypr/modules/keybindings.conf ~/shared/
# Share Fish abbreviations
grep 'abbr --add' ~/.config/fish/config.fish > ~/shared/abbreviations.fish
Create Template Variables
# Instead of:
$terminal = kitty
# Document as:
$terminal = kitty # Edit: your preferred terminal
Document Dependencies
## Required Packages
- Waybar >= 0.9.0
- Hyprland >= 0.40.0
- Fish shell >= 3.0
- Nerd Font (any variant)
Testing Changes Safely
Backup Before Editing
# Backup entire config
cp -r ~/.config/hypr ~/.config/hypr.backup
# Backup specific file
cp ~/.config/fish/config.fish ~/.config/fish/config.fish.bak
Test in Isolation
# Test Fish config
fish --no-config # Start clean shell
source ~/test-config.fish # Test specific file
# Test Hyprland module
# Create test config that sources only what you need
Incremental Changes
- Change one thing at a time
- Test immediately
- Commit if it works
- Repeat
git add ~/.config/hypr/modules/keybindings.conf
git commit -m "Add custom keybinding for screenshot tool"
Advanced Patterns
Dynamic Configuration Generation
# Generate config based on system
function generate_hypr_config
set monitors (hyprctl monitors | grep Monitor | awk '{print $2}')
for monitor in $monitors
echo "monitor = $monitor,preferred,auto,1" >> monitors.conf
end
end
Configuration Validation
# Validate before applying
function validate_fish_config
fish -n ~/.config/fish/config.fish
and echo "✓ Config is valid"
or echo "✗ Syntax error in config"
end
Auto-Sync Across Machines
# Add to Fish config or cron
function sync_dotfiles
cd ~/dotfiles
git pull origin main
git push origin (hostname)
end
Getting Help
Debugging Your Extensions
Fish:
fish --debug # Verbose debug output
fish --private # Isolated test session
Hyprland:
hyprctl reload # Reload config
hyprctl logs # Check error logs
Waybar:
killall waybar
waybar --log-level debug # Verbose output
Useful Resources
Quick Start Checklist
To extend this configuration:
Remember: This configuration is designed to be modified. Don’t be afraid to experiment!