everything she knows

A quiet reference for a cozy tool. Find what you need, take your time.

getting started

what is nina?

intro

Nina is a NixOS Intuitive Navigation Assistant — a gentle command-line tool that wraps the full NixOS workflow in one quiet, consistent voice.

She handles package search, rebuilds, flakes, services, generation history, and remote machines — all without dropping you into a different screen, switching tools, or making you memorise long nixos-rebuild incantations.

The goal is simple: NixOS should feel like home. Nina is one step toward that.

(っ˘ω˘ς )

Nina stays inline at your prompt. Search results, install confirmations, diff previews — everything comes to you. You never leave the shell you're already in.

installation

setup

Nina is a Nix flake. No channels, no overlays, no nixpkgs pin needed. Just two ways to get her:

keep her in your profile
$ nix profile add github:hopeineveryline/nina
→ available everywhere, every terminal, every time
just borrow her for one run
$ nix run github:hopeineveryline/nina
→ no commitment, no trace left behind
(•̀ᴗ•́)و

Nina is flake-friendly and works on NixOS 24.05 and newer. Nix experimental features flakes and nix-command must be enabled.

add to your system configuration

If you prefer managing tools through your system configuration:

# in your flake.nix inputs:
nina.url = "github:hopeineveryline/nina";
 
# in configuration.nix:
environment.systemPackages = [ inputs.nina.packages.${system}.default ];

first run

setup

Just type nina at the prompt. She'll introduce herself and show you what she can do. (っ˘ω˘ς )

$ nina
♡ hi, i'm nina
tell me what you want to do with nix
 
nina search <query> search packages or options
nina apply rebuild and switch
nina diff preview what would change
nina help the full list

From here, search for a package, apply a change, or just wander through the tips section to see what's possible.

commands

packages

install · remove · profile

Install and remove packages without memorising store paths or profile flags. Nina handles fuzzy matching when the name is close but not exact.

nina install
nina install <pkg> [--try] [--profile <name>]

Install a package into your active profile. If the name doesn't match exactly, Nina shows you the closest options and lets you pick. Σ(°∀° )

$ nina install neovim-nightly
✦ fuzzy install recovery — stays at the prompt
j/k navigate · d detail · enter install · q cancel
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
▸ neovim-unstable 0.11.0-dev [matches fuzzy]
neovim 0.11.0 vim-fork, next-gen
neovim-nightly 0.11.0 rolling release
✓ picked neovim-unstable, added to configuration.nix
--try install ephemerally — gone when the shell closes
--profile <name> install to a named profile instead of default
--on <machine> install on a remote machine via SSH
nina remove
nina remove <pkg>

Remove a package from your profile. Like install, Nina uses fuzzy matching if the name is slightly off.

$ nina remove bat
· removing bat from active profile
✓ bat removed
nina profile
nina profile [list | switch <name> | rollback]

Manage named Nix user profiles. Useful if you want to keep work and personal tool sets separate.

nina pin / nina unpin
nina pin <pkg> · nina unpin <pkg>

Pin a package to a specific version, or release a pin. Helpful when you need an older version while the rest of the system updates.

system changes

diff · apply · back

Preview, apply, and roll back changes to your NixOS system. Nina shows you exactly what will change before it happens, and arms a rollback the moment things go sideways.

nina diff
nina diff [--from <gen>] [--to <gen>]

Show what would change if you applied right now. Compares the current config against the running system, or two specific generations against each other.

$ nina diff
✦ generation diff preview
- services.openssh.enable = false
+ services.openssh.enable = true
✓ one clean service tweak, nothing spooky
nina check
nina check

Dry-run the build. Catches syntax errors, missing files, and config mistakes before they reach your running system. No changes are made.

nina apply
nina apply [--on <machine>] [--no-confirm] [--boot]

Rebuild the system and switch to the new generation. Nina prompts for confirmation, shows a brief diff, and arms a rollback timer if anything looks wrong after switching.

$ nina apply
✦ rebuilding the active machine
· checking flake inputs and local changes
· building generation 349 for kyoshi
✓ generation 349 is live
--on <machine> rebuild a remote machine over SSH
--boot set the new generation as boot default, don't switch now
--no-confirm skip the confirmation prompt (scripts, CI)
nina back
nina back [--to <gen>]

Roll back to the previous generation. With --to, you can jump to any specific generation by number.

