> ## Documentation Index
> Fetch the complete documentation index at: https://safia.maximusolution.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SAFIA Environment Variables: Full Reference Guide

> Complete reference for every SAFIA environment variable — required fields, LLM settings, admin dashboard, knowledge base, and bot behavior tuning.

SAFIA reads all configuration from a `.env` file in your installation directory. The `safia setup` wizard creates this file interactively, and `safia config` lets you edit individual values at any time. This page documents every supported variable.

<Note>
  Restart the bot after changing any variable for the new values to take effect:

  ```bash theme={null}
  safia restart
  ```
</Note>

***

## Required

These four variables must be set before the bot can start.

<ParamField body="TELEGRAM_BOT_TOKEN" type="string" required>
  Your Telegram bot token, obtained from `@BotFather`. This authenticates the bot with the Telegram API.

  ```text theme={null}
  TELEGRAM_BOT_TOKEN=7123456789:AAFxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  ```
</ParamField>

<ParamField body="LLM_API_KEY" type="string" required>
  API key for your chosen LLM provider. Used for all chat completions and receipt vision. See [LLM Providers](/cli/llm-providers) for per-provider instructions.

  ```text theme={null}
  LLM_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
  ```
</ParamField>

<ParamField body="DATABASE_URL" default="sqlite+aiosqlite:///data/safia.db" type="string">
  Connection string for the database that stores transactions, debts, portfolios, and user data. Defaults to a local SQLite file — no setup required. For production use, you can point this at a PostgreSQL database.

  ```text theme={null}
  # SQLite (default — zero configuration)
  DATABASE_URL=sqlite+aiosqlite:///data/safia.db

  # PostgreSQL
  DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/safia
  ```
</ParamField>

<ParamField body="CACHE_DB_PATH" default="data/cache.db" type="string">
  SQLite file used to persist SAFIA's in-memory cache (chat history, rate-limit counters, and market data). The cache is kept in memory for speed and flushed to this file so state survives bot restarts. No external cache server is required.

  ```text theme={null}
  CACHE_DB_PATH=data/cache.db
  ```
</ParamField>

***

## LLM settings

<ParamField body="LLM_PROVIDER" default="lunos" type="string">
  Which LLM provider to use for chat completions. Accepted values: `lunos`, `groq`, `openai`, `custom`.

  ```text theme={null}
  LLM_PROVIDER=lunos
  ```
</ParamField>

<ParamField body="LLM_MODEL" default="openai/gpt-oss-120b" type="string">
  The model identifier sent to the LLM provider. The exact format depends on your provider — for example, Groq uses `llama-3.3-70b-versatile` while Lunos uses `openai/gpt-oss-120b`.

  ```text theme={null}
  LLM_MODEL=openai/gpt-oss-120b
  ```
</ParamField>

<ParamField body="LLM_BASE_URL" type="string">
  Base URL for the LLM API. This is **only required when `LLM_PROVIDER=custom`**. Must point to an OpenAI-compatible `/v1` endpoint.

  ```text theme={null}
  LLM_BASE_URL=https://openrouter.ai/api/v1
  ```
</ParamField>

<ParamField body="VISION_MODEL" default="mistralai/mistral-small-3.2-24b-instruct" type="string">
  Model used for receipt and document photo scanning. Must support vision input. Uses the same provider and API key as `LLM_PROVIDER`.

  ```text theme={null}
  VISION_MODEL=mistralai/mistral-small-3.2-24b-instruct
  ```
</ParamField>

<ParamField body="GROQ_API_KEY" type="string">
  API key for the Groq platform. This is **always required for voice message transcription** (Whisper via Groq), regardless of which `LLM_PROVIDER` you use for chat. If omitted, voice messages are disabled.

  ```text theme={null}
  GROQ_API_KEY=gsk_xxxxxxxxxxxxxxxxxxxxxxxx
  ```

  <Note>
    If you set `LLM_PROVIDER=groq`, your main `LLM_API_KEY` doubles as the Groq key for transcription — you do not need to set `GROQ_API_KEY` separately in that case.
  </Note>
</ParamField>

***

## Admin dashboard

<ParamField body="ADMIN_USERNAME" type="string">
  Username for the admin dashboard at `http://127.0.0.1:5454`. The setup wizard defaults this to `admin` if you leave it blank. Leave both `ADMIN_USERNAME` and `ADMIN_PASSWORD` unset to disable authentication entirely.

  ```text theme={null}
  ADMIN_USERNAME=admin
  ```
</ParamField>

<ParamField body="ADMIN_PASSWORD" type="string">
  Password for the admin dashboard. The setup wizard generates a random password if you leave the field blank. Set a strong value to protect the dashboard from unauthorized access.

  ```text theme={null}
  ADMIN_PASSWORD=your-strong-password
  ```
