Commit Graph
2885 Commits
Author SHA1 Message Date
Ryan Yin d7c493f5cd chore(agents): drop the dsh-nu plugin
dsh-nu replaced every shell command with Nushell and refused bash/pwsh
syntax before it spawned; in practice the refusals were too noisy. Drop
the flake input, install plain dsh, and remove the docs describing the
Nushell-only shell.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-05 11:46:03 +08:00
Ryan Yin dfa53c71d7 fix(nix): take NUR packages from ryan4yin.cachix.org
58d1af8f dropped the cache while adding the pull-through caches. Without
it a NUR bump rebuilds its npm deps here, and dsh's npmDepsFetcherVersion
2 fixed output includes the packuments the Huawei npm mirror rewrites, so
the build fails NUR's hash check instead of reusing its CI-built output.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-05 11:45:51 +08:00
Ryan Yin 706ec235ee chore(nur): update nur-ryan4yin
dsh 0.2.2-alpha.2 -> 0.2.2-rc.1 and computer-use-linux 0.7.36 ->
0.7.37; cua-driver stays 0.38.0. The nur-packages diff is version bumps
plus regenerated dsh lockfile only, with no module or overlay changes.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-05 09:49:49 +08:00
Ryan Yin c4a00e507c fix(nixpak): pass the session TZ through to sandboxes
ICU takes the zone name from the /etc/localtime symlink target path. A bind
mount turns it into a plain file, which keeps the TZif data but loses the
path, so the only identifier left is the ambiguous "CST" abbreviation that
ICU reads from the file and maps to America/Chicago.

