Skip to content

Installing & updating

Alex Kollar edited this page Nov 10, 2026 · 11 revisions

Installing Navi, and keeping her up to date

Navi lives on your own computer — the app, her model, her memory, and her voice are all on your machine.

Right now Navi installs on Linux. That is the one installer in the package: install.sh. How you run it depends on where your copy came from — from the release zip, run ./install.sh (its scripts arrive executable, so that just works); from a git clone or GitHub's source zip, run bash install.sh instead (the paragraph below explains why, in plain words). Windows and macOS installers are planned for later — they are not in this package yet, so there is nothing to run on those systems today.

  1. Download the app package and unzip it — or clone the repo / unzip GitHub's source zip, and use bash install.sh in the next step instead of ./install.sh.
  2. Run the Linux installer: ./install.sh from the release zip, or bash install.sh from a clone or source zip. It asks one question: should her model start when the app opens, or when the computer boots? Either is fine.
  3. The installer downloads her model file (big — about 3 GB — so this takes a while) unless it is already there. It never downloads it twice.
  4. It also offers her voice, and sets up the tool that builds her window, the same way — say no and she still works; she just cannot talk out loud yet.
  5. It looks at your machine — the processor and its cores, how much memory, the graphics chip — and picks her thinking settings to fit it: how many CPU cores, how big a context, how much she reads at once, and whether the graphics chip helps. A modest machine gets the gentle, proven numbers; a strong one gets more. It writes what it found and why into hardware-profile.log, and you can see or change the result later in Settings.
  6. Open Apex from your app menu. Her own window opens — no web browser. That window is the app.

On Linux she installs into /opt/navi-apex. Her window talks to a small helper program (the bridge) at port 8675, and the bridge talks to her model at port 8080. Your things are safe: updating, reinstalling, and even a fresh install (--fresh) keep what is yours — her model file, installed chips and knowledge packs, the vault, the DHD certificate home (config/dhd/ — a real certificate there is never wiped by a reinstall), her Soul and Memory pages, her voice and its models. A first install is the only true blank start.

One installer, every major Linux family. The installer reads your distro from /etc/os-release and says out loud which family it found. Only its dependency step changes with the family — the same development libraries and base tools, under each family's own package names:

  • Debian family (Debian, Ubuntu, Pop!_OS, Mint and their kin) — installed with apt.
  • Fedora and Fedora-based distros — installed with dnf.
  • Arch and Arch-based distros — installed with pacman.
  • Bazzite — Fedora-based but immutable, so it is its own case (below).

Everything else — profiling your machine, the model download, what an update keeps, the startup choice — is the same on every family. On Bazzite the installer never layers packages onto the system with rpm-ostree and never asks for a reboot: her window is built inside a Fedora distrobox when you have one, and when you don't, the window build is skipped — in plain words, during the install — and you get the complete core install: the bridge and the dashboard, which start.sh opens in your browser. Create a Fedora distrobox later and re-run the installer to add the window. And if your distro isn't one the installer recognizes, it says so, guesses no package manager, installs everything it can user-space, and completes the core install just the same.