</ParamField>

<ParamField body="FLASK_SECRET_KEY" type="string">
  Secret key used by the admin dashboard to sign session cookies. Set this to a long, random string. The setup wizard generates one automatically.

  ```text theme={null}
  FLASK_SECRET_KEY=some-long-random-string
  ```
</ParamField>

***

## Knowledge base

The knowledge base uses Qdrant for vector storage and either local ONNX embeddings or a remote embedding API.

<ParamField body="QDRANT_PATH" default="data/qdrant" type="string">
  Local filesystem path where Qdrant stores vector data. Used when `QDRANT_URL` is not set. No separate Qdrant server is required — vectors are stored directly on disk.

  ```text theme={null}
  QDRANT_PATH=data/qdrant
  ```
</ParamField>

<ParamField body="QDRANT_URL" type="string">
  URL of a remote Qdrant instance. When set, this overrides `QDRANT_PATH` and SAFIA connects to the remote server instead of using local disk storage.

  ```text theme={null}
  QDRANT_URL=http://127.0.0.1:6333
  ```
</ParamField>

<ParamField body="EMBEDDING_LOCAL" default="true" type="boolean">
  When `true`, SAFIA generates embeddings locally using the ONNX Runtime and the `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2` model (\~120 MB, downloads once). Set to `false` to use a remote embedding API instead.

  ```text theme={null}
  EMBEDDING_LOCAL=true
  ```
</ParamField>

<ParamField body="EMBEDDING_BASE_URL" default="https://api.lunosrouter.com/v1" type="string">
  Base URL of the remote embedding API. Only used when `EMBEDDING_LOCAL=false`.

  ```text theme={null}
  EMBEDDING_BASE_URL=https://openrouter.ai/api/v1
  ```
</ParamField>

<ParamField body="EMBEDDING_API_KEY" type="string">
  API key for the remote embedding provider. Falls back to `LLM_API_KEY` if not set. Only used when `EMBEDDING_LOCAL=false`.

  ```text theme={null}
  EMBEDDING_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
  ```
</ParamField>

<ParamField body="EMBEDDING_MODEL" default="openai/text-embedding-3-small" type="string">
  Model name sent to the remote embedding API. Only used when `EMBEDDING_LOCAL=false`.

  ```text theme={null}
  EMBEDDING_MODEL=openai/text-embedding-3-small
  ```
</ParamField>

<ParamField body="EMBEDDING_VECTOR_SIZE" default="384" type="integer">
  Dimensionality of the embedding vectors. Must match the output dimensions of your embedding model. The default `384` matches the local ONNX model. If you switch to `text-embedding-3-small`, set this to `1536`.

  ```text theme={null}
  EMBEDDING_VECTOR_SIZE=384
  ```
</ParamField>

<ParamField body="KB_CHUNK_WORDS" default="450" type="integer">
  Size of each document chunk in words when ingesting files into the knowledge base. Larger chunks preserve more context; smaller chunks improve retrieval precision.

  ```text theme={null}
  KB_CHUNK_WORDS=450
  ```
</ParamField>

<ParamField body="KB_CHUNK_OVERLAP_WORDS" default="70" type="integer">
  Number of words that overlap between adjacent chunks. Overlap helps avoid splitting context across chunk boundaries.

  ```text theme={null}
  KB_CHUNK_OVERLAP_WORDS=70
  ```
</ParamField>

<ParamField body="KB_MAX_UPLOAD_MB" default="200" type="integer">
  Maximum file size in megabytes for documents uploaded to the knowledge base via the admin dashboard.

  ```text theme={null}
  KB_MAX_UPLOAD_MB=200
  ```
</ParamField>

***

## Bot behavior

<ParamField body="REMINDER_ENABLED" default="true" type="boolean">
  Enables or disables the reminder system. When enabled, SAFIA can send scheduled price alerts, news digests, and portfolio summaries.

  ```text theme={null}
  REMINDER_ENABLED=true
  ```
</ParamField>

<ParamField body="REMINDER_TICK_SECONDS" default="30" type="integer">
  How often (in seconds) the reminder scheduler checks for due reminders. Reduce this for faster reminder delivery at the cost of slightly higher CPU usage.

  ```text theme={null}
  REMINDER_TICK_SECONDS=30
  ```
</ParamField>

<ParamField body="DAILY_MESSAGE_LIMIT" default="1000" type="integer">
  Maximum number of messages a single user can send per day. Users who exceed this limit receive a rate-limit notice. Set to a higher value for less restrictive usage.

  ```text theme={null}
  DAILY_MESSAGE_LIMIT=2000
  ```
</ParamField>
