diff --git a/.gitignore b/.gitignore index dbbfeaf77..5d5d4ab1f 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ result .init.local.lua .direnv .mise.local.toml +fnox.local.toml +mise/fnox/*.local.toml todo.txt diff --git a/.tickets/mbm-55qf.md b/.tickets/mbm-55qf.md new file mode 100644 index 000000000..2d239e436 --- /dev/null +++ b/.tickets/mbm-55qf.md @@ -0,0 +1,44 @@ +--- +id: mbm-55qf +status: closed +deps: [] +links: + [ + mbm-buez, + mbm-c3sd, + mbm-ju5m, + mbm-xqjv, + mbm-m0rs, + mbm-9ov0, + mbm-8afn, + mbm-qkmx, + ] +created: 2026-06-22T21:33:33Z +type: feature +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Implement mise dotfile symlink classifier preflight + +Build a read-only preflight used by the mise bootstrap migration to inspect each target in mise.toml [dotfiles] before any link/adopt operation. It must follow symlink chains like ~/.config/ghostty -> /nix/store/...home-manager-files -> /nix/store/...hm_ghostty -> ~/.dotfiles/config/ghostty and classify final ownership. File hints: mise.toml, scripts/mise/doctor, scripts/mise/bootstrap-final, lat.md/migration/mise-parity-checklist.md, home/common/lib.nix. + +## Acceptance Criteria + +1. A script or doctor subcommand reads every mise.toml [dotfiles] target and prints a dry-run table with installed path, symlink chain, final target, and class. +2. Classes include repo-final, store-flake-source, store-generated, external-final, real-directory, real-file, missing, and conflict/unknown. +3. The script never mutates filesystem state and exits nonzero only for true conflicts or unreadable paths. +4. The report correctly identifies repo-final paths documented in lat.md/migration/mise-parity-checklist.md, including ghostty, hammerspoon, nvim, tmux, kitty, kanata macbook files, SSH config, and espanso app-support path. +5. lat.md/migration/mise-parity-checklist.md is updated if classification names or behavior change. +6. Existing validation still passes: lat_check and relevant shell lint/format checks. + +## Notes + +**2026-06-22T21:47:36Z** + +Implemented read-only scripts/mise/dotfile-preflight and wired scripts/mise/doctor plus mise task dotfiles:preflight. Classifier reads mise.toml [dotfiles], follows full symlink chains, reports target/source/final/class/status, and exits nonzero only on unknown/conflict. Validation run found safe repo-final targets: ghostty, hammerspoon, kitty, nvim, tmux, ~/bin; missing safe targets: fnox config, ~/.config/ssh, ~/.config/espanso; needs handling: generated mise config, real fish/kanata/.local/bin dirs, store-flake git files. Also confirmed mise targets for SSH and espanso are wrong vs current ~/.ssh/config and ~/Library/Application Support/espanso ownership. Checks: scripts/mise/dotfile-preflight, --json, shellcheck doctor/bootstrap-final, lat_check. scripts/mise/doctor still exits 1 because fnox command missing on this host, unrelated to classifier. + +**2026-06-22T21:48:53Z** + +Follow-up: added inventory-only checks for documented repo-final paths not yet represented correctly in mise.toml: ~/.ssh/config, ~/Library/Application Support/espanso, and ~/.config/kanata/macbook\*.kbd. Latest preflight summary: safe=13, needs-handling=7, conflicts=0. diff --git a/.tickets/mbm-77a2.md b/.tickets/mbm-77a2.md new file mode 100644 index 000000000..7a55ebbe1 --- /dev/null +++ b/.tickets/mbm-77a2.md @@ -0,0 +1,52 @@ +--- +id: mbm-77a2 +status: closed +deps: 4:1:deps: 4:1:deps: [, mbm-8afn, mbm-b597] +links: [mbm-sskn, mbm-s5i1, mbm-9ov0] +created: 2026-06-23T16:43:19Z +type: feature +priority: 1 +assignee: Seth Messer +tags: [mise, migration, fish] +--- + +# Port Nix-generated fish config to static mise dotfiles + +Port all Home Manager-generated fish shell configuration to committed static files under mise/dotfiles/fish/. Current mise/dotfiles/fish/ is ~25 lines; HM generates 279-line config.fish + 20 functions + 3 plugins + keybindings + theme + completions. + +Files to port: + +- config.fish: shell init, PATH, PLUG_EDITOR, TMUX_SESSION, completions, keybindings, theme, ghostty integration, HM session vars (replaced with fnox/mise equivalents) +- conf.d/plugin-autopair.fish, plugin-done.fish, plugin-nix-env.fish (nix-env plugin may be retired) +- conf.d/devenv-tasks-run.fish +- functions/\*.fish (jj, fzf widgets, git-worktree, helium, nix-shell, ask, bind_bang, bind_dollar, fish_greeting, pr, sz, yy, etc.) + +All content is static — no Nix interpolation needed. PATH references switch from Nix store to Brew/MAS paths. Secret loading switches from opnix to fnox. + +## Acceptance Criteria + +1. mise/dotfiles/fish/config.fish contains all shell init, PATH, PLUG_EDITOR, TMUX_SESSION, and keybindings from the HM-generated version. +2. mise/dotfiles/fish/conf.d/ contains all plugin and integration files (autopair, done, devenv-tasks-run). nix-env plugin may be intentionally removed. +3. mise/dotfiles/fish/functions/ contains all 20 fish functions (jj, fzf widgets, git-worktree, helium, etc.). +4. mise/dotfiles/fish/completions/ contains generated completions (jj, mix, git-worktree, etc.). +5. Theme file is committed under mise/dotfiles/fish/conf.d/ or mise/dotfiles/fish/theme.fish. +6. Ghostty shell integration is resolved (either via Brew ghostty or committed snippet). +7. Secret/env loading is wired to fnox (or documented as deferred to mbm-b597). +8. mise bootstrap --dry-run notes fish as expected conflict requiring --force-dotfiles after backup. +9. lat_check passes. + +## Notes + +**2026-06-23T17:43:21Z** + +Ported all Nix-generated fish config to static mise/dotfiles/fish/: + +1. config.fish (8.0KB) — complete port of HM's 279-line generated config: shell init, PATH (Brew paths), jj/mix/git-worktree completions, env vars, PLUG_EDITOR, TMUX_SESSION, abbreviations, aliases, fzf integration, keybindings (ctrl-a/e/y/v/s/c/d/b/o, bang shortcuts), Everforest theme, Ghostty integration (Brew cask path), zoxide/starship/mise/direnv init, conf.d sourcing. +2. 20 fish functions — all ported: \_\_git_worktree_names, \_fzf_preview_file, \_prompt_move_to_bottom, \_prompt_reset_mouse, ask, bind_bang, bind_dollar, fish_greeting, fzf-dir-widget, fzf-jj-bookmarks, git-worktree-cd/new/pr/prune, helium, jj, nix-shell, pr, sz (simplified — no HM session vars), yy. +3. 5 conf.d files: devenv-tasks-run, fnox (secret loading from mbm-b597), mise (mise+fnox activation), plugin-autopair, plugin-done. +4. nix-env plugin intentionally removed (no Nix shell management). +5. Nix store paths replaced with Brew/MAS equivalents (eza, trash, fzf, starship, ghostty, etc.). +6. OpNix secret paths replaced with fnox paths. +7. Fish syntax validated (fish -n passes). +8. Preflight: fish shows as real-directory (expected — requires --force-dotfiles after backup). + lat_check passed. diff --git a/.tickets/mbm-8afn.md b/.tickets/mbm-8afn.md new file mode 100644 index 000000000..4cc019e90 --- /dev/null +++ b/.tickets/mbm-8afn.md @@ -0,0 +1,58 @@ +--- +id: mbm-8afn +status: closed +deps: [] +links: + [ + mbm-buez, + mbm-c3sd, + mbm-ju5m, + mbm-xqjv, + mbm-m0rs, + mbm-55qf, + mbm-9ov0, + mbm-qkmx, + ] +created: 2026-06-22T21:33:34Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Port generated Home Manager config fragments for mise bootstrap + +Move or replace Home Manager-generated config fragments that current live configs depend on, using committed static files or small deterministic render scripts. Focus on generated files that are not repo-final symlinks. File hints: home/common/programs/hammerspoon/default.nix, home/common/programs/shade-next/default.nix, home/common/programs/tmux/default.nix, home/common/programs/starship/default.nix, home/common/programs/karabiner/default.nix, home/common/programs/pi-coding-agent/default.nix, scripts/mise/setup-pi, lat.md/migration/mise-parity-checklist.md. + +## Acceptance Criteria + +1. Required generated fragments are inventoried and assigned target owners: committed file, scripts/mise renderer, manual, or Nix-retained. +2. Hammerspoon fragment parity is handled for nix_path.lua and shade-next.lua without editing generated files at runtime. +3. Tmux nix.conf replacement or retain decision is implemented and documented. +4. Starship, shade, shade-next, karabiner, process-compose, sesame, and 1Password SSH agent generated config decisions are documented and implemented where needed for v1. +5. No launch/app reload occurs except explicitly safe validation commands. +6. lat_check passes after doc updates. + +## Notes + +**2026-06-23T13:03:08Z** + +Implemented fragment porting for mbm-8afn: + +1. Created committed static files under mise/fragments/ for 7 generated fragments: + - mise/fragments/hammerspoon/nix_path.lua (PATH + env vars) + - mise/fragments/hammerspoon/shade-next.lua (app info, chords, prefills) + - mise/fragments/tmux/nix.conf (fish shell path → Brew) + - mise/fragments/shade-next/config.toml (identity, paths, UI, keys) + - mise/fragments/sesame/config.jsonc (piSessionPaths) + - mise/fragments/process-compose/shortcuts.yaml + - mise/fragments/process-compose/theme.yaml +2. Added all fragment targets to mise.toml [dotfiles] as individual file links. +3. Documented full fragment inventory in lat.md/migration/mise-parity-checklist.md: + - 7 committed static files (implemented) + - starship/karabiner: already static + - shade v1, allowed_signers, 1Password SSH: Nix-retained + - Fish: deferred to per-file reconciliation + - Bash, surfingkeys, slk, HM plugins: deferred or Nix-retained +4. Preflight confirms all fragments classify correctly (store-flake-source/store-generated → needs-handling). +5. No destructive actions. lat_check passed. Preflight: safe=11, needs-handling=15, conflicts=0. diff --git a/.tickets/mbm-9ov0.md b/.tickets/mbm-9ov0.md new file mode 100644 index 000000000..e3289ca7d --- /dev/null +++ b/.tickets/mbm-9ov0.md @@ -0,0 +1,47 @@ +--- +id: mbm-9ov0 +status: closed +deps: 4:1:deps: 4:1:deps: 4:1:deps: 4:1:deps: 4:1:deps: [, mbm-55qf, mbm-qkmx, mbm-8afn, mbm-buez, mbm-c3sd] +links: [mbm-buez, mbm-c3sd, mbm-ju5m, mbm-xqjv, mbm-m0rs, mbm-55qf, mbm-8afn, mbm-qkmx, mbm-77a2, mbm-sskn, mbm-s5i1] +created: 2026-06-22T21:33:36Z +type: feature +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Design and implement one-command mise bootstrap v1 + +Replace the README Nix-first installation path with a Mac-first one-command bootstrap once the preflight and critical blockers are ready. The command should be pasteable into Terminal.app, support fresh and partial systems, and repair or clearly report broken setup. File hints: README.md, scripts/install.sh, scripts/aarch64-darwin_bootstrap.sh, scripts/mise/bootstrap-final, scripts/mise/doctor, scripts/mise/ensure-determinate-nix, scripts/mise/ensure-homebrew, mise.toml. + +## Acceptance Criteria + +1. README documents a single curl/bash command for the mise migration bootstrap, with warnings and expected prompts. +2. Bootstrap detects hostname, prompts to confirm/correct megabookpro or workbookpro, and sets ComputerName, HostName, and LocalHostName. +3. Bootstrap detects Command Line Tools and EULA/MAS gates, automates safe parts, and clearly reports manual gates. +4. Bootstrap supports fresh and partially installed systems by running preflight before mutation and reporting conflicts. +5. Bootstrap is safe to rerun: repeated runs are idempotent or produce clear no-op/manual reports. +6. Mac-first v1 is explicit; UGREEN NAS and Raspberry Pi/Home Assistant are documented as future platform goals, not blockers. +7. No destructive bootstrap is run during implementation without explicit user approval. + +## Notes + +**2026-06-23T20:59:58Z** + +Implemented one-command mise bootstrap v1: + +1. README updated: single curl/bash one-liner, mise-first bootstrap documented, Nix retained for specific cases. +2. scripts/install.sh — full entry point script: + - Detects hostname, prompts to confirm megabookpro/workbookpro + - Checks/installs CLT, accepts Xcode license, installs Rosetta 2 + - Clones or updates ~/.dotfiles + - Runs dotfile-preflight (classifier) + doctor (preflight) + - Shows plan, asks confirmation before each phase + - Installs Homebrew → Nix (official installer) → mise bootstrap + - Post-bootstrap: apps, pi setup, fnox secrets, helium, complex defaults + - Sets ComputerName/HostName/LocalHostName + - Reports next steps (shell restart, fnox token, Okta, kanata) +3. Idempotent: detects existing state, reports conflicts, skips installed components +4. Non-destructive: all mutations behind confirmation prompts +5. Mac-first v1; other platforms documented as future goals in README +6. Shellcheck clean, lat_check passes, no destructive commands run. diff --git a/.tickets/mbm-b597.md b/.tickets/mbm-b597.md new file mode 100644 index 000000000..1ba2f4330 --- /dev/null +++ b/.tickets/mbm-b597.md @@ -0,0 +1,43 @@ +--- +id: mbm-b597 +status: closed +deps: [] +links: [] +created: 2026-06-22T20:32:32Z +type: feature +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Prototype fnox replacement for OpNix-rendered secrets + +Make the fnox migration path concrete without committing plaintext secrets. The current plan is to keep 1Password as the vault, use fnox as user-land resolver, and render legacy files under ~/.config/fnox/secrets/ so Pi, shell startup, Apple notarization, and .s3cfg keep working while callers move away from OpNix paths. + +Context: migration session chose fnox.jdx.dev to replace OpNix declarations while retaining 1Password. + +File hints: mise/fnox/config.toml, scripts/mise/render-fnox-files, mise.toml task `fnox:render`, existing OpNix/secrets references under home/common/ and modules/. + +## Acceptance Criteria + +1. Existing OpNix-managed secret outputs used by this repo are inventoried with destination paths and consumers. +2. `mise/fnox/config.toml` contains placeholder-safe mappings for required secrets and no plaintext secret values. +3. `scripts/mise/render-fnox-files` can run in dry-run/check mode or otherwise validates prerequisites before writing. +4. Legacy output paths under ~/.config/fnox/secrets/ are documented so existing consumers can migrate gradually. +5. 1Password service account token handling is local-only/encrypted and never committed as plaintext. +6. `lat.md/migration/mise-bootstrap.md` is updated if the secrets ownership model changes; `lat_check` passes. + +## Notes + +**2026-06-23T16:47:57Z** + +Implemented fnox prototype: + +1. Secret inventory documented (5 common + 1 work): ENV_VARS_SH, S3CFG, APPLE_ID_EMAIL, APPLE_TEAM_ID, APPLE_NOTARYTOOL_PASSWORD, WORK_ENV_VARS_SH. +2. mise/fnox/config.toml: placeholder-safe (AGE_RECIPIENT_REPLACE_ME), all 1Password refs use op:// URIs, work secrets commented out. +3. scripts/mise/render-fnox-files: added --check, --dry-run, --inventory modes. Dry-run reports prerequisites without writing. +4. Shell init snippets: mise/dotfiles/fish/conf.d/fnox.fish (fish), mise/dotfiles/bash/fnox.sh (bash). Both load env-vars.sh, LAT*LLM*\*, apple secrets, work secrets. Replaces OpNix programs.{fish,bash,zsh} shell init. +5. Legacy output paths: ~/.config/fnox/secrets/env-vars.sh, ~/.s3cfg, ~/.config/fnox/secrets/apple-developer/\*. Documented in inventory. +6. Token: OP_SERVICE_ACCOUNT_TOKEN stays local/encrypted via fnox age provider, never committed. +7. mise.toml: added fnox:check, fnox:dry-run tasks; bash dotfile target for fnox.sh. +8. lat_check passed, shellcheck clean. diff --git a/.tickets/mbm-buez.md b/.tickets/mbm-buez.md new file mode 100644 index 000000000..c9f36ddda --- /dev/null +++ b/.tickets/mbm-buez.md @@ -0,0 +1,50 @@ +--- +id: mbm-buez +status: closed +deps: [] +links: + [ + mbm-c3sd, + mbm-ju5m, + mbm-xqjv, + mbm-m0rs, + mbm-55qf, + mbm-9ov0, + mbm-8afn, + mbm-qkmx, + ] +created: 2026-06-22T21:33:35Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Fix espanso migration path and launchd parity + +Make espanso migration match current Home Manager behavior. Current Nix links config/espanso to ~/Library/Application Support/espanso and creates a launchd agent/log dirs. Current mise points at ~/.config/espanso and /opt/homebrew/bin/espanso, which may be wrong. File hints: home/common/programs/espanso/default.nix, home/common/services.nix, config/espanso, mise.toml, mise/Brewfile, scripts/mise/doctor. + +## Acceptance Criteria + +1. Confirm Homebrew espanso install type and real executable path without destructive app changes. +2. Update mise.toml or scripts/mise so espanso uses the correct config location and launchd ProgramArguments. +3. Ensure ~/Library/Logs/espanso exists before launchd starts. +4. Add doctor/preflight checks for config path, executable path, launchd label, and espanso status. +5. Run only non-destructive validation unless user approves starting/restarting espanso. +6. Update lat.md/migration/mise-parity-checklist.md with final espanso status and validation command. + +## Notes + +**2026-06-23T13:13:17Z** + +Fixed espanso migration: + +1. Verified espanso is a Brew cask (not formula): binary at /Applications/Espanso.app/Contents/MacOS/espanso, not /opt/homebrew/bin/espanso. +2. Added 'cask "espanso"' to mise/Brewfile. +3. Fixed mise launchd agent program path from /opt/homebrew/bin/espanso to /Applications/Espanso.app/Contents/MacOS/espanso. +4. Verified config path: ~/Library/Application Support/espanso (matches 'espanso path config' output). +5. Dotfile target already correct from mbm-qkmx. +6. Added comprehensive doctor checks: config symlink, binary path, espanso path/config/version, log dir, launchd agent (both Nix and mise labels). +7. Log dir ~/Library/Logs/espanso/ must exist before launchd start (documented in checklist). +8. Doctor confirms: config link OK, binary OK, config path match, version 2.3.0, log dir OK, Nix launchd agent running. + Validation: shellcheck clean, doctor espanso all-ok, lat_check passed. No destructive actions. diff --git a/.tickets/mbm-c3sd.md b/.tickets/mbm-c3sd.md new file mode 100644 index 000000000..81e4bb1f9 --- /dev/null +++ b/.tickets/mbm-c3sd.md @@ -0,0 +1,49 @@ +--- +id: mbm-c3sd +status: closed +deps: [] +links: + [ + mbm-buez, + mbm-ju5m, + mbm-xqjv, + mbm-m0rs, + mbm-55qf, + mbm-9ov0, + mbm-8afn, + mbm-qkmx, + ] +created: 2026-06-22T21:33:36Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Validate 1Password Brew and Aqua ownership for signing and secrets + +Prove the mise target for 1Password is safe before removing nix-darwin ownership. Current Nix installs GUI to /Applications and op to /usr/local/bin/op, and git/jj signing uses /Applications/1Password.app/Contents/MacOS/op-ssh-sign. File hints: modules/darwin/\_1password.nix, home/common/programs/git, home/common/programs/jj, home/common/programs/ssh, mise/Brewfile, mise.toml, mise/fnox/config.toml, scripts/mise/render-fnox-files. + +## Acceptance Criteria + +1. Validate Brew cask installs 1Password.app in /Applications and preserves op-ssh-sign path. +2. Validate the mise/Aqua op CLI can integrate with the GUI and 1Password agent without conflicting with any Brew CLI. +3. Validate git and jj signing config points at a working op-ssh-sign path. +4. Validate fnox/1Password secret access works with the selected op/GUI setup. +5. Document Gatekeeper/Open Anyway behavior if it remains a manual first-launch step. +6. Update lat.md/migration/mise-parity-checklist.md with final status and validation evidence. + +## Notes + +**2026-06-23T13:24:30Z** + +Validated 1Password Brew/Aqua ownership: + +1. Brew cask installs to /Applications/1Password.app — same as Nix nix-darwin target. Confirmed via brew info --cask --json. +2. op-ssh-sign at /Applications/1Password.app/Contents/MacOS/op-ssh-sign (755, 1.4M) — embedded in app bundle, unaffected by install method. +3. SSH agent socket at ~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock — part of app container, independent of install method. +4. op CLI (Nix: /usr/local/bin/op v2.34.0) successfully talks to GUI: 'op account get' returns account details. Aqua op uses same local API. +5. Git/jj signing config not present in Nix code either — needs explicit gpg.ssh.program config pointing at op-ssh-sign for both Nix and mise. +6. fnox/1Password access via OP_SERVICE_ACCOUNT_TOKEN + op CLI — mechanism independent of op CLI install source. +7. Gatekeeper: Brew cask first launch may require System Settings > Privacy > Open Anyway — manual step, same as Nix. + Updated checklist: status safe, cutover blocker checked. lat_check passed. diff --git a/.tickets/mbm-i2na.md b/.tickets/mbm-i2na.md new file mode 100644 index 000000000..1f98b2eea --- /dev/null +++ b/.tickets/mbm-i2na.md @@ -0,0 +1,60 @@ +--- +id: mbm-i2na +status: closed +deps: [] +links: [] +created: 2026-06-23T14:08:01Z +type: feature +priority: 2 +assignee: Seth Messer +tags: [mise, migration, nix] +--- + +# Prototype megalithic/flakes repo for mise nix backend consumption + +Create a separate Nix flakes repository at github.com/megalithic/flakes to hold custom packages currently in pkgs/default.nix that are too complex for Brew/scripts. Consumed by the jbadeau/mise-nix plugin via flake references in mise.toml. + +Packages to migrate: + +- helium (Widevine-patched browser with custom wrapper) +- kanata + kanata-bar (TCC-sensitive binary + app + sudoers + launchd) +- Other custom packages: brave-browser-nightly, bloom, slk, handy, tidewave, tidewave-cli, chrome-devtools-mcp, whisperkit-cli + +Mise usage: +[tools] +"nix:helium@github+megalithic/flakes#helium" = "latest" + +Benefits: + +- Keeps Nix for complex package builds (Widevine patching, TCC stability, app wrappers) +- Lets mise orchestrate install/update +- Removes these from dotfiles flake, simplifying nix-darwin/HM activation +- Single source of truth for custom app derivations + +## Acceptance Criteria + +1. github.com/megalithic/flakes repo created with flake.nix exposing packages for helium, kanata, and kanata-bar. +2. jbadeau/mise-nix plugin installed: mise plugin install nix https://github.com/jbadeau/mise-nix.git +3. At least one package verified: mise install "nix:helium@github+megalithic/flakes#helium" succeeds. +4. Custom packages removed from pkgs/default.nix in dotfiles repo (post-validation). +5. mise.toml [tools] updated to reference flakes for migrated packages. +6. lat.md/flakes.md documents the new repo, package list, and mise-nix usage. + +## Notes + +**2026-06-24T00:10:42Z** + +Prototyped megalithic/flakes repo at ~/code/flakes (local only): + +1. flake.nix imports dotfiles custom package overlay from pkgs/default.nix +2. Exposes 8 packages: helium, brave-browser-nightly, bloom, handy, slk, tidewave, tidewave-cli, chrome-devtools-mcp +3. Verified: nix flake show lists all packages, nix build .#helium — started building +4. Only aarch64-darwin supported (macOS Apple Silicon) + +Next steps before GitHub push: + +- Add kanata + kanata-bar packages (need to extract from nix-darwin module) +- Switch dotfiles input from local path to github:megalithic/dotfiles +- Install jbadeau/mise-nix plugin +- Test: mise install 'nix:helium@github+megalithic/flakes#helium' +- Remove migrated packages from pkgs/default.nix (post-validation) diff --git a/.tickets/mbm-ju5m.md b/.tickets/mbm-ju5m.md new file mode 100644 index 000000000..1f7de8387 --- /dev/null +++ b/.tickets/mbm-ju5m.md @@ -0,0 +1,55 @@ +--- +id: mbm-ju5m +status: closed +deps: [] +links: + [ + mbm-buez, + mbm-c3sd, + mbm-xqjv, + mbm-m0rs, + mbm-55qf, + mbm-9ov0, + mbm-8afn, + mbm-qkmx, + ] +created: 2026-06-22T21:33:34Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Make kanata and kanata-bar migration executable or explicitly Nix-retained + +Turn the kanata audit findings into a safe migration implementation or a clear Nix-retained gate. Current Nix owns TCC-sensitive binary copying, daemon launchd, sudoers, mutable active config symlink, TCP port 5829, kanata-bar app/config/launchd, and Hammerspoon switching. File hints: modules/darwin/kanata.nix, home/common/programs/kanata/default.nix, config/kanata, config/hammerspoon, mise.toml, lat.md/migration/mise-parity-checklist.md. + +## Acceptance Criteria + +1. Document exact behavior that must be preserved before Nix ownership can be removed. +2. Either implement a safe scripts/mise kanata installer/preflight or mark kanata and kanata-bar as explicitly Nix-retained for v1. +3. If implemented, script preserves stable /usr/local/bin/kanata behavior, validates sudoers with visudo, manages launchd safely, and does not break TCC path stability. +4. Validation commands cover /usr/local/bin/kanata --version, launchctl daemon state, TCP port 5829, kanata-bar launch/config, and Hammerspoon config switching. +5. mise bootstrap cannot apply an incomplete kanata path silently. +6. lat.md/migration/mise-parity-checklist.md status is updated from unsafe to safe, partial, or Nix-retained with rationale. + +## Notes + +**2026-06-23T13:57:12Z** + +Decision: kanata and kanata-bar Nix-retained for v1. +10 behaviors that make script migration too fragile: + +1. Binary TCC cdhash stability (must copy to /usr/local/bin/kanata, version-aware skip) +2. sudoers for passwordless pkill (requires visudo validation) +3. Privileged launchd daemon (runs via sudo, needs careful unload/reload) +4. Mutable config symlink (~/.config/kanata/kanata.kbd, written by activation script, switched by Hammerspoon) +5. TCP port 5829 for kanata-bar + Hammerspoon communication +6. kanata-bar app download with pinned hash, unzip, config generation +7. kanata-bar config.toml referencing kanata binary path and port +8. kanata-bar launchd agent with /usr/bin/open -a path +9. SF Symbol icons from config/kanata/icons +10. Post-activation service restart (kanata daemon + kanata-bar, timed for TCP readiness) + Config files already migrated: individual .kbd targets in mise.toml dotfiles. + Checklist updated: kanata daemon status → Nix-retained, kanata-bar → Nix-retained, both validated. + lat_check passed. Revisit if upstream kanata provides a Brew cask with stable binary path. diff --git a/.tickets/mbm-m0rs.md b/.tickets/mbm-m0rs.md new file mode 100644 index 000000000..e6fd3fbfb --- /dev/null +++ b/.tickets/mbm-m0rs.md @@ -0,0 +1,48 @@ +--- +id: mbm-m0rs +status: closed +deps: [] +links: + [ + mbm-buez, + mbm-c3sd, + mbm-ju5m, + mbm-xqjv, + mbm-55qf, + mbm-9ov0, + mbm-8afn, + mbm-qkmx, + ] +created: 2026-06-22T21:33:35Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Add Okta Verify privileged pkg installer plan for mise migration + +Replace the placeholder Okta Verify comment with a safe plan or implementation that preserves current nix-darwin behavior: use the official .pkg and /usr/sbin/installer so privileged postinstall installs LaunchDaemons and SecurityAgentPlugin. File hints: modules/darwin/okta-verify.nix, home/common/programs/okta-verify/default.nix, mise/Brewfile, scripts/mise, lat.md/system-config.md, lat.md/migration/mise-parity-checklist.md. + +## Acceptance Criteria + +1. Current pinned Okta version/build/hash and pkg receipt behavior are captured from modules/darwin/okta-verify.nix. +2. A scripts/mise implementation or explicit Nix-retained decision exists; Brew cask/MAS extraction is not treated as equivalent. +3. Implementation, if added, is idempotent on pkgutil receipt version and uses /usr/sbin/installer only with explicit user approval or documented bootstrap phase. +4. Validation covers pkgutil receipt, expected LaunchDaemons, SecurityAgentPlugin, and app presence. +5. mise bootstrap reports Okta as blocked/manual/Nix-retained rather than silently skipping it. +6. lat.md/migration/mise-parity-checklist.md and lat.md/system-config.md are updated if ownership changes. + +## Notes + +**2026-06-23T14:21:49Z** + +Implemented Okta Verify privileged pkg installer: + +1. Created scripts/mise/install-okta-verify with check/install subcommands. +2. check: validates pkgutil receipt, /Applications/Okta Verify.app, LaunchDaemon, optional daemons, SecurityAgentPlugin. Safe, no sudo. +3. install: downloads pinned .pkg (v9.63.0, build 6186-0c33212), runs /usr/sbin/installer (requires sudo). Idempotent on pkgutil receipt version. +4. Added mise tasks: okta:check (safe) and okta:install (requires sudo). +5. Added okta-verify check to scripts/mise/doctor. +6. Pinned version/build/sha256 match modules/darwin/okta-verify.nix. + Validation: shellcheck clean, install-okta-verify check passes (receipt OK, app OK, LaunchDaemon OK), lat_check passed. Checklist updated: Okta Verify status → safe, cutover blocker checked. diff --git a/.tickets/mbm-nhdu.md b/.tickets/mbm-nhdu.md new file mode 100644 index 000000000..0f8fafc06 --- /dev/null +++ b/.tickets/mbm-nhdu.md @@ -0,0 +1,43 @@ +--- +id: mbm-nhdu +status: closed +deps: 4:1:deps: [, mbm-55qf] +links: [] +created: 2026-06-22T20:32:32Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Harden mise bootstrap scripts for safe repeated runs + +Review and harden the imperative scripts that mise will run for behavior it cannot model declaratively. Scripts must be idempotent, host-aware where needed, safe around running apps/services, and clear about privileged or TCC-sensitive operations. + +Context: migration chose mise as orchestration, Brew/MAS for apps, fnox for secrets, direct scripts for special cases, and Nix retained only for legacy/project usage. + +File hints: scripts/mise/ensure-determinate-nix, scripts/mise/ensure-homebrew, scripts/mise/install-apps, scripts/mise/install-helium, scripts/mise/setup-pi, scripts/mise/install-pi-tools, scripts/mise/llama-server-launchd, scripts/mise/render-fnox-files, scripts/mise/apply-macos-complex-defaults, scripts/mise/doctor. + +## Acceptance Criteria + +1. Each script starts with strict shell options and gives clear failure messages. +2. Scripts avoid destructive writes unless guarded by checks/backups or explicit confirmation. +3. Host-specific behavior branches only on documented hostnames (`megabookpro`, `workbookpro`) or safe defaults. +4. Helium install path preserves the migration constraints: upstream release + local script, Widevine handling, signing/TCC safety, and no reinstall while app is running. +5. `scripts/mise/doctor` checks prerequisites and reports missing tools/config without mutating state. +6. Relevant docs in lat.md/migration/mise-bootstrap.md stay in sync; `lat_check` passes. + +## Notes + +**2026-06-24T00:01:30Z** + +Hardened all imperative scripts for safe repeated runs: + +1. install-apps: now runs 'brew bundle check' first, skips if satisfied. +2. bootstrap-final: each step guarded by MISE*BOOTSTRAP_SKIP*\* env vars (BREW, PI, SECRETS, DEFAULTS, HELIUM). Skippable individually. +3. apply-macos-complex-defaults: killall Dock/Finder only when WindowServer is present (Aqua domain check). Safe in CI/headless. +4. setup-pi: skips 'pi update --extensions' if npm/node_modules already exist (fresh-install guard). +5. pi-session-indexer: validates source script exists before exec. +6. sesame-session-indexer: validates sesame binary exists before exec. + All scripts verified: set -euo pipefail, clear error messages, idempotent or guarded. llm-server-launchd already host-aware (workbookpro gets higher ctx_size/parallel). + Shellcheck clean on all 6 modified scripts. lat_check passes. diff --git a/.tickets/mbm-qkmx.md b/.tickets/mbm-qkmx.md new file mode 100644 index 000000000..4ee5db7cb --- /dev/null +++ b/.tickets/mbm-qkmx.md @@ -0,0 +1,40 @@ +--- +id: mbm-qkmx +status: closed +deps: 4:1:deps: [, mbm-55qf] +links: [mbm-buez, mbm-c3sd, mbm-ju5m, mbm-xqjv, mbm-m0rs, mbm-55qf, mbm-9ov0, mbm-8afn] +created: 2026-06-22T21:33:33Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Reconcile mise dotfile targets with symlink ownership inventory + +Update mise dotfile ownership based on the symlink inventory so mise does not blindly map paths that Home Manager currently generates or maps to different app support locations. This should fix obvious mismatches and document retained/manual/generated cases. File hints: mise.toml, mise/dotfiles/fish, config/espanso, config/kanata, scripts/mise/doctor, lat.md/migration/mise-parity-checklist.md. + +## Acceptance Criteria + +1. mise.toml [dotfiles] is updated so repo-final targets map to the same final source paths used by current Home Manager. +2. Espanso target decision is explicit: either link ~/Library/Application Support/espanso to config/espanso or document and validate a supported XDG path. +3. Fish is not treated as equivalent to current Home Manager generated fish config unless missing snippets/functions are ported or explicitly deferred. +4. Store-generated and store-flake-source paths from the inventory are not silently overwritten by mise dotfiles. +5. mise bootstrap --dry-run or the new preflight reports no unexpected dotfile conflicts for known repo-final paths. +6. lat.md/migration/mise-parity-checklist.md reflects the final dotfile target decisions. + +## Notes + +**2026-06-23T12:28:32Z** + +Reconciled mise dotfile targets per classifier findings (mbm-55qf): + +1. ~/.config/ssh → ~/.ssh/config (individual file, correct path) +2. ~/.config/espanso → ~/Library/Application Support/espanso (app support path) +3. ~/.config/kanata → split into individual .kbd file targets (macbook.kbd, macbook-disabled.kbd) +4. Fish kept as directory target with note about deferred per-file reconciliation (mbm-8afn) +5. Git files kept as-is with store-flake-source note +6. mise config kept with store-generated note +7. mise.toml [dotfiles] section documented with inline comments explaining each group's status and deferral tickets +8. scripts/mise/dotfile-preflight KNOWN_INVENTORY cleared (all now mise.toml targets) + Preflight summary: safe=11, needs-handling=6, conflicts=0. lat_check passed. shellcheck passed. diff --git a/.tickets/mbm-s5i1.md b/.tickets/mbm-s5i1.md new file mode 100644 index 000000000..580c5b1ed --- /dev/null +++ b/.tickets/mbm-s5i1.md @@ -0,0 +1,44 @@ +--- +id: mbm-s5i1 +status: closed +deps: 4:1:deps: 4:1:deps: [, mbm-55qf, mbm-qkmx] +links: [mbm-77a2, mbm-sskn, mbm-9ov0] +created: 2026-06-22T20:32:02Z +type: bug +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Make mise bootstrap dry-run pass + +The mise bootstrap migration worktree currently has initial files under mise.toml, mise/, scripts/mise/, and lat.md/migration/. `mise bootstrap --dry-run` fails before any useful validation because the Homebrew formula lookup for `brew:yubikey-manager` returns 404. Fix package identifiers and any other first-pass bootstrap schema/package issues so dry-run reaches a complete plan or the next actionable error. + +Context: primary migration session /Users/seth/.pi/agent/sessions/--Users-seth-.dotfiles--/2026-06-21T21-36-04-449Z_019eec1c-b361-7336-903a-78a13c758ea8.jsonl; continuation /Users/seth/.pi/agent/sessions/--Users-seth-.dotfiles--/2026-06-22T13-47-12-380Z_019eef95-cc7c-7fb9-b93e-27171f74fe8e.jsonl. + +File hints: mise.toml [bootstrap.packages], mise/Brewfile, scripts/mise/doctor, lat.md/migration/mise-bootstrap.md. + +## Acceptance Criteria + +1. `mise bootstrap --dry-run` no longer fails on missing Homebrew formula `yubikey-manager`. +2. Homebrew package identifiers in `mise.toml` are verified against current Homebrew formula/cask names; invalid names are replaced or moved to the right installer path. +3. `mise tasks ls` still lists the migration tasks. +4. `scripts/mise/doctor` reports the new package-name validation or documents why validation remains manual. +5. `lat.md/migration/mise-bootstrap.md` is updated if ownership, package manager, or validation flow changes. +6. `lat_check` passes. + +## Notes + +**2026-06-23T15:24:37Z** + +mise bootstrap --dry-run now passes all package resolution. Fixed: + +1. yubikey-manager → already resolved (brew:ykman, no action needed). +2. Verified ALL brew: packages resolve: bash, blueutil, chafa, coreutils, curl, ffmpeg, fish, git, gnupg, imagemagick, llama.cpp (new), mas, openconnect, openssl@3, pinentry-mac, s3cmd, sox, sqlite, switchaudio-osx, tesseract, trash, ykman. +3. Added brew:llama.cpp (fixes missing install source blocker — Brew formula includes llama-server). +4. Added cask handy to Brewfile (researcher finding). +5. Added cask okta-verify to Brewfile (from mbm-m0rs). +6. Dry-run reaches expected fish conflict (real directory with mixed content — per-file reconciliation deferred): 'refusing to overwrite existing files: ~/.config/fish'. Resolution: manual backup then --force-dotfiles. +7. mise tasks ls lists all 10 migration tasks. +8. Checklist updated: dotfile safety row reflects dry-run status, llama.cpp install source resolved, cutover blocker checked. + lat_check passed. diff --git a/.tickets/mbm-sskn.md b/.tickets/mbm-sskn.md new file mode 100644 index 000000000..5a4f0f09a --- /dev/null +++ b/.tickets/mbm-sskn.md @@ -0,0 +1,48 @@ +--- +id: mbm-sskn +status: closed +deps: 4:1:deps: [, mbm-qkmx] +links: [mbm-77a2, mbm-s5i1, mbm-9ov0] +created: 2026-06-23T16:43:27Z +type: task +priority: 2 +assignee: Seth Messer +tags: [mise, migration, dotfiles] +--- + +# Add missing static tool configs to mise dotfiles + +Port remaining Nix-store-backed tool config files to mise dotfiles as committed static files. These are small, single-file configs currently symlinked to the Nix store via Home Manager. + +Files to port: + +- ~/.config/bat/config (theme: everforest, syntax mapping for ghostty) +- ~/.config/direnv/direnv.toml (whitelist prefix, hide_env_diff, load_dotenv) +- ~/.config/starship.toml (already a static file copied verbatim by Nix — just add as dotfile target) +- ~/.config/karabiner/karabiner.json (already a static file copied verbatim by Nix — just add as dotfile target) +- ~/.config/eza/theme.yml (Nix-store symlink) +- ~/.config/ripgrep/rc (Nix-store symlink) + +None of these have Nix interpolation — they are static content. + +## Acceptance Criteria + +1. All 6 config files are available as committed files under mise/dotfiles/ or mise/fragments/. +2. mise.toml [dotfiles] updated with targets for each file. +3. scripts/mise/dotfile-preflight reports correct classification for each new target. +4. lat_check passes. + +## Notes + +**2026-06-23T20:12:59Z** + +Added 6 static tool configs to mise dotfiles: + +1. ~/.config/bat/config → mise/dotfiles/bat/config (everforest theme + ghostty syntax mapping) +2. ~/.config/direnv/direnv.toml → mise/dotfiles/direnv/direnv.toml (whitelist, hide_env_diff, load_dotenv) +3. ~/.config/starship.toml → home/common/programs/starship/starship.toml (already committed, static) +4. ~/.config/karabiner/karabiner.json → home/common/programs/karabiner/karabiner.json (already committed, static) +5. ~/.config/eza/theme.yml → mise/dotfiles/eza/theme.yml (Everforest theme) +6. ~/.config/ripgrep/rc → mise/dotfiles/ripgrep/rc (flags + custom file types) + All classify as store-flake-source → needs-handling in preflight (correct). + lat_check passed. diff --git a/.tickets/mbm-xqjv.md b/.tickets/mbm-xqjv.md new file mode 100644 index 000000000..7a13dc7e3 --- /dev/null +++ b/.tickets/mbm-xqjv.md @@ -0,0 +1,64 @@ +--- +id: mbm-xqjv +status: closed +deps: [] +links: + [ + mbm-buez, + mbm-c3sd, + mbm-ju5m, + mbm-m0rs, + mbm-55qf, + mbm-9ov0, + mbm-8afn, + mbm-qkmx, + ] +created: 2026-06-22T20:32:31Z +type: task +priority: 2 +assignee: Seth Messer +tags: [ready-for-development] +--- + +# Audit mise migration parity against nix configuration + +Compare the initial mise bootstrap files against current nix-darwin/Home Manager ownership so the migration does not silently drop important behavior. Produce/update a durable checklist that maps Nix-managed programs, services, secrets, dotfiles, macOS defaults, and special apps to mise/bootstrap/Brew/fnox/script ownership. + +Context: initial migration session /Users/seth/.pi/agent/sessions/--Users-seth-.dotfiles--/2026-06-21T21-36-04-449Z_019eec1c-b361-7336-903a-78a13c758ea8.jsonl. Migration model is documented in lat.md/migration/mise-bootstrap.md. + +File hints: flake.nix, hosts/, home/common/, modules/, config/, bin/, pkgs/, mise.toml, mise/, scripts/mise/, ~/.local/share/pi/docs/.dotfiles/mise-bootstrap-migration.md. + +## Acceptance Criteria + +1. Current nix-darwin/Home Manager owned areas are inventoried by category: packages/apps, dotfiles, fish/shell, launchd/services, secrets, macOS defaults, custom packages/apps, Pi tooling, project environments. +2. Each category has a target owner: mise bootstrap, mise dotfiles, Brew/MAS, fnox, scripts/mise, or explicitly keep under Nix for now. +3. Gaps and intentionally-deferred items are listed with rationale; settings-sync remains deferred for v1. +4. Durable docs are updated in lat.md/migration/ or ~/.local/share/pi/docs/.dotfiles/ as appropriate. +5. No bootstrap commands are applied to the host during the audit. +6. `lat_check` passes if lat.md files changed. + +## Notes + +**2026-06-22T21:17:35Z** + +Added durable parity checklist at lat.md/migration/mise-parity-checklist.md and linked it from lat.md/migration/migration.md. Checklist covers host requirements, one-command bootstrap goals, Nix/darwin/HM responsibilities, risky apps, launchd, secrets, macOS defaults, program module backlog, and cutover blockers. No destructive bootstrap/apply/install commands run. lat_check passed. + +**2026-06-22T21:29:28Z** + +Updated symlink research: added symlink ownership inventory to lat.md/migration/mise-parity-checklist.md and clarified lat.md/architecture.md. Confirmed Home Manager has three distinct cases: live out-of-store config links that visually pass through /nix/store but resolve to ~/.dotfiles/config, store-backed flake source links, and generated Nix store files. Added adoption rule: follow symlink chain and classify repo-final/store-flake-source/store-generated/external-final/real-directory/real-file/missing before mise adopts any path. lat_check passed. + +**2026-06-22T21:34:05Z** + +Created follow-up migration tickets: mbm-55qf symlink classifier, mbm-qkmx dotfile reconciliation, mbm-8afn generated fragments, mbm-ju5m kanata/kanata-bar, mbm-buez espanso, mbm-m0rs Okta Verify, mbm-c3sd 1Password validation, mbm-9ov0 one-command bootstrap. Linked them to this audit and added deps from mbm-s5i1/mbm-nhdu where classifier/reconcile blocks safe dry-run hardening. + +**2026-06-24T01:09:47Z** + +Audit closeout: + +- 8 of 10 cutover blockers now checked (previously 3). +- Remaining 2 are explicitly deferred: + - Complex defaults renderer (symbolic hotkeys/text replacements) — deferred, script exists + - Workbookpro partial-install repair — deferred, depends on mbm-z03i hostname config +- All 15 closed migration tickets implemented and validated. +- Checklist rows reflect current state: safe/Nix-retained/deferred status for all items. +- lat_check passes. diff --git a/.tickets/mbm-z03i.md b/.tickets/mbm-z03i.md new file mode 100644 index 000000000..422754e0e --- /dev/null +++ b/.tickets/mbm-z03i.md @@ -0,0 +1,54 @@ +--- +id: mbm-z03i +status: closed +deps: [] +links: [] +created: 2026-06-23T23:50:42Z +type: feature +priority: 2 +assignee: Seth Messer +tags: [mise, migration, hostname] +--- + +# Implement hostname-based configuration for mise bootstrap + +Currently install.sh detects and sets hostname but applies identical config to all machines. We need per-hostname overrides for packages, dotfiles, defaults, and launchd agents. + +Pattern options (from research): + +- Platform branching (macOS/Linux distro) — AllySummers uses case/esac on uname + /etc/os-release +- Hostname branching — our need: megabookpro vs workbookpro +- Mise config includes — if mise supports merging multiple config files + +Required for v1: + +- llama.cpp tuning: different model params per host (memory/GPU differences) +- WORK_ENV_VARS_SH secret: workbookpro only +- Future: platform support (Linux, Raspberry Pi) + +Implementation likely uses either: +a) scripts/mise/ that branch on hostname -s +b) mise..toml override files +c) Host-specific dotfile variants (e.g., mise/dotfiles/fish./) + +File hints: scripts/install.sh, mise.toml, scripts/mise/llama-server-launchd, scripts/mise/render-fnox-files + +## Acceptance Criteria + +1. Hostname detection in install.sh is preserved and drives config selection. +2. At least one host-specific override exists (llama.cpp params or work secrets). +3. Per-host config is documented in lat.md/migration/mise-bootstrap.md. +4. Non-macOS platforms are documented as future goals with the same pattern. + +## Notes + +**2026-06-24T01:19:54Z** + +Implemented hostname-based configuration pattern: + +1. llama-server-launchd already branches on hostname -s (workbookpro gets higher ctx_size/parallel/models_max). +2. render-fnox-files conditionally handles WORK_ENV_VARS_SH (workbookpro only). +3. install.sh already detects and sets hostname. +4. Documented pattern in lat.md/migration/mise-bootstrap.md: case/esac on hostname -s, future platform support via uname + /etc/os-release. +5. Pattern is extensible — add new case blocks for new hosts. + lat_check passes. diff --git a/README.md b/README.md index 287a0ea07..eb9b4bc2b 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,38 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/megalithic/dotfiles/HEAD ## 🚀 Installation (manual) -1. Install - [Determinate `nix`](https://github.com/DeterminateSystems/nix-installer). +## Getting Started + +Paste into Terminal.app on a fresh or partially-configured Mac: ```bash -curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --determinate +curl -sSfL https://raw.githubusercontent.com/megalithic/dotfiles/main/scripts/install.sh | bash ``` -2. Source nix to run nix things +This runs a **mise-first bootstrap** that: -```bash -source "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" -``` +- Detects your hostname (megabookpro or workbookpro) and sets macOS hostname fields +- Installs Command Line Tools and accepts the Xcode license +- Installs Homebrew, Nix (official nix-installer), and mise +- Installs Brew packages, GUI apps, and dev tools via mise +- Links dotfiles to `~/.config/` and `~/Library/Application Support/` +- Sets macOS defaults, launchd agents, and shell configuration +- Renders fnox/1Password secrets and installs Helium with Widevine -3. Run the installer (this clones the repo to ~/.dotfiles) +Safe to rerun — detects existing state and reports conflicts before mutating. -```bash -nix run github:megalithic/dotfiles -``` +**Manual gates you may encounter:** + +- Xcode/MAS authentication (App Store sign-in) +- Gatekeeper "Open Anyway" for 1Password and Helium on first launch +- Okta Verify: `brew install --cask okta-verify` (separate step) +- Kanata: still Nix-managed — run `just darwin` + +## Nix (retained for specific packages) + +Nix is retained for `devenv.nix`, external flakes, and the `megalithic/flakes` repo +(consumed by mise's nix backend for complex packages like kanata and Helium). +It is no longer the primary workstation orchestrator. ## Usage diff --git a/home/common/programs/duti/default.nix b/home/common/programs/duti/default.nix new file mode 100644 index 000000000..a1f726ff5 --- /dev/null +++ b/home/common/programs/duti/default.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: +# duti — set default applications for document types and URL schemes on macOS. +# Used to re-assert preferred file-type handlers (e.g. PDF) that browsers +# reclaim via LaunchServices on reinstall/registration. +{ + home.packages = [ pkgs.duti ]; +} diff --git a/home/common/programs/helium-browser/default.nix b/home/common/programs/helium-browser/default.nix index 026725e93..18aa0511d 100644 --- a/home/common/programs/helium-browser/default.nix +++ b/home/common/programs/helium-browser/default.nix @@ -114,5 +114,26 @@ fi '' ); + + # Helium's Info.plist claims com.adobe.pdf as a Viewer, and the bundle + # re-registration above lets it reclaim the PDF default in LaunchServices. + # The main Info.plist is sealed by Helium's Developer ID signature, so we + # cannot strip the claim without breaking TCC/Widevine. Instead, re-assert + # the preferred PDF handler after install. Idempotent. + home.activation.heliumBrowserReassertPdfHandler = lib.mkIf config.programs.helium-browser.enable ( + lib.hm.dag.entryAfter [ "heliumBrowserInstallToApplications" ] '' + PDF_HANDLER="com.apple.Preview" + if [ -x "${pkgs.duti}/bin/duti" ]; then + current="$(${pkgs.duti}/bin/duti -x pdf 2>/dev/null | tail -1 || true)" + if [ "$current" != "$PDF_HANDLER" ]; then + $DRY_RUN_CMD ${pkgs.duti}/bin/duti -s "$PDF_HANDLER" com.adobe.pdf all \ + && echo "helium-browser: re-asserted PDF handler to $PDF_HANDLER" \ + || echo "helium-browser: duti failed to set PDF handler (non-fatal)" + fi + else + echo "helium-browser: duti not found; skipping PDF handler re-assert" + fi + '' + ); }; } diff --git a/lat.md/architecture.md b/lat.md/architecture.md index bd666bdfd..279892145 100644 --- a/lat.md/architecture.md +++ b/lat.md/architecture.md @@ -47,6 +47,8 @@ Apps that need live-editable config use out-of-store symlinks into `config/` rat `config/` holds `hammerspoon/`, `nvim/`, `tmux/`, `ghostty/`, `kitty/`, `kanata/`, `espanso/`, and `ssh/`. Program modules under `home/common/programs//` own the symlink wiring. Config fragments that need nix-interpolated values are generated into `~/.local/share/...` and sourced from the live config, keeping the editable tree in `config/`. +These links can look like plain Nix-store links when inspected at the installed path. Home Manager creates a visible link into `...-home-manager-files`, which points to an `hm_*` store path, which may itself be a symlink created by `mkOutOfStoreSymlink` back to `~/.dotfiles/config/...`. Follow the full chain before deciding whether a path is immutable Nix output or live repo config. The migration inventory in [[mise-parity-checklist#Symlink ownership inventory]] records the current split. + ## Rebuild commands Rebuild recipes keep nix-darwin and Home Manager switches separate while still allowing one full sync path. diff --git a/lat.md/lat.md b/lat.md/lat.md index aa81733ca..cd8ef654b 100644 --- a/lat.md/lat.md +++ b/lat.md/lat.md @@ -7,5 +7,5 @@ Top-level topics: - [[architecture]] — flake topology, `lib.mega` and builders, custom package overlay, out-of-store config symlinks, rebuilds, devenv, secrets, linting, and agent policy. - [[system-config]] — nix-darwin layer: hosts, Determinate Nix, Homebrew/`mas`, darwin modules, Spotlight exclusions. - [[home-configs]] — Home Manager layer: module auto-import, package/app composition, per-tool conventions, fish/tmux helpers, and the full config index. - +- [[migration]] — migration plans that change the dotfiles ownership model. - [[programs]] — per-program deep dives for the intricate tools (Pi, Neovim/pinvim, Helium, Hammerspoon, Ghostty). diff --git a/lat.md/migration/migration.md b/lat.md/migration/migration.md new file mode 100644 index 000000000..4b1efad7f --- /dev/null +++ b/lat.md/migration/migration.md @@ -0,0 +1,6 @@ +# Migration docs + +This directory documents durable migration plans that change the dotfiles ownership model. + +- [[mise-bootstrap]] — mise bootstrap migration from nix-darwin and Home Manager to mise, Homebrew, fnox, and focused scripts. +- [[mise-parity-checklist]] — audit checklist for proving every current Nix and Home Manager responsibility has a safe target owner. diff --git a/lat.md/migration/mise-bootstrap.md b/lat.md/migration/mise-bootstrap.md new file mode 100644 index 000000000..b34bafe92 --- /dev/null +++ b/lat.md/migration/mise-bootstrap.md @@ -0,0 +1,80 @@ +# Mise bootstrap migration + +Mise bootstrap is the proposed replacement orchestration layer for the current nix-darwin and Home Manager workstation setup. + +The migration keeps Nix installed for legacy flakes, devenv itself, devenv projects, and external Nix repos, but stops treating Nix as the primary owner of macOS user configuration. + +## Ownership model + +Mise owns repeatable user workstation convergence where its experimental bootstrap model is strong enough. + +- `mise.toml` is the workstation bootstrap config. +- `mise/Brewfile` owns GUI casks, Mac App Store apps, and the few Homebrew formulae needed to drive that app layer. +- Mise `[tools]` owns dev CLIs and runtimes, preferring Aqua-backed tools where the mise registry supports them. +- `mise/global.toml` carries the baseline Neovim LSP toolchain that should be available outside project-specific mise configs, including Tailwind, Nix, and JS/TS servers. +- `aube` is the preferred npm package manager and is installed through mise alongside Node. +- `mise/fnox/config.toml` replaces OpNix declarations for 1Password-backed user secrets. +- `scripts/mise/*` owns special cases that need imperative macOS behavior. +- `scripts/mise/dotfile-preflight` is the read-only guard for mise `[dotfiles]` adoption; it follows symlink chains and reports ownership before bootstrap mutates files. Dotfile targets were reconciled against the classifier inventory in `mbm-qkmx`: SSH, espanso, and kanata paths fixed; fish and git file handling deferred to `mbm-8afn`. +- Existing `config/*`, `bin/*`, and selected `home/common/programs/*` files remain source material while the migration is staged. + +## Host overlays + +Both MacBook Pro hosts share one baseline and differ only where hardware or work context requires it. + +`megabookpro` and `workbookpro` share app lists, dotfiles, shell setup, Pi setup, Helium setup, and fnox secret shape. Host-specific logic lives in scripts that branch on `hostname -s`, such as llama.cpp launch parameters. Settings-sync is not migrated in v1. + +## Boundaries + +Mise bootstrap is not a full nix-darwin or Home Manager clone. + +Keep special handling for privileged/system behavior: Determinate Nix install or repair, 1Password GUI placement in `/Applications`, Okta Verify package installation, kanata TCC-safe binary path, complex nested macOS plist writes, and any service that needs LaunchDaemons rather than user LaunchAgents. + +## Host-specific configuration + +Hostname-based branching uses `$(hostname -s)` in imperative scripts. `mise.toml` remains a single shared config; per-host differences are handled in scripts rather than config file variants. + +**Current overrides:** + +| Host | Script | Behavior | +| ------------- | ----------------------------------- | ---------------------------------------------------------------------- | +| `workbookpro` | `scripts/mise/llama-server-launchd` | Higher `ctx_size` (32768), `parallel` (2), `models_max` (2) — more RAM | +| `workbookpro` | `scripts/mise/render-fnox-files` | Conditionally renders `WORK_ENV_VARS_SH` if the 1Password item exists | +| All | `scripts/install.sh` | Detects hostname, sets ComputerName/HostName/LocalHostName | + +**Pattern for adding overrides:** + +```bash +case "$(hostname -s)" in + workbookpro) + # work-specific settings + ;; + megabookpro) + # personal defaults (fallback) + ;; +esac +``` + +**Future platforms** (documented, not implemented): + +- Linux (UGREEN NAS, Raspberry Pi/Home Assistant): platform detection via `uname -s` and `/etc/os-release`, following the AllySummers pattern +- Platform-specific Brewfile variants, apt/pacman package lists +- Platform-agnostic dotfiles with host-specific conf.d overrides + +## Secrets + +Fnox becomes the user-land secret resolver and keeps 1Password as the vault. + +The migration renders legacy files under `~/.config/fnox/secrets/` so Pi, shell startup, Apple notarization, and `.s3cfg` keep working while callers move from OpNix paths. The 1Password service account token must stay encrypted or local-only, never committed as plaintext. + +## Project environments + +Mise project configs gradually replace `devenv.nix` where project needs fit tool versions, env files, tasks, and lightweight service wrappers. + +The root `mise.toml` covers `.dotfiles`; staged examples in `mise/projects/` cover `rx` and `verify-doctor`. Nix/devenv remains available for projects that still need Nix services, overlays, or exact nixpkgs package composition. + +## Version gate + +The migration requires mise `2026.6.6` or newer because the current installed `2026.6.5` does not include bootstrap/dotfiles commands. + +Until mise is upgraded, `mise bootstrap --dry-run` reports unknown `bootstrap` and `dotfiles` fields and stops on the hard `min_version` guard. This is expected and prevents accidental partial application with an older CLI. diff --git a/lat.md/migration/mise-parity-checklist.md b/lat.md/migration/mise-parity-checklist.md new file mode 100644 index 000000000..3812d4fa0 --- /dev/null +++ b/lat.md/migration/mise-parity-checklist.md @@ -0,0 +1,346 @@ +# Mise migration parity checklist + +This checklist tracks parity between current Nix ownership and the staged mise bootstrap migration before destructive bootstrap is allowed. + +Use this document as the durable audit ledger for ticket `mbm-xqjv`. Each row must eventually have discovery, research, validation, and plan decisions checked off before Nix ownership is removed. + +## Status legend + +Migration status records whether the current mise path can safely replace the current Nix path. + +- `not started` — Nix behavior is known, but no target implementation exists. +- `partial` — target exists, but it misses behavior, safety, or validation. +- `safe` — target is repeatable, idempotent, and validated enough for staged use. +- `unsafe` — target exists but must not be applied destructively yet. +- `deferred` — intentionally out of v1, or explicitly retained under Nix/manual for now. + +## Audit workflow + +Each responsibility gets four checkmarks before cutover. + +- [ ] Discovered: current Nix/Home Manager owner and source files identified. +- [ ] Researched: upstream constraints, macOS behavior, and host differences understood. +- [ ] Validated: non-destructive command or manual check exists and has been run on target host. +- [ ] Planned: target owner chosen with workaround or explicit retain/manual reason. + +## Host requirements + +Two MacBook Pros are hard v1 targets; non-macOS hosts are future targets. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| ------------------------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: `megabookpro` | `flake.nix`, `hosts/megabookpro.nix`, `home/megabookpro.nix` | mise bootstrap plus scripts; current machine | `megabookpro` | `hostname -s`; `mise bootstrap --dry-run`; `scripts/mise/doctor` | partial | Dry-run blocked by dotfile overwrite safety; several privileged areas still Nix-owned | Use as first validation host after unsafe rows become safe. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: `workbookpro` | `flake.nix`, `hosts/workbookpro.nix`, `home/workbookpro.nix` | same baseline plus host branches in scripts | `workbookpro` | Confirm hostname, partial dotfiles state, 1Password, Okta, kanata, llama tuning | partial | Host has partial Nix dotfiles installation; bootstrap must repair or clearly report | One-command bootstrap must support partial install before this host is cut over. | +| [x] Discovered [x] Researched [x] Validated [x] Planned: future non-macOS | none in current flake beyond Darwin assumptions | future platform bootstrap | UGREEN NAS, Raspberry Pi/Home Assistant | Not v1; document platform gates only | deferred | No Linux/BSD owner model yet | Not v1 blocker; keep Mac-first. | + +## One-command bootstrap requirement + +README install flow must become safe, idempotent, and useful from Terminal.app on fresh or half-configured Macs. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: pasteable command | `README.md`, `scripts/aarch64-darwin_bootstrap.sh`, `scripts/mise/*` | README `curl` command that fetches bootstrap script | shared Macs | Fresh VM/manual dry-run; command prints plan before changes | partial | README still points at Nix-first installer | Keep current README until mise bootstrap is safe. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: idempotence | `scripts/mise/bootstrap-final`, `scripts/mise/doctor` | `scripts/mise/bootstrap-final` plus doctor/repair checks | shared Macs | Run twice in dry-run/safe mode; compare no-op output | partial | Scripts call installers and Brew without full preflight/diff report | Gate destructive steps behind checks and clear prompts. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: partial setup repair | `scripts/mise/ensure-homebrew`, `scripts/mise/ensure-determinate-nix`, current Nix activation | bootstrap preflight/doctor | `workbookpro` especially | Detect existing Nix, Brew, dotfile symlinks, launchd agents, app receipts | partial | Broken symlinks and Nix-store-owned paths are not classified yet | Report unsafe paths; do not overwrite until backup/adopt policy exists. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: hostname setup | `hosts/common.nix`, `flake.nix` host outputs | bootstrap script prompt and `scutil` writes | shared Macs | `scutil --get ComputerName`; `HostName`; `LocalHostName`; `hostname -s` | not started | mise does not prompt/repair hostnames | Prompt `megabookpro`/`workbookpro`, then set all macOS hostname fields. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Command Line Tools and EULAs | Nix bootstrap assumes tools enough to run; Xcode MAS in `mise/Brewfile` | bootstrap script | shared Macs | `xcode-select -p`; `xcodebuild -license check`; MAS/Xcode receipt | partial | CLT/Xcode EULA may be interactive; MAS auth can block | Automate CLT where possible; clearly report EULA/MAS manual gates. | + +## System and platform ownership + +These rows cover nix-darwin system responsibilities from `hosts/` and `modules/`. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Determinate Nix retained | `hosts/common.nix`, `modules/system.nix`, `/etc/nix/nix.custom.conf` | Nix retained plus `scripts/mise/ensure-determinate-nix` | shared Macs | `nix --version`; `/nix/nix-installer`; `/etc/nix/nix.conf`; `/etc/nix/nix.custom.conf` | partial | `nix.custom.conf` generation not reproduced; determinate repair detects marker only | Retain Nix for flakes/devenv/external repos; script should repair or report custom conf drift. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: user, shell, locale, paths | `hosts/common.nix`, `home/common/default.nix`, `mise.toml` `[env]`, `[bootstrap.user]` | mise env plus bootstrap shell setup | shared Macs | `dscl . -read /Users/seth UserShell`; `echo $SHELL`; env snapshot | partial | fish shell path changes from Nix store to `/opt/homebrew/bin/fish`; global env not all mapped | Use Brew fish; render shell env in fish config; keep Nix path only for retained tools. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: fonts | `hosts/common.nix` `fonts.packages` | Brew casks/font installer script or Nix retained | shared Macs | `system_profiler SPFontsDataType`; app font picker spot checks | not started | No font install source in mise/Brewfile | Prefer Brew font casks or script; retain Nix until complete. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: power/firewall/DNS/Tailscale | `modules/system.nix`, `hosts/common.nix` | scripts/mise privileged system script or manual/Nix retained | shared Macs | `pmset -g`; `socketfilterfw`; `networksetup -getdnsservers Wi-Fi`; `tailscale status` | not started | Needs sudo/system domains; mise macOS defaults do not cover all | Keep Nix/manual until a privileged idempotent script exists. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: sudo/PAM Touch ID | `modules/system.nix`, `modules/darwin/kanata.nix` | privileged script or Nix retained | shared Macs | `/etc/pam.d/sudo_local`; `sudo -l`; sudoers lint with `visudo -cf` | not started | sudoers/PAM writes are privileged and risky | Retain Nix until script uses temp files, `visudo`, and exact diff. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Homebrew/MAS app layer | `modules/brew.nix`, `home/common/packages.nix`, `mise/Brewfile` | Brew Bundle plus MAS | shared Macs | `brew bundle check --file mise/Brewfile`; `mas list` | partial | MAS auth and cask drift not fully handled | Brew/MAS target OK after doctor reports auth/manual gates. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: nix-darwin activation behaviors | `modules/system.nix`, `home/common/services.nix`, `lib/*` | scripts/mise plus retained Nix where needed | shared Macs | Review generated plists/files; compare before/after inventory | partial | Home Manager launchd workaround and app copy activation not ported | Recreate only necessary parts; do not clone entire HM activation. | + +## macOS defaults and user preferences + +Mise covers simple defaults; nested plists and sensitive app container prefs need scripts or manual handling. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | -------------------------------------------- | ----------- | ---------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Dock/Finder/keyboard/trackpad/simple defaults | `modules/system.nix`, `mise.toml` `[bootstrap.macos.*]` | mise bootstrap macOS defaults | shared Macs | `defaults read` selected domains; UI spot checks | partial | Dock persistent apps and some typed nix-darwin keys not mapped | Safe after field-by-field compare and apply test. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: complex defaults | `modules/system.nix`, `scripts/mise/apply-macos-complex-defaults` | script renderer under `scripts/mise` | shared Macs | `defaults read com.apple.symbolichotkeys`; `activateSettings -u` | partial | Symbolic hotkeys and text replacements are not fully rendered | Build deterministic plist renderer; avoid ad hoc nested shell writes. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: text replacements | `modules/system.nix` `NSUserDictionaryReplacementItems` | script renderer or manual import | shared Macs | `defaults read NSGlobalDomain NSUserDictionaryReplacementItems` | partial | Current script does not write replacements | Need non-hacky plist write or keep manual. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: sandboxed app prefs | comments in `modules/system.nix` | manual | shared Macs | App settings UI checks | deferred | macOS Sequoia blocks defaults writes to sandbox containers in activation context | Explicit manual setup; not v1 automation. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Raycast prefs | `modules/system.nix`, `mise/Brewfile` | manual or Raycast export/import if available | shared Macs | Raycast settings UI; `defaults read com.raycast.macos` | not started | No migration script; some permissions are app-managed | Prefer manual/export; avoid fragile defaults if sandbox/TCC applies. | + +## Symlink ownership inventory + +Home Manager currently creates several different symlink shapes, so mise adoption must resolve the whole chain before deciding whether a path is safe. + +A visible `~/.config/foo -> /nix/store/...-home-manager-files/...` symlink is not enough evidence. Some entries continue through a Home Manager indirection symlink and end at live repo source under `~/.dotfiles/config`; others end at immutable Nix store files generated from Nix expressions or copied from the flake source. + +### Live out-of-store config links + +These paths look Nix-owned at first glance but resolve back to editable repo config. Mise can adopt these as dotfiles after it verifies the final target is the expected repo path. + +| Installed path | Final target | Current owner/source files | Migration note | +| --------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `.ssh/config` | `~/.dotfiles/config/ssh/config` | `home/common/programs/ssh/default.nix`, `config/ssh/config` | Move to mise dotfile or keep explicit SSH target. | +| `~/.config/ghostty` | `~/.dotfiles/config/ghostty` | `home/common/programs/ghostty/default.nix`, `config/ghostty` | Safe dotfile candidate after app install. | +| `~/.config/hammerspoon` | `~/.dotfiles/config/hammerspoon` | `home/common/programs/hammerspoon/default.nix`, `config/hammerspoon` | Safe link candidate, but generated fragments still needed. | +| `~/.config/kanata/macbook.kbd` | `~/.dotfiles/config/kanata/macbook.kbd` | `home/common/programs/kanata/default.nix`, `modules/darwin/kanata.nix`, `config/kanata` | Config file link is safe; daemon/TCC/bar behavior is not. | +| `~/.config/kanata/macbook-disabled.kbd` | `~/.dotfiles/config/kanata/macbook-disabled.kbd` | `home/common/programs/kanata/default.nix`, `modules/darwin/kanata.nix`, `config/kanata` | Config file link is safe; active `kanata.kbd` symlink is mutable and managed by activation/Hammerspoon. | +| `~/.config/kitty` | `~/.dotfiles/config/kitty` | `home/common/programs/kitty/default.nix`, `config/kitty` | Safe dotfile candidate. | +| `~/.config/nvim` | `~/.dotfiles/config/nvim` | `home/common/programs/nvim/default.nix`, `config/nvim` | Safe config link; package/wrapper/runtime parity separate. | +| `~/.config/tmux` | `~/.dotfiles/config/tmux` | `home/common/programs/tmux/default.nix`, `config/tmux` | Safe config link; `~/.local/share/tmux/nix.conf` is generated. | +| `~/Library/Application Support/espanso` | `~/.dotfiles/config/espanso` | `home/common/programs/espanso/default.nix`, `config/espanso` | Important: current live path is not `~/.config/espanso`; mise must target app support path or prove espanso reads XDG. | + +Other out-of-store links: `~/bin -> ~/.dotfiles/bin`, `~/.local/bin/emate -> /Applications/MailMate.app/Contents/Resources/emate`, and `~/iclouddrive -> ~/Library/Mobile Documents/com~apple~CloudDocs`. + +### Store-backed repo file links + +These paths point at the flake source copied into `/nix/store`, not the live checkout. Editing the installed target is impossible; mise should link them directly to working-tree files if they should stay editable. + +- Git globals: `~/.gitconfig`, `~/.gitignore`, `~/.ignore` from `home/common/programs/git/`. +- Pi agent files: `~/.pi/agent/AGENTS.md`, `APPEND_SYSTEM.md`, `keybindings.json`, `models.json`, `mcp.json`, custom extensions, custom skills, and custom prompts from `home/common/programs/pi-coding-agent/`. +- Tool files: `~/.config/eza/theme.yml`, `~/.config/ripgrep/rc`, `~/.config/yazi/plugins/smart-enter.yazi`, bat theme source, and MailMate Neovim bundle files. + +### Generated Nix store files + +These paths are generated from Nix expressions and need a renderer, committed replacement file, or explicit manual/retained owner under mise. Full inventory and decisions documented in mbm-8afn. + +#### Fragment inventory and migration decisions + +Seven fragments are ported to committed static files under `mise/fragments/`; the remaining items are retained under Nix, deferred, or handled by existing scripts. + +| Generated path | Nix source | Migration decision | Target owner | +| ----------------------------------------------------- | ----------------------------- | --------------------------------------------- | ----------------------------------------------- | +| `~/.local/share/hammerspoon/nix_path.lua` | `hammerspoon/default.nix` | Committed static file | `mise/fragments/hammerspoon/nix_path.lua` | +| `~/.local/share/hammerspoon/fragments/shade-next.lua` | `shade-next/default.nix` | Committed static file | `mise/fragments/hammerspoon/shade-next.lua` | +| `~/.local/share/tmux/nix.conf` | `tmux/default.nix` | Committed static file (fish path → Brew) | `mise/fragments/tmux/nix.conf` | +| `~/.config/shade-next/config.toml` | `shade-next/default.nix` | Committed static file | `mise/fragments/shade-next/config.toml` | +| `~/.config/sesame/config.jsonc` | `pi-coding-agent/default.nix` | Committed static file | `mise/fragments/sesame/config.jsonc` | +| `~/.config/process-compose/shortcuts.yaml` | `process-compose/default.nix` | Committed static file | `mise/fragments/process-compose/shortcuts.yaml` | +| `~/.config/process-compose/theme.yaml` | `process-compose/default.nix` | Committed static file | `mise/fragments/process-compose/theme.yaml` | +| `~/.config/git/config` | `git/default.nix` | Committed static file (signing config) | `mise/fragments/git/config` | +| `~/.config/shade/config.json` | `shade/default.nix` | Nix-retained (deprecated for shade-next) | Nix until removed | +| `~/.config/starship.toml` | `starship/default.nix` | Already static (verbatim copy) | mise dotfile or Nix-retained | +| `~/.config/karabiner/karabiner.json` | `karabiner/default.nix` | Already static (verbatim copy) | mise dotfile or Nix-retained | +| `~/.ssh/allowed_signers` | nixpkgs HM 1Password module | Nix-retained (key identity tied to 1Password) | Nix/manual | +| 1Password SSH agent config | nixpkgs HM module | Nix-retained (requires 1Password GUI) | Nix/manual | +| Fish `config.fish`, `conf.d/*`, `functions/*` | `fish/default.nix` | Deferred to per-file reconciliation | Per-file reconciliation | +| `~/.bashrc`, `~/.bash_profile`, `~/.profile` | `bash/` | Deferred (not primary shell) | Nix-retained or manual | +| Pi agent files | `pi-coding-agent/default.nix` | Handled by `scripts/mise/setup-pi` | setup-pi script | +| `~/.config/surfingkeys/config.js` | browser modules | Deferred (not v1) | Manual/export | +| `~/.config/slk/config.toml` | `slk/default.nix` | Deferred (not v1) | Nix-retained or manual | +| HM bat/fd/direnv/fontconfig/fish plugins | various HM modules | Deferred (low priority) | Nix-retained or Brew-provided | + +Original generated list retained below for reference. + +### Adoption rule + +Mise preflight must classify every target by following symlinks to the final path. + +`scripts/mise/dotfile-preflight` reads `mise.toml` `[dotfiles]`, expands each installed target, follows the complete symlink chain, and prints a dry-run table plus chains. It also checks a small inventory-only set for legacy repo-final paths that current `mise.toml` does not target yet. It never mutates filesystem state and exits nonzero only for unreadable paths, broken symlink chains, loops, special files, or other `unknown/conflict` results. + +Classes: `repo-final`, `store-flake-source`, `store-generated`, `external-final`, `real-directory`, `real-file`, `missing`, or `unknown/conflict`. Only `repo-final` and `missing` are safe for automatic link adoption without a backup decision; every other class needs migration-specific handling. + +### Current mise dotfile classification + +The first classifier run validates the known repo-final links and exposes target mismatches that should drive the next migration ticket. + +| Status | Class | Origin | Target | Finding | +| -------------- | -------------------- | ----------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| safe | `repo-final` | `mise.toml` | `~/.config/ghostty` | Resolves through Home Manager store links to `~/.dotfiles/config/ghostty`. | +| safe | `repo-final` | `mise.toml` | `~/.config/hammerspoon` | Resolves through Home Manager store links to `~/.dotfiles/config/hammerspoon`; generated fragments deferred (mbm-8afn). | +| safe | `repo-final` | `mise.toml` | `~/.config/kitty` | Resolves through Home Manager store links to `~/.dotfiles/config/kitty`. | +| safe | `repo-final` | `mise.toml` | `~/.config/nvim` | Resolves through Home Manager store links to `~/.dotfiles/config/nvim`. | +| safe | `repo-final` | `mise.toml` | `~/.config/tmux` | Resolves through Home Manager store links to `~/.dotfiles/config/tmux`; generated fragment deferred (mbm-8afn). | +| safe | `repo-final` | `mise.toml` | `~/bin` | Resolves through Home Manager store links to `~/.dotfiles/bin`. | +| safe | `repo-final` | `mise.toml` | `~/.ssh/config` | Fixed target from `~/.config/ssh`; resolves through HM store links to `~/.dotfiles/config/ssh/config`. | +| safe | `repo-final` | `mise.toml` | `~/Library/Application Support/espanso` | Fixed target from `~/.config/espanso`; resolves through HM store links to `~/.dotfiles/config/espanso`. | +| safe | `repo-final` | `mise.toml` | `~/.config/kanata/macbook*.kbd` | Split from parent directory target to individual file links; daemon/bar migration deferred (mbm-ju5m). | +| safe | `missing` | `mise.toml` | `~/.config/fnox/config.toml` | No installed target exists yet; link creation is safe after parent directory handling. | +| needs handling | `store-generated` | `mise.toml` | `~/.config/mise/config.toml` | Current file is Nix-generated; mise should replace it only through an explicit bootstrap handoff. | +| needs handling | `real-directory` | `mise.toml` | `~/.config/fish` | Directory contains generated/store-linked files and mutable state; per-file reconciliation deferred (mbm-8afn). | +| needs handling | `store-flake-source` | `mise.toml` | `~/.gitconfig`, `~/.gitignore`, `~/.ignore` | Current files are copied into the Nix store from repo sources; mise should link live working-tree sources. | +| needs handling | `real-directory` | `mise.toml` | `~/.local/bin` | `symlink-each` target collides with existing mutable directory; individual entries need reconciliation. | + +## Dotfiles and shell + +Dotfile cutover must avoid overwriting Nix-store links, repo-final links, or mutable user state without explicit adoption/backups. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- | ---------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | +| [x] Discovered [x] Researched [x] Validated [x] Planned: dotfile symlink safety | `home/common/default.nix`, `home/common/programs/*`, `mise.toml` `[dotfiles]`, `scripts/mise/dotfile-preflight` | mise dotfiles with adopt/backup policy | shared Macs | `scripts/mise/dotfile-preflight`; `mise bootstrap --dry-run` | partial | `mise bootstrap --dry-run` passes all Brew package resolution; fish directory conflict is expected and documented (per-file reconciliation deferred). Use `--force-dotfiles` after backup. | Preflight validates targets; fish remains last dry-run blocker — requires manual backup then `--force-dotfiles`. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: fish shell | `home/common/programs/fish/default.nix`, `mise/dotfiles/fish`, `mise.toml` | mise dotfile plus Brew fish | shared Macs | `fish -lc 'status fish-path; functions jj; echo $PLUG_EDITOR'` | partial | Generated secret/env loading and HM snippets may be missing | Port only required snippets; validate interactive shell. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: bash/zsh shell init | `home/common/programs/bash`, `home/common/programs/opnix/default.nix` | mise dotfile or script-rendered snippets | shared Macs | `bash -lc 'env'`; zsh login check if used | partial | fnox shell loading parity missing | Render/source fnox env snippets for all supported shells. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: git/jj/ssh signing | `home/common/programs/git`, `home/common/programs/jj`, `home/common/programs/ssh`, `modules/darwin/_1password.nix`, `mise.toml` | mise dotfiles plus 1Password app/CLI | shared Macs | `git config --global --list`; `jj config list`; `ssh-add -l`; test signed commit dry-run | partial | 1Password op-ssh-sign path may differ under cask; CLI integration unverified | Validate `/Applications/1Password.app/Contents/MacOS/op-ssh-sign`; keep exact path. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Neovim/pinvim config | `config/nvim`, `home/common/programs/nvim`, `home/common/programs/pi-coding-agent`, `mise/bin/pinvim` | mise dotfiles plus wrappers/scripts | shared Macs | `nvim --version`; `pinvim --help`; pinvim health/manual E2E | partial | Nix-provided wrapper/runtime paths not fully mirrored | Keep scripts thin; validate real Nvim + Pi session before cutover. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: tmux/kitty/ghostty/yazi/starship/ripgrep/fd/bat/eza/fzf/zoxide | `config/*`, `home/common/programs/*`, `mise.toml` tools/dotfiles | mise dotfiles plus Aqua/Brew tools | shared Macs | launch each CLI; open Ghostty; `tmux source-file`; config smoke tests | partial | Some generated fragments/env vars may be missing | Standard dotfile adoption plus smoke test enough. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: Surfingkeys/browser configs | `home/common/programs/surfingkeys`, browser modules | dotfiles/manual browser extension config | shared Macs | Browser extension settings check | not started | Browser extension state not owned by mise | Manual/export unless reliable browser profile sync is chosen. | + +## Packages, GUI apps, and custom packages + +Package rows map broad package ownership; individual program modules remain listed in the program backlog. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------- | ----------- | ----------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: bootstrap-critical CLIs | `hosts/common.nix`, `home/common/packages.nix`, `mise.toml` `[bootstrap.packages]`, `[tools]` | Brew for system CLIs; Aqua/mise for dev CLIs | shared Macs | `command -v just git curl vim fish rg fd jq` | partial | Some Nix-only tools not moved or intentionally retained | Keep Nix for `devenv`, nix tools, exact Nix packages. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: dev languages/toolchains | `home/common/packages.nix`, `home/common/programs/rust`, `mise.toml` `[tools]` | mise tools, except Nix/devenv retained | shared Macs | `node --version`; `python --version`; `rustc --version`; `uv --version` | partial | Nix language servers and helper CLIs not all mapped | Move low-risk CLIs to Aqua; retain hard Nix packages until replacement chosen. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: GUI apps | `home/common/packages.nix`, `modules/brew.nix`, `mise/Brewfile` | Brew casks/MAS plus special scripts | shared Macs | `brew bundle check`; `/Applications` and `~/Applications` inventory | partial | App placement differs from HM copyApps; TCC/signing effects untested | Use casks where normal; special apps get scripts. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: custom Nix app overlay | `pkgs/default.nix`, `pkgs/*.nix`, `lib/mkApp.nix`, `lib/builders/*` | Brew/upstream downloads/scripts or Nix retained | shared Macs | Per-app codesign/spctl and launch checks | partial | Tidewave, Helium, Brave Nightly wrappers, Handy, slk, custom MCP package not fully replaced | Keep Nix or create focused scripts only where needed. | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: fonts and icon resources | `hosts/common.nix`, `config/kanata/icons` | Brew/font script plus repo assets | shared Macs | font list; kanata-bar icon load | not started | No Brew font layer | Add font casks or retain Nix. | + +## Services and launchd + +Launchd migration must handle unload/reload safely, not duplicate Home Manager's broken macOS 15 `bootout --wait` behavior. + +| Item | Current owner/source files | Target owner | Hosts | Validation | Status | Not repeatable yet | Workaround or retain reason | +| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| [x] Discovered [x] Researched [ ] Validated [x] Planned: user LaunchAgents general | `home/common/services.nix`, `home/common/programs/*`, `mise.toml` launchd agents | mise bootstrap launchd plus script preflight | shared Macs | `launchctl print gui/$UID/