A beautiful, interactive TUI application for managing your dotfiles and configuration files across multiple machines.
- 🎨 Beautiful TUI - Clean, modern interface built with Charmbracelet Bubble Tea
- 📁 Smart Discovery - Automatically finds your dotfiles and config directories
- 🔗 Symlink Management - Creates and manages symlinks to keep configs in sync
- 📝 Template Support - Dynamic templates with variables for different environments
- 🔄 Easy Sync - Move your entire configuration between machines effortlessly
- ⚙️ Smart Editor Integration - Edit files and directories with your preferred editor
- 🗂️ Category Organization - Organize configs by type (shell, editor, git, etc.)
- 💾 Backup System - Automatic backups before making changes
- 🎯 Selective Linking - Link individual files or all at once
- Go 1.21 or later
- Gum (optional, for enhanced UI)
# macOS
brew install gum
# Ubuntu/Debian
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
sudo apt update && sudo apt install gum
# Arch Linux
pacman -S gumgo install github.com/pergatore/config-manager@latestOr build from source:
git clone https://github.com/pergatore/config-manager.git
cd config-manager
go build -o config-manager
sudo mv config-manager /usr/local/bin/-
Run the application:
config-manager
-
First-time setup: The setup wizard will guide you through:
- Choosing your preferred editor (vim, nvim, VS Code, etc.)
- Selecting your shell (bash, zsh, fish)
- Discovering existing configuration files
-
Add configurations: Press
ato add dotfiles and config directories -
Link configurations: Press
lto link a specific file, orLto link all
a- Add new configuration file or directoryr- Remove configuration from managemente- Edit configuration file (supports directories)l- Link selected configurationL- Link all configurationsb- Create backup of current configurationsq- Quit application
- ✓ - Configuration is properly linked
- ✗ - Configuration is not linked
⚠️ - Configuration has conflicts (file exists but isn't linked)
Config Manager makes it easy to sync your dotfiles across multiple computers.
-
On your primary machine, initialize a git repository for your entire config-manager directory:
cd ~/.config/config-manager git init git add . git commit -m "Initial config-manager setup" git remote add origin https://github.com/yourusername/config-manager-dotfiles.git git push -u origin main
-
On a new machine, install config-manager and clone your complete setup:
# Install config-manager first go install github.com/pergatore/config-manager@latest # Remove any existing config-manager directory rm -rf ~/.config/config-manager # Clone your complete configuration git clone https://github.com/yourusername/config-manager-dotfiles.git ~/.config/config-manager # Run config-manager and link everything config-manager # Press 'L' to link all configurations
That's it! Your new machine now has:
- All your dotfiles and configurations
- Your config.json settings
- Your custom templates
- Your backup history
- All categories and preferences
-
Keep machines in sync:
# After making changes on any machine cd ~/.config/config-manager git add . git commit -m "Update configurations" git push # On other machines cd ~/.config/config-manager git pull config-manager # Re-link if needed
-
Export your complete configuration:
tar -czf my-complete-config.tar.gz -C ~/.config config-manager -
On the new machine:
# Install config-manager first go install github.com/pergatore/config-manager@latest # Extract your complete setup tar -xzf my-complete-config.tar.gz -C ~/.config # Link everything config-manager # Press 'L' to link all configurations
By making the entire ~/.config/config-manager directory your repository, you get:
- ✅ Complete portability - Everything moves together
- ✅ No manual config copying - config.json is included
- ✅ Template preservation - All your custom templates travel with you
- ✅ Backup history - Your backup history is preserved (optional)
- ✅ Category settings - Custom categories and preferences included
- ✅ One-command setup - Clone and you're ready to go
Config Manager supports dynamic templates that automatically adapt to different environments and machines. Instead of manually editing config files on each computer, templates fill in the details automatically.
Templates let you create one config file that automatically adapts to different computers. For example, your .gitconfig can automatically use different email addresses for work vs personal machines, while keeping everything else the same.
Let's create a .gitconfig that automatically adapts based on your machine's hostname:
# Create the templates directory
mkdir -p ~/.config/config-manager/templates
# Create a git config template that uses hostname detection
cat > ~/.config/config-manager/templates/gitconfig.tmpl << 'EOF'
[user]
name = {{ .user }}
email = {{ .user }}@{{ if contains .hostname "work" }}company.com{{ else }}gmail.com{{ end }}
[core]
editor = {{ .editor }}
autocrlf = input
# Work-specific settings
{{ if contains .hostname "work" }}
[url "[email protected]:company/"]
insteadOf = https://github.com/company/
[commit]
gpgsign = true
[user]
signingkey = ABC123DEF456
{{ end }}
# Personal settings
{{ if not (contains .hostname "work") }}
[github]
user = {{ .user }}
[pull]
rebase = true
{{ end }}
[push]
default = simple
[alias]
st = status
co = checkout
br = branch
# Configuration for {{ .user }} on {{ .hostname }}
EOFYour ~/.config/config-manager/config.json stays completely portable - no machine-specific variables needed:
{
"editor": "vim",
"shell": "zsh",
"global_variables": {}
}- In config-manager, press
ato add your existing.gitconfig - Edit the config to mark it as a template:
{
"name": ".gitconfig",
"source": "git/gitconfig",
"target": "/home/username/.gitconfig",
"category": "git",
"template": true,
"variables": {}
}Press l in config-manager to link your .gitconfig.
What happens:
- Config-manager reads
templates/gitconfig.tmpl - Checks your hostname and applies appropriate conditionals
- Fills in built-in variables:
{{ .user }},{{ .hostname }},{{ .editor }} - Creates the final file and symlinks it
On work laptop (hostname: work-laptop-01):
[user]
name = john
email = [email protected]
[core]
editor = vim
autocrlf = input
[url "[email protected]:company/"]
insteadOf = https://github.com/company/
[commit]
gpgsign = true
[user]
signingkey = ABC123DEF456
[push]
default = simple
[alias]
st = status
co = checkout
br = branch
# Configuration for john on work-laptop-01On personal MacBook (hostname: Johns-MacBook-Pro):
[user]
name = john
email = [email protected]
[core]
editor = vim
autocrlf = input
[github]
user = john
[pull]
rebase = true
[push]
default = simple
[alias]
st = status
co = checkout
br = branch
# Configuration for john on Johns-MacBook-ProThe key insight: Same template file, same config.json, but different outputs based on hostname detection!
Create ~/.config/config-manager/templates/zshrc.tmpl:
# {{ .user }}'s {{ .shell }} configuration on {{ .hostname }}
export EDITOR="{{ .editor }}"
export PATH="$HOME/bin:$PATH"
# Work-specific settings (based on hostname)
{{ if contains .hostname "work" }}
export COMPANY_API_KEY="work-api-key-123"
export WORK_PROJECT_DIR="$HOME/work"
alias deploy="kubectl apply -f"
alias vpn="sudo openvpn /etc/openvpn/work.conf"
{{ end }}
# Personal settings (based on hostname)
{{ if contains .hostname "home" }}
export PERSONAL_PROJECT_DIR="$HOME/projects"
alias blog="cd $PERSONAL_PROJECT_DIR/blog"
alias backup="rsync -av $HOME/Documents/ /backup/"
{{ else if contains .hostname "macbook" }}
export PERSONAL_PROJECT_DIR="$HOME/Code"
alias blog="cd $PERSONAL_PROJECT_DIR/blog"
# macOS-specific aliases
alias brew-update="brew update && brew upgrade"
{{ end }}
# Common aliases for all machines
alias ll="ls -la"
alias ..="cd .."
alias grep="grep --color=auto"And ~/.config/config-manager/templates/gitconfig.tmpl:
[user]
name = {{ .user }}
email = {{ .user }}@{{ if contains .hostname "work" }}company.com{{ else }}gmail.com{{ end }}
[core]
editor = {{ .editor }}
autocrlf = input
# Work-specific git settings
{{ if contains .hostname "work" }}
[url "[email protected]:company/"]
insteadOf = https://github.com/company/
[commit]
gpgsign = true
{{ end }}
# Personal git settings
{{ if not (contains .hostname "work") }}
[github]
user = {{ .user }}
{{ end }}
[alias]
st = status
co = checkout
br = branchWhy Hostname-Based Conditionals Work Best:
- ✅ No circular dependencies - hostname is always available when templates are processed
- ✅ Fully portable - same config.json works on all machines
- ✅ Self-contained - no external environment setup needed
- ✅ Immediate evaluation - works reliably every time you link
- ✅ Predictable - same hostname always produces the same result
Different machines automatically get different configs:
Work laptop (work-laptop-01):
export COMPANY_API_KEY="work-api-key-123"
email = [email protected]Personal MacBook (Johns-MacBook-Pro):
export PERSONAL_PROJECT_DIR="$HOME/Code"
email = [email protected]
alias brew-update="brew update && brew upgrade"Home desktop (home-desktop):
export PERSONAL_PROJECT_DIR="$HOME/projects"
email = [email protected]
alias backup="rsync -av $HOME/Documents/ /backup/"This approach keeps your config.json completely portable while automatically adapting to each machine!
Templates automatically have access to:
Built-in System Variables:
{{ .user }}- Current username (from$USERenvironment variable){{ .hostname }}- Machine hostname (fromos.Hostname()){{ .editor }}- Your configured editor (from config-manager setup){{ .shell }}- Your configured shell (from config-manager setup)
Custom Variables:
- Any variables from
global_variablesin config.json - Any file-specific variables in the file's
variablessection
Example of all variable types:
# Built-in variables
User: {{ .user }} # → john
Host: {{ .hostname }} # → work-laptop
Editor: {{ .editor }} # → vim
Shell: {{ .shell }} # → zsh
# Custom global variables (from config.json global_variables)
Email: {{ .email_domain }} # → company.com
Environment: {{ .environment }} # → work
# File-specific variables (from file's variables section)
API Key: {{ .api_key }} # → secret-key-123Use Go template functions for dynamic content:
{{ if eq .environment "work" }}...{{ end }}- Conditional sections{{ .user | upper }}- Transform text to uppercase{{ .hostname | lower }}- Transform text to lowercase
- Create template file in
~/.config/config-manager/templates/ - Add variables to
config.json - Mark file as template when adding to config-manager
- Link the template - config-manager generates the final file
- On new machines - same template + different variables = different output
This way, you maintain one template but get machine-specific configs automatically! Perfect for managing configurations across work laptops, personal machines, and servers.
Config Manager stores everything in ~/.config/config-manager/:
~/.config/config-manager/
├── config.json # Main configuration file
├── dotfiles/ # Your managed dotfiles
│ ├── shell/
│ ├── editor/
│ ├── git/
│ └── misc/
├── templates/ # Template files
│ ├── gitconfig.tmpl
│ ├── zshrc.tmpl
│ └── vimrc.tmpl
└── backups/ # Automatic backups
└── 2024-01-15_14-30-45/
# Add your nvim config directory
# Press 'a', select '.config/nvim (directory)'
# Edit your config
# Select nvim, press 'e', choose which file to edit
# Link it
# Press 'l' to link just nvim, or 'L' to link everything# Add your shell config
# Press 'a', select '.zshrc (file)' or '.bashrc (file)'
# Make it a template if you want environment-specific settings
# Edit config.json or recreate with template support
# Link across machines
# Your shell config will adapt to each environment# Always backup before major changes
# Press 'b' to create a timestamped backup
# Backups are stored in ~/.config/config-manager/backups/Edit config.json to add your own categories:
{
"categories": ["shell", "editor", "git", "terminal", "wm", "custom"]
}Customize which file extensions are treated as templates:
{
"template_extensions": [".tmpl", ".template", ".tpl", ".j2"]
}Config Manager works with any editor. Popular configurations:
{
"editor": "nvim" // or "vim", "code", "emacs", "nano"
}Q: Config Manager doesn't find my dotfiles
A: Make sure they're in your home directory and not hidden by .gitignore or similar.
Q: Symlinks aren't working
A: Check that the source files exist in ~/.config/config-manager/dotfiles/ and you have proper permissions.
Q: Templates aren't rendering A: Verify your template syntax and check that variables are defined in your config.
Q: Editor integration isn't working
A: Make sure your editor is in your $PATH and the editor name in config matches the command.
- Check the status messages in the application
- Look at backup files if something goes wrong
- File issues on GitHub
We welcome contributions! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Charm's amazing TUI libraries
- Inspired by various dotfile management tools
- Thanks to the Go community for excellent tooling