| 2026-10-07 |
deploy: runbook for updating a running instance
...
Adds deploy/UPDATE.md: preflight, the branch shapes (master vs the
tracked .env on deploy), what to rebuild before pushing (the frontend
dist is committed and the server never builds it), the verification
commands that prove the new bundle is the one being served, rollback,
and the traps — tracked secrets in mcp_servers.d/, gitignored vendor
kit dist, service-worker cache, Android app needing only a restart.
Linked from deploy/README.md.
Eugene Sukhodolskiy
committed
13 hours ago
|
| 2026-09-26 |

PWA: installable webclient, offline shell, web push
...
Installability:
- public/manifest.webmanifest (standalone, theme #16161E) + PNG icons
generated from logo.svg (regular + maskable, served via /images mount)
- index.html: manifest link, theme-color, apple-touch-icon
Offline shell:
- hand-rolled sw.js (no workbox): navigation = network-first (3s race)
with cached-shell fallback + background refresh (a stale cached shell
would 404 on entry chunks after a deploy); /assets/* cache-first
(content-hashed); /images/* cache-first capped; /api,/ws,/auth,/push,
/content pass-through
- vite closeBundle plugin stamps __NAVI_BUILD_VERSION__ (digest of
index.html + asset names) into dist/sw.js; sw.js served no-store so
every deploy reactivates the SW and activation evicts old caches
- SW registration in main.js, PROD only (dev HMR untouched)
- OfflineBanner (useOnline composable) over the app shell
Web push (VAPID, pywebpush):
- navi/push/ package: push_subscriptions table (postgres, boot-time DDL),
PushSubscriptionStore, PushService (async fan-out, to_thread sends,
404/410 prunes dead endpoints, per-session cooldown)
- routes: GET /push/vapid-key, POST/DELETE /push/subscribe (auth-gated)
- trigger in orchestrator run_agent + run_recall: push on StreamEnd when
no WebSocket client watches the session; fire-and-forget, never
disturbs the run; anonymous fallback only when auth is off
- client: usePush composable + Notifications settings panel (enable/
disable via PushManager.subscribe with the server VAPID key)
- notification click focuses the app at /#<session_id> (hash routing
opens the right chat); payload body is a markdown-stripped <=140-char
preview
NAVIVAPID keys empty = push fully disabled (graceful, like other optional
integrations). dist/ artifacts committed per repo convention.
Tests: pytest push store/service/routes/trigger (+23), vitest usePush
(83 webclient tests green). Full suite 1143 passed.
Eugene Sukhodolskiy
committed
11 days ago
|
| 2026-09-10 |
deploy: NAVI_HOST=0.0.0.0 — fresh installs join the swarm peer channel
...
Fresh deployments were 'visible but deaf': announcements to the hive are
outbound and worked, but inbound /peer/* connections hit the localhost-only
bind and failed with ConnectError. 0.0.0.0 makes the peer channel work;
127.0.0.1 stays documented for machines outside the swarm.
Eugene Sukhodolskiy
committed
27 days ago
|
swarm stage 2: peer-to-peer channel — /peer endpoints + peer tool
...
Server side (navi/api/routes/peer.py, port 8099):
- GET /peer/hello — open discovery ping (name, uuid prefix, version)
- GET /peer/status — PSK; identity, uptime, machine facts, hive view
- POST /peer/ask — PSK; one-shot agent run under PEER_ASK_PROFILE
(default server_admin) answers, one concurrent ask at a time
- loop guard: answering agent runs without the peer tool (deterministic
recursion cut) + own-uuid asks refused with 409
- verify_swarm_key in navi/swarm.py accepts .swarm-key.previous
(rotation window, constant-time)
Client side (navi/tools/peer.py):
- peer tool: list (hive book, stale cache fallback marked), status,
ask by swarm name; asks go direct peer-to-peer, hive never on the
message path
- audit events on both sides (peer.ask_sent/received/answered/failed)
peer tool added to server_admin, navi_code, developer profiles.
Eugene Sukhodolskiy
committed
28 days ago
|
| 2026-09-09 |
swarm stage 1: instance identity, PSK, hive registry, announce loop
...
- navi/identity.py: adjective-animal names + uuid in instance.json
(generated at install, renameable by hand)
- navi/swarm.py: HiveAnnouncer - periodic POST /announce to the hive
with non-blocking reachability tracking (transitional logs, /health
export, hive_status context provider reports outages to the agent)
- hive/: standalone FastAPI address book (SQLite, port 8087, PSK via
X-Swarm-Key with .swarm-key.previous rotation window, TTL online
status, host from client IP, port from payload). Not installed or
started by default - run manually on the main server.
- ports moved to 8099 (API) / 8098 (UI MCP)
- install.sh: PYTHONIOENCODING=utf-8 in the systemd unit, generates
instance.json and .swarm-key on fresh installs
Eugene Sukhodolskiy
committed
28 days ago
|
port: 8000/8001 -> 8099/8098 everywhere
...
navi runs on shared servers where 8000/8001 are usually taken. New
defaults: API 8099, navi_ui MCP 8098. Touched: config defaults
(navi_port, navi_ui_mcp_port, public_url, gnauth_redirect_uri),
navi-server launcher docs, env.template/.env.example, install.sh
health-check fallback, terminal client base_url, webclient dev configs
(useWebSocket, contentLinks, vite proxy), android url hint, docs.
Also made the navi_ui FastMCP constructor port settings-driven instead
of a hardcoded 8001 (it was overridden at start anyway).
Eugene Sukhodolskiy
committed
28 days ago
|
fix: ASCII-safe startup log messages + force UTF-8 stdout in the systemd unit
...
A unit on an old distro without a UTF-8 locale gets latin-1/ascii
stdout; structlog's print of the em-dash in the webclient-disabled
message raised UnicodeEncodeError and killed the app at startup
(Application startup failed, crash-loop restart counter 28). The unit
now sets PYTHONIOENCODING=utf-8 so any future non-ASCII log line is
safe too.
Eugene Sukhodolskiy
committed
28 days ago
|
deploy: auto-install docker compose v2 plugin when the host lacks it
...
Ubuntu 18.04's docker packages predate compose v2. The plugin is a
single static binary that runs on any distro with docker CLI >= 18.09,
so the script downloads it into /usr/local/lib/docker/cli-plugins
(system-wide — sudo docker compose sees it too) when docker compose is
unavailable, with the same offline pattern as the python tarball: a
pre-downloaded binary next to install.sh wins. If the CLI is too old
to support plugins at all, the error asks for docker --version.
Eugene Sukhodolskiy
committed
28 days ago
|
deploy: standalone CPython fallback for old distros
...
venv cannot be shipped in the repo — it embeds absolute paths and
distro-specific compiled wheels (asyncpg, uvloop, cryptography), so it
dies on any other machine. Instead, when the host has no python >= 3.11
(Ubuntu 18.04: 3.6, 22.04: 3.10; system python must not be replaced),
install.sh fetches a standalone astral python-build-standalone CPython
3.12 into .python/ — self-contained, needs only glibc >= 2.17, works
on any distro. The tarball is cached next to the repo and reused; on
offline servers a pre-downloaded tarball next to install.sh wins.
Verified locally: tarball layout, venv creation, pip install.
Eugene Sukhodolskiy
committed
28 days ago
|
deploy: pick the newest python >= 3.11 instead of hardcoding python3
...
Ubuntu 22.04's system python3 is 3.10 and must not be replaced (apt
depends on it) — a deadsnakes install lives under python3.11/3.12.
The install now tries those names before plain python3 and builds
the venv with whichever qualifies, with a hint in the error path.
Eugene Sukhodolskiy
committed
28 days ago
|
deploy: README opens with the full install breakdown
Eugene Sukhodolskiy
committed
28 days ago
|
deploy: regenerate placeholder secrets from the deploy branch's .env on first install
Eugene Sukhodolskiy
committed
28 days ago
|
deploy: one-command server bundle (dockerized postgres + systemd)
...
deploy/install.sh — everything in one command: prerequisite checks,
.env provisioning from env.template (generated DB password), dockerized
PostgreSQL (pgvector image, restart: always, bound to 127.0.0.1, vector
+ pg_trgm extensions), venv + pip install, a systemd unit with
Restart=always (the server lives from installation, per the roadmap
where these modules become each other's subagents), health check, and
navi-code/navi-server symlinks into PATH. Idempotent — safe to re-run.
Default deployed shape: web UI off, auth off, terminal client only.
Re-enabling the web panel later is editing .env + restart — nothing is
removed from the tree.
The deploy branch (next commit set) differs from master only by a
filled-in .env.
Eugene Sukhodolskiy
committed
28 days ago
|