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

22 files
4f0092888eb7
back to HEAD
c35b8c5bbfb7doctor: add home manager check — when HM is detected, doctor appends a 'home manager' row with note 'standalone gen <n>' (or 'module'), status ok; gated on detection so the table is unchanged on machines without home-manager; homeDoctorNote builds the caller-owned note string; build+tests green4 months agoe0aef3b8a987status: show home manager generation when HM is installed — homeStatusLine adds a dim 'hm gen <n> <date>' row indented under the machine rows, gated on standalone HM detection so a machine without home-manager shows nothing (verified: no hm line on a no-HM host); statusCmd no longer early-returns on --all so the hm line renders in both modes; build+tests green4 months agoe0ee1531cdefhome packages: list home-manager managed packages — homePackages reads the current home generation's store path, lists its references via nix-store -q --references, and renders name+version through output.listPkg (reusing pkgFromStorePath); skips versionless support outputs and home-manager scaffolding paths; build+tests green4 months agoe54614fcd2b5home diff: diff between home manager generations — homeDiff parses the two newest home generations and runs nix store diff-closures on their store paths via exec.diffClosuresPaths (tty streams native color, piped path captures+strips ANSI like system diff); <2 generations prints 'nothing to diff yet'; build+tests green4 months ago55d6ea4397d0home check: home-manager build without switch — homeCheck runs 'home-manager build' (validates + builds, no activation), prints ':: ok' on success or routes to checkFailed + BuildFailed on non-zero; build+tests green4 months ago1dc3b72b2db4home edit: open home.nix in editor — homeEdit resolves ~/.config/home-manager/home.nix via exec.homeNixPath and opens it in cfg.editor; placed before the module redirect so it works in both standalone and module mode (the same path detection keys on); build+tests green4 months agobe5e5b56ec22home history: parse home-manager generations into aligned table — homeHistory captures 'home-manager generations', parses into number/date/time rows via parseHomeGenerations, renders through output.homeHistoryRow with the first (newest) row marked current; build+tests green incl parseHomeGenerations unit test4 months ago89cc9bd8035fhome back: rollback via home-manager switch --rollback — homeBack parses home generations (newest-first), takes gen[0]=current and gen[1]=target, confirms, runs 'home-manager switch --rollback'; <2 generations prints 'already at the oldest generation' instead of failing; build+tests green4 months agoee5a921daea4home apply: standalone switch + module detection — new 'nina home' command group (multi-word, dispatched in main); exec.detectHomeManager returns standalone/module/none (home-manager on PATH, else ~/.config/home-manager/home.nix); home apply runs 'home-manager switch' (or '--flake <dir>#$USER' when flake.nix present), --dry runs 'home-manager build'; module mode redirects to 'nina apply'; none shows 'not detected'; parseHomeGenerations + homeCurrentGen for the gen line; build+tests green, help+detection smoke-verified on mac (no HM)4 months agoa3e1e6fb62c2config: auto-detect flake system, note on channel commands — commands.flakeSystem returns true when cfg.flake OR a live flake.nix is found in the config dir; nina channel now prints the flake note for detected (not just configured) flakes; flakeChannelNote reworded to ':: note: flake-based system — use nina flake update to update inputs'; build+tests green4 months agoe917196e218fapply: auto-detect flake.nix and pass --flake for non-default config paths — exec.configHasFlake checks machine.config_path/flake.nix locally; useFlakeFlag gates on presence AND path != /etc/nixos (which nixos-rebuild auto-detects); switch/dry-activate/build routed through nixosRebuildRun; switch substep shows the --flake path; build+tests green4 months ago73ca9ec06eb5bump version to v3.0.24 — VERSION 3.0.23->3.0.24 and build.zig.zon 3.0.22->3.0.24 (re-synced); nina --version confirms v3.0.24, build+tests green. Ships the community-feedback brief: XDG config path + migration, flake-aware setup wizard, subcommand help, service --user, and 'nina why' alias4 months ago3fae308e0554add nina why <pkg> as top-level alias for nina pkg why — commands.why dispatches to exec.pkgWhy(args[0]); registered in main dispatch; 'why <pkg>' added to help — build+tests green, verified 'nina why ripgrep' and 'nina pkg why ripgrep' both run 'nix why-depends .# ripgrep', no-arg why gives clean 'package not found'4 months ago34a678d5d87dservice: add --user flag for user service support across all service commands — parse --user (main.zig Args+Ctx); exec.serviceList/serviceCtl/serviceLogs take a user bool: --user injects 'systemctl --user'/'journalctl --user' and drops sudo for user-owned units; covers list/logs/status/start/stop/restart/enable/disable; service help footer documents --user — build+tests green, argv traced via fake systemctl/journalctl (logs --user -> 'journalctl --user -u <svc> -n N --no-pager', status --user -> 'systemctl --user --no-pager status <svc>' no sudo, system paths unchanged)4 months ago6a4241b6957asubcommand help: show usage when grouped command has no subcommand — output.subcommandHelp renders an aligned {invocation, desc} table; flake/service/store/channel/gen/pkg now print their subcommand list on empty sub or explicit 'help' (e.g. 'nina flake', 'nina flake help'); channel help shows before the flake note; real subcommands still dispatch unchanged — build+tests green, all six groups + explicit help verified4 months agobbbdab1eedc3setup: flake vs channel awareness in wizard and config — firstRunWizard asks channels(1)/flakes(2) after machine name, prompts for flake directory vs config path accordingly, and writes top-level 'flake = true' for flakes; NinaConfig.flake field + config parser + test; channel command group prints ':: note: using a flake system — channel commands may not apply' when cfg.flake (note: nina update is the self-updater here, so the note lives on the channel group) — build+tests green, both wizard paths and the note verified on temp HOME4 months ago74510ec9f7ddconfig: use XDG_CONFIG_HOME (~/.config/nina/config) with auto-migration — configPath resolves $XDG_CONFIG_HOME/nina/config then ~/.config/nina/config; load() migrates legacy ~/.nina.conf (copy+delete, dim note) idempotently; firstRunWizard+setup write to XDG path and mkdir -p the parent; exec.ensureDir helper added — build+tests green, migration/XDG/idempotency verified on temp HOME4 months agod55887bd29e5add branded PS1 prompt and exit instruction to nina try and develop4 months ago0e5a095f8dccnina setup creates ~/.nina.conf via wizard when config not found4 months agoe66b7c22892fauto-run setup on first run when ~/.nina.conf not found4 months agob7b8e9e220c2remove unfillable freed parameter from cleanDone; show 'done' instead of 'freed ?'4 months ago3bc371dc76eeset kepr.build trigger to on-promote4 months agof7c64427fb9aupdate install.sh: rename to NixOS Intuitive Navigation Assistant, fix prompt to always fire via /dev/tty, add post-install onboarding with color and spacing4 months ago5f7a024da0cffix install command: remove #nina suffix per forum post4 months agoc140a4444cf7add install.sh redirect: discontinued notice + nix profile add path; bump to v3.0.194 months ago5096769f9bb3fix goodbye to cleanly remove via nix profile remove; delete install.sh; drop ~/nina.nix system-managed path; update README install section to 3 paths; bump to v3.0.184 months agob487cd10cf40bump to 3.0.174 months ago983675ccedb4fix goodbye/update: detect nina element by storePath when element key is 'default' (tarball install via default output)4 months ago6f3f265f176aupdate copyright holder to Asha Software4 months ago478c16209784add MIT license4 months ago0cfd715f1cd2bump to 3.0.164 months agob9f538746a24widen action column from 12 to 16 to fit service-status without breaking alignment4 months ago077e773ecaf7make NixOS installer profile-only: drop generate_nixos_module + offer_config_import (no more ~/nina.nix generation or /etc/nixos editing), so curl|sh does a single per-user 'nix profile add' instead of also wiring a system module — fixes the double-install; remove now-dead out/hr helpers and unused GREEN/BOLD palette vars; update the source-build note; document the declarative module + flake-input paths in README for power users (the nixos-module.nix/flake stay in the repo); sh -n clean4 months ago68fb95c07a2ffix nina goodbye for nix profile + system-module installs: detect install method via parsed 'nix profile list --json' element names (new profileHasNina/profileJsonHasNina) instead of assuming /nix/store means a profile install; remove by element name 'nina' (was the unmatched regex '.*nina.*'); when system-managed via ~/nina.nix, instruct instead of editing /etc/nixos or deleting an imported file; apply same detection to update's self-upgrade path; add profileJsonHasNina unit test incl store-path decoy; build+tests green on darwin and x86_64-linux4 months agob519d45f7a23install.sh: use 'nix profile add' instead of deprecated 'install' alias in nixos_profile_install — the binary already used 'add' (exec.zig) but the installer still printed warning: 'install' is a deprecated alias for 'add'; update the section header and failure message to match; sh -n clean4 months ago05457b1ff3c3add flake.lock pinning nixpkgs nixos-unstable to rev 331800de (2026-05-31, narHash sha256-x5UQuRsH3MqI0U9afaXSNqzTPSeZlRLvFAav2Ux1pNw=); generated via nix flake lock on kyoshi, eval confirms nina-3.0.154 months agoe4b3b0360eccadd tty/NO_COLOR-gated ANSI palette to install.sh (pink prefix, cyan paths/commands, green ✓, dim dividers, red errors) mirroring nina's binary; colorize say/die/hr, the system-wide install section, the config-import prompt + success, and the farewell; add a blank line before the manual block so it no longer mashes against the [y/N] answer4 months agof31363a24350back up configuration.nix to .nina-bak before editing — single sudo sh -c does cp backup then cp new content (one password prompt, positional args avoid quoting); setupNixosWrote notes the backup path4 months ago7323b63a7566setup: on NixOS offer to append 'nix.settings.experimental-features = [ "nix-command" "flakes" ];' into configuration.nix (insert before final brace, sudo cp, default-No prompt) instead of writing ~/.config/nix/nix.conf; show copy-paste manual fallback + nixos-rebuild instruction; detect already-declared-needs-rebuild case; add exec.appendFeaturesToNixosConfig/nixosConfigEnablesFeatures and output.confirmDefaultNo + setupNixos* messages4 months ago29642d33c40eadd offer_config_import: prompt to append ~/nina.nix into an existing imports list in /etc/nixos/configuration.nix (backs up first, awk-inserts as first list entry, idempotent, manual fallback); reformat post-install output into a spaced 'system-wide install' section with unprefixed out/hr helpers instead of mashed nina: lines4 months agoc89bd7b1bf37add --no-write-lock-file to nix profile install (tarball flakes are read-only, cannot persist lock); fix unstable channel URL to channels.nixos.org (old releases.nixos.org path 404s); try prebuilt static binary on NixOS before source build4 months ago402c59e6e7e7redirect fetch_source progress to stderr so command substitution captures only the srcdir path, not the 'fetching source' message — fixes broken 'cd' in nix-shell build4 months ago1ea6dc71d2a4install.sh: offer to enable nix features after install — maybe_setup_features probes 'nix eval --expr 1' (needs nix-command); if off, prompts 'enable them now? [Y/n]' read from /dev/tty (works under curl|sh) and runs the freshly-installed 'nina setup' on yes, else points to 'nina setup'; wired into all install paths, self-gates on 'have nix' and already-enabled. sh -n clean; verified probe skips on kyoshi (features on) and 'nina setup' reports 'all set' non-destructively4 months ago4871502e9c71add 'did you mean?' typo suggestion to install: when a package name has 0 search results, closestPackage() prefix-searches for candidates and ranks by case-insensitive Levenshtein (editDistance); if the best is typo-close (threshold max(2,len/3)) it prints ':: <q> not found — did you mean <pkg>?' and confirms before installing, else the plain not-found error. Verified on kyoshi: firefux->firefox, ripgrp->ripgrep, zzzzqqq->not found. build+tests green incl editDistance test4 months agof7a6d8142581help tagline: append 'by Asha Software' -> 'NixOS Intuitive Navigation Assistant by Asha Software' — build+tests green4 months agofb7d739d80dfhelp tagline: 'nixos helper' -> 'NixOS Intuitive Navigation Assistant' (the nina backronym) — build+tests green, verified4 months ago904eb6cf75a4document search key-collision fix in CONTINUITY: type-to-filter / Enter-to-select model replaces single-letter actions; deployed to kyoshi4 months agofc944d79e97efix search keys colliding with typing: letters in a package name (the i in 'ripgrep', t in 'git') were triggering install/try/etc. Now every printable key types into the query; only Enter (select), Tab (detail), arrows (nav), Esc (cancel) act. Enter returns the highlighted package and the shared selectAndInstall() prompt (i/s/t) runs after the widget's raw mode is gone — no collision. Also dupe the chosen package into the caller's allocator (search arena deinits on return; old code returned dangling slices). Removed now-unused copyToClipboard + SearchResult; controls now '[enter] install [tab] info [up/down] nav [esc] cancel' — build+tests green4 months ago5ea64eb84989document post-ship search UX in CONTINUITY: 500ms debounce + searching indicator + empty-query guard; Tab-to-expand package detail (home/license/attr via nix eval meta) — both deployed to kyoshi4 months ago5a193aa6bb32add Tab-to-expand package details in search widget: Tab toggles the detail pane between description (collapsed) and metadata (homepage + license + attr), fetched on demand via api.packageMeta (one 'nix eval --json .meta', parses homepage + license array/object/string), cached by attr in its own arena, with a 'loading...'/'details unavailable' state; loop unified to a single render point; '[tab] info' added to controls — detail pane stays exactly 4 lines so WIDGET_LINES is preserved; build+tests green4 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