$ nina back
· rolling back from gen 349 → gen 348
✓ generation 348 is active
ε-(´∀`; )

Before applying, Nina always takes a backup of your configuration.nix. Even if the build goes through and something is wrong, nina back brings you home.

flakes & dev shells

flake · develop · build

Inspect flake outputs, step into dev shells, build specific outputs, and manage the flake lifecycle — all with the same quiet vocabulary.

nina flake show
nina flake show [<flake-ref>]

Show what a flake exposes — packages, apps, dev shells, NixOS modules. Works on the current directory or any flake reference.

$ nina flake show
✦ what this flake offers
packages: default nina
apps: default nina
devShells: cargo rustc pkg-config
nina develop
nina develop [<output>]

Enter the flake's dev shell. Spawns a subshell with all the dev dependencies available. Type exit to return to your regular shell.

$ nina develop
✦ entering dev shell
· flake devShell: default
· type exit when you want your regular shell back
✓ shell spawned
nina build
nina build [<output>] [--show-trace]

Build a flake output. Result is linked as ./result in the current directory.

nina flake update
nina flake update [<input>]

Update the flake lock file. Pass a specific input name to update only that one.

(ノ◕ヮ◕)ノ

When you run nina develop, the dango does a little dance. It's a small thing. It's a good thing.

inspection & care

status · service · clean

Check on the health of your system, follow service logs, inspect the store, and reclaim disk space — without jumping between different tools.

nina status
nina status [--all] [--on <machine>]

Show the health of your active machine — current generation, running services, any failed units. With --all, shows a fleet overview across all configured machines.

$ nina status --all
✦ fleet summary
kyoshi local gen 349 clean synced
azula ssh gen 192 clean synced
✓ no drift detected across machines
nina service
nina service <action> <name>

Manage systemd services. Actions: start, stop, restart, status, logs. The logs action accepts -f to follow.

$ nina service logs ollama -f
✦ following logs for ollama
[info] loading model metadata
[info] serving on 0.0.0.0:11434
✓ live stream attached
nina store
nina store [--query <pkg>] [--closure <pkg>] [--size]

Inspect the Nix store. Query packages by name, show dependency closures, or list paths by disk usage.

nina clean
nina clean [--keep N] [--all]

Garbage collect old build results and unused store paths. Keeps the last N generations (default: 4). Reports how much space was recovered. ( ˘ω˘ )

$ nina clean
✦ reclaiming old build leftovers
· 4 generations kept · 11 removed
· 6.8 GB returned to disk
✓ cleanup complete
--keep N keep the last N generations (default: 4)
--all remove all old generations, keep only the current
--dry-run show what would be removed without doing it

generation history

history · go · gen · log

Your system's whole story is saved in generations. Browse them, compare them, travel back to any of them. Nothing is gone until you clean it up.

nina history
nina history [--limit N]

List all system generations with timestamps and a brief summary of what changed.

$ nina history
349 ▸ current today 14:22 +openssh
348 today 11:04 +ripgrep -bat
347 yesterday +neovim
346 3 days ago flake update
nina go
nina go <generation>

Switch to any generation by number. The same as nina back but for any point in your history, not just the previous one.

nina gen
nina gen

Show details about the current generation — number, timestamp, installed packages, and kernel version.

nina log
nina log [--from <gen>] [--to <gen>]

Show the changes between generations in chronological order. A clean changelog of your system over time.

(´▽`)

Generations are your safety net. Apply freely, knowing you can always go back. nina history shows the whole story. nina go takes you there.

machine config

edit · info · channel · boot

Edit your configuration safely, inspect the running system, manage channels, and set boot defaults — all without needing to remember the right file path or nixos-rebuild flag.

nina edit
nina edit [--backup] [--diff]

Open configuration.nix in your editor. Nina automatically creates a timestamped backup before you start, shows a diff when you save, and prompts whether to apply.

$ nina edit
✦ safe config editing with rollback
· backing up configuration.nix
· diff preview shown before writing
· apply will prompt for confirmation
✓ backup saved · diff ready · rollback armed
nina info
nina info

Show a summary of the running system: hostname, current generation, kernel version, NixOS version, uptime, and disk usage.

nina channel
nina channel [list | add <url> | remove <name> | update]

Manage Nix channels. List what's configured, add new channels, remove old ones, or update all channels at once.

nina boot
nina boot [<generation>]

Set the default boot generation in the bootloader without switching right now. Useful when you want to test a change only on the next reboot.

(ˊᗜˋ)

nina edit respects your $EDITOR environment variable. Set it to your favourite editor and Nina will meet you there.

remote machines

--on · mood · doctor

The same voice, even over SSH. Every Nina command accepts --on <machine> and behaves identically on a remote host. No separate tooling, no context switching.

the --on flag
nina <command> --on <machine>

Any Nina command runs on a configured remote machine. The machine name matches an entry in your Nina config file, or falls back to your SSH config.

$ nina apply --on azula
✦ rebuilding azula over ssh
· building generation 193 for azula
✓ azula is on generation 193
 
