Contributing¶
Conventions and guidelines for modifying this dotfiles repository.
Note
Even for personal use, following these conventions keeps the repo maintainable as it grows.
For Maintainers¶
If you're setting up repository settings or managing GitHub configuration, see GitHub Setup Guide for branch protection rules, status checks, and other repository settings.
File Naming Conventions¶
The dot_ Prefix¶
Files in the repo root use the dot_ prefix to represent dotfiles (chezmoi convention):
| In Repo | Deploys To |
|---|---|
dot_zshrc | ~/.zshrc |
dot_aliases | ~/.aliases |
dot_config/nvim/ | ~/.config/nvim/ |
Why? - Dotfiles are hidden by default, making them hard to browse - The prefix makes the repo structure explicit - Chezmoi uses this convention for templating
Adding a New Tool¶
Follow this checklist when adding a new CLI tool:
1. Add to mise.toml¶
2. Create Aliases (if applicable)¶
In dot_aliases, add to the appropriate section:
# ═══════════════════════════════════════════════════════════════
# [Category Name]
# ═══════════════════════════════════════════════════════════════
alias short='toolname'
3. Update Documentation¶
| File | Update |
|---|---|
docs/TOOLS.md | Add entry with rationale, commands, config |
README.md | Add to Tools table if notable |
docs/meta/CHANGELOG.md | Add to "Added" section |
4. Update Doctor (if critical)¶
If the tool is essential, add a check to mise-tasks/doctor:
5. Test¶
Adding Aliases¶
Naming Conventions¶
| Type | Convention | Examples |
|---|---|---|
| Single letter | Common operations | g (git), v (nvim) |
| Short | Memorable abbreviations | lg (lazygit), ll (ls -l) |
| Prefix groups | Related commands | dot-* for dotfile management |
Section Organization¶
Group aliases by function with section headers:
# ═══════════════════════════════════════════════════════════════
# Section Name
# ═══════════════════════════════════════════════════════════════
Current sections in dot_aliases: 1. Navigation 2. Directory Listing 3. Git 4. Utils 5. Modern Coreutils 6. Safety 7. System & Config 8. Dotfile Management 9. Container 10. Editor 11. Python 12. Zsh Suffix Aliases 13. WSL Integration 14. Service Packs
Documentation¶
- Simple aliases (
alias g='git') don't need comments - Complex functions should have a brief comment explaining the "why"
- Reference
docs/TOOLS.mdfor detailed tool documentation - Check for Namespace Collisions (see below)
Alias Safety & Namespace Collisions¶
Because this setup uses frameworks like oh-my-zsh plugins, simple names like gcl or ps might already be taken by plugins. This can cause "parse error near ()" crashes when you try to redefine them as functions.
Best Practices: 1. Check before you alias: Run type <name> or which <name> in a full shell to see if it exists. 2. Defensive Unalias: If you must overwrite a common name with a function (e.g., specific overrides like ps or gcl), include a defensive unalias guard:
dot-) for custom tools to avoid conflicts entirely. Modifying Configurations¶
When to Edit Synced Files¶
Edit the synced file when: - The change should apply to all machines - It's a fix or improvement everyone benefits from - You're adding a new tool/feature
When to Use Local Overrides¶
Use ~/.zshrc.local when: - Machine-specific paths or tools - Work vs. personal configuration - Experimental changes you're testing
See CUSTOMIZATION.md for override patterns.
Dependency Updates¶
This project uses Renovate Bot to automate tool and dependency updates.
Workflow¶
- Weekly Schedule: Renovate checks for updates every weekend.
- Pull Requests:
- Updates are grouped to minimize PR noise (e.g., "mise tools").
- Patch updates for stable languages (Node, Python, Rust) are automerged if CI passes.
- Major/Minor updates require manual review and merge.
- Manual Updates:
- You can manually update tools by running
mise upgradelocally and committing the changes tomise.toml.
Configuration¶
Configuration is located in .github/renovate.json. It handles: - mise.toml tool versions - Brewfile (macOS dependencies) - .pre-commit-config.yaml (hook versions) - GitHub Actions workflow versions
Adding a Mise Task¶
Mise tasks are shell scripts that automate common operations. They live in mise-tasks/ and are invoked via mise run <task>.
Task File Structure¶
Create a new file in mise-tasks/ (no extension needed):
#!/bin/bash
#MISE description="Short description shown in 'mise tasks'"
#MISE alias="shortname"
#USAGE flag "-f --force" help="Force the operation"
#USAGE flag "-v --verbose" help="Enable verbose output"
#USAGE arg "<input>" help="Input file path"
set -e
# Source shared colors (with fallback for standalone execution)
if [ -f "scripts/lib/colors.sh" ]; then
# shellcheck disable=SC1091
source "scripts/lib/colors.sh"
else
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m'
fi
# Parse flags (usage-lib handles this, but manual parsing works too)
for arg in "$@"; do
case "$arg" in
--force|-f) FORCE=true ;;
--verbose|-v) VERBOSE=true ;;
esac
done
# Task implementation here
echo -e "${GREEN}Task complete!${NC}"
Pragma Reference¶
| Pragma | Purpose | Example |
|---|---|---|
#MISE description="..." | Shown in mise tasks list | "Check environment health" |
#MISE alias="..." | Short name for the task | "doc" for mise run doc |
#MISE depends=["..."] | Run other tasks first | depends=["lint", "test"] |
#MISE sources=["..."] | Files that trigger re-run | sources=["src/**/*.ts"] |
#MISE outputs=["..."] | Files the task produces | outputs=["dist/**"] |
#USAGE flag "..." | Define CLI flags | flag "-v --verbose" |
#USAGE arg "..." | Define positional args | arg "<file>" help="Input" |
Best Practices¶
- Always use
set -e- Exit on first error - Source colors with fallback - Tasks may run standalone
- Check for required tools - Use
command -v tool >/dev/null - Support non-interactive mode - Check
$CIor[ ! -t 0 ] - Add cleanup traps -
trap 'cleanup' EXITfor temp files - Make tasks idempotent - Safe to run multiple times
- Protect
$HOMEhygiene - Keep non-dot repo artifacts in.chezmoiignore
Testing Your Task¶
# List all tasks
mise tasks
# Run with verbose output
mise run mytask --verbose
# Check for shellcheck issues
shellcheck mise-tasks/mytask
Example Tasks¶
| Task | Purpose |
|---|---|
install | Apply dotfiles via chezmoi |
doctor | Validate environment health |
test | Run BATS test suite |
lint | Run all linters |
backup | Backup current configs |
Directory Structure¶
dotfiles/
├── dot_zshrc # → ~/.zshrc
├── dot_aliases # → ~/.aliases
├── dot_gitconfig # → ~/.gitconfig
├── dot_tmux.conf # → ~/.tmux.conf
├── dot_config/ # → ~/.config/
│ ├── nvim/ # Neovim config
│ ├── atuin/ # Atuin config
│ └── wsl/ # WSL templates
├── dot_secrets.example # Template (not deployed)
├── .chezmoi.toml.tmpl # Chezmoi config template
├── .chezmoidata.yaml # Package lists per distro
├── .chezmoiignore # Platform-specific ignores
├── .chezmoiversion # Minimum chezmoi version
├── run_once_*.sh.tmpl # One-time setup scripts
├── encrypted_dot_secrets.age # Encrypted secrets
├── mise-tasks/ # Mise task scripts
│ ├── install # Apply dotfiles
│ ├── doctor # Validate environment
│ ├── update # Update dotfiles + tools
│ ├── setup-secrets # Configure age encryption
│ └── ...
├── scripts/ # Utility scripts
│ └── bootstrap # Initial setup
├── provision/ # OS provisioning
│ └── windows/ # Windows setup scripts
├── docs/ # Documentation
├── mise.toml # Tool definitions
├── Brewfile # macOS packages
└── README.md # Quick start
Development Workflow¶
Pre-commit Hooks¶
We use pre-commit to ensure code quality before every commit.
Setup:
Running manually:
What is checked: - ShellCheck (scripts) - Executable permissions - Trailing whitespace - End-of-file fixers - Gitleaks (secrets detection)
Changelog & Releases¶
We follow Conventional Commits to automate changelogs.
Commit Message Format: type(scope): description
feat: New featuresfix: Bug fixesdocs: Documentationchore: Maintenance
Generating Changelog: We use git-cliff to generate changelogs.
Attribution Policy: - Commit/changelog authorship must list only human contributors. - Do not add AI co-author or AI attribution lines (for example Co-authored-by entries for tool names).
Testing Changes¶
Before Committing¶
-
Pre-commit: Ensure hooks pass
-
Install check: Reinstall symlinks
-
Health check: Run the doctor
-
Run tests: Execute the test suite
-
Functional test: Manually verify changes work
CI Failures¶
If CI fails on your PR, see CI Troubleshooting Guide for debugging steps.
Local Testing Workflows¶
Testing Alias/Function Changes¶
# Quick test in new shell
zsh -ic "source dot_aliases && myfunction arg1"
# Run specific BATS tests
bats tests/aliases.bats --filter "myfunction"
# Test interactively
zsh -i # Opens new shell with changes
Testing Mise Task Changes¶
# Validate task syntax
shellcheck mise-tasks/mytask
# Run with debug output
bash -x mise-tasks/mytask
# Test idempotency (run twice)
mise run mytask && mise run mytask
Testing Zshrc/Config Changes¶
# Check for syntax errors
zsh -n dot_zshrc.tmpl
# Validate chezmoi template
chezmoi execute-template < dot_zshrc.tmpl > /dev/null
# Test shell startup time
time zsh -i -c exit
# Profile startup (detailed)
mise run profile
Testing in Isolation¶
# Use devcontainer for clean environment
# VS Code: "Reopen in Container"
# Or test with Docker directly
docker run -it --rm -v "$PWD:/dotfiles" ubuntu:latest bash
Cross-Platform Testing¶
If you have multiple machines: 1. Commit and push changes 2. Pull on another machine 3. Run mise run update 4. Verify with mise run doctor
Commit Conventions¶
Message Format¶
Types¶
| Type | Use For |
|---|---|
feat | New tool, alias, or feature |
fix | Bug fix |
docs | Documentation only |
refactor | Code change that doesn't add features or fix bugs |
chore | Maintenance, cleanup, dependency updates |
Examples¶
feat: add yazi file manager
docs: add troubleshooting guide for WSL clipboard
fix: correct fzf preview command for bat
chore: update mise tools to latest versions
Pull Request Guidelines¶
If working with others or contributing to forks:
PR Checklist¶
- Follows file naming conventions
- Documentation updated
- CHANGELOG.md updated
-
mise run doctorpasses - Checked for alias collisions
- Tested on target platform(s)