Comprehensive, modular, and idempotent dotfiles system for Linux Mint with i3 window manager.
This repository contains my complete Linux Mint system configuration, including:
- 52+ modular installation scripts for automated setup
- i3 window manager configuration with custom keybindings and scripts
- Neovim setup with LazyVim and custom plugins
- Development environment (Git, Node.js, Rust, Python, VS Code, tmux)
- Productivity tools (Obsidian, Todoist, Teams, Sunsama, etc.)
- Web applications as PWAs using custom webapp script
- All dotfiles managed with GNU Stow for easy deployment
- User services for persistent background apps via
systemd --user
Inspired by the "You installed Omarchy, Now What?" approach, adapted for Linux Mint:
- Idempotent scripts - Safe to run multiple times
- Modular design - Install only what you need
- Latest packages - Uses PPAs, Flatpak, and official repos (not Ubuntu's outdated packages)
- Portable - One repository, easy to deploy on any Linux Mint system
# Clone the repository
git clone https://github.com/shanekunz/Linux-IroncladMint.git ~/dotfiles
cd ~/dotfiles
# Run the bootstrap script (installs core packages + deploys dotfiles)
chmod +x bootstrap.sh
./bootstrap.shThe bootstrap script will:
- Install essential prerequisites (git, stow, flatpak)
- Install core packages (i3, neovim, terminal tools, dev tools)
- Install common applications (browsers, discord, obsidian, vscode)
- Deploy all dotfiles using GNU Stow
- Backup any existing configs to
~/.config-backup-TIMESTAMP/
# Install individual packages as needed
./scripts/install-PACKAGE.sh
# Example: Install only neovim and i3
./scripts/install-neovim.sh
./scripts/install-i3.sh
# Deploy dotfiles with stow (from the dotfiles directory)
cd ~/dotfiles
./scripts/stow-dotfiles.sh # Recommended: deploy managed packages with backups
stow nvim # Just neovim config
stow i3 # Just i3 config- GNU Stow (dotfiles management)
- Build essentials, curl, wget, git
- Caskaydia Cove Nerd Font
- i3-wm, i3blocks, i3lock
- rofi (application launcher)
- picom (compositor)
- nitrogen (wallpaper manager)
- flameshot (screenshots)
- dunst (notifications)
- Network manager applet
- Blueman (Bluetooth)
- feh, arandr
- Git (latest via PPA)
- GitHub CLI
- Lazygit (TUI)
- Neovim (latest via PPA)
- Visual Studio Code
- Ghostty terminal
- tmux
- Starship prompt
- eza, bat, zoxide, btop
- mise - Universal version manager (Node.js, .NET, Rust, Python, Go, and 100+ tools)
- OpenCode
- Claude CLI
- Firefox (Mozilla PPA)
- Chromium (snap)
- Microsoft Edge
- Discord (Flatpak)
- Zoom
- Signal (official repo)
- Whatsie (WhatsApp client, Flatpak)
- Teams for Linux (Flatpak)
- LocalSend (Flatpak)
- Telegram (Flatpak)
- Obsidian (Flatpak)
- Todoist (Flatpak)
- Sunsama (AppImage)
- Emote (emoji picker)
- OBS Studio (latest PPA)
- Steam
- RetroArch
- Sunshine (game streaming)
- accountable2you (snap)
- glow (markdown renderer)
- Flatpak + Flathub
- Kanata (keyboard remapper with Enthium v13 layout)
- CopyQ (clipboard manager)
- Home Assistant (Docker)
- Matter Server (Docker) - for Apple Home / Matter device integration
- Obsbot Tiny 2 controller (Rust)
Created using custom webapp script (via install-webapps.sh):
- ChatGPT
- Claude
- Gmail
- Outlook
- Linear
- Jira
- Confluence
- Limitless
- Apple Music
- Brain.fm
~/dotfiles/
├── bash/ # .bashrc, .profile (sources ~/.secrets)
├── git/ # .gitconfig
├── x11/ # .Xresources, .xprofile (HiDPI scaling)
├── i3/.config/i3/ # Complete i3 setup + keybinds.md
├── nvim/.config/nvim/ # LazyVim configuration
├── ghostty/.config/ghostty/
├── starship/.config/starship.toml
├── tmux/.tmux.conf
├── rofi/.config/rofi/
├── picom/.config/picom/
├── i3blocks/.config/i3blocks/
├── lazygit/.config/lazygit/
├── flameshot/.config/flameshot/
├── kanata/.config/kanata/ # Enthium v13 keyboard layout
├── kanata/docs/ # Kanata layer diagrams + KLE JSON sources
├── nitrogen/.config/nitrogen/
├── copyq/.config/copyq/ # Clipboard manager commands
├── environment.d/ # HiDPI env vars (GDK_SCALE, QT_SCALE_FACTOR)
├── systemd-user/ # User-level systemd services
├── gh/.config/gh/ # GitHub CLI preferences
├── mise/.config/mise/ # Tool version manager config
├── claude/.claude/ # Claude settings, statusline, commands, agents, skills
├── opencode-common/.config/opencode/ # Shared OpenCode commands, agents, themes, tui
├── opencode-linux/.config/opencode/ # Linux-specific OpenCode config
├── opencode-wsl/.config/opencode/ # WSL-specific OpenCode config and skills
├── bin/.local/bin/ # webapp script, lazygit, sunsama
├── home-scripts/ # .secrets.template for API keys
├── obsbot/.local/ # Obsbot source and binary
└── scripts/ # 55+ installation scripts
This repo now carries your personal Claude/OpenCode setup plus the shared AI workflow assets you use day to day.
- Claude keeps personal settings in
claude/.claude/settings.jsonandclaude/.claude/statusline.sh. - OpenCode keeps shared UI config in
opencode-common/.config/opencode/themes/andtui.json. - Shared OpenCode slash commands and agents live in
opencode-common/.config/opencode/. - OpenCode host-specific MCP defaults and skills live in
opencode-linux/.config/opencode/andopencode-wsl/.config/opencode/.
This keeps your machine self-contained in one dotfiles repo while preserving the reusable AI tooling you were previously sourcing from a separate repository.
The repo can also manage long-running background apps with systemd --user.
This repo includes systemd-user/.config/systemd/user/opencode-telegram-group-topics-bot.service plus the helper command ~/.local/bin/opencode-telegram-group-topics-bot-service.
Why this setup:
- Starts automatically when your user session starts
- Stops cleanly with one command when you want to run the bot manually for debugging
- Uses the same
.envthat already lives in your bot repo
One-time setup:
cd ~/projects/opencode-telegram-group-topics-bot
npm install
npm run build
cd ~/dotfiles
./scripts/stow-dotfiles.sh
systemctl --user daemon-reload
systemctl --user enable --now opencode-telegram-group-topics-bot.serviceUseful commands:
opencode-telegram-group-topics-bot-service status
opencode-telegram-group-topics-bot-service logs
opencode-telegram-group-topics-bot-service stop
opencode-telegram-group-topics-bot-service start
opencode-telegram-group-topics-bot-service restartLocal development handoff:
opencode-telegram-group-topics-bot-service stop
cd ~/projects/opencode-telegram-group-topics-bot
npm run devThat uses the same repo-local config as the service. When you are done testing, stop your manual process and start the service again:
opencode-telegram-group-topics-bot-service startOptional: if you want it to keep running even before you log into the desktop session, enable user lingering:
sudo loginctl enable-linger "$USER"Kanata keymap visuals and their editable sources are in kanata/docs/.
- Config source of truth:
kanata/.config/kanata/kanata.kbd - Diagram source of truth:
kanata/docs/*.json(Keyboard Layout Editor format) - Rendered diagrams:
kanata/docs/*.png
When changing Kanata layers, keep config and diagrams in sync. See
kanata/docs/README.md for the update workflow and KLE link.
The Neovim setup uses LazyVim as a base with your custom plugins tracked directly in the dotfiles repo.
Your custom plugins are in ~/dotfiles/nvim/.config/nvim/lua/plugins/:
alpha.lua- Dashboarddap-dotnet.lua- .NET debuggingsql.lua- SQL toolsexample.lua- Template for new plugins
Add new plugins by creating files in this directory following LazyVim's plugin format.
To pull the latest LazyVim starter template updates:
cd ~/dotfiles
# Add LazyVim as a remote (one-time setup)
git remote add lazyvim-upstream https://github.com/LazyVim/starter
# Fetch latest LazyVim changes
git fetch lazyvim-upstream
# Create a temporary branch to review changes
git checkout -b lazyvim-update
# Pull LazyVim changes into nvim folder
git checkout lazyvim-upstream/main -- nvim/.config/nvim/init.lua
git checkout lazyvim-upstream/main -- nvim/.config/nvim/lua/config/lazy.lua
git checkout lazyvim-upstream/main -- nvim/.config/nvim/lua/config/options.lua
# Add other base files you want to update
# Review changes
git diff main
# If satisfied, merge into main
git checkout main
git merge lazyvim-update
# Delete temporary branch
git branch -d lazyvim-update
# Re-add your custom plugins if they were overwritten
# Your plugins should still be in lua/plugins/Note: LazyVim updates are usually not necessary. Only do this if you want new LazyVim features or fixes. Your custom plugins in lua/plugins/ will not be affected by LazyVim updates.
All scripts are idempotent and can be run independently:
# Install a specific tool
./scripts/install-neovim.sh
# Install category
./scripts/install-i3.sh
./scripts/install-rofi.sh
# ... etc
# Or use the master script
./scripts/master-install.sh./scripts/stow-dotfiles.shThis script auto-detects WSL vs native Linux and stows the matching OpenCode host package:
opencode-commonon every machineopencode-wslon WSLopencode-linuxon native Linux
If you need to force the host profile for testing, use:
DOTFILES_HOST=wsl ./scripts/stow-dotfiles.sh
DOTFILES_HOST=linux ./scripts/stow-dotfiles.shcd ~/dotfiles
stow -D -t ~ bash git x11 i3 nvim ghostty starship rofi picom i3blocks lazygit flameshot nitrogen bin obsbot gtk-3.0 gtk-4.0 home-scripts kanata claude environment.d mise gh copyq opencode-common tmux opencode-linux opencode-wslcd ~/dotfiles
stow nvim # Just deploy Neovim configDo not manually stow both opencode-linux and opencode-wsl into the same home directory. The helper script above picks the correct one and also migrates old repo-owned symlinks if you switch layouts later.
For a terminal-focused WSL setup, use the narrower installer instead of master-install.sh:
./scripts/install-wsl-safe.shThat installs a CLI-safe package set, stows only the WSL-friendly dotfiles subset, and avoids desktop/i3/media services that do not belong in WSL.
If you accidentally run ./scripts/master-install.sh, ./bootstrap.sh, or ./scripts/bootstrap.sh inside WSL, they now stop and require an explicit y confirmation before continuing with the full Linux Mint path.
The custom webapp script creates Progressive Web Apps using Microsoft Edge in app mode:
webapp "App Name" "https://example.com" "1400x900"
# Note: Use 'x' format for dimensions, not commaCreate webapp-urls.local.conf in the dotfiles directory to override URLs:
cp webapp-urls.conf webapp-urls.local.conf
nano webapp-urls.local.conf # Edit your organization's URLs
./scripts/install-webapps.sh # Re-run to apply changesThe .local.conf file is gitignored and won't be committed to your repository.
- Mod key: Windows key (Mod4)
- Gaps: 8px inner, 4px outer
- HiDPI Scaling: Comprehensive 150% scaling for 4K displays
- Xft.dpi, GTK, Qt, and Electron apps all configured
- Automatic cursor scaling
- Environment variables managed via .xprofile
- Custom scripts in
~/.config/i3/scripts/:- Mouse auto-centering (on focus and new windows)
- DPI management with xrandr
- Monitor management (main-only, dual, streaming modes)
- Environment scaling setup
- Scaling diagnostics tool
App Launchers (Mod+letter for quick access):
- 20+ app hotkeys for instant launching
- Organized by category: Development, Productivity, Work Tools, Communication
- See
~/.config/i3/keybinds.mdfor complete reference or press Mod+Shift+?
Window Management:
- Mod+Escape - Focus parent container (manipulate groups of windows)
- Vim-style navigation (hjkl)
- Split controls for 2x2 grids and complex layouts
API keys and tokens are stored in ~/.secrets (not tracked in git):
# First time setup - copy template and fill in your keys
cp ~/dotfiles/home-scripts/.secrets.template ~/.secrets
chmod 600 ~/.secrets
nano ~/.secretsThe .bashrc automatically sources this file. Keys included:
JIRA_API_TOKEN- Atlassian API tokenLINEAR_API_KEY- Linear project managementOPENAI_API_KEY- OpenAI APIBRAVE_API_KEY- Brave Search API- Add your own as needed
For data NOT in dotfiles (OpenClaw, HomeAssistant, etc.), use the backup script:
# Run manually
./scripts/backup-system-state.sh
# Or use hotkey: Mod+Control+bThis creates an encrypted archive in ~/system-backup/ containing:
- OpenClaw (memory, credentials, agent auth, skills config)
- HomeAssistant config and token
- Matter server device pairings
~/.secretsfile- GOG CLI, OpenCode, JIRA configs
- Keyrings
Upload the encrypted backup to your cloud storage (iCloud, Google Drive, etc.) for disaster recovery.
The stow-dotfiles.sh script automatically backs up existing dotfiles before deployment:
~/dotfiles-backup-YYYYMMDD-HHMMSS/
For the full repo-specific update flow, run:
./scripts/update-system.shThis script safely:
- Pulls the latest dotfiles changes with
git pull --ff-onlywhen the repo is clean - Runs
apt,flatpak, andsnapupdates where available - Updates
miseitself and installedmise-managed tools - Re-runs the dotfiles install scripts (
master-install.shon Linux,install-wsl-safe.shon WSL) - Re-deploys dotfiles with
stow-dotfiles.sh
Manual equivalent:
sudo apt update && sudo apt upgrade
flatpak update
snap refreshSee the Neovim Configuration section above for instructions on pulling LazyVim upstream updates.
mise upgrade # Upgrade mise itself
mise up # Update all installed tools
mise use --global node@lts # Update Node.js
mise use --global dotnet@8 # Update .NET
mise use --global rust@latest # Update RustThis setup prioritizes latest versions over Ubuntu's stable (often outdated) packages:
- PPAs for Git, Neovim, Firefox, OBS
- Flatpak for Obsidian, Todoist, Teams (always latest)
- Official repos for VS Code, Signal, Edge, GitHub CLI
- Direct downloads for Discord, Zoom
- mise - Universal version manager for Node.js, .NET, Rust, Python, Go, and more
PPA not available for your version:
- Edit the script to use a different PPA or install from apt
- Or skip that package (scripts are modular)
Package not found:
- Check if the package name changed
- Update the script with the new package name
Permission denied:
chmod +x bootstrap.sh
chmod +x scripts/*.shScript fails partway through:
- Check the error message for the specific package
- Fix that individual install script
- Re-run bootstrap (scripts are idempotent, safe to re-run)
If stow reports conflicts:
# Backup existing configs are automatically created at:
~/.config-backup-TIMESTAMP/
# Or manually move conflicting files:
mv ~/.bashrc ~/.bashrc.backup
cd ~/dotfiles && stow bashLog out and log back in after installing Flatpak apps, or update desktop database:
sudo update-desktop-databaseEnsure Microsoft Edge is installed and the webapp script is executable:
which microsoft-edge
chmod +x ~/.local/bin/webappAll scripts are independent. If one fails:
# Check what went wrong
cat scripts/install-PACKAGE.sh
# Fix the issue and re-run just that script
./scripts/install-PACKAGE.shIf you get password prompts for Edge, git, or GOG on startup, the GNOME keyring password doesn't match your login password:
./scripts/fix-keyring.shChoose option 1 to reset all keyrings, then log out/in and set the new keyring password to match your login password.
To set up Home Assistant with Matter support (for Apple Home devices):
# Install Docker first if needed
sudo apt install docker.io
sudo usermod -aG docker $USER
# Log out and back in
# Run the setup script
./scripts/setup-homeassistant.shAccess Home Assistant at http://localhost:8123
Data is stored in:
~/homeassistant/- HA config, automations, database~/matter-server/- Matter device pairings
- Linux Mint (tested on Linux Mint 21+)
- 10+ GB free disk space (for all programs)
- Internet connection
- Inspired by the "You installed Omarchy, Now What?" workflow
- LazyVim by @folke
- GNU Stow for dotfiles management
MIT License - Feel free to use and modify for your own setup!
Author: Shane Kunz Last Updated: April 2026