Repository navigation
PLAT-001: [EPIC] OS-agnostic from-zero bootstrap — macOS bring-up as the forcing function #2013
Description
Why
A new macOS machine (macOS 27, arm64, Homebrew preinstalled) has to reach the same working state as the Linux and Windows boxes. We use it to make bootstrap OS-agnostic, from zero, and idempotent, so that no new machine on any OS fails the same way twice.
macOS support is listed as still open in #1843 and has no spec. DOCS-001 (#127) turned the claim into "planned". This epic closes that open item. It does not run beside #1843 and #131: wherever one of their rows already covers the work, this epic depends on that row instead of copying it.
We measured this on the Mac on 2026-10-05, using four read-only audits and one live dotf doctor run (52 pass / 37 fail / 22 warn). They produced 53 findings; the full ledger is the first comment. Three things stand out:
- Several failures already hit Linux arm64, not just macOS. Four of them are silent:
setup-linux.shdownloads age/eza/jq/gh/shellcheck from hard-codedlinux-amd64URLs. On any other OS or arch, setup logs SUCCESS and leaves ELF binaries that cannot run and that shadow working copies (~/.local/bincomes first in PATH). A broken eza breaksls.compile-harness.shusesmapfile(bash ≥4, which violates ADR-003). On bash 3.2 no skills, agents or rules deploy for any agent, and setup turns that failure into a warning.dotf tools installruns before uv, so the hive uv-tool entry fails on the first run on every OS.- On first run, setup overwrites the user's
~/.zshrcwith no backup.
- The code branches on "is it Windows?" instead of declaring what each OS needs. Darwin inherits every Linux assumption:
- doctor expects
~/Applications/<tool>-<ver>,*_HOME, and anapt installhint; dotf updaterunssetup-linux.sh;- the scheduler is systemd-only;
env-contract.jsonhas nodarwinkey.
- doctor expects
- The darwin binary is built but never run in CI (ubuntu and windows only).
Constraints
- The bootstrap stays in shell (ADR-020 C7). New logic goes into
dotf, not into setup scripts (ADR-041). There will be nosetup-macos.shfork: Linux and macOS share ~90% of the path. The doctor's drift map is also regex-derived from one script's text, so a second script would be invisible to the ADR-012 assertion. - ADR-003: every shell file runs on bash 3.2 and zsh. "Require Homebrew bash" is not an acceptable fix.
- Every fix lands together with the guard that would have caught it (test, doctor check or CI). If a step can fail while reporting success or "nothing found", it gets a preflight or post-condition probe (
.claude/CLAUDE.md). - Windows must not regress. The Windows CI leg stays required, and each wave that touches shared paths books a Windows check.
- Pins are floors (ADR-036). Auto-merge is forbidden. Each row is one PR under ~300 LOC.
- One spec per track, opened only when its wave starts. ADR-043 allows 10 work-in-progress specs and there are 16 active today.
- Setup is not run on the Mac until Wave 1 is green. Running it today would leave the machine worse off. Each Mac run after that feeds new findings into the ledger.
Decisions
| # | Decision | State |
|---|---|---|
| D1 | One POSIX bootstrap. The only OS-specific step is the class-3 package-manager step (apt / brew / winget). Everything else is declarative in dotf. |
proposed |
| D2 | OS is a declared dimension. The platforms vocabulary from #1843 B1 (absent = all; unlisted = skipped, not failed) covers packages.json, ai/deploy.json, env-contract.json (gains a darwin key) and doctor checks. Code stops treating "anything but Windows" as Linux. |
proposed |
| D3 | Toolchains and pinned CLIs via mise (widened by D7); dotf stays orchestrator and verifier. Homebrew can't pin; Nix, SDKMAN and asdf have no native Windows. mise ships from the catalog as a checksummed github-release, not from brew. versions.conf stays the source of truth: dotf renders the global mise config and runs mise install --locked. The committed mise.lock covers linux-x64, macos-arm64 and windows-x64. Java is temurin-21 (vendor always named), Maven comes from aqua, Python from mise; uv keeps venvs and uv tool. JAVA_HOME comes from mise activate, plus a static env file for GUI and IDE use. Gates: (a) a spike proves Java-via-mise on Windows before Windows switches; (b) legacy ~/Applications/<tool>-<ver> installs are reported as leftovers and removed only after the mise version passes. Rollout uses the Mac as canary. |
accepted (owner, 2026-10-05) |
| D4 | On macOS, Homebrew is for class-3 tools, casks/GUI apps and system libraries only, never toolchains. It is driven from packages.json (D8); a Brewfile, if one exists, is generated from it and never kept by hand. |
decided (owner, 2026-10-07) |
| D5 | One scheduling table emits systemd, launchd or a Scheduled Task (#1843 B8, dotf schedule). No hand-written launchd blocks. Whether to port or retire the hive-upgrade timer is decided against the ADR-036 floor amendment (2026-10-03). |
proposed |
| D6 | Orca is replaced by herdr on every OS, completely (owner, 2026-10-05): every role Orca has today (cockpit, parallel agents, worktrees and their setup hooks, keybindings, agent hooks, the remote CDE on ace2) moves to herdr, and Orca is uninstalled from all three machines. Diffs are reviewed with lazygit. This reverses the 2026-10-04 HOLD in #1586 for the cockpit only. In ADR-032, herdr replaces Orca in the level-2 row and remains a deletable backend, not the substrate (C7 unchanged). Defaults: the deployed config sets a prefix that does not collide with tmux's ctrl+b; agent integrations are a declared dotf deploy step, not a hand-run herdr integration install; the ADR-032 agent.Backend on herdr is out of scope (the v0.9.3 API has no pane exit code). |
accepted (owner) |
| D7 | Pinned CLIs go through mise too (aqua backend, with checksums and attestations): age, zoxide, shellcheck, jq, bats, golangci-lint, sops, direnv, fzf, herdr and lazygit. packages.json keeps npm, uv-tool and mise itself. Gap: eza has no aqua entry and publishes no macOS asset (only vfox/cargo backends); W2 verifies vfox:jdx/vfox-eza on all three OSes, and if it fails eza goes class-3 on darwin. |
accepted (owner, 2026-10-05) |
| D8 | One package SSOT, tiered by install mechanism, not one list per OS. mise (versions.conf) for toolchains and pinned CLIs, identical on every OS; packages.json for npm, uv-tool and github-release; and, extending D7, packages.json also carries the class-3 packages as source.type: system entries that name the package per manager (apt, brew, winget). A manager with no name skips the entry on that OS. dotf tools sync drives the managers idempotently and doctor verifies the result. No hand-kept package list survives in setup-linux.sh, setup-windows.ps1 or a Brewfile. |
decided (owner, 2026-10-07) |
| D11 | SSH trust for the whole mesh is a CA, in two phases (owner, 2026-10-13; #2373). Scope: every sshd on the mesh, about 10 hosts (homelab, vps and gcp1, workstations); principals manu and deployer. Phase 1 in dotfiles: an offline root in the secrets plane signs host certificates and per-machine user certificates (30 to 90 days) through a dotf converge step, with a KRL; it retires the shared id_ed25519, the pin file and Ansible's accept-new, and stays the break-glass path. Phase 2 in kubelab: step-ca as an online intermediate on the VPS, outside the cluster it protects, with Authelia as identity. No public SSH: 22 closes on vps and gcp1, with a terraform break-glass variable (kubelab#2224). |
accepted (owner, 2026-10-13) |
Tracks
Each row is one PR. "After" lists hard dependencies, and "Ledger" lists the findings the row closes.
W — Stop the silent failures (pure bug fixes that also hit Linux; no macOS framing needed)
| Id | PR | After | Ledger |
|---|---|---|---|
| W1 | feat(tools): post-install exec probe. After every catalog install, run <tool> --version and fail the step on non-zero. |
— | F-030 guard |
| W2 | refactor(setup): setup calls dotf tools sync (T2) and the five hard-coded linux-amd64 URL blocks (age, eza, jq, gh, shellcheck) are deleted. gh stays class-3. Old ~/.local/bin/<tool> copies are reported by doctor as leftovers that may shadow mise's. |
T1, T2 | F-030, F-014, F-006 |
| W2b | feat(env): the mise PATH hook on all three OSes: shims dir on PATH for non-interactive callers, mise activate in the bash/zsh/pwsh rc files. Without it dotf tools sync succeeds and nothing is on PATH, a new false success. Doctor checks mise doctor reports the shims on PATH. |
T2 | — |
| W3 | fix(harness): remove mapfile from compile-harness.sh (4 sites); add a lint guard for bash-4-only constructs; run bats under bash 3.2. |
— | F-031, F-017 |
| W4 | fix(setup): a failure in compile-harness or deploy makes setup fail loudly, with a preflight. | W3 | F-048 |
| W5 | fix(setup): install order puts managers (uv, node) before dotf tools install. |
— | F-047, F-029 (part) |
| W6 | fix(config): .gitconfig resolves the gh helper via PATH; .bashrc prepends to PATH and never resets it; .zshrc guards oh-my-zsh. |
— | F-032, F-033, F-034 |
| W7 | fix(setup): back up any existing unmanaged rc file before the first overwrite. | — | F-035 |
| W8 | fix(setup): replace stat -c, chmod --reference and a bare sha256sum (shasum fallback) with portable forms. |
— | F-037, F-038, F-011 |
| W9 | fix(secrets): render opencode.jsonc with mode 0600; doctor checks the mode. |
— | F-050 |
| W10 | #2063 ci: macOS leg running go test, bats (bash 3.2 and zsh) and GOOS=darwin go vet. Non-required until green, then required. This is #1843 E10, pulled forward. Three layers, one suite: OS behaviour that can be injected (doctor's System.GOOS, deploy's goos) is tested on Linux; the real macOS runs only the tests tagged os-sensitive (bats --filter-tags, bash 3.2 and zsh), the full suite on main; from-zero end to end is X1. Includes the Mac bats triage: every failure classified (script bug, non-hermetic test, Linux-only) and resolved before the leg is switched on. |
— | F-012 |
P — Declare the OS (the agnostic contract)
| Id | PR | After | Ledger |
|---|---|---|---|
| P0 | docs(adr): OS-agnostic bootstrap. Covers tier-0 (shell: package manager + dotf) vs tier-1 (dotf converge), records D1, D2, D4, D5 and D8, extends ADR-036 class 3 with brew, and refreshes the stale ADR-012/036 text. |
— | F-046, F-019 |
| P1 | = #1843 B1 (platforms selector on deploy entries). |
P0 | — |
| P2 | feat(contract): add a darwin key to env-contract.json. Doctor reports the resolved OS rather than silently mapping darwin to linux. |
P0 | F-001 |
| P3 | refactor(doctor): checks declare the platforms they apply to; remediation hints come from the catalog per OS and package manager; path comparison folds case on darwin; the git floor is per OS. | P1, P2 | F-002, F-018, F-025, F-043 |
| P4 | feat(bootstrap): OS-dispatching entrypoint (detect OS and arch, run class-3 managers, install dotf, hand off). install.sh and dotf update dispatch through it. Covers #366. |
P0 | F-020, F-036, F-029 |
| P5a | feat(tools): dotf tools reads source.type: system (apt/brew/winget names, an OS with no name skips) and plans and installs through the OS manager. Reader first: today an unknown type is an error (install.go, "unsupported source type"), so the installed dotf would fail every sync if entries shipped in the same PR (#1814 class, same shape as B1). |
T2 | F-006 (part) |
| P5b | feat(tools): class-3 entries in packages.json (git, gh, tmux, xclip, parallel, and the darwin casks from the owner's app list). It deletes the hand-kept winget list in setup-windows.ps1 and the tmux/xclip install warnings in setup-linux.sh, and closes the cleanup half of #2057 (undeclared brew formulae). |
P5a, then the release carrying it as the DOTF_VERSION pin |
F-006 (part) |
| P6 | fix(bootstrap): deploy the rc files and run dotf env generate before any agent is installed, so CLAUDE_CONFIG_DIR and the path vars exist on the first run. |
P4 | F-005, F-052 |
| P7 | = #1843 B2 (home dotfiles as deploy entries, which retires the regex-over-setup drift map). | P1 | F-045 |
| P8 | feat(bootstrap): scripts/macos-defaults.sh, the opt-in analog of windows-defaults.ps1 (-WithDefaults), codifying the manual baseline in the vault runbook runbook-macos-workstation-setup (debloat, defaults, firewall, FileVault check). Idempotent: a second run reports 0 changes. |
P4 | F-057 |
| P9 | #2016 feat(bootstrap): instructions-first deploy as the first step on any new machine: dotf harness mirror, compile-harness.sh --deploy and dotf harness bind write only agent config dirs (~/.claude, ~/.gemini, ~/.config/opencode, ~/.pi, ~/.copilot), never rc files or binaries. Doctor FAILs when an agent binary is present without its instruction file. |
W3 | F-060 |
| P10 | feat(converge): the tools step installs the packages.json catalog on every OS (install, mise sync, install), so a Mac, where no setup runs, gets its brew, release, npm and uv tools; a manager nothing installs or a sudo password is reported, not failed. PLAT-001b AC12. Found by the 2026-10-10 ledger audit. |
P4 | F-006, F-029, F-047 (part) |
T — Toolchains and pinned CLIs (D3, D7 accepted)
Split by risk. T0–T2 land in Wave 1 on every OS, rendering CLIs only. Those are ~/.local/bin binaries with no legacy layout to collide with. Java, Go, Python, Maven and Node enter the rendered config only in Wave 3. Rollout for toolchains: the Mac is the canary. T3, T4 and T6 land on the Mac first. It has no legacy ~/Applications/<tool>-<ver> installs, so nothing can break and no leftover handling is needed yet. Linux and Windows move (T6) only after the Mac has run dotf doctor clean for a while.
| Id | PR | After | Ledger |
|---|---|---|---|
| T0 | docs(adr): toolchains and pinned CLIs via mise (amends ADR-036; records D3 and D7). Also archives DX-007-orca-cli-bootstrap as abandoned (D6), which frees a WIP slot. |
D3, D7 | F-003 |
| T1 | feat(tools): add mise as a checksummed github-release catalog entry. Pin mise itself in versions.conf and set min_version, because mise releases are date-versioned. |
T0, W1 | — |
| T2 | feat(tools): dotf tools sync renders the global mise config from versions.conf (Wave 1: CLIs only) and runs mise install --locked. mise.lock is committed and CI regenerates it for linux-x64, macos-arm64 and windows-x64. W1's post-condition carries over: every tool is exec-probed after install (mise which + --version), not trusted on mise's exit 0. |
T1 | — |
| T3 | refactor(doctor): check versions with mise ls --json plus exec probes; replace the *_HOME and ~/Applications checks; report legacy installs as leftovers. |
T2 | F-003, F-041 |
| T4 | refactor(shell): mise activate (bash, zsh, pwsh) replaces the APPS_HOME/JAVA_HOME block; dotf writes a static env file for GUI and IDE use. |
T2 | F-041 |
| T4b | refactor(shell): Node via mise retires .zsh/nvm.zsh and the nvm wiring (bash, zsh). |
T4 | — |
| T5 | spike(windows): Java via mise on Windows. This gates T6's Windows half. Fallback if it fails: the JDK stays a winget class-3 install on Windows, and mise handles everything else, so T5 cannot block the whole track. | T2 | — |
| T6 | chore: migrate the existing machines; doctor --fix removes leftovers only after T3 passes. |
T3, T5 | — |
S — Services and OS integration
| Id | PR | After | Ledger |
|---|---|---|---|
| S1 | = #1843 B8 (dotf schedule), with a launchd backend as an explicit requirement. Moves vault maintenance from crontab to dotf vault maintain. |
P1 | F-010, F-026, F-039, F-044 |
| S2 | Revised 2026-10-13 (owner: "En hive"). hive owns the supervisor: hive service install gains a launchd backend (hive#488, PR hive#489; verified on the Mac). Dotfiles half, after a hive release carries it: a hive-service converge step that runs hive service install on every OS (replaces the setup-linux.sh block); the darwin remedy in checks_hive_daemon.go (it tells the user to run hive serve by hand); the X1 ratchet entry darwin the hive daemon is down retired or re-owned in the same PR, depending on whether bootstrap gui/<uid> works on a GitHub macOS runner. Worker credential on macOS: #2351. |
hive release | F-051 |
| S3 | feat(env): a launchd agent runs launchctl setenv so GUI-launched apps see VAULT_PATH and the other path vars. |
S1 | F-021 |
| S4 | feat(cli): notifier abstraction (notify-send / osascript / Windows); darwin process probe for worktree sweep. |
— | F-022, F-023 |
| S5 | Verify first, then fix: Orca paths and process detection on macOS, and agy's invalid mcp_config.json. |
— | F-024, F-008 |
| S6 | fix(config): tmux clipboard via OSC52 or a detected bridge; terminfo; terraform completion and the obsidian alias resolved via PATH or OS. | — | F-040, F-042 |
| S7 | feat(bootstrap): SSH key provisioning on a fresh machine (restore from the age/Bitwarden escrow); doctor check. | W2 | F-007 |
| S8 | = #1843 B10 (MCP manifest rendered per tool). | — | F-049 |
| S9 | docs: README platform table, the stale ai-tools-setup.md runbook, the retired codex payload, and the vault context drift. |
P4 | F-016, F-053 |
| S10 | fix(deploy): first deploy over configs that already exist backs them up instead of reporting endless drift. | P1 | F-009 |
| S11 | feat(ssh): D11 phase 1. ADR first, then the dotf signing step, HostCertificate and TrustedUserCAKeys in the workstation-target drop-in, @cert-authority *.kubelab.internal replacing the pins, per-machine keys (S7 becomes "generate here and sign"), KRL through converge. Closes #2373 and kubelab#2223; phase 2 opens as a kubelab ticket. |
S7, PLAT-001b pin PR | #2373 |
H — Orca → herdr (D6; supersedes the #1586 HOLD, #1586 stays the history)
The Mac is the canary again: it has neither Orca nor herdr, so H1–H5 land here first with nothing to retire. Retirement (R) starts only after gate V is green on all three OSes.
| Id | PR | After | Notes |
|---|---|---|---|
| H1 | feat(tools): herdr through mise (aqua:herdrdev/herdr), pinned at 0.9.3; checksums and attestations verified per target. |
T2 | linux and macOS assets carry build attestations; the Windows zip does not |
| H2 | spike(windows): does mise install herdr keep conpty/ next to herdr.exe? Fallback if not: on Windows only, herdr's own install.ps1 as class-3, so H2 cannot block the track. |
H1 | |
| H3 | feat(doctor): herdr pin-drift check (linux x64/arm64, darwin arm64, windows x64). | H1, H2 | 0.x churn: set update.version_check=false |
| H4 | feat(deploy): ai/herdr/config.toml (non-colliding prefix, the ported Orca tab keys, [worktrees] directory, pane_history=false, update checks off), plus HERDR_CONFIG_PATH in env-contract.json so one dst works on every OS (Windows default is %APPDATA%). This is the first worked example of D2. |
H3, P2 | |
| H5 | feat(doctor): herdr checks (binary, config deployed, server/socket reachable). | H3 | |
| H6 | feat(deploy): herdr agent integrations (claude, opencode, pi, copilot, agy) as declared deploy steps; they coexist with harness bind, which never touches foreign hooks. |
H4 | |
| H7 | Port the orca.yaml worktree setup hooks (mise install, deps install, .env.local copy, compose down) as a dotf worktree setup step bound in herdr (keybinding or plugin). The owner uses them daily. |
H4 | |
| H8 | feat(herdr): ace2 as a remote machine (herdr machine add), plus a runbook that supersedes the vault's Orca CDE runbook. |
H4 | |
| H9 | feat(tools): lazygit pinned through mise, plus a herdr keybinding that opens it in the active worktree. It replaces Orca's diff viewer. | T2, H4 | |
| V | Gate, no code: herdr in daily use on Linux, Windows and macOS (including H7 worktree hooks, H8 ace2 and H9 lazygit), dotf doctor green on each, recorded here. |
H3–H9 | |
| R0 | Per machine, in this order: remove the Orca hooks (~/.claude/settings.json hook groups, ~/.copilot/hooks/orca.json, ~/.pi/agent/extensions/orca-*.ts, the agy hooks.json orca-status block), check that every agent still starts, and only then uninstall the Orca binary. Doctor gains an "Orca leftovers" warning with --fix guidance. Reversing the order leaves every agent hitting failing hooks. |
V | |
| R1 | Retire the orca-keybindings deploy entry, ai/orca/, the ORCA.md manifest target (drop it, don't replace it) and initrepo/templates/orca.yaml (a user-facing dotf init change), with their tests. |
R0 | |
| R2 | Retire cli/internal/orca/, cmd/orca.go, the deployOrcaHooks call, checks_orca.go and their tests. |
R0 | |
| R3 | Clean up setup and bats; per-OS uninstall runbook (AppImage/.deb, Windows NSIS, brew cask). | R1, R2 | |
| R4 | Docs: ADR-032 §2 amendment (herdr in the level-2 row, still deletable), mark old lessons superseded, close #462/#899/#436/#942/#1748, archive DX-007. Vault: archive the Orca CDE runbook and update MEMORY.md and session-protocol. | R3 |
X — Proof
| Id | PR | After |
|---|---|---|
| X1 | ci: end-to-end from-zero job on clean macos-latest and ubuntu-latest runners: bootstrap, then dotf doctor exits 0, then a second run reports 0 changes. It asserts the first run converged before it checks idempotence (lesson 328). Runs on PRs to main only, because macOS minutes cost 10×. |
W*, P4 |
| X2 | ci: fail on any linux-amd64, x86_64-unknown-linux or linux_amd64 literal outside packages.json. Extends #1843 C2. |
W2 |
| X3 | Windows parity run on the work laptop: setup, doctor and idempotence. | T5, P4 |
| X4 | ci(test-windows): run dotf doctor --scope machine and drop the fabricated identity (vault, age key, Bitwarden stand-ins) its full doctor needs today. Same reading as X1 since D10 (#2337). |
D10 |
Waves
- Wave 1: W1 to W10, plus T0, T1 and T2 (CLIs only). Plain bug fixes that also protect Linux arm64; W2 needs T1 and T2.
- Wave 2: P0 to P7, plus the first real bootstrap of the Mac. New findings from that run go into the ledger.
- Wave 3: T0 to T6 (needs D3), together with S1 to S3 and H1 to H6 (needs D7).
- Wave 4: the rest of S (S11, the SSH CA, after S7 and the PLAT-001b pin PR), gate V, then R0 to R4 per machine, then X1 to X3. X1 becomes a required check.
Owner actions, when their wave arrives
- Provide the list of apps and casks for the Brewfile (P5).
- Hand-carry the age identity key to the Mac (
~/.config/age/key.txt, mode 0600) and log in to Bitwarden. Secrets, SSH and hive depend on it. - Accept the cost of the macOS runner for X1.
- Book a Windows session for T5 and X3.
Acceptance
- On a clean
macos-latestrunner and a cleanubuntu-latestrunner, one bootstrap run leavesdotf doctorexiting 0, and a second run reports 0 changes, with first-run convergence asserted before idempotence is checked. - No catalog install can report success for a binary that does not execute (W1 probe).
- No hard-coded OS/arch release literal exists outside
packages.json(X2). setup-linux.shandsetup-windows.ps1shrink measurably, tracked per PR.- Every ledger ID is closed with its guard, or explicitly deferred with a reason.
- This Mac runs the same daily workflow as the Linux and Windows machines: shell, agents with skills and hooks, MCP and hive, secrets, vault.
Activity
mlorentedev commentedon Oct 6, 2026
Findings ledger (measured on the macOS box, 2026-10-05)
Each row closes only with its guard, or is explicitly deferred. New findings from each Mac run are appended here.
Machine: macOS 27.0.1 arm64, Homebrew preinstalled, dotf 0.64.0 (release binary).
Rule: every finding gets root cause + agnostic fix + regression guard (test/doctor/CI) so it
never fails again on ANY new machine.
env-contract.jsonhas onlylinux/windowsdefaults, nodarwinposixdefault (linux+darwin) with per-OS override, or explicitdarwinenv.ForOS(darwin reads its own key, else linux) /TestCheckContractOnDarwin,TestTheRealContractKeysByKnownOSAndCopiesNothingsudo apt install -y tmuxon macOSaptstring in hints when GOOS=darwintmuxInstallanswers brew on darwin /TestCheckTmux_TheRemedyNamesThisOSPackageManager~/Applications/<tool>-<ver>(JAVA/MAVEN/PYTHON/GO/MINIKUBE_HOME)--version, not pathtimeoutmissing on macOS (GNU coreutils)timeoutcall in any script, test, hook or Go exec, now or at the 2026-10-05 snapshotdotf env generateran butpaths.shnot sourced (vars unset in shell).bashrcdeploys only via setup, so bash on a Mac still misses it — P7bbrewchannel on darwindotf tools install --checkin CI matrix~/.ssh— ssh/config deploy + key provisioning undefined for a fresh machine~/.gemini/config/mcp_config.jsoninvalid JSONdotf deployidempotent, back up foreign files.pre-dotfbackup for every deploy entry incl. merges (#2043);configs-deployruns it on darwin (#2245)install-dotf.sh:155usessha256sum— present at /sbin on macOS 27 (measured), absent on older macOS → addshasum -a 256fallback_dotf_sha256falls back toshasum -a 256(#2145,scripts/install-dotf.sh:146)macos-latestleg (go test + bats + setup idempotence)setup-linux.sh:972stat -c %s(BSD stat differs)setup-linux.sh:221,250hard-codedlinux-amd64for age/jq{os}/{goarch}catalogsetup-linux-only-downloads.batspre-commit install(secret gate) — manual README stepdoctor --fixrunspre-commit installin the vault (#553,TestCheckVaultHooks_InstalledOnFix)10_projects/dotfiles/context.md+_index.mdclaim Linux/macOS/Windows; README says macOS "planned"Tracking conventions found: tasks → bitácora GitHub Project #1 (ADR-018); OS-agnostic vehicle = CLI-091 epic #1843 Track B (declarative convergence,
osselector in deploy entries,dotf converge); bootstrap stays shell (ADR-020 C7); memory rule: never grow setup scripts.From Go CLI audit
bash→ macOS/bin/bash3.2 lacksmapfile→ false FAIL every run (checks_deploy.go:732)mem.ResolveBashbashdrift check no longer false-FAILs; Mac doctor 2026-10-10 shows no harness FAIL!= windows; darwin inherits Linux expectations (*_HOME,~/Applications/<tool>-<ver>, core tools list, tmux apt hint, Obsidian CLI)required_on,darwinkey)TestAppsLayout_DarwinSkipsNamingMise,TestVersionedPaths_ASetHomeIsCheckedOnDarwinToo. A fulldotf doctoron the Mac (2026-10-10) shows no linux-only expectation leftbrewchannel in catalog nor ADR-036 class 3 (only apt/winget)dotf updateoff-Windows always runssetup-linux.sh(update.go:111-119)bootstrap.sh#366) /dotf convergedotf updateconverges (#2274);legacy-setupskips darwinenv persistno-op off Windows; GUI/Dock apps on macOS don't see VAULT_PATH etc.launchctl setenvvia LaunchAgent at login (darwin backend)worktree sweepnever reaps on darwin (no libproc impl,sweep_proc_other.go)lsof/libprocdoneancestor guard /sweep_proc_darwin_test.go, caller-walk tests shared viadone_proc_unix_test.govault maintainnotifications onlynotify-sendnotifyCommandper GOOS, osascript with the text as argv /TestNotifyCommand_ReachesEachOSNotifier~/.config/orca+pgrep orca-linux.*AppImage— wrong on macOS (~/Library/Application Support,.app)UserDataDirfollows Electron's appData; running check reads Chromium'sSingletonLock(linux, darwin) /TestUserDataDir_FollowsElectronAppData,TestRunning_ReadsTheSingletonLock. Orca absent on the Mac, so a livetunethere is an owner check; the Windows lockfile check waits on #2291. Found: Orca's profile layout, #2294sameDircompares the files (os.SameFile), not an OS-folded spelling /TestSamePath_OneDirectoryInAnotherCaseIsTheSamecommand -vas OS proxydotf schedulebw servenot supervised across reboots on any POSIXdotf scheduledotf self-update(ADR-041 §7) not implemented — binary updates only via install-dotf.sh (#1843 A4)From setup-linux.sh audit
lsalias{os}/{goarch}(ADR-036 D1 already says so) — #1843 C1<tool> --version) in catalog installermapfile(761,1254,1405,1439) → fails on bash 3.2 → no skills deployed for any agent; violates ADR-003mapfileremoved, compile-harness runs on bash 3.2 (#2015).gitconfig:5,8credential helper!/usr/bin/gh(brew: /opt/homebrew/bin/gh) and emptyhelper =clears osxkeychain → HTTPS auth breaks!gh auth git-credential(PATH lookup).gitconfigdeleted (#2208); doctor checks the helper.bashrc:137resets PATH dropping /opt/homebrew/bin.bashrconly prepends PATH, guarded brew shellenv (#2283).zshrc:13sources oh-my-zsh unconditionally; nothing installs itcompinit(#2043).zshrclacksbrew shellenv; first run overwrites user ~/.zshrc without backup.pre-dotfbackup on first overwrite for every deploy entry (#2043); brew shellenv in both rcs (#2043, #2283)..bashrcitself still deploys via setup until P7binstall.sh:52hardcodesexec ./setup-linux.shstat -c %s(972) →.claude.jsontruncation guard silently OFF on macOSwc -c <chmod --reference(828) → pi enabledModels never syncs, warns each runchmod --referenceremoved (#2145)command -vas OS proxydotf scheduleemitting systemd/launchd/schtasks from one table (#1843 B8); hive-upgrade maybe retire (ADR-036 2026-10-03 floor amendment)tmux-256colorterminfo may be missing on macOSpbcopy/xclip/clip.exedetectiontests/tmux.bats(real tmux)APPS_HOME=$HOME/Applicationscollides with macOS's real ~/Applications; JAVA_HOME pointing to nothing breaks /usr/bin/javacomplete -C /usr/bin/terraform,alias obsidian='obsidian --no-sandbox'hardcodedcommand -vresolution; OS-gated alias.bashrcterraform (#2290) /tests/bashrc-guards.batsTestCheckGitWindowsFloor$CURRENT_DIR/scripts/..., not deployed copy; should targetdotf vault maintaindotf scheduleTestHomeDeployMapCoversSetup) — couples truth to one scriptToolchain research (decision input for F-003/F-019/F-041)
Recommendation: mise for toolchains + pinned CLIs (native Linux/macOS/Windows,
mise.lockwith per-platform URL+checksum,--locked, aqua backend w/ cosign/SLSA). dotf stays orchestrator+verifier: mise bootstrapped as github-release catalog entry (not brew — mise docs advise against); versions.conf stays SSOT →dotfrenders global mise config +mise install --locked; committed mise.lock regenerated in CI for linux-x64,macos-arm64,windows-x64.Homebrew: casks/GUI/system libs only (no version pinning; Brewfile lock removed by design).
Java:
temurin-21(always name vendor), lock pins exact build; Maven via aqua; Python via mise (python-build-standalone), uv stays for venvs/uv tool. Open risk: Java on Windows via mise undocumented → test before switching Windows.*_HOME:
mise activatesets JAVA_HOME in shells; dotf writes static env for IDE/GUI (+ optional /Library/Java/JavaVirtualMachines symlink on mac).Doctor: compare
mise ls --jsonvs versions.conf/lock, exec version probes, JAVA_HOME inside mise dir; legacy ~/Applications/- reported as leftovers, removed only after mise version passes.Rejected: Nix (no native Windows), SDKMAN (no native Windows), asdf (no Windows, no lock), brew for toolchains (no pinning).
Sources: mise.jdx.dev/dev-tools/mise-lock.html, /installing-mise.html, /dev-tools/backends/aqua.html, /lang/java.html, docs.brew.sh/Brew-Bundle-and-Brewfile
From harness / AI-layer audit
dotf tools install(:293) runs before uv (:599) → hive uv-tool entry fails on first run on every OS; only MCP prerequisite rescues itrequires_managerand ordersrecords-harnessfails loud (#2025); directsetup-linux.shstill WARNshive clientdaemon proxy; opencode/copilot/agy per-sessionuvx hive-vault; agy gets no context7)opencode.jsoncrendered with plaintext secrets, no file mode setdotf deploywith mode 0600 (#2269); doctor reports mode drift (#2111)dotf secrets runwrapper); upstreamhive service installon darwin was a non-zero stub (AI-022) — reverify on 4.2.2dotf schedule/service backend for launchd; doctor vialaunchctl printCLAUDE_CONFIG_DIRnot exported before first claude run →.claude.jsonat ~ root vs in config dirdocs/runbooks/ai-tools-setup.md(Gemini CLI, drawio MCP, "macOS: ./setup-linux.sh"); codex payload still written though retiredharness/model-map.json:29), so~/.codex/AGENTS.mdstaysmlorentedev commentedon Oct 6, 2026
Ledger update — 2026-10-05
main@ 946afa5): 1632/1776 pass, 144 fail. About 65 are compile-harness/skill deploy (mapfile, F-031 → W3). About 35 are pr-agent, release-please and review-attestation workflow tests (cause TBD: GNU tool or missing yq/python). About 25 are vault-health and crystallize parity (TBD). The rest are scattered (chmod --referenceF-038, eol, guards).go build/vet/test ./...passes on darwin/arm64 (30 packages). The Go layer needs no darwin fix to run its own tests.Progress: W1 → #2014 (exec probe; on real assets, 0.64.0 installed the linux ELF on darwin with exit 0, while the branch refuses it and places nothing).
fix(tools): stage the install probe on Dest's mount, not /tmp
fix(harness): run compile-harness on macOS bash 3.2
fix(tests): extend the bash 3.2 guard to the test suite and zsh
feat(tools): refuse to install a binary that does not run here (#2014)
mlorentedev commentedon Oct 6, 2026
Ledger update — 2026-10-05 (end of session 1)
vfox:jdx/vfox-eza,cargo:eza) and publishes no macOS release assetvault 00_meta/runbooks/runbook-macos-workstation-setup.md(written 2026-10-05 in another session, uncommitted) documents the Mac baseline as manual steps: debloat,defaults, FileVault, firewall. A manual runbook is the failure mode this epic removes.scripts/macos-defaults.sh, the opt-in analog ofwindows-defaults.ps1(-WithDefaults), generated from that runbook; the runbook keeps the rationale and points at the scriptci.yml(bats, shellcheck, test-windows) runs only on PRs intomain. A stacked PR (base = another branch) shows green without running them.mainand CI runs before its merge~/.gemini(F-008)Progress: W1 → #2014 (review addressed: in-Dest staging for noexec /tmp); W3 → #2015 (review addressed: guard covers tests, bash 4.2+ constructs, zsh-safe
nan-quality-bench.sh).fix(harness): run compile-harness on macOS bash 3.2
fix(tests): extend the bash 3.2 guard to the test suite and zsh
fix(harness): run compile-harness on macOS bash 3.2
fix(tests): extend the bash 3.2 guard to the test suite and zsh
mlorentedev commentedon Oct 6, 2026
Ledger update — F-060 (found at handoff, 2026-10-05)
~/.claude/CLAUDE.mdwas never deployed, so the "no AI attribution" rule (AGENTS.md §counter-defaults) never reached Claude Code, and the CLI's default attribution leaked into every commit and PR of this session. #2015 was rewritten; the squash commit 9db6df4 onmainkeeps aCo-authored-bytrailer (owner decides). This is the exact failure AGENTS.md line 202 describes, triggered by F-031 (no deploy on bash 3.2) plus the "don't run setup yet" constraint.dotf harness mirror+compile-harness.sh --deploy+dotf harness bind, which write only agent config dirs and never rc files or binaries) as the first bootstrap step on any new machine, before any agent session commits. Doctor FAILs loudly when an agent binary is present but its instruction file is missing.80 remaining items
mlorentedev commentedon Oct 12, 2026
Windows mise update (isolated x64 fixture; no catalog activation yet):
.exe, somise which direnvcannot find it. The Windows renderer now declaresgithub:direnv/direnvwithbin = "direnv.exe". Pinned mise 2026.9.13 resolves and runs direnv 2.37.1; a repeated install adds 0 tools.dotf tools syncinstalled and probed all 27 marked CLIs plus PyYAML in an isolated Windows fixture. The second run saysnothing to do; a dry-run saysunchanged/nothing to install. Go tool/converge/cmd suites, vet, and 123 Windows setup BATS tests pass. The catalog still excludes Windows.bats.cmd(aube on mise 2026.10.8 still produces no launcher).npm.package_manager = "npm"applies to every npm tool in the user's global mise config. Node/npm are present on this host, but not provisioned bypackages.jsonorversions.conf;setup-windows.ps1installs Node in legacy-setup, after converge's tools step. A freshinstall.ps1therefore cannot sync npm-backed bats in one pass.The updated spec evidence and troubleshooting guide are in the
feat/mise-windowsworktree; no changes were made tomain.mlorentedev commentedon Oct 12, 2026
Follow-up on the Windows mise reader: the installer-policy and first-run Node blockers are resolved in
feat/mise-windowswithout changingmain.NODE_VERSION=24.11.1is now a marked mise pin (same owner on every OS). On Windows, sync refuses bats without that pin and installs Node before bats when needed.mise install --force npm:batschild usingMISE_NPM_PACKAGE_MANAGER=npm. The managed config no longer sets a global npm package manager; a real isolated from-zero run without npm on PATH installed all 28 pins plus PyYAML, the next run did nothing, andmise settings get npm.package_managerremainedauto.dotf converge --only tools: first pass installed mise and four representative pins, second pass returned0 changed, 1 ok.platformsgate yet. The currently pinneddotf0.67.0 still selects unsupported aqua bats on Windows. Ship this Go reader first, then bumpDOTF_VERSIONto a release carrying it before enabling Windows and removing duplicated winget/uv setup blocks. That activation still needs a from-zero full production-catalog verification.ci: prove a machine from zero converges and stays converged (#2331)
mlorentedev commentedon Oct 13, 2026
S2, the "first verify": hive-vault 4.3.0
hive service installon darwin is a stub (hive/_service.py:10: "macOS: a documented stub (launchd); a follow-up, not in the CI matrix"; line 332 tells the user to create a launchd agent with KeepAlive by hand). So on a Mac nothing ever starts the daemon,~/.local/share/hive/daemon.tokennever exists, and every agent whose MCP config runshive clientfails to connect (observed 2026-10-12 in pi: "could not read daemon credential at …/daemon.token"). The X1 gate lists this FAIL under S2 (.github/scripts/from-zero-known-failures.txt).mlorentedev commentedon Oct 13, 2026
New row, A1 (owner, 2026-10-12):
workstation-targetconverge step, tracked in #2356 (SEC-011). It hardens a machine that accepts SSH (sshd drop-in, mesh-only firewall, power policy, unattended tailscale), opt-in per machine, withInspectas the dry run, a preflight beforeApplyandchanged=0on the second run. It sits next togit-hooksandhive-serviceunder PLAT-001b. Until it lands,docs/runbooks/guide-workstation-ssh-target.mdis the interim procedure.feat(env): declare machine roles and keep the sections a write does n…
feat(converge): add the workstation-target step for macOS
feat(converge): add the workstation-target step for macOS (#2361)
mlorentedev commentedon Oct 13, 2026
Overnight plan, 2026-10-13 (agent, owner-independent)
Serial: one PR open at a time (strict protection re-runs every other PR on each merge).
v0.68.0is out; everything below goes to 0.69.0.dotf pr triage-queueexit 0.bashrc,.profile,.inputrcasplatforms: [linux, darwin]deploy entries, manifest v4, setup-linux copy blocks deleted, X1 ratchet entries droppedff5b01a2). Review fix: the rc-file tail deploy stays fatal underset -edoctor --scope machine; test-windows drops the fabricated identity (X4)dotf spec auditstep;DOTFILES_DOCTOR_NO_IDENTITYdeleted)954526a7, lesson 404): marketplace sources declared inai/claude/marketplaces.json, registered before the first install666cd436); #2019 Blocked on the owner's ADR-028 decisionpwshshim)ee8fdb2,require_pwsh); fix (b), the orphaned install, stays on #2375guide-workstation-ssh-target.md: Linux sections collapse to the dotf flow6f4261f7), with the review's three rollback fixesAddKeysToAgent+UseKeychaininssh/config4315f95); design finding hive#492dotf deployor skill deployd611728); from-zero 38387691830 green on both OSeslatest80a6131a, review triaged (1 applied ina9c0a9fb, 1 declined); lands before the 0.69.0 cut (owner decision 2026-10-13). When Windows mise activates (W2b) and rendersclaude, delete the vendor install block insetup-windows.ps1in the same change (review finding 2)agent-extensions)df443d6); from-zero 38391592787: first converge4 added; 3 added, second"changed": 0on both OSes3e83a635); from-zero evidence with P5c in 38396154386; #2392 rebased and its stale darwin known failure removed (c875e04a). Found on the Mac: the master still launcheduvx pdf-modifier-mcp(lesson 405)021cd632, lesson 406); scope guard, restore on a failed re-add,Lost, settings guard from review. Mac plan:pdf-modifier to re-register127d71cc); Mac: one WARN, pdf-modifierAGY_HOMEe22c868c);AGY_APP_DATAread only as a fallback until #2404; guard keeps it out of shell, PowerShell and rc files57a0fa56)--fixremoves them through deploy's staged writed35802cf); Mac read-only: six FAILs, the six rules #2349 correctedd59dcecf); four cases of the family fixed, three review rounds against cmark-gfm, lesson 407BASH_REMATCHwithout the zsh shimbeb9d24); seven suites onrun_both_shells, guard requiresKSH_ARRAYSandBASH_REMATCH, lesson 4083bf2f5a); race on main 7/10, branch 0/15, lesson 409pr landspec after its independent review45750a8); review PASS, F1 fixed in the spec, F2-F4 filed as #2410pr landreports a landed merge as merged, names a stale lock PID, finds the registry from any directory13b4f46,skip-sdd: findings of an archived, reviewed spec); cross-repo registry filed as #2414install.ps1on 0.68.0:poetry: reports 2.4.1 after install, below the pin 2.5.1, and every run reinstalls with--forceC:\SPB_Data, mirror underC:\Users\mlorente).jsonreport + full.logtranscript)<StateDir>/converge/runs/, redact secrets on write,0700/0600, never committed or mirrored). Built in #2446 (2026-10-13); live Windows-box run open after the release that carries itFindings for the ledger:
0 added, 3 failedplugins:setup-linux.shrunsdotf deploy \|\| log_warninginside the opaquelegacy-setupentry. That is W4's class (a failed deploy must fail setup); run 38366816961 is a concrete instance.native build latest), which is why CI and every workstation disagreed on the default marketplace.Owner-gated, not tonight:
sudo ufw status verboseon msi (is port 22 also confined totailscale0?), ace2 fingerprint, Hetzner console (kubelab#2224), vps host key (kubelab#586), AC11 Dock relaunch. S11 (#2373) stays queued behind S7 and the WIP ceiling.Filed overnight: #2381 (CLI-104), #2384 (CLI-105), #2387 (BUG-127), #2388 (SEC-014), hive#492. BUG-127 and CLI-105 share one mechanism (#1843 B10) and are planned as one converge step. Later: #2393 (CLI-106, doctor misses a missing Claude plugin or server), #2395 (CLI-107,
AGY_HOMEvsAGY_APP_DATA).Also filed: #2397 (BUG-128), #2399 (CLI-108, delete the Claude MCP twin; the Windows half waits for hive in the Windows catalog, since the twin's
prerequisite_commandis the only Windows install of hive-vault), #2402 (CLI-109,deploy.jsonspells contract-named agent dirs with{HOME}), #2404 (CLI-110, drop theAGY_APP_DATAfallback one release after #2401), #2407 (REFACTOR-018, one markdown stripper for the knowledge and spec gates; carries the theoretical review findings of #2406), #2408 (BUG-129), #2410 (CLI-111, the code findings of CLI-098's archive review), #2414 (CLI-112, read the registry of the repository--reponames).feat(tools): install Claude Code and agy through mise at their newest…
mlorentedev commentedon Oct 13, 2026
Ledger update (2026-10-13, evening): where every row stands
About 31 of the epic's ~62 rows are done in 8 days (10-05 to 10-13), a sustained 3.9 rows a day. The overnight burst on 10-12/13 (22 items in ~36 h) is not that rate.
tasks.md:28box is stale), P1, P2, P3 (no code), P4, P5a, P6, P7a/b, P9, P10a9c0a9fb)macos-defaults.sh, not started.zsh/nvm.zshstill on main),mise.lock, H3, H4, H5, H6backupOnce), X1 (#2331, not yet required), X2, X4WIP: 13 active specs on
origin/mainagainst ADR-043's limit of 10. Archivable after their reviews: AI-045 and TOOL-013. Owner-blocked: FIX-WIN-TUI-001 (#2019). Starting S1, PLAT-003 or S11 needs four archives.Issue balance: 429 open. Since 10-12: 19 closed, 31 opened (net +12).
Critical path, not PR count. The agent effort is about 45-55 PRs, but the calendar is set by:
Estimate
mlorentedev commentedon Oct 13, 2026
Plan to close waves 1, 2 and 2.5 and start herdr (2026-10-13, owner priority)
Finding: the pin on main is
DOTF_VERSION=0.68.0, and 0.68.0 already carries every reader these rows were waiting for: the TOML merge (e0be8242, H4),versionArgs(f6557b46, kubectl/helm),--no-remove, and the cask reader (040c1fcc). By the repo's own rule (#1814 class), H4, kubectl/helm and the casks can land now. Ordering hazard: an older dotf refuses the whole catalog on the new cask key, and the Mac runs 0.67.0, so the cask PR lands after the Mac runs 0.69.0.Agent, in order (no owner input needed):
claude,piandagyon PATH after the first converge: claude and agy done in feat(tools): install Claude Code and agy through mise at their latest release #2392 (from-zero.yml, "The agents resolve on PATH"); pi waits on Move the pi CLI install from the setup twins into packages.json #2278, two PRs (reader now, entry after the release carrying it is the pin; sequencing on Move the pi CLI install from the setup twins into packages.json #2278)herdrdeploy entry, TOML merge), H3 (pin drift and attestations), H5 (doctor checks), H6 (agent integrations), H9 (lazygit keybinding). Track H lives under PLAT-001c, so no new spec# mise: clipinsscripts/macos-defaults.sh, code and dry run only (applying it on the Mac is the owner's call)verification.mdAC1,dotf spec reviewdotf spec review, archive on PASSOwner, ordered by what each unblocks:
runbook-macos-workstation-setupNothing is dropped: before any
spec archive, its open boxes move to a row here or to their owning issue. A deferral with no existing home is the one case that gets a new ticket, and it is said so when filed.feat(tools): install Claude Code and agy through mise at their latest…
mlorentedev commentedon Oct 13, 2026
Debt ledger, 2026-10-13 (after 0.69.0)
Found while landing #2416–#2422 and converging the Mac on 0.69.0. The Mac now reads
doctor: 173 pass, 0 FAIL, 5 WARN.::error::(shipped:::warning::+ hand-over),verification.md:136overclaims the guard, the third promotion line unanswered. Contract set, frozen until archive: f2/f5/f8 still pass on an empty filter, f1'smimo-v2\.5"is quote-shape dependent and negates a grep error, f9's behavior sentence predates the weighted pool. Tests: AC4's shipped concurrency numbers are pinned by no testharness/skills/teardown/SKILL.mdis not a stray edit: it matches the vault's00_meta/skills/teardown/SKILL.md(the SSOT) byte for byte below the generated header. main's generated record is the stale one (generated_sha 9789e43dvs the vault'sb83fcf48)compile-harness.shin a PR; then msi runsgit checkout -- harness/skills/teardown/SKILL.md && git pull --ff-onlyci/macos-leg: PR #2063 closed, 7 commits not on main, 6 days olddotf --versionis an unknown flag; onlydotf versionworksdoctor --fixrestarts Colima and stops its containerscolima list); the adoption path doctor lacked is #2427.d916959, 181 → 182 items). The drill half stays open asdotf secrets usb verify+ yearly full RECOVER (owner decision on #1770), PLAT-001a rows.AGENT.md(builder, curator, planner, shipper) states its bare-string skills are deliberately ungated because they are situational, and the roster guard (SKILLS_MIN = 3) forbids dropping them. Remaining defect: the persona schema cannot declare "situational", so doctor'sPersona skill enforcementWARN (13 of 27) can never clear on a state the repo calls correct. Fix shape: a declarable thirdenforcevalue the gate ignores and doctor counts as declared, touchingpersona.go, the gate, the doctor check,compile-harness.shparsers andcheck-roster-consistency.py; spec-sized, queued until WIP allows a specapplied: firewall,ENABLED=yes, input policy DROP, witness written; from the Macssh -o BatchMode=yes msi trueover the mesh exit 0,nc -z -w 5 10.0.0.9 22over LAN exit 1./install.sh --only workstation-targetmust report0 changed; agent records the evidence in PLAT-001bverification.mdand ticks row 210harness/skills/*/SKILL.mdrecords from the vault on converge, and no check compares the committed record with the vault, so a vault skill edit leaves main stale silentlygenerated_shawith the vault sourceinstall.sh, the legacysetup-linux.shanddotf converge/doctor: different status markers, the tool catalog printed twice, legacy and converge output interleaveddotf(status helpers), legacy setup output routed through it; design via the advisor before codeufw default deny incomingcan block docker bridge (172.x) traffic to host services on msidotf doctorrun from a non-login shell (ssh host 'dotf doctor') reports the five tool-home variables (APPS_HOME,JAVA_HOME,MAVEN_HOME,GO_HOME,MINIKUBE_HOME) as FAIL and the env contract as WARN, because no profile was read; it cannot tell that from real drift. Measured on msi 2026-10-13: 5 FAIL non-login, 0 FAIL underzsh -licVAULT_PATHto the literal~/Projects/knowledgeinstead of the ADR-025 resolver (checks_automemory.go,checks_vault_hooks.go,checks_trigger_targets.go,checks_deploy.go:61); #2425 fixed only its own checkenv.ResolvePathNot debt, recorded so nobody re-opens it:
agent-extensionsre-registering pdf-modifier was a first-run add, not a loop; the Mac's next plan reads0 MCP server(s) to add, 4 present(msi to confirm on its second run).Also not debt:
doctor --fixremoved sixdenyrules of the formBash(...:*)that matched nothing; the working forms (Bash(git push *--force*)etc.) are present, deployed fromai/claude/settings.json.mlorentedev commentedon Oct 14, 2026
Windows from-zero production-catalog run (EGW-LEN029, corporate box, 2026-10-13): not converged. The catalog stays excluded.
The bats channel is already solved and released.
npm:batswithMISE_NPM_PACKAGE_MANAGER=npmscoped to the install child landed in #2345 (007c92fc), andgit merge-base --is-ancestor 007c92fc ef5d135aconfirms that 0.69.0 carries it. What this run tested is the remaining AC4 row: the full production catalog, run from zero with the released binary, twice.Setup: installed dotf 0.69.0; fixture =
git archive e7338fb2, withplatformsremoved from themiseentry in the copy only (packages.jsonon main is untouched).HOME,XDG_CONFIG_HOME,XDG_STATE_HOMEandMISE_{DATA,CACHE,STATE}_DIRpoint under%TEMP%\z2. PATH has no node, npm or mise.dotf converge --repo <fixture> --only tools --planlisted onlysops, misepluscopilot, yarn (npm), with no winget or uv-tool installs. The real~\.local\binheld 22 entries before and after.sops 3.13.1,mise 2026.9.13installed into the fixture homemise ls --installed= 37);bin-pathshasbats.cmd,direnv.exe,node.exe;npm.package_managerstaysautocopilot: npm exited 0 but copilot does not run on PATH; the same foryarn. Launchers land in<MISE_DATA_DIR>\installs\node\24.11.1\, because mise's Node has no npmrc settingprefix=%APPDATA%\npm. Filed as #2438 (TOOL-027), which blocks activationchanged=0mise exec -- bats --version/bin/bash: ...\bats: No such file or directory, becausebashresolves toC:\WINDOWS\system32\bash.exe(WSL) first on this PATH. WithC:\Program Files\Git\binprepended it reportsBats 1.13.0. That is #2346 (BUG-122), now measuredDiscarded artefact: a first attempt (
%TEMP%\z1) also overrodeUSERPROFILE. Ten aqua tools then failed Sigstore verification withTUF error: Could not determine cache directory. With onlyHOMEoverridden (z2), all of them installed. Record this for any future isolated Windows run: do not overrideUSERPROFILE.Not exercised (satisfied by host copies on PATH):
opencode,bw(npm),poetry,pre-commit(uv-tool), and the wingetsystementriesgh,eza,docker,aws. A truly empty box would also hit #2438 for opencode and bw.Next for activation: #2438, then #2346, then repeat this run. Fixture dirs
%TEMP%\z1and%TEMP%\z2are left on the box for the owner to remove.