* refactor(shells): use native Home Manager Nushell environment
Replace the Bash login-shell wrapper and hand-maintained Nushell PATH with programs.nushell.loadSessionVariables and home.sessionPath. Launch Nushell directly from Kitty, Ghostty, and Zed, with the macOS config-home override and Ghostty's vendor autoload directory.
Upstream feature: https://github.com/nix-community/home-manager/pull/9666
Assisted-by: DeepSeek Harness (deepseek-flash)
* feat(hosts): use Nushell as login shell on Ruby and Kana
Set the per-user shell explicitly and add Nushell to the system shell list. The system default shell and root remain unchanged.
Assisted-by: DeepSeek Harness (deepseek-flash)
* fix(ssh): preserve tuios session marker across SSH
Forward TUIOS_SESSION and accept it on NixOS sshd, so an SSH session opened from inside tuios does not auto-attach a nested remote tuios.
Assisted-by: DeepSeek Harness (deepseek-flash)
* feat(nixos): use Nushell login shell on non-desktop hosts
Enable the Nushell login shell through a shared module imported by the server and agent profiles. Desktop profiles continue to use Bash.
Assisted-by: DeepSeek Harness (deepseek-flash)
* fix(tuios): skip auto-attach in SSH sessions
Remote interactive shells now stay plain Nushell instead of starting a nested TUIOS when the SSH client is already inside a local TUIOS session. Local TUIOS auto-start is unchanged.
Assisted-by: DeepSeek Harness (deepseek-flash)
- Add the agent profile (modules/nixos/agent.nix: rootless Podman, linger,
nix-ld) with home/linux/tui.nix as its home role; ruby, kana and
aquamarine use it, so hosts no longer import from hosts/idols-ruby.
- Gate nushell's ~/.secrets source behind modules.shell.secrets.enable,
off on agent hosts.
- Persist the TUI home state on aquamarine's tmpfs root.
- Document host profiles in hosts/README.md; add tests/agent-profile and
drop the x86_64 colmena-parity test, which needs mysecrets.
Assisted-by: Claude Code (claude-opus-5-5)
Move standalone repository docs from the root into docs/ and add a documentation index that links the moved docs and the code-local runbooks.
Update Markdown links, source comments, and the root entry points to the new locations. Keep README.md and AGENTS.md at the root as required entry points.
Assisted-by: DeepSeek Harness (deepseek-flash)
`just mihomo-geo` copied geodata into the state dir so a cold start never
fetched it. tmpfiles now links v2ray-rules-dat and the DB-IP lite mmdbs
there, so geo-auto-update moves to the gateway config only.
Assisted-by: Claude Code (claude-opus-5-5)
WA-023 warns once nixVersions.stable reaches 2.35; WA-046 fails the build
once nixpkgs' xdg-desktop-portal-wlr is no longer the broken 0.8.4, so both
pins get revisited instead of lingering.
Assisted-by: Claude Code (claude-opus-5-5)
It is already the sshd module default, and the shared firewall forces
allowedTCPPorts to [ ] anyway; toplevel drvPaths are unchanged.
Assisted-by: Claude Code (claude-opus-5-5)
systemd's 60-fido-id.rules marks the FIDO hidraw node and the CCID USB
device as security tokens, and 70-uaccess.rules grants them to the
active seat. Drop the hand-written rules and the plugdev membership.
Assisted-by: Claude Code (claude-opus-5-5)
Exporters raced networkd for the LAN address at boot; drop the
network-online ordering and unlimited-restart hack and let a FreeBind
socket unit hold the port, passed in via --web.systemd-socket.
Assisted-by: Claude Code (claude-opus-5-5)
The boot-time oneshot only fixed the zones present when it ran, and
node_exporter had to Require it. A powercap add rule covers every zone
whenever it appears; the collector reads at scrape time, so no ordering
is needed.
Assisted-by: Claude Code (claude-opus-5-5)
On shoukei a DNS takeover that timed out failed mihomo.service, and the
nixpkgs unit has no Restart=, so the proxy stayed down. Prefix the hook
with '-' (fail open, like ai's hook). Also switch the dashboard title
patch to --replace-fail.
Assisted-by: Claude Code (claude-opus-5-5)
Cleanup runs as ExecStopPost, which a power loss mid-backup skips; the
leftover @restic-snapshot then failed every later run.
Assisted-by: Claude Code (claude-opus-5-5)
- WA-017: keyd(1) documents `control = layer(control)` etc. as the
default modifier bindings, so a keyd bump will never keep right-hand
modifiers distinct; the passthrough is intentional config. Say so in
peripherals.nix and drop the row.
- WA-026: installOnHost + restarting microvm@<guest> is the fallback
microvm.nix's own deploy.rebuild uses; only the in-place sshSwitch is
broken, so the removal condition is now about that.
- WA-023: locked versions are 2.35.3 (latest) and 2.34.9 (stable).
Assisted-by: Claude Code (claude-opus-5-5)
Each of these overrode a value nothing else set at a higher priority:
- qemu-guest: btrbk, hardwareTools and cloud-init have no competing
definition on the guests.
- mdns: nixpkgs' sunshine module sets avahi.publish.* with mkDefault.
- computer-use: i18n now sets the time zone with mkDefault.
- darwin terminal: the shared ghostty/kitty font sizes are now mkDefault.
- shoukei: sunshine is mkDefault false in remote-desktop.nix, zram's
memoryPercent is mkDefault 50; supportedFilesystems now merges instead
of discarding the fsType entries other modules add.
- youko: nothing enables docker.
- nixpak: pasta.enable and sockets.pipewire are mkDefault in the shared
modules, sockets.pulse already was.
Every NixOS host's toplevel drvPath is unchanged; on fern and frieren the
terminal font sizes and time zone evaluate to the same values.
Assisted-by: Claude Code (claude-opus-5-5)
nix-darwin runs `brew bundle` as `sudo --preserve-env=PATH ... env ...`,
so the variables the mkBefore'd activation snippet exported never reached
brew; activation was using the default upstream endpoints. Set them via
homebrew.onActivation.extraEnv, which nix-darwin puts on the `env` command
line (evaluated on fern), and drop the snippet.
Assisted-by: Claude Code (claude-opus-5-5)
nixpkgs' security/ca.nix and nix-darwin's security/pki module both append
"Comodo AAA Services root" to the cacert blacklist themselves, so the
explicit entry only duplicated it. Removes WA-040.
Assisted-by: Claude Code (claude-opus-5-5)
Run nginx on youko as a loopback pull-through HTTP cache for
cache.nixos.org and cache.numtide.com, exposed by Caddy at
https://nix-cache.writefor.fun.
Assisted-by: DeepSeek Harness (deepseek-flash)
Set the user-level npm/pnpm registry to npmmirror, and make Nix builds use the same mirror through nixpkgs' npmRegistryOverrides and rewriteURL. The configured Nixpkgs policy is also applied to myNurPkgs and Colmena's nodeNixpkgs so NUR packages such as dsh use the mirror while preserving Colmena parity.
Switch to the native deb package from nixpkgs-patched (#560225), remove the AppImage/FHS bwrap layer, and enable native Wayland while keeping the X11 fallback.
Keep only WeChat state under one app-scoped HOME and bind the host Documents and Downloads directories like the other desktop apps. User-selected files also go through the XDG FileChooser portal. Remove the launcher, activation script, and compatibility symlinks.
Assisted-by: DeepSeek Harness (deepseek-flash)
The homelab hosts accept root SSH with long-lived file keys, run several
exposed services with almost no systemd sandboxing, and keep no audit trail of
privileged actions. Close those three gaps, weighing each measure against its
cost instead of adopting a policy wholesale.
SSH
- Turn off KbdInteractiveAuthentication: nixpkgs defaults it to true and PAM
then still accepts the Unix password despite PasswordAuthentication = false.
- authorizedKeysInHomedir = false: only keys declared in Nix take effect;
youko keeps Gitea's forced-command file through `Match User gitea`.
- Pin aquamarine's passphrase-free remote-builder keys to
`restrict,command="nix-daemon --stdio --store daemon"`, so builds run in the
system daemon instead of an audited root login session.
systemd sandboxing
- Add the mylib.systemdHardening preset and apply it to the exposed, weakly
sandboxed services: caddy 7.8 -> 1.5, vmalert 8.2 -> 1.4, rustfs 6.6 -> 1.4,
whisper-asr 7.7 -> 1.6. An eval test pins the key restrictions.
- Rejected: a global all-keys policy (<=0.2 score gains on services nixpkgs
already sandboxes) and per-service confinement (bind paths to maintain).
auditd on all four hosts, reusing nixpkgs' loader and unit
- Audit login sessions only: a first `-a never,task -F auid=unset` rule keeps
services out of the per-syscall audit path. A compromised service is
therefore unrecorded until it opens a session.
- Record root commands, credential and host-key access, writes to SSH, account,
PAM, Nix-trust and audit configuration, module loads and session denials.
- Rejected: global denial logging, service-UID watches and
--loginuid-immutable (the kernel already records loginuid changes).
Verified on all four hosts after deployment: zero failed units, k3s 6/6 Ready,
and the exposed services healthy.
Assisted-by: Claude Code (claude-opus-5-5)
* chore(nix): update nixpkgs to e62746b and fix 26.11 breakage
Bump nixpkgs to e62746b and preservation to 00be7f7, then adapt to the removals and renamed options in the new revision: drop the removed boot.initrd.systemd.enable settings, trim the stale emSign CA blacklist on Linux while keeping it for the older Darwin input, and migrate Avahi publishing to settings.publish. Work around sunshine still setting the legacy Avahi options and keep dsh-nu on its tested Nushell 0.115.1. Patch NUR dsh's pnpm call to pass nodejs = null, and update pyclipsync for the stdenv.hostPlatform.system rename.
* chore(nix): refresh flake inputs for 26.11
- update nixpkgs-darwin to the same e62746b revision as nixpkgs
- make dsh-nu follow main nixpkgs and patch its testedWith manifest for the resolved Nushell
- refresh floating inputs; update lanzaboote, tuios, and ponytail
- drop the nixpkgs-2505 and rust-overlay workarounds
- keep pyclipsync on main and simplify the cross-platform CA blacklist
- adopt home-manager's Nushell loadSessionVariables default
* fix(gitea): use ROOT_URL for nixpkgs 26.11
nixpkgs removed the legacy settings.server.DOMAIN option; the existing ROOT_URL already carries the public URL.
* chore(nix): update dsh-nu to 0.7.0
Assisted-by: DeepSeek Harness (deepseek-flash)
The nvidia exporter binds the host's static LAN IPv4, but unlike the node and smartctl exporters it was not ordered after network-online.target. On boot it lost the race with networkd, hit the systemd start limit, and stayed failed until manually restarted.
Nothing imported it and the riscv64 output was already commented out; riscv64 hosts live in ryan4yin/nixos-config-sbc.
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
The backup unit publishes `restic_backup_last_success_timestamp_seconds` for the node_exporter textfile collector, and a rejected alert now fails the notify unit instead of exiting 0.
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
Hosts without Home Manager (aquamarine, the VM hosts, k3s guests) had no
interpreter. The system profile is separate from the per-user one, so desktops
keep their Home Manager copy in PATH.
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
Aquamarine builds for ai and shoukei across the three platforms, with both
daemons logging in as root. They authenticate with their passphrase-free SSH
host keys, and ssh_known_hosts now carries each builder's address.
Assisted-by: DeepSeek Harness 0.2.0-rc.2 (deepseek-flash)
The tuned package ships tuned-ppd.service with WantedBy=graphical.target, so
activation starts it without /etc/tuned/ppd.conf and switch-to-configuration exits 4.
Assisted-by: DeepSeek Harness (deepseek-flash)
The gateway LAN IPv6 transparent path stalls on TCP flows while IPv4 forwarding remains healthy. Withholding AAAA answers keeps LAN clients on the working fake-IPv4 TProxy path until the IPv6 path is fixed
Assisted-by: DeepSeek Harness (gpt-6.1-sol)
--redact produced a "shareable" template but replaced only the secret and the proxy-subscription urls: rule-provider tokens, private domains, the LAN controller address and the routing rules all stayed. Nothing in the repo consumed it.
Assisted-by: DeepSeek Harness (Qwen3.8-Flash-Next-IQ3_S-ista-text)
Without it mihomo skips the TUN's v6 half when no NIC has an IPv6 address at startup, yet still installs its strict-route v6 blackhole, which locks the host out of IPv6.
Assisted-by: DeepSeek Harness (qwen3.8-flash-iq3s-text)
No host defines a *-nixos-tests output; the pod firewall drops 5900-5903
from pod sources; the mihomo core keeps geodata and cache in its
StateDirectory; WA-020 was used twice and the cited WA-028 had no row.