* chore(aquamarine): take the NPU stack from nixos-unstable-small
* refactor(aquamarine): load the NPU driver via hardware.cpu.intel.npu
Assisted-by: DeepSeek Harness (claude-opus-5-5)
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)
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)
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)
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.
NixOS copies mode-carrying /etc entries such as authorized_keys.d during
stage-2 activation, which runs before systemd starts. preservation mounted the
persisted /etc/ssh from preservation.target afterwards and hid that copy, so a
key change only took effect on `switch`: revoking a key and rebooting silently
restored the old one.
Prepare the mount in initrd, before activation runs, and cover it with a VM
test that seeds a stale authorized_keys file, reboots, and asserts the declared
key replaced it. The same test fails on that assertion with inInitrd disabled.
Verified on all four hosts: /persistent/etc/ssh/authorized_keys.d/root is now
rewritten at boot instead of keeping the timestamp of the last switch.
Assisted-by: Claude Code (claude-opus-5-5)
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)
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)
Colmena deployments now ship the same toplevel as nixosConfigurations: nodes gain the nixpkgs
registry, nixPath and dated version, and akane no longer gets the x86_64 dsh.
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (claude-opus-5-5)
* feat(agents): use the shell's own dialect; allow 5 s retry backoff
Assisted-by: DeepSeek Harness (deepseek-flash)
* feat(dsh): make Nushell the only shell
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): wait for CI in the background
Pushes to a PR often start multi-minute CI runs, and an agent that holds
the turn open on a foreground watch reports nothing until it ends. Require
the pushed head and running checks to be reported first, the watch to run
in the background, and the result to be collected after independent work
or after ending the turn.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): keep the shell-handoff rule platform-neutral
The global rules carry no Windows assumptions: drop the cmd, pwsh, and
wsl handoff examples and keep the POSIX forms plus the dsh refusal.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(dsh): keep the shell-swap docs POSIX-only
This repository manages Linux and Darwin hosts, not Windows: drop the
Windows handoff examples and terminal-backend wording from dsh.md. The home
patch also disabled pwsh-sandbox redundantly because dsh-base already
disables that row on POSIX; keep only the active bash-sandbox disable and
verify the composed rows with --dump-config.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): keep the global rules runtime-neutral
Global rules are loaded by every agent CLI, so they must not describe one
runtime's behavior. Drop the dsh-specific sentence and wording while keeping
the expectation to prefer Nushell structured pipelines and Python. Runtime
behavior stays documented in home/base/tui/agents/dsh.md.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): default shell work to Nushell
Keep the Nushell preference explicit in the runtime-neutral global rules, and
keep runtime behavior in runtime docs. Bash stays a narrow fallback for tasks
Nushell cannot do.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): tighten global-rule scope and CI guidance
Keep global rules runtime- and project-neutral, and state that boundary in the
file. Remove the duplicated CI turn-steering text in favour of the Communication
rule, resolve the watch run before watching instead of relying on
gh pr checks --watch alone, name the working-directory parameter generically,
and distinguish a bounded retry backoff from a fixed completion wait.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): never estimate a CI run's duration
A CI run has no predictable length, so do not turn "it looks short" into a
reason to wait. The rule is unconditional: report the head and started checks,
start a background watch, and end the turn; collect the result on completion.
The eval scenario now uses an unknown duration.
Assisted-by: DeepSeek Harness (deepseek-flash)
* docs(agents): move maintenance guidance to the README
The runtime/project boundary is guidance for editing the rules, not a rule
agents need loaded every session. The README's Maintaining global rules
section already owns that audience; the loaded rules keep only behavior.
Assisted-by: DeepSeek Harness (deepseek-flash)
* refactor(dsh): render the home patch from a YAML template
Move the home-layer cordis patch into dsh-cordis.patch.yml, substitute the
bundle and Nushell store paths with replaceVars, and link the rendered file
through home.file.source. This module is the only writer of
~/.dsh/cordis.patch.yml, the current host has no such file, and the profile
patch is a separate layer.
Assisted-by: DeepSeek Harness (deepseek-flash)
* refactor(dsh): install the shell plugin through NUR withPlugins
Replace the local runCommand bundle, peer symlink, and home-layer YAML file
with the plugin package and dsh.withPlugins from ryan4yin/nur-packages#43. The
package wrapper adds a generated --patch overlay after the profile layer, so
dsh no longer writes or manages ~/.dsh/cordis.patch.yml. The NUR input is
temporarily pinned to the PR branch and its commit; point it back at main once
the NUR PR merges.
Assisted-by: DeepSeek Harness (deepseek-flash)
* refactor(nix): expose the NUR package set as nurPkgs
Pass one per-system NUR package set through specialArgs instead of repeating
nur-ryan4yin.packages.${pkgs.stdenv.hostPlatform.system} at each call site.
The agents, rime, and idols-ruby modules now use the short binding.
Assisted-by: DeepSeek Harness (deepseek-flash)
* refactor(nix): use nurPkgs in package overlays
The overlays receive specialArgs too, so they can use the per-system NUR
package set instead of rebuilding the long input path from prev. This leaves
only the definition in outputs/default.nix.
Assisted-by: DeepSeek Harness (deepseek-flash)
* refactor(nix): name the per-system NUR set myNurPkgs
Leave room for consuming another NUR repository later, and match the existing
mylib/myvars naming.
Assisted-by: DeepSeek Harness (deepseek-flash)
* chore(dsh): consume the merged NUR package set
nur-ryan4yin now points at main after ryan4yin/nur-packages#43 was squash
merged; the lock records the merge commit. No branch ref remains.
Assisted-by: DeepSeek Harness (deepseek-flash)
* fix(dsh): pass the web profile explicitly
The withPlugins launcher prepends --patch, which historically prevented dsh
from auto-expanding "dsh web" into "--profile web". Pass the profile
explicitly in the Just recipe and the verification commands so they work with
both plain dsh and the wrapper.
Assisted-by: DeepSeek Harness (deepseek-flash)
* chore(dsh): pick up the wrapped-profile fix
Update nur-ryan4yin to the squash merge that keeps an implicit profile name
first, so "dsh web" and "just dsh-web" work through the wrapper again.
Assisted-by: DeepSeek Harness (deepseek-flash)
* chore(dsh): pick up the plugin peer-link fix
Update nur-ryan4yin to the squash merge that links the dsh peer tree at
node_modules/@deepseek-ai instead of nesting it one level deeper. This is the
import failure that stopped nushell-executor from activating after deploy.
Assisted-by: DeepSeek Harness (deepseek-flash)
The goal is speech recognition on the NPU for vinput, and sherpa-onnx cannot
deliver it: every model it loads keeps a dynamic time axis, which the NPU
compiler rejects outright. Qwen3-ASR and SenseVoice both core-dumped in
vpux-compiler ("Got non broadcastable dimensions pair"), and reshaping the ONNX
inputs does not help because the dynamic dimensions sit inside the graph
(WA-037). Whisper is the only family OpenVINO publishes fully static IRs for,
and its fixed 30 s window is exactly what the compiler accepts.
The host now runs an OpenAI-compatible /v1/audio/transcriptions service backed
by whisper-large-v3-turbo int8 on the NPU: 1.5 s for 11 s of audio against
2.1 s on CPU, with the compiled graph cached in /var/cache so only a cold cache
pays the ~60 s NPU compile. vinput on the desktop sends raw PCM to it through a
small provider script.
Only the NPU driver and compiler still come from the unmerged branch in the
`nixpkgs-npu` input (NixOS/nixpkgs#570230), whose nixpkgs also happens to be
the one where openvino-genai 2026.4.0.0 builds at all.
Assisted-by: DeepSeek Harness 0.2.1-rc.2 (deepseek-v4.1-flash)
Every remaining pkgs-x64 consumer runs only on x86_64-linux hosts, where the
native pkgs already carries the same allowUnfree config
(modules/nixos/base/nix.nix) and overlays (modules/base/overlays.nix), so
replace the references with pkgs and drop the extra nixpkgs instantiation
(which also removes an eval on aarch64-darwin).
media.nix keeps the native Zoom app on x86_64 hosts only, since zoom-us has
no aarch64 Linux build.
* 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).
* fix(colmena): expose colmenaHive for the new evaluator
nixpkgs now ships the nix-community Colmena rewrite, whose default
evaluator reads an evaluated colmenaHive flake output instead of the raw
colmena hive. Without it every colmena apply recipe failed with
"does not provide attribute colmenaHive".
Add a colmena input pinned to the same v0.5.0 as nixpkgs and expose
colmenaHive = colmena.lib.makeHive <raw hive>, with the raw hive kept as
an internal binding rather than a flake output of its own.
* chore: clean up stale colmena and aquamarine references
- point the Colmena links at nix-community/colmena after the move
- rename the security-aquamarine-metrics test to youko-metrics (it
already tested youko) and update the outputs README
- drop the commented aquamarine remote-builder example
nixpkgs-blender tracked the nixpkgs master branch, so every `just up` re-bumped it and started a full Blender/CUDA source rebuild even though Blender stayed at 5.2.2 LTS. Pin it to a fixed rev so bumps are deliberate.
The OIDN cmake override is obsolete: nixpkgs#545542 made setupCudaHook add nvcc to CUDAToolkit_ROOT, fixing the CMake 4.3+ split-root failure (nixpkgs#544701). Dropping it also stops Blender's derivation from depending on nixpkgs-stable.
Deploy RustFS in place of the retired MinIO and move the S3 consumers over.
- flake.nix / flake.lock / outputs/default.nix: add a nixpkgs-small
(nixos-unstable-small) input for the rustfs 1.0.0 package (with the web
console), instantiated as pkgs-small in genSpecialArgs alongside the other
nixpkgs instances; drop the rustfs flake input. The rest of the system stays
on the default nixpkgs.
- hosts/12kingdoms-youko/homelab-services/rustfs.nix: use nixpkgs' own
services.rustfs module, with package = pkgs-small.rustfs and
environmentFile = the agenix rustfs.env secret.
- caddy.nix: s3.writefor.fun (S3 API) and s3-console.writefor.fun (console,
redirects / to /rustfs/console/).
- secrets/nixos.nix: declare a single rustfs.env (dotenv) secret holding
RUSTFS_ACCESS_KEY / RUSTFS_SECRET_KEY, replacing the separate key files.
- infra/minio -> infra/rustfs: buckets are managed with the hashicorp/aws
provider against the RustFS S3 endpoint; IAM/ILM are applied with rc.
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.
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.
* feat: comment out nixpkgs-unstable, we use unstable by default
Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>
* fix: typo...
---------
Signed-off-by: Ryan Yin <xiaoyin_c@qq.com>