Environment variables override Frona's YAML configuration. Most settings use the FRONA_ prefix; provider and search credentials also use the unprefixed names listed below.
Precedence and naming
For component settings, Frona loads built-in defaults, applies YAML, then applies environment overrides. A value set in the server environment therefore takes precedence over the same field saved through the administration UI. Restart Frona after changing its environment; in Docker Compose, recreate the container to apply changed environment values.
After FRONA_, the first underscore separates the component from its field. Single underscores within the field name are preserved. Use double underscores for deeper nesting:
| Environment variable | Configuration field |
|---|---|
FRONA_SERVER_PORT | server.port |
FRONA_BROWSER_WS_URL | browser.ws_url |
FRONA_CHANNEL_RETRY__MAX_RETRIES | channel.retry.max_retries |
Use numeric values for numeric fields and true or false for booleans. The general startup variables below are handled separately from component settings. Standard provider variables perform provider discovery; ${ENV_VAR} references in YAML select a named variable's value.
Environment variables must be available to the Frona process. A host .env file is not automatically loaded by the server or forwarded into a container. See Docker Compose environment forwarding.
General
| Variable | Default | Description |
|---|---|---|
FRONA_SERVER_DATA_DIR | data | Base data directory. Defaults for FRONA_CONFIG, database.path, storage.data_dir, storage.skills_dir, storage.cache_dir, and storage.ontology_dir are derived from this path. Per-user state lives at {data_dir}/users/{user_handle}/... |
FRONA_CONFIG | {data_dir}/config.yaml | Path to the YAML config file |
FRONA_LOG_LEVEL | info | Log level for frona and tower_http: trace, debug, info, warn, or error. Used when FRONA_LOG_CONFIG is unset |
FRONA_LOG_CONFIG | -- | Complete tracing filter string, such as frona=debug,tower_http=info. Overrides FRONA_LOG_LEVEL |
Server
| Variable | Default | Description |
|---|---|---|
FRONA_SERVER_PORT | 3001 | Port the backend API listens on |
FRONA_SERVER_STATIC_DIR | /app/static | Directory containing the frontend static build |
FRONA_SERVER_BASE_URL | -- | Public base URL of the server (used for callbacks) |
FRONA_SERVER_MAX_BODY_SIZE_BYTES | 104857600 (100 MB) | Maximum request body size |
FRONA_SERVER_CORS_ORIGINS | -- | Comma-separated list of allowed CORS origins |
FRONA_SERVER_MAX_CONCURRENT_TASKS | 10 | Maximum concurrent tasks across all agents |
FRONA_SERVER_BACKEND_URL | -- | Override backend API URL |
FRONA_SERVER_FRONTEND_URL | -- | Override frontend URL |
FRONA_SERVER_EXTERNAL_URL | -- | Externally-reachable URL of the server (e.g., ngrok tunnel, public domain). Used as the default callback target for inbound webhooks (Twilio, Telegram, etc.) when no per-feature override is set |
FRONA_SERVER_ISSUER_URL | -- | JWT token issuer URL |
FRONA_SERVER_SSE_PENDING_EVENTS_SECS | 60 | How long to buffer SSE events after client disconnects |
FRONA_SERVER_SHUTDOWN_TIMEOUT_SECS | 60 | Graceful shutdown timeout |
FRONA_SERVER_TIMEZONE | auto-detect | Server-default IANA timezone (e.g. America/Los_Angeles). Used for cron, reminders, and the <temporal_context> block when a user has no profile timezone set. Empty auto-detects from TZ, then /etc/localtime, falling back to UTC. |
Sandbox
| Variable | Default | Description |
|---|---|---|
FRONA_SANDBOX_DISABLED | false | Disable filesystem sandboxing. Not recommended for production. |
FRONA_SANDBOX_MAX_CPU_PCT | 95.0 | Per-principal CPU usage limit (% of total system CPU). |
FRONA_SANDBOX_MAX_MEMORY_PCT | 80.0 | Per-principal memory usage limit (% of total system memory). |
FRONA_SANDBOX_TIMEOUT_SECS | 0 | Default sandbox execution timeout (0 = no timeout). |
FRONA_SANDBOX_MAX_TOTAL_CPU_PCT | 98.0 | Global CPU cap across all sandboxed processes. |
FRONA_SANDBOX_MAX_TOTAL_MEMORY_PCT | 90.0 | Global memory cap across all sandboxed processes. |
FRONA_SANDBOX_DEFAULT_NETWORK_ACCESS | true | Grant sandbox principals outbound network access by default. Override with forbid policies. |
Authentication
| Variable | Default | Description |
|---|---|---|
FRONA_AUTH_ENCRYPTION_SECRET | dev-secret-change-in-production | Secret used to derive the AES-256 key protecting signing keypairs, vault configurations, local credentials, and managed provider keys and account tokens. Must be changed in production. |
FRONA_AUTH_ACCESS_TOKEN_EXPIRY_SECS | 900 (15 min) | Access token lifetime |
FRONA_AUTH_REFRESH_TOKEN_EXPIRY_SECS | 604800 (7 days) | Refresh token lifetime |
FRONA_AUTH_PRESIGN_EXPIRY_SECS | 86400 (24 hours) | Pre-signed URL lifetime |
FRONA_AUTH_EPHEMERAL_TOKEN_EXPIRY_SECS | 300 (5 min) | Ephemeral principal token lifetime injected into sandboxed processes. |
FRONA_AUTH_ALLOW_REGISTRATION | true | Allow anyone to sign up from the Register page. Set to false on shared installs so only admins can create accounts. See Managing Users. |
Change the encryption secret in production
FRONA_AUTH_ENCRYPTION_SECRET is used to derive an AES-256 encryption key (via SHA-256) that protects JWT signing keypairs, vault provider configurations, local credential values, and managed credential payloads, including provider keys and account tokens. It is not used directly for JWT signing; instead it encrypts the private keys that do the signing.
A built-in default is provided for local development, but you must set your own value in production. If the default is left in place and database files are ever exposed (backup leak, file traversal, shared host), an attacker could decrypt the signing keypairs and forge authentication tokens for any user.
Managed credentials are included in automatic encryption-key rotation. Back up the encryption secret together with the database and configuration; see Backups.
Generate a strong random secret:
openssl rand -base64 32SSO (OpenID Connect)
| Variable | Default | Description |
|---|---|---|
FRONA_SSO_ENABLED | false | Enable OIDC authentication |
FRONA_SSO_AUTHORITY | -- | OpenID Connect authority URL |
FRONA_SSO_CLIENT_ID | -- | OIDC client ID |
FRONA_SSO_CLIENT_SECRET | -- | OIDC client secret |
FRONA_SSO_SCOPES | openid email | OpenID scopes to request |
FRONA_SSO_DISABLE_LOCAL_AUTH | false | Force SSO-only authentication, disables local login |
FRONA_SSO_SIGNUPS_MATCH_EMAIL | true | Match SSO signups to existing accounts by email |
FRONA_SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION | true | Accept unverified emails from the IdP |
FRONA_SSO_CLIENT_CACHE_EXPIRATION | 0 | Accepted but unused in v2026.10.0; changing it has no effect on client metadata caching |
Database
| Variable | Default | Description |
|---|---|---|
FRONA_DATABASE_PATH | {FRONA_SERVER_DATA_DIR}/db | Path to the SurrealDB data directory |
Browser
| Variable | Default | Description |
|---|---|---|
FRONA_BROWSER_WS_URL | -- | WebSocket URL of the Browserless instance |
FRONA_BROWSER_PROFILES_PATH | /profiles | Path for storing browser profiles |
FRONA_BROWSER_CONNECTION_TIMEOUT_MS | 30000 | Timeout for connecting to the browser |
FRONA_BROWSER_API_TOKEN | frona fallback | Authentication token for the Browserless HTTP management API |
Search
| Variable | Default | Description |
|---|---|---|
FRONA_SEARCH_PROVIDER | -- | Search provider: searxng, tavily, or brave |
FRONA_SEARCH_SEARXNG_BASE_URL | -- | Base URL of the SearXNG instance |
TAVILY_API_KEY | -- | API key required for Tavily search |
BRAVE_API_KEY | -- | API key required for Brave Search |
When FRONA_SEARCH_PROVIDER is unset, Frona selects the first configured option in this order: TAVILY_API_KEY, BRAVE_API_KEY, then FRONA_SEARCH_SEARXNG_BASE_URL. An explicit provider selection requires its matching key or URL; Frona does not fall back to another provider if that value is missing. Forward search credentials into the container just like model-provider credentials.
Vault
| Variable | Default | Description |
|---|---|---|
FRONA_VAULT_ONEPASSWORD_SERVICE_ACCOUNT_TOKEN | -- | 1Password service account token |
FRONA_VAULT_ONEPASSWORD_VAULT_ID | -- | 1Password default vault ID |
FRONA_VAULT_BITWARDEN_CLIENT_ID | -- | Bitwarden personal API key client ID |
FRONA_VAULT_BITWARDEN_CLIENT_SECRET | -- | Bitwarden personal API key client secret |
FRONA_VAULT_BITWARDEN_MASTER_PASSWORD | -- | Bitwarden master password |
FRONA_VAULT_BITWARDEN_SERVER_URL | -- | Bitwarden server URL (for self-hosted instances) |
FRONA_VAULT_HASHICORP_ADDRESS | -- | HashiCorp Vault server address |
FRONA_VAULT_HASHICORP_TOKEN | -- | HashiCorp Vault auth token |
FRONA_VAULT_HASHICORP_MOUNT | -- | HashiCorp Vault KV2 mount path (default: secret) |
FRONA_VAULT_KEEPASS_PATH | -- | Path to KeePass .kdbx file |
FRONA_VAULT_KEEPASS_PASSWORD | -- | KeePass master password |
Storage
Per-user state (workspaces, uploaded files, MCP server data, channel sessions, vault, tokens) is rooted at {FRONA_STORAGE_DATA_DIR}/users/{user_handle}/.... Browser profiles are kept separately on the browserless container's volume (FRONA_BROWSER_PROFILES_PATH). See Workspaces.
| Variable | Default | Description |
|---|---|---|
FRONA_STORAGE_DATA_DIR | {FRONA_SERVER_DATA_DIR} | Root data directory for all per-user state |
FRONA_STORAGE_SHARED_CONFIG_DIR | resources | Path for shared prompts and agent configs (read-only, ships with the binary) |
FRONA_STORAGE_SKILLS_DIR | {FRONA_SERVER_DATA_DIR}/skills | Path for installed shared skills |
FRONA_STORAGE_CACHE_DIR | {FRONA_SERVER_DATA_DIR}/system/cache | Path for system caches |
FRONA_STORAGE_ONTOLOGY_DIR | {FRONA_SERVER_DATA_DIR}/ontology | Directory for user-supplied ontology files, loaded alongside bundled ontologies |
FRONA_SERVER_DATA_DIR defaults to data. It supplies initial defaults for these paths and the database and config-file paths. Explicit YAML fields or environment overrides can replace each path independently. Setting only FRONA_STORAGE_DATA_DIR moves the per-user storage root; it does not change the database, config-file, skills, cache, or ontology paths. See Backups when splitting data across directories.
Scheduler
| Variable | Default | Description |
|---|---|---|
FRONA_SCHEDULER_POLL_SECS | 60 | How often the scheduler checks for due tasks |
Memory
| Variable | Default | Description |
|---|---|---|
FRONA_MEMORY_BACKEND | basic for upgrades | Memory backend: basic or pkm |
FRONA_MEMORY_MODEL_GROUP | memory | Model group for background memory work; basic compaction falls back to the chat agent model, PKM to primary |
FRONA_MEMORY_BASIC_COMPACTION_TOKEN_THRESHOLD | 3000 | Basic-memory compaction token threshold |
FRONA_MEMORY_BASIC_COMPACTION_SECS | 7200 | Basic user/agent memory compaction interval |
FRONA_MEMORY_BASIC_SPACE_COMPACTION_SECS | 3600 | Basic space-memory compaction interval |
FRONA_MEMORY_PKM_SEARCH_TOP_K | 8 | Maximum results returned by PKM search |
FRONA_MEMORY_PKM_SHORT_MEMORY_HALF_LIFE_SECS | 1209600 | Short-memory decay half-life |
FRONA_MEMORY_PKM_SHORT_MEMORY_DEMOTE_THRESHOLD | 0.1 | Short-memory decay-score cutoff; memories below this score are excluded from the prompt |
FRONA_MEMORY_PKM_SHORT_MEMORY_TOP_N | 16 | Maximum injected short-memory lines |
FRONA_MEMORY_PKM_SHORT_MEMORY_TOKEN_CAP | 3000 | Short-memory prompt token budget |
FRONA_MEMORY_PKM_PLAYBOOK_INDEX_TOKEN_CAP | 1500 | Playbook-index prompt token budget |
FRONA_MEMORY_PKM_CONSOLIDATE_SECS | 60 | Consolidation sweep cadence |
FRONA_MEMORY_PKM_CONSOLIDATE_IDLE_SECS | 300 | Required chat idle time |
FRONA_MEMORY_PKM_CONSOLIDATION_CONCURRENCY | 4 | Parallel extraction or authoring calls |
FRONA_MEMORY_PKM_CONSOLIDATION_MAX_TOOL_TURNS | 8 | Classify/resolve exploration-tool turn limit |
FRONA_MEMORY_PKM_CONSOLIDATION_MAX_SUBMISSIONS | 8 | Classify/resolve/reconcile submission limit |
FRONA_MEMORY_PKM_PLAYBOOK_MAX_TOOL_TURNS | 20 | Playbook exploration-tool turn limit |
FRONA_MEMORY_PKM_PLAYBOOK_MAX_SUBMISSIONS | 20 | Playbook submission limit |
FRONA_MEMORY_PKM_EXTRACT_MAX_TOKENS | 10000 | Transcript-token limit per extraction request |
FRONA_MEMORY_PKM_EXTRACT_MAX_MESSAGES | 300 | Message limit per extraction request |
FRONA_MEMORY_PKM_EXTRACT_AGENT_EVIDENCE_LOOKBACK_MESSAGES | 10 | Agent-message evidence lookback |
FRONA_MEMORY_PKM_EXTRACT_AGENT_EVIDENCE_RESULT_TOKEN_CAP | 4000 | Token cap per evidence search or read |
FRONA_MEMORY_PKM_CONSOLIDATION_MAX_ATTEMPTS | 3 | Current-stage failures allowed per pass |
FRONA_MEMORY_PKM_ADJUDICATION_MAX_ATTEMPTS_PER_BATCH | 40 | Adjudication submissions allowed per batch |
FRONA_MEMORY_PKM_CONSOLIDATION_CHECKPOINT_FAILURE_CAP | 2 | Fatal checkpoint resets allowed |
FRONA_MEMORY_PKM_CONSOLIDATION_RETRY_BASE_SECS | 120 | Base retry delay |
FRONA_MEMORY_PKM_CONSOLIDATION_KEEP_RECORDS | 20 | Finished consolidation records retained per user |
Inference
| Variable | Default | Description |
|---|---|---|
FRONA_INFERENCE_MAX_TOOL_TURNS | 200 | Maximum tool call iterations per response |
FRONA_INFERENCE_DEFAULT_MAX_TOKENS | 8192 | Output-token reservation for context budgeting when the model has no explicit output limit. Set model-group max_tokens to impose a generation limit |
FRONA_INFERENCE_COMPACTION_TRIGGER_PCT | 80 | Accepted configuration field, but currently unused by the chat compactor; see below |
FRONA_INFERENCE_HISTORY_TRUNCATION_PCT | 90 | Percentage of the history budget usable after reserving output tokens and system-prompt space; older messages are removed to fit |
In v2026.10.0, chat compaction uses a fixed threshold of 80% of the context window remaining after the output-token reservation. Changing FRONA_INFERENCE_COMPACTION_TRIGGER_PCT does not change that threshold. FRONA_INFERENCE_DEFAULT_MAX_TOKENS is not a universal generation cap: explicitly configured model groups without max_tokens can leave the request's output limit unset. See model settings.
Voice (Twilio)
| Variable | Default | Description |
|---|---|---|
FRONA_VOICE_PROVIDER | -- | Voice provider. Currently only twilio is supported |
FRONA_VOICE_TWILIO_ACCOUNT_SID | -- | Twilio account SID |
FRONA_VOICE_TWILIO_AUTH_TOKEN | -- | Twilio auth token |
FRONA_VOICE_TWILIO_FROM_NUMBER | -- | Twilio phone number for outbound calls (E.164 format) |
FRONA_VOICE_TWILIO_VOICE_ID | -- | Twilio voice ID for text-to-speech |
FRONA_VOICE_TWILIO_SPEECH_MODEL | -- | Twilio speech recognition model |
Twilio webhook callbacks now use FRONA_SERVER_EXTERNAL_URL instead of the old FRONA_VOICE_CALLBACK_BASE_URL.
LLM Providers
The following names are recognized for automatic provider discovery. Frona adds the discovered connection when its handle is not already configured; an existing connection takes precedence. If both configured providers and models are empty, Frona also creates a default primary group using one of the discovered providers. If you configure any provider in YAML or settings, configure its model groups explicitly as well.
| Variable | Provider |
|---|---|
ANTHROPIC_API_KEY | Anthropic (Claude) |
OPENAI_API_KEY | OpenAI (GPT) |
GROQ_API_KEY | Groq |
OPENROUTER_API_KEY | OpenRouter |
DEEPSEEK_API_KEY | DeepSeek |
GEMINI_API_KEY | Google Gemini |
COHERE_API_KEY | Cohere |
MISTRAL_API_KEY | Mistral |
PERPLEXITY_API_KEY | Perplexity |
TOGETHER_API_KEY | Together AI |
XAI_API_KEY | xAI (Grok) |
HYPERBOLIC_API_KEY | Hyperbolic |
MOONSHOT_API_KEY | Moonshot |
MIRA_API_KEY | Mira |
GALADRIEL_API_KEY | Galadriel |
HUGGINGFACE_API_KEY | Hugging Face |
OLLAMA_API_BASE_URL | Ollama (self-hosted, no API key needed) |
For named connections, use a reference such as api_key: ${WORK_OPENAI_API_KEY} in the config file. Custom variable names do not create connections automatically. The provider editor can select a server environment variable and stores its name as a reference; the variable picker exposes names, not secret values.
Azure, Bedrock, ChatGPT account access, and GitHub Copilot require an explicit connection. For example, AZURE_OPENAI_API_KEY can be referenced by an Azure connection but is not an automatic-discovery variable. Bedrock can use the server's AWS credential chain. See Providers & Models for setup.
Docker Compose environment forwarding
Variables in the host's .env file are available for Compose interpolation, but they are not automatically passed into a container. Add every provider variable the container needs to the Frona service's environment list. The repository's development Compose file currently forwards ANTHROPIC_API_KEY; add the other discovery, search, or custom variable names you use.
For example, this Compose fragment forwards a required Tavily key from the host environment or .env file:
services:
frona:
environment:
FRONA_SEARCH_PROVIDER: tavily
TAVILY_API_KEY: ${TAVILY_API_KEY:?Set TAVILY_API_KEY}Apps
| Variable | Default | Description |
|---|---|---|
FRONA_APP_PORT_RANGE_START | 4000 | Start of the port range for app allocation |
FRONA_APP_PORT_RANGE_END | 4100 | End of the port range for app allocation |
FRONA_APP_HEALTH_CHECK_TIMEOUT_SECS | 30 | Maximum time to wait for an app to become healthy |
FRONA_APP_MAX_RESTART_ATTEMPTS | 2 | Restart attempts before marking a crashed app as failed |
FRONA_APP_HIBERNATE_AFTER_SECS | 259200 (3 days) | Inactivity duration before auto-hibernating an app |
Cache
| Variable | Default | Description |
|---|---|---|
FRONA_CACHE_ENTITY_TTL_SECS | 300 (5 min) | Time-to-live for cached entities |
FRONA_CACHE_ENTITY_MAX_CAPACITY | 1000 | Maximum number of cached entities |
Channel
Default retry policy for channel connections. Per-channel overrides on the channel detail page take precedence. The double underscore after RETRY is required because retry is a nested object. Single-underscore forms such as FRONA_CHANNEL_RETRY_MAX_RETRIES do not configure the retry policy.
| Variable | Default | Description |
|---|---|---|
FRONA_CHANNEL_RETRY__MAX_RETRIES | 4294967295 (effectively unlimited) | Total retry attempts before a channel is marked Failed. |
FRONA_CHANNEL_RETRY__INITIAL_BACKOFF_MS | 1000 (1s) | Delay before the first retry. |
FRONA_CHANNEL_RETRY__BACKOFF_MULTIPLIER | 2.0 | Delay multiplier between attempts. |
FRONA_CHANNEL_RETRY__MAX_BACKOFF_MS | 60000 (60s) | Cap on the delay between attempts. |
Share
Short share links and preview pages used by channel adapters. See Config File → Share.
| Variable | Default | Description |
|---|---|---|
FRONA_SHARE_TTL_SECS | 2592000 (30 days) | Lifetime of a share row. Expired links return a non-leaking 404. |
FRONA_SHARE_CLEANUP_INTERVAL_SECS | 21600 (6 hours) | How often the scheduler deletes expired share rows. |
Signal
Safety caps for the signal matcher.
| Variable | Default | Description |
|---|---|---|
FRONA_SIGNAL_MAX_PENDING_PER_USER | 50 | Maximum number of pending signal watches per user. |
FRONA_SIGNAL_DEFAULT_MAX_EVALUATIONS | 50 | Default cap on candidates a one-shot watch can be evaluated against. |
FRONA_SIGNAL_DEFAULT_MAX_CONTINUOUS_EVALUATIONS | 1000 | Default cap on fires a continuous-mode watch can absorb. |
MCP
| Variable | Default | Description |
|---|---|---|
FRONA_MCP_ENABLED | true | Enable MCP server support. |
FRONA_MCP_CACHE_PATH | {data_dir}/system/mcp-cache | Shared package cache directory (npm, uv). Per-server workspaces are not separately configurable; they live under {data_dir}/users/{user_handle}/mcps/{mcp_handle}/. |
FRONA_MCP_MAX_SERVERS_PER_USER | 32 | Maximum MCP servers per user. |
FRONA_MCP_STARTUP_TIMEOUT_SECS | 30 | Seconds to wait for the initialize handshake. |
FRONA_MCP_HEALTH_CHECK_INTERVAL_SECS | 10 | Interval between liveness checks. |
FRONA_MCP_MAX_RESTART_ATTEMPTS | 3 | Restart attempts before marking a server as failed. |
FRONA_MCP_DEFAULT_TRANSPORT | stdio | Default transport for new MCP servers: stdio or http. |
FRONA_MCP_PORT_RANGE_START | 4100 | Start of port range for local HTTP MCP servers. |
FRONA_MCP_PORT_RANGE_END | 4200 | End of port range (exclusive). |
FRONA_MCP_BRIDGE_MODE | true | Expose MCP tools via the mcpctl CLI bridge. See Bridge mode. |
Debug transcript tracing
These variables apply only to debug builds. Release builds, including production images, do not write transcript traces. Debug builds read these settings once, when tracing is first used.
| Variable | Default | Description |
|---|---|---|
FRONA_LLM_TRACE | disabled | Directory for JSON traces of model requests and responses; a nonempty path enables tracing |
FRONA_LLM_TRACE_MIRROR | disabled | Optional second directory receiving the same traces; requires FRONA_LLM_TRACE |
Trace files contain the actual system prompts, conversation text, page content, tool definitions, and tool output sent to the model. Use a private directory and treat the files as conversation data.
Model groups
Model groups do not have predefined environment-variable names. Configure them through Config File → Models or the administration interface.