Commit Graph
217 Commits
Author SHA1 Message Date
Ryan Yin a8d47e30cf fix(ai): pin the 4K monitor at 144 Hz and record the OSD wake workaround
The DPMS wake failure is the monitor no-signal auto power-off (HPD cycling during idle), not the refresh rate: the 120 Hz pin did not fix it. Disabled in the OSD and recorded as WA-041; pin 144.000 explicitly so niri stops silently falling back.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 13:56:01 +08:00
Ryan Yin 169a87f3b9 fix(ai): pin the 4K monitor to its real 120 Hz mode
The 4090 reports the panel 120 Hz mode as 119.880, not 120, so niri fell back to 144 Hz; that DSC link stays dark after a DPMS wake.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-21 12:03:40 +08:00
ryan4yin | 二花 d5fac4bcce fix(ai): bound niri's NVIDIA free-buffer pool (#477)
* fix(ai): bound niri's NVIDIA free-buffer pool

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)

* docs(ai): trim the niri VRAM workaround comment

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-19 01:15:54 +08:00
Ryan Yin 2a792a643f fix(ai): reclaim page cache before the desktop's anon pages
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-18 22:05:03 +08:00
Ryan Yin 35ae8732c3 fix(preservation): keep EasyEffects state across reboots
EasyEffects 8 keeps its KConfig settings database plus user presets, autoload
profiles and imported models under $HOME, which the tmpfs root drops on
reboot; bind-mount both directories from /persistent.

Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-flash)
2026-10-18 21:42:52 +08:00
ryan4yin | 二花 d6450d48a2 feat(remote-builders): build ai and shoukei on aquamarine (#467)
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)
2026-10-17 00:49:22 +08:00
Ryan Yin e42d7adc88 chore(ai,aquamarine): shrink the swapfile to 32G
disko creates the swapfile only when it formats the pool, so the live 96G files
keep their size until they are recreated with btrfs filesystem mkswapfile; that
frees 64G per host.

