|
| 1 | +# Improvement Plan — devpreferences |
| 2 | + |
| 3 | +**Date:** 2026-06-10 |
| 4 | +**Status:** Phase 1 executed; Phase 2 proposed |
| 5 | +**Scope:** Repository hygiene, CI, dependency management for vendored scripts, documentation, and shell-config correctness. |
| 6 | + |
| 7 | +## 1. Repository overview |
| 8 | + |
| 9 | +This repository holds personal development environment preferences (dotfiles), organised by tool: |
| 10 | + |
| 11 | +| Directory | Contents | |
| 12 | +|---------------|-----------------------------------------------------------------| |
| 13 | +| `bash/` | `.bash_profile`, `.bash_aliases` (aliases shared with zsh) | |
| 14 | +| `zsh/` | `.zshrc` (Oh My Zsh + starship), `.zshenv` (cargo env) | |
| 15 | +| `git/` | `.gitconfig` (aliases + sensible defaults), `.gitignore_global` | |
| 16 | +| `starship/` | `starship.toml` prompt configuration | |
| 17 | +| `terminator/` | Terminator terminal emulator configuration | |
| 18 | +| `lsd/` | `config.yaml`, `icons.yaml` for lsd (ls replacement) | |
| 19 | + |
| 20 | +There is no build system, no tests, and (before this plan) no CI. Files are consumed by manually copying or symlinking them into `$HOME`. |
| 21 | + |
| 22 | +## 2. Findings |
| 23 | + |
| 24 | +### 2.1 Bugs / correctness |
| 25 | + |
| 26 | +1. **`git/.gitconfig` — invalid config key (silent failure).** |
| 27 | + `[core] excludefile = ~/.gitignore_global` uses a non-existent key. The correct key is |
| 28 | + `excludesfile` (`core.excludesFile`). Git ignores unknown keys silently, so the global |
| 29 | + gitignore referenced by the README has never actually been active through this file. |
| 30 | + |
| 31 | +2. **`git/.git-prompt.sh` is a stale vendored copy.** |
| 32 | + The header claims "Aug 2024", but comparison of git blob SHAs against |
| 33 | + `git/git@master:contrib/completion/git-prompt.sh` shows the local copy |
| 34 | + (blob `a187b63…` after stripping the two local header lines) differs from upstream |
| 35 | + (blob `6186c47…`, 21,338 bytes vs ~18,660 locally). The local copy predates the |
| 36 | + 2024-08-20 upstream batch which added custom 0-width PS1 marker support and several |
| 37 | + portability/quoting fixes (`fbcdfab`, `0dbe3d3`, `29bcec8`, `b732e08`, `fe445a1`). |
| 38 | + Vendoring third-party scripts with no update mechanism guarantees this kind of drift. |
| 39 | + |
| 40 | +3. **`zsh/.zshrc` — unguarded source.** |
| 41 | + `source $ZSH_CUSTOM/aliases.zsh` aborts with an error on any machine where that file |
| 42 | + has not been symlinked yet, producing a noisy (and partially broken) shell startup. |
| 43 | + |
| 44 | +### 2.2 Hygiene / industry standards gaps |
| 45 | + |
| 46 | +4. **No CI.** Shell config files are exactly the kind of artifact that benefits from |
| 47 | + ShellCheck: errors are silent and only discovered on the next machine you provision. |
| 48 | +5. **No agent/contributor entry point.** No `AGENTS.md`; the README does not describe |
| 49 | + the repo layout, installation, or conventions (e.g. gitmoji-style commit subjects). |
| 50 | +6. **No `.editorconfig`.** Mixed editors across machines can introduce whitespace drift. |
| 51 | +7. **ShellCheck findings in `bash/.bash_profile`.** A mix of false positives |
| 52 | + (`GIT_PS1_*` variables consumed by the sourced `git-prompt.sh`; color variables used |
| 53 | + by the deprecated-but-kept `color_my_prompt`) and one legitimate style issue |
| 54 | + (`SC2155` declare-and-assign). These need inline directives with justification so CI |
| 55 | + can run at default severity instead of being watered down globally. |
| 56 | +8. **No automated update for GitHub Actions versions.** Once CI exists, action versions |
| 57 | + should be kept current (Dependabot). |
| 58 | + |
| 59 | +## 3. Plan |
| 60 | + |
| 61 | +### Phase 1 — executed now |
| 62 | + |
| 63 | +| # | Action | Details | |
| 64 | +|---|--------|---------| |
| 65 | +| 1 | **Fix `core.excludesfile` typo** | `excludefile` → `excludesfile` in `git/.gitconfig`. | |
| 66 | +| 2 | **De-vendor `git-prompt.sh`** | Delete `git/.git-prompt.sh`. Add `scripts/update-git-prompt.sh` which downloads the latest upstream version from `git/git@master` to `~/.git-prompt.sh` (configurable destination, fails loudly, validates the download looks like the real script before installing). `bash/.bash_profile` already sources `~/.git-prompt.sh` only if present, so no change needed there. | |
| 67 | +| 3 | **Add ShellCheck CI** | `.github/workflows/shellcheck.yml`: runs on push/PR, checks `bash/` dotfiles and `scripts/*.sh` with bash dialect. zsh files are excluded (ShellCheck does not support zsh). | |
| 68 | +| 4 | **Make bash files ShellCheck-clean** | Add `# shellcheck shell=bash` headers, targeted `disable` directives with reasons (SC2034 for externally-consumed vars, SC1090/SC1091 for runtime sources), and fix the real SC2155 finding. | |
| 69 | +| 5 | **Guard zsh alias sourcing** | `[ -f "$ZSH_CUSTOM/aliases.zsh" ] && source …` so a fresh machine still gets a working shell. | |
| 70 | +| 6 | **Add `AGENTS.md`** | Repo map, conventions, what is safe to change, how files map to `$HOME`, CI expectations. | |
| 71 | +| 7 | **Add `.editorconfig`** | UTF-8, LF, final newline, 2-space indent for YAML/TOML, tabs preserved where files already use them. | |
| 72 | +| 8 | **Add Dependabot config** | Weekly updates for GitHub Actions. | |
| 73 | +| 9 | **Rewrite `README.md`** | Layout table, installation/symlink instructions, git-prompt update script usage, link to plans and AGENTS.md. Keep the existing reference-article links. | |
| 74 | + |
| 75 | +### Phase 2 — proposed (not executed) |
| 76 | + |
| 77 | +| # | Action | Rationale | |
| 78 | +|---|--------|-----------| |
| 79 | +| 1 | **`install.sh` or GNU Stow adoption** | Symlinking by hand is error-prone. GNU Stow is the de-facto standard for dotfiles (`stow bash git zsh …`); the current per-tool directory layout is almost Stow-compatible already (files would need to mirror `$HOME`-relative paths, e.g. `lsd/.config/lsd/config.yaml`). Decide between Stow and a small idempotent `install.sh`; either should back up existing files before linking. | |
| 80 | +| 2 | **Add a LICENSE** | The repo is public; without a license it is "all rights reserved" by default. MIT is typical for dotfiles. Left as a deliberate owner decision. | |
| 81 | +| 3 | **zsh syntax check in CI** | ShellCheck cannot lint zsh; a cheap `zsh -n zsh/.zshrc` job catches syntax errors. | |
| 82 | +| 4 | **Scheduled CI freshness check for git-prompt** | A monthly workflow comparing upstream blob SHA against a recorded one, opening an issue when upstream moves. Complements the update script. | |
| 83 | +| 5 | **Pre-commit hooks** | `pre-commit` with `shellcheck` + whitespace hooks for local feedback before CI. | |
| 84 | +| 6 | **Retire deprecated prompt code** | `color_my_prompt` and the color variables in `bash/.bash_profile` are dead since starship took over the prompt; once confident, delete them (they are the main source of ShellCheck noise). | |
| 85 | +| 7 | **Pin starship/lsd minimum versions in docs** | Configs assume features of specific tool versions; documenting them avoids surprises on older distros. | |
| 86 | + |
| 87 | +## 4. git-prompt.sh strategy (decision record) |
| 88 | + |
| 89 | +**Options considered:** |
| 90 | + |
| 91 | +- **A. Keep vendoring, update manually** — status quo; proven to drift (header said |
| 92 | + "Aug 2024" yet was already behind other Aug 2024 commits). |
| 93 | +- **B. Git submodule of `git/git`** — pulls a ~250 MB repository for one 21 KB file; |
| 94 | + rejected. |
| 95 | +- **C. Fetch-on-demand script (chosen)** — `scripts/update-git-prompt.sh` downloads the |
| 96 | + canonical file from `https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh` |
| 97 | + into `~/.git-prompt.sh`. Pros: always current on demand, removes 612 lines of |
| 98 | + third-party code from the repo, no merge noise on updates. Cons: requires network on |
| 99 | + first setup; mitigated by clear error messages. The script validates the downloaded |
| 100 | + content (shebang-less but must contain `__git_ps1`) and is atomic (temp file + `mv`). |
| 101 | + |
| 102 | +## 5. Verification |
| 103 | + |
| 104 | +- `shellcheck` (v0.9.0, bash dialect) passes locally on all checked files at default severity. |
| 105 | +- `scripts/update-git-prompt.sh` exercised locally against a temp destination. |
| 106 | +- `git -c include.path=… config core.excludesfile` resolves after the typo fix. |
0 commit comments