Give `river` a dedicated RDMA VF and two RSTP trunk attachments.
Keep client services on the router VIPs and carry Digiweb VLANs
over both switch paths.
Set VF trust, multicast reception, bridge MAC and ARP behavior for
local switching. Wait for Kea interface readiness and apply RSTP
costs through `mstpd` despite port-registration and rename races.
Load `palace`'s RAID module in the initrd. Record RouterOS and
RouterBOOT upgrades and validate port, carrier and switch outages.
Document the deployed architecture, interface handoffs and recovery
procedures. Add physical socket maps, NIC capacities and cable
connections alongside the logical topology and failover checks.
Use the supported PCI layout for released DPDK 26.03, matching the
upstream fix in SPDK 26.05. Otherwise SPDK 26.01 selects an older
layout and crashes during PCI scanning.
Wraps `go-grip` to preview docs in the browser before pushing,
rendered locally with live reload. Defaults to `docs/README.md`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream v1.4.5 moves the effort level into parentheses after the
model name.
Also read the CLI version from the `version` field Claude Code passes
on stdin instead of caching `claude --version` for an hour, which kept
showing the old version after an upgrade. `claude --version` remains
as an uncached fallback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cache all deploy node connection settings and invalidate them when
HEAD or tracked working-tree contents change. Preserve SSH argument
boundaries and support explicit refreshes.
Configure the Numtide substituter and signing key in the shared cache
settings and flake configuration so Codex can use prebuilt binaries.
Document the cache and retain the input’s tested nixpkgs pin.
Pass `--accept-flake-config` explicitly because `doas` drops the
devshell configuration that enables it. This avoids prompts for the
flake’s binary cache settings when rebuilding as root.
Only set `programs.codex.mutableSettings` when Home Manager exposes it.
This fixes evaluation on 26.05, including boxes with the GUI disabled.
Record the removal TODO and guidance for future compatibility guards.
Move Git, Git LFS and `diff-so-fancy` into the common home module.
Enable Jujutsu with the same identity and add it to the devshell.
Document `jj` workflows and prefer them in Jujutsu workspaces.
Pin Codex independently through `llm-agents.nix` and update unstable
home-manager for `programs.codex.mutableSettings`.
Declare the status line, including both usage windows, while preserving
imperative settings during activation.
Pin the community image and start simpland3 while retaining
simpland2. Correct the server-files volume name and reuse the
admin ID in both access lists.
Explicitly remove expired generations from the nonstandard Harmonia
profile before collecting garbage. This keeps old CI closures from
remaining rooted until the cache exhausts its inodes.
Firefox can exhaust swap while `MemAvailable` remains above the unload threshold. Track new `pswpout` pages so active swapping triggers tab unloading without treating stale swap occupancy as permanent pressure.
Rebase the fork branches and refresh nixpkgs, home-manager, and the
approved ancillary inputs. Update kernel and release metadata, adapt
removed package and Home Assistant options, and keep Determinate Nix
on its tested nixpkgs revision to avoid duplicate Boost patches.
Retire Sharry and its public endpoint because copyparty replaces it.
Document the GitHub mirror gate and require real devshell and system
builds in the upgrade validation workflow.
Pin `openwrt-feeds` to repository state that includes vendored APK
indexes, keeping image builds independent of mutable upstream indexes.
Document the corresponding refresh workflow.
Move the skill to the shared agent location while retaining Claude
compatibility. Document kernel refreshes and the release metadata
policy as part of each upgrade, and make commit-message wrapping
explicit and verifiable.
Router-sized 4096-entry rings on every port with GRO kept across
forwarding, the IOMMU in passthrough mode, and EEE pinned off on the
I226-V ports as one trigger for their link-drop erratum. The ring and
GRO settings are .link files, so they land on a device add event rather
than at switch time.
Also document the tuning deliberately not done -- coalescing and PCIe
ASPM -- and what measuring the NICs' ESP offload found, since the
esp4_offload modules are software batching and easy to mistake for it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
esp4_offload/esp6_offload provide GSO/GRO batching for ESP and are not
autoloaded when an SA is created, costing around a third of the mesh's
encrypted throughput. Load the one matching each secured mesh's
underlay family.
Also document the per-SA single-core limit and pcrypt as an option.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lan-lo is a VLAN on et100g, which carries hi's jumbo frames, so it
inherited 9000 rather than the 1500 the lo VLAN runs at. MSS clamping
hid this from TCP; UDP without working PMTUD was silently dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Keep logically distinct changes in separate commits" was being read as
split anything separable, which turns one piece of work into several
commits that only make sense read together.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
portcullis is wired over 10G to fergal, which uplinks to jim's spare
SFP+ port. That uplink is untagged VLAN 1, so hi is carried tagged on a
lan-hi VLAN interface: a static assignment at 192.168.68.41 / ::6:1,
resolving through the router VIPs like any other hi client. Its gateway
route outranks the DHCP default, making 10G the preferred path while the
2.5G bootstrap stays as a fallback. Deploy now targets that address.
The hi MTU goes on the .network rather than the .link, since a .link is
only applied at udev device-add -- with it there, et10g-0 stays at 1500
across a switch and lan-hi cannot take 9000.
jim's sfp-spare was tagged into hi and lo out of band to match.
fergal turns out to belong with portcullis rather than to the home
fabric -- it goes to Nikhef when the box does -- so its documentation
moves to the colony site, leaving home/switches.md a short section on
what it borrows from that fabric.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By is the only trailer wanted here; session links are not.
Also spell out that bodies should stay concise.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fergal is an 8-port SFP+ switch on a Realtek RTL9303, running OpenWrt
rather than RouterOS or UniFi. It is not part of the fabric yet, but
its firmware is now built here via astro's nix-openwrt-imagebuilder.
Packages are baked into the image: OpenWrt's package server keeps only
the current build of each feed, so installing at runtime stops working
as soon as the feed moves past the running firmware.
Those feed indexes rotate constantly, and upstream pins only the
indexes -- a mismatch drops evaluation into import-from-derivation,
putting this flake's eval on the network. The openwrt-feeds input pins
expanded per-package hashes instead, in a repository of its own
because they run to hundreds of thousands of generated lines.
Flashing gets a procedure doc and a thin skill pointing at it, the
same split as the box installation and nixpkgs upgrade procedures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Canonical, agent-agnostic procedure for bringing a new box into the
flake, from a booted installer through to a deployable system, plus a
thin Claude Code skill pointing at it -- same split as the nixpkgs
upgrade procedure.
Records the conventions that were not written down anywhere: sgdisk
plus an LVM PV for the nix and persist volumes, adopting the
installer's SSH host keys so secrets can be encrypted before first
boot, and taking whatever show-hw-config emits that the flake's own
modules do not already set.
Also notes in AGENTS.md that a changed recipient list should be
re-encrypted per file with ragenix --rekey-one; --rekey rewrites every
secret in secrets/ and buries the actual change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New bare-metal box headed for Nikhef, intended to take over most of
estuary's colony edge routing. This is the bootstrap config only: the
hardware, the single-NVMe ESP + LVM layout, and enough networking to
boot and be reachable.
It is being staged at home before it is racked, so it has no colony
assignments yet. Every 2.5G port takes DHCP and whichever one is
patched in brings the box up; kea registers the DHCP hostname, so the
deploy node points at portcullis.dyn.h.nul.ie until there is a real
colony FQDN for it.
The host key was adopted from the installer session and seeded onto
the persist volume before first boot, so my.secrets.key could be set
up front -- which makes portcullis a recipient of the user-passwd
secret that my.user declares for every box.
Documented with a box page, a row in the colony site index, and a note
in the colony section of networking.md that the topology is expected
to change once portcullis takes over from estuary.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`netboot-update` failed with an opaque curl usage error whenever the
`installer` tag advanced past a build that had not published assets:
the `jq` select found no matching asset, and the empty result was
passed straight to `curl` as the URL. Report the missing asset (and
an unresolvable tag) instead.
The unit also had its network dependency inverted, being `wantedBy`
network-online.target rather than wanting and ordering after it. Fix
the idiom and keep it in the boot transaction via multi-user.target.
On river that is not enough on its own, because the WAN is a pppd
interface that networkd's wait-online knows nothing about, so
network-online.target is reached well before there is a route
off-site. Gate the service on wan-online.target there, following the
same wantedBy + partOf idiom as ipsec, which also re-runs the fetch
whenever the link returns.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`release-action` is archived; its repository points at
`gitea-release-action` as the replacement. The inputs were renamed
(`api_key` -> `token`, `title` -> `name`).
The new action is a Node one rather than Go, so the Go setup step
kept in the previous commit is no longer needed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gitea writes uploaded release assets to a temp file before storing
them. That landed in `/tmp`, which is on the 2G tmpfs root, so
uploading the installer ISO failed with:
ParseMultipartForm [E] ... write /tmp/multipart-...: no space
left on device
Point the service's `TMPDIR` at the state volume, which has room.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The installer workflow had not been touched since 2024 and missed
both the Ubuntu 26.04 runner bump and the move to Determinate Nix as
the common Nix. Bring it in line with `ci.yaml`.
The Go setup step stays: it supports the Gitea release action rather
than the Nix build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`boot.initrd.systemd.extraConfig` was removed upstream and now fails
an assertion, which broke the `netbootArchive` target and with it the
second build step of the installer release workflow. Move the two
timeout settings to `settings.Manager`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The ISO target had drifted from nixpkgs and no longer evaluated:
`iso-image.nix` now defines `image.baseName` itself, which conflicts
with ours, so force it.
Drop the `boot.initrd.systemd.enable = false` override from the
`asISO` build target. The missing `/dev/root` it worked around is no
longer an issue, and scripted initrd is deprecated for removal in
26.11.
Replace the wpa_supplicant stanza, which upstream's
`installation-device.nix` no longer carries, with NetworkManager.
Keep it out of `multi-user.target` so nothing network-related starts
until asked; NetworkManager enables wpa_supplicant as its backend,
which is D-Bus activated on demand.
Pick up three more bits from that profile: the installer
`variant_id`, the pstore drop-in that stops an install evacuating the
target's persistent entries, and the mdadm `PROGRAM` stub that
silences the unset-mail warning.
Built and booted as an ISO to confirm.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Some headsets alternate play and pause events independently of the
actual player state. Treat either event as a toggle so an out-of-sync
event is not a no-op.