Assisted-by: DeepSeek Harness 0.2.0-rc.2 (deepseek-flash)
2026-10-16 21:18:33 +08:00
Ryan Yin 789b230780 chore: drop conda from the Linux and macOS profiles
Assisted-by: DeepSeek Harness 0.2.0-rc.2 (deepseek-flash)
2026-10-16 21:18:33 +08:00
ryan4yin | 二花 a0ff9f7fd7 fix(ssh,ai): keep connections to idle LAN peers fast (#463)
* fix(ssh): retry and multiplex LAN connections
* fix(ai): shrink the neighbour-probe fallback to ~1s

Assisted-by: DeepSeek Harness 0.2.0-rc.2 (deepseek-flash)
2026-10-16 20:07:19 +08:00
ryan4yin | 二花 3266aad4a2 fix(power): drop TuneD for native CPU scaling (#461) 2026-10-16 16:45:08 +08:00
ryan4yin | 二花 b4b293ebfa fix(power): pin the tuned profile per host, cap the VM hosts (#458)
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-16 00:42:48 +08:00
ryan4yin | 二花 bebe5bcf42 feat(ai,aquamarine): expose board fans and temperatures via SuperIO (#456)
* feat(ai): load nct6683 for the board's NCT6687D SuperIO
* feat(aquamarine): load nct6775 for the board's NCT6798D SuperIO

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-15 23:58:23 +08:00
Ryan Yin 47dabbf55e docs(ai): drop the tracker links from the monitor and ARGB comments
Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-15 22:29:16 +08:00
Ryan Yin 7eb5ac5017 feat(ai): add OpenRGB control for the board ARGB
Enabling the module runs `openrgb --server` at boot and installs its udev rules,
so the GUI and the CLI reach the MSI controller without root.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-15 22:25:24 +08:00
Ryan Yin b3700b1d9f feat(ai): control external monitors over DDC/CI
The module loads i2c-dev and grants /dev/i2c-* to the i2c group and locally
logged-in users, so ddcutil no longer needs root.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-15 22:25:24 +08:00
ryan4yin | 二花 e8819de40c feat(vinput): own the config here and read keys from the environment (#445)
* feat(vinput): read provider keys from an EnvironmentFile
* feat(vinput): manage the config from this repository
2026-10-15 13:54:20 +08:00
Ryan Yin 55b7741108 refactor(ai): return ai to the MSI MAG B760M MORTAR and the RTX 4090
The second NVMe and its LUKS volume leave with the Z890 board, so the data-disk disko module is deleted; `ai` must activate this change before the disk is pulled, or its initrd blocks on the missing volume.

Assisted-by: DeepSeek Harness (deepseek-flash)
2026-10-14 20:15:01 +08:00
ryan4yin | 二花 9c38819517 docs: review and correct comments and documentation (#436) 2026-10-12 10:02:38 +08:00
ryan4yin | 二花 5c5c11d646 docs(idols-ai): record the mixed-memory freeze and current state (#433)
Assisted-by: DeepSeek Harness (gpt-6.1-sol, deepseek-flash)
2026-10-11 20:13:06 +08:00
ryan4yin | 二花 3e66bbf24f feat(hosts): add WiVRn CLI streaming for Quest 3 #392 2026-10-10 22:49:48 +08:00
Ryan Yin 0041afc2e7 fix(hosts): drop the legacy ctx7 preservation entry
The ctx7 login still lives in the old directory; activation without moving it loses the login.

Assisted-by: DeepSeek Harness (qwen3.8-flash-iq3s-text)
2026-10-10 19:58:33 +08:00
Ryan Yin 7b21ea5adb feat(agents): rewrite find-docs onto the nixpkgs ctx7 CLI
Assisted-by: DeepSeek Harness (claude-opus-5-5, deepseek-flash, qwen3.8-flash-next iq3)
2026-10-10 19:49:44 +08:00
Ryan Yin 3b2c328fd2 docs(idols-ai): mark the mixed-memory settings as daily-use verified 2026-10-10 07:19:45 +08:00
ryan4yin | 二花 0e12440148 refactor(secrets): move nushell-secrets.nu out of agenix (#423) 2026-10-09 22:40:50 +08:00
ryan4yin | 二花 63b7183381 feat(mihomo): keep unproxiable ranges out of TUN, fix the startup DNS race (#419)
* feat(mihomo): keep ranges that can never be proxied out of TUN

The list lives in policy.yaml as tun_exclude_address; sources.yaml may override
it. 198.18.0.0/15 stays in TUN: that is the fake-ip range itself.

* feat(mihomo): match Valve's content servers by ASN

The 20 hand-copied prefixes had drifted from what AS32590 announces. The rule
type needs GeoLite2-ASN.mmdb, so geox-url.asn points at the same mirror.

* feat(mihomo): render the gateway config from the same sources

The hand-kept copy had drifted: a manual sync carried the desktop's secret onto
the gateway and dropped external-ui-url. --redact yields a shareable template.

* fix(mihomo): open the link DNS takeover only once the core serves it

The core opens :1053 after parsing rules, and rule parsing is where missing
geodata gets fetched. Flipping at fork time made that fetch SERVFAIL, the config
fatal, and the unit unstartable.

* fix(justfile): keep local endpoints out of the agent proxy

With only HTTP_PROXY set, a request to this host's own llama-swap endpoint went
to mihomo. Node matches exact hosts only, so the literals carry it; the CIDRs
serve curl and Go.

* feat(justfile): seed mihomo geodata into the service state dir

So a cold start never needs the download that the DNS takeover made unstartable.
2026-10-09 12:31:59 +08:00
Ryan Yin fe302fa950 docs(idols-ai): record overnight mixed-memory voltage tests 2026-10-09 07:44:51 +08:00
Ryan Yin 841214c325 docs(idols-ai): summarize mixed-memory voltage tests
Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>
2026-10-09 00:30:15 +08:00
ryan4yin | 二花 48ac4f76bf fix(tuios): keep sessions across reboots and split them by purpose (#416) 2026-10-08 20:29:52 +08:00
ryan4yin | 二花 9e2633f496 feat(gaming): generic umu game installer, skill, and desktop entries (#411) 2026-10-08 14:59:11 +08:00
ryan4yin | 二花 5f6a1dadf4 docs: fix stale claims and AI-flavored prose (#397) 2026-10-07 14:48:36 +08:00
ryan4yin | 二花 95b849420e feat(gaming): declarative Proton and dGPU game rendering (#393) 2026-10-07 13:14:42 +08:00
Ryan Yin a7cc474a50 docs(hosts): update the idols-ai memory notes for 1.28 V
The bring-up runs at the default 1.25 V; afterwards Gear mode is set to
Gear2 and VDD/VDDQ are raised to 1.28 V, changing nothing else. 1.29 V and
up do not train. Also record that the 1.25 V config passed stressapptest
but still hard-froze under a real llama.cpp load, so a passing test is not
proof of stability.
2026-10-07 07:38:52 +08:00
Ryan Yin a091fe1aca docs(hosts): refresh the ai screenshots and correct its hardware notes
- replace the btop screenshot with the 2026-10-06 annotated capture
  (btop + fastfetch + the strata/llama.cpp serving logs); the old
  2026-10-01 file is gone, so the README link moves to the new name
- drop the Helix/AI-agents screenshot and its README reference
- fix stale hardware descriptions: the hosts/README.md inventory row and
  the idols-ai header comment still said i5-13600KF, and the zswap pool
  comment sized its percentages against the old 96G of RAM (now 128G)
- record the hardware history: the platform was rebuilt on 2026-04-27
  (PR #257/#258) onto the Colorful CVN Z890 ARK FROZEN + Core Ultra 7
  270K Plus, replacing the MSI board and i5-13600KF the host was added
  with in 2023-05; the 2x48G kit predates that rebuild, the 2x16G kit
  was added 2026-10-06
- make the DIMM bring-up order mandatory and record its failure mode:
  with the 48G pair in first, or all four DIMMs from the start, the
  board does not POST
- gloss the Chinese BIOS labels in English, marked as translations of
  the labels rather than the firmware's own English wording

Left alone on purpose: the 96G swapfile in hosts/idols-ai/disko-fs.nix.
It was grown from 20G to 1x-RAM on 2026-10-02 (a26ab3be), when the host
still had 96G; resizing it again means re-running disko on the machine,
so that stays a separate decision.
2026-10-06 22:32:34 +08:00
ryan4yin | 二花 e653ec3306 docs(hosts): add mixed-memory notes for idols-ai (#391)
Document the 4-DIMM kit mix (2×48G JUHOR + 2×16G GLOWY) on the Colorful
CVN Z890 ARK FROZEN V20:

- hardware (CPU, board, and both kits)
- the install order that trains (16G pair first)
- the only stable settings (XMP off, DDR5-4800 @ 1.25 V)
- the stress-test recipe and results
- the XMP @ 5600 failure and how to recover a board that will not POST
- re-enrolling the LUKS TPM unlock after a BIOS change
2026-10-06 21:39:23 +08:00
Ryan Yin 87e87aad7d fix(agents): perserve dsh data 2026-10-06 17:00:01 +08:00
Ryan Yin 975d2668a8 feat(idols-ai): back up the dsh state directory (~/.dsh) with restic
dsh keeps its session transcripts, workspace storages, and profiles in
DSH_HOME=~/.dsh, which was outside the backup allowlist. Exclude its
.credentials.yaml like the module's other credential paths.
2026-10-05 23:46:04 +08:00
ryan4yin | 二花 6b8c5bfae4 feat(vinput): drop NPU/OpenVINO support (#384)
Vinput's streaming Zipformer models have unbounded dynamic shapes, so
OpenVINO cannot compile them for the GPU or the NPU; the `openvino`
provider and ai's Intel NPU enablement could never run on the NPU (noted
as unverified in WORKAROUNDS WA-017). Remove the backend option, the
daemon's OpenVINO library path, and the intel-npu module enable, and
update the eval test, README and WORKAROUNDS (drop WA-016 and WA-017).

Keep Vinput's stock package and its bundled sherpa-onnx (1.13.4): the
fork-based and nixpkgs-master sherpa overrides existed only to provide the
`openvino` provider, so drop package.nix with them.

Assisted-by: opencode (DeepSeek V4.1 Flash)
2026-10-05 15:42:48 +08:00
ryan4yin | 二花 502d0c85c7 fix(preservation): keep vinput config and models across reboots (#381)
Vinput stores its core config in ~/.config/vinput/config.json and its
downloaded sherpa-onnx models in ~/.local/share/vinput/models/. Neither
was bind-mounted from /persistent on the tmpfs-root hosts, so a reboot
wiped both and vinput-daemon started with "Local ASR provider model is
not configured". Persist both directories and document the one-shot CLI
model setup in the vinput README.
2026-10-05 00:18:01 +08:00
ryan4yin | 二花 8f0961d9c2 fix(desktop): tie ai's link DNS takeover to mihomo's lifecycle (#380)
* fix(desktop): tie ai's link DNS takeover to mihomo's lifecycle

sing-tun normally points systemd-resolved at the TUN DNS by running
resolvectl (dns/domain/default-route). Under nixpkgs' hardened
DynamicUser mihomo unit that hand-off fails silently: the unit's
RestrictAddressFamilies blocks resolvectl's D-Bus socket and resolve1
requires privileged authorization, so resolved keeps querying the
physical-link DNS, fake-ip is bypassed, and domain rules degrade to
MATCH.

Do the hand-off as '+' ExecStartPost/ExecStopPost hooks instead: '+'
commands run outside the sandbox (systemd.exec: address-family
restrictions do not apply to them) and ExecStopPost reverts even on
crashes, so a dead mihomo leaves DNS usable.

Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>

* docs(mihomo): record sing-tun's resolvectl hand-off as the leak cause

Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>

* refactor(desktop): keep mihomo only on ai and shoukei

ruby/kana never ran the core (service inactive live), and their
resolved + TUN combo would reintroduce the resolver leak once enabled.
Drop the enable and the explicit module import from computer-use; the
eval test now pins mihomo=false for both guests.

---------

Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>
2026-10-05 00:07:32 +08:00
ryan4yin | 二花 bbfe1fa53b feat(desktop): replace Clash Verge with native mihomo on all NixOS hosts (#379) 2026-10-04 21:04:41 +08:00
Ryan Yin a695a3ce3d feat(vinput): add NPU speech input on ai 2026-10-04 19:51:22 +08:00
Ryan Yin bf193e4082 chore(agents): drop the kimi-code CLI
Kimi Code moved its desktop client into an internal repository in July 2026 (MoonshotAI/kimi-code#1849), so the polished surface is no longer open source; the CLI that stays behind overlaps opencode2 and pi. Removing it drops one more redundant harness.
2026-10-04 12:52:50 +08:00
Ryan Yin 349fe7f5cf chore(agents): drop the oh-my-pi (omp) CLI
oh-my-pi is a feature-complete superset of pi, so its role is already covered: opencode2 for a batteries-included harness, pi for the minimal/local-model one. Keeping it meant maintaining two nearly identical harnesses.
2026-10-04 12:39:08 +08:00
ryan4yin | 二花 2ee0b9c7eb chore(tui): remove standalone herdr, superseded by tuios (#374) 2026-10-04 11:23:16 +08:00
ryan4yin | 二花 3a5b9ec4c6 docs: README audit fixes and de-duplication (#371) 2026-10-03 18:28:58 +08:00
ryan4yin | 二花 6a1b4c699a chore(docs): prune stale TODOs (#370) 2026-10-03 17:50:28 +08:00
ryan4yin | 二花 d056aece28 chore(workarounds): re-evaluate stale hardware/kernel fixes (#360)
* chore(workarounds): re-evaluate stale hardware/kernel fixes

Prune workarounds whose root cause is gone, fix one vendor typo, and
document the ones we keep:

- drop `transparent_hugepage=madvise` on shoryu/shushou/youko: it was tied to
  the old fixed 1G hugetlb pool, and the VMs now use ordinary memory
- shoryu: `hardware.cpu.intel.updateMicrocode` -> `amd` (it is an AMD APU)
- ai: drop `i915.enable_guc=3` (GuC/HuC submission is the default on modern
  i915/Xe)
- kernel-hardening: name the Dirty Frag CVEs (CVE-2026-43284 / CVE-2026-43500)
  and the re-evaluation condition
- document re-eval conditions for the Insta360 resume fix, the darwin
  auto-optimise-store workaround, and the youko USB-SATA bridge mitigations

* chore(workarounds): keep the Dirty Frag module blacklist as defence in depth

* chore(ai): correct the i915.enable_guc rationale (verified against the kernel)

* chore(darwin): drop the auto-optimise-store workaround (nix#7273 fixed)
2026-10-03 11:25:34 +08:00
ryan4yin | 二花 dc3ec8c159 feat(storage): relax ai NVMe workarounds and add drive SMART monitoring (#359)
* fix(ai): relax NVMe power-management workarounds and enable smartd

Logs show no NVMe errors, so allow APST again (capped at 100 ms), restore
the default io_timeout, and drop pcie_aspm=off. Add smartd for drive
health visibility.

* feat(storage): add drive/SSD SMART monitoring on physical hosts

node_exporter's nvme collector only exposes node_nvme_info and namespace
capacity, not SMART health, so SSD wear/lifespan and drive temperature were
not observable anywhere.

- enable services.prometheus.exporters.smartctl on physical hosts, gated on
  modules.hardwareTools (off on QEMU/MicroVM guests), bound to the host's LAN
  address on port 9633
- firewall: drop 9633 from anything but the monitoring host
- youko: scrape smartctl-<host> for the physical hosts
- alert rules (storage.yml): SMART health, NVMe wear, available spare, media
  errors, critical warning, and drive temperature (warn 70 / crit 80 C)
- Grafana dashboard "Drive SMART (smartctl)"
2026-10-03 11:13:46 +08:00
Ryan Yin d9208f492b fix(preservation): keep logrotate state in a persisted directory 2026-10-03 09:42:14 +08:00
ryan4yin | 二花 9254b63a18 chore(idols-ai): move tmp state off RAM onto btrfs and harden tmp mounts (#348)
* feat(idols-ai): persist /var/tmp and small state dirs, wipe /var/tmp at boot

Move the strata model staging area (~3G) off the root tmpfs onto the
persistent btrfs volume to free RAM, preserve btrbk/cups/logrotate
state, and wipe /var/tmp at boot so it only accumulates between
reboots.

* chore(idols-ai): add nosuid,nodev to root tmpfs and tmp btrfs mounts

Hardens /, /tmp and /snapshots; safe because /dev, /run, /nix and
/run/setuid-programs are separate mounts, so nothing there needs suid
bits or device nodes.

* chore(idols-ai): add noatime to the @tmp btrfs mount

Temp files do not need access times; matches the @nix subvolume style
and saves btrfs metadata writes.

* chore(idols-ai): harden the /var/tmp bind mount with nosuid,nodev

World-writable staging data should not honor suid bits or device
nodes, same as /tmp and /snapshots.

* fix(idols-ai): preserve logrotate state as a file, fix persisted dir ownership

- /var/lib/logrotate.status is a regular file, not a directory: move it from
  preservation directories to files. A missing state entry makes logrotate
  treat every log as freshly rotated, so it must survive reboots.
- keep /var/lib/btrbk owned by btrbk:btrbk 0750 so preservation does not
  override the btrbk module's rule with root:root.
- set /var/tmp mode 1777 explicitly instead of relying on systemd's tmp.conf
  ordering.
- rewrite comments to describe the paths generically.

* chore(idols-ai): cap journal, wipe coredumps at boot, persist upower/noctalia

- services.journald.settings.Journal: SystemMaxUse=10G, RuntimeMaxUse=256M,
  matching the cap already set on idols-kana/idols-ruby.
- wipe /var/lib/systemd/coredump at boot: it lives in the persisted
  /var/lib/systemd and crash dumps can contain secrets copied from memory.
- persist /var/lib/upower (device battery history) and
  ~/.local/state/noctalia (shell settings, notification/clipboard history).
2026-10-02 21:58:21 +08:00