An Arch/Hyprland desktop that is built and running, and a NixOS/niri laptop that is specced with early phases landing. This deck adopts each machine's real palette as you move through it, the colors are transcribed from the running hosts.
One is dark, neon, and glowing. One is light, quiet, and Nordic. Two machines, two vibes.
←→ to move through swipe to move through
both machines are real; screenshots pending
Both machines have exactly one source of truth for color, and everything downstream is generated from it. They only differ on which direction the arrow points.
The split isn't only cosmetic. It's also about what you can safely change, what you can roll back, and whether "the config" is a thing you edit or a thing you produce.
In other words, both run (very) different distros. The name says it all: the
archbox runs an Arch-based distro, while the
nixbox is on NixOS.
-- archbox
~/.config/hypr/colors.lua
# nixbox
modules/palette.nix Same instinct, solved twice: one palette can't do every job. Full neon everywhere is fine until you have to read it all day.
Archbox splits by function. Vivid Cyberdream for chrome you glance at: borders, lock screen, bar accents. Softer TokyoNight Storm for anything you read for an hour: terminal, Neovim, the Qt apps whose lists you scan.
Nixbox splits by time. Snow Storm by day, Polar Night after dusk, both prebuilt as variants and swapped without a rebuild.
The two archbox palettes agree on the color doing most of
the work: the Cyberdream cyan and TokyoNight's teal sit 4 degrees apart in hue.
Only the pink and green were orphans, and both were replaced with the terminal's own
values. The bases stay deliberately mismatched, so the terminal reads as lifted and
floating rather than flush with the wallpaper.
The one that's finished, at least as much as anything ever is. Built for throughput and glow, on hardware that doesn't need to apologize (or hang) for a compositor effect.
The deck just changed palette. Everything from here is TokyoNight Storm, the palette the desktop uses for surfaces you read.
Chrome is glanced at; a terminal is stared into. Full-saturation neon works for a border you register in peripheral vision, but wrong for a buffer you scan for an hour. The transition you just watched is the argument; your eyes should be telling you the difference.
# reading surfaces only
bg #24283b
bg_dark #1f2335
fg #c0caf5
comment #565f89
blue #7aa2f7 -- link
teal #2ac3de -- selection values transcribed from colors.lua · M.tn
It's dotstack a homegrown system that takes components, package lists, harnesses, sync scripts, and skills that keep a snapshot of a live workstation.
The arrow points up. You change the running machine, and the sync pulls that change into the repo as a described component rather than a captured blob. Restore runs the same components in the other direction.
components/ per-app install + restore units
config/ tracked dotfiles
lib/ shared shell harness
markers/ what is managed, and by whom
packages/ explicit package sets
restore-all the other direction Four files carry the palette's hex values and cannot read the Lua table — a GLSL shader, a SCSS file, a daemon's JSON, and the Lua itself. check-colors.sh greps all four and exits non-zero if they've drifted. Duplication you can't remove is duplication you test.
Several models and harnesses maintain these machines. Deciding which one gets which job might start on vibes, but should build evidence that converges on what's ideal in which harness for what situation. Enter a recent project: the Orchestration Logs.
Every orchestration session also creates a dated note with re-runnable evidence: a command,
a grep, a file:line. Opinions don't survive distillation. The
entries are sorted by what actually failed, which is the field that earns
the log its keep:
The tally is the punchline. Across 43 logged entries, harness and provider problems outnumber model problems roughly two to one — most "the AI failed" moments were plumbing.
A tale of trying to debug constant black screens, perseverance, and a little (a lot of) help from my friends (/agents). Provided as an example of a day in the Linux driver life.
GSP_RM_CONTROL. That's the GPU system
processor's resource-manager control channel, not a graphics submission. nixbox · gen 36 · 2026-08-17
No video wallpaper. No heavy blur. UHD 620 will render a compositor beautifully and will not render a compositor showing off.
The boot partition used to be the sharper constraint: 12 MiB free on a shared 100 MiB ESP, one existing initrd eating ~42 MiB, and no room for a second. That single number ended up being a whole argument against using Plymouth for login. We removed the old Windows install, repartitioned, and /boot became a dedicated 1 GiB partition with 913 MiB free.
The constraint evaporated but Plymouth still isn't on the roadmap, classic case of an old implementation staying in even once the reasons change. But it could go in now.
Constraints don't produce a compromised design. They produce a specific one: flat surfaces, real contrast, geometry instead of effects.
#5E81AC does about 90% of the accent work. Aurora colors appear only when they mean something — an error, a warning, a live state. A palette where every color is available everywhere is a palette that communicates nothing.
nixbox · gen 36 · 2026-08-17
The two accents are disciplined. Nord's #5E81AC is valid as
a fill, a ring, or large display type, but would fail contrast as small text on a Snow Storm
ground. So small text uses a derived ink value, and a helper called
pickInk makes that choice rather than each generator guessing.
frost = {
accent = "#5E81AC";
hl = "#81A1C1";
fill = "#88C0D0";
}; nixbox · gen 36 · 2026-08-17
Every generated theme traces back to the palette; a generator that hardcodes a hex value is a bug. Contrast is not a review step. Programmatic WCAG tests enforce 4.5:1 for normal text and 3:1 for large text and non-text UI across every required pair.
Because each activation is a generation, every repaint is rollback-able. The worst outcome of a bad color is a boot menu entry.
Zenith at the center, horizon at the circumference, North up, East left because you are looking up, not down at a map.
Eight fixture cities pin the math. Sydney catches hemisphere errors: Crux must be above the horizon and Polaris below. Quito puts both poles near the rim. Get a sign wrong anywhere and a fixture fails.
Identical input produces byte-identical output. Because even lock screens deserve to be spectacular.
nixbox · gen 36 · 2026-08-17
nixbox · gen 36 · 2026-08-17
The civil date is the seed to produce one stable mountain geometry. Sun position and ambient light then progress through UTC-keyed frames, rendered from the same ephemeris the star chart uses.
The wallpaper is not a slideshow or animation; it's a function of the date and the clock, and it selects the correct frame rather than fading between images. Re-running the selector when nothing has changed is a no-op.
mockdestination state · phase 5 pending
Waybar and the quickshell HUD are consumers, not data sources. Weather, VPN state, astronomy, and theme each publish one schema-checked cache; every instrument reads it.
The rule that keeps it honest: no duplicate data daemons. If the bar and the HUD disagree about the temperature, that is a bug in one cache, not a race between two pollers. Stale and offline are explicit states with their own rendering, not a blank field.
5 of 8 phases done. Phase state is a declared human judgment. "Acceptance criteria met" is not something a script gets to infer. Everything below it is automatic.
specced · quiet for 23 days · source rice-progress.json seed data · not yet host-bound
That is the actual question. An agent working on deep internals - bootloader, kernel, display stack - can sever the connection it would need to undo its own change. Ask it to fix the thing, and the failure mode isn't a bad diff. It's a laptop that no longer boots and no longer answers.
Code review doesn't help: the change is correct right up until it isn't, and by then nothing is listening. So the machine gets a deadman switch. A guard is armed with a ten-minute timer before the change, and if nobody disarms it, the host restores itself to a pinned known-good closure. That covers both a hung switch and a dead network equally, because both look identical from outside: silence.
Failure and unknown are the same outcome: don't disarm, don't retry in place, let the timer fire. A machine that recovered itself is a correct result, not an incident.
tx=$(sudo station-guard arm 10)
sudo station-deploy test "$closure"
station-health --expect test
# feature probes + screenshot review
sudo station-deploy switch "$closure"
station-health --expect switch
sudo station-guard disarm "$tx"
The whole machine is a git repository. Every package, service, keybind and color is
declared in Nix, so a rebuild reads the repo and produces a byte-identical system.
nixbox is compiled, not accumulated.
That is the reproducibility win, and it hands you the security problem attached to it: the repo can now rewrite the machine. So nixbox pulls with repository-scoped, read-only deploy keys. It can read its own configuration and cannot write back. Proving they are read-only is where the trust-boundary thinking shows up.
Push a unique ref with --dry-run through each alias and require
an explicit permission rejection. If git answers
Everything up-to-date, the probe proved nothing — it never
reached the permission check. A successful fetch proves nothing either.
The default GitHub credential path is configured to fail closed before any key is installed, and a fresh clone that misses the local override is supposed to fail. Never retry through the default host or a forwarded agent.
$ git push --dry-run parent HEAD:probe-x
remote: Permission denied to deploy key
✓ rejected — this is the pass
$ git push --dry-run child HEAD:probe-x
Everything up-to-date
✗ FAIL — proves nothing, never
reached the permission check The same instinct as a protocol audit: an assertion that passes for the wrong reason is worse than no assertion, because it retires the question.
One machine is finished and drives daily. One is a spec with more and more phases landing. This page says so on every slide rather than in a footnote.
The thesis holds in both directions. Whether the arrow points from the machine to the repo or from the repo to the machine, there is exactly one place a color is defined, and everything else is generated, tested, and reversible.
← back to wschwab.xyzspecced · quiet for 23 days · this page rebuilds daily and recomputes its own status
Every slide is deep-linkable — /rice/#7 opens slide 7 and
survives a refresh. Prefer to scroll? Use read as one page.