nina

@june

NixOS is powerful, but it can be a lot. Nina keeps the whole workflow — packages, options, rebuilds, services, remote machines — right at the prompt.

https://nina.asha.software

Zig

v3.4.14 · 229 saves · 10,620 lines · updated 1 week ago

42 files
4f2faa7345dd
back to HEAD
kiln/8.3 KB · 4 months ago
src/130.1 KB · 4 months ago
test/24.6 KB · 4 months ago
vm/A reproducible NixOS 24.11 dev image for exercising nina, built once and booted as disposable copy-on-write overlays so every run starts from the exact same snapshot.24.6 KB · 4 months ago
tests/11.5 KB · 4 months ago
boot-overlay.shBoot a THROWAWAY copy-on-write overlay of the golden image, run commands over the serial console, then discard the overlay.2.0 KB · 4 months agobuild-golden.shBake the golden NixOS qcow2: boot the minimal ISO headless under qemu, drive a scripted nixos-install over the serial console, power off.3.5 KB · 4 months agoconfiguration.nixGolden NixOS dev image for nina testing — the reproducible "exact starting snapshot".2.4 KB · 4 months agoinstall.shRuns INSIDE the NixOS minimal installer (over serial) to lay down the golden system onto /dev/vda from the seed media.1.2 KB · 4 months agoREADME.mdA reproducible NixOS 24.11 dev image for exercising nina, built once and booted as disposable copy-on-write overlays so every run starts from the exact same snapshot.1.7 KB · 4 months agorun-in-vm.shRun a test script inside a throwaway overlay of the golden image, injecting a fresh nina binary so we test the latest build without rebaking the golden.2.3 KB · 4 months ago
build.zig1.7 KB · 4 months agobuild.zig.zon4.2 KB · 4 months agoflake.nix2.0 KB · 4 months agoinstall.shnina install script Run: curl -fsSL kepr.uk/nina/install.sh | sh Or: NINA_INSTALL_DIR=/usr/local/bin sh install.sh10.5 KB · 4 months agokepr.build211 B · 4 months agonixos-module.nixStandalone NixOS module for nina — no flake inputs needed.1.3 KB · 4 months agoVERSION7 B · 4 months ago
05d1462ec09fmake search feel responsive (only search when you stop typing): debounce 250->500ms so a normal between-keystroke pause no longer triggers the blocking nix search; show 'searching...' over stale results while the search runs so the pause reads as progress not a freeze; guard empty query in the widget's doSearch (was fetching the whole 108k catalog on open — verified now shows '0 results' instantly) — build+tests green4 months agoda3d2938f6d0document post-ship fixes in CONTINUITY: debounce selection-OOB crash (reset+clamp) and nix profile add deprecation fix; both deployed and verified on kyoshi (crash sequence no longer segfaults)4 months agob746e1064ef7fix nix profile deprecation warning on install: use 'nix profile add' (current verb) instead of 'nix profile install' (deprecated alias that prints a warning on modern nix); updated the command echo + teach text to match — build+tests green4 months ago1191127df903fix debounce crash: clamp selection in search widget — navigating during the 250ms debounce window grew selection against the old result set; when the debounced search returned fewer results, renderWidget indexed packages[selection] out of bounds (segfault in ReleaseFast). Now reset selection=0 when a debounced search lands, and clamp selection to count-1 in renderWidget as defense — build+tests green4 months ago7abf027a795erecord kyoshi deploy: v3.0.15 built ReleaseFast in ~/projects/nina and installed to ~/.local/bin/nina (old binary backed up); live PATH nina --version = v3.0.15, re-verified hello/status/log/mood/diff on installed binary4 months agoe5a835849145document finishing-brief session in CONTINUITY: debounce, 10 kaomoji, color refinements, 6 fixes (OF-3/5/6/7/8/9), v3.0.15; real-hardware read-only verification on kyoshi via ephemeral build; diff NO_COLOR approach replaced with capture+stripAnsi after kyoshi revealed nix ignores NO_COLOR4 months ago38ab7ce66df4polish list system versions — strip nix multi-output suffixes (-bin/-man/-dev/...) so the version column reads clean (curl 8.20.0 not 8.20.0-bin); verified on kyoshi: less 692, openssh 10.3p1; build+tests green incl suffix test4 months ago9b54f69bee5afix diff ANSI: capture+strip instead of NO_COLOR — nix store diff-closures ignores NO_COLOR, so when piped, diffClosures now captures output and strips CSI sequences via stripAnsi(); tty path still streams native color — verified on kyoshi: 'nina diff | cat' emits 0 ESC bytes (was 1); build+tests green incl stripAnsi test4 months agob7d3ccd72f2abump version to v3.0.15 — VERSION + build.zig.zon; nina --version confirms v3.0.15, build+tests green4 months ago3bec58cfa908fix clean phrasing under generation limit (OF-9) — clean() prints ':: cleaning <machine>' + 'only N generation(s) — nothing to remove.' and skips gc when total <= keep (keep=1 for 'clean all', else cfg.generations), killing 'keeping 5 of 1'; cleaning case now clamps to 'keeping {keep} of {total}' — build+tests green4 months ago6016e2b06f60fix back error message for no older generation (OF-8) — back() now checks for any generation older than current; if none, prints ':: error: already at the oldest generation' and exits cleanly instead of running rollback and surfacing nixos-rebuild's 'build failed'; prev now resolves to newest-older gen, not current-1 — build+tests green4 months agoab2b04787858fix log --last N truncation (OF-7) — readNinaLog now keeps only the final N non-empty lines when last>0 (was '_ = last'), copying out before freeing content; default last=50 unaffected when fewer entries — build+tests green, --last 2 verified returns exactly 2 of 4 entries4 months agof1e9d723cc0ffix list parse nix profile json + show system packages (OF-3) — list() parses nix profile list --json (object/array forms) into name+version rows, adds system section from /run/current-system/sw references; pkgFromStorePath splits <hash>-<name>-<version>; aligned two-column table via padded listPkg; header now 'packages <machine>' — build+tests green incl new parse test4 months agocec9ca91b68dfix diff suppress child ANSI when piped (OF-5) — diffClosures prepends 'env NO_COLOR=1' to nix store diff-closures when output.colorEnabled() is false; added public output.colorEnabled() accessor; SSH-safe via env — build+tests green4 months agob73567de331ffix status --all iterates all configured machines (OF-6) — statusRowFor helper renders each cfg.machines entry via existing SSH routing; unreachable remote shown red instead of bogus gen 0 — build+tests green, two-machine table verified4 months agofca9546777e4color refinements in output.zig + search.zig — bold-white gen in status row, cyan version numbers and cyan attr value in search widget+plain, dim-bracket/pink-letter key hints, dim log timestamps, cyan actionable suggestion lines — build+tests green4 months ago85cb9c4a3870add 10 kaomoji to output.zig (8 constants, rare/earned placements); excited kaomoji gated on persistent ~/.nina-apply-failed flag; sad kaomoji only on network/ssh/search errors via printSystemError — grep confirms glyphs only in output.zig, hello shows face, build+tests green4 months ago37f985da095dadd 250ms debounce to search query input via Io.Clock poll loop; stale results stay visible while typing — build + tests green4 months agodebc6352f6d5document hybrid test session in CONTINUITY: kyoshi §2 suite, 12 fixes (all verified real-hardware), golden VM destructive suite all-green, open findings4 months agod9f67551ab8ebump version to v3.0.14 (12 fixes: auto-pin, non-root gen read, fast store info, search color/empty, log json, status columns, streaming stdout, pkg size, arena leaks, mood, flush, headers)4 months ago4c34ae00a009add nina mood: plain-language machine health (systemctl is-system-running + current gen + last-applied age + system closure size); registered in dispatch and help4 months ago11ccaf00b0c5fix command-exit memory leaks: route all command allocations through an arena in main.zig, freed before main returns (per brief 3.3); NINA_DEBUG=1 nina hello now reports zero leaks4 months ago7d2118a61798fix pkg size returning blank: resolve nixpkgs#<pkg> (bare name isn't a valid installable) and report human-readable closure size4 months agoadfd556a21fbfix stdout output corruption on redirect: use File.Writer.initStreaming (was default positional, which pwrites from offset 0 and clobbers surrounding output in redirected files and >> append)4 months ago8aa0bab7f860fix status empty disk/time columns: add exec.systemStatus (current-system closure size via path-info -S /run/current-system + system profile symlink age) and render in status row4 months ago78c1d70126e3fix nina log: parse JSON-lines log into date/time/action/outcome columns (was dumping raw JSON); write new entries as JSON with real Io.Clock.real timestamp (kills hardcoded 2026/00:00)4 months ago46652f694f90flush buffered output before spawning inherited-stdout children (stream/streamLocal) so nina headers aren't reordered after journalctl/systemctl output4 months ago89e3dbd1918ffix remove header (show 'removing' not 'installing') and flake show header (meaningful 'flake outputs' not ':: .')4 months ago6ce61f1948e5fix search plain rendering: route through color-gated output (no ANSI leak to non-tty pipes) and reject empty query instead of dumping the whole catalog4 months ago9c82a195ab39fix store info hang: drop pathological 'nix path-info -S --all' and slow 'du -sh /nix/store'; sum narSize from path-info --json (timeout-wrapped) for count + total4 months ago15cc71755519read system generations from profile symlinks instead of nix-env --list-generations (avoids root-only profile lock); fixes history/gen current/diff/status gen as non-root4 months ago41b75b265eb0implement registry auto-pin: pin nixpkgs once via ~/.nina-registry-pinned flag, announced before search/install/setup4 months ago670b260dac73scroll results list when selection moves past visible window4 months agob307f871462fuse b.graph.environ_map instead of std.c.getenv for KEPR_TARGET in build.zig (Zig 0.16 libc-free env access)4 months agod87bd9832610nix-shell fallback: use pinned nixpkgs-unstable if zig_0_16 not in channel4 months ago4f2faa7345ddsmart update: nix profile upgrade when in nix store; goodbye command for clean uninstall4 months ago1e7fb76f4530hello cheatsheet, NINA tagline, friendly farewell; flake+module descriptions updated4 months agocc69486cead8add flake.nix, nixos-module.nix; rewrite install.sh with ASCII banner, NixOS nix profile/nix-shell paths, and update reminder4 months agoc10740f41f1aadd install.sh — binary from Kepr with source fallback, Zig 0.16 guidance4 months ago2aa7f7247657fix: Align search stdin TTY probe with std.Io.File.isTty (v3.0.13)4 months ago2af4a89e497dfix: Switch color detection to std.Io.File.isTty (v3.0.12)4 months ago139d763aea8cfeat: Add --version flag and version output (v3.0.11)4 months ago13667345d2bdfix: Harden config parser boolean handling (v3.0.10)4 months ago20f42f37bb78add nina update: kepr self-update with blake3 verification and atomic install4 months ago4afdbd225c8fadd nina setup: detects and enables nix-command + flakes in ~/.config/nix/nix.conf4 months agoe6b790aa94d5build.zig reads KEPR_TARGET env var for Kepr cross-compile — falls back to standardTargetOptions4 months agof06063e4aaf4add kepr.build — enables Kepr Builds for all four platforms on every offer4 months agobc7cf129a9b7before kepr.build and KEPR_TARGET support4 months ago5ace885c717brecord G-12 routing validated via ssh-to-self; add multimachine test; all 12 groups exercised4 months agoeff585c773cffix machine config: host implies remote (local=false) so test-remote renders as ssh; v3.0.94 months ago

