Commit Graph

158 Commits

Author SHA1 Message Date
Emma Thorpe 108f7b9528 feat(rpi5): add nginx reverse-proxy module
Enable nginx with the recommended proxy/TLS/optimisation/gzip settings and a
declarative virtualHosts table -- each proxied service is a Nix entry, so the
routing lives in-repo. Ships one HTTP-only example vhost; enableACME/forceSSL
are present but commented, to be flipped per-vhost once a DNS name and cert
exist. Opens 80 and 443.
2026-06-16 13:25:57 +01:00
Emma Thorpe 1cb8371775 feat(rpi5): add Docker host with LAN-restricted network socket
Enable Docker and expose the daemon over TCP 2375 by extending the systemd
docker.socket ListenStream (avoids the daemon.json hosts vs unit -H fd://
conflict). The port is not added to allowedTCPPorts; instead an nftables
rule accepts it only from the trusted LAN subnet. Plain 2375 is
root-equivalent, so the source restriction is the only safeguard -- mTLS on
2376 is the documented upgrade path.
2026-06-16 13:25:31 +01:00
Emma Thorpe 2fc39a5f15 feat(rpi5): add placeholder hardware-configuration
Committed so the lyrathorpe-rpi5 host evaluates in CI before the Pi is
provisioned. It is a placeholder, not a bootable config: on first install,
regenerate it on the device with nixos-generate-config and replace this file.
Excluded from formatters/linters by the existing hardware-configuration.nix
rules.
2026-06-16 13:25:02 +01:00
lyrathorpe 5f4fd8d74e Merge pull request 'Feat/extra needed apps' (#29) from feat/extra-needed-apps into main
CI / flake (push) Successful in 3m38s
Reviewed-on: #29
2026-06-16 11:56:13 +01:00
lyrathorpe d8c4f6bb0b Merge pull request 'fix(renovaterc.json): ensure lockfile updates auto merge' (#30) from fix/renovate-automerge into main
CI / flake (push) Successful in 3m36s
Reviewed-on: #30
2026-06-16 11:55:35 +01:00
Emma Thorpe 8c3b101a14 ci: always run the workflow on PRs, guard the heavy steps
CI / flake (pull_request) Successful in 3m24s
This job is a required status check on main. The workflow was path-filtered
to **.nix/flake.lock/ci.yaml, so a PR touching none of those (e.g. a
.renovaterc.json-only change) skipped the workflow entirely, leaving the
required check pending forever and making the PR unmergeable.

Run the workflow on every PR so the check is always reported, but keep a
'detect' step that diffs the PR against its base and runs nix flake check
and the per-host evals only when a .nix file, flake.lock, or this workflow
changed. When nothing Nix-relevant changed the heavy steps skip and the job
still passes, so the required check stays green-reportable without burning a
full evaluation on unrelated changes. Checkout uses fetch-depth: 0 so the
diff has the base history.
2026-06-16 11:51:18 +01:00
Emma Thorpe 2b69485107 feat(edaas): set hostName to emmathorpe-edaas
CI / flake (pull_request) Successful in 3m44s
The host inherited the stock NixOS default hostname 'nixos', which does not
match the flake's nixosConfigurations attribute 'emmathorpe-edaas'. nh
selects the configuration by the local hostname, so bare 'nh os switch'
failed to resolve. Pin the hostname to the attribute name so it resolves
without an explicit -H/--hostname flag.
2026-06-16 11:30:22 +01:00
Emma Thorpe 886ac4eb36 fix(git.nix): make personal signingkey a mkDefault
git.nix and work.nix both define user.signingkey. They used to hold the
same value, which types.str tolerates, but git.nix now sets the personal
key while work.nix sets the work key, so the two plain definitions
conflict on the EDaaS host.

Mark git.nix's signingkey as mkDefault, mirroring user.email: personal
hosts get the personal key, and work.nix's plain work-key definition wins
on the work host.
2026-06-16 11:27:17 +01:00
Emma Thorpe ffedf769a0 fix(shell.nix): let gh own its config.yml so auth login works
home-manager renders ~/.config/gh/config.yml as a read-only /nix/store
symlink whenever programs.gh is enabled (unconditionally, not gated on
settings). gh rewrites that file on 'gh auth login' and 'gh config set',
which then fail with a permission error.

Suppress the managed config.yml via xdg.configFile and drop the
settings.git_protocol declaration that created it; gh now owns the file.
The token lives in hosts.yml, which home-manager never manages. Set the
SSH protocol at runtime with 'gh config set git_protocol ssh'.
2026-06-16 11:21:51 +01:00
Emma Thorpe eec713e886 refactor(git.nix): drop redundant gh and duplicate tea packages
programs.gh.enable (in shell.nix) already installs gh, so the explicit
pkgs.gh was redundant. pkgs.tea was also declared in shell.nix; keep the
single declaration there and remove the duplicate here.
2026-06-16 11:12:48 +01:00
Emma Thorpe e995283363 feat(shell.nix): configure htop settings and meters
Flesh out programs.htop: tree view, sensible highlights, hidden kernel
threads, left CPU/Memory/Swap bar meters and right Tasks/LoadAverage/Uptime
text meters. color_scheme = 0 inherits the terminal's Catppuccin Mocha
palette, as htop has no custom-theme support of its own.

Drop the explicit pkgs.htop: programs.htop.enable already installs it.
2026-06-16 11:12:44 +01:00
Emma Thorpe a753355c0f fix(shell.nix): correct home.activation typo
The zcompdump reset was declared under home.actiVation (stray capital V),
an unknown option that fails module evaluation, so the activation script
never ran. Restore the correct home.activation attribute.
2026-06-16 11:12:38 +01:00
lyrathorpe e125296015 feat(shell.nix): add htop installation 2026-06-16 10:55:57 +01:00
lyrathorpe e0b3eb2393 feat(git.nix): add GitHub and Gitea CLI 2026-06-16 10:50:49 +01:00
lyrathorpe 35c3b08862 fix(renovaterc.json): ensure lockfile updates auto merge 2026-06-16 10:44:46 +01:00
lyrathorpe 6730efa3ce Merge pull request 'Feat/edaas renovate review timer' (#28) from feat/edaas-renovate-review-timer into main
CI / flake (push) Successful in 3m55s
Reviewed-on: #28
2026-06-16 10:40:50 +01:00
lyrathorpe fc459ddb1b Merge pull request 'chore(deps): lock file maintenance flake inputs' (#27) from renovate/lock-file-maintenance-flake-inputs into main
CI / flake (push) Successful in 4m28s
Reviewed-on: #27
2026-06-16 10:37:36 +01:00
Renovate Bot 052b95c00e chore(deps): lock file maintenance flake inputs
CI / flake (pull_request) Successful in 4m25s
2026-06-15 00:02:51 +00:00
Emma Thorpe 783754bda2 feat(edaas): auto-approve low-risk Renovate PRs + daily shell reminder
CI / flake (pull_request) Successful in 4m0s
Extend the daily Renovate review so it triages instead of only advising,
and surface results in the interactive shell.

- Auto-approve: PRs graded low risk (patch/minor bumps to tooling, infra,
  test or framework libs; symmetric diff; CI passing; no app logic) that
  are not already approved get an APPROVE review via
  pull_request_review_write. These repos automerge on approval, so this
  merges them with no human in the loop -- intentional. Medium/high risk,
  failing/pending CI, stale branches and anything needing judgement are
  left untouched for Emma. No merge tool is granted.
- State + reminder: each run records ~/.local/state/renovate-review/
  {last-run,needs-review.txt}. A once-a-day interactive zsh reminder
  (programs.zsh.initContent) warns if the timer hasn't run, lists the PRs
  needing review, or confirms an all-clear.

Verified: nix build (eval + shellcheck) green; triage parsing and the
reminder's run/stale/all-clear/throttle branches exercised against
synthetic state. The first live auto-approval is left for a supervised
scheduled/manual run.
2026-06-11 15:46:12 +01:00
Emma Thorpe dc08522bab feat(edaas): add daily headless Renovate PR review timer
Add a systemd user timer on the EDaaS/WSL host that runs Claude Code
headless once a day (08:47) to review Renovate dependency PRs awaiting
Emma's review. It queries GitHub via the project-scoped github MCP
server, excludes PRs against archived repositories, grades each PR's
risk, and writes a recommendation-only summary to the journal
(journalctl --user -u renovate-review). It never approves or merges.

- lyrathorpe/home/renovate-review.nix: wrapper + service + timer.
  Auth is Vertex AI via the inherited project/region/model env; Claude
  Code provisions its own network egress, so no proxy is set. The
  prompt lives in a store file so its literal backticks/$ don't trip
  shellcheck in the wrapper.
- lyrathorpe/home/work.nix: import the module (host-scoped to EDaaS).
- system/machine/EDaaS/configuration.nix: enable user linger so the
  timer fires without an attached login session.
2026-06-11 11:57:13 +01:00
lyrathorpe a40558d35e Merge pull request 'Chore/darwin config fixes' (#26) from chore/darwin-config-fixes into main
CI / flake (push) Successful in 3m13s
Reviewed-on: #26
2026-06-10 18:08:49 +01:00
Emma Thorpe 18c1e10f13 fix(darwin): pam_reattach for Touch-ID sudo in tmux; trim dock defaults
CI / flake (pull_request) Successful in 3m17s
Touch ID for sudo failed because pam_tid can't reach the GUI session
from inside tmux (terminals here auto-start tmux); enable sudo_local
reattach (pam_reattach) so the session is re-attached first. Also drop
the dock autohide and tilesize defaults.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 18:02:02 +01:00
Emma Thorpe 0c6d6ac167 chore(darwin): drop declarative masApps; install MAS apps manually
nix-darwin 26.05 forces activation to run as root, and mas cannot reach
the App Store/StoreKit session from root, so homebrew.masApps silently
failed to install. Remove the masApps list; install those apps by hand
with `mas install <id>` from a GUI Terminal. The mas CLI stays in
systemPackages for that.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:58:49 +01:00
lyrathorpe ee319d2d3e Merge pull request 'Feat/claude code config' (#25) from feat/claude-code-config into main
CI / flake (push) Successful in 3m14s
Reviewed-on: #25
2026-06-10 17:35:44 +01:00
Emma Thorpe a97b433a7b feat(home): seed Claude Code memory from Nix (repo as source of truth)
CI / flake (pull_request) Successful in 3m15s
Vendor the auto-memory directory into the repo (claude/memory/) and
symlink it read-only into ~/.claude/memory. Recall keeps working; the
runtime "save a memory" path no longer writes there. CLAUDE.md instructs
Claude to add/change memories in this repo and rebuild instead, so the
flake stays the single source of truth. README documents the split.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:26:50 +01:00
Emma Thorpe 184a09ad71 feat(home): manage Claude Code static config via home-manager
programs.claude-code on every host: the global CLAUDE.md (persona) and
the Soviet Engineer output style are now declared. settings.json is left
unmanaged on purpose — Claude rewrites it at runtime (permission grants,
/config) and a read-only store symlink would break those writes. Drops
the now-redundant explicit claude-code package from work.nix (the module
installs it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:22:00 +01:00
lyrathorpe 6ee8852c3b Merge pull request 'Feat/audit improvements' (#24) from feat/audit-improvements into main
CI / flake (push) Successful in 3m38s
Reviewed-on: #24
2026-06-10 17:08:25 +01:00
Emma Thorpe 3e5a0958ab chore(mbp): set hostname to Lyra-Asahi
CI / flake (pull_request) Successful in 3m44s
Was Emma-Asahi; align with the lyrathorpe persona used across the configs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:59:46 +01:00
Emma Thorpe 972b8f4c60 docs: document the audit improvements; fix remaining stale work refs
Update the home README (editor plugins + format-on-save, btop/lazygit/
hyperfine/sd, git aliases, tmux extrakto, fonts/emoji coverage),
KEYBINDINGS (telescope/trouble/comment), and the top README (shared
module layers + nix-flake-check CI). Correct the last work/default.nix
reference in default.nix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:49:33 +01:00
Emma Thorpe 89850b37ce ci: run full nix flake check + add nix-community substituter
Replace the formatting-only build with `nix flake check`, so deadnix,
statix and the pre-commit hooks are enforced in CI (not just local
hooks). Add the nix-community binary cache to the runner's nix config to
speed up the check closure. The explicit per-host eval pass is kept for
granular output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:46:19 +01:00
Emma Thorpe 8c058632ef feat(darwin): declarative macOS defaults + Touch-ID sudo
Touch ID now authorises sudo (via sudo_local, update-safe). Adds the
standard system.defaults blocks — dock autohide / no-recents, Finder
extensions + path bar + list view, dark mode, fast key repeat, trackpad
tap-to-click — so the Mac's UI is managed declaratively too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:44:53 +01:00
Emma Thorpe 318c64a371 feat(home): work k8s/TF CLIs, shell + git polish, themed btop, lazygit
- work.nix: k9s, kubectx/kubens, stern, dyff, tflint, terraform-docs,
  yq-go for the EDaaS Kubernetes/Terraform workflow.
- shell.nix: btop themed Catppuccin Mocha (vendored theme; not bundled),
  hyperfine + sd, and the tmux extrakto plugin (prefix+Tab grab).
- git.nix: amend/fixup/undo aliases, commit-graph maintenance, and
  lazygit (themed). Corrected the stale work/default.nix doc references.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:43:43 +01:00
Emma Thorpe 5dd14a8e68 feat(nvim): format-on-save + telescope/gitsigns/which-key/trouble and QoL
- conform-nvim format-on-save mirroring the repo's treefmt set (nixfmt,
  stylua, ruff, shfmt, prettier, gofumpt; LSP fallback for terraform).
- telescope (+fzf-native) with <leader>ff/fg/fb; trouble (<leader>xx).
- gitsigns, which-key, lualine (catppuccin), comment, autopairs,
  treesitter-textobjects.
- luasnip wired into cmp for snippet completion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:37:46 +01:00
Emma Thorpe ef0fc9a5c5 feat(sway): polkit agent, kanshi, night-light, idle-inhibit, lid policy
- Polkit authentication agent (lxqt-policykit) as a sway-session user
  service — programs.sway only enables the daemon, so GUI auth dialogs
  (nemo mount, NM/blueman) previously failed silently. Corrected the
  header comment that wrongly claimed the agent was handled system-side.
- kanshi for output/display management (safe internal-panel default; a
  documented template for docked/Cinema-Display profiles).
- gammastep night-light (manual location; adjust coordinates).
- inhibit_idle on fullscreen so video doesn't get blanked/locked.
- logind lid policy on the laptops: suspend on battery, lock on AC.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:34:06 +01:00
Emma Thorpe 2836ea1150 feat(nixos): nix-ld + nix-community cache + font coverage (base layer)
In common-nixos.nix (every NixOS host):
- programs.nix-ld for all hosts, not just WSL — foreign dynamic binaries
  (VS Code server, prebuilt toolchains) run on the dev boxes too. Removed
  the now-redundant per-host enable from the EDaaS config.
- nix-community.cachix.org substituter (merges with the Asahi cache).
- Noto sans + colour-emoji fonts and fontconfig defaultFonts mapping, so
  the WSL box (and anything asking fontconfig for "monospace") stops
  rendering tofu.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:26:53 +01:00
Emma Thorpe d172157101 feat(nixos): physical-host services — power, bluetooth, OOM, firmware
- thermald on the x86 hosts (guarded; the Asahi MBP self-governs).
- T400 battery charge thresholds (75/80) via tp_smapi; tlp itself comes
  from the nixos-hardware profile.
- Bluetooth (bluez + powerOnBoot) and blueman on the laptops — the MBP
  already loads Apple BT firmware but bluez was never running.
- earlyoom + fwupd on the physical graphical hosts; zram on the Mac Pro.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:26:44 +01:00
Emma Thorpe 93571386bd feat(nixos): key-only sshd hardening on T400 and Mac Pro
New system/modules/ssh.nix disables password and keyboard-interactive
auth and root login, and installs the authorized key for the primary
user. Imported by the two hosts that run sshd; each still enables the
service and opens port 22 in its own config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:22:12 +01:00
Emma Thorpe bdfc27cf93 feat(nixos): add nixos-hardware profiles for the x86 hosts
T400 gets the generic lenovo-thinkpad + common-pc-laptop(-ssd) +
common-cpu-intel blocks (no t400-specific profile exists); this also
enables tlp and the tp_smapi/acpi_call battery tooling. Mac Pro 3,1 gets
common-pc-ssd + common-cpu-intel. nixos-hardware follows our nixpkgs to
keep a single nixpkgs in the closure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 16:19:33 +01:00
lyrathorpe 9a095abd5c Merge pull request 'fix(zsh): move dotDir to XDG (~/.config/zsh), preserve history' (#23) from fix/zsh-xdg-dotdir into main
CI / flake (push) Successful in 2m54s
Reviewed-on: #23
2026-06-10 15:58:47 +01:00
Emma Thorpe c7f2f5503b fix(zsh): move dotDir to XDG (~/.config/zsh), preserve history
CI / flake (pull_request) Successful in 2m21s
Set programs.zsh.dotDir to ~/.config/zsh, adopting the new home-manager
default and silencing the dotDir deprecation warning on rebuild. Pin
history.path to the existing ~/.zsh_history so the move doesn't orphan it,
and extend the zcompdump-reset activation to the new $ZDOTDIR location
(legacy $HOME and cache paths still swept). README updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:54:39 +01:00
lyrathorpe fa6f747467 Merge pull request 'Feat/neovim' (#22) from feat/neovim into main
CI / flake (push) Successful in 2m50s
Reviewed-on: #22
2026-06-10 15:49:09 +01:00
Emma Thorpe 55bce14bf3 feat(nvim): migrate editor from vim to Neovim (parity + LSP)
CI / flake (pull_request) Successful in 2m51s
Rewrite editor.nix on programs.nixvim, keeping every prior feature: file
tree (nvim-tree, toggle ,,), indent guides (indent-blankline), fugitive,
vim-tmux-navigator, Catppuccin Mocha, 2-space hard tabs, and the
*Jenkinsfile=groovy rule. Replace the inert ALE with a real LSP stack —
nvim-lspconfig, nvim-cmp completion, and tree-sitter for highlighting.
Leader is Space; LSP keymaps gd/gr/K/<leader>rn/<leader>ca.

Universal servers: nil (Nix), lua_ls, pyright (Python), terraformls. The
work box (work.nix) additionally enables omnisharp (C#) and helm_ls (Helm),
so the heavy omnisharp closure stays off the personal machines.

default.nix drops VISUAL=vim so nixvim's defaultEditor owns $EDITOR/$VISUAL.
README and KEYBINDINGS updated (and two stale references corrected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:42:06 +01:00
Emma Thorpe b8f09ed9ea chore(flake): add nixvim input
Declarative Neovim, on the nixos-26.05 release branch and following our
nixpkgs to keep a single nixpkgs in the closure. Consumed by
lyrathorpe/home/editor.nix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:31:29 +01:00
lyrathorpe 88a23937ba Merge pull request 'Feat/repo improvements' (#21) from feat/repo-improvements into main
CI / flake (push) Successful in 2m16s
Reviewed-on: #21
2026-06-10 15:11:18 +01:00
Emma Thorpe 63ca392537 chore(flake): treefmt + deadnix/statix + pre-commit; relocate work module
CI / flake (pull_request) Successful in 2m10s
- treefmt-nix drives `nix fmt` and the formatting check (nixfmt/shfmt/
  prettier; generated files and flake.lock excluded). Replaces the
  bespoke find-based check.
- deadnix and statix as flake checks and pre-commit hooks; deadnix
  ignores module-arg patterns, statix.toml disables the two house-style
  lints (repeated_keys, empty_pattern). Fixed the one real deadnix hit
  (unused overlay arg) and statix hit (use inherit for claude-code).
- git-hooks.nix installs the pre-commit gate via the devShell.
- .editorconfig for the base style.
- Move system/modules/work/default.nix -> lyrathorpe/home/work.nix (it is
  a home-manager module). README gains a Development section; docs
  reformatted by the new formatter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:08:10 +01:00
Emma Thorpe f41879710c feat(nixos): disk hygiene, dedupe shared options, fix MacPro docs
- common-nixos: nix.settings.auto-optimise-store + larger download buffer.
- workstation: fstrim, boot.tmp.cleanOnBoot, and the shared graphical
  options moved here from the per-host configs (pipewire, swaylock PAM
  stub, redistributable firmware) -- MBP-Asahi gains audio it lacked.
- T400: zramSwap for the low-RAM host.
- MBP-Asahi: nixos-apple-silicon binary cache substituter.
- MacPro31 README: describe the real (LVM/UUID) hardware config; it is no
  longer a placeholder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:08:10 +01:00
Emma Thorpe 6a0d3680fd feat(home): theme CLI tools, add staples, env defaults and mime apps
- Catppuccin Mocha for fzf (colors), bat (catppuccin/bat tmTheme) and
  git delta (syntax-theme + navigate/line-numbers/side-by-side).
- CLI staples on every host: ripgrep, fd, jq, btop, plus gh (SSH) and
  tea (Gitea CLI).
- home.sessionVariables: PAGER, MANPAGER (bat), VISUAL; xdg.enable.
- xdg.mimeApps defaults (web->Firefox, directories->nemo).
- Document the stateVersion pin. README updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:08:10 +01:00
lyrathorpe f029c1cf67 Merge pull request 'Feat/shell tmux git tooling' (#20) from feat/shell-tmux-git-tooling into main
CI / flake (push) Successful in 2m19s
Reviewed-on: #20
2026-06-10 14:40:39 +01:00
Emma Thorpe 2bdca1c469 docs: sync shell/keybinding docs with the rest of the branch
CI / flake (pull_request) Successful in 2m18s
Update the interactive-shell README and keybindings reference for changes
made after the initial docs commit: no scheduled GC (manual only),
NO_TMUX escape hatch, default-terminal tmux-256color + truecolor, the
JetBrainsMono Nerd Font (new Fonts section + iTerm2 caveat), the
UseKeychain IgnoreUnknown guard, and the vim-tmux-navigator (Ctrl-hjkl) +
resurrect save/restore tmux bindings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:37:27 +01:00
Emma Thorpe 4ca136f2b4 fix(ssh): guard macOS UseKeychain with IgnoreUnknown
nixpkgs' openssh lacks Apple's keychain patch, so `UseKeychain yes` is
rejected as "Bad configuration option" when that ssh is on PATH. Prefix
it with `IgnoreUnknown UseKeychain` (the module emits IgnoreUnknown first)
so a non-Apple ssh skips it while Apple's ssh still honours it. Still
Darwin-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:37:27 +01:00