Updates

Changelog

What's new in Nova.

Integrations load on demand — smaller prompts, sharper tool use

  • Lazy MCP tool loading — connected integrations no longer inject every tool schema into every LLM call. Each server now contributes a one-line capability index entry (~15 tokens: name, summary, tool count), and agents call a new load_integration_tools meta-tool to pull in a server’s real schemas only when a task needs them. Three installed integrations used to cost 10–25k prompt tokens per agent call; now they cost a few dozen until actually used
  • Small local models pick tools better — shrinking the tool list is a direct quality win for local models, which get measurably worse at tool selection as the list grows
  • “Always inject” opt-out per server — expand a server card on the Integrations page to switch a hot integration back to schemas-in-every-call. Pods that pin specific mcp__ tools in their allowlist also keep direct injection, no load step required
  • Nothing else changes — consent gating for mutating MCP actions, the permission UI’s per-server toggles, and the install/catalog flow all work exactly as before
  • Fixed: editing an MCP server wiped its metadata — the edit form now round-trips server metadata instead of resetting it
  • Fixed: one bad session id wedged conversation scoring — a non-UUID session id in usage events made every chat-scorer iteration fail; scoring now skips such rows

Local inference becomes a pool — run several backends at once

  • Named backend pool — local inference is no longer one active backend. The gateway now routes over a pool of named entries (bundled containers plus user-named remotes like remote-vllm-a, remote-vllm-b), each with its own URL, optional auth header, and discovered model catalog. Manage it on the Models page’s new Backend pool card
  • Model-aware routing — a request goes to the backend that actually serves the requested model (:latest aliasing included); anything unresolvable falls back to the first enabled entry with model substitution, so local-first keeps always answering
  • Two of the same engine, no confusion — entries are user-named, so two vLLM boxes are distinguishable, independently health-checked, and independently enable/disable-able
  • Zero-step upgrade — the pool seeds itself from the previous single-backend settings on first boot; bundled container start/stop and the Settings backend selector now write pool entries under the hood
  • First slice of the models/inference unified plan — role → (provider, model) fallback chains drawn from this pool come next

Runaway pipeline stages now get killed, not just noticed

  • Per-stage wall-clock timeout — every pipeline stage now runs under a wall-clock budget (pipeline.stage_timeout_seconds, default 15 minutes, Settings → AI & Pipeline → Execution & Context). A stage that exceeds it is actually cancelled in-process: in-flight LLM calls and tool rounds stop, and the task fails with a clear, retryable error naming the stage and the budget
  • Why it matters — the stale-heartbeat reaper only notices a task that goes silent. A stage that kept heartbeating while grinding through slow model calls could burn tokens indefinitely; now the reaper is just the backstop for a dead process
  • Safe with irreversible actions — cancellation composes with the tool idempotency ledger: a side-effecting tool killed mid-flight is recorded as fate-unknown, so a retry surfaces the ambiguity instead of firing the action twice
  • Tunable and escapable — raise the budget if your local models legitimately need longer; set 0 to disable the in-process kill entirely

API key changes apply live — no more restarts

  • Provider keys hot-reload — saving or removing an API key in Settings → AI & Models → Provider Status now applies to the running gateway within about a second. The “restart required” banner is gone, replaced by live-apply confirmation; provider availability dots flip on their own
  • Revocation is live too — removing a key drops the provider out of the failover chains immediately (unless a .env fallback value exists)
  • Fixed: dashboard-added keys missing from failover — previously a key that existed only in the encrypted secrets store (never in .env) worked for explicit model requests but silently never joined the automatic fallback chains, even after a restart
  • Faster recovery from a bad key — rotating a rejected key clears its 10-minute credential cooldown on the spot, so the fixed key is retried immediately
  • NVIDIA NIM key manageable from the UI — added to the Provider Status key editor alongside the other providers