← newerolder →

details

nina

Nina is a command-line helper for NixOS. Use it to find packages, apply your configuration, roll back a generation, or check another machine over SSH.

nina search ripgrep
nina apply
nina back
nina status --all

It calls the Nix tools you already use and gives common tasks shorter names. Your configuration stays in Nix files. Nina is written in Zig and builds as a single binary with no third-party Zig dependencies; it needs Nix and the relevant system tools to carry out commands.

Install

Nina's system commands are for NixOS. Package and development commands use Nix, which needs the nix-command and flakes experimental features enabled.

Install in your user profile:

nix profile add 'https://kepr.uk/nina/archive/HEAD.tar.gz#nina'

Then run:

nina setup

Setup creates Nina's configuration if it is missing and checks the required Nix features. On NixOS, it offers to add the setting to /etc/nixos/configuration.nix; you must rebuild for it to take effect. If the install command above fails because these features are disabled, enable them in Nix first.

To build from source, you need Zig 0.16:

koh steal kepr.uk/nina
cd nina && zig build -Doptimize=ReleaseFast
sudo cp zig-out/bin/nina /usr/local/bin/nina

You can also download a source archive from releases:

tar xf nina-*.tar.gz && cd nina-*/
zig build -Doptimize=ReleaseFast
sudo cp zig-out/bin/nina /usr/local/bin/nina

