## Summary
Follow-up cleanups from the post-refactor audit (issues #50–#53). All behaviour-preserving except the work-host changes (kube-tmux + Lens removal).
## Changes
- **#51** `refactor(ssh)` — move `services.openssh.enable` + `firewall.allowedTCPPorts = [ 22 ]` into `modules/ssh.nix`; drop the duplicated lines from T400, MacPro31, RPi5.
- **#50** `fix/feat(work)` — load kube-tmux from a pinned `flake = false` input (it is not in nixpkgs) and reference `${inputs.kube-tmux}/kube.tmux` directly, so the status line no longer depends on a manual `$HOME/code/kube-tmux` checkout. (Supersedes the interim file-existence guard.)
- **#52** `chore` — gitignore the untracked `tf-inspect/` scratch project.
- **#53** `chore` — remove the unused Lens package entirely (`pkgs.lens` + its unfree entry; `unfreePackages` is now just `claude-code`), fix the `nil`→`nil_ls` LSP doc, remove the redundant `.editorconfig` block, name the RPi5 Docker subnet in a `let` binding.
## Deferred (from #53, noted in the commit)
- `.gitignore` firmware entry — documented behaviour, low value, left as-is.
- Per-eval `nixpkgs-unstable` overlay import — inherently per-system; no clean single-import hoist.
## Verification
- `nix flake check` passes (treefmt, deadnix, statix, pre-commit, all hosts + Darwin + homeConfigurations).
- Derivation-path diff vs `main`: `lyrathorpe-mbp`, `lyrathorpe-t400`, `lyrathorpe-macpro31`, `lyrathorpe-rpi5` are byte-identical (confirms #51 and the subnet `let` binding change nothing). Only `emmathorpe-edaas` differs — the kube-tmux input (#50) and the Lens removal (#53).
Closes#50, #51, #52, #53.
---------
Co-authored-by: Emma Thorpe <emma.thorpe@citrix.com>
Reviewed-on: #54
## Summary
Separates user identity (data) from the reusable Nix modules and lets a host declare any number of users, replacing the previous one-user-per-host structure. Also restructures the tree and exposes the home config for use off these hosts.
## Changes
- **User registry** (`users/registry.nix`): per-user identity (name, email, groups, authorized + signing keys) as the single source of truth; no user data hardcoded in modules.
- **Multi-user `mkHost`**: a host declares a `users` set keyed by username; per-user identity is injected into each home config via the `identity` module arg.
- **Restructured layout**: `users/`, `home/`, `modules/`, `hosts/`, `lib/` replace the former `lyrathorpe/` and `system/` trees.
- **Portable outputs**: standalone `homeConfigurations."<user>@<system>"` (the portable subset — shell, git, editor, claude) plus an exported `homeModules` for use on machines not managed by this flake, or as an input to other flakes.
- Docs (`README.md`, `home/README.md`) and `.gitignore` updated for the new paths.
## Fixes
- Closes#46 — shared user module authorized one user's SSH key for every account.
- Closes#47 — git committer identity hardcoded as defaults instead of per-user.
- Closes#48 — EDaaS systemd linger hardcoded to a literal username.
## Verification
- `nix flake check` passes: treefmt, deadnix, statix, pre-commit, and evaluation of all NixOS hosts + Darwin + homeConfigurations.
- Derivation-path comparison vs `main`: `lyrathorpe-mbp` and `emmathorpe-edaas` are byte-identical; `lyrathorpe-t400`, `lyrathorpe-macpro31` and `lyrathorpe-rpi5` differ only by de-duplicating a repeated `authorized_keys` entry (confirmed with nix-diff — no other change).
- Standalone `homeConfigurations."lyrathorpe@x86_64-linux".activationPackage` builds.
## Notes
- `emmathorpe` has no personal authorized key yet (it previously inherited Lyra's key via the bug in #46); the registry entry is intentionally empty — add a real key if SSH login as `emmathorpe` is wanted (moot on the WSL host).
- A two-repo (public dotfiles / private systems) split is deferred by design; this internal restructure is the prerequisite for it.
---------
Co-authored-by: Emma Thorpe <emma.thorpe@citrix.com>
Reviewed-on: #49
The NixOS-WSL module's wslConf.interop submodule declares only `enabled`
and `appendWindowsPath`. `register` and `includePath` are not valid
wsl.conf interop keys, and the freeform INI type does not cover keys
nested under the already-declared `interop` group, so they were rejected
as unknown options. Remove them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes#39.
nvim-cmp ships no default keymaps, so the completion menu (including the path source) appeared but nothing could navigate or accept it.
Bind the usual set in `plugins.cmp.settings.mapping`:
- `<C-n>` / `<C-p>` and `<Tab>` / `<S-Tab>` — select next/previous
- `<C-Space>` — open the menu
- `<C-e>` — abort
- `<CR>` — confirm with `select = false` (bare Enter stays a newline unless an entry is highlighted)
Documentation: `KEYBINDINGS.md` gains a completion-menu table under the Neovim section covering these keys, and the Neovim summary is reworded accordingly.
Verified by rendering the generated nvim config: the mappings emit as raw Lua (e.g. `["<CR>"] = cmp.mapping.confirm({ select = false })`), not quoted strings.
---------
Co-authored-by: Emma Thorpe <emma.thorpe@citrix.com>
Reviewed-on: #40
catppuccin v2.0.0 renamed its lualine theme files; there is no longer a
plain "catppuccin" theme, only per-flavour files (catppuccin-mocha, etc.)
and catppuccin-nvim. The old name no longer resolved, so lualine fell back
to the auto theme and emitted a notice. Pin to catppuccin-mocha to match
the configured colorscheme flavour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add system/machine/RPi5/README.md (flash/boot, regenerate hardware-config,
Docker-socket security caveat and remote-client usage, how to add a
reverse-proxy vhost). Add lyrathorpe-rpi5 to the README host table and note
that the swayDesktop flag now lives in system/modules/features.nix so headless
hosts keep TTY login.
Add the aarch64-linux Raspberry Pi 5 host to the host table: the RPi5
machine config, the raspberry-pi-5 nixos-hardware profile, and key-only
sshd. Headless, so no swaywm.nix; base home modules only.
lyrathorpe/user.nix reads features.swayDesktop.enable on every host, but the
option was declared inside lyrathorpe/swaywm.nix -- so a host that does not
import swaywm.nix (a headless server) would fail evaluation. Move the option
declaration to a new always-imported system/modules/features.nix and wire it
into baseModules; swaywm.nix keeps only its implementation (config) block.
Headless hosts can now omit swaywm.nix and the flag defaults to false.
Tie the RPi5 submodules together: import hardware-config, docker.nix and
reverse-proxy.nix; pin networking.hostName to the flake attr name so nh
resolves; use U-Boot/extlinux boot (raspberry-pi-5 profile supplies kernel +
firmware); enable key-only sshd and a default-deny firewall opening 22.
Headless -- swaywm.nix is not imported, so swayDesktop stays off.
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.
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.
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.
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.
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.
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.
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'.
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.
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.
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.
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.