Environment variables
Every runtime knob merido reads, generated directly from the Config struct so this table is never out of date. Each is set with its MERIDO_-prefixed environment variable. For how configuration is layered and which knobs matter most, see Configuration.
| Variable | Default | Description |
|---|---|---|
MERIDO_PROFILE | local | — |
MERIDO_HOST | 127.0.0.1 | Address to bind the HTTP server to. |
MERIDO_PORT | 8788 | — |
MERIDO_DATA_DIR | (computed) | Local data directory (SQLite, logs) for the local profile. |
MERIDO_DATABASE_URL | unset | Explicit database URL. When unset, a SQLite file under data_dir is used. Also accepts a bare DATABASE_URL (no MERIDO_ prefix) as a fallback, the convention Supabase/Fly/Heroku Postgres inject — see [Config::load]. |
MERIDO_REDIS_URL | unset | Redis URL for shared cluster state (HA). Accepts bare REDIS_URL as a fallback. Stored but not yet consumed until the HA data plane lands. |
MERIDO_MULTI_TENANT | false | Enable self-serve multi-tenancy: email+password signup, per-user org isolation, and admin tier. Off by default — single-user self-host keeps its current password-free local behavior. |
MERIDO_ADMIN_EMAILS | empty | Emails that become system admins on signup (comma-separated in env). Matched case-insensitively against the signup email. |
MERIDO_RESEND_API_KEY | unset | Resend HTTP API key for transactional email (verification / password reset). When unset, emails are logged instead of sent (dev/local). |
MERIDO_EMAIL_FROM | unset | Verified Resend sender address, e.g. merido <[email protected]>. |
MERIDO_PUBLIC_URL | unset | Public base URL used to build verification / reset links in emails. |
MERIDO_DASHBOARD_DIR | unset | Directory of built dashboard assets to serve. When unset, falls back to dashboard/dist if present. |
MERIDO_MASTER_KEY_PATH | unset | Path to the 32-byte master key used for encryption-at-rest. When unset, a key is created under data_dir/master.key (or taken from MERIDO_MASTER_KEY). |
MERIDO_DASHBOARD_PASSWORD_HASH | unset | Argon2 PHC hash of the dashboard password. When unset, the dashboard/admin API is open (local single-user default); when set, login is required. |
MERIDO_JWT_SECRET | unset | Secret used to sign dashboard session JWTs. When unset, one is derived from the master key at startup. |
MERIDO_REQUIRE_API_KEY | false | Require a valid client API key on every /v1/* proxy request. Off by default (local single-user convenience: anonymous localhost callers are allowed); MUST be enabled on any deployment reachable from the public internet, otherwise unauthenticated callers can burn upstream provider credits. |
MERIDO_VIRTUAL_MODELS_ONLY | false | Strict gateway mode: require every /v1/* chat request to target a configured Virtual Model (or a MERIDO_ROUTES route, or the built-in auto). When on, a bare provider/model id is rejected with a 400 and GET /v1/models advertises only the Virtual Models — raw upstream models are never exposed or directly callable, so all traffic flows through Virtual Models. Off by default (direct provider/model passthrough is allowed, the local-first convenience). |
MERIDO_RATE_LIMIT_RPM | unset | Per-client-key sustained rate limit, in requests per minute. None disables rate limiting. |
MERIDO_RATE_LIMIT_BURST | unset | Per-client-key burst allowance (max tokens). Defaults to rate_limit_rpm when unset and a limit is configured. |
MERIDO_DEDUP_TTL_MS | unset | Request-dedup cache TTL in milliseconds. When set, identical non-streaming requests within the window return a cached response. None disables dedup. |
MERIDO_SEMANTIC_CACHE_TTL_MS | unset | Semantic-cache TTL in milliseconds. The fuzzy sibling of dedup: a request whose prompt embedding is within semantic_cache_threshold of a recent one reuses that response. Requires semantic_cache_embed_model; None disables. |
MERIDO_SEMANTIC_CACHE_THRESHOLD | unset | Minimum cosine similarity for a semantic-cache hit (default 0.95 when the cache is enabled but this is unset). Higher is stricter / fewer false hits. |
MERIDO_SEMANTIC_CACHE_EMBED_MODEL | unset | The provider/model used to embed prompts for the semantic cache, e.g. openai/text-embedding-3-small. Required to enable the semantic cache. Must be an external provider — a merido/… model would re-enter the proxy and is rejected (the cache stays off). Cache entries are scoped per target (provider, model, wire-format, client key, request params), so a hit is only ever another request to the same model with the same parameters whose prompt embeds within the threshold; the embedding model only needs to be stable, not shared across chat providers. |
MERIDO_SEMANTIC_CACHE_ENABLED | false | Master switch for the productized semantic cache (Wave 22.3). Off by default because a fuzzy cache can return a semantically-different answer (a "false hit"), which is correctness-sensitive — an operator must opt in explicitly. Independent of the legacy semantic_cache_ttl_ms/embed_model plumbing: this flag (plus the per-route map) governs whether a lookup is consulted and at what similarity bar. (MERIDO_SEMANTIC_CACHE_ENABLED.) |
MERIDO_SEMANTIC_CACHE_REVALIDATE_RATE | 0.05 | Fraction of semantic-cache hits to divert into sampled re-validation, in [0.0, 1.0]. On a sampled hit the server treats the lookup as a MISS, lets the real request proceed, and compares the fresh response against the value the cache would have served — measuring how often a "hit" was actually correct (precision). Default 0.05 (5%) bounds the false-hit blast radius while keeping the re-validation tax small. 0.0 disables the guard. (MERIDO_SEMANTIC_CACHE_REVALIDATE_RATE.) |
MERIDO_SEMANTIC_CACHE_PRECISION_FLOOR | 0.90 | Measured-precision floor in [0.0, 1.0]. When a route's sampled precision drops below this, the guard self-protects by raising that route's effective threshold (and, at the limit, disabling the route's cache). Default 0.90: fewer than 1-in-10 sampled hits may be false before the guard clamps down. (MERIDO_SEMANTIC_CACHE_PRECISION_FLOOR.) |
MERIDO_ROUTES | empty | Virtual-model routes: named, cost-ordered candidate model lists with model-level fallback. A client requesting a route's name is served by the best capable target. Populated from the MERIDO_ROUTES env var (a JSON array of route objects) by [Config::load]; empty by default. |
MERIDO_HEALTH_CHECK_INTERVAL_SECS | unset | Active health-check interval in seconds. When set, a background prober calls each connection's /models endpoint on this cadence and feeds the result to the circuit breaker, so a recovered provider is detected proactively rather than on the next failed request. None (default) disables active probing. |
MERIDO_MONTHLY_BUDGET_USD | unset | Monthly spend budget in USD. When set, the advisor reports budget status (a linear end-of-month projection and any overage) for the current calendar month. None (default) disables budget tracking. |
MERIDO_SESSION_BUDGET_USD | unset | Per-session spend cap in USD: cumulative cost allowed per agent session (session_id) before requests are blocked (402). None disables the cap. Overridable per API key via api_keys.session_budget_usd. |
MERIDO_CAVEMAN_LEVEL | unset | Caveman output-compression level applied to every request. When set to a recognised level (lite, full, ultra, wenyan-lite, wenyan, wenyan-ultra), an intensity-tuned, format-aware system prompt is injected to cut output verbosity. None or an empty/blank value disables it; an unrecognised value is ignored (logged) at startup. |
MERIDO_MITM_ENABLED | false | Enable the MITM interception server at startup. When true, merido spawns a local TLS proxy that intercepts known coding-CLI hosts and rewrites their traffic to this gateway's /v1 API. Off by default. (MERIDO_MITM_ENABLED.) |
MERIDO_MITM_PORT | unset | Port the MITM interception server binds (on host). Defaults to 8443 when unset and MITM is enabled. (MERIDO_MITM_PORT.) |
MERIDO_MITM_MANAGE_HOSTS | false | When MITM is enabled, also manage the OS hosts file: map every intercepted host to 127.0.0.1 so the local proxy receives their traffic. Best-effort and requires elevated privileges; failures are logged, not fatal. (MERIDO_MITM_MANAGE_HOSTS.) |
MERIDO_MITM_INSTALL_CA | false | When MITM is enabled, install the generated root CA into the OS trust store so intercepted TLS handshakes validate. Best-effort; failures are logged, not fatal. (MERIDO_MITM_INSTALL_CA.) |
MERIDO_OUTBOUND_PROXY | unset | Global outbound proxy URL applied to every upstream request (e.g. http://user:pass@host:port or socks5://host:port). A per-connection proxy_url overrides this. None (default) sends traffic directly. (MERIDO_OUTBOUND_PROXY.) |
MERIDO_PLUGIN_PATH | unset | Path to a WASM filter plugin — a sandboxed request/response byte transform run by the plugin host on the chat request path. Honoured only when the binary is built with the server's wasm cargo feature; otherwise it is logged and ignored. None (default) disables plugins entirely. (MERIDO_PLUGIN_PATH.) |
MERIDO_SHADOW_EVAL_ENABLED | false | Enable shadow evaluation (Wave 21.1): replay a small, deterministic % of live traffic against an alternate ("shadow") model to prove a cheaper model is good enough, WITHOUT affecting the live response. Opt-in and off by default — it captures request/response bodies (encrypted at rest, TTL-bounded) and spends upstream credits on the replay. (MERIDO_SHADOW_EVAL_ENABLED.) |
MERIDO_SHADOW_SAMPLE_RATE | 0.02 | Fraction of eligible requests to shadow-sample, in [0.0, 1.0] (deterministic per-request sampling). Default 0.02 (2%) keeps the replay cost and stored volume small. (MERIDO_SHADOW_SAMPLE_RATE.) |
MERIDO_SHADOW_DAILY_USD_BUDGET | 5.0 | Daily USD budget cap on shadow-replay spend. Once the day's replays reach this cap, further sampling is skipped until the next day. Default 5.0. (MERIDO_SHADOW_DAILY_USD_BUDGET.) |
MERIDO_SHADOW_TTL_DAYS | 7 | Retention, in days, for stored shadow samples (the concrete expires_at a TTL sweep deletes by). Default 7. (MERIDO_SHADOW_TTL_DAYS.) |
MERIDO_PRICING_SYNC_ENABLED | true | Keep model prices fresh by syncing a public rate-card snapshot on startup and then on an interval, layered above the compiled-in fallback table (operator overrides always win). Default true; failures are non-fatal — the gateway falls back to the last cached snapshot, then the built-in table. (MERIDO_PRICING_SYNC_ENABLED.) |
MERIDO_PRICING_SYNC_URL | https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json | Primary pricing source: a LiteLLM-format model_prices_and_context_window.json (USD per token). Default points at LiteLLM's main. (MERIDO_PRICING_SYNC_URL.) |
MERIDO_PRICING_FALLBACK_URL | https://models.dev/api.json | Fallback pricing source used only when the primary fetch fails: a models.dev api.json (USD per 1M tokens). (MERIDO_PRICING_FALLBACK_URL.) |
MERIDO_PRICING_SYNC_INTERVAL_SECS | 21600 | How often (seconds) to re-sync prices in the background. Default 21600 (6 hours). (MERIDO_PRICING_SYNC_INTERVAL_SECS.) |
MERIDO_PRICING_SYNC_FETCH_TIMEOUT_SECS | 90 | Per-fetch HTTP timeout (seconds) when downloading an upstream rate card. Default 90 — the pinned LiteLLM snapshot is ~1.5 MB and takes up to ~80 s on a slow link; 20 s (the old hard-coded value) cuts it off. (MERIDO_PRICING_SYNC_FETCH_TIMEOUT_SECS.) |
MERIDO_PRICING_SYNC_LITELLM_REF | v1.89.1 | Git ref (tag or commit SHA) used to build the LiteLLM pricing URL, so the synced rate card is pinned to a reproducible snapshot rather than the floating main branch. Default is a pinned release tag; operators should update this when a new LiteLLM release is available. (MERIDO_PRICING_SYNC_LITELLM_REF.) |
MERIDO_PRICING_SYNC_DRIFT_PCT | 25.0 | Price-change percentage that triggers a drift review flag. When a model's input or output price shifts by more than this percentage between two consecutive synced snapshots, the change is logged as a warning and recorded in the process-global review list (but the new price is always applied). Default 25.0 (flag changes larger than 25%). (MERIDO_PRICING_SYNC_DRIFT_PCT.) |
MERIDO_USAGE_RETENTION_DAYS | unset | Opt-in retention for raw usage_events: when set (> 0), a background pruner deletes rows older than this many days. None (the default) keeps usage data forever — no pruning runs. (MERIDO_USAGE_RETENTION_DAYS.) |
MERIDO_ERROR_RULES | empty | Operator-supplied error-classification rules that supplement and override the compiled-in defaults. Consulted by [merido_router::classify_with_rules] before the built-ins, so an operator can reclassify an upstream error (e.g. treat a provider-specific "warming up" 503 as a short cooldown) without recompiling. Populated from the MERIDO_ERROR_RULES env var (a JSON array of rule objects) by [Config::load]; empty by default, leaving built-in classification unchanged. (MERIDO_ERROR_RULES.) |
MERIDO_LOG_ENABLED | true | Whether to persist a per-request log of every /v1 data-plane request (metadata + request/response bodies) for the Monitor → Logs page. true by default; capture is best-effort and never blocks a request. (MERIDO_LOG_ENABLED.) |
MERIDO_LOG_BODIES | false | Whether to store request/response bodies (and redacted headers) alongside the log metadata. false by default (privacy-first: only metadata is kept); set true to also capture prompt/response content. Can be toggled at runtime from the dashboard (Logs page) via the request_log.bodies setting, which overrides this startup default. (MERIDO_LOG_BODIES.) |
MERIDO_LOG_MAX_BODY_BYTES | 1048576 | Max bytes of a single request or response body stored per request; larger bodies are truncated and flagged. Default 1048576 (1 MiB). (MERIDO_LOG_MAX_BODY_BYTES.) |
MERIDO_LOG_RETENTION_DAYS | 30 | Retention for request logs: a background pruner deletes rows older than this many days. Default 30; 0 disables time-based pruning. (MERIDO_LOG_RETENTION_DAYS.) |
MERIDO_LOG_RETENTION_MAX_BYTES | 2147483648 | Size cap (bytes) for the total compressed request-log bodies; the pruner evicts oldest rows until under it. Default 2147483648 (2 GiB); 0 disables size-based pruning. (MERIDO_LOG_RETENTION_MAX_BYTES.) |