Installing from a git clone — or from GitHub's source zip (the zip the green Code button offers, the one that unpacks to a folder like Apex-main) works too — with two honest differences. First, how you run it: from a clone or a source zip, the way is bash install.sh — and bash start.sh when you start her from that source tree. Run it through bash because it needs no executable permission. Why, in plain words: the git tree does not preserve the scripts' executable permission, so every script that comes out of a clone or a source zip arrives without it, and a script without that permission cannot be run as ./install.sh until the permission is set — running it through bash skips that entirely, because bash reads the file itself. From the release zip it is the other way round: its scripts arrive executable, so ./install.sh is the instruction there. Release zip → ./install.sh; clone or GitHub source zip → bash install.sh. If you try ./install.sh from a clone anyway, you will meet a baffling pair of errors — bash answers Permission denied, and sudo ./install.sh answers command not found, which sounds like the file is not there at all. It is there; it just cannot be run that way. Use bash install.sh and both errors go away. (If you prefer ./install.sh, you can set the permission yourself first — chmod +x install.sh start.sh run-llamafile.sh — and then run it the usual way. That works too; bash is simply the shorter path, and the one these instructions lead with.) Second, the icons: the clone does not carry the binary icon files (the app icon, its .ico/.icns renditions, and her window's icon): those ship only inside the release zip. So a clone install runs without the custom icon — the installer says so in plain words while it installs, the app and its menu entry use a fallback icon, and her standalone window is not built, because it is built around that icon; she opens in your browser instead. Everything else about the install is exactly the same. The release zip remains the complete package.

Updating is real, and it works like this. The Updater tab (and one quiet automatic check each time she starts) asks GitHub for the project's latest release on her channel and compares its tag with her VERSION file. The channel is a setting the Updater remembers: Stable (the default) follows full releases only — the latest full release from main — while Edge follows the newest release including pre-releases, from the dev branch. So the check, the comparison and the apply are all channel-aware. If a newer release exists, the single line under Navi's status in the status column flips to a yellow Update available. The Updater screen shows that release's notes right there — the words from its GitHub release page, or, when the release page carries none, the matching section of the project's CHANGELOG — so you can read what changed before you press the button. An About this release dropdown in the Updater carries everything that release's GitHub release page offers — name, tag, Edge/full badge, published date, the link, the package asset, and the full patch notes rendered in place — and when no release exists yet for the running version, it says so honestly instead of inventing one. Press Download & install and she does the whole job from that one click: the release package is downloaded, checked (it must be a real Apex package — and a package that arrives gzip-wrapped is unwrapped and accepted, not refused), and unpacked beside the app, under updates/; then a small helper that outlives the app runs that folder's installer with --startup and --voice from the install's own settings — never with --fresh, so everything that's yours is kept, exactly as the paragraph above promises — and relaunches her. While it works, the Updater names the step it is on — downloading, verifying, staging, installing, restarting. When she comes back, the Updater shows the confirmation in plain words — Updated v0.1.7 → v0.1.8 with the actual versions — and only when the VERSION file after the restart reads the version the update promised. If any step fails, the Updater names the step and the reason, nothing is left half-applied that can be rolled back, and — once the package was staged — it shows the manual fallback as a fallback: the staged folder and the one command that finishes the job by hand, running that folder's ./install.sh --startup <launch|boot> --voice <yes|no> in a terminal — flag-complete, with both values from the install's own settings (startup from the config; voice counts as installed when her venv is on disk), so the update never depends on the staged installer being able to ask anything. A terminal counts only if it opens: the installer tests opening /dev/tty instead of checking whether the device node is readable, so a terminal-less run gets the plain instruction to re-run with --startup launch|boot (and --voice) instead of dying mid-prompt. And if a check cannot reach GitHub — no network, or GitHub's rate limit — the Updater says that, in those words, instead of pretending you are up to date.

An update either flips fully or stays on the old version. The installer carries the new bridge and VERSION under staged names and flips them only as its final act — the config's version record first, the VERSION file last of all — so a step that fails before the flip leaves every version witness reading the old build, and Check for updates honestly offers the update again instead of declaring a broken install current. And the Updater reports the outcome in plain words, in three states: installed, not installed, or installed, with a tail failure in the named step — when the installer exits nonzero after the flip but the target build is standing on disk, the step is named from the install log. The manual fallback text remains for the case that earns it: nonzero exit, old build still standing.

Updates never need a reboot. When an update runs, the installer first proves the old bridge is stopped — it finds it by its pid file, by the process holding the port, or by its working folder, waits for it to stop, and ends it by force if it will not go politely. If the port still cannot be cleared, the install stops before replacing any file and names the process holding the port, with the exact command that ends it. A manual install over a running Apex relaunches her at the end and verifies the new build is answering before it says Done (—no-relaunch installs without relaunching, and says plainly that Apex is not running). If a dashboard stays open across an update, it notices the bridge is newer than the page and offers a Reload button at the top of the status column.

Turn Sudo Mode on before you update. The installer's system step needs root, and without it an update can stall or finish without its system packages — field-proven the hard way. So when an update is available and Sudo Mode is off, the Updater shows a red warning directly above the Download & install button: Enable Sudo Mode before updating. Turn Sudo Mode on (in the status column) and the warning is replaced by a quiet green Sudo Mode is on — ready to update. It is a warning, not a lock — the button still works, because you may know your machine needs nothing new.

Once you opt in, the install chain moves. The moment you press Download & install, the step chain — downloading, verifying, staging, installing, DHD prerequisites, restarting — appears directly above the release notes, with a slim progress bar across the top of its card: the bar for the glance, the chain for the receipts. And if the Installing step runs long, the chain says why, in place: Taking a while? This step is likely rebuilding the UI — that can take a few minutes on modest hardware. It's working, not stuck. We're working on making it faster. No countdown and no ETA — on a modest machine an honest note beats a lying estimate.

One file says which version she is. At the top of the install folder sits a plain text file named VERSION. It holds the version number, and optionally a build status after it — full releases carry the bare number, like 0.1.8, which is what the current release carries; pre-releases are Edge builds with the e suffix, like 0.1.8e. The old alpha/"a" naming is retired, and older tags written that way still read correctly, as Edge — a stable build reads *v0.1.7*, an Edge build *v0.1.7e*. The number and the build status in VERSION are the only version the Updater trusts: reading them is how it knows whether a newer release exists, and matching them is how it confirms an update took. Every other thing you read about the version — the page, the status column, the installer — reads it from here too, so everywhere agrees. Installing an update replaces the VERSION file along with the rest of the app; no other place stores the version.

Clone this wiki locally