Commit Graph
100 Commits
Author SHA1 Message Date
Ryan Yin 9a6923b4e9 fix(k3s): drop Home Manager from test masters
Keep the six node configuration intact while removing the failing user activation from the three control-plane MicroVMs. Update the regression test and current K3s configuration notes.
2026-09-24 13:35:33 +08:00
ryan4yin | 二花 f5f4531fcb Merge pull request #312 from ryan4yin/fix/k3s-test-1-guest-dns
fix(k3s): stabilize guest networking and control-plane metrics
2026-09-24 11:36:41 +08:00
ryan4yin | 二花 882383f754 Merge pull request #309 from ryan4yin/fix/k3s-test-1-stable-ipv6
fix(k3s): disable temporary IPv6 addresses in test VMs
2026-09-24 11:29:23 +08:00
Ryan Yin c752703488 docs(network): explain DHCPv6 DNS overrides 2026-09-24 10:43:49 +08:00
Ryan Yin 688a244ae0 fix(k3s): ignore advertised DNS on test VMs 2026-09-23 23:44:13 +08:00
Ryan Yin f357569d32 fix(k3s): disable IPv6 privacy on guest NICs 2026-09-23 23:05:53 +08:00
Ryan Yin fa0743a28b fix(k3s): disable temporary IPv6 addresses in test VMs 2026-09-23 22:28:35 +08:00
Ryan Yin d1dd35bd7c chore(codex): bump the override to 0.156.1
0.156.1 still lacks the codex-chatgpt recursion_limit attribute, so keep the postPatch that adds it. The vendored Cargo.lock is unchanged, so the cargoHash stays the same.
2026-09-23 12:07:28 +08:00
Ryan Yin 55aa4e3e10 fix(k8s): link the CNI dirs on the k3s agent nodes
cilium writes /etc/cni/net.d while istio-cni reads k3s's own dir, so on the new workers the chained plugin never found a network config. Add the symlinks the server module already has.
2026-09-23 12:07:28 +08:00
Ryan Yin 64cad91401 fix(k8s): unblock the k3s-test-1 workers
kubelet refuses to self-assign the reserved node-role.kubernetes.io/* labels, so the worker --node-label made the agent crash-loop. Drop it and rely on the masters' control-plane taint for placement; document that the taint only lands via registerWithTaints on first registration, so it was applied by hand here.
2026-09-23 12:07:28 +08:00
Ryan Yin a3efb42202 chore(k8s): update secrets 2026-09-23 12:07:28 +08:00
Ryan Yin a2604a0c32 chore(codex): override to 0.156.0 pending llm-agents bump 2026-09-23 10:37:52 +08:00
Ryan Yin f6e331dbf7 flake.lock: Update
Flake lock file updates:

• Updated input 'llm-agents':
    'github:numtide/llm-agents.nix/34081a176242cbccd62f19978f32abfff933813f?narHash=sha256-5QvQZFsM/xcZRVUGuv56QU3d0RQZcqR9axikxGf1KLE%3D' (2026-09-19)
  → 'github:numtide/llm-agents.nix/fcf80443a6e5363f30dc9b191bcb65cfcd788df2?narHash=sha256-uWgg4A%2BhrlViz1L0y9D8zMkIjQU8UzJqoyxaZ3xY24Q%3D' (2026-09-23)
• Updated input 'llm-agents/bun2nix':
    'github:Mic92/bun2nix/5765b0614591f75ee8ba5596e81ae85c167d1071?narHash=sha256-mEq2kU%2BljompTToZ44Afvm7d/rHJ5iMBl0tjZuyShJs%3D' (2026-08-29)
  → 'github:Mic92/bun2nix/07a5bfc8ac36c5370199343fa620b69f63186e33?narHash=sha256-1/SLBjSYBzDdDhvLQ83wrzBakyS/xNGgtxHGNuveOEQ%3D' (2026-09-21)
• Updated input 'llm-agents/nixpkgs':
    'github:NixOS/nixpkgs/c7def046b9a883d46974757852106483d741586f?narHash=sha256-6RSEDHIWQtesQKWSu5qRai8L2h4KgCgMEfJHstW99G4%3D' (2026-09-14)
  → 'github:NixOS/nixpkgs/b6c98e9e6633ee64753b594ff4a5febf0367fc00?narHash=sha256-QpXotokGh5eeMG1Njiuh27oP0rK6t5%2BcMp7ymXSs7mc%3D' (2026-09-22)
2026-09-23 09:50:10 +08:00
ryan4yin | 二花 5d0055b024 Merge pull request #277 from ryan4yin/feat/cua-headless-sway
feat(computer-use): headless X11/i3 + cua-driver on ruby and kana
2026-09-21 21:43:45 +08:00
Ryan Yin 0185fd0f85 docs(computer-use): document the headless i3 session 2026-09-21 21:31:27 +08:00
Ryan Yin 00aab5f562 feat(computer-use): add a headless X11/i3 environment
Give the idols-ruby and idols-kana VMs a headless computer-use
environment: Xvfb plus i3, driven by cua-driver (and computer-use-linux
as a fallback). Includes the system module (AT-SPI, fonts, Mesa, Clash
Verge proxy, proxy-region timezone), the home i3 module (Xvfb/i3/x11vnc
services, browser flags), host wiring and an eval test.
2026-09-21 21:31:27 +08:00
Ryan Yin 90761a6b73 feat(computer-use): package computer-use-linux and cua-driver
Package the prebuilt releases (computer-use-linux v0.7.1 and
cua-driver-rs v0.24.0) under pkgs/, injected through thin callPackage
overlays so they are easy to relocate to the NUR repository later.
2026-09-21 21:31:27 +08:00
Ryan Yin 37f29154d1 docs(backup): record what the metrics actually expose
rest-server only ships the go/promhttp defaults, so repository growth is
charted from node-exporter's filesystem metrics instead.
2026-09-21 20:57:41 +08:00
Ryan Yin 842cd26f64 feat(monitoring): scrape the restic rest-server
Expose /metrics on the loopback-bound server, scrape it with
victoriametrics, and block /metrics on the public vhost.
2026-09-21 20:56:01 +08:00
Ryan Yin 1cbb52add1 docs(secrets): desktops and recovery_key have identical access
recovery_key is a member of desktop_keys, so every group written as
desktop_keys ++ ... covers both.
2026-09-21 20:51:13 +08:00
Ryan Yin 89e57b5b39 docs(secrets): state that every secret must be decryptable by the desktops
The desktops hold the trusted admin keys and are where secrets are edited and
rekeyed from; narrowing a set to the servers alone breaks agenix -r and drops
the offline recovery key.
2026-09-21 20:50:11 +08:00
Ryan Yin a43aa02a69 docs(secrets): state the recipient invariant
A recipient set must answer two questions: who may read it, and how it is
recovered once those hosts are gone. Dropping recovery_key while narrowing
a secret is easy and silent.
2026-09-21 20:45:47 +08:00
Ryan Yin 8a44c23d74 docs(backup): say 'cloud copy' rather than 'offsite'
Clearer for a reader who does not live in backup jargon; the requirement
(not in the homelab, immutable) is spelled out in the text.
2026-09-21 20:44:56 +08:00
Ryan Yin 096607a5c5 feat(backup): notify on failure, and 404 unconfigured hostnames
A failed backup was silent. Post to alertmanager (which routes above-info
to telegram), and have caddy answer 404 instead of its empty 200 for
*.writefor.fun names that are not services.
2026-09-21 20:42:39 +08:00
Ryan Yin c3f0dbf8bd revert(backup): drop append-only for the desktop endpoint
A desktop holds both the plaintext and the repository password, so blocking
deletion on the server protects little while preventing the automatic
retention the client needs. Immutability belongs in the offsite copy.
2026-09-21 20:38:08 +08:00
Ryan Yin 5a017666f6 refactor(backup): name the REST endpoint restic.writefor.fun
'backup' did not say what the service is.
2026-09-21 20:38:08 +08:00
Ryan Yin d322f4d2b6 docs: add BACKUP.md, and stagger the restic schedule per host
The design (layers, password groups, retention, restore steps) was only in
code comments. Also make the timer configurable: a whole hour of random
delay defeated any staggering, and the desktop's push, youko's own run and
btrbk all otherwise contend for the same disks.
2026-09-21 20:38:08 +08:00
Ryan Yin 2ff93c16ce feat(restic): move idols-ai's off-host backup to the REST server
Split the repository password into desktop and homelab groups, add the
environmentFile/pruneOpts module options, and point the desktop at youko's
REST endpoint.
2026-09-21 20:38:08 +08:00
Ryan Yin 1e2cef2550 feat(youko): serve restic backups over an append-only REST server
Run restic-rest-server behind caddy (append-only, private repos, htpasswd
from agenix) and register youko's host key centrally.
2026-09-21 20:38:08 +08:00
Ryan Yin 12ac5f45aa feat(idols-ai): restic backup to a local repository
Allowlist of the irreplaceable directories (Documents, work, Pictures,
nix-config, .local/state); project checkouts under ~/codes live in git and
are not backed up. Kept the excludes generic, since this repo is public.

Also move the restic-password secret to a desktop.enable || server.storage
gate so desktops get it without enabling a server group.
2026-09-21 19:04:58 +08:00
ryan4yin | 二花 9ef7ba7112 Merge pull request #297 from ryan4yin/feat/app-data-to-ssd
feat(youko): move the service data from the HDD to the SSD
2026-09-21 18:00:10 +08:00
Ryan Yin a755b6fa11 feat(youko): move the service data from the HDD to the SSD
The services now run directly on the host, so their state does not belong
on the HDD behind the flaky USB-SATA bridge: /data/apps was small-file
heavy and latency/consistency sensitive. Point every dataDir at
/persistent/apps (the LUKS nvme) instead.

The HDD keeps the bulk data that suits it: /data/fileshare (173G) and
/data/backups (24G). The HDD's old @apps subvolume and its data are left
in place for now.
2026-09-21 17:56:35 +08:00
ryan4yin | 二花 12966d326c Merge pull request #296 from ryan4yin/fix/usb-hdd-mitigations
fix(youko): mitigate the flaky USB-SATA HDD bridge
2026-09-21 17:56:08 +08:00
Ryan Yin 5bbe17ebcd fix(youko): also try disabling the WD idle3 (Intellipark) timer
-B 255 turns APM off and it stuck, but the disks still reach standby, so
the bridge firmware is likely doing the spindown. -J 0 additionally asks
the drive to stop parking its heads (sdb has ~1M load cycles).
2026-09-21 17:43:05 +08:00
Ryan Yin 899162055a fix(youko): drop pcie_aspm=off, re-assert the hdparm settings hourly
pcie_aspm=off was the least-justified mitigation (the flakiness is on the
USB/SATA side) and costs power. Also log the disks' APM level/state and
re-apply the settings hourly, since the bridge or the disk firmware can
drop them (the disks were still reaching standby).
2026-09-21 17:42:21 +08:00
Ryan Yin 45a35a080d fix(youko): address the HDDs by-id, not /dev/sdX
Follows the disko config (ata-WDC_...-<serial>); the sdX names are not
stable.
2026-09-21 17:38:54 +08:00
Ryan Yin ce1645619f fix(youko): mitigate the flaky USB-SATA HDD bridge
The two 4TB HDDs sit behind a JMicron JMS567 that resets and throws
UDMA-CRC / I/O errors (the disks themselves are healthy). Best-effort
mitigations while the enclosure stays in use:

- kernel: usbcore.autosuspend=-1, usb-storage.delay_use=10, pcie_aspm=off
- udev: keep the bridge's power/control=on (never autosuspend)
- disable APM/standby on the HDDs (spindown is a common reset trigger)
- enable smartd (watch the CRC count and disk health)

The kernel parameters need a reboot to take effect.
2026-09-21 17:37:52 +08:00
ryan4yin | 二花 4867e94171 Merge pull request #294 from ryan4yin/chore/drop-kubevirt-guest
chore: drop the KubeVirt guest bits and dead upload recipes
2026-09-21 17:29:49 +08:00
Ryan Yin 8b1fa3ac87 chore(secrets): drop the unreferenced dae-subscription secret
Nothing consumes it (it was gated on modules.secrets.server.network)
and its only content was the secret definition.
2026-09-21 17:29:36 +08:00
Ryan Yin 03619f8055 chore(utils.nu): drop the dead upload-vm helper
It wrote a built image into a KubeVirt DataVolume over the CDI upload
proxy; with KubeVirt gone (and the Justfile callers removed) it is dead
code.
2026-09-21 17:27:16 +08:00
Ryan Yin dbeef8bfaa docs: drop Virtual-Machine.md
It documented the retired KubeVirt workflow (upload a qcow2, create the vm
in k8s-gitops, let Flux create it), which no longer exists. The general
deployment notes live in the README and the per-platform docs
(hosts/k8s/README.md for the microVMs).
2026-09-21 17:26:38 +08:00
Ryan Yin e939c54d26 chore: refresh the remaining KubeVirt references
Update the user-facing bits that still pointed at KubeVirt: the homepage
dashboard group and entries (and drop the dead LongHorn one), the docs,
and remove the now-unneeded virtctl package.
2026-09-21 17:25:38 +08:00
Ryan Yin 6180072646 chore: drop the KubeVirt guest bits
The k3s-test workers never ran (they were stuck waiting for volume
binding) and will be re-added as microVMs, so remove their KubeVirt
configs and everything that only existed for KubeVirt guests:

- hosts/k8s/k3s-test-1-worker-{1,2,3} and their outputs
- lib/genKubeVirtGuestModule.nix and lib/genK3sAgentModule.nix (the
  latter was only used by the workers)
- the KubeVirt image upload recipes (upload-vm, upload-idols,
  upload-k3s-test) and the kubevirt image package in the idols outputs
- refresh the docs; keep only accurate historical mentions (e.g. the
  restic backup path must stay as it is)
2026-09-21 17:24:40 +08:00
ryan4yin | 二花 8427dee2e6 Merge pull request #292 from ryan4yin/chore/rename-12kingdoms
refactor: rename the three VM hosts to 12kingdoms-*
2026-09-21 17:11:58 +08:00
Ryan Yin 2c7629000f refactor: rename the three VM hosts to 12kingdoms-*
Drop the now-meaningless kubevirt- prefix and move the hosts out of
hosts/k8s/, following the existing 12kingdoms-shoukei layout: the
directory and output carry the theme prefix while the configuration,
hostname and colmena target are the bare name (shoryu, shushou, youko).

- hosts/k8s/kubevirt-* -> hosts/12kingdoms-*; the shared disko config
  becomes host-disko-fs.nix; the now-different relative imports are fixed
- outputs, vars/networking.nix keys, the Justfile recipes/tags, the eval
  tests and the docs follow
- colmena reaches these hosts by IP (a new targetHost override), since
  their DNS name changes with the hostname and is not resolvable until
  the router learns it
2026-09-21 17:10:14 +08:00
ryan4yin | 二花 3aec8341dd Merge pull request #291 from ryan4yin/chore/retire-host-k3s
chore(hosts): retire the k3s cluster on the physical hosts
2026-09-21 17:05:25 +08:00
Ryan Yin 8d848a878a chore(gitignore): trim the Python section to what a script repo needs
This is not a Python package, so drop the packaging/build/pyinstaller/
framework/type-checker/pyenv/poetry/pdm/pixi/celery/rabbitmq rules and the
unused Marimo and Streamlit sections. Keep the bits occasional Python
scripts do need: byte-compiled files, virtualenvs, local secrets and the
common tool caches.
2026-09-21 16:59:42 +08:00
Ryan Yin 116f2dc114 chore(gitignore): stop ignoring the repository's own lib/
The Python section of the .gitignore template has a bare 'lib/' (and
'lib64/'), which also matched the Nix helper modules in lib/. The
'!lib/*.nix' line added earlier could not help, since a file cannot be
re-included while its parent directory is excluded.
2026-09-21 16:58:24 +08:00
Ryan Yin cf2435e854 chore(hosts): retire the k3s cluster on the physical hosts
The physical hosts no longer need k3s or KubeVirt: aquamarine runs
natively, the k3s-test masters run as microVMs and kana/ruby under
libvirt. So drop the host cluster and split the shared parts out of the
KubeVirt host module:

- lib/genVmHostModule.nix: the host bits the VMs still need (br0 + the
  physical NIC as a bridge port, KVM, sysctls, earlyoom, libvirt,
  journald, stateVersion)
- the three hosts use it and drop genK3sServerModule; also drop the
  longhorn workarounds (openiscsi + the /usr/local/bin tmpfile) and the
  virtctl package
- remove lib/genKubeVirtHostModule.nix
2026-09-21 16:57:42 +08:00
ryan4yin | 二花 6e551770ac Merge pull request #290 from ryan4yin/chore/rename-kubevirt-hw-config
refactor: rename the KubeVirt hardware config to qemu-guest
2026-09-21 16:50:36 +08:00
Ryan Yin 01110e93d2 Merge remote-tracking branch 'origin/main' into chore/rename-kubevirt-hw-config
# Conflicts:
#	outputs/x86_64-linux/src/k3s-test-1-master-1.nix
#	outputs/x86_64-linux/src/k3s-test-1-master-2.nix
#	outputs/x86_64-linux/src/k3s-test-1-master-3.nix
2026-09-21 16:50:25 +08:00
ryan4yin | 二花 e1b6019037 Merge pull request #289 from ryan4yin/feat/k3s-microvm
feat(microvm): run the k3s-test-1 masters as microVMs
2026-09-21 16:49:51 +08:00
Ryan Yin 60c59543b3 refactor: rename the KubeVirt hardware config to qemu-guest
The file is not KubeVirt-specific: it is the hardware configuration for
any QEMU guest that boots from a disk (KubeVirt or libvirt). All it does
is pull in qemu-guest.nix and set fileSystems."/" from the disk labeled
nixos.
2026-09-21 16:48:47 +08:00
Ryan Yin b9c5d3e5c9 docs: describe the k3s-test microVMs
hosts/k8s/README.md: how the microVMs keep state, the tap/br0 naming, how
to move a KubeVirt VM over in place, and the refreshed TODOs. Also note
the migration in Virtual-Machine.md and flag the volume images in
AGENTS.md.
2026-09-21 16:37:53 +08:00
Ryan Yin e428d66abf feat(microvm): make the guest volume sizes configurable
etcSize/varSize/homeSize (MiB) with the old defaults. The masters get a
20G /var: k3s server + containerd + logs already filled the old 4G.
2026-09-21 16:37:53 +08:00
Ryan Yin 4ad359696e feat(microvm): run the k3s-test-1 masters as microVMs
Replace the KubeVirt/etcd members with microVMs on the three physical
hosts, keeping the existing cluster: the guests inherit their host key
and k3s state from the old disks, so etcd recovers in place instead of
bootstrapping a new cluster.

- convert hosts/k8s/k3s-test-1-master-{1,2,3} to genMicrovmGuestModule
  and switch their outputs to the microvm module (keep home-modules)
- declare the vms on shoryu/youko/shushou and bridge their taps to br0
- each guest config is self-contained (its secret group and the
  nixpkgs.config override live in the guest, not the host module)
- guest specialArgs carry agenix/mysecrets so secrets/nixos.nix works
2026-09-21 16:32:23 +08:00
Ryan Yin 9b76879235 feat(microvm): add a microVM guest module
lib/genMicrovmGuestModule.nix: qemu guest with a shared read-only store
(virtiofs), persistent /etc, /var and /home volumes, a tap on br0 (its
name derived from the guest IP, as IFNAMSIZ caps it at 15 chars), and a
deterministic MAC. Also keep lib/*.nix tracked.
2026-09-21 16:32:23 +08:00
ryan4yin | 二花 bbc4bf9449 Merge pull request #288 from ryan4yin/feat/aquamarine-to-youko
feat: run aquamarine's services natively on kubevirt-youko
2026-09-21 15:50:25 +08:00
Ryan Yin bc7d62b063 refactor(kubevirt-youko): resolve cert paths with relativeToRoot
The service modules moved two levels deeper, so their certs/ paths
resolved relative to the wrong directory. Use mylib.relativeToRoot so
they no longer depend on the module's depth.
2026-09-21 15:50:15 +08:00
Ryan Yin f9c902691b refactor: name the youko service modules by purpose
Drop the retired host's name from the filenames:
aquamarine-services.nix -> homelab-services.nix and the aquamarine/
module dir -> homelab-services/. The "aqua" name now stays only in the
docs/vars, where it is kept for a possible later test microvm/qemu-vm on
idols-ai.
2026-09-21 15:46:55 +08:00
Ryan Yin c292509351 refactor: retire the aquamarine VM host
Aquamarine's services now run directly on kubevirt-youko, so the guest
definition is no longer needed:

- move its service modules to hosts/k8s/kubevirt-youko/aquamarine/ and
  drop the explicit import list, leaving aquamarine-services.nix with
  just its IP and secret groups
- delete the guest base, journald override, output entry and home config
- repoint the eval tests that read the guest's config to kubevirt-youko
- drop the now-dead 'aqua' colmena recipe and its image upload

The aqua KubeVirt VM itself is deleted separately; the name is kept in
the docs for a possible later test microvm/qemu-vm on idols-ai.
2026-09-21 15:45:02 +08:00
Ryan Yin dfc3c2884a fix(aquamarine): order transmission after its data mount 2026-09-21 15:39:52 +08:00
Ryan Yin abd28347ab fix(aquamarine): qualify the uptime-kuma image for podman 2026-09-21 15:39:52 +08:00
Ryan Yin 37ebd7a5f8 feat(kubevirt-youko): run aquamarine's services on the host 2026-09-21 15:39:52 +08:00
Ryan Yin 40b3786f14 docs(kubevirt): refine switch vs boot guidance 2026-09-20 22:45:22 +08:00
Ryan Yin 54016a9da2 fix: address nixpkgs rename/deprecation warnings 2026-09-20 22:42:06 +08:00
Ryan Yin 0802b5a3d1 feat(kubevirt): cap host journald at 10G 2026-09-20 22:42:03 +08:00
Ryan Yin fb522af5c0 feat(kubevirt): cap journald disk usage on all VMs 2026-09-20 22:22:50 +08:00
Ryan Yin 68bea13405 docs(kubevirt): document boot+reboot for KubeVirt hosts 2026-09-20 22:22:47 +08:00
Ryan Yin 4e66a6de57 chore: remove insecure modelscope package 2026-09-20 21:36:23 +08:00
Ryan Yin 9bb608a577 fix(idols-aquamarine): migrate journald.extraConfig to settings.Journal 2026-09-20 21:36:21 +08:00
Ryan Yin 69f60095ae fix(networking): drop shoukei static address
shoukei is a laptop using DHCP and never consumes hostsAddr.shoukei.
Its 192.168.5.108 collided with k3s-prod-1-master-1 and produced a wrong
ssh Host shoukei entry.
2026-09-20 20:26:17 +08:00
Ryan Yin 5613e00b6c chore: noctalia - adjust osd position 2026-09-20 13:52:31 +08:00
Ryan Yin 51d5fab0bd flake.lock: Update
Flake lock file updates:

• Updated input 'mysecrets':
    'git+ssh://git@github.com/ryan4yin/nix-secrets.git?ref=refs/heads/main&rev=490e3aca901fa703083822ee64a65f0a1f4529af&shallow=1' (2026-06-12)
  → 'git+ssh://git@github.com/ryan4yin/nix-secrets.git?ref=refs/heads/main&rev=8cd11a98a258410e3af03a2bf3bfeff2201fa5f8&shallow=1' (2026-09-20)
2026-09-20 11:37:05 +08:00
Ryan Yin b1276082ea refactor(noctalia): move theme mode into the declarative config
The Settings UI stored `theme.mode` in ~/.local/state/noctalia/settings.toml, so it was not versioned. Pin it in the config baseline; the [location] sunrise/sunset schedule still drives light/dark.
2026-09-20 10:54:34 +08:00
Ryan Yin e93cb9793d fix(noctalia): keep the bar readable in light mode
At background_opacity 0.2 the light-mode surface disappears into dark wallpapers, so the dark light-mode text sits on a dark bar. Raise it to 0.61 to keep contrast while staying slightly translucent.
2026-09-20 10:35:48 +08:00
Ryan Yin 063c31cc30 refactor(noctalia): hot-reload config via out-of-store symlink
`programs.noctalia.settings` deploys the TOML as a store symlink, so every edit needs a `home-manager switch`. Deploy the baseline from the config layer with `mkOutOfStoreSymlink` instead: Noctalia hot-reloads config-layer files and never rewrites them, so edits apply live while Settings UI changes stay in ~/.local/state/noctalia/settings.toml (which loads last) and out of the repo.

Update the docs and host-specific comments to match the two-layer model.
2026-09-20 10:35:48 +08:00
Ryan Yin 7bd873e414 fix(firefox): share MPRIS artwork, trash and host config paths
The sandbox remaps XDG_DATA_HOME/XDG_CONFIG_HOME, so paths Firefox exposes to
or shares with the host ended up isolated. Bind the MPRIS artwork dir and the
real trash rw, and mimeapps.list, user-dirs.dirs and the shared NSS cert store
ro.

recently-used.xbel stays isolated: GTK writes it atomically, which a
single-file rw bind would break.
2026-09-20 02:11:58 +08:00
Ryan Yin 140a6d6288 feat(noctalia): hide the media widget when idle 2026-09-20 02:00:31 +08:00
Ryan Yin 47bf47f41d chore(desktop): drop duplicate applets and tune the noctalia bar 2026-09-20 01:35:20 +08:00
Ryan Yin 0403fbda87 feat(noctalia): restore bar system monitors and a dated clock
Add cpu, ram, disk and network up/down sysmon widgets to the bar start lane,
matching the old v4 SystemMonitor. Set the clock to ISO date, full English
weekday and 24h time (e.g. "2026-09-19 Saturday 16:06").
2026-09-19 16:15:38 +08:00
Ryan Yin ccaed6beff chore(i18n): keep only China-specific locale overrides
English stays the default (LANG=en_US.UTF-8). Drop the Chinese overrides for
LC_TIME, LC_NUMERIC, LC_ADDRESS, LC_NAME, LC_TELEPHONE and LC_IDENTIFICATION:
LC_NUMERIC matches en_US, the others are effectively unused, and LC_TIME forced
Chinese date and weekday names.

Keep zh_CN only where the en_US default is wrong for China: metric units, A4
paper and CNY.
2026-09-19 16:15:35 +08:00
Ryan Yin 8866a3bd92 docs(agents): document deploy recipes, host naming and conventions
- clarify 'just niri' (<hostname>-niri) vs 'just local' (bare hostname)
- note where overlays/hardening packages live
- note the Noctalia config location and host-specific <host>.toml overrides
2026-09-19 15:33:21 +08:00
Ryan Yin 7dba3b7fd7 chore: drop the redundant CLAUDE.md symlink
CLAUDE.md was just a symlink to AGENTS.md; AGENTS.md is the single source of agent guidance.
2026-09-19 15:32:18 +08:00
Ryan Yin 4d8fec5fa9 docs: rewrite the root README
Refresh the repository overview after the move to Noctalia v5:

- fix the component table: Noctalia as the desktop shell, native screenshots, systemd-networkd/NetworkManager, Zed & VS Code as GUI editors, Zellij as a multiplexer
- correct the deploy instructions (niri hosts use 'just niri'; 'just local' matches the bare hostname) and the Nvidia link
- update the NixOS badge to 26.11 and add a short validation section
2026-09-19 15:30:37 +08:00
Ryan Yin 98fbf010b8 docs: fix broken links and editor references in readmes
- root README: VS Code config moved from home/linux/gui/base/editors.nix to vscode.nix
- READMEs now list both GUI editors (Zed, the primary one, plus VS Code)
- base README: xdg is a directory now, nvidia.nix no longer exists, editors.nix -> vscode.nix
- idols-ai README: disko-fs-media.nix -> disko-fs-data.nix (/persistent/data)
- secrets README: password-store moved from home/base/desktop to home/base/tui
- drop unused link definitions (AstroNvim, wl-clipboard, Catppuccin)
- fix a pre-existing typo flagged by the typos hook (keeped -> kept)
2026-09-19 15:23:09 +08:00
Ryan Yin 001d180b22 feat(noctalia): upgrade to the native v5 shell
Noctalia v5 is the native C++/Wayland rewrite; the Quickshell-based v4 line (pkgs.noctalia-shell) is EOL and its JSON config is not migrated upstream.

- use the upstream home-manager programs.noctalia module (present at our pinned HM revision) instead of the hand-rolled package + symlink module: it installs pkgs.noctalia, validates config.toml at build time via checkConfig, and supports customPalettes; drop the v4 Qt/Qt6ct session setup
- replace the v4 settings.json/plugins.json with a minimal shared config.toml (font, Catppuccin shell palette, templates off, screenshot annotation, accessibility/bar scale, night light, wallpaper, location/weather); host-specific bits live in per-host files (shoukei's eDP-1 backlight in noctalia/host-shoukei.toml), which merge after config.toml. Application theming stays with catppuccin/nix
- treat config.toml as the single source of truth: do NOT persist ~/.local/state/noctalia and set setup_wizard_enabled = false, so UI tweaks are promoted back into the repo instead of accumulating in app-owned state
- port niri keybinds to 'noctalia msg ...', update spawn-at-startup and the backdrop layer namespace, fix the broken 'octalia-shell' media-previous bind, and replace the grim/slurp/satty screenshot stack with Noctalia's native region/fullscreen/annotate commands (drop the unused packages)
- drop the now-redundant swaybg and swaylock (Noctalia owns the wallpaper and lock screen, the latter authenticating against the PAM 'login' service) and its PAM entry; keep wlogout as an emergency fallback
- update hypridle's lock commands and the matching eval test
- refresh the noctalia docs
2026-09-19 15:07:54 +08:00
Ryan Yin 2dff4f062b fix(networking): disable systemd-resolved mDNS when avahi is enabled
networkd enables systemd-resolved by default, and resolved's own mDNS responder conflicts with avahi (duplicate answers, avahi logs 'Detected another mDNS stack running on this host'). Keep avahi for DNS-SD (cups-browsed depends on it) and turn resolved's mDNS off.
2026-09-19 13:54:19 +08:00
Ryan Yin 5d9b117442 fix(agents): keep opencode inline config quoting intact
home.sessionVariables writes export NAME="value" without escaping embedded double quotes, so the JSON {"share":"disabled"} reached opencode as the shell word {share:disabled} and failed config parsing. Emit the export with sessionVariablesExtra instead.
2026-09-19 13:54:15 +08:00
Ryan Yin 33383414a2 fix(niri): match outputs by EDID to survive connector renumbering
The 2026-09 nixpkgs update changed DRM probe order, renaming the Intel connectors DP-1 -> DP-4 and HDMI-A-2 -> HDMI-A-3. The connector-name based output and open-on-output rules stopped matching, which dropped monitor scale/mode/position and sent every named workspace to the first output. Match by make/model/serial instead, which is stable across connector renumbering.
2026-09-19 13:26:24 +08:00
Ryan Yin 7242892355 fix(hardening): refresh wechat source hashes
Tencent replaced the file behind the versionless CDN URLs, so the pinned hashes stopped matching. Refresh the x86_64 and aarch64 hashes with nix store prefetch-file.
2026-09-19 13:26:20 +08:00
Ryan Yin a465853b6a flake.lock: Update
Flake lock file updates:

• Updated input 'home-manager':
    'github:nix-community/home-manager/ec1a8fdf74ed3f276148ee106299a2ba0e65d51f?narHash=sha256-XL2qfqmocfsvuEGyomZg4nOZfkuSe8vZtrOX99I%2Bb6I%3D' (2026-08-22)
  → 'github:nix-community/home-manager/17903129f47656fa4d07e78ad87f6592ff4f2527?narHash=sha256-voJJ5IZR4w2149u2Jm/j2zifeWROlpZQ%2BJzmCQwjgn8%3D' (2026-09-18)
• Updated input 'lanzaboote/rust-overlay':
    'github:oxalica/rust-overlay/f60c1b57ff805a46b5175c76fc981fb4f81efbcc?narHash=sha256-r4LDUF%2BzmJnkftvCVkCrUhSJazsf6EVJF%2BV2l4/MYbI%3D' (2026-08-23)
  → 'github:oxalica/rust-overlay/8534567325bd8a8d2928e6afd81e0a87d19efd3c?narHash=sha256-9mWUnReOUXfKjZuJAL/bAFH3LUyECTRtXgSNVjRw3UY%3D' (2026-06-21)
• Updated input 'llm-agents':
    'github:numtide/llm-agents.nix/e320800dd9dc2b156bfa77fbeeb00e9e7295f3a9?narHash=sha256-ykJRnaTqcTxPrUTdhVwpd3nLT3p%2BPvitmhbxZbgo5HI%3D' (2026-09-10)
  → 'github:numtide/llm-agents.nix/34081a176242cbccd62f19978f32abfff933813f?narHash=sha256-5QvQZFsM/xcZRVUGuv56QU3d0RQZcqR9axikxGf1KLE%3D' (2026-09-19)
• Updated input 'llm-agents/nixpkgs':
    'github:NixOS/nixpkgs/5052d7ccbcfb7e4ae1586cb2ecf95a2e3707dce9?narHash=sha256-PJCTsE4I20CrJJPcye9/z6brRFysG5%2Baygr/dZK097k%3D' (2026-09-09)
  → 'github:NixOS/nixpkgs/c7def046b9a883d46974757852106483d741586f?narHash=sha256-6RSEDHIWQtesQKWSu5qRai8L2h4KgCgMEfJHstW99G4%3D' (2026-09-14)
• Updated input 'nix-gaming':
    'github:fufexan/nix-gaming/daa997a8979f01a0defcc2065ba824c65bb461f6?narHash=sha256-BXGiZoNdYzfs5ZqsSlSvNvMgcL4%2Bje67BRUoyXY%2Bfjw%3D' (2026-08-23)
  → 'github:fufexan/nix-gaming/5928fa386f57488e918a7d1b282f8daf3e103d02?narHash=sha256-bhzBYZm4whYF6/I7zkS1UxBNSbj5RNVysK6gYzl5weo%3D' (2026-09-18)
• Updated input 'nix-gaming/flake-parts':
    'github:hercules-ci/flake-parts/427bf4bd9435fdf21321c8cc628c24efc14c0f7a?narHash=sha256-4dtXQk/NMePegK/nWp5NSeuZKLATItOq61lpEvmXqGw%3D' (2026-08-01)
  → 'github:hercules-ci/flake-parts/31729ca8cbdb4fa927b34e5f4353e6a83f39e993?narHash=sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU%3D' (2026-09-03)
• Updated input 'nix-gaming/flake-parts/nixpkgs-lib':
    'github:nix-community/nixpkgs.lib/0e79af5e3d4dcfcd676ab5ba3f95d2e3352e078c?narHash=sha256-OmshNvn2vupOFpYinLUu%2B1Dnpu4n7Q5N3ggGVNHpkUI%3D' (2026-07-26)
  → 'github:nix-community/nixpkgs.lib/596e2e3940e09b2abbeb03f75fa1828c57fcd72c?narHash=sha256-DTQSMxzDWmT0zhguthvegnVkn7CFqGCv4IHCzk5ZUpM%3D' (2026-08-30)
• Updated input 'nix-gaming/git-hooks':
    'github:cachix/git-hooks.nix/809414f0cdadf82cf11b06c2b29ba9b3168b3297?narHash=sha256-O2tBn84NNuHrnqNVxx/XqsXwfYvS1YwBh%2B7CBnbCYsk%3D' (2026-08-22)
  → 'github:cachix/git-hooks.nix/27555e2624241fb116b49095df4caaee85a25691?narHash=sha256-nt%2BlUqYVpc9Y6JeMd2WmXzCDojasdadKo0mWcluvY2Y%3D' (2026-09-01)
• Updated input 'nixos-apple-silicon':
    'github:nix-community/nixos-apple-silicon/53798a0eb0fa4c8cfaeca7bdc5b4ad22ed210c95?narHash=sha256-zRPYCn5RJWxr9uyUwNIQjPsTFcIFRwuRnI91dqvGA0k%3D' (2026-08-16)
  → 'github:nix-community/nixos-apple-silicon/57a14ae9be0eaf7bf66e95490ed2d7c6f4bd4c9e?narHash=sha256-QIPbA%2BdtbY6OFeREyisXu/QsrNhT1jNr4DT7rHWKImE%3D' (2026-09-19)
• Updated input 'nixpak':
    'github:nixpak/nixpak/333bd8c7ca0c014e61be1933b3c131c9dfa20218?narHash=sha256-eh6isB4Gt3Wry1fPqRI1qKWySjDbalvaBwToG82jcR4%3D' (2026-07-26)
  → 'github:nixpak/nixpak/853aa37cf5b5ced298752cc644ffb07cabb741bf?narHash=sha256-KwHZMqTRy9OFaT1Z/Lx6jZsPoWXKDS1OXCc80SsmOyk%3D' (2026-09-17)
• Updated input 'nixpak/flake-parts':
    'github:hercules-ci/flake-parts/17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e?narHash=sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w%2B6NWK9yA%3D' (2026-07-01)
  → 'github:hercules-ci/flake-parts/31729ca8cbdb4fa927b34e5f4353e6a83f39e993?narHash=sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU%3D' (2026-09-03)
• Updated input 'nixpak/hercules-ci-effects':
    'github:hercules-ci/hercules-ci-effects/86c7c78a840b44b1a0a5cbc7e9baa0154c0d0f3f?narHash=sha256-vy0EiuiLRKWbXYOqdEKoy5ImlbHcdMC52x9BcC/MwQ8%3D' (2026-06-15)
  → 'github:hercules-ci/hercules-ci-effects/6c58de7236d1cd634deea07bd15d52c7ce470bd3?narHash=sha256-fknJsE4XnFjUfo87T9jyZ15ivJZB/varWvsJMYk0BNY%3D' (2026-09-15)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/2c423e03bbafcff28bfadc6781a4a8257f205cb5?narHash=sha256-dt4WdcvsA8/RCe%2BVZZwqU0X%2BXMM3wBbGCWA0/sFWzGo%3D' (2026-08-22)
  → 'github:nixos/nixpkgs/e554fab72f81915600f3f449b786fd9af40439a5?narHash=sha256-ZKhUe/2IJUq1JhKxKMu8rbkgSGmPP2ZCqlIPn40aGCM%3D' (2026-09-17)
• Updated input 'nixpkgs-blender':
    'github:nixos/nixpkgs/c2c93465e2871183025a30c52d19b6804311526f?narHash=sha256-8cgQR83UlOCuSkmKvOQcHTiRrSknUqTUbnRM7ai4obI%3D' (2026-08-23)
  → 'github:nixos/nixpkgs/20b1ddd1aa5ace70c9468305030aa4f9ef79671b?narHash=sha256-B44WL6h0XoLjJ41bUPJk0X5SDinLCII//6EcBLXKiJ0%3D' (2026-09-19)
• Updated input 'nixpkgs-darwin':
    'github:nixos/nixpkgs/a831408e6378bc02ebf8cc09b52c96ca86f6bab4?narHash=sha256-NcYt9QJfpJiF1lAyN8BDPB4EeScbPU%2BEwQqPiBElrpU%3D' (2026-08-22)
  → 'github:nixos/nixpkgs/a32edd7654519351e48e80372a928df336394670?narHash=sha256-RjR8AyvGlWuw16XRj7C1YDEw4E27ciuyPeB2nDMzgTU%3D' (2026-09-17)
• Updated input 'nixpkgs-master':
    'github:nixos/nixpkgs/c2c93465e2871183025a30c52d19b6804311526f?narHash=sha256-8cgQR83UlOCuSkmKvOQcHTiRrSknUqTUbnRM7ai4obI%3D' (2026-08-23)
  → 'github:nixos/nixpkgs/20b1ddd1aa5ace70c9468305030aa4f9ef79671b?narHash=sha256-B44WL6h0XoLjJ41bUPJk0X5SDinLCII//6EcBLXKiJ0%3D' (2026-09-19)
• Updated input 'nixpkgs-stable':
    'github:nixos/nixpkgs/5880666fd9eb563038431edb35c2d0aa595884e6?narHash=sha256-OURZPknrTjQrlNyxPdqzyqmU/81Wes1CUP/Ft1Rv/YI%3D' (2026-08-20)
  → 'github:nixos/nixpkgs/ecc58f32d1069a3e3f8a991e2233d365689f748d?narHash=sha256-vrwAiXmz%2B0hs/IWXZalFG/Ws6xQRcW%2BgClUDlfvcfjQ%3D' (2026-09-17)
• Updated input 'nixvim':
    'github:nix-community/nixvim/b397fb9f6950d57355d62bb92457d223464e0115?narHash=sha256-Hj/nkhKDv0aJly1PAUstrhrgEYn1mVSkLIYMh90r/Pc%3D' (2026-08-16)
  → 'github:nix-community/nixvim/0043fc97e267fee06ac0d858399ff6fac4242a92?narHash=sha256-JNsVNLux4emA7/BeZYzzAKnBaPnkatpaf/Fwf7PQT4E%3D' (2026-09-13)
• Updated input 'nixvim/flake-parts':
    'github:hercules-ci/flake-parts/427bf4bd9435fdf21321c8cc628c24efc14c0f7a?narHash=sha256-4dtXQk/NMePegK/nWp5NSeuZKLATItOq61lpEvmXqGw%3D' (2026-08-01)
  → 'github:hercules-ci/flake-parts/31729ca8cbdb4fa927b34e5f4353e6a83f39e993?narHash=sha256-glZLQlzIn1fXH6PazR2iUmTo7kzzyYSshrWhLS9TqCU%3D' (2026-09-03)
• Updated input 'pre-commit-hooks':
    'github:cachix/git-hooks.nix/809414f0cdadf82cf11b06c2b29ba9b3168b3297?narHash=sha256-O2tBn84NNuHrnqNVxx/XqsXwfYvS1YwBh%2B7CBnbCYsk%3D' (2026-08-22)
  → 'github:cachix/git-hooks.nix/59f4ca0d063a1a3ec722c88b51a33004862e5379?narHash=sha256-PFD1nxptCXJyJoiYO1gf/5Vv43yqGpHtMC6LUhl9/pQ%3D' (2026-09-15)
2026-09-19 12:28:19 +08:00
Ryan Yin f23d5d4245 docs(monitoring): note dead-man switch and backup freshness TODOs 2026-09-19 12:14:20 +08:00
Ryan Yin a8ea040c32 fix(trash): persist the cleanup timer
trash-empty lacked Persistent=true, so a host that was off or suspended at the scheduled time never ran the purge and trash retention silently stopped.
2026-09-19 12:11:18 +08:00
Ryan Yin 3318103f8a chore(guix): remove the unused Guix integration
Guix was enabled on every desktop host, but shoukei had no /gnu mount (store and state lived on the tmpfs root) and it was not used. Drop the module, the modules.guix option, the @guix subvolume and the /var/guix preservation entry.
2026-09-19 12:11:15 +08:00
Ryan Yin fc8b9e5ba0 chore(aquamarine): disable the broken restic backup
The restic job needs three agenix secrets that do not exist yet (restic-password, ssh-key-for-restic-backup and an rclone config for the smb-downloads remote). Comment it out until they are provisioned so it does not fail silently every night.
2026-09-19 12:11:11 +08:00
Ryan Yin d78f6badd4 fix(aquamarine): repair monitoring config
Load both *.yml and *.yaml alert rule files: the Loki rules were named .yaml while only *.yml was loaded, so they silently never ran. Fix the Grafana domain typo (writefo.fun -> writefor.fun). Comment out the postgres-playground datasource, which used the Grafana admin password for a role that has no password and could never authenticate.
2026-09-19 12:11:07 +08:00
Ryan Yin ff961c1bc9 fix(flake): make the eval-tests check a derivation
checks.<system>.eval-tests returned a boolean, so nix flake check failed with "not a derivation". Wrap the evalTests result in a runCommand so flake check actually evaluates it.
2026-09-19 12:11:03 +08:00
Ryan Yin e7f984745b fix(home): autostart Chrome on aarch64 Linux 2026-09-19 09:51:08 +08:00
Ryan Yin 501c6af220 chore(agents): remove rtk integration
RTK compresses only shell output and independent evaluations show little to no end-to-end cost reduction. Drop the package and its install snippets; runtime artifacts were uninstalled separately.
2026-09-19 09:47:52 +08:00