Export TZ from time.timeZone and pass TZ/TZDIR through the nixpak env
allowlist.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-04 21:38:18 +08:00
ryan4yin | 二花 13d95daa36 fix(remote-builders): serve x86_64 only, drop aquamarine binfmt (#517)
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-04 17:28:30 +08:00
ryan4yin | 二花 71fa928254 feat(canokey): sudo, SSH, LUKS and OpenPGP setup for daily use (#516)
Use the CanoKey for daily authentication on idols-ai and shoukei, with
the existing passwords, passphrases and per-host SSH keys as fallback.

- sudo: pam_u2f with a shared origin (pam://ryan4yin) and a Nix-store
  authfile built from myvars.canokeyU2fKeys; the primary key is
  registered and touch-to-sudo works on idols-ai.
- SSH: one resident ed25519-sk key (application=ssh:ryan4yin) exported
  to ~/.ssh/id_ed25519_sk; GitHub tries it before the per-host key.
- shoukei LUKS: fido2-device=auto with token-timeout=10s. Update
  nixos-apple-silicon (linux-asahi 7.2.14), whose initrd adds
  thunderbolt_apple and reset_apple_cio so USB-C comes up before unlock.
- GPG: scdaemon disable-ccid so it uses pcscd.
- docs/security-keys.md: setup, PINs, enrollment, backup key and
  recovery; deduplicate the FIDO notes left by #515.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-04 01:50:21 -06:00
ryan4yin | 二花 2cf3a58028 feat(nixpak): pass FIDO2 keys to Firefox, Chromium and Chrome (#515)
* feat(nixpak): pass FIDO2 keys to Firefox, Chromium and Chrome

Assisted-by: DeepSeek Harness (deepseek-flash)

* feat(nixpak): support FIDO2 hotplug via udev-maintained node directory

Replace launch-time hidraw discovery with host udev rules that hard-link
FIDO-tagged hidraw nodes into /dev/fido-hidraw and remove them on unplug.
The sandbox dev-binds that directory and gets static /dev/hidrawN symlinks
into it, so keys plugged in after launch work and no stale node survives a
reused hidraw minor.

Narrow the extra mounts from whole /sys and /run/udev to /sys/class/hidraw,
/run/udev/data and /run/udev/control; the policy suite now forbids the
broad mounts and checks the wrapper and bind follow the fido2 option.

Assisted-by: Claude Code (claude-opus-5-5)

* refactor(nixpak): rewrite FIDO2 bwrap wrapper in Python

The bash argument loop was hard to follow. Python inserts the /dev/hidrawN
symlinks before "--" with a single list splice, and the header now explains
the whole host-udev -> bind -> symlink chain step by step.

Assisted-by: Claude Code (claude-opus-5-5)

* docs(canokey): document phone-only management policy

PCs only use the CanoKey; CanoKey Console management stays in the phone
app and the Admin PIN is never typed on a PC. Record what the config
enforces (sandboxed browsers get no raw USB/CCID, no vendor WebUSB udev
rule) and what it does not (uaccess on the raw USB node, PC/SC access to
the Admin applet, CTAP management from browsers).

Assisted-by: Claude Code (claude-opus-5-5)

* docs(canokey): separate management from use, link CanoKey docs

Assisted-by: Claude Code (claude-opus-5-5)

* fix(nixpak): create /dev/fido-hidraw from the udev rule

NixOS applies /dev tmpfiles entries only at boot; switch-to-configuration
runs systemd-tmpfiles-resetup with --exclude-prefix=/dev. After a switch
without reboot the directory was missing and every `ln` failed with exit
code 1, so no browser saw the key. The add rule now runs `mkdir -p` first.

Also fix the documented trigger command: `udevadm trigger` defaults to
`change`, which the add-only rule ignores.

Assisted-by: Claude Code (claude-opus-5-5)

* refactor(nixpak): keep tmpfiles as the only creator of /dev/fido-hidraw

The /dev tmpfiles units run before systemd-udevd on every boot, so the
directory always exists before coldplug. The mkdir in the udev rule only
covered the first switch without reboot and duplicated the tmpfiles rule;
drop it and document the one-time `systemd-tmpfiles --prefix` command.

Assisted-by: Claude Code (claude-opus-5-5)

* docs(nixpak): record FIDO2 hardware validation in Firefox and Chrome

After a reboot on ai with the CanoKey present at boot, udev linked only
the FIDO interface and WebAuthn works in Firefox and Chrome. Chromium and
plugging the key in after launch remain pending.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-04 13:38:32 +08:00
Ryan Yin 432de26764 feat(agents): add Qwen Code and use OpenCode V2 as opencode
Expose llm-agents' opencode2 package under the normal opencode command and persist Qwen Code's ~/.qwen state on the ephemeral-root hosts.
2026-11-04 00:15:43 +08:00
Ryan Yin 99b0208a2a fix(aquamarine): persist raft state
Preserve ~/.raft across reboots so Raft Computer keeps its enrollment, machine identity, agent state and app data. ~/.local/bin and ~/.config/gh were already persisted.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-03 23:50:45 +08:00
ryan4yin | 二花 ff7102d75b feat(agents): align ruby and kana computer-use support (#514)
* feat(agents): align ruby and kana computer-use support

Assisted-by: DeepSeek Harness (deepseek-flash)

* test(agents): keep one full-host test for ruby and kana

Both guests run the same agent configuration, so a second full-host test
does not add coverage.

Assisted-by: DeepSeek Harness (deepseek-flash)

* fix(computer-use): disable cua-driver telemetry before start

The i3 init hook did not reliably disable the default-on setting, so both
hosts could start the daemon with telemetry enabled.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-03 23:08:51 +08:00
ryan4yin | 二花 d8b298019a refactor(shells): use native Home Manager Nushell and Nushell login on non-desktop hosts (#513)
* 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)
2026-11-03 22:31:24 +08:00
Ryan Yin e3bc8cbe4c chore(nur): update nur-ryan4yin
Update nur-ryan4yin to d82be0b. Audit: only the prebuilt packages cua-driver (0.36.0 -> 0.38.0) and computer-use-linux (0.7.20 -> 0.7.36) changed; the NUR modules and trust-related settings did not move. Only the kana and ruby system closures change.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-03 20:49:06 +08:00
Ryan Yin c4c75a2d8d fix(npm): use the Huawei npm mirror
Only Huawei works with prefetch-npm-deps: npmmirror 404s on its doubled
slash, and Tencent answers 567 to its concurrent fetches (WA-049).

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-03 20:02:39 +08:00
ryan4yin | 二花 9a307b313d refactor: host profiles; give ruby, kana and aquamarine the TUI home (#512)
- 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)
2026-11-03 04:57:06 -06:00
ryan4yin | 二花 eb6f6c34f0 chore(gaming): inline the nix-gaming tunables and drop the input (#511)
Assisted-by: Claude Code (claude-opus-5-5)
2026-11-03 14:49:25 +08:00
Ryan Yin 4470b3d014 docs: centralize documentation under docs/
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)
v0.20.0
2026-11-02 17:48:57 +08:00
ryan4yin | 二花 be3e27c49b feat(homelab): enable Wake-on-LAN on the mini PCs (#509) 2026-11-02 15:36:29 +08:00
ryan4yin | 二花 7ea9fd3197 feat(ipython): add data helpers without persisted history (#510)
Add a dedicated IPython module with startup helpers for JSON, YAML, TOML, and CSV plus a small set of common standard-library imports for interactive use.

Disable SQLite history and stop preserving ~/.ipython: interactive sessions can contain credentials and other sensitive data, so that profile state must not survive reboots implicitly.

Assisted-by: DeepSeek Harness 0.2.2-alpha.2 (deepseek-flash)
2026-11-02 14:45:20 +08:00
Ryan Yin 179b20a42c fonts: add Japanese and Korean locale fallbacks
Keep SC as the default and select JP/KR glyphs for lang=ja/ko.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-02 12:06:29 +08:00
Ryan Yin f9ece8167d fonts: prefer Noto CJK family names
Noto CJK and Source Han share the same glyphs; Noto names are more common in Linux.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-11-02 11:45:12 +08:00
Ryan Yin 1193e20cf0 docs: remove completed C4 cleanup card 2026-11-02 11:16:27 +08:00
ryan4yin | 二花 c384073469 fix(ai): reapply the OpenRGB profile after resume (#508)
The Mystic Light controller drops its LED state on S3 resume without
re-enumerating, so no udev event fires and openrgb.service keeps running
without reloading the profile. Reapply it from a unit ordered after
suspend.target, through the running server.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-02 10:57:41 +08:00
Ryan Yin 0f5ad1ad10 fix(aquamarine): socket-activate whisper-asr with FreeBind
At boot whisper-asr could start before the LAN address was configured and
fail with "could not bind on any address". Let whisper-asr.socket bind it
with FreeBind and have uvicorn take fd 3, like the exporters.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin c732f3b9bb refactor(vr): route headset audio with a WirePlumber hook
A default-node hook selects wivrn.sink/wivrn.source whenever they exist,
so the polling wivrn-audio.nu unit, its saved state and `just vr-audio`
go away. Streams follow via linking.follow-default-target.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin be592ae75c refactor(mihomo): link geodata from nixpkgs instead of seeding it by hand
`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)
2026-11-01 11:55:14 -06:00
Ryan Yin c8bbeb708d refactor(overlays): get NUR packages from the nur-ryan4yin overlay
myNurPkgs evaluated a second nixpkgs just for four packages. Apply the
NUR repo's own overlay instead, so they come from the host's pkgs.

Darwin's pkgs now gets nixpkgsConfig too: it set nixpkgs.pkgs, which
ignores nixpkgs.config, so only myNurPkgs carried the npm mirror there.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin 70d8bd6791 refactor(shoukei): drop dead nettle and qemu-user static overlays
Both only touch pkgsStatic builds, which nothing on this host pulls in
since qemu-user binfmt was removed; the toplevel drvPath is unchanged.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin 6ea53e8dd7 refactor(darwin): decrypt agenix secrets to /etc/agenix via path
agenix's darwin module honours age.secrets.<name>.path and applies owner and
mode itself, so the environment.etc links and the postActivation chown/chmod
that re-applied them go away.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin 3789a2a282 chore(nixos): guard the nix and xdg-desktop-portal-wlr pins at eval time
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)
2026-11-01 11:55:14 -06:00
Ryan Yin eaa53004e5 fix(aquamarine): install only clr's OpenCL ICD instead of the openvino-gpu wrapper
hardware.amdgpu.opencl.enable also adds clr, whose OpenCL 2.2 libOpenCL.so.1
lands in /run/opengl-driver/lib, first in OpenVINO's RUNPATH, and shadows the
ocl-icd loader the GPU plugin links. With clr.icd alone the plugin finds
ocl-icd, so the wrapper and WA-038 go.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin fe280d8fa2 refactor(ssh): drop no-op openFirewall
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)
2026-11-01 11:55:14 -06:00
Ryan Yin 04a8438bd3 refactor(canokey): rely on systemd uaccess rules instead of custom udev
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)
2026-11-01 11:55:14 -06:00
Ryan Yin 4ecb7c475e fix(git): back up a stray ~/.gitconfig after writeBoundary
Move it aside with HM's `run mv` (dry-run aware) instead of an
unconditional rm before checkLinkTargets.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:55:14 -06:00
Ryan Yin ce49b03014 fix(monitoring): socket-activate LAN exporters with FreeBind
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)
2026-11-01 11:55:14 -06:00
Ryan Yin b063feca29 chore(youko): drop victoriametrics' leftover data-dir group
The data dir is the module's own DynamicUser StateDirectory (already
/var/lib/victoriametrics -> private/victoriametrics on youko), so the
victoriametrics-data group, its tmpfiles rule and SupplementaryGroups
did nothing. stateDir was set to its default.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 64c465660c refactor(youko): create the /data-ro mountpoints in initrd tmpfiles
Root is tmpfs, so the backing dirs must exist before the /data bind
mounts. initrd tmpfiles rules on /sysroot do that before switch-root,
replacing the activation script.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 6fa6e6626e refactor(youko): run homepage from the native NixOS module
services.homepage-dashboard runs the nixpkgs package with DynamicUser,
replacing the :latest container, its system user and the activation
script that rsynced the YAML into place. The YAML stays as is and is
linked into /etc/homepage-dashboard.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin c8d8b17a27 refactor(youko): link caddy's wallpapers with tmpfiles
A tmpfiles L+ symlink to the store path replaces the activation script
that rsynced it on every switch. Files that were removed upstream no
longer linger.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 5c9bb6f95f chore(shoryu): drop the libvirt default-network oneshot
NixOS's libvirtd-config copies default.xml but never creates its
autostart link, and shoryu has no networks/autostart directory at all,
so virbr0 never starts and the oneshot had nothing to disable.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin f520c992d5 refactor(youko): order transmission-netns after the br0 device
Replace the 30 s `ip link show br0` poll with BindsTo/After on
sys-subsystem-net-devices-br0.device.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 8d32297dcd refactor(ai): reset the Insta360 Link on resume via a usbcore quirk
USB_QUIRK_RESET_RESUME ("b") makes usbcore reset the camera instead of
resuming it, and uvcvideo implements reset_resume, so the resume hook
that ran usbreset after S3 is no longer needed.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 8084f25e6f refactor(youko): disable HDD spindown from a udev rule
Apply hdparm -B 255 -S 0 whenever a disk appears, which also covers the
re-add after a bridge reset, instead of a boot oneshot plus an hourly
timer. Drop -J 0: hdparm has always aborted it without
--please-destroy-my-drive, and wdidle3 already reads disabled on both
disks (it is persistent firmware state).

This was the last user of mylib.systemdHardening.privilegedOneshot, so
remove the preset and its test group.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin f8ca25a03b refactor(power-monitoring): grant RAPL read access from a udev rule
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)
2026-11-01 11:42:57 -06:00
Ryan Yin 42341491f3 refactor(shoukei): cap battery charging from a udev rule
macsmc-battery's "add" uevent fires before the supply accepts writes
(power_supply_register bumps use_cnt after device_add); its deferred
register work then emits "change". Match both instead of polling for 30 s
from a oneshot.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin ecf242d6ab refactor(aquamarine): cap the R9700 power limit from a udev rule
amdgpu registers power1_cap with its hwmon device, so a rule on each
card's hwmon add event replaces the oneshot that polled /sys/class/hwmon
for 60 s waiting for both cards to probe.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 11:42:57 -06:00
Ryan Yin 2036b97f85 docs(workarounds): put WA-048 back in the table
It was wrapped across lines after a blank line, so it rendered as a
paragraph. Text unchanged.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:51:51 -06:00
Ryan Yin 7c0b5fc0b8 fix(mihomo): keep the proxy up when the resolved hook times out
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)
2026-11-01 10:51:51 -06:00
Ryan Yin 201070155a fix(homepage): drop the weather providers block that never worked
A 2024 formatter pass turned `{{…}}` into a YAML flow map, the variable
was never passed to the container, and no widget uses it.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:51:51 -06:00
Ryan Yin 8b22aec1bb fix(restic): drop a stale btrfs snapshot before taking a new one
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)
2026-11-01 10:51:51 -06:00
Ryan Yin 32620ed9db chore(aquamarine): drop pcie_aspm=off
It was a precaution for the R9700 links, never an observed problem, and
on BIOS 1013 the FADT already disables ASPM ("ACPI FADT declares the
system doesn't support PCIe ASPM"), so the parameter did nothing.

Assisted-by: Claude Code (claude-opus-5-5)
2026-11-01 10:51:51 -06:00