Brain page & smarter model management

  • Brain page reborn — a live 3D view of Nova’s OKF memory at /brain, with three lenses (Galaxy, Orrery, Singularity), retrieval glow streamed over SSE as Nova thinks, click-to-inspect frontmatter with edit/delete, a free-flight camera, and a chat drawer that shares your main conversation
  • New memory endpointsGET /api/v1/memory/graph, PUT /api/v1/memory/item/{id} (edit in place), and GET /api/v1/memory/events (retrieval SSE)
  • Dynamic model recommendations — the Models page now pulls the live ollama.com popularity ranking (with real sizes, parameter variants, and links) or a curated list, and by default only shows models that fit your machine, plus cloud
  • Unified local model management — every local backend (Ollama, LM Studio, …) reads the same “on disk / in memory” table with Load/Unload; each store is its own labeled section so switching backends is unambiguous
  • Recommended cloud models with pricing — curated picks grouped by job with input/output $/Mtok and one-click use
  • User management — permanently delete users (not just deactivate), with history preserved unattributed
  • Fixed: LM Studio showing every downloaded model as “in memory”, the LM Studio Test button misrouting to cloud OpenAI, a stale-dashboard-after-deploy cache bug, and double-encoded audit-log JSON

Your Nova, your account: owner identity, safe defaults, monitoring inside the app

This release makes Nova yours in the literal sense: an account you create is the key to everything, the dangerous defaults are gone, and you can watch the autonomous brain work without leaving the app.

Accounts are the front door now. First boot asks you to create your owner account — name, email, password — and that’s the administrator credential from then on. Invite others with real roles (owner, admin, member, viewer, guest — each explained where you pick it), copy invite links any time, edit anyone’s name, email, role, and account expiry, and sign out from the new sidebar account menu. The .env admin secret still exists, but demoted to what it should be: break-glass recovery and automation, entered on the login page if you ever need it. Sign-in itself got hardened — brute-force throttling per IP and per account, with identical response timing whether an email exists or not.

Safe by default. Your home directory mounts read-only into agent sandboxes unless you explicitly opt into writes — a prompt-injected agent can’t touch dotfiles or keys on a default install. Network position no longer grants admin: being on the LAN lets you use Nova (chat, view, Inbox), but changing settings, reading secrets, or touching recovery always requires credentials, no matter where the request comes from. Fresh installs trust only localhost until you say otherwise.

Monitoring, embedded. An opt-in Grafana profile ships two provisioned dashboards over Nova’s own database — autonomy (goals, schedules, what the brain learned) and operations (throughput, spend, delivery receipts) — embedded at Infrastructure → Monitoring with your Nova session as the login. Same username, same password, no second sign-in; make observability starts it.

First boot, actually verified. The whole first-run path — onboarding gate, invite-exempt first registration, wizard setup authorized by your brand-new account, one-shot completion — is now walked end-to-end on a pristine instance as part of development, which is exactly how we caught (and removed) a leftover migration that had been silently breaking every fresh install.

The overnight shift got debugged too. Standing goals no longer double-fire outside their schedule, and if the morning-briefing agent fumbles its push notification, the briefing text itself still reaches your phone and Inbox through the completion notice.

Removed: the screenpipe workstation-capture experiment (service, UI, and docs) — six thousand lines lighter.

Nova reaches your phone: push notifications, human checkpoints, lockscreen decisions

Autonomous work is only useful if it can reach you when it matters. This release gives Nova a complete human-in-the-loop channel: push notifications to your phone, a way for agents to park mid-task and ask you for something, and one-tap decisions straight from the lockscreen.

Bundled push notifications (ntfy). Nova now ships its own self-hosted ntfy server — no cloud account, no phone-number registration. Approvals, task failures, review/clarification requests, and finished goal work publish to a private random topic (the topic name is the subscription secret). Install the ntfy app, subscribe, done. Interactive chat tasks deliberately don’t buzz your phone; autonomous work does.

Human checkpoints: agents can ask for help mid-task. A new request_human_checkpoint tool lets the Task Agent stop on things only a human can do — solve a CAPTCHA, provide an emailed verification code, make a judgment call — without losing its place:

  • The task parks in a new waiting_human status with its full conversation snapshotted; a checkpoint card appears in Pending Approvals and pushes to your phone.
  • Your reply (typed in the card or the task’s new Checkpoint tab) is injected back as the tool’s result, and the agent resumes exactly where it stopped — no re-running, no double-submitted forms.
  • If the agent was driving a browser, it attaches a screenshot of the page it’s parked on, so you see what it sees.
  • Declining also resumes the task — the agent is told to wrap up gracefully instead of stranding. Unanswered checkpoints cancel after 24h.

