Conventions¶
Privacy & PII Protection¶
This repository has strict rules against committing personal information.
Rules¶
- No hardcoded usernames — Never include your local username in files
- No home paths — Never include
/home/yournameor/Users/yourname - No personal emails — Use placeholders or templating
Git Hooks¶
Hooks are orchestrated by the pre-commit framework via .pre-commit-config.yaml at repo
root. Secret + PII scanning is delegated to betterleaks, whose ~170-rule
default pack covers common credentials (AWS / GCP / Azure / GitHub / Stripe / Slack / SSH keys / JWTs / etc.).
Project-specific policy hooks (subject line length, dirty-tree refusal, cross-branch push refusal) live in hooks/lib/.
For framework mechanics — cache layout, per-stage dispatch, what runs at pre-commit vs commit-msg vs pre-push, and
debugging — see Git Hooks. This section covers only the privacy / PII-specific concerns.
Personal PII config: ~/.config/betterleaks/personal.toml (chezmoi-managed, create_ prefix — never overwritten).
The file is intentionally outside the repo so personal PII patterns are never committed. The chezmoi setup script
creates a .betterleaks.toml symlink at the repo root pointing at it; the symlink is gitignored. betterleaks
auto-discovers .betterleaks.toml at the repo root — no env var needed.
A local betterleaks-config-gate hook runs first and fail-closes if the symlink is missing or broken, or if the
config still contains a REVIEW_ME marker (shipped in fresh installs to force the user to read the file before their
first commit).
If a commit is blocked by betterleaks finding a literal home path or username, replace it with a chezmoi template variable:
Note: Never use --no-verify to bypass these hooks.
Code Style¶
- Idempotency: Scripts must be safe to run multiple times
- Error handling: Use
set -euo pipefailin bash scripts - Platform checks: Use
.isMacos/.isLinux/.isBluefinfor OS-specific logic - Tool guards: Always check
command -v <tool>before using optional tools - Local overrides: Use
99-local.zshfor machine-specific changes (create_— never overwritten)
Shell Best Practices¶
Use shellcheck to catch common bash pitfalls (unquoted variables, regex injection, [ ] vs [[ ]], unused variables,
etc). Fix flagged warnings rather than disabling rules. Add # shellcheck disable=SC#### only with a comment explaining
why.
Just Recipe Attributes¶
Recipe attributes must appear in this order (omit any that don't apply):
This matches the convention used throughout _common.just.tmpl and all modules.
Just Indentation¶
Recipe bodies use 4 spaces — the default for just --fmt. This is enforced by ~/.editorconfig.
Template Delimiters¶
All .tmpl files use custom chezmoi delimiters to avoid clashing with just's {{ }}:
[{ }]— chezmoi, evaluated atchezmoi applytime{{ }}— just, evaluated at recipe runtime
For Docker/Go format strings inside just recipes, double the opening braces: {{{{.ID}} → renders as {{.ID}}. Do not
double the closing braces.
See Templates for worked examples and the full three-layer escaping reference.
For details on script lifecycle and shell modules, see Platforms, Scripts, and Shell Modules.
Package Data Convention¶
All package declarations live in .chezmoidata/packages.yaml as the single source of truth.
Entry Format¶
Each entry is an object with pkg (required) and optional fields:
- {pkg: "neovim"} # simple
- {pkg: "ffmpeg", skip_minimal: true, comment: "yazi: thumbnails"} # with flags
- {pkg: "iputils-ping", bin: "ping"} # when binary differs
| Field | Used by | Purpose |
|---|---|---|
pkg |
Install scripts, Brewfile | Package name passed to the package manager |
type |
Brewfile template | "cask" for Homebrew casks (default: brew) |
comment |
Brewfile template | Rendered as # comment after the brew/cask line |
bin |
dotfiles-verify.sh |
Binary to check on $PATH (defaults to pkg if omitted) |
skip_bluefin |
Brewfile template | true to exclude on Bluefin (provides natively) |
skip_minimal |
Brewfile template | true to exclude in container installs |
Structure¶
# Homebrew packages — by platform
brew:
common: # every machine
macos: # macOS only
linux: # Linux only
# OS packages — installed via apt/dnf/flatpak, not Homebrew
packages:
linux_apt: # Debian/Ubuntu via apt
linux_dnf: # Fedora/Bluefin via dnf
flatpak: # Linux desktop apps via flathub
Template Filtering¶
Brewfile.tmpl uses missing-key=zero so absent skip_* flags default to false (include the package). The filter
logic:
[{- if not (and .skip_bluefin $.isBluefin) }] # skip only if flag set AND on Bluefin
[{- if not (and .skip_minimal $.isMinimal) }] # skip only if flag set AND minimal
Packages are grouped by purpose within each platform section, alphabetical within groups.
Dotfiles Repository¶
The repo identity and remote URLs are defined in .chezmoidata/data.yaml under repo:. A run_after script configures
the chezmoi source repo on every apply:
user.name/user.emailfrom.repo.name/.repo.email- Split remote: HTTPS fetch (no auth for public repo), SSH push (YubiKey)
Commits & Pull Requests¶
Commit Messages¶
Conventional Commits format is enforced by
commitlint at the commit-msg stage, configured via .commitlintrc.yaml at the repo
root. The config extends @commitlint/config-conventional (the spec's reference rule set) and adds
header-max-length: 80 plus subject-min-length: 5.
- Required types:
feat,fix,docs,style,refactor,perf,test,build,ci,chore,revert - Scope: Optional but encouraged (e.g.,
zsh,brew,nvim,bluefin) - Keep the subject line under 80 characters
- Reference issues where applicable
Before Submitting¶
- Run
just maint test smoke local-all— all distros must pass - Run
just dotfiles verifyon the target machine - Check
chezmoi difffor unexpected changes - Ensure no PII is included (pre-commit hook will catch most cases)