NuFiDocs
NuFi Team boxDay two

Day two

The handful of nufi-box commands that matter after the install, and the one check that catches the failure nobody expects.

Everything below is ./nufi-box from the directory you installed from.

Is it healthy?

./nufi-box doctor

Eleven checks in plain words. Ten of them ask the box about itself. The eleventh is the one worth knowing about.

The name, not just the box

The box announces nufi.local on the LAN with the address it had on install day. Change network, pick up a new DHCP lease, unplug a dock — and the name now points at a stranger while the box itself is in perfect health. Every laptop in the room fails to reach it; the box has no idea.

 !!  nufi.local points at 192.168.1.99, this machine is 192.168.1.25 — run: nufi-box announce
./nufi-box announce

That re-publishes the name at the address the box has now and records it, so the certificate and the banner follow the machine. Run doctor before any demo. This is the single most common way a working box looks broken.

What is running

./nufi-box status          # every service, the model, disk, last backup
./nufi-box logs            # all of it, following
./nufi-box logs librechat  # one service

Start, stop, restart

./nufi-box up
./nufi-box down
./nufi-box restart

Restart is also the cure for one specific confusion: the app caches the model list per gateway and never expires it, so a model you have just added shows up only after the app restarts.

Departments

./nufi-box drive add finance   # folder, share, team and agent

People

./nufi-box user add hana@legal.example --name "Hana Kim"
./nufi-box user list

The box has no sign-up page — who may sign in is an administrator's decision, not a self-service one. user add prints a generated password once; it is not stored anywhere it can be read back.

Note that this is a different thing from invite, which is about a laptop joining the mesh so it can reach the box from outside the office. user add is about a person being allowed to sign in at all.

Studio routines

./nufi-box flows install    # put the department routines into Studio; safe to repeat
./nufi-box flows list       # every flow, with its id

flows install keeps a routine that is already there, edits and all, and creates only what is missing.

From home

./nufi-box mesh up            # join the box to the coordinator
./nufi-box mesh status
./nufi-box invite alice --os macos --drives legal,hr
./nufi-box members
./nufi-box revoke alice

invite writes one file a laptop opens to join. On the LAN you need none of it. What the coordinator is, what the three values are, and how to name a box so two can share a network: On the LAN and from home.

The certificate

./nufi-box ca-cert     # the file every laptop trusts once

Updating

./nufi-box update                       # fetch the newest release, apply it, check it
./nufi-box update --ref nufi-box-v1.2.0 # a specific tag instead of the latest main
./nufi-box update --rollback            # put back what the last update replaced

It asks you to type the box name to confirm, unless run with --yes (needed when there is no terminal to confirm on — a script, a timer). It resolves the ref (or main) to a commit sha through the GitHub API before fetching, so nufi-box status can later say truthfully what commit the box is running; if the API is unreachable it fetches the ref directly and says sha unknown instead of guessing.

Then: it fetches the whole archive (deliberately — pulling just deploy/box out of it is a trick that only works on macOS's tar, and fails plainly on every Ubuntu box), backs up the box first (nufi-box backup), snapshots the current files — deploy/box, the two directories it depends on beside it, and the digest of every image running now — applies the new ones, and re-runs install-box.sh — the same installer day one used, which already keeps .env and every answer and secret, so an update never re-asks the four questions. Each run downloads about 185 MB and unpacks about 340 MB in a temporary directory, removed once the update finishes either way.

Then it runs nufi-box doctor. If that passes, you are done. If it fails — or if the installer itself fails, or the file copy does — update rolls back on its own — the files and the images go back to what they were, the stack restarts, and it prints where the backup from this run landed. It does not restore that backup automatically: your data is meant to carry forward across an update by design (migrations), and putting the database back is a decision for a person holding the backup's path (nufi-box restore <path>), not something a failed check should do by itself.

Not signed yet. The archive comes straight from GitHub over TLS — the same transport a browser gets, nothing more. There is no signature on it and nothing checks one. A signed bundle from updates.nufi.me is the next phase (see the README's "What is not built yet").

Something is wrong

./nufi-box doctor              # first — what, in plain words
./nufi-box support             # then — package it up to send

support gathers what an engineer actually needs for the first reply on a support thread — the box's version, docker compose ps, doctor's own output, the last 300 lines of every service's logs, the compose config, and a few small files (schedules.ini, caddy/mesh.caddy, a per-department folder listing, the data/backup listing) — into one .tar.gz next to data/support/ (or wherever --to DIR says). It prints the path, the size, and who to send it to.

Nothing in it is a secret. env-keys.txt lists the names of every key in .env and whether each has a value, never the value — and never a fragment of one, since it reads .env as entries rather than lines, so a multi-line secret (the console's signing key is a PEM) counts as one key, not one per line of it. compose.yml is docker compose config with every value that looks like a secret — a .env key ending in _KEY, _SECRET, _PASSWORD, PEM, TOKEN or _IV — blanked out everywhere it appears, and again by that entry's own name. Every other file in the bundle goes through the same value-level redaction before the tar is made — a log line, not just compose.yml's own rendering, can carry a secret too. No document's name ever leaves the box either: the bundle lists each department's folder and a file count, never a file's name. It works on a box that will not start and one whose doctor is failing: a check that cannot answer says so in the bundle instead of stopping the rest. The one thing that does stop it is the sweep itself — it needs python3, and without a working one the bundle is not packed: support prints NOT SWEPT, leaves the raw directory behind with a README.txt that says so, and exits non-zero.

This is the local half only. support does not open a connection from Dudaji into the box, and nothing on the box listens for one — that remote half is still not built.