Lockscreen decisions. Set the dashboard URL your phone can reach (Settings → Notifications → Lockscreen actions) and approval/checkpoint pushes carry Approve/Deny buttons that decide directly from the notification. Each button is a signed one-shot link — an HMAC scoped to that single approval, decision, and expiry, minted with a server-side key that never leaves the machine. No admin secret on your phone, nothing to steal from the notification history, and a spent or tampered link is rejected.

A morning briefing, delivered. The channel’s first standing use: a seeded Morning briefing goal distills yesterday’s journal and fresh intel into one push a day (11:00 UTC by default — it’s a normal scheduled goal, edit it in Goals). It rides the new send_push tool: informational pushes any agent can send, storm-braked at 10/hour — the counterpart to request_human_checkpoint for messages that don’t need an answer.

An Inbox, so the phone is optional. Everything Nova sends — briefings, agent messages, task outcomes — also lands in a dashboard Inbox with unread badges and full message bodies. Delivery receipts and a live connected-subscriber count in Settings make the push channel honest: “accepted by ntfy” is not “delivered to a device”, and when nothing is subscribed, Nova says so instead of glowing green.

Scheduled goals actually fire now. Two fixes surfaced while wiring the briefing: migration-seeded schedules (nightly memory curation, intel sweeps) were never armed — cortex now initializes any cron goal it finds unscheduled — and a scheduled goal’s instructions now reach the executing agent verbatim instead of as a lossy one-line paraphrase.

Bundled inference containers return; memory goes all-in on markdown

Two structural changes land together: Nova can run local inference itself again, and the legacy engram memory backend is gone.

Bundled local inference (hybrid). Four inference servers now ship as opt-in Docker Compose profiles — Ollama, vLLM, SGLang, and llama.cpp — started and stopped from Settings → Local Inference (or COMPOSE_PROFILES in .env). External servers keep working exactly as before; LM Studio and Custom endpoints stay external-only.

  • Several containers can be warm at once; the active backend selection switches instantly between them (the gateway just swaps its routing URL).
  • Model storage is configurable: point OLLAMA_MODELS_DIR at an existing ~/.ollama, HF_CACHE_DIR at your HuggingFace cache, or LLAMACPP_MODELS_DIR at a GGUF folder — no re-downloading.
  • GPU acceleration comes from a docker-compose.gpu.yml overlay that the installer activates only after positive NVIDIA detection. vLLM/SGLang starts are refused on CPU-only hosts with an actionable message; Ollama and llama.cpp run fine on CPU.
  • The recovery service owns the container lifecycle and writes/clears the in-network routing URL on start/stop — which also fixes the long-standing stale-inference.url bug after backend switches.
  • The ./install wizard’s “All-in-one” mode now actually works: it enables the bundled Ollama profile, prompts for the model directory, detects GPUs, warns about port 11434 collisions with a host-run Ollama, and pulls the default model.

Engram memory backend removed. The OKF markdown bundle — a folder of markdown files with OKF frontmatter, BM25 retrieval, no embeddings, no Postgres — is now Nova’s only built-in memory backend (external providers can still plug in via memory.provider_url). Removing the frozen pgvector graph deleted ~14k lines: the engram engine, its 20+ Postgres tables’ worth of schema, the 3D Brain visualization, and the engram-only dashboard surfaces (Sources domain summary, User Profile, Memory Health, Consolidation/Self-Model settings). Backups now capture the memory folder itself — memory lives in files, and pg_dump alone would miss it. Your memory is a directory you can cat, grep, and git.

Memory subsystem hardening — two production-cliff queries fixed, real-DB test infrastructure