$ nina service logs ollama -f --on azula
✦ following logs for ollama on azula
[info] serving on 0.0.0.0:11434
configuring machines

Define remote machines in ~/.config/nina/config.toml:

# ~/.config/nina/config.toml
 
[machines.azula]
host = "june@azula"
key = "~/.ssh/id_ed25519"
fleet commands
nina status --all health overview across all configured machines
nina mood check the dango's mood on each remote machine
nina hello ping all machines and confirm they're reachable
nina doctor run a full diagnostic across the fleet
(˶ᵔ ᵕ ᵔ˶)

Nina keeps remote work from turning into a whole new personality. Same verbs, same little reassurances, same sense of where you are.

reference

configuration

config.toml

Nina's config file lives at ~/.config/nina/config.toml. All settings are optional — if the file doesn't exist, Nina uses sensible defaults and works fine out of the box. (´ω`)

full example
# ~/.config/nina/config.toml
 
[core]
default_machine = "kyoshi"
confirm_apply = true
confirm_rollback = true
show_dango = true
animations = true
 
[search]
limit = 10
channel = "nixpkgs"
 
[clean]
keep_generations = 4
 
[machines.azula]
host = "june@azula"
key = "~/.ssh/id_ed25519"
all options
option type default description
core.default_machine string hostname machine Nina operates on by default
core.confirm_apply bool true prompt before applying system changes
core.confirm_rollback bool true prompt before rolling back
core.show_dango bool true show the dango character at the prompt
core.animations bool true enable all animations (also respects prefers-reduced-motion)
search.limit integer 10 default number of results shown in search
search.channel string "nixpkgs" default channel for package search
clean.keep_generations integer 4 generations to keep when running nina clean
machines.<name>.host string SSH connection string (user@host)
machines.<name>.key string ~/.ssh/id_ed25519 path to the SSH private key

the dango ♡

moods · feelings

The dango is Nina's little companion — an animated ASCII rice dumpling who sits at your prompt and shows you how things are going. She has feelings. They're good ones, mostly.

She appears whenever Nina is doing something, and her mood reflects what's happening. It's a small thing. It makes the terminal feel a little less lonely.

idle

Calm and present. Nina is ready, watching, waiting for you to tell her what to do. A gentle breathing motion that says everything is fine.

shows when: at the prompt, search open, reading your config
happy

Arms up, bouncing. Something went right. A build succeeded, an apply finished cleanly, the fleet is healthy. She's celebrating with you.

shows when: after nina apply, nina status --all clean, nina clean
sad

Head drooping, still. Something needs attention. A build failed, a service is down, a package wasn't found. She's not panicking — just honest.

shows when: build error, failed service, network unreachable
sweep

Sweeping side to side, stick swishing. She's working. Garbage collecting, editing your config, following a log stream — steady, focused work.

shows when: nina clean, nina edit, nina service logs -f
dance

Arms up, spinning, full of joy. She loves dev shells. The moment you step into one, she can't help herself. It's her favourite thing.

shows when: nina develop, entering any dev shell
( ´•̥̥̥ω•̥̥̥` )

You can turn the dango off with core.show_dango = false in your config, if you prefer a quieter experience. She understands. She won't take it personally.

tips & recipes

patterns · workflow

A few patterns that make daily NixOS life a little smoother. (*˘︶˘*)

daily driver routine

A quiet morning with Nina:

# check if anything drifted overnight
$ nina status --all
 
# update flake inputs and preview changes
$ nina flake update && nina diff
 
# apply if the diff looks good
$ nina apply
safe exploration

Try a package without committing to it:

$ nina install bat --try
→ bat is available in this shell only
→ gone when you exit, no trace in configuration.nix
fleet rollout

Push the same config change to multiple machines:

$ nina apply --on kyoshi
✓ kyoshi on generation 349
$ nina apply --on azula
✓ azula on generation 193
$ nina status --all
✓ no drift detected across machines
generation archaeology

Something broke three days ago and you're not sure when:

$ nina history
→ find the last known-good generation
$ nina log --from 344 --to 349
→ see what changed across those five generations
$ nina go 344
✓ back to the good place
home-manager

Nina works alongside home-manager. She manages NixOS system config; home-manager handles your user environment. They don't get in each other's way. (˶ᵔ ᵕ ᵔ˶) Run Nina for system changes, home-manager for dotfiles and user packages.

useful aliases
# in your shell config
alias ns="nina search"
alias no="nina option"
alias na="nina apply"
alias nd="nina diff"
alias nb="nina back"
(≧◡≦)

When something goes wrong, nina back is always there. When you're not sure what to try next, nina diff shows you the picture. And when things go right, the dango lets you know.