# Changelog

This file documents all notable changes to this project.

## v0.2.511 — 2026-07-08

Bug-fix release: restore shell aliases that were silently dropped after the CD-completion fragment.

### Fixed

- **`reload`, `r`, `mkcd`, `quit` — and every alias/function defined after the CD-completion block — were undefined** whenever `compdef` was not yet available when `90-ux-aliases.sh` was sourced (profiles that don't run `compinit`, and fast-startup shells). The zsh branch of `defaults/.chezmoitemplates/aliases/cd/cd-completion.aliases.sh` skipped completion registration with a **file-scope `return 0`**; because that fragment is inlined into the single concatenated `90-ux-aliases.sh`, the bare `return` aborted the whole file, dropping `set_default_aliases()` (which defines `reload` et al.) and everything after it. Replaced the early-return with a positive `if command -v compdef …; then … fi` guard, so only the completion block is skipped when `compdef` is not ready.

### Changed

- **`scripts/version-sync.sh`**: excluded the two dated release write-ups (`docs/articles/2026-07-05-*.md`) from version verification. They record the release they shipped in ("shipped in v0.2.510" + release-tag link) as historical fact; the `--verify` pass was false-flagging those refs as inconsistent even though the update pass correctly leaves them alone.

## v0.2.510 — 2026-07-05

Post-v0.2.509 quality-of-life release: default branch renamed `master` → `main`, docs site relit with a custom dark + terminal-green MkDocs Material theme, shells warmed up (fish alias→abbr, zsh PATH prune), font bumped to 20pt across every terminal template, themes rebuilt from wallpapers.

### Added

- **Custom docs theme** (#960). doc.dotfiles.io now serves MkDocs Material with a bespoke palette (near-black `#0b0e14` background, terminal-green `#7ee787` accent), Inter + JetBrains Mono fonts, hero + 8-card feature grid landing page. Header, tabs, sidebar, TOC, admonitions, code blocks, tables, custom scrollbar all restyled in `docs/stylesheets/extra.css`.
- **CLAUDE.md `## Handing over commands` rule** (#959). Cross-project preference deployed to `~/.claude/CLAUDE.md`: when Claude Code needs the user to run shell steps themselves, it must hand them over as one runnable script file, not fenced code blocks or scattered one-liners.
- **`mirror-main-to-master` workflow** (#961). Fast-forwards `master` from `main` on every push during the rename grace period so bookmarked `raw.githubusercontent.com/…/master/…` install URLs keep resolving. Retire on 2027-07-05 per tracking issue #962.
- **fish alias-cache pre-warm** (#964). New `run_onchange_after_30-regen-fish-alias-cache.sh.tmpl` regenerates `~/.cache/fish/bash-aliases.fish` at chezmoi-apply time when the alias sources change, so the first fish shell after apply doesn't pay ~200ms rebuilding the cache from scratch.

### Changed

- **Default branch: `master` → `main`** (#961). GitHub-side rename plus 96 in-repo edits (workflow triggers, docs URIs, install URLs, ruleset filename, git aliases). Every `raw.githubusercontent.com/…/master/…` and `github.com/…/blob/master/…` reference now points at `/main/`. Workflow `pull_request:` / `push:` triggers keep `master` as a grace-period fallback until the mirror is retired.
- **Portability + missing commands** (#953). Ships as part of v0.2.509 via PR #953 (already tagged) — cross-platform fixes for macOS/BSD/Alpine/openSUSE (base64 `-D` fallback, `sort -V` stdin buffering, `date +%s%3N` guards, zypper/apk/pkg package-manager detection) plus wiring for `dot teleport`, `dot uninstall`, `dot policy`, `dot secret-audit`, `dot completion <bash|zsh|fish|nu>`, `dot fonts patch`. Cross-shell parity for `dot secrets load --shell posix|fish|nu` and auto-secret-load in bash/fish/nushell. See [v0.2.509 release notes](https://github.com/sebastienrousseau/dotfiles/releases/tag/v0.2.509).
- **Terminal font 12 → 20** (#963). `defaults/.chezmoidata.toml` and every terminal template (alacritty, wezterm, ghostty, kitty, waybar) bumped so a fresh install reads at 20pt across the surface.
- **Themes rebuilt** (#963). K-Means CIELAB color extraction re-run over all 206 detected wallpapers → 752 theme sections. Five dark themes removed where the underlying wallpaper is inherently light-toned (hello, iphone, valentine, modern, firewatch) — their `-light` counterparts kept.
- **Zsh PATH prune** (#963). The pre-existing dedup+prune tail in `00-core-paths.sh` was gated behind `[ -z "$ZSH_VERSION" ]`, so zsh never pruned. Now runs native zsh path-array iteration for zsh (89 → 77 entries with no non-existent dirs) alongside the existing bash 4+ associative-array and bash 3.x awk paths.

### Fixed

- **Fish startup 217 ms → 119 ms** (#963). `defaults/dot_config/fish/conf.d/aliases.fish.tmpl` now writes the bash-bridge cache as `abbr --add NAME -- VALUE` instead of `alias NAME=VALUE`. Fish's `alias` builtin creates one function per entry (~183 µs); `abbr` is a command-line-time expansion at ~40 µs. Sourcing the same 878-entry cache went 170 ms → 34 ms. Cache self-heals on upgrade (staleness now also fires on the old `alias` format).
- **Scorecard code-scanning alerts** (this release, #965). Nine `TokenPermissionsID` alerts closed by adding top-level `permissions: contents: read` (least-privilege default) to workflows that only declared job-level write permissions. One `PinnedDependenciesID` alert closed by hash-locking `requirements-docs.txt` via `pip-compile --generate-hashes` and switching pages.yml to `pip install --require-hashes`.

### Housekeeping

- Bumped `package.json`, `defaults/.chezmoidata.toml`, and every managed markdown reference from `v0.2.508` → `v0.2.510` (26 files consistent).
- Pruned the stale `feat/v0.2.509` local branch (its remote was deleted at merge time).
- Retired the `.git/*.sh` session helper scripts left over from the rename + docs-theme + housekeeping PRs.

## v0.2.508 — 2026-06-30

Makes `dot apply` / `dot update` behave like an OS package-manager update —
unattended and reliable on macOS — and converts the cross-platform required
check into an always-runs gate so documentation-only PRs are mergeable.

### Fixed

- **`dot apply` / `dot update` run unattended** (#946). They no longer stall on
  chezmoi's "file changed since chezmoi last wrote it" prompt, which could not
  be answered because chezmoi always runs under `gum spin`/captured output (no
  controlling TTY) and aborted with "could not open a new TTY". They now apply
  the canonical source with `--force` by default, like `apt`/system updates;
  local drift to *managed* files yields to the source. Opt back into prompts
  with `DOTFILES_INTERACTIVE_APPLY=1`, and keep machine-local tweaks in the
  unmanaged `~/.zshrc.local` or `~/.config/zsh/rc.d.local/*.zsh`.
- **macOS apply no-op** (#946). The concurrency lock used `flock(1)`, which does
  not exist on macOS — `! flock` took the "already running" branch and made
  `dot apply` exit 0 without applying anything. It now falls back to an atomic
  `mkdir` lock when `flock` is absent (portable to macOS/BSD). The optional
  AI-provider installer menu is also gated on real interactivity (TTY + not CI).

### Changed

- **CI required check** (#944). `Test on ubuntu-latest` (path-filtered, so it
  never ran on docs-only PRs and left them unmergeable) is replaced by an
  always-runs `Cross-Platform Tests` gate that reports success when the OS
  matrix is skipped and failure when it fails.

## v0.2.507 — 2026-06-30

This release ships the **`dot ai` cockpit** — an interactive Bubble Tea TUI for
the 18-agent AI fleet with a local Claude gateway — grows the bundled theme
collection from 150 to 173, and repairs the AI provider install path
end-to-end.

### Added

- **`dot ai` cockpit** — bare `dot ai` now opens an interactive Bubble Tea TUI
  to browse, launch, install, and monitor the AI fleet, backed by a local Claude
  gateway and an 18-agent provider roster (#936).
- **Floral theme collection** — grew the bundled themes from 150 to 173 (#940).

### Fixed

- **AI installs (`dot ai install`):** three reproducible failures (#942).
  - *Duplicate banner* — the cockpit shells out to `dot ai install <tool>` once
    per tool, and each subprocess reprinted the full command banner. `dotExec`
    now sets `DOT_AI_RAW=1`, matching the streaming path.
  - *amp* — `@sourcegraph/amp` publishes only prerelease-tagged npm versions,
    which mise filters out (`@latest` resolves to nothing). Routed to amp's
    native installer, pre-resolving `AMP_VERSION` to dodge an upstream bug where
    amp's own version fetch builds a malformed checksum URL.
  - *Cursor* — `cursor.com/install` User-Agent-sniffs and served marketing HTML
    to curl (failing the shebang check); now sends a browser UA to fetch the
    real install script.
  - Also unified the `dot ai tools` fallback install loop (amp/cursor/goose/grok
    were silently skipped there) and added an `ai` command summary line.
- **CI / release reliability:** theme nil-guard and shfmt-absent skip (#939);
  repinned a stale reusable shell-lint workflow and hardened pin-bumping (#937);
  the distribute workflows now poll for the release asset before consuming it
  (#931).

## v0.2.505 — 2026-06-04

Claude Code is no longer installed through mise/npm. npm 11 silently drops
the platform-native `optionalDependency` on global installs, leaving a stub
binary that errors with "claude native binary not installed". The fix moves
Claude Code to Anthropic's native installer and audits the other AI tools for
the same class of bug. This release also repairs Linux install breaks, hardens
cross-platform shell parity (bash, fish, nushell), and adds SPDX license
headers across the source tree.

### Fixed

- **Claude Code install** — switched off the mise `npm:@anthropic-ai/claude-code`
  pin onto Anthropic's native installer (`~/.local/bin/claude`, self-updating),
  which fetches the platform binary directly and sidesteps the npm 11
  optional-dependency bug. Bootstrap (`run_onchange_15-ai-cli-tools`), `dot ai`,
  and `dot apply`'s "install missing providers" flow all install Claude Code
  natively now instead of reinstalling the broken package.
- **Linux install breaks (every distro):** Neovim fetched `nvim-linux64.tar.gz`,
  an asset Neovim renamed after v0.10.3, so the pinned v0.11.6 download 404'd and
  aborted the whole provision run — now arch-aware (`nvim-linux-{x86_64,arm64}`)
  with ARM support; AIChat defaulted to a `latest` tag baked into the asset
  filename (also a guaranteed 404) — now pinned via `AICHAT_TAG`.
- **Clipboard (`cb`):** crashed under `set -u` on non-Wayland Linux
  (`$WAYLAND_DISPLAY` was referenced unguarded); added `command -v` guards, an
  `xsel` fallback, and clear per-backend (Wayland/X11/WSL) error messages.
- **Bash parity:** `dot_bashrc` shipped ~14 hardcoded aliases and none of the
  library functions — it never sourced the shared `~/.config/shell/*` hub. It
  now loads the same layers zsh does (867 aliases + 185 functions), matching its
  documented Tier-1 "Full" status.
- **fish/nushell `goto`/`cdls`:** these change directory but were run through a
  `bash -c` subshell, so the `cd` was discarded — they silently no-op'd.
  Reimplemented natively (fish functions; nushell `def --env`, the only form
  whose `cd` propagates to the caller).
- **Docs:** fixed 18 hardcoded absolute markdown links (`/home/seb/.dotfiles/…`,
  broken on GitHub and on any other machine) to file-relative paths.

### Changed

- **Removed two redundant mise pins** uncovered while auditing the other AI
  tools: `npm:codex-cli` (a legacy package — codex.js — that collided on the
  `codex` bin name; Codex is already provided by the native `codex` pin) and
  `npm:opencode-ai` (a broken-wrapper duplicate of the native `opencode` pin).
  Both shims already resolved to the native builds, so runtime behaviour is
  unchanged. copilot/gemini/qwen/zai were checked and are unaffected.
- **Extracted** the shared Claude native-installer helper and the AI
  provider→mise-package map into `lib/dot/ai-install.sh`, removing duplication
  across `dot ai` and `dot apply`.
- **Cross-distro robustness:** Debian/Ubuntu now symlink `~/.local/bin/{bat,fd}`
  to `batcat`/`fdfind`; a missing apt/dnf/pacman warns loudly instead of silently
  installing nothing; WSL gets a best-effort `wslu` install for `wslview`. fish
  and nushell now export `EDITOR`/`VISUAL`/`PAGER` to match the zsh/bash profile.
- **Licensing:** added `SPDX-License-Identifier: MIT` headers (SPDX-first / REUSE
  form) and normalized the copyright line to `Sebastien Rousseau` across 831
  repo-only source files; dropped the contradictory `All rights reserved.`.
- **README** — fixed the OpenSSF Best Practices badge (was linking to the
  new-project form with a static label; now the live `cii/percentage/12840`
  endpoint linked to the real project).

## v0.2.504 — 2026-06-03

First-class **stock-macOS** support: the installer and the entire `dot` CLI
now run correctly under the system `/bin/bash` 3.2, and the mise↔chezmoi
ownership conflict is resolved structurally. Found by performing a clean
end-to-end install and exercising every command. Full suite: 4821/4821.

### Fixed

- **macOS bash 3.2 compatibility** across the CLI, which had assumed bash 4+:
  - iTerm2 profile `run_onchange` used `declare -A` and aborted `chezmoi apply`; rewritten with indexed arrays.
  - `dot ai` used `local -n` namerefs + `declare -A`; now passes arrays by value and reads probe results from the cached TSV via `awk`.
  - `dot security-score` and the `matrix` effect dropped `declare -A` (parallel arrays / `case`).
  - `dot fleet apply` replaced the bash-4.3 `wait -n` throttle with a portable PID-FIFO; `dot theme rebuild` now requires bash 4 and re-execs under a newer bash when available.
  - `dot perf` / `dot bundle` / `dot benchmark` / `dot doctor` / `dot sync` and the pre-commit hook: empty-array `"${arr[@]}"` under `set -u` aborted on bash 3.2; cleanup traps now use the `set +u` idiom.
  - `.bashrc` guards bash-4-only `shopt` options (`globstar`, `dirspell`, `autocd`).
- **Installer:** backup loop no longer recurses into live `~/.ssh/agent` sockets; seeds git identity from `git config --global` and prints a hint when none is set. The v0.2.503 migration no longer exits non-zero under `set -e`.
- **mise:** the chezmoi-managed base config moved to `conf.d/00-dotfiles.toml`; `~/.config/mise/config.toml` is now mise's `.chezmoiignore`'d writable global, so `mise use -g` no longer drifts the source. An absent `gh` token no longer breaks the whole config, and the x86_64-only hyperfine aqua package (unrunnable on Apple Silicon) is no longer managed by mise. `version-sync.sh` no longer hangs on a non-TTY stdin (rg now searches the tree, not stdin) and respects `EXCLUDE_FILES`.
- **`Brewfile.cli`:** add `zellij` and `sops` (checked by `dot doctor`, previously absent).
- **`dot version-locks`** is `.chezmoiroot`-aware again (had reported "config not found" since the v0.2.503 reorg).
- **Tests:** robust large-HEIC wallpaper dimension probe (`-ping`); `test_perf_percentiles` trusts mise in its isolated environment.

### Changed

- Homebrew/Scoop release installers now actually install (sha256 substitution, Scoop `extract_dir` + Windows entrypoint).

## v0.2.503 — 2026-05-30

Polish + cross-platform + Scorecard release **plus** the
incremental repo reorganisation per
`docs/operations/RFC_v0_2_503_reorganization.md`. The reorg ships
in phases across this PR; each phase is independently atomic and
verified by `dot lint` + the existing test matrix.

### Added

- **`STRUCTURE.md`** + **`scripts/README.md`** — repo-map docs so a new contributor orients in <30s. Explains the chezmoi naming contract that forces the current layout.
- **`MAINTAINERS.md`** + **`GOVERNANCE.md`** — formal single-maintainer declaration + decision/RFC process. Required by the OpenSSF Best Practices badge application; contextualises the Scorecard `Code-Review` 0/30 score.
- **`docs/operations/ROADMAP_V0_2_503.md`** — seven-workstream scope for this release.
- **`docs/operations/RFC_v0_2_503_reorganization.md`** — 267-line formal RFC for the v0.2.503 framework / user-config split. Covers target layout (Debian/aws-cli discipline), `.chezmoiroot` strategy, 7-step idempotent migration script, distribution surface table, ~5-week implementation plan.
- **`docs/security/VERIFY_RELEASE.md`** — end-user "how to verify a `dot` release" walkthrough. Three independent attestations (SBOM, Cosign keyless, SLSA L3); identity-bound `cosign verify-blob` recipe; `slsa-verifier` recipe; one-liner `verify-dot-release` shell function.
- **`install/{homebrew/dot.rb, scoop/dot.json, aur/PKGBUILD}`** + **`install/README.md`** — distribution-channel scaffolds for the v0.2.503 standalone-CLI tarball. Publication checklist per channel.
- **`scripts/qa/check-version-consistency.sh`** — catches drift between `.chezmoidata.toml` (source-of-truth) and the 8 human-visible version surfaces (CLI banner, man page, bento splash, README badge, etc.). `--quiet` mode for hooks; `--fix` for auto-correct. Wired into pre-push.
- **`tools/docs/generate-command-index.sh`** — regenerates `docs/manual/command-index.md` from `dot help all` (caught 9 missing entries, 58 → 67). `--check` mode for CI gating.
- **`scripts/qa/scorecard-snapshot.sh`** — refreshes the per-check table in `docs/security/SCORECARD.md` from `api.scorecard.dev` between BEGIN/END markers.
- **`.github/workflows/doc-drift.yml`** — gates PRs on the two new `--check` hooks (`command-index`, `version-consistency`).
- **`.github/ISSUE_TEMPLATE/scorecard.md`** — Scorecard regression issue scaffold matching the triage flow in `SCORECARD.md`.
- **`.github/PULL_REQUEST_TEMPLATE.md`** — Euxis signature block embedded so contributors don't trip `pr-signature.yml`.
- **`tools/ci/windows-smoke-test.ps1`** — native `chezmoi apply --dry-run` check (no bash required). Catches Go-template syntax errors on Windows.
- **README badges** — OpenSSF Best Practices ("in progress") + License (MIT) shields.

### Fixed

- **`LICENSE`** — normalised 1284-line MIT+GPL3+GPL2+Apache+QRCode conglomerate to clean 21-line MIT. GitHub's license detector now returns `MIT` (was `NOASSERTION`). Expected effect: Scorecard `License` 9 → 10.
- **`.github/workflows/scorecard.yml`** — wired `SCORECARD_TOKEN` PAT path (falls back to `github.token` when absent). Unlocks `Branch-Protection` + `Webhooks` checks from `-1` to 10 once the maintainer creates the PAT (one-time setup, ~5 min per `docs/security/SCORECARD.md`).
- **Version sweep** — `scripts/version-sync.sh 0.2.503` across 26 files, plus manual fixups for `bento.sh` banner and man-page header (not in version-sync's file list — now in `check-version-consistency.sh` spec to prevent recurrence).

### Documentation

- **`docs/security/SCORECARD.md`** — added baseline snapshot (7.6 / 10 at 2026-05-17), updated "Closed this cycle" log with v0.2.502 + PR #894 SLSA backfill, full PAT-creation walkthrough for unblocking the `-1` checks.

### Reorganisation (per RFC, incremental phases)

- **Phase 0 — RFC in-scope.** `RFC_v0_2_503_reorganization.md` repositioned from "deferred to v0.3.0" to "shipping in v0.2.503". CHANGELOG + ROADMAP + scaffold docs updated.
- **Phase 1 — `lib/` move.** `scripts/dot/lib/{utils,ui,platform,log,bento}.sh` → `lib/dot/{utils,ui,platform,log,bento}.sh`. Every `source` path in `scripts/dot/commands/*.sh` updated. Non-breaking for end users (lib is not chezmoi-deployed).
- **Phase 2 — `bin/` dispatcher.** `dot_local/bin/executable_dot{,-bootstrap,-theme-sync,-load-benchmark-pty}` → `bin/<name>`. Chezmoi-deployed wrappers at the old paths still exec the canonical for backward compatibility on existing installs.
- **Phase 3 — `share/` man + completions.** Man pages, zsh completions, and shell-init fragments moved out of `dot_local/share/` into top-level `share/`.
- **Phase 4 — `defaults/` + `.chezmoiroot`.** All 33 chezmoi-tracked source paths (every `dot_*`, `private_dot_*`, `run_onchange_*`, `.chezmoi*`) moved into `defaults/`; `.chezmoiroot=defaults` activated. Chezmoi natively re-bases its source-root; the included migration script (`install/migrate/migrate-v0_2-to-v0_2_503.sh`) handles the user-machine transition idempotently. Repo root is now strictly project metadata + framework distribution; all user-config payload lives under `defaults/`. New `resolve_chezmoi_source_dir()` in `lib/dot/utils.sh` separates chezmoi-content lookups from repo-root lookups.
- **Phase 5 — `tools/` split.** Repo-only ops (`scripts/{ci,release,maintenance,docs}` → `tools/{ci,release,maintenance,docs}`). 68 references swept across workflows, CHANGELOG, READMEs, PR template, PowerShell parity matrix.
- **Phase 6 — automatic seamless migration.** `install/migrate/migrate-v0_2-to-v0_2_503.sh` wired into `install.sh`, `chezmoi run_before` hook, and direct invocation. State-file guard at `$XDG_STATE_HOME/dotfiles/v0_2_503-migration/.complete` ensures real work runs exactly once per host. Snapshot kept for inspection.

### Big-ticket features (per "what else" iterations)

- **`dot env emit`** — v1 workstation-environment manifest emitter. JSON Schema 2020-12 at `docs/schema/dot-env-v1.json`; doc + downstream-consumer matrix at `docs/operations/MANIFEST.md`. Closes R3 §7.4 strategic-reversal item ahead of the 2026-09-17 / 2026-09-11 AGNTCon + EU CRA windows.
- **Native PowerShell module** — `scripts/dot/powershell/Dot.psm1` + `bin/dot.ps1` dispatcher. `dot version` / `dot help` / `dot agents check` now zero-bash on Windows. POWERSHELL_PARITY.md updated, smoke test extended.
- **OSS-Fuzz scaffold** — `oss-fuzz-integration/` ready-to-PR upstream bundle. Two native Go fuzzers (`FuzzValidateName`, `FuzzInitURLResolver`) verified at 2M+ execs each. CI workflow runs them per PR. `docs/security/FUZZING.md` covers onboarding + when-to-add-a-harness.

### Phase 1 hardening (test framework + CI quality gates)

- **`DOT_STRICT=1` test mode** — promotes silent `command not found` / `unbound variable` inside `cov_exercise_functions_file` to test failures. Default stays tolerant. Caught the `require_source_dir` regression that escaped pre-v0.2.503 review. Regression test in `tests/unit/misc/test_cov_strict_mode.sh`. Documented in `docs/operations/TESTING.md`.
- **Pre-commit drift gates** — `command-index-drift` + `version-consistency` hooks added to `.pre-commit-config.yaml`. Same checks already enforced by `doc-drift.yml` in CI; now also caught at commit time so contributors don't push, wait for CI, and then re-push.
- **FINAL SUMMARY per-file failure list** — `test_runner.sh` now lists which test files failed (not just the total count). With 4000+ assertions a single failure was previously a 3-grep search through the run log; now it's at the bottom of the summary.
- **`perf-baseline.yml` on push** — added `feat/**` push trigger so regressions catch at PR time, not the Monday cron. Cron remains source-of-truth for the recorded baseline; push runs are measure-only and emit `::warning::` on regression.
- **`bump-reusable-pins.yml`** — auto-PR caller workflows (`ci.yml`, `ci-enforced.yml`) when a `reusable-*.yml` merges to master. Closes the two-commit fix-and-bump-pin foot-gun that bit us on the shfmt globstar fix. SHA-pinned, signed via `ACTIONS_BOT_SIGNING_KEY`.

### Phase 2 release engineering (signing + packaging + distribution)

- **`release-package-dot.yml`** — on `release.created`, stages bin/lib/share/completions into a canonical `dot-VERSION/` tree and produces a deterministic `dot-VERSION.tar.gz` + `.zip` (sorted, TZ=UTC, owner=0, zip -X -D). Reproducible across runners. Uploaded as release assets.
- **`security-release.yml` manifest job** — on `release.published`, builds `ALL_SHA256SUMS` over every release asset and Cosign-keyless-signs it. One signed manifest now covers every artefact in a release; downstream verification is `cosign verify-blob ALL_SHA256SUMS` then `sha256sum -c ALL_SHA256SUMS`. SBOM + SLSA L3 provenance were already in place.
- **`release-attestation-check.yml`** — weekly watchdog that walks the latest release, asserts the full attestation bundle (SBOM + sig + cert + intoto + manifest + sig + cert) is present, opens / comments on a tracking issue if anything is missing. Catches silent upload failures the release-time workflow can't detect.
- **`release-distribute-{homebrew,scoop,aur}.yml`** — three sibling workflows that, on `release.published`, hash the new release artefacts and ship to each distribution channel. Homebrew + Scoop open PRs to `sebastienrousseau/{homebrew-tap,scoop-bucket}`. AUR pushes directly to `ssh://aur@aur.archlinux.org/dotfiles-git.git` via `AUR_SSH_KEY`. All idempotent, signed-commit, default-branch-detection, comment-on-existing-PR for re-runs. Three were drafted by Mistral Vibe via the new delegator (see below); 49% saved vs Claude.
- **`docs/operations/RELEASE_PIPELINE.md`** — end-to-end map of all five release workflows, their triggers, dependencies, and secrets. Single source of truth for the release flow.

### AI cost optimization

- **`/vibe` Claude Code skill** ported from [pcx-wave/vibe-skill](https://github.com/pcx-wave/vibe-skill) and shipped via chezmoi to `~/.claude/skills/vibe/`. Delegates coding tasks to a cheap model (Mistral Vibe / DeepSeek / Gemini Flash) while Claude only sees the final `git diff` + tool-call summary (~500-1500 tokens per delegation regardless of how many file reads happen internally). Slash commands: `/vibe`, `/vibeon`, `/vibeoff`, `/vibestatus`, `/vibe-model-pick`, `/vibe-model-clear`, `/vibe-report`.
- **`dot ai delegate "<prompt>"`** + **`dot ai cost [--since N]`** — CLI shims so the same delegator + cost reporter work from the terminal without Claude Code. Both expose the underlying `vibe-delegate` / `delegate-report` tools deployed by the skill.
- **Unified provider log** — every `dot ai <provider>` invocation now appends a JSONL entry to `~/.local/share/delegate-runs.jsonl`, so `dot ai cost` reports spend across Claude + Gemini + Aider + Vibe etc., not just Vibe. Token-level fields stay zero for providers that don't surface them; the report tolerates the gap.
- **`docs/architecture/AI_COST_OPTIMIZATION.md`** — pattern, prices, deployed pieces, state files, provider coverage matrix, future work (budget guard, prompt cache, model routing, rate-limit awareness).

## v0.2.502 — 2026-05-17

### Added

- **`dot agents`** — multi-harness AI agent context generator. `CLAUDE.md` is canonical; `dot agents render` mirrors it into `AGENTS.md` (the cross-harness standard read by Codex/Copilot/Cursor/Windsurf/Amp/Devin), `.cursor/rules/dotfiles.mdc`, and `.codex/config.toml`. `dot agents check` returns rc 0 when in sync (suitable for a pre-commit hook). Round-1 audit gap #1 closed.
- **`dot init <github-user|owner/repo|url>`** — analogue to `chezmoi init`. Bootstrap a foreign dotfiles repo through this framework's harness with `--dry-run`, `--no-apply`, `--force` flags; an interactive trust prompt warns before SSH/HTTPS clones; refuses plain HTTP. Owner/repo and bare-user shorthands validated against `[A-Za-z0-9._-]+` to block shell-metacharacter injection.
- **`dot fleet apply`** — SSH-based fleet reconciliation across hosts in `~/.config/dotfiles/fleet.toml`. Parallel fan-out (default 4-way) via background-job semaphore (no `xargs -d` so it works on macOS BSD xargs too). Hostnames validated against `[A-Za-z0-9._@:+/-]+` before fan-out. Flags: `--host`, `--cmd "<shell>"` (trust boundary — warning shown), `--dry-run`, `--jobs <n>`. Per-host stderr captured; collision-safe `mktemp -d -t dotfiles-fleet.XXXXXX` temp dir.
- **`dot registry`** — JSON-indexed module marketplace scaffold. Subcommands `list / search / info / install / url / set-url`. Default registry at `https://sebastienrousseau.github.io/dotfiles/registry.json` (published from `docs/registry.json` via GitHub Pages). 6h cache TTL; `set-url` validates HTTPS-only (or `file://` for testing) and writes atomically via `mktemp + mv`. Full module contract + contribution flow in [`docs/operations/REGISTRY.md`](docs/operations/REGISTRY.md).
- **Sub-100ms CLI cold-start gate** — `tools/ci/dot-cli-startup-bench.sh` measures median dispatcher startup under a clean `env -i`. New workflow `.github/workflows/dot-cli-bench.yml` runs on every PR touching `bin/dot` or `scripts/dot/**`. Current observation: median 47ms locally; CI budget 250ms.
- **`docs/operations/HARD_AUDIT_2026.md`** — consolidated audit (round 1 + round 2 addendum) of operational reliability, performance, documentation accuracy, cross-platform parity, security posture, competitor positioning, 2026 industry trends, and adoption playbook. Produced from twelve parallel research-agent runs.

### Fixed

- **`install.sh`** — removed the unverified `get.chezmoi.io` curl|sh fallback. The SHA256-verified installer is now the only path; if it fails, we refuse to bootstrap rather than silently degrading (H6).
- **`scripts/dot/lib/platform.sh`** — `dot_path_to_unix` / `dot_path_to_native` return rc 2 with a stderr error when called in WSL without `wslpath`, instead of silently echoing a Windows-format path (H9).
- **`bin/dot`** — user-provided custom commands now run in a subshell so a `exit` in the user script can't kill the whole CLI (H1).
- **`scripts/dot/commands/fleet.sh`** — `dot fleet namespace set` writes via `mktemp + mv` instead of the brittle GNU/BSD `sed -i` dance (H3).
- **`dot_config/zsh/dot_zshrc.tmpl`** — `_cached_eval` uses `mktemp` instead of `${cache}.tmp.$$`, eliminating the PID-collision race under shell recycling (H4).
- **`scripts/dot/commands/meta.sh`** — cache-clear uses `find ... -type f -delete` with a directory guard instead of `rm -rf "$cache_dir/zsh"/*-init.zsh`, which expanded the literal pattern when no files matched (H5).
- **`scripts/dot/commands/agent.sh`** — replaced three `set +e / "$@" / set -e` blocks with idiomatic `if !` so bash errexit suspension is implicit (M4).
- **`scripts/dot/commands/core.sh`** — `cmd_status` captures chezmoi stderr and inspects the exit code, so a chezmoi crash is now distinguishable from a clean tree (M1).
- **`scripts/dot/lib/ui.sh`** — `ui_run_cmd` guards the rc-file read with `[[ -s ]]` to avoid races between the subshell write and the parent read (M3).
- **`scripts/security/lock-configs.sh`** — pre-checks `sudo` availability and TTY attachment before attempting `chattr +i`, instead of failing per-file in automation (M5).
- **`tools/ci/install-chezmoi-verified.sh`** — unsupported-architecture error now names the supported set (x86_64/amd64, arm64/aarch64) and points at the upstream release page (M7).
- **`docs/manual/03-reference/01-dot-cli.md`** + **`docs/manual/command-index.md`** — removed six commands that were documented but never shipped (`dot verify`, `dot benchmark`, `dot prewarm`, `dot clean-cache`, `dot remove`, `dot update`). Added the new `agents`, `init`, `registry`, and `fleet apply` sections (C3).
- **Version drift** — bumped `v0.2.501` → `v0.2.502` in five doc surfaces (`docs/manual/00-introduction.md`, `docs/manual/_toc.yml`, `docs/index.md`, `docs/manual/03-reference/02-config-files.md` × 2) (C2).
- **`docs/manual/index.md`** — new landing page for `https://doc.dotfiles.io/manual/` (the Jekyll site was 404ing because `jekyll-readme-index` had no `README.md`/`index.md` to render in `docs/manual/`).

### Security

- **`scripts/dot/commands/agents.sh`** — render only writes when the resolved root contains `.chezmoidata.toml`, so a user running `dot agents render` from inside an unrelated git repo can't accidentally write agent configs there. Output files get explicit `chmod 0644`.
- **`scripts/dot/commands/init.sh`** — owner/repo and bare-user shorthands are now validated against `[A-Za-z0-9._-]+` before URL construction.
- **`scripts/dot/commands/fleet.sh`** — hostnames validated against `[A-Za-z0-9._@:+/-]+` before SSH fan-out; an attacker controlling `fleet.toml` can no longer inject shell metacharacters.
- **`scripts/dot/commands/registry.sh`** — `set-url` refuses non-HTTPS schemes (with a `file://` exemption for local testing) and writes config atomically.

### Documentation

- **`docs/operations/REGISTRY.md`** — module contract, JSON schema, and contribution flow for the new registry.
- **`docs/operations/COVERAGE.md`** — documents the achieved unit-test floor (~47%) plus the structural ceiling for xtrace-only instrumentation; closes #883.

### Round 3 (HARD_AUDIT_2026.md Part 7)

- **C1 closed — GPG disclosure key published.** Generated `security@sebastienrousseau.com` ed25519 + cv25519 keypair, fingerprint `55AFAD364FD9DB3819E61F0C8D688FAFA9144693`, expires 2029-05-15. Published to WKD at `sebastienrousseau.github.io/.well-known/openpgpkey/`. Repo carries the armored public key at `docs/security/security-pubkey.asc`.
- **`.github/workflows/verify-gpg-wkd.yml`** (N1) — imports both the in-repo `.asc` and the live WKD-fetched key, compares fingerprints, fails loud on mismatch. Runs on push/PR + weekly schedule (Mondays 09:00 UTC). Wires the expiry monitor as the final step.
- **`scripts/security/check-disclosure-key-expiry.sh`** (N2) — monitors the 2029-05-15 expiry; warns at 90 days remaining, fails CI at 30 days.
- **`dot fleet apply --verify-hosts`** (N4) — closes the TOFU window per-invocation. Aborts the apply unless every host in `fleet.toml` is already present in `~/.ssh/known_hosts`.
- **`install.sh` Charm GPG pin** (N5) — pins `CHARM_GPG_EXPECTED_FPR=C026D31B92F9BBE91D5DB75AB07AE17C9E0A6585`; aborts (removing the keyring file) on mismatch.
- **`scripts/lib/secrets_provider.sh` exit codes** (N6) — `dot_secrets_get` now returns `2` (no provider), `3` (provider returned empty / key not found), or the provider's own rc; stderr names provider + key for diagnosis.
- **R3 docs drifts** — purged 5 orphan dispatch routes + 1 orphan help-table entry in `bin/dot`; relabelled `dot agents` + `dot fleet apply` from "Full" to "Stub (bash-bridged)" on Windows-native in `docs/reference/POWERSHELL_PARITY.md`; corrected Microsoft Build 2026 date from "2026-05-19 in Seattle" to actual `2026-06-02 to 2026-06-03 in San Francisco (Fort Mason)` in `ROADMAP_2026.md`.
- **R3 mocked-SSH test catches 2 real bugs.** `tests/unit/fleet/test_fleet_apply_mocked_ssh.sh` (5 tests with PATH-shim overriding `ssh`) caught: (a) subshell counter loss via pipe — fixed with `done < <(printf '%s\n' "$entries")`; (b) RETURN trap referencing `local tmpdir` failed under `set -u` — fixed with `printf -v _cleanup 'rm -rf %q' "$tmpdir"`.
- **R3 strategic reversal.** Ship `dot env emit` BEFORE `--attest` (driven by AGNTCon Amsterdam 2026-09-17 deadline + EU CRA SBOM binding 2026-09-11). Full rationale in `HARD_AUDIT_2026.md` §7.4.

### Round 4 (HARD_AUDIT_2026.md Part 8)

- **Zero reliability findings** — second consecutive 0-finding round. 4 of 5 candidate perf claims were false positives (SSH-agent guard, completion-chain forks, FNM completion, carapace defer) caught by live verification.
- **Documentation completeness fixes:**
  - `README.md` — removed 4 stale references to ghost commands `dot verify` / `dot benchmark` / `dot prewarm` (none ship). Routed to `dot secrets verify`, `dot perf`, `dot health`.
  - `docs/manual/03-reference/05-feature-flags.md` — documented the 9 previously-undocumented flags (`alias_wrapper`, `zellij`, `fuzzel`, `mako`, `foot`, `kanshi`, `touch`, `t2`, `surface`) with purpose + platform applicability + requirements.
  - `dot_local/share/man/man1/dot.1` — header bumped `v0.2.500 → v0.2.502`, `April → May 2026`.
  - `dot_config/zsh/rc.d/30-options.zsh.tmpl` — completion-block comment no longer references the non-existent `dot prewarm`.
- **Strategic outputs** (deferred to follow-up PRs / R5):
  - OSPS Baseline v2026.02.19 Level-2 adoption path documented as the cross-walk for EU CRA Article 24, NIS2 Article 21, SSDF v1.2.
  - **R5 headline** identified: Shai-Hulud-class personal-device defence (credential-locality policy + honeytoken + shell-init integrity manifest + post-incident playbook in `SECURITY.md`).
  - **Strategic leapfrog** identified: `dot attest --format=trustmee-wasm` — Wasm-verifiable workstation attestation (composes SLSA-Graduated + arXiv:2602.13148 TrustMee + MCP-exposed workstation state). No competitor reaches this.
  - **Top-5 de-facto adoption gaps**: Homebrew tap, AUR `PKGBUILD`, Scoop manifest, Hyprland config, awesome-dotfiles listing.

### Performance + polish (post-R4)

- **`dot_config/zsh/dot_zshrc.tmpl`** — `_cached_eval_impl` writes use `>|` (force-clobber) instead of `>`, so the just-`mktemp`'d temp file is not rejected when the user has `setopt noclobber` set globally via `dot_config/shell/05-core-safety.sh:15`. Fixes the `_cached_eval_impl:64: file exists` warning surfaced on every interactive shell with a cache miss.
- **`dot_config/shell/00-core-paths.sh.tmpl`** — system paths added via `path_prepend` (which removes duplicates first) instead of `PATH="...:${PATH}"`, eliminating the duplicate-system-path bloat that accumulates when the parent shell already had those entries (macOS launchd default).
- **`dot_config/zsh/dot_zshrc.tmpl`** — re-apply `typeset -U path` after `_dotfiles_async_init` runs cached `export PATH=...` from mise/atuin/etc, since those bypass zsh's `-U` flag on the `path` array.
- **`scripts/diagnostics/doctor.sh`** — only flag tools that actually emit shell-init eval and are not already lazy-loaded; raise PATH-length thresholds (60 ok / 120 warn) to match a populated mise-managed dev machine; skip `nu` when `cached_eval.nu` is present.
- **`dot_config/git/hooks/executable_commit-msg`** — replaced hardcoded `/Users/seb` path with `${HOME}` so the hook is portable across hosts.
- **`dot_config/fish/conf.d/{direnv,mise-activate}.fish`** — empty shadow files that override Homebrew `vendor_conf.d` to prevent eager init. fish dedupes `conf.d/` by basename, user wins. Saves ~140ms on every fish shell start; both tools are loaded lazily via `_cached_eval` in `init.fish`.
- **`.devcontainer/Dockerfile`** — chezmoi install now goes through `tools/ci/install-chezmoi-verified.sh` (SHA256-verified) instead of the unverified `curl -fsSL https://get.chezmoi.io` fallback. Closes R4 §8.3 P3 / mirrors R1 H6 fix in `install.sh`.
- **`typos.toml`** — extended file exclusions (`**/*.asc`, `**/*.pgp`, `**/*.gpg`, `**/*.sig`) to skip armored cryptographic blobs; added `fpr` / `FPR` to the allow-list (GPG `--with-colons` fingerprint column label).

## v0.2.501

### Added

- **Warp + iTerm2 theme support** — the two terminals the theme system did not yet cover are now first-class. `dot_warp/themes/dotfiles.yaml.tmpl` deploys a Warp theme; `run_onchange_22-iterm2-profile.sh.tmpl` writes an iTerm2 Dynamic Profile to `~/Library/Application Support/iTerm2/DynamicProfiles/dotfiles.json`. Both pick up the active theme's `.term` palette, so one `chezmoi apply` switches all six supported terminals (kitty, alacritty, wezterm, foot, warp, iterm2). The README's "Why this repo is different" surface lists this under wallpaper-driven themes.
- **Starship Transient Prompt (fish)** — `dot_config/fish/conf.d/init.fish.tmpl` calls `enable_transience` after the cached `starship init`, collapsing past prompts to the `[character]` glyph in scrollback. The zsh implementation is a forward-compatibility hook only — Starship 1.24.2 does not yet ship `enable_transience` for zsh (upstream tracker [starship/starship#3522](https://github.com/starship/starship/issues/3522)). Rationale and rejected alternatives recorded in [ADR-010](docs/adr/ADR-010-starship-transient-prompt.md).
- **`_cached_eval` enhancements (#847)** — `EVALCACHE_DISABLE=true` bypass for debugging, realpath sidecar pin to catch PATH-shadow swaps, file-path argument mtime check, init-failure handling (warns and returns rc instead of caching an empty output), and a new `_cached_eval_clear` helper. Applied to all three implementations (zsh, bash, fish). Adds shdoc docstrings.
- **JSON Schema for `.chezmoidata.toml`** — `config/chezmoidata.schema.json` (draft-07) plus `.taplo.toml` and a new `lint-chezmoidata` CI job. Catches typos in feature flags, profile names, `default_shell`, and `node_manager` at PR time.
- **OIDC trusted publishing for npm (#836)** — `publish-npm` workflow authenticates via OIDC instead of a long-lived `NPM_TOKEN`. Provenance is attached to every published tarball. The migration is breaking on the CI side: `NPM_TOKEN` is no longer used. **Manual followup needed before the first OIDC release**: configure Trusted Publishing on npmjs.com for `@sebastienrousseau/dotfiles` pointing at `sebastienrousseau/dotfiles` + `.github/workflows/npm-publish.yml`.
- **`lint-copyright` in `ci.yml` (#834)** — the fast CI pipeline now runs the reusable copyright-header lint. Previously only `ci-enforced.yml` ran it.
- **Test coverage roadmap, Slices 1–5d (#883)** — replaced the broken kcov pipeline with a pure bash xtrace runner that works on Linux and macOS. Eight iterations land the floor at **33% measured, 36.73% real (5,783 / 15,744 lines)**:
    - Slice 1: 2.72% baseline + xtrace runner (`PS4 + BASH_ENV`).
    - Slice 2: 12.01% — 59 shallow → deep conversions via new `tests/framework/coverage_helpers.sh` (sandbox + safe-mode entry-point exercise).
    - Slice 3: 18.90% — 47 auto-generated exercise tests + 119 deep conversions.
    - Slice 4: 19.16% — smart-output shims (`chezmoi`, `git`, `curl`) and subcommand probes.
    - Slice 5: 34.10% — `cov_exercise_functions_file` helper (source + call each function), sandbox `$HOME/.dotfiles` symlink unblocks scripts that guard on a managed checkout, `test_auto_dot_driver.sh` drives the top-level `dot` dispatcher through 70 read-only subcommands, aggregator filters lines after `set +o xtrace` (intentionally unmeasurable in `security-score.sh` / `scorecard.sh`) and structural-only keywords (`fi`, `done`, etc.).
    - Slice 5b: 33.73% honest — PS4 `set -u` guard (`${BASH_SOURCE:-}`) and SF: path canonicalization (collapses duplicate keys like `commands/../lib/log.sh`).
    - Slice 5c: 36.10% — `cov_exercise_functions_file` added to every existing auto-test.
    - Slice 5d: 36.73% — seven more auto-tests for scripts the existing-test scan had skipped.

    `MIN_COVERAGE_PCT` floor: 0 → 10 → 17 → 18 → 30 → **33** (3-point cushion absorbs cross-platform jitter).
- **GitHub Pages deploy of `docs/` to doc.dotfiles.io** — new `.github/workflows/pages.yml` builds the Jekyll site (cayman theme, kramdown, Liquid disabled for chezmoi-template snippets) and publishes on every push to master that touches `docs/**`. Replaces the old approach where `manual-publish.yml` deployed the multi-format manual to Pages.
- **PR consolidation — 8 Dependabot bumps (#839–#846)** — major bumps: `actions/deploy-pages` 4→5, `softprops/action-gh-release` 2→3, `actions/download-artifact` 4→8.0.1, `docker/setup-buildx-action` 3→4, `actions/upload-pages-artifact` 3→5, `actions/github-script` 8→9. Minor and SHA-only refreshes for `actions/cache`, `actions/setup-node`, `bridgecrewio/checkov-action`, `devcontainers/ci`, `docker/login-action`, the `github/codeql-action` family, and `trufflesecurity/trufflehog`. All actions remain pinned by full commit SHA.
- **Re-source guards** on the five shared library files where re-sourcing would corrupt state: `tests/framework/{assertions,mocks}.sh` and `scripts/dot/lib/{utils,ui,log}.sh`.
- **`tests/unit/ci/test_validate_chezmoidata.sh`** — 13 assertions covering the new schema-validator script. Restores the 100% module-coverage floor that the schema commit had broken.
- **`tests/unit/ci/test_check_*.sh`** — four new module-coverage tests for `check-insecure-tls`, `check-dangerous-chmod`, `check-regression-traceability`, and `run-coverage`. Keeps module coverage at 221/221.
- **`docs/operations/COVERAGE.md`** — documents the why-not-kcov decision (Ubuntu 24.04 bash 5.2 incompatibility) and the xtrace approach (`PS4 + BASH_ENV`).
- **`.chezmoiignore`** — new file at the repo root. Excludes 880 → 408 paths from chezmoi's managed surface: build artifacts (`coverage/`, `nightly-reports/`, `_build/`), repo metadata (`README.md`, `CHANGELOG.md`, `LICENSE`, `.github/`, `.git/`), documentation tree (`docs/`, intended for doc.dotfiles.io, not `$HOME`), and CI scaffolding (`scripts/`, `tests/`, `examples/`, `install/`, `nix/`, `config/`, `.well-known/`). Also gates `dot_warp/` to macOS via a template conditional. Before this file, any developer machine that had run the test suite locally would have ~600 MB of coverage trace data deployed under `~/coverage/` on the next `chezmoi apply`.
- **Goose and Codex CLI in `dot ai`** — both AI agents now appear in the status surface under "Agents (autonomous)". `goose` and `codex` are wired in `_ai_mise_pkg` (so `dot ai-setup` knows their install targets), in the bridge `case` (so `dot goose --pattern X "prompt"` and `dot codex --pattern X "prompt"` route correctly), and in the route table in `bin/dot`.
- **Spinner feedback on slow operations** — `dot ai` now shows `Probing N AI tools (cached for 300s)…` during the cold-cache refresh. Previously the command sat silent for 15–30s on the first run after the 5-min TTL expired.

### Changed

- **README rewrite for accuracy and readability** — three concrete inaccuracies fixed: PowerShell was incorrectly listed as Tier-3 (ADR-007 does not place it in the tier system), `dot bundle --manual` was a flag that does not exist (correct command is `dot manual --offline`), and the supported-terminal list missed Warp and iTerm2. Six coverage gaps filled (Starship Transient, JSON Schema, OIDC, `_cached_eval` enhancements, Bash as explicit Tier-1, and several previously-unmentioned `dot` subcommands). Command count corrected from "30+" to "over 80". Flesch baseline 28.3 → 42.9 raw / 47.7 prose-only.
- **Header badges unified to `for-the-badge` style** — OpenSSF Scorecard and Codespaces badges now use shields.io renderings at the same height as Build / Version / Downloads.
- **`manual-publish.yml`** — Pages-deploy steps removed. The workflow now only builds the multi-format manual and attaches it to releases.
- **Coverage runner is now Linux + macOS** — the kcov-only runner had a hard Darwin skip. The xtrace runner works on both, so the pre-commit hook can invoke it on developer machines regardless of platform.
- **`MIN_COVERAGE_PCT` in `.github/workflows/coverage.yml`** — raised from aspirational `50` (which never measured anything) to a real `10` floor based on the Slice 2 baseline. Ratchets up with each subsequent slice.
- **`dot ai` runs probes in parallel** — the 14-tool cold-cache refresh now runs via `xargs -P` (defaults to `$(nproc)` workers, override via `DOTFILES_AI_PROBE_JOBS`). Cold-cache wall-time on a fast laptop: 6.2s → 1.9s. Warm-cache (within the 5-min TTL): ~0.07s, unchanged.

### Fixed

- **`core.hooksPath` config gap** — the global `commit-msg` hook is now tracked under chezmoi and pointed at by the user's git config, so the AI-attribution trailer fires on every commit.
- **Liquid templating false-mangle of chezmoi snippets in docs** — 14 files containing `{{ … }}` Go-template syntax inside code blocks were being silently evaluated as Liquid by Jekyll. Bulk-wrapped with `{% raw %}` / `{% endraw %}`.
- **Multiple `A && B || C` antipatterns** — restructured to proper `if/then/else` blocks across `tests/fuzz/fuzz_install.sh`, `tests/snapshots/test_snapshots.sh`, three diagnostics tests, two security tests, and `tests/unit/security/test_pre_push_bypass.sh`.
- **macOS reliability gate** — the `cov_exercise_script` helper now probes for `timeout` then `gtimeout` (coreutils on macOS) before falling back to no-timeout. The previous version returned `rc=127` for every script on macOS-latest.
- **Windows chezmoi installer fallback** — `setup-chezmoi` composite action now uses the upstream installer's `-t v$version` flag on Windows (Git Bash). The previous positional-arg form made chezmoi try to run itself as a subcommand and exit non-zero.
- **Typos hook allowlist** — added 9 entries for alias names (`yout`, `hom`, `cod`, `dsk`, `dwn`, `mus`, `pic`, `wth`) and SLSA terminology (`intoto`, `writeable`) that the hook incorrectly flagged.
- **`tools/ci/check-insecure-tls.sh` and `compliance-guard.yml`** — both now exclude themselves and the `tests/` tree from the curl/wget/chmod pattern scans. The scanners were flagging their own legitimate pattern fixtures.
- **`dot health --fix` chezmoi-sync detection** — `chezmoi status` output has two columns: column 1 (last-applied vs. actual) and column 2 (actual vs. target). The health dashboard previously counted both columns, so a single uncommitted edit to a source file (column-1-only drift, normal during development) was reported as "1 file out of sync" even though `chezmoi apply` had nothing to fix. The dashboard now counts only column-2 drift (the apply-actionable kind) and surfaces source-only drift as an informational footnote.
- **`dot health --fix` post-apply verification** — `heal_chezmoi_drift` previously ran `chezmoi apply --force` via `_pkg_install`, which silenced stdout/stderr. When apply partially failed (e.g., on conflicting files), the next health-check pass showed the same drift count and the user had no signal that anything was wrong. The heal now captures the apply log, re-runs `chezmoi status` to verify the drift cleared, and reports either "✓ X file(s) synced" or "⚠ X applied, Y still drifted — run `chezmoi diff` to inspect". On hard failure, the last 5 lines of the apply log are surfaced inline.
- **`ui_spinner_stop` rc=1 on a TTY** — the function's last line was `[[ ! -t 1 ]] && printf "\n"`, which evaluates to rc=1 when stdout is a TTY. Under `set -euo pipefail`, that rc killed every caller, including `_ai_refresh_status_cache` — silently leaving the user with an empty cache file. Added explicit `return 0`.
- **macOS `xargs -I{} -n1` payload splitting** — `_ai_refresh_status_cache` originally passed `-n1` on top of `-I{}`, which on BSD-xargs triggers a quirk where the input line is word-split on whitespace. Entries like `"0|Agents (autonomous)|…"` arrived as `["0|Agents", "(autonomous)|…", …]`, garbling every probe. Removed the `-n1` (it's redundant with `-I{}`).
- **macOS `xargs` apostrophe-quote bug** — BSD-xargs reads `Block's coding agent` as an unterminated single quote, aborts parsing, and drops every record after the offending one. Switched the probe pipeline to null-delimited input (`printf '%s\0' …` + `xargs -0`). This was masking Goose's presence: it had been silently absent from `dot ai` even when installed.
- **AI dispatcher route gaps** — four bridge tools (`autohand`, `vibe`, `qwen`, `zai`) were accepted by the bridge `case` in `ai.sh` but missing from the route table in `bin/dot`. `dot autohand …` was hitting "Unknown ai command". Routes filled in.
- **`run_ai_with_context` missing handlers for Goose and Codex** — `dot codex "prompt"` and `dot goose "prompt"` would route correctly through the dispatcher and bridge case but then fall through to "Unsupported tool" because the per-tool execution case was missing. Added `codex)` and `goose)` arms.

### Security

- **OIDC trusted publishing for npm** — see Added above. Drops the long-lived `NPM_TOKEN` from CI.
- **SHA-pinned GitHub Actions everywhere** — confirmed across all workflows after the Dependabot consolidation.
- **`bash-dbgsym` not required** — the kcov-based coverage runner needed Ubuntu's debug symbols for bash, which created a supply-chain question (additional apt source). The xtrace replacement removes that requirement.

## v0.2.500

### Added

- **Wallpaper-driven theme engine** — themes are no longer hand-crafted. `extract-theme.py` uses K-Means clustering in CIELAB color space to extract dominant colors from any wallpaper image and generate a full terminal palette (16 ANSI colors, accent, bg/fg, panel, border) with WCAG AAA contrast enforcement.
- **Automatic wallpaper discovery** — `rebuild-themes.sh` scans system wallpapers (macOS `/System/Library/Desktop Pictures/`, Linux `/usr/share/backgrounds/`) and custom wallpapers (`~/Pictures/Wallpapers/`). Custom overrides system. Themes are cached and only regenerated when wallpapers change.
- **`dot theme rebuild`** — new command to regenerate themes from discovered wallpapers. Supports `--force` (ignore cache) and `--list` (show wallpapers without rebuilding). Parallel processing (4 jobs).
- **System wallpaper fallback** — when no custom wallpaper exists, `wallpaper-sync.sh` maps theme names to platform-native wallpapers before falling back to "skip gracefully".
- **HEIC → PNG auto-conversion** on Linux via `magick`/`heif-convert`/`convert`.
- **macOS accent from wallpaper** — `macos_accent` field in generated themes maps wallpaper dominant hue to macOS accent color. `dot-theme-sync` reads it from themes.toml instead of a hardcoded case statement.
- **Build artifact redirection** — Cargo, Go, pip, uv, Zig caches → `/tmp/builds/`.

### Changed

- **themes.toml is now auto-generated** — run `dot theme rebuild` after adding wallpapers. Do not edit manually.
- **Theme family derived from themes.toml** — `get_theme_family()` in `switch.sh` reads the `family` field dynamically instead of hardcoded case patterns.
- **macOS appearance refresh** — kills cfprefsd/SystemUIServer/Dock/System Settings after accent changes.
- **Graceful wallpaper fallback** — theme switching works without custom wallpapers. Core changes (colors, accent, dark/light) always apply; wallpaper is optional.

### Removed

- **Static theme definitions** — all hand-crafted theme entries replaced by wallpaper-driven generation.

## v0.2.497

### Added

- **Verified chezmoi installer** — `install.sh` prefers `tools/ci/install-chezmoi-verified.sh` with SHA256 checksum validation before falling back to `get.chezmoi.io`.
- **detect-secrets baseline** — `.secrets.baseline` for pre-commit secret scanning alongside gitleaks.
- **Lua plugin module headers** — `@module` docstrings for ui.lua, coding.lua, lsp.lua, editor.lua, dap.lua explaining plugin selection rationale.

### Changed

- **CI hardening** — Pinned `nix-installer` to SHA, removed `continue-on-error` from Home Manager build, replaced `mapfile` with portable `while read` loops.
- **Plugin version pins** — toggleterm pinned to `^2`, venv-selector uses `version = false` instead of `branch = "main"`.
- **DAP port configurable** — `DAP_DEV_SERVER_PORT` environment variable overrides default port 3000.
- **SSH template hardening** — Added `hasKey` guard for `.chezmoi.kernel` in SSH config template.
- **Test framework** — Restored `TESTS_PASSED`/`TESTS_FAILED` counter names for backward compatibility with 383 test files; fixed `mock_os` PATH restoration between test cases.
- **Documentation** — Fixed default shell reference (Zsh → Fish) in INSTALL.md, added CI badge and test runner to README, added function docstrings to `utils.sh`.

### Fixed

- **Shell compatibility** — Replaced zsh-only `unfunction` with POSIX `unset -f` in shell templates.
- **Quote nesting** — Fixed broken double-quote nesting in `run_onchange_after_fonts.sh.tmpl`.
- **Quoted expansion** — Added missing quotes around `$ZINIT_HOME` in zinit bootstrap.
- **JSON injection** — Escaped double quotes in `health.sh` JSON output fields.
- **Arithmetic portability** — Replaced `$(seq ...)` with `((i=N; i>=1; i--))` in `log-rotate.sh`.

## v0.2.496

### Added

- **Startup budget tracking** — CI now captures per-component timing from `DOTFILES_DEBUG=1` and fails on regression.
- **Behavioral unit tests** — 10 critical functions now have runtime behavior tests (extract, genpass, encode64, path_prepend, platform detection, lazy loaders).
- **Property-based tests** — `property_testing.sh` framework wired up with roundtrip, idempotence, and length-invariant tests.
- **git-cliff configuration** — Automated CHANGELOG generation from conventional commits.
- **Nix CI gate** — Home Manager activation package built and validated in CI.

### Changed

- **Performance** — Lazy-loaded `thefuck` (~200ms saving) and cached `carapace` output via `_cached_eval` (~50ms saving).
- **Starship timeout** — Reduced `command_timeout` from 2000ms to 500ms for snappier prompts in large repos.
- **PATH consolidation** — All PATH mutations now originate from `00-core-paths.sh.tmpl`; removed scattered prepends from zshenv/zprofile stubs.
- **heal.sh modular split** — Broken into domain modules (heal-shell, heal-tools, heal-perms, heal-cache) for testability.
- **dot CLI modular split** — Subcommands dispatched to individual scripts in `scripts/dot/commands/` for maintainability.

### Fixed

- **Security** — Replaced `curl|sh` pipes in `heal.sh` (starship, atuin) with download-to-temp + shebang validation. Pinned all heal.sh GitHub release versions with SHA256 checksums.
- **Security** — `install.sh` now uses the secure `install/lib/chezmoi.sh` library instead of inline `curl|sh`.
- **Security** — `dot-bootstrap` Nix installer now downloads to temp file with validation before execution.
- **Security** — Extended `insecure-tls-check` pre-commit hook to cover `.tmpl` files.
- **Security** — Added `sudo` availability guard in `heal.sh` before package manager calls.
- **Documentation** — Fixed placeholder URLs in WSL2 troubleshooting guide.
- **Documentation** — Added ADR-007 and ADR-008 to ADR index.
- **Documentation** — Linked hero-shot.svg from README; updated hero-shot to show factual `dot doctor` output.
- **Reliability** — `bench.sh` now uses `mktemp` instead of hardcoded `/tmp/bench.json`.

## v0.2.495

### Fixed

- **Installation failure (Issue #807)**: Resolved "unbound variable" errors in `install.sh` by correctly initializing color and path variables.
- **Shell Compatibility**: Fixed syntax errors when running `install.sh` with `sh` by ensuring the script runs with `bash` and updating documentation accordingly.
- **Broken Links**: Updated installation instructions in `README.md` and `docs/guides/INSTALL.md` to use the GitHub raw URL, bypassing issues with the `dotfiles.io` redirect.
- **Documentation Sync**: Synchronized versioning and installation commands across all documentation and source files.

### Changed

- **Repository Restructuring**: Reorganized non-deployed files for improved discoverability.
  - Docs categorized into `architecture/`, `guides/`, `reference/`, `security/`, `operations/` subdirectories.
  - Tests promoted to top-level `tests/` with domain-based unit test subdirectories.
  - Function templates grouped into subdirectories matching `groups.json` groups.
  - `install/helpers/` merged into `install/lib/`.
  - Renamed `.chezmoitemplates/gnome/` to `.chezmoitemplates/desktop/`.
  - Added `docs/NAMING_CONVENTIONS.md` standardization guide.
  - Added `dot_config/.module-manifest.json` for logical grouping of flat config directories.

## v0.2.493

### Added

- Implementation of `_cached_eval` for Zsh, Bash, and Fish for ultra-fast startup.
- Full integration of `zoxide` and `atuin` in Nushell with caching.
- Explicit management of `sgpt`, `poetry`, `fisher`, `micro`, and `pueue` configs.
- Robust `target_os` detection for Arch/CachyOS in `install.sh`.

### Changed

- Refactored `install.sh` to use a modular `main()` function.
- Moved XDG exports in `dot_bashrc` above interactive checks.
- Optimized Zellij configuration with 2026-ready UX (rounded corners, compact layout).

### Fixed

- Resolved 100% of security alerts regarding `apt-get` recommendations.
- Achieved 100.00% module test coverage with new maintenance tests.
- Fixed Nix profile sourcing drift in `dot_zshenv`.
- Resolved CI failures across linting, formatting, and unit test suites.



### Added

- **2026 Frontier Stack** — Full support for Fish (Autoloading) and Nushell (Structured Data).
- **Deterministic Portability** — Nix Flakes integration for bit-for-bit identical environments.
- **Async Task Management** — Integrated Pueue daemon for non-blocking background operations.
- **Local AI RAG** — `dot-ai` semantic search over your dotfiles configuration.
- **Wasm Runtime** — Wasmtime support for ultra-fast, pre-compiled Rust/Zig tools.
- **One-Command Provisioner** — `dot-bootstrap` for instant environment setup on clean servers.
- **OS Theme Sync** — `dot theme sync` to match OS appearance (macOS/GNOME).
- **Yazi Synergy** — `yy` wrapper for "cd-on-exit" directory navigation.

### Changed

- **Fish Shell** — Transitioned from monolithic aliases to a dynamic function autoloading pipeline.
- **Starship** — Added async indicators for background tasks and Nix environments.
- **Diagnostics** — `dot doctor` and `dot heal` are now mise-aware and 2026-stack compatible.
- **Neovim** — Migrated IDE toolchain (LSPs/Linters) into the Nix Flake.

## v0.2.491

### Added

- **Fast mode** — `DOTFILES_FAST=1` skips heavy startup work for the quickest first prompt.
- **Runtime toggles** — `DOTFILES_DEFER_ZINIT` and `DOTFILES_ENABLE_COLORS` controls.
- **Ultra-fast mode** — `DOTFILES_ULTRA_FAST=1` runs a minimal init path.
- **Minimal prompt** — `DOTFILES_ULTRA_FAST_PROMPT=1` keeps the ultra-fast prompt lightweight.
- **AI opt-in** — `DOTFILES_AI=1` enables AI helper scripts.

### Changed

- **Deferred tool init** — Atuin, Starship, Zoxide, and FZF now load after the first prompt.
- **Zinit bootstrap** — Deferred by default to reduce first-prompt latency.
- Updated all version references to v0.2.491.

### Documentation

- Added performance mode guidance and updated benchmark wording to reflect real-world variance.

## v0.2.478

### Added

- **Lazy alias loading** — Tool-specific aliases (~137KB across 35+ categories) now load after the first prompt via a `precmd` hook, keeping shell startup fast while retaining full alias coverage.
- **GPG signature verification** in `install.sh` — Verifies chezmoi release checksums against the upstream GPG signature with graceful degradation when `gpg` is unavailable.
- **Unit tests for all refactored scripts** — 100 new tests across 7 test files covering alias split, lazy hooks, FNM fix, PATH entries, GPG verification, CI pinning, gitleaks config, heal.sh fixes, and `dot new` Python guard.

### Changed

- **Alias split architecture** — Separated monolithic alias template into eager (`90-ux-aliases.sh`, 14 core categories) and lazy (`91-ux-aliases-lazy.sh`, 35+ tool categories).
- **FNM triple initialization fixed** — Removed eager `eval "$(fnm env)"` from `.zshrc` and duplicate lazy-load block from `30-options.zsh`; single lazy-load via wrapper functions remains.
- **CI chezmoi version pinned** to v2.47.1 with correct `-t` tag flag (was `-v`, which is invalid for `get.chezmoi.io`).
- **`dot_zshenv` PATH entries** — Added idempotent `~/.local/bin` and `/opt/homebrew/bin` PATH guards so tools are available before `.zshrc` loads.
- **`dot new` Python guard** — Moved Python pre-flight check before filesystem operations to avoid creating empty directories on failure.
- Updated all version references to v0.2.478.

### Fixed

- **`heal.sh` SC2015** — Replaced `A && B || C` pattern with proper `if/then` to satisfy shellcheck.
- **`heal.sh` shfmt formatting** — Fixed case branch spacing and pipe operator alignment.
- **Gitleaks false positive** — Allowlisted chezmoi GPG public key fingerprint via inline annotation and commit SHA.

### Documentation

- Added shell startup flow (16 phases) to `ARCHITECTURE.md` with rc.d and shell/ load order tables.
- Added alias system documentation covering eager/lazy split, glob ordering, and manifest convention.
- Added startup flow diagram to `README.md`.

## v0.2.477

### Added

- **Topgrade provisioning parity** across macOS, Linux, and WSL
  - Added `topgrade`, `mise`, `rustup`, `tmux`, `pipx`, `ruby`, `yazi` to Brewfile.cli
  - Added Linux binary installs for topgrade, mise, yazi with SHA256 verification
  - Added rustup via official installer with `--no-modify-path`
  - Added `cargo-install-update` for topgrade's cargo step
  - Added `gh` (GitHub CLI) to Linux package managers
  - Added `tmux`, `pipx`, `ruby` to Linux system packages
  - Created `run_onchange_12-tmux-plugins.sh.tmpl` for tpm provisioning
  - Added chezmoi-managed `topgrade.toml.tmpl` with platform-specific disable lists
  - Moved stylua and delta installs after rustup so cargo is available
  - Replaced yazi hint-only block with actual binary download

- **Security and GPG**
  - Added `gnupg` to Brewfile.cli and Linux package lists (#381)
  - Updated GPG agent cache TTL to 1 day (86400 seconds) (#392)

- **Node.js tooling**
  - Added `.npmrc` config with scoped registries support (#439)
  - Added `.yarnrc.yml` for Yarn Berry configuration (#440)
  - Added `.noderc` for Node REPL configuration (#271)
  - Added `eslint_d` global install for fast linting (#441, #267)
  - Added `prettier_d` global install for fast formatting (#442, #268)
  - Added `typescript` and `typescript-language-server` global installs

- **Bun**
  - Added `bunfig.toml` configuration (#447, #273)
  - Added Bun paths to core-paths

- **Kubernetes**
  - Added KUBECONFIG merge logic for `~/.kube/config.d/*` (#487, #313)
  - Added `hm` alias for `helm` (#489, #315)
  - Added K9s configuration with Catppuccin Mocha skin (#314)
  - Added `kube-linter` to Brewfile.cli (#319)
  - Added `kubesec` to Brewfile.cli (#318)

- **Neovim**
  - Added `ts_ls` (TypeScript) to mason-lspconfig ensure_installed (#269)
  - Added DAP configuration with `js-debug-adapter` support (#270)

- **macOS**
  - Added Finder List View as default view mode (#511)
  - Added Finder path bar, status bar, and folders-first sorting

- **Dot CLI**
  - Added `dot packages` command to list installed packages (#375)

- **Testing**
  - Added 14 security validation tests in `test_security_fixes.sh`
  - Added unit tests for TOCTOU prevention, input validation, and safe parsing

### Changed

- Updated all version references to v0.2.477
- **CI/CD consolidation**
  - Consolidated 5 workflow files into 3 (`ci.yml`, `codeql.yml`, `security-release.yml`)
  - Implemented 5-stage pipeline: LINT → SECURITY → TEST → QUALITY → BENCHMARK
  - Added consistent naming convention: `Category / Specifics`
  - Added concurrency groups for faster PR feedback
  - Merged Docker tests and benchmarks into main CI workflow

### Fixed

- **Security hardening (OWASP)**
  - `mount_read_only.sh`: Input validation and secure temp file with `mktemp`
  - `chezmoi-apply.sh`/`chezmoi-update.sh`: Safe flag parsing with `read -ra`
  - `tmux-sessionizer`: Session name sanitization to prevent injection
  - `install.sh`: Escaped sed metacharacters for safe pattern matching
  - `teleport.sh`: Added tar safety flags (`--no-absolute-names`)
  - `permission.aliases.sh`: Added warnings for overly permissive modes (666/777)
  - `genpass.sh`: Numeric input validation
  - `backup.sh`: Enhanced error handling for tar operations
  - `age-init.sh`: Safe JSON output with `json.dumps`

- **Cross-platform compatibility**
  - `99-custom.paths.sh`: Added macOS guards and path existence checks
  - `00-default.paths.sh`: Added darwin guard for Homebrew, Linuxbrew support
  - `view-source.sh`: Plain curl command for portability
  - `configuration.aliases.sh`: File existence checks before sourcing
  - `install_neovim.sh`: Linux-only guard, user-local fallback when no sudo
  - `upgrade_neovim_nightly.sh`: Platform guard, sudo fallback
  - `run_before_00-audit.sh`: Container-safe hostname detection
  - Removed hardcoded `/usr/bin` paths in `last.sh`, `hexdump.sh`, `httpdebug.sh`, `caffeine.sh`

## v0.2.476

### Added

- **AI CLI Tools (NPM-based)**
  - Added `claude` (@anthropic-ai/claude-code) - Anthropic Claude CLI for AI-powered coding
  - Added `gemini` (@google/gemini-cli) - Google Gemini CLI for terminal AI assistance
  - Added `codex` (@openai/codex) - OpenAI Codex CLI for code generation and understanding
  - Added `opencode` (opencode-ai) - OpenCode AI assistant with TUI
  - Added `droid` (@factory/cli) - Factory AI Droid for intelligent code orchestration
  - All tools installed globally via npm/fnm
  - Auto-install fnm and Node.js LTS if not present

### Changed

- Updated all version references to v0.2.476

## v0.2.474


### Added

- **Shell configuration**
  - Added `.profile` with POSIX-compatible login shell configuration
  - Added `.bashrc` fallback for non-Zsh environments
  - Added `.inputrc` with enhanced Readline configuration
  - Added `.vimrc` legacy support for environments without Neovim
  - Added `.Xresources` with X11 configuration and Catppuccin theme

- **Database CLI configuration**
  - Added `.psqlrc` with enhanced PostgreSQL CLI configuration
  - Added `.sqliterc` with SQLite CLI settings
  - Added `mycli` configuration for MySQL CLI
  - Added `redis-cli` configuration
  - Added `mongosh` configuration for MongoDB Shell

- **Kubernetes tooling**
  - Added `kubectx` and `kubens` aliases for context/namespace switching
  - Added `stern` aliases for multi-pod log tailing
  - Added `kube-linter` aliases for manifest linting
  - Added `kubesec` aliases for security scanning
  - Added `minikube` configuration and aliases
  - Enhanced Kubernetes aliases with comprehensive kubectl shortcuts

- **Nix integration**
  - Added `packages` output to Nix flake
  - Added `dot-utils` meta-package derivation
  - Added `tmux`, `eza`, `yq`, `age`, `gnupg` to package list
  - Added install hook script for `nix profile install`

- **Dot CLI**
  - Added `dot --version` to display version information
  - Added `dot add` to add files to chezmoi source
  - Added `dot status` to show configuration drift
  - Added `dot cd` to print source directory path
  - Enhanced `dot tools` with `install` subcommand for Nix shell

- **Docker tooling**
  - Added comprehensive Docker aliases (`dco`, `dprune`, `dlogsf`, `dexec`)
  - Added Docker Compose aliases (`dco` for `docker compose`)
  - Added Docker Buildx aliases for multi-platform builds
  - Added Lazydocker configuration (`config.yml`)
  - Added support for Dive and Hadolint

- **Tmux enhancements**
  - Added vim-style copy bindings (`v` for selection, `y` for yank)
  - Added tmux-sessionizer script for fuzzy session switching
  - Updated clipboard integration for macOS and Linux

- **CI/CD**
  - Added Luacheck CI for Lua linting
  - Added shfmt format checking for shell scripts
  - Added Gitleaks secrets scanner
  - Added link rot checker for documentation
  - Added idempotency double-run test
  - Expanded test matrix to include macOS-13, macOS-14, and multiple Ubuntu versions

- **Completions**
  - Added Bash completion for the `dot` CLI
  - Enhanced Zsh completion with command descriptions

- **Documentation**
  - Enhanced installation guide with Nix instructions
  - Enhanced troubleshooting guide with more common issues
  - Added comprehensive tools list with tables
  - Added aliases reference documentation
  - Added feature flags documentation
  - Enhanced architecture documentation with diagrams
  - Enhanced CODEOWNERS with detailed ownership rules
  - Enhanced contributing guide with PR guidelines

### Changed

- Updated all version references to v0.2.474
- Made shebangs portable (`#!/usr/bin/env bash`)
- Improved documentation with Apple-style clarity
- Updated Brewfile.cli with Kubernetes tools

### Fixed

- Fixed duplicate alias conflicts in Docker aliases

## v0.2.474

- See the release notes and commit history for detailed changes.

## v0.2.472

- See the release notes and commit history for detailed changes.
