`dsh-llm-pi-ai` registers its built-in providers once, so a second instance
in the profile patch fails on mount with `provider "..." is already declared`.
Extend the base `llm-pi-ai` row instead.
dsh rewrites a profile's cordis.patch.yml at runtime, so linking the web
profile put GUI state in the checkout and let runtime writes clobber manual
edits. Link the stable policy as the $DSH_HOME home layer instead: dsh applies
it after every profile and only reads it.
The host-plane compaction-basic row is disabled on the web surface and each
agent preset owns its own copy, so the top-level override was inert. Drop it;
the model contextWindow/maxTokens are the effective knobs.
- add home/base/tui/agents/dsh/cordis.patch.yml, linked from default.nix
- drop the ~/.dsh/profiles/web link and the tracked web/ profile
- keep runtime state and private/local model routes in the profile patch
- update the eval test and README
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.
Explicit session action lists replace the built-in defaults, so re-declare all
five actions; lock stays immediate, logout/suspend/reboot/shutdown arm a 10 s
countdown that a second press runs immediately.
QT_QPA_PLATFORMTHEME=gtk3 (from #386) made Qt derive its color scheme
from GTK3, which has no dynamic dark/light signal, so Telegram and other Qt
apps were stuck on the light palette after Noctalia's theme mode changed.
Use the portal theme instead: Qt then follows
org.gnome.desktop.interface color-scheme, which Noctalia writes. The trade-off
is Qt's built-in "Sans Serif" 9pt font, which a font-providing platform theme
would be needed to change.
go-musicfox posts its own desktop notification on every track change and both popups sit at bottom_right, so the media OSD was a second, redundant popup.
* feat(rime): share the Rime config and user dictionary across Linux and macOS
Move the Rime data, preferences, and user dictionary into home/base/gui/rime so fcitx5-rime and Squirrel read the same files.
* feat(vinput): open the command palette with right Ctrl
Pin keyd's right-hand modifiers (rightcontrol/rightshift/rightmeta) to their own keycodes; keyd otherwise folds them into the left keys. Set Vinput's MenuKey to right Ctrl and clear CommandKeys, which would shadow it.
* feat(fcitx5): switch CN/EN with Ctrl+Space and right Shift
Clear AltTriggerKeys, whose Shift_L default toggled on left Shift. Left Shift is now a plain modifier and right Shift switches through the shared Rime config.
Clear AltTriggerKeys, whose Shift_L default toggled on left Shift. Left Shift is now a plain modifier and right Shift switches through the shared Rime config.
Pin keyd's right-hand modifiers (rightcontrol/rightshift/rightmeta) to their own keycodes; keyd otherwise folds them into the left keys. Set Vinput's MenuKey to right Ctrl and clear CommandKeys, which would shadow it.
* fix(desktop): align Qt app fonts with GTK
Qt apps kept their built-in default font ("Sans Serif" 9) while GTK apps use
`gtk-font-name` (Noto Sans 11), so Telegram and other Qt apps rendered
noticeably smaller than GTK apps like Firefox. Set
QT_QPA_PLATFORMTHEME=gtk3; the plugin ships with qtbase, so it needs no
extra package and also gives Qt apps GTK file dialogs.
* chore(desktop): drop unused Xft.dpi from the Wayland GTK profile
Xft.dpi/ *.dpi are X11 X-resource settings. This file is only imported by
the niri (Wayland) hosts, where xwayland-satellite sets its own Xft.dpi
(96 x output scale, currently 144), and the i3 hosts are headless 1080p
computer-use sessions that do not import it. So the setting had no effect
anywhere; remove it instead of keeping a misleading knob.
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)
metacubexd hardcodes its tab title in the SPA, so dashboards on
different hosts are indistinguishable. Patch the static <title> and
re-apply the hostname from config.js, since Nuxt's useHead resets
document.title on every route change.
The config deliberately stays out of the store, under the home directory, which is a persistent bind mount on tmpfs-root hosts. When the service and the mount are introduced in the same activation, mihomo can start before the mount is up and fail with "Failed to set up credentials: No such file or directory", making the switch report status 4. Add RequiresMountsFor so the mount is brought up and ordered before the service.
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.
* 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>
The cherry-picked openvino 2026.4.1 bump (upstream PR #564046, still
unmerged) made onnxruntime 1.27.1 fail its OpenVINO EP MatMulNBits
numerical test, breaking sherpa-onnx and the ai-niri system build.
The fork branch now stays at upstream openvino 2026.4.0.
Restore the rule dropped in 9822dafa: keep GitHub Git remotes on SSH, make sure the Nix-managed ~/.ssh/config is used, and rerun outside the sandbox when it is rejected.
Move the flypy schema data to the rime-data-flypy package in
ryan4yin/nur-packages and keep only the personal user dictionary
(flypy_user.txt) here. The overlay merges the NUR data with that file
and exposes the result as pkgs.rime-data, fcitx5-rime's rimeDataPkgs,
and pkgs.flypy-squirrel.
* refactor: consume computer-use packages from NUR
* fix: expose flake inputs to package overlays
Package overlays are imported from two places with different argument
shapes: outputs/default.nix passes a set containing `inputs`, while
modules/base/overlays.nix passes the NixOS module args, where genSpecialArgs
spreads each flake input as a top-level argument. The new NUR-backed
overlays read `inputs.nur-ryan4yin`, so evaluation failed on the module
path. Also expose the whole flake input set as `inputs` in genSpecialArgs.
* chore: bump nur-ryan4yin input
Update the locked nur-packages revision to the current main (nixpkgs
26.05, unused packages removed).
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.
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.
node_exporter listened on 0.0.0.0, so access control rested entirely on
the nftables allowlist. Bind node/smartctl exporters to the host static
LAN IPv4 (the same address VictoriaMetrics scrapes), keeping the socket
off tailscale/bridge interfaces even if the firewall regresses.
Hosts without a static LAN address (shoukei, akane) now run no exporters
at all instead of loopback-bound ones nobody scrapes; akane, a UTM VM,
previously ran a loopback smartctl exporter with no physical disks.
LAN-bound exporters also get the boot-race treatment from #372
(network-online ordering plus patient restart); loopback-bound hosts
must not pull in network-online because NM wait-online would stall
their offline boots.
The exporter binds to the host LAN address, which systemd-networkd
assigns during boot. Without ordering, the service starts before the
address exists, `bind: cannot assign requested address` trips the
start limit, and the unit stays failed until restarted manually.
Order the unit after network-online.target, and since wait-online is
best-effort (120s timeout), also retry patiently so the unit self-heals
when the link comes up late.
The optional kernel reboot-visibility change was closed without merging, so remove the planned-reporter wording. Replace it with the manual booted-vs-selected kernel check and update the P1 TODO accordingly.
Add SECURITY.md covering the threat model, trust boundaries,
proportionate kernel/process hardening, the update/reboot routine and
remaining prioritized work. Record the dated read-only audit findings
(listeners, privileged workloads, effective RBAC, secret metadata and
sandbox/SSH boundaries) separately from planned controls and runtime
verification.
Define agent-first diagnosis: scoped root read-only access on homelab
hosts, and normal-user diagnostics on core desktops with no new sudo
grants. Add canonical domain-based k3s API endpoint regression tests,
record the unverified Darwin secret-ownership concern as WA-015, and
correct comments claiming mode 0000 blocks privileged root.
muvm is disabled because it does not build/run on nixos-apple-silicon yet, not because of a permanent hardware limitation; the 16k page size is the reason it is wanted, and the removal condition is muvm building and working.