# Configuration

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`.

## LLM

| 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`. |
| `OPENAI_API_KEY` | str | `""` | OpenAI API key (if using OpenAI backend) |
| `ANTHROPIC_API_KEY` | str | `""` | Anthropic API key (if using Anthropic backend) |

For direct Ollama Cloud access without fallback: set `OLLAMA_HOST=https://ollama.com` and `OLLAMA_API_KEY=<key>`.

### Multi-server fallback (`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:

```json
[
  { "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.

## LLM Timeouts

| Variable | Type | Default | Description |
|---|---|---|---|
| `LLM_COMPLETE_TIMEOUT` | int | `120` | Seconds before a non-streaming `complete()` call times out |
| `LLM_STREAM_FIRST_CHUNK_TIMEOUT` | int | `180` | 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=180` is a safe upper bound for local Ollama. Reduce if using a fast cloud endpoint.

## Security / Sandboxing

| 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.

## Database

| Variable | Type | Default | Description |
|---|---|---|---|
| `DB_PATH` | str | `navi.db` | SQLite database file path |
| `DATABASE_URL` | str | `""` | PostgreSQL URL (`postgresql://user:pass@host:port/db`). Overrides `DB_PATH` when set. |

## Logging

| Variable | Type | Default | Description |
|---|---|---|---|
| `LOG_LEVEL` | str | `INFO` | Python logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`) |

## Tools

| Variable | Type | Default | Description |
|---|---|---|---|
| `TOOLS_DIR` | str | `tools` | Directory for user-defined tools (auto-discovered at startup) |

## Session files

| 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 |

## Public URL

| Variable | Type | Default | Description |
|---|---|---|---|
| `PUBLIC_URL` | str | `http://localhost:8000` | Base URL used by `share_file` to build download links. Set this when behind a reverse proxy. |

## Context compression

| Variable | Type | Default | Description |
|---|---|---|---|
| `CONTEXT_COMPRESSION_ENABLED` | bool | `true` | Enable/disable automatic context compression |
| `CONTEXT_COMPRESSION_THRESHOLD` | float | `0.70` | 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 | `3000` | Max output tokens for the summary LLM call |

## Gmail

| 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) |

## Persona

| 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.

## Example `.env`

```dotenv
# Single-server mode:
OLLAMA_HOST=http://localhost:11434
OLLAMA_API_KEY=
OLLAMA_DEFAULT_MODEL=gemma4:31b-cloud

# Multi-server fallback mode (overrides OLLAMA_HOST/API_KEY):
# OLLAMA_BACKENDS_FILE=ollama_backends.json

OLLAMA_NUM_CTX=65536
OLLAMA_THINK=true

FS_ALLOWED_PATHS=*
TERMINAL_ALLOWED_COMMANDS=*

DB_PATH=navi.db
LOG_LEVEL=INFO
TOOLS_DIR=tools

CONTEXT_COMPRESSION_ENABLED=true
CONTEXT_COMPRESSION_THRESHOLD=0.70
CONTEXT_KEEP_RECENT=8

NAVI_PERSONA_FILE=persona.txt
```
