Environment Variables
Every env var the agent reads, grouped by category, with defaults and consumers
This page is the per-variable reference. For the convention
(how to add a new env var, the loader, the checklist), see
Getting Started → Environment Variables.
The canonical template with blank values lives at
.env.example at the repo root.
Conventions used in the tables
| Column | Meaning |
|---|---|
| Variable | Env var name. UPPER_SNAKE, provider-prefixed. |
| Default | — means no default; missing the var either gates a feature or fails boot (see the Effect column). |
| Format | Expected value shape. |
| Consumer | File or module that reads the var. |
| Effect | What happens when the var is unset, or what the var enables when set. |
Variables with safety-critical behavior have an extra prose note directly below their table.
Precedence
Variables exported by your shell, CI, or systemd win over
values in .env. The loader does not overwrite existing keys.
See loader details.
LLM providers
At least one LLM path must resolve at boot: ANTHROPIC_API_KEY,
OPENROUTER_API_KEY, or a stored OAuth profile from
minara login openai | anthropic | openrouter. If none resolve,
the process refuses to start with NoProviderAvailableError.
| Variable | Default | Format | Consumer | Effect |
|---|---|---|---|---|
ANTHROPIC_API_KEY | — | sk-ant-... | apps/agent/src/llm/select-provider.ts | Primary Claude credential. Unset: falls through to stored OAuth profile, then OpenRouter. |
OPENROUTER_API_KEY | — | sk-or-... | apps/agent/src/llm/openrouter.ts | Alternative router over many models. Unset: tried only if Anthropic paths fail. |
OPENAI_API_KEY | — | sk-... | apps/agent/src/tools/image.ts, research KB | Image generation + KB embeddings. Unset: image tools silently disable, KB embedding skipped. |
OLLAMA_API_KEY | — | from ollama.com/settings/keys | apps/agent/src/llm/v2/custom-loaders.ts | Ollama Cloud credential. Unset: the ollama provider is unavailable. |
OLLAMA_BASE_URL | https://ollama.com | absolute URL | apps/agent/src/llm/v2/custom-loaders.ts | Override the Ollama host (self-hosted / enterprise / local http://localhost:11434). |
Minara core
| Variable | Default | Format | Consumer | Effect |
|---|---|---|---|---|
MINARA_API_KEY | — | mnr_... | apps/agent/src/minara/client.ts, safe-trading-client.ts | Minara REST credential. Unset: falls back to saved device-flow JWT; else NoMinaraAuthError. |
MINARA_BASE_URL | production URL | absolute URL | apps/agent/src/minara/client.ts, apps/agent/src/gateway/server.ts, apps/agent/src/gateway/auth-cli.ts | Override for staging / self-host. Unset: production. |
AGENT_MODEL | claude-sonnet-4-6 | provider model id | apps/agent/src/gateway/cli.ts, apps/agent/src/gateway/server.ts | Main agent-loop model. Also settable via minara model use <id>. |
MINARA_DATA_DIR | ~/.minara | absolute path | apps/agent/src/gateway/cli.ts, apps/agent/src/app/bootstrap.ts, sandbox | Root for SQLite + sandbox + auth + logs. Empty value falls back to default. |
FILES_URL_BASE | /v1/files | absolute URL or path | apps/agent/src/app.ts | Public prefix for file links. Set when behind a reverse proxy. |
OFFLINE_MODE | off | 1/true/yes/on | apps/agent/src/tools/_shared/fetch-timeout.ts | Hard-disable outbound HTTP from sandbox tools. Unset: normal online behavior. |
LOG_LEVEL | info | debug|info|warn|error | apps/agent/src/core/logger.ts | Global logger threshold. debug produces ~4× volume but is safe. |
HTTP gateway
Only matters for npm run serve / node dist/gateway/server.js.
| Variable | Default | Format | Consumer | Effect |
|---|---|---|---|---|
GATEWAY_PORT | 8080 | integer 1–65535 | apps/agent/src/gateway/server.ts | TCP port the gateway binds. |
GATEWAY_AUTH_TOKEN | — | opaque string | apps/agent/src/gateway/server.ts | Bearer token required on every /v1/... route. Unset: auth disabled, every request accepted. |
WEBHOOK_PORT | — | integer 1–65535 | apps/agent/src/gateway/server.ts | Optional dedicated port for inbound webhooks. Unset: webhook routes live on GATEWAY_PORT. |
⚠ Never expose an unauthenticated gateway to the internet. Fund-moving tools are reachable through
/v1/chat. SetGATEWAY_AUTH_TOKENto a high-entropy value (e.g.openssl rand -hex 32) before binding to any non-loopback interface. See HTTP API → Authentication.
Safety and fund-moving
| Variable | Default | Format | Consumer | Effect |
|---|---|---|---|---|
MINARA_SKIP_FUND_CONFIRM | off | 1/true/yes/on | apps/agent/src/tools/_shared/confirm.ts | Bypasses the confirm: true gate on every fund-moving tool handler. |
⚠
MINARA_SKIP_FUND_CONFIRMis the only process-wide bypass of the handler-level confirmation gate. The LLM cannot skip it; the REPL cannot skip it. Use it only in non-interactive contexts (backtests, server-side workflow engine, CI smoke tests). Never set it in an interactive REPL session or on a production deployment unless you are certain every caller is non-human.
Builtin tools
Each entry gates one or more tool factories or skills. Missing
var means the tool factory returns [] and the gated skill is
hidden from the catalog. See
Adding a Tool → feature-gating on env.
| Variable | Consumer | Effect |
|---|---|---|
TAVILY_API_KEY | apps/agent/src/tools/web.ts | Gates web_search + web_extract. Unset: research.web degrades to DuckDuckGo scraping. |
FAL_KEY | apps/agent/src/tools/image.ts | Enables Fal.ai image / video models. Optional companion FAL_QUEUE_URL for async jobs. |
FAL_QUEUE_URL | apps/agent/src/tools/image.ts | Override for a private Fal.ai queue endpoint. Unset: uses Fal's public queue. |
MESSAGING_DEFAULT_PROVIDER | apps/agent/src/app/messaging.ts, apps/agent/src/tools/messaging.ts | Default provider id for send_message when the caller omits provider (telegram, discord, slack, email, whatsapp, signal, home_assistant). Unset: first configured provider wins. |
MESSAGING_MAX_ATTACHMENT_BYTES | apps/agent/src/messaging/attachment-resolver.ts | Per-attachment size cap applied before any upload. Decimal integer (bytes); values ≤ 0 are ignored. Default: 52 428 800 (50 MB). Provider APIs enforce their own maxima independently. |
TELEGRAM_BOT_TOKEN | apps/agent/src/messaging/telegram.ts | <bot_id>:<secret> from @BotFather. Pair with TELEGRAM_CHAT_ID. Configurable via minara gateway add telegram. Supports streaming edits (750ms throttle). |
TELEGRAM_CHAT_ID | apps/agent/src/messaging/telegram.ts | Numeric chat id (negative for channels). Unset: the Telegram path of send_message returns a config error. |
TELEGRAM_RICH_TEXT | apps/agent/src/messaging/telegram.ts | Render replies as Telegram rich text (HTML, falling back to MarkdownV2 then plain). Default on; 0/false/no/off sends plain text. Read once at startup. |
SLACK_WEBHOOK_URL | apps/agent/src/messaging/slack.ts | Slack Incoming Webhook URL. Simplest Slack path — channel baked into the URL, no streaming edits. |
SLACK_BOT_TOKEN | apps/agent/src/messaging/slack.ts | Slack bot token (xoxb-...). Enables streaming edits via chat.update (1200ms throttle). Pair with SLACK_CHANNEL_ID. |
SLACK_CHANNEL_ID | apps/agent/src/messaging/slack.ts | Default Slack channel id (e.g. C0123ABC). Required together with SLACK_BOT_TOKEN. |
DISCORD_BOT_TOKEN | apps/agent/src/messaging/discord.ts | Discord bot token. Enables streaming edits via PATCH /channels/{}/messages/{} (1000ms throttle). |
DISCORD_CHANNEL_ID | apps/agent/src/messaging/discord.ts | Default Discord channel snowflake id. Bot must have Send Messages (+ Manage Messages for streaming). |
HASS_URL | apps/agent/src/messaging/home_assistant.ts | Home Assistant base URL (no trailing slash). Pair with HASS_TOKEN + HASS_NOTIFY_SERVICE. |
HASS_TOKEN | apps/agent/src/messaging/home_assistant.ts | Long-lived access token from your HA profile. |
HASS_NOTIFY_SERVICE | apps/agent/src/messaging/home_assistant.ts | Notify service id (mobile_app_pixel, alexa_tts). Leading notify. prefix is optional. One-shot, no streaming. |
SMTP_HOST | apps/agent/src/messaging/email.ts | Outbound SMTP host. Pair with SMTP_PORT, SMTP_USER, SMTP_PASSWORD, EMAIL_FROM, EMAIL_TO. |
SMTP_PORT | apps/agent/src/messaging/email.ts | SMTP port (587 STARTTLS / 465 SSL). Adapter picks TLS mode by port. |
SMTP_USER | apps/agent/src/messaging/email.ts | SMTP username. Optional for open relays. |
SMTP_PASSWORD | apps/agent/src/messaging/email.ts | SMTP password or app-specific password. Masked on minara gateway list. |
EMAIL_FROM | apps/agent/src/messaging/email.ts | From-address header value. |
EMAIL_TO | apps/agent/src/messaging/email.ts | Default recipient when send_message omits channel. |
WHATSAPP_ACCESS_TOKEN | apps/agent/src/messaging/whatsapp.ts | Meta Cloud API Bearer token (System User). Masked on minara gateway list. |
WHATSAPP_PHONE_NUMBER_ID | apps/agent/src/messaging/whatsapp.ts | Numeric phone-number id from the Meta Developer app. |
WHATSAPP_RECIPIENT | apps/agent/src/messaging/whatsapp.ts | Default recipient (E.164, e.g. +12025551234). |
SIGNAL_CLI_NUMBER | apps/agent/src/messaging/signal.ts | Your registered Signal sender number (E.164). Validated at construction. |
SIGNAL_RECIPIENT | apps/agent/src/messaging/signal.ts | Default recipient (E.164). Revalidated per-send; unsafe values are rejected before subprocess. |
SIGNAL_CLI_BINARY | apps/agent/src/messaging/signal.ts | Override path to the signal-cli binary (default: PATH lookup). Factory returns null silently if the binary isn't found. |
TELEGRAM_WEBHOOK_SECRET | apps/agent/src/messaging/inbound/server.ts | Shared secret echoed in X-Telegram-Bot-Api-Secret-Token. Verified constant-time; mismatch → 401. Unset → /webhooks/telegram returns 404. |
SLACK_SIGNING_SECRET | apps/agent/src/messaging/inbound/server.ts | Slack signing secret for HMAC-SHA256 verification over v0:{ts}:{body}. 5-min replay window. Unset → /webhooks/slack returns 404. |
DISCORD_APPLICATION_PUBLIC_KEY | apps/agent/src/messaging/inbound/server.ts | Ed25519 public key (hex) for Discord interaction signature verification. Unset → /webhooks/discord returns 404. |
MESSAGING_INBOUND_TRANSCRIBE | apps/agent/src/messaging/inbound/transcribe.ts | Enable OpenAI Whisper transcription for inbound voice attachments. Falsy default. Requires OPENAI_API_KEY. Format: 1/true/yes/on. |
MESSAGING_INBOUND_ENABLED | apps/agent/src/app/messaging.ts | Master off switch for the inbound HTTP webhook listener (auto-boots InboundServer + agent-bridge when 1). Off by default; setting it also requires at least one provider secret for routes to accept traffic. |
MESSAGING_INBOUND_PORT | apps/agent/src/app/messaging.ts | Port for the inbound HTTP listener. Default 8787. |
MESSAGING_INBOUND_HOST | apps/agent/src/app/messaging.ts | Bind host for the inbound HTTP listener. Default 127.0.0.1 — production expects a TLS-terminating reverse proxy. |
MESSAGING_INBOUND_MAX_BODY_BYTES | apps/agent/src/app/messaging.ts | Per-request body cap for inbound webhooks. Default 4194304 (4 MB). |
MESSAGING_INBOUND_HISTORY_TURNS | apps/agent/src/messaging/inbound/session-router.ts | Sliding-window size for inbound session history fed to agentLoop.run(). Default 20. Invalid values fall back to default. |
MESSAGING_INBOUND_DISABLE_STREAMING | apps/agent/src/app/messaging.ts | Force one-shot replies instead of createStreamSink token-by-token edits for inbound turns. Off by default (streaming enabled). Useful for tests / slow channels. |
MESSAGING_INBOUND_GC_INTERVAL_MS | apps/agent/src/app/messaging.ts | Interval for the periodic attachment-retention sweep. Default 3600000 (1 h). 0 disables the timer (manual minara inbound gc only). |
MESSAGING_INBOUND_ATTACHMENT_RETENTION_DAYS | apps/agent/src/messaging/inbound/attachment-gc.ts | Age (days) after which inbound attachment BYTES are deleted from sandbox/inbound/<sess>/. SQLite metadata survives. Default 90. |
MESSAGING_INBOUND_SESSION_RETENTION_DAYS | apps/agent/src/messaging/inbound/attachment-gc.ts | Age (days) after which the whole session row (+ cascade inbound_messages) is purged. Default 180. |
WHATSAPP_VERIFY_TOKEN | apps/agent/src/messaging/inbound/server.ts | Shared token for WhatsApp's one-time hub.verify challenge. Set when registering the webhook URL in the Meta dashboard. Unset → GET /webhooks/whatsapp returns 404. |
WHATSAPP_APP_SECRET | apps/agent/src/messaging/inbound/server.ts | Meta app secret — HMAC-SHA256 key for verifying X-Hub-Signature-256 on every POST. Unset → POST /webhooks/whatsapp returns 404. |
MESSAGING_SIGNAL_INBOUND | apps/agent/src/app/messaging.ts | Independent off switch for the Signal daemon (signal-cli daemon --socket). Off by default. Requires SIGNAL_CLI_NUMBER to be configured. Format: 1/true/yes/on. |
SIGNAL_CLI_SOCKET_PATH | apps/agent/src/app/messaging.ts | UNIX socket path the Signal daemon binds + we connect to. Default <dataDir>/signal.sock. |
TWITTERAPI_API_KEY | apps/agent/src/tools/providers/twitterapi.ts | Third-party scraper. Gates research.social.twitter via requires_env. |
X_API_BEARER_TOKEN | apps/agent/src/tools/providers/x-api.ts | Official X API v2 app-only Bearer from console.x.com. Gates the x.api skill. |
GLASSNODE_API_KEY | apps/agent/src/tools/providers/glassnode.ts | Glassnode on-chain metrics. Gates research.onchain.glassnode. |
QDRANT_URL | apps/agent/src/skills/builtin/research/knowledge-base.ts | Vector KB endpoint. Gates research.knowledge_base. Pair with OPENAI_API_KEY for embeddings. |
QDRANT_API_KEY | apps/agent/src/skills/builtin/research/knowledge-base.ts | Optional auth for Qdrant Cloud. Local docker usually needs no key. |
TWITTERAPI_API_KEYandX_API_BEARER_TOKENare distinct. The former goes through a third-party scraper; the latter speaks directly toapi.x.com/2. Either or both can be set.
E2B cloud sandbox
E2B is opt-in. The local code/shell sandbox remains the
default even when E2B is configured. The router only hands
work to workspace.e2b when the user names it explicitly
("e2b", "cloud sandbox", "isolated VM"), unless FORCE_E2B=1
flips the contract.
| Variable | Default | Format | Consumer | Effect |
|---|---|---|---|---|
E2B_API_KEY | — | opaque key | apps/agent/src/tools/providers/e2b.ts | Gates workspace.e2b. Unset: local sandbox only. |
FORCE_E2B | off | 1/true/yes/on | apps/agent/src/app/bootstrap.ts, apps/agent/src/tools/code.ts, apps/agent/src/tools/terminal.ts | Ops-level override. Disables local sandbox, routes all code/shell to E2B. Requires E2B_API_KEY or boot fails. |
Autonomous turns (cron, workflow, price-alert) cannot auto-activate
workspace.e2bwithout an operator-authored workflow that explicitly declares it inskill_scope. The workflow engine'strustedSeedpath emits a loud audit log whenever that escape is exercised. See Workflows.
MCP integrations
See MCP Integration for the runtime semantics. All entries below are independently gated; missing envs don't break anything else.
| Variable | Format | Consumer | Effect |
|---|---|---|---|
MCP_SERVERS | JSON array | apps/agent/src/app/mcp.ts | Overrides default MCP servers. Example: [{"name":"defillama","command":"npx","args":[…]}]. |
DEFILLAMA_API_KEY | opaque string | apps/agent/src/defillama/client.ts | DefiLlama Pro API key. Gates the 10 defillama.* builtin skills. Injected as URL path prefix on Pro-host calls. Replaces retired DEFILLAMA_MCP_TOKEN / mcp.defillama.com path. Unset: all 10 skills hide from catalog. |
MCP_EVM_RPC_URL | streamable-HTTP URL | apps/agent/src/app/mcp.ts → mcp.evm_rpc skill | Raw EVM JSON-RPC sub-agent. Bounded at 15 steps / 240s per query. |
MCP_ETHERSCAN_URL | streamable-HTTP URL | apps/agent/src/app/mcp.ts → mcp.etherscan skill | Etherscan-style explorer across 60+ EVM chains. |
MCP_SOLSCAN_URL | streamable-HTTP URL | apps/agent/src/app/mcp.ts → mcp.solscan skill | Solscan-compatible Solana explorer. |
MCP_GOPLUS_URL | streamable-HTTP URL | apps/agent/src/app/mcp.ts → mcp.goplus skill | GoPlus multi-chain Web3 security analytics. Leave unset in prod if you want v1 semantics. |
All URL vars must advertise the streamable-HTTP MCP transport. The v1 SSE endpoints will not work.
External skills
Vendored skills under apps/agent/src/skills/external/ consume these
through requires_env gating or by having the LLM read them
via the terminal tool. Missing var means the corresponding
skill is hidden from the catalog.
| Variable | Skill(s) | Header / usage |
|---|---|---|
CMC_PRO_API_KEY | cmc-api-crypto, cmc-api-dex, cmc-api-exchange, cmc-api-market | Header X-CMC_PRO_API_KEY |
COINGECKO_API_KEY | coingecko | x-cg-pro-api-key (Pro) or x-cg-demo-api-key |
COINANK_API_KEY | coinank (derivatives: OI, funding, liquidations, whale tracking, order flow, ETF) | Header apikey |
COINGLASS_API_KEY | coinglass | Header CG-API-KEY |
FMP_API_KEY | fmp — gates the external.fmp built-in skill. Public-equity quotes, technicals, fundamentals, analysts, calendar, SEC, news, screener, macro, sectors, ETF. 2026-04-20: migrated from the MCP_FMP_URL sub-agent to a vendored external skill. | Query param ?apikey= |
OKX_API_KEY | okx-* family (wallet / DEX / onchain / security / agentic wallet / DeFi / x402) | Used by the onchainos CLI |
PRIVATE_KEY | polymarket | EVM signer hex (0x…) |
RPC_URL | polymarket | Absolute EVM RPC endpoint |
POLY_BUILDER_API_KEY | polymarket | Builder API credential |
POLY_BUILDER_SECRET | polymarket | Builder API credential |
POLY_BUILDER_PASSPHRASE | polymarket | Builder API credential |
⚠
PRIVATE_KEYis a hot wallet key. Treat the machine that holds it as a trading terminal. Never put it in a shared or multi-user environment. Prefer hardware-wallet-backed signing where possible.The three
POLY_BUILDER_*variables must be set together. Partial configuration leaves the Polymarket skill in a half-configured state that fails on first authenticated call.
Reading the inventory programmatically
# Which env vars are set right now?
minara config list
# Which env-gated skills and tools are currently available?
minara skills list
minara tools list
# Full doctor report with env coverage
minara doctorminara doctor is the fastest way to see which provider,
tools, and skills are actually live given the env you've
loaded. Missing credentials surface as yellow warnings rather
than silent gaps.
Changes to this page
Adding or removing an env var requires updating all four locations in the same commit:
.env.exampleat the repo root.apps/agent/docs-src/env-vars.md, the authoritative internal reference.- This page.
- Getting Started → Environment Variables inventory table.
Reviewers reject PRs that touch process.env.<NAME> without
matching doc updates. The convention is recorded in
Conventions §1.