nina goodbye uninstalls Nina. Run nina update to check for a newer Nina release. If your system configuration manages Nina, update it through that configuration.

Apply a configuration

nina edit opens configuration.nix in your editor. Check it before applying, or build it without switching:

nina edit
nina check
nina apply --dry
nina apply

Nina also supports flake-based system configurations. Set the machine's config directory to the directory containing your configuration.

If you need to go back, use nina back. To choose a specific generation, find its number with nina history, then run nina go <n>.

Command What it does
nina history Lists system generations
nina back Rolls back one generation
nina go <n> Switches to generation <n>
nina diff Compares generations
nina upgrade Updates Nix inputs or channels and rebuilds
nina clean Removes old system generations and collects garbage

nina clean keeps the number of generations set in your config, five by default. Removing generations means you can no longer roll back to them.

Find and use packages

nina search <q> searches nixpkgs through nix search. In a terminal, results appear in an inline browser. Use the arrow keys to move, Tab for package details, Enter to select a package, and Escape to cancel. When stdin is not a terminal, search prints a plain list.

nina search ripgrep
nina install ripgrep
nina try ripgrep
nina remove ripgrep
nina list

Selecting a package in search or running nina install asks how you want to use it:

  • Install it in your user profile without a system rebuild.
  • Add it through your system configuration: Nina opens the editor at the package list and offers to apply your changes.
  • Try it in a temporary shell without installing it.