Five sprints of work on memory-service/app/engram/ close two scaling-cliff queries that would have stalled the subsystem at production scale, plus 214 unit tests on what was previously the most under-tested complex code in Nova.

  • Spreading-activation cliff fixed (P1). The recursive CTE used to join engram_edges on (source_id = X OR target_id = X) — an OR predicate that defeated both single-column edge indexes and forced Postgres into a Bitmap-OR plan. Rewritten as a single recursive reference with a LATERAL UNION ALL of two indexed branches (source-side + target-side), each with a per-hop fan-out cap (default 50) and a tenant filter on the neighbor join. The activation deep-mode follow-up got the same treatment: 1.507 ms → 0.129 ms (~12× speedup) measured on a 4156-engram database.
  • Consolidation merge cliff fixed (P2). The duplicate-merge phase used to do an O(N²) cartesian self-join over engram embeddings, generating 5.7M candidate pairs in 2.68s on the same database. Replaced with a per-candidate HNSW shortlist (top-K nearest neighbors of the same type/source_type, SET LOCAL hnsw.ef_search = 40 for stable top-K) plus a loser_ids exclusion set so popular winners can absorb additional duplicates within a cycle.
  • Schema-synthesis batched. The coherence-gate that compares each source engram’s embedding against a synthesized schema’s embedding used to make 5 round-trips per cycle (one per source). Now one batched WHERE id = ANY(...) query.
  • Working-memory dedup. assemble_context used to call get_embedding(query) twice — once for neural-router rerank, once for retrieval logging. Now computed at the top of the function and reused.
  • memory-service connection reuse. Eight per-call httpx.AsyncClient(...) sites collapsed to one shared singleton (get_http_client()) registered in the FastAPI lifespan. Mirrors the existing get_redis() pattern.
  • Real-Postgres + pgvector unit-test fixtures. New conftest.py provides db_session (per-test BEGIN/ROLLBACK), redis_test (db15 with FLUSHDB), engram_factory, edge_factory, fake_llm (replay+record with prompt-hash normalization), graph_builder, and a JSON snapshot helper. The previous mock-based fixtures are quarantined in conftest_legacy.py. 214 tests run end-to-end on real services in ~6 seconds.

If you’re upgrading: schema changes are additive and run automatically at memory-service startup. The 214 unit tests are gated behind cd memory-service && uv run scripts/setup_test_db.py && uv run pytest tests/ — you only need them if you’re modifying the engram subsystem.

A handful of spec/code mismatches surfaced during the test sweep — working_memory.py’s “five-tier slot system” is a DB-schema artifact only (no runtime promotion/demotion), decompose() is pure (no DB writes; persistence happens in ingestion.py), and reconstruction.py does no token-budget truncation (the caller is responsible). Tests now document the actual contracts; reconciling docs/audits with reality is follow-up work.

Platform secrets — provider keys + bridge tokens move out of writable .env

The platform_secrets store introduced for the Capability Platform now backs all sensitive runtime config — provider API keys, chat-bridge tokens, OAuth client secrets — not just user-granted GitHub PATs.

  • LLM gateway boots with provider keys read from platform_secrets (DB-backed, encrypted at rest) instead of .env. The dashboard’s Provider Status panel writes/rotates keys via the admin API; nothing edits .env at runtime.
  • chat-bridge boots with Telegram and Slack tokens read from platform_secrets. The bridge service no longer needs raw tokens in any process environment after the secrets land in the DB.
  • Recovery service rejects writes to secret-bearing keys via its /env editor — operators are nudged toward the proper Settings UI flow rather than .env poking.
  • Worker services (intel-worker, knowledge-worker) use a shared PlatformSecretsResolver to fetch their dependencies (HuggingFace tokens, RSS feed creds, etc.) at startup with the same encryption + audit guarantees.
  • Recovery’s Docker SDK gated behind socket-proxy (SEC-006b). Recovery no longer has direct access to /var/run/docker.sock; it talks to a tightly-scoped socket-proxy that allows only the operations recovery actually needs (compose up/down, container inspect for health). Reduces blast radius if recovery’s API is ever compromised.

Migration is automatic on first restart: the orchestrator’s startup handler reads any secret-bearing keys still in .env, writes them into platform_secrets, and logs a one-time notice. Subsequent restarts read from platform_secrets only. To rotate, use the dashboard or the admin API — direct .env edits to provider keys won’t take effect until a platform_secrets upsert runs.

Capability Platform — credentialed tools, consent gate, audit log, autonomous CI triage

The Capability Platform (M11) gives Nova the safe-by-default rails to act on external systems with user consent: a credential vault, an HMAC-signed audit log, a consent-gate workflow, and the first end-to-end autonomous “see a failing CI build → propose a PR” loop.

  • Encrypted credential vault. A platform_secrets store with per-secret AES encryption (master key auto-bootstrapped on first install) holds OAuth tokens, GitHub PATs, and service credentials. Secrets are referenced by name; runtime fetches happen via PlatformSecretsResolver so the orchestrator and worker services no longer read raw API keys from .env.
  • Hash-chained audit log. Every credentialed action — credential read, tool execution, approval decision — appends to an append-only audit log with a SHA-256 hash chain that ties each row to the previous. The maintain drive in cortex verifies the chain daily and pages on tampering.
  • Consent gate. New external tools declare a tier — READ (auto), PROPOSE (auto), MUTATE (consent required) — and MUTATE calls land in an approval_requests queue. The dashboard’s Approvals panel shows pending requests; a single approval/denial closes the loop, and a worker resumes the originating agent goal automatically. “Approve and remember” rules let users pre-authorize categories of action.
  • GitHub provider, four tiers. Twelve github_external tools cover READ (list_repos, get_pr, get_check_runs), PROPOSE (open_draft_pr, comment_on_pr), MUTATE (open_pr, merge_pr, close_pr), and SETUP (register_webhook, add_collaborator). Granted PAT scopes are captured at validation time; tools surface scope_mismatch warnings before attempting privileged calls.
  • Autonomous CI triage drive. Cortex’s new ci_triage_agent pod watches GitHub webhooks → check_run failures dispatch a stimulus → the goal pipeline proposes a fix PR. A singleton-elected polling worker provides a fallback when webhooks lag. The drive enforces a per-cycle cost budget and audits its own actions.
  • v1 release gate closed. Commit cf26c927 lands the automated end-to-end test that proves the full webhook → cortex → goal → PR loop works without human intervention on the happy path. This is the milestone where Nova first acts autonomously on a user’s repo.

If you’re upgrading: connect a GitHub PAT in the Settings → Connections panel, then watched_repos in the Connected Services section. The Approvals panel shows what Nova wants to do; nothing MUTATEs without explicit approval (or a matching auto-approve rule).

Inference modes — bundled Ollama by default

Nova now asks how you’d like to use it on first run, and ships sensible defaults for each option:

  • hybrid (default) — bundles Ollama for local AI, falls back to cloud providers when needed. Best of both worlds. First-run downloads ~5.4 GB of starter models (qwen2.5:1.5b, qwen2.5:7b, nomic-embed-text).
  • local-only — bundles Ollama, never uses cloud. Privacy-first or offline-friendly. Same ~5.4 GB starter models.
  • cloud-only — does not bundle Ollama at all (no image pull, no container, no model downloads). Lightest footprint, requires cloud API keys.

After install, switching modes (and pointing Nova at an external Ollama / vLLM instance like http://192.168.x.y:11434) lives in the dashboard — Settings → AI & Models, no scripts. The first-install prompt is just the bootstrap step before the dashboard is running.

Under the hood: a single user-facing NOVA_INFERENCE_MODE knob now derives both COMPOSE_PROFILES (whether the bundled ollama Compose service ships and starts) and LLM_ROUTING_STRATEGY (how the gateway picks providers). The setup.sh wizard writes both to .env idempotently, preserving any unrelated profiles you already have set.

Heads-up for existing installs: if your .env previously had OLLAMA_BASE_URL=auto or OLLAMA_BASE_URL=host and you depended on the gateway probing your host’s Ollama instance (Windows/macOS native install, remote LAN box, etc.), those values now resolve to the bundled service (http://ollama:11434) instead. The brittle subprocess-based probe (and scripts/resolve-ollama-url.sh) is gone. To keep using your host’s Ollama, set OLLAMA_BASE_URL to a literal URL — e.g. OLLAMA_BASE_URL=http://host.docker.internal:11434 for a same-host install, or OLLAMA_BASE_URL=http://192.168.x.y:11434 for a LAN box.

Security hardening — admin secret, OAuth state, recovery guards

Five interlocking security gaps closed in one chain:

  • Admin secret no longer impersonates users. The X-Admin-Secret header used to silently authenticate user-context endpoints — every fresh install was effectively “log in as anyone” by header. Now UserDep is JWT-only; admin secret authenticates admin endpoints only. Worker services (intel-worker, knowledge-worker) were unaffected because they already hit admin endpoints exclusively.
  • Random admin secret on install. scripts/install.sh generates a 32-byte URL-safe NOVA_ADMIN_SECRET when .env contains the literal default, an empty value, or no value at all. The generated secret is displayed once at the end of install with a “save this to your password manager” prompt. Orchestrator, recovery, and cortex now refuse to start with the literal default unless NOVA_ALLOW_DEFAULT_ADMIN_SECRET=1 is set (escape hatch for tests/dev).
  • Recovery service hardened. CORS allowlist replaces wildcard. Critical services (postgres, redis, recovery itself) cannot be restarted via the API — operators must use docker compose restart from the host where the consequences are obvious. Container matching switched from substring (if name in c.name) to exact com.docker.compose.service label, so restart_service("post") no longer accidentally matches postgres.
  • Cortex CORS allowlist. Same wildcard → settings-driven allowlist fix as recovery; cortex now matches the orchestrator pattern.
  • OAuth CSRF protection. Google OAuth flow now requires a state parameter. /api/v1/auth/google mints 32 bytes of URL-safe random state, stores it in Redis with a 10-minute TTL, and returns it alongside the consent URL. /api/v1/auth/google/callback validates state via GETDEL (single-use) and uses the Redis-stored redirect_uri rather than any client-supplied value — closing both CSRF and redirect_uri-tampering vectors. PKCE is a follow-up.

If you’re upgrading: rerun ./scripts/install.sh to regenerate your admin secret (or set a strong NOVA_ADMIN_SECRET manually). The Redis runtime override at nova:config:auth.admin_secret still wins at runtime — clear it with docker compose exec redis redis-cli -n 1 DEL nova:config:auth.admin_secret if it has drifted from .env.

A few intentionally-deferred items get their own future work: a built-in secret manager (which will absorb a “rotate from dashboard” feature), service-account JWTs to replace X-Admin-Secret for internal worker calls, OAuth PKCE, and retiring the admin secret entirely in favor of an is_admin JWT claim. The current chain shrinks blast radius enough that those become value-adds, not emergencies.

./uninstall — clean removal in one command

Nova now ships with a top-level ./uninstall script that removes everything Nova installed on the machine: containers, networks, named volumes, locally-built Docker images, the bind-mounted data/ directory, backups/, .env and its backups, build artifacts (dist/, node_modules/, __pycache__, .pytest_cache), and the agent workspace at ~/.nova/workspace/.

The flow is preview-first: ./uninstall always shows you exactly what will be deleted, broken down by category with disk-size totals, before asking for an explicit uninstall confirmation. Pass --dry-run to see the preview without any destruction, or --yes to skip the confirmation in scripted contexts.

The cloned repo source itself is left intact (delete it manually with cd .. && rm -rf nova if you want), and shared upstream Docker images (ollama/ollama, pgvector/pgvector, redis, etc.) are NOT touched — they may be in use by other Docker projects on the same machine. Use docker image prune -a separately if you want a deeper sweep.

For routine “reset Nova to a clean slate while keeping it installed,” use the in-app factory reset under Settings → System. ./uninstall is for “Nova is leaving this machine.”

Also in this release: the top-level setup script and scripts/setup.sh have been renamed to install and scripts/install.sh to match the conventional install/uninstall pairing. The make setup target is now make install.

One-line install + --help everywhere

Two small DX improvements that make Nova nicer to start and nicer to live with.

scripts/bootstrap.sh + curl-pipe-bash one-liner. New users can now install Nova with a single command:

Terminal window
curl -fsSL https://raw.githubusercontent.com/jeremyspofford/nova/main/scripts/bootstrap.sh | bash

The bootstrap script checks for git and docker, clones the repo (defaults to ./nova, override with NOVA_DIR=<path>), and re-attaches the install wizard to the controlling terminal so you land directly in the mode-selection prompt. Pass --no-install to clone without launching the wizard, or just keep using the git clone && cd nova && ./install flow if you’d rather audit the source first — both routes hit the same wizard.

--help on every script. Every user-facing script (./install, ./uninstall, scripts/install.sh, scripts/backup.sh, scripts/restore.sh, scripts/setup-remote-ollama.sh, scripts/detect_hardware.sh, scripts/bootstrap.sh) now responds to --help / -h with a clear usage block — what the script does, how to invoke it, what flags and environment variables it accepts. No more “what does this script even do” — just append --help.

Voice Chat & Conversation Mode

  • Voice service (voice-service, port 8130) — STT via OpenAI Whisper, TTS via OpenAI TTS with provider abstraction for Deepgram and ElevenLabs
  • Conversation mode on Brain page — Gemini-style hands-free voice loop with auto-listen, silence detection, and barge-in interruption
  • Barge-in support — start talking while Nova is speaking to interrupt her mid-sentence; warm mic pattern eliminates turn-transition latency
  • Live transcription — real-time display of words as you speak (Web Speech API for live display, Whisper for final accuracy)
  • Audio level visualization — animated bars respond to mic input volume in real-time
  • Mute now immediately stops TTS playback mid-sentence (previously only prevented new sentences)
  • Model selector synced between Chat and Brain pages — change model from either and it stays in sync
  • Configurable voice settings: silence timeout (500ms-10s) and barge-in threshold (0.05-0.50) in Dashboard Settings
  • Voice service is optional — enable with --profile voice, dashboard auto-hides voice UI when unavailable

Managed Inference Backends

  • Added managed inference backend lifecycle — select vLLM or Ollama from the dashboard, Nova handles container start/stop/health
  • Hardware detection: auto-detects GPU vendor, VRAM, Docker GPU runtime at setup and runtime
  • New LocalInferenceProvider in LLM gateway wraps the active backend with 5-second config cache
  • Backend switching with drain protocol: zero dropped requests when switching between backends
  • New Settings section: Local Inference (AI & Models tab) with backend selector, live status, hardware info
  • Recovery service now manages inference containers via Docker Compose profiles with health monitoring (30s interval, exponential backoff restart)
  • vLLM model discovery via /v1/models endpoint
  • In-flight request tracking (GET /health/inflight) enables graceful drain during backend switches
  • Redis db7 allocated for recovery service (nova:system:* namespace for system facts)

Remote Access & Navigation

  • Added Remote Access page with Cloudflare Tunnel and Tailscale setup wizards
  • Updated NavBar with improved navigation structure
  • Expanded MCP server catalog with new entries

Shared UI & Mobile

  • Introduced shared UI primitives for consistent component design
  • Fixed mobile layout overflow across all dashboard pages
  • CSS deduplication pass

Recovery Service

  • Added recovery sidecar service for backup/restore and factory reset
  • Database backup/restore via CLI and web UI
  • Service management with Docker SDK integration
  • Startup screen showing services coming online

Platform Hardening

  • Fixed MCP tools invisible to agents
  • Added test foundation with pytest fixtures
  • Fixed streaming token counts for subscription providers
  • Fixed reaper race condition with Redis dedup gate
  • Structured JSON logging across all services
  • Embedding cache activation (3-tier: Redis, PostgreSQL, LLM Gateway)
  • Working memory cleanup background job

Dashboard MVP

  • Overview page with live agent cards
  • Usage analytics with monthly/weekly/daily charts
  • API key management with one-time reveal
  • Models page showing 39 models grouped by provider
  • Dark mode and theme system
  • Settings page with provider status, context budgets, and admin controls