All configuration is loaded from .env via pydantic-settings (navi/config.py). The global settings object is imported everywhere as from navi.config import settings.
| Variable | Type | Default | Description |
|---|---|---|---|
NAVI_DEFAULT_PROFILE_ID |
str | "" |
Default profile used when a client creates a session without specifying a profile_id. Empty string means "no default". |
| Variable | Type | Default | Description | |
|---|---|---|---|---|
OLLAMA_HOST |
str | http://localhost:11434 |
Ollama server URL (used when OLLAMA_BACKENDS_FILE is not set) |
|
OLLAMA_API_KEY |
str | "" |
Ollama Cloud API key (used when OLLAMA_BACKENDS_FILE is not set) |
|
OLLAMA_DEFAULT_MODEL |
str | gemma4:31b-cloud |
Default model (can be overridden per profile) | |
OLLAMA_NUM_CTX |
int | 65536 |
Context window size in tokens | |
OLLAMA_THINK |
bool | true |
Enable extended reasoning (thinking) | |
OLLAMA_BACKENDS_FILE |
str | "" |
Path to JSON file with multi-server config (see below). When set, overrides OLLAMA_HOST/OLLAMA_API_KEY. |
|
OLLAMA_REQUEST_TIMEOUT |
int | 30 |
Seconds before Ollama request times out (affects fallback speed) | |
EMBEDDING_OLLAMA_HOST |
str | "" |
Ollama server for embedding model (falls back to OLLAMA_HOST if empty) |
|
EMBEDDING_OLLAMA_API_KEY |
str | "" |
API key for embedding Ollama server | |
EMBEDDING_MODEL |
str | nomic-embed-text:latest |
Embedding model for memory vector search | |
EMBEDDING_DIMENSIONS |
int | 768 |
Vector dimensionality for embeddings | |
OPENAI_API_KEY |
str | "" |
OpenAI API key (if using OpenAI backend) | |
OPENAI_MODEL |
str | "gpt-4" |
Default model for OpenAI backend | |
OPENAI_BASE_URL |
str \ | None | None |
Custom base URL for OpenAI-compatible endpoints (e.g. vLLM, LM Studio) |
ANTHROPIC_API_KEY |
str | "" |
Reserved — no Anthropic backend implemented yet |
For direct Ollama Cloud access without fallback: set OLLAMA_HOST=https://ollama.com and OLLAMA_API_KEY=<key>.
| Variable | Type | Default | Description |
|---|---|---|---|
BRAVE_SEARCH_API_KEY |
str | "" |
Brave Search API key (free tier: 2000 req/month). Used when DuckDuckGo returns no results. |
SEARXNG_URL |
str | "" |
Self-hosted SearXNG meta-search URL, e.g. http://localhost:8888 |
OLLAMA_BACKENDS_FILE)When OLLAMA_BACKENDS_FILE points to a JSON file, Navi uses FallbackOllamaBackend instead of the single-server backend. The file contains an ordered list of servers:
[
{ "host": "https://ollama.com", "api_key": "ollama_..." },
{ "host": "http://localhost:11434" }
]
Each profile's model field is also a priority list (see docs/profiles.md). The fallback algorithm tries all combinations in a nested loop:
for each server (in order):
for each model (in order):
try → success: use this server+model
LLMConnectionError → blacklist server, skip remaining models, try next server
LLMModelNotFoundError → blacklist (server, model) pair, try next model
raise if all exhausted
Blacklisting is in-memory (module-level sets in navi/llm/fallback.py) and persists until server restart. A dead server or missing model is only probed once per process lifetime, avoiding latency spikes from repeated retries.
For streaming calls, the first chunk is awaited before yielding, so connection/model errors are caught before any output is sent to the client — clean retry with no partial response.
| Variable | Type | Default | Description |
|---|---|---|---|
LLM_COMPLETE_TIMEOUT |
int | 120 |
Seconds before a non-streaming complete() call times out |
PLANNING_LLM_TIMEOUT_SEC |
int | 240 |
Seconds before a non-streaming planning phase call times out (plan tool / subagent pipeline). Wider than LLM_COMPLETE_TIMEOUT — cloud models prefill big planning prompts for up to a couple of minutes, and a timeout here silently kills the plan. |
LLM_STREAM_FIRST_CHUNK_TIMEOUT |
int | 90 |
Seconds to wait for the first token of a streaming call (prefill phase) |
LLM_STREAM_CHUNK_TIMEOUT |
int | 60 |
Max seconds between consecutive tokens in a streaming call |
Large contexts can take 60–90 s to prefill; LLM_STREAM_FIRST_CHUNK_TIMEOUT=90 covers the common case for local Ollama. Increase (e.g. 180) for very large contexts or slow GPUs; reduce for fast cloud endpoints.
| Variable | Type | Default | Description |
|---|---|---|---|
FS_ALLOWED_PATHS |
str | "*" |
Comma-separated paths the filesystem tool can access. "*" = no restriction |
TERMINAL_ALLOWED_COMMANDS |
str | "*" |
Comma-separated allowed executables for terminal. "*" = allow all |
SSH_HOSTS_FILE |
str | ssh_hosts.json |
Path to JSON file with named SSH connections |
settings.fs_allowed_paths_list and settings.terminal_allowed_commands_list are computed properties that parse the comma-separated strings into lists.
| Variable | Type | Default | Description |
|---|---|---|---|
TERMINAL_USER_ALLOWED_COMMANDS |
str | long allowlist | Comma-separated allowed executables for non-admin users. Admin bypasses this restriction. |
settings.terminal_user_allowed_commands_list — computed property parsed from the comma-separated string.
| Variable | Type | Default | Description |
|---|---|---|---|
DATABASE_URL |
str | "" |
PostgreSQL URL (postgresql://user:pass@host:port/db). Required — Navi requires PostgreSQL 15+ with pgvector extension. |
| Variable | Type | Default | Description |
|---|---|---|---|
NAVI_WEBCLIENT_ENABLED |
bool | true |
Master switch for the web UI. false registers none of the web-facing routes (/, /assets, /images, /content-viewers, /content, /admin panel, /debug*) and skips the navi_ui MCP server — a pure API/WS server for terminal clients. The admin JSON API (/admin/*) stays, still gated by require_admin. Toggling requires a server restart. |
NAVI_HOST |
str | 127.0.0.1 |
Bind address for the navi-server launcher (uvicorn). 127.0.0.1 = local-only; remote clients connect via SSH tunnel or reverse proxy. |
NAVI_PORT |
int | 8099 |
Bind port for the navi-server launcher. |
Navi instances can form a swarm: each announces itself to a tiny registry service ("hive", see hive/README.md) running on the main server; agents ask the book who is alive and where. The registry is never a blocking dependency — with HIVE_URL empty, or with the hive down, everything else works and the agent is simply told the book is unreachable.
| Variable | Type | Default | Description |
|---|---|---|---|
HIVE_URL |
str | "" |
Hive registry address (e.g. http://192.168.1.168:8087). Empty = standalone navi, no announcements. |
ANNOUNCE_INTERVAL_SEC |
int | 120 |
How often this navi re-announces itself to the hive. |
SWARM_KEY_FILE |
str | .swarm-key |
Shared PSK file (gitignored, 0600, generated by deploy/install.sh). |
INSTANCE_FILE |
str | instance.json |
This navi's identity for the swarm: generated name (single female name from Japanese/American/Spanish pools) + instance id. Rename = edit the file, restart. |
PEER_ASK_PROFILE |
str | server_admin |
Which profile answers incoming /peer/ask questions (one-shot agent run). |
PEER_ASK_TIMEOUT_SEC |
int | 120 |
Hard ceiling for a single peer ask — the LLM turn inside /peer/ask. |
See deploy/README.md for the one-command server deployment (bash deploy/install.sh): dockerized PostgreSQL + systemd + navi-code in PATH, web UI and auth off by default.
| Variable | Type | Default | Description |
|---|---|---|---|
LOG_LEVEL |
str | INFO |
Python logging level (DEBUG, INFO, WARNING, ERROR) |
| Variable | Type | Default | Description |
|---|---|---|---|
TOOLS_DIR |
str | tools |
Directory for user-defined tools (auto-discovered at startup) |
CONTEXT_PROVIDERS_DIR |
str | context_providers |
Directory for user-defined context providers (auto-discovered at startup) |
user_key (BYOK)Per-server JSON config (mcp_servers.d/<name>.json) — where a user's personal credential is injected. Details in mcp.md.
// HTTP server: key goes into an Authorization-style header
{ "transport": "streamable_http", "url": "https://…",
"user_key": { "header": "Authorization", "prefix": "Bearer " } }
// stdio server: key goes into an env var
{ "transport": "stdio", "command": "uvx", "env": { "API_KEY": "default" },
"user_key": { "env": "API_KEY" } }
Keys are stored Fernet-encrypted (NAVI_AUTH_ENCRYPTION_KEY, see Authentication above). Users without a saved key fall back to the default credential from the config file.
| Variable | Type | Default | Description |
|---|---|---|---|
SESSION_FILES_DIR |
str | session_files |
Directory for uploaded session files |
SESSION_FILES_MAX_SIZE_MB |
int | 200 |
Max upload size per file in megabytes |
SHARE_FILE_MAX_SIZE_MB |
int | 1024 |
Max file size share_file may copy into session files, in megabytes |
SESSION_MESSAGES_WINDOW |
int | 1000 |
Max hot (non-archived) messages per session |
WS_REPLAY_BUFFER_SIZE |
int | 500 |
Max events retained per WebSocket turn for reconnect replay |
| Variable | Type | Default | Description |
|---|---|---|---|
PUBLIC_URL |
str | http://localhost:8099 |
Base URL used by share_file to build download links. Set this when behind a reverse proxy. |
| Variable | Type | Default | Description |
|---|---|---|---|
CONTEXT_COMPRESSION_ENABLED |
bool | true |
Enable/disable automatic context compression |
CONTEXT_COMPRESSION_THRESHOLD |
float | 0.90 |
Trigger compression at this fraction of OLLAMA_NUM_CTX |
CONTEXT_KEEP_RECENT |
int | 8 |
Number of recent conversation turns to keep verbatim |
CONTEXT_SUMMARY_TEMPERATURE |
float | 0.3 |
Temperature for the summarization LLM call |
CONTEXT_SUMMARY_MAX_TOKENS |
int | 6000 |
Max output tokens for the summary LLM call |
OUTPUT_RESERVE_TOKENS |
int | 2048 |
Headroom reserved for model response in context size checks |
CONTEXT_MESSAGE_TOKEN_BUDGET |
int | 0 |
Per-message token budget for the LLM context view. A single tool/assistant message whose estimated size exceeds this is head/tail-truncated in the built context only (stored history is never mutated) so one huge tool result cannot alone blow the window. 0 = auto (OLLAMA_NUM_CTX // 6). |
| Variable | Type | Default | Description |
|---|---|---|---|
GMAIL_ADDRESS |
str | "" |
Gmail address for the email_manager tool (IMAP/SMTP with App Password) |
GMAIL_APP_PASSWORD |
str | "" |
Gmail App Password (not the account password — generate at myaccount.google.com) |
| Variable | Type | Default | Description |
|---|---|---|---|
NAVI_AUTH_ENABLED |
bool | true |
Master auth switch. Set false to disable OAuth/API-token auth entirely. Every request is treated as the local anonymous admin user. Use only for trusted single-user/local deployments. |
GNAUTH_BASE_URL |
str | http://gnexus-auth.local |
gnexus-auth server base URL |
GNAUTH_CLIENT_ID |
str | "" |
OAuth client ID |
GNAUTH_CLIENT_SECRET |
str | "" |
OAuth client secret |
GNAUTH_REDIRECT_URI |
str | http://localhost:8099/auth/callback |
Must match redirect URI registered in gnexus-auth |
GNAUTH_ADMIN_ROLE_SLUG |
str | navi_admin |
Role slug that maps to Navi admin role |
GNAUTH_USER_ROLE_SLUG |
str | navi_user |
Role slug that maps to Navi user role |
GNAUTH_PROFILE_PATH |
str | /account/profile |
Path appended to gnauth_base_url for profile links |
NAVI_AUTH_ENCRYPTION_KEY |
str | "" |
Fernet key (base64, 32 bytes). Generate once with python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())". Never change after first launch. |
NAVI_AUTH_COOKIE_NAME |
str | navi_auth_session |
Session cookie name |
NAVI_AUTH_COOKIE_SECURE |
bool | False |
Set True behind HTTPS |
NAVI_AUTH_COOKIE_SAMESITE |
str | lax |
SameSite policy |
NAVI_AUTH_COOKIE_MAX_AGE_DAYS |
int | 30 |
Cookie lifetime |
Full auth setup guide: docs/auth.md.
| Variable | Type | Default | Description |
|---|---|---|---|
NAVI_PUSH_VAPID_PUBLIC_KEY |
str | "" |
VAPID public key for web push. Empty = push fully disabled (endpoints 503, no notifications sent). |
NAVI_PUSH_VAPID_PRIVATE_KEY |
str | "" |
VAPID private key. Generate the pair once: pip install py_vapid && python -m py_vapid gen. |
NAVI_PUSH_VAPID_SUBJECT |
str | mailto:admin@navi.local |
Contact for the push service (a mailto: or https: URL). |
NAVI_PUSH_COOLDOWN_SEC |
int | 30 |
Minimum seconds between two pushes for the same session. |
Push notifications fire when an agent turn (or a scheduled recall) completes and no browser tab is watching that session. See docs/push.md.
| Variable | Type | Default | Description |
|---|---|---|---|
SYNAPSE_SOURCE_URL |
str | "" |
GNEXUS Synapse base URL for the outgoing source API. Empty = nothing is ever emitted. |
SYNAPSE_SOURCE_API_KEY |
str | "" |
syn_* source key registered in the Synapse admin panel (write it into .env yourself). |
SYNAPSE_SOURCE_NAME |
str | navi |
Source name on Synapse's side. |
Without both URL and key, Synapse-linked outgoing events are silently skipped and the UI disables Synapse-linked options (source_ready: false). See docs/synapse.md.
| Variable | Type | Default | Description |
|---|---|---|---|
NAVI_PERSONA |
str | "" |
Global personality prompt prepended to every profile's system prompt |
NAVI_PERSONA_FILE |
str | "" |
Path to a .txt file containing the persona (preferred over inline NAVI_PERSONA) |
Recommended: use NAVI_PERSONA_FILE=persona.txt rather than inlining the persona in .env, because multi-line values don't parse reliably in .env files.
The _load_persona_from_file validator reads the file on startup if NAVI_PERSONA is empty and NAVI_PERSONA_FILE is set.
| Variable | Type | Default | Description |
|---|---|---|---|
TASKS_MAX_PER_SESSION |
int | 5 |
Concurrent running background tasks per session |
TASKS_MAX_GLOBAL |
int | 20 |
Concurrent running background tasks server-wide |
TASKS_MAX_SPAWN |
int | 2 |
Concurrent background spawn_agent per session |
TASKS_TTL_SEC |
int | 3600 |
Finished-task retention before reaping |
TASKS_EVENT_BUFFER_SIZE |
int | 50 |
Per-task event ring (spawn tasks use 200) |
TASKS_RATE_LIMIT |
int | 10 |
Max task spawns per 5 min per session |
TASK_NOTES_MAX_PENDING |
int | 20 |
Pending completion notes per session |
TASK_NOTES_PER_TURN |
int | 5 |
Max notes coalesced into one turn injection |
MESSAGE_QUEUE_MAX |
int | 5 |
User messages queued while a run is active |
BACKGROUNDABLE_TOOLS |
str | terminal,ssh_exec,peer,spawn_agent,code_exec |
Tools accepting "background": true |
PARALLEL_TOOL_CALLS |
bool | false |
Execute a multi-tool-call batch concurrently (per-profile override: AgentProfile.parallel_tool_calls) |
See docs/tasks.md for the full mechanism.
When a terminal (run), code_exec or ssh_exec call is detached and the agent did not pass timeout, the executor lifts it to 300 s for the detached run only — the tools' short foreground defaults (20/30/60 s) would otherwise mark long commands "completed" with partial output while the process is still running.
.env# LLM — Ollama (primary) OLLAMA_HOST=http://localhost:11434 OLLAMA_API_KEY= OLLAMA_DEFAULT_MODEL=gemma4:31b-cloud OLLAMA_NUM_CTX=65536 OLLAMA_THINK=true OLLAMA_REQUEST_TIMEOUT=30 # Multi-server fallback mode (overrides OLLAMA_HOST/API_KEY): # OLLAMA_BACKENDS_FILE=ollama_backends.json # LLM — OpenAI (optional) # OPENAI_API_KEY=sk-... # OPENAI_MODEL=gpt-4 # OPENAI_BASE_URL=https://api.openai.com/v1 # Database (PostgreSQL 15+ with pgvector) DATABASE_URL=postgresql://user:pass@localhost:5432/navidb # Security / sandboxing FS_ALLOWED_PATHS=* TERMINAL_ALLOWED_COMMANDS=* # Misc LOG_LEVEL=INFO TOOLS_DIR=tools SHARE_FILE_MAX_SIZE_MB=1024 SESSION_MESSAGES_WINDOW=1000 WS_REPLAY_BUFFER_SIZE=500 # Context compression CONTEXT_COMPRESSION_ENABLED=true CONTEXT_COMPRESSION_THRESHOLD=0.90 CONTEXT_KEEP_RECENT=8 # Persona NAVI_PERSONA_FILE=persona.txt NAVI_DEFAULT_PROFILE_ID=navi_code