Search and installation may need network access to fetch Nix inputs or packages. nina option <q> searches NixOS options.

Home Manager

Nina supports standalone Home Manager and Home Manager integrated into a NixOS configuration. To create a standalone configuration:

nina home init

Add --switch to activate it immediately. Nina chooses a Home Manager branch from your NixOS version and leaves an existing configuration in place.

Command What it does
nina home apply Applies your home configuration
nina home back Rolls back one home generation
nina home history Lists home generations
nina home edit Opens home.nix
nina home check Builds the home configuration without switching
nina home diff Compares the latest two home generations
nina home packages Lists packages in the home generation

When Home Manager is part of your NixOS configuration, nina home apply runs a system rebuild. Home commands operate on the local user; they do not support --on.

Configure Nina

Nina reads ~/.config/nina/config, or $XDG_CONFIG_HOME/nina/config when that environment variable is set.

editor      = hx
generations = 5
confirm     = true
teach       = false
color       = true

[machine]
name    = my-machine
config  = /etc/nixos
local   = true
default = true

Set editor to your preferred editor. generations controls how many system generations cleanup keeps. With teach = true, Nina prints the underlying commands as you work.

Nina disables color when stdout is not a terminal and respects NO_COLOR.

Work on another machine

Add a machine with an SSH host to your config:

[machine]
name    = azula
host    = azula
user    = june
ssh_key = ~/.ssh/id_ed25519

Put --on <name> after the command to select it:

nina apply --on azula
nina service logs ollama -f --on azula
nina status --all

Remote system operations use SSH and the tools on the target machine. nina status --all checks every configured machine. Use nina hello to list them.

Run hooks

Place executable scripts in ~/.config/nina/hooks/ to run before or after these operations:

pre-apply     post-apply
pre-back      post-back
pre-home      post-home
pre-upgrade   post-upgrade

Missing or non-executable hooks are skipped. If a pre-hook fails, Nina shows its last five output lines and asks whether to continue, defaulting to no. A failed post-hook produces a warning after the operation succeeds. Hooks run locally, including when the operation targets a remote machine.

For example, save this as ~/.config/nina/hooks/pre-apply to check for uncommitted changes, then make it executable with chmod +x:

#!/usr/bin/env sh
# ~/.config/nina/hooks/pre-apply
if git -C ~/nixos-config status --porcelain | grep -q .; then
    echo "uncommitted changes - commit before applying"
    exit 1
fi

More commands

Command What it does
nina status Shows machine health
nina doctor Checks for common problems
nina log Shows Nina's operation history
nina service list Lists systemd services
nina service logs <s> Reads a service's journal
nina service start/stop/restart <s> Controls a service
nina flake show Shows flake outputs
nina flake update Updates flake inputs
nina pin <in> <rev> Pins a flake input to a revision
nina unpin <in> Updates a pinned input
nina develop Enters a development shell
nina build Builds a flake output
nina run <p> Runs a package
nina edit --dir Opens the configuration directory
nina fmt Formats the system configuration
nina info Shows system information
nina boot Lists boot entries

Run nina help for the full command list, nina <group> help for a group such as home or service, and nina man [topic] for the built-in manual. nina --version prints the installed version.

Build and test

From the source directory:

zig build
zig build test
zig fmt --check build.zig src/*.zig

System operations need a NixOS host for live testing. The VM test harness describes testing against disposable NixOS images.

Made by Asha Software.

Website · Source · Documentation