Build opencode's config.json with pkgs.formats.json instead of shipping
a static file, pinning each formatter command to its store-path binary
via lib.getExe. Drops the standalone config/opencode/config.json.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add formatter entries for nix, prettier (md/yaml/json/web), shell,
python, toml and lua, and install the matching tools via the opencode
home module so they are available wherever opencode runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Serve only Qwen3.6-27B; remove the unused 35B-A3B preset.
Tuning:
- Move model-specific keys (spec-type, sampling temp/top-p/top-k/min-p)
out of the [*] defaults into [Qwen3.6-27B] so they no longer leak onto
other models; draft-mtp in particular only works on MTP-weighted models.
- Drop the duplicate parallel key from [*].
- Bump ubatch-size 256 -> 512 for faster iGPU prefill on Strix Halo.
- Add threads-batch = 16 to use all cores for prefill while keeping
generation at threads = 8 under full GPU offload.
Resolves the URL through the Odesli public API (api.song.link) and
replies with the canonical song.link page plus per-platform deep links
(Spotify, Apple Music, YouTube/YT Music, Tidal, Deezer, Amazon Music,
SoundCloud). Country is pinned to DE.
Preload Qwen3.6-27B and Qwen3.6-35B-A3B at startup (load-on-startup)
so both are warm immediately under --models-max 2, set parallel = 1
as the [*] fallback for any other model, and adjust per-model context
size and draft depth.
Replace the per-model llama-server units with a single service that
uses llama-server's --models-preset (models.ini) and --models-max 2,
so the 35B-A3B and 27B models are loaded on demand from one config.
Drop the now-redundant 27B / 27B-MTP / coder-next variant files and
the unused CacheDirectory + slot-save-path KV-slot handling.
A skeptical PR review skill that defaults to REJECT. Encodes the
staff-engineer adversarial stance: lead with problems, assume bugs
exist, require severity+location+fix+test per finding, mandate an
execution trace, and end with an explicit verdict.
Includes base-branch detection (gh pr view → upstream → heuristic →
ask) so the review never silently diffs against the wrong base.
Apple's built-in ssh-agent has no sk-api/libfido2 support and refuses
signing operations for ed25519-sk / ecdsa-sk hardware keys. Enable the
existing metacfg.security.ssh module (which runs pkgs.openssh's
ssh-agent under launchd) via the common darwin suite, and export
SSH_AUTH_SOCK from environment.shellInit so bash, zsh, and fish (via
/etc/fish/foreign-env/shellInit) all point at the nix-managed socket.
Add obsidian-skills as a flake input (flake = false) and map each
skill subdirectory into ~/.agents/skills/<skill>, alongside the
existing local skills. Updates flow through `nix flake update
obsidian-skills`.
- harald@sgx-nixos: orphan, no matching NixOS system and no
home.stateVersion set, so it failed standalone evaluation
- harald@sgx-azure: referenced metacfg.tools.direnv.enable but no
modules/home/tools/direnv exists, causing eval failure
New metacfg.cli-apps.js module (enabled by default) pins minimum
release ages for npm and bun across all home configurations, so the
mitigation against newly published malicious packages applies
uniformly rather than living as untracked dotfiles on one machine.
The bot no longer shells out to `opencode run`. Instead it POSTs to the
OpenAI-compatible /chat/completions endpoint exposed by llama-server on
halo.hoyer.tail:8000 directly. This removes the Bun/sqlite cold-start
overhead per request, drops the pkgs.opencode runtime dependency, and
eliminates the ExecStartPre dance that materialized config.json into the
service's $HOME.
Conversation history is now stored as a proper OpenAI `messages` list
with system/user/assistant roles, instead of the XML blob that was
inlined into a single `opencode run` argument. The interactive opencode
setup (config/opencode/config.json) is unchanged — only the bot stops
depending on it.
The module gains a `modelBaseUrl` option; `model` is now the bare model
name (`halo-8000`) without the provider/ prefix that the opencode CLI
required.
Vendors the npm tarball + lockfile and wraps the `pi` binary with `fd` and
`ripgrep` on PATH. Also installs it on the m4 darwin host.
`buildNpmPackage` is pulled from `inputs.unstable` because nixos-25.11's
`prefetch-npm-deps-0.1.0` panics on cacache index entries that contain
either multiple lines or JSON values with embedded spaces (npm's
`accept: application/...; q=1.0, ...` headers). For this lockfile,
`@esbuild/netbsd-arm64` and `@rollup/rollup-linux-x64-musl` trigger
both conditions and `--map-cache` fails with `EOF while parsing a
string at line 1 column 369`. Fixed upstream in nixos-unstable, which
now uses `lines()` + `split_once('\t')`.
Mirrors the existing nextcloud-claude-bot setup but invokes `opencode run`
against the local `halo-8000` provider/model. The bot listens on
127.0.0.1:8086, is exposed via the `/_opencode-bot/` location on
nc.hoyer.xyz, and uses `@Halo` as its mention trigger in group chats.
The opencode config (config/opencode/config.json) is installed into the
service's $HOME/.config/opencode/ on each start, so the bot picks up the
same provider definition the user uses interactively. The model map keys
are renamed to `halo-8000` / `halo-8001` so the canonical
`provider/model` reference works without an alias indirection.
tailscale set is strict about boolean flags and silently ignores
--advertise-exit-node without =true. Result: the tailscaled-set unit
ran cleanly but AdvertiseRoutes stayed null. Spell the value out so the
flag takes effect.
Disable rxrpc, kafs, af_key, esp4, esp6 across all systems that enable
metacfg.base. None of them are used on these hosts, and they have a
history of CVEs — blacklisting reduces kernel attack surface.
Introduces a headscale ACL policy (file-mode) plus matching client config:
- New systems/x86_64-linux/attic/headscale-policy.hujson:
* tag:llm restricts a node to talking only to halo:8000
* all other harald@ nodes have full mesh access to each other
* harald@ nodes can route internet traffic via approved exit nodes
* autoApprovers.exitNode = [tag:llm] auto-approves the exit route
advertised by any tag:llm node (currently mx)
- attic headscale.nix: wire policy.mode = "file" / policy.path to
the .hujson above.
- mx default.nix: enable useRoutingFeatures = "server" (needed for IP
forwarding) and add extraSetFlags = ["--advertise-exit-node"] so the
flag is reapplied on every activation, not just initial login.
Operational steps after deploy:
headscale nodes tag -i 10 -t tag:llm