MINARA

Builtin tools

Builtin tools (src/tools/*) Each one is optional — missing key → the feature silently disables.

web_search / web_extract backend

web_search and web_extract share one backend. The model cannot pick a provider. First available of: 1. Tavily — TAVILY_API_KEY. Highest priority. 2. Firecrawl — FIRECRAWL_API_KEY, only when Tavily is not available. 3. Exa — local EXA_API_KEY, or a signed-in Minara session (platform exaPassthrough), only when neither Tavily nor Firecrawl is available. There is no chain fallthrough, no DuckDuckGo / Google / Brave / Anthropic native path, and no HTML-fetch extract. Empty results and HTTP errors stay on the chosen backend. JS-walled pages belong to browser_navigate / browser_snapshot. Advanced filters (Exa category, Firecrawl sources/tbs, Tavily topic/depth) appear on the tool schema for the active backend only.

EXA_API_KEY

Exa web search and extract (after Tavily and Firecrawl).

  • What it controls: the backend for both web_search and web_extract when neither Tavily nor Firecrawl is available. A local key is used directly (beats platform passthrough). When unset, a signed-in Minara session still runs Exa via platform exaPassthrough. Exa is a neural search index; search results carry highlight snippets. Extract uses /contents (clean page text). Failures do not fall through to another backend.
  • Consumed by: src/tools/web-backends.ts via createWebTools() in src/app.ts.
  • When to set: you want Exa locally without depending on Minara login.
  • When unset: Tavily is used if its key is set, otherwise Firecrawl, otherwise Exa still runs if you are signed in. If none of those are available, the tools are hidden.
  • Format: Exa API key from https://dashboard.exa.ai/api-keys.
  • Setting home: Settings → API Keys

FIRECRAWL_API_KEY

Firecrawl search + extract (after Tavily).

  • What it controls: the backend for web_search and web_extract when Tavily is not available. /search returns titles/URLs; /scrape returns clean markdown (onlyMainContent: true).
  • Consumed by: src/tools/web-backends.ts via createWebTools() in src/app.ts.
  • When to set: you want search + high-quality page extract without Tavily.
  • When unset: Firecrawl is skipped; Exa is used if a local key is set or you are signed in.
  • Free tier: 500 credits/month. Format: Firecrawl API key from https://www.firecrawl.dev/app/api-keys.
  • Setting home: Settings → API Keys

TAVILY_API_KEY

Tavily web search and extract (highest priority).

  • What it controls: the default backend for web_search and web_extract. Failures do not fall through to Firecrawl or Exa.
  • Consumed by: src/tools/web-backends.ts via createWebTools() in src/app.ts.
  • When to set: you want Tavily as the web research backend.
  • When unset: Firecrawl is used if its key is set, otherwise Exa (local key or signed-in passthrough). If none of those are available, web_search and web_extract stay hidden. There is no DuckDuckGo fallback.
  • Format: Tavily API key from https://tavily.com.
  • Setting home: Settings → API Keys

GOAL_MAX_TURNS

max automatic continuation turns for a standing /goal before it pauses for review (REPL goal mode).

  • Default when unset: 20
  • Format: positive integer
  • Setting home: Settings → Preferences (schema key)

POSITION_MEMORY_ENABLED

position/session-aware memory injection. When on, each chat turn that involves an asset (a ticker in the message, or one of the user's recent spot top symbols) gets up to 5 stored memories about that asset injected into the volatile prompt tail — past views and trade notes for advice-style questions, the user's analysis preferences and habits for fundamentals-style questions. Deterministic and local (keyword intent routing + SQLite lookups, zero extra LLM calls); the trading signal comes from the pre-built spot top-symbols artifact refreshed by the trading-summary rebuild. Consumed by app.ts (positionMemoryProvider) via memory/position-memory.ts. Read live through the preferences manager, so flipping it takes effect on the next turn.

  • Default when unset: off
  • Format: 1/true/yes/on to enable
  • Setting home: Settings → Preferences (schema key)

OPENAI_API_KEY

OpenAI platform key, multi-purpose.

  • What it controls: (1) research.knowledge_base skill — text-embedding-3-* embeddings written to Qdrant. (2) Audio TTS in src/tools/audio.ts. (3) Optional LLM provider (opt-in) — distinct from the OpenAI OAuth path. Setting this env alone does NOT auto-select OpenAI as the LLM provider. To enable the LLM path, run minara auth login openai --api-key $OPENAI_API_KEY which writes the openaiApiKey profile slot.
  • Consumed by: src/skills/builtin/research/knowledge-base.ts, src/tools/audio.ts, src/llm/openai-api-key.ts.
  • When unset: research KB writes are skipped; TTS unavailable; LLM uses another provider.
  • Format: sk-... from https://platform.openai.com.
  • Setting home: LLM provider credential (Settings → Provider & Model)

OPENAI_BASE_URL

optional override for the OpenAI API base URL.

  • What it controls: where the OpenAI api-key LLM client + tools call.
  • Default: https://api.openai.com/v1
  • When to set: targeting an Azure OpenAI-compatible gateway or a corporate proxy with the same wire shape.
  • When unset: official OpenAI endpoint is used.
  • Setting home: Not a user-facing setting

OPENAI_ORG_ID

optional OpenAI organization header.

  • What it controls: sent as OpenAI-Organization on every LLM call.
  • When to set: your OpenAI account has multiple orgs and you want billing routed to a specific one.
  • When unset: the default org tied to the API key is used.
  • Setting home: Not a user-facing setting

FAL_KEY / FAL_QUEUE_URL

Fal.ai image/media provider.

  • What it controls: Fal.ai authentication for image_generate, video_generate, and the live image/video model catalog.
  • Consumed by: src/media/* and the media generation tools.
  • When to set: you want API-key authentication. You can instead use Settings > Provider & Model > Image & video to sign in with Fal.ai.
  • When unset: media generation requires Fal.ai sign-in.
  • Format: FAL_KEY is an opaque string from https://fal.ai; FAL_QUEUE_URL is an optional override for the queue endpoint (absolute URL, only set if you're using a private Fal.ai deploy).
  • Setting home: Settings → API Keys (FAL_KEY)
  • Setting home: Not a user-facing setting (FAL_QUEUE_URL)

Messaging gateways

Configured messaging channels contribute separate MCP tools, such as mcp_messaging-lark_send_message. The model selects a channel by tool identity; internal workflows and notifications can use MESSAGING_DEFAULT_PROVIDER. Prefer minara auth messaging add <provider> to store credentials in the messaging credential slot.

MESSAGING_DEFAULT_PROVIDER

default channel for internal workflows and notifications.

  • What it controls: Selects the provider for internal MessagingService calls that omit a provider. Channel MCP tools fix their provider and do not use this default.
  • Consumed by: src/messaging/service.ts (provider resolution).
  • When to set: Set when multiple channels are configured and internal notifications need a default destination.
  • When unset: A single available provider is selected automatically; multiple available providers require an explicit choice.
  • Format: A configured messaging provider id, such as telegram, slack, or lark. Case-insensitive.
  • Setting home: Not a user-facing setting

MESSAGING_MAX_ATTACHMENT_BYTES

per-attachment size cap for send_message({attachments: [...]}) calls.

  • What it controls: before each attachment is uploaded to its provider API, the resolver stats the sandbox file and rejects with a clear error when the size exceeds this value. Prevents an unbounded LLM-controlled path from DOSing SMTP relays / Discord / Telegram with massive files.
  • Consumed by: src/messaging/attachment-resolver.ts.
  • When to set: operators want to tighten the 50 MB default (e.g. for Slack free-tier 1 GB storage quotas, or to block any audio longer than a minute).
  • When unset: defaults to 52 428 800 bytes (50 MB). Provider APIs enforce their own maxima independently — this cap is the Minara- side limit; providers may still reject larger files their APIs consider too big.
  • Format: decimal integer (bytes). Values <= 0 are ignored.
  • Setting home: Not a user-facing setting

TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID

outbound Telegram messaging.

  • What it controls: Configures the telegram gateway used by the channel MCP tool mcp_messaging-telegram_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/telegram.ts.
  • When to set: you want the agent (or a workflow trigger) to push alerts to a Telegram channel or DM.
  • When unset: The telegram channel MCP tools are unavailable until the gateway is configured.
  • Format: TELEGRAM_BOT_TOKEN is the 123456:ABC-DEF... string from @BotFather; TELEGRAM_CHAT_ID is a numeric chat id (negative for channels/groups, positive for DMs).
  • Setting home: Settings → Messaging

TELEGRAM_RICH_TEXT

render outbound replies as Telegram rich text.

  • What it controls: when on (the default), markdown replies are rendered to Telegram HTML (bold, headings, tables, code blocks, task lists) with a MarkdownV2 → plain-text fallback if Telegram rejects the markup. Streaming edits flush only fully-closed constructs so the user never sees half-rendered formatting.
  • Consumed by: src/messaging/telegram.ts.
  • When to set: set to false (or 0/no/off) to send the agent's text verbatim with no formatting.
  • When unset: rich text is ON.
  • Setting home: Settings → Preferences (schema key)

SLACK_BOT_TOKEN / SLACK_CHANNEL_ID

outbound Slack.

  • What it controls: Configures the slack gateway used by the channel MCP tool mcp_messaging-slack_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/chatsdk/adapters/slack.ts.
  • When to set: team / work notifications and two-way Slack chat.
  • When unset: The slack channel MCP tools are unavailable until the gateway is configured.
  • Format: SLACK_BOT_TOKEN starts with xoxb-; SLACK_CHANNEL_ID is a C... channel id (not the #name).
  • Setting home: Settings → Messaging

SLACK_APP_TOKEN

app-level token (xapp-…) for Socket Mode inbound.

  • What it controls: enables the client-outbound Slack inbound daemon (Socket Mode). With this set, the agent opens a WebSocket to Slack and receives Events API messages — no public Request URL / webhook server needed, so two-way chat works on a no-public-IP machine. Pair with SLACK_BOT_TOKEN (used to send the reply).
  • Consumed by: src/messaging/inbound/slack-daemon.ts.
  • When to set: you want Slack two-way chat without exposing a public webhook (e.g. running on a laptop / behind NAT). Generate it in the Slack app config under "Socket Mode" / "App-Level Tokens" with the connections:write scope.
  • When unset: Slack inbound falls back to the webhook route (needs a public Request URL + SLACK_SIGNING_SECRET).
  • Format: xapp-1-....
  • Setting home: Settings → Messaging

DISCORD_BOT_TOKEN / DISCORD_CHANNEL_ID

outbound Discord.

  • What it controls: Configures the discord gateway used by the channel MCP tool mcp_messaging-discord_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/discord.ts.
  • When to set: community server notifications, Discord-centric teams.
  • When unset: The discord channel MCP tools are unavailable until the gateway is configured.
  • Format: DISCORD_BOT_TOKEN is the opaque bot secret from the Developer Portal app page; DISCORD_CHANNEL_ID is a numeric channel snowflake. The bot must have been invited to the server + channel with the Send Messages + Manage Messages permissions (Manage Messages is only needed if you rely on streaming edits).
  • Setting home: Settings → Messaging

HASS_URL / HASS_TOKEN / HASS_NOTIFY_SERVICE

Home Assistant notify.

  • What it controls: Configures the home_assistant gateway used by the channel MCP tool mcp_messaging-home_assistant_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/home_assistant.ts.
  • When to set: you want trade alerts pushed to phone push / Alexa TTS / other Home Assistant-mediated endpoint.
  • When unset: The home_assistant channel MCP tools are unavailable until the gateway is configured.
  • Format: HASS_URL is the full base URL (https://hass.example:8123, no trailing slash); HASS_TOKEN is a long-lived access token from your HA profile; HASS_NOTIFY_SERVICE is a notify service id (mobile_app_pixel, alexa_tts; the leading notify. is optional — stripped by the adapter).
  • Setting home: Settings → Messaging

SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD / EMAIL_FROM / EMAIL_TO

outbound email (SMTP).

  • What it controls: Configures the email gateway used by the channel MCP tool mcp_messaging-email_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/email.ts (wraps MIT-licensed nodemailer).
  • When to set: compliance / archival channels, or when the target recipient doesn't use one of the chat platforms.
  • When unset: The email channel MCP tools are unavailable until the gateway is configured.
  • Format: SMTP_HOST is the relay hostname; SMTP_PORT is 587 for STARTTLS or 465 for SSL (the adapter picks TLS mode by port — secure: true iff port === 465); SMTP_USER / SMTP_PASSWORD are credentials (use an app-specific password for Gmail); EMAIL_FROM is the From header address; EMAIL_TO is the default recipient (can be overridden per-message via channel).
  • Setting home: Settings → Messaging

GOOGLE_OAUTH_CLIENT_ID / GOOGLE_OAUTH_CLIENT_SECRET

operator-supplied Google OAuth client that powers the "Email (Gmail)" one-click connect (provider id email-gmail).

  • What it controls: enables the Connect-Gmail button in the Email (Gmail) Plugin setup. The agent then sends notifications through the Gmail API using the narrow gmail.send scope (it never reads mail).
  • Consumed by: src/gateway/api.ts (OAuth init) + src/messaging/gmail.ts.
  • When to set: to offer the Gmail connector. Create an OAuth client in Google Cloud console, type "Desktop app" (loopback redirect), then paste the ID + secret here OR directly in the Email (Gmail) panel. Precedence matches every other messaging credential: an exported env var wins; otherwise the value saved in the UI is used.
  • When unset (and not entered in the UI): the Connect-Gmail button is disabled; other providers keep working.
  • preferences-schema-coverage: SKIP — messaging-provider credentials are managed in the matching Plugin setup, not the Preferences schema (same as SMTP_* / TELEGRAM_*).
  • Setting home: Settings → Messaging

GMAIL_REFRESH_TOKEN / GMAIL_SENDER_EMAIL / GMAIL_TO

Gmail connection state. GMAIL_REFRESH_TOKEN and GMAIL_SENDER_EMAIL are written by the Connect-Gmail flow (no need to set by hand). GMAIL_TO is an optional recipient override — leave blank to push notifications to the connected inbox itself (push-to-self). preferences-schema-coverage: SKIP — see GOOGLE_OAUTH_CLIENT_ID above.

  • Setting home: Settings → Messaging

WHATSAPP_ACCESS_TOKEN / WHATSAPP_PHONE_NUMBER_ID / WHATSAPP_RECIPIENT

outbound WhatsApp via the Meta Cloud API.

  • What it controls: Configures the whatsapp gateway used by the channel MCP tool mcp_messaging-whatsapp_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/whatsapp.ts.
  • When to set: you've provisioned a Meta Business app with WhatsApp Business API access and need notifications delivered via WhatsApp.
  • When unset: The whatsapp channel MCP tools are unavailable until the gateway is configured.
  • Format: WHATSAPP_ACCESS_TOKEN is a long opaque Bearer token (usually starts with EAA...) issued by the Meta Developer Portal or your Business System User; WHATSAPP_PHONE_NUMBER_ID is the numeric id of the registered business phone number; WHATSAPP_RECIPIENT is a default recipient in E.164 format (+12025551234) — the channel argument of send_message overrides it per call.
  • Note: recipients must have an active 24-hour customer service window or be sent a pre-approved template message — that's a Meta policy constraint, not ours. Plain text messages only work if the user has messaged the business in the last 24 hours.
  • Setting home: Settings → Messaging

SIGNAL_CLI_NUMBER / SIGNAL_RECIPIENT / SIGNAL_CLI_BINARY

outbound Signal.

  • What it controls: Configures the signal gateway used by the channel MCP tool mcp_messaging-signal_send_message and internal notifications. The MCP tool fixes the provider; channel overrides the default destination.
  • Consumed by: src/messaging/signal.ts.
  • When to set: you want privacy-focused alerts to a Signal recipient and have the signal-cli tool available on the host.
  • When unset: The signal channel MCP tools are unavailable until the gateway is configured.
  • Runtime dependency: signal-cli must be installed and on PATH (macOS: brew install signal-cli; Debian: see upstream repo). Before first use, register the sender number: signal-cli -u +15555550100 register then enter the SMS code that arrives on the phone. If the binary is not present at app boot, the signal provider is silently skipped — other providers continue to work.
  • Format: SIGNAL_CLI_NUMBER and SIGNAL_RECIPIENT must both be in E.164 format (leading +, country code, 8-15 total digits, no spaces or dashes — e.g. +12025551234). The adapter validates the regex at construction and on every send() call, and uses a fixed argv layout with -- before the recipient to block any leading-dash flag injection. SIGNAL_CLI_BINARY is an optional override for the binary path — default is PATH lookup for signal-cli.
  • CLAUDE.md §4a Bucket B exemption: this module spawns a subprocess but uses argv form with shell: false, and no LLM input reaches the argv — the message body is passed via a distinct -m slot, and the recipient is regex-validated before being written.
  • Setting home: Settings → Messaging

Inbound messaging webhook (optional, kill-switched)

The inbound listener is NOT started automatically — callers instantiate InboundServer themselves (see src/messaging/inbound/server.ts). When enabled, it listens for signed webhooks from Telegram, Discord, and Slack and dispatches normalized InboundMessage events to a single registered handler. WhatsApp + Signal inbound are NOT wired in this PR (WhatsApp needs a cert-exchange handshake; Signal uses a signal-cli daemon JSON-RPC socket — both deserve their own PR).

TELEGRAM_WEBHOOK_SECRET

shared secret echoed by Telegram in the X-Telegram-Bot-Api-Secret-Token header. Set at the same time as setWebhook's secret_token parameter.

  • What it controls: requests missing or mismatching this header return 401 before the handler runs.
  • When unset: the /webhooks/telegram route returns 404 — the inbound server behaves as if Telegram inbound isn't configured.
  • Format: opaque string, 1–256 chars (Telegram's own constraint).
  • Setting home: Not a user-facing setting

SLACK_SIGNING_SECRET

Slack app signing secret (NOT the bot token).

  • What it controls: webhook signature verification using HMAC-SHA256 over v0:{timestamp}:{body}, per Slack's published scheme.
  • When unset: the HTTP webhook path can't verify Slack requests; Socket Mode (SLACK_APP_TOKEN) doesn't need it.
  • Format: opaque hex string from Basic Information → App Credentials.
  • Setting home: Settings → Messaging

DISCORD_PUBLIC_KEY / DISCORD_APPLICATION_ID

Discord app identity.

  • What it controls: the Vercel Chat SDK Discord adapter's constructor requires the application public key (even in Gateway mode), so DISCORD_PUBLIC_KEY must be set alongside DISCORD_BOT_TOKEN to build the adapter. DISCORD_APPLICATION_ID is optional and identifies the app for slash-command registration.
  • When unset: Discord is treated as unconfigured (the adapter can't be built without the public key).
  • Format: DISCORD_PUBLIC_KEY is 64-character lowercase hex (raw 32-byte Ed25519 public key); DISCORD_APPLICATION_ID is the numeric app id.
  • Setting home: Settings → Messaging

WHATSAPP_APP_SECRET / WHATSAPP_VERIFY_TOKEN

WhatsApp Cloud API inbound webhook (Meta).

  • What it controls: - WHATSAPP_APP_SECRET signs every POST via X-Hub-Signature-256 (HMAC-SHA256 over the raw body). Bad signature → 401. - WHATSAPP_VERIFY_TOKEN is the Meta hub.verify_token echoed on the one-time GET handshake when the operator registers the webhook URL in the Meta dashboard.
  • When unset: - WHATSAPP_APP_SECRET missing → /webhooks/whatsapp POST = 404. - WHATSAPP_VERIFY_TOKEN missing → /webhooks/whatsapp GET = 404.
  • Format: opaque strings; the app secret is hex from the Meta app dashboard, the verify token is whatever you configured.
  • Setting home: Settings → Messaging

PR2: Asian IM platforms (Lark / WeCom / DingTalk / WeChat OA / QQ / LINE)

Each block sets BOTH the outbound credentials AND the inbound webhook secrets needed by src/messaging/inbound/specs/<id>.ts. Leaving any block empty disables both outbound + inbound for that provider; the route 404s and the gateway is omitted from the live map.

LARK_APP_ID / LARK_APP_SECRET / LARK_DEFAULT_CHAT_ID / LARK_VERIFICATION_TOKEN / LARK_ENCRYPT_KEY / LARK_DOMAIN

Lark / Feishu — LARK_*. Tenant-token outbound + signed/encrypted webhook events.

  • What it controls: outbound Lark IM messaging; inbound webhook events (im.message.receive_v1) for the agent-loop.
  • Consumed by: src/messaging/lark.ts + src/messaging/inbound/specs/lark.ts.
  • Format: LARK_APP_ID — cli_xxxxx from Lark developer console. LARK_APP_SECRET — opaque secret from the same console. LARK_DEFAULT_CHAT_ID — default oc_xxxxx chat id. LARK_VERIFICATION_TOKEN — Event Subscription verification token. LARK_ENCRYPT_KEY — optional Event Subscription encrypt key. When set, inbound POST bodies arrive AES-256-CBC-encrypted under SHA256(encrypt_key). Leave blank for plaintext mode. LARK_DOMAIN — open.feishu.cn (default, mainland) or open.larksuite.com (international).
  • Setting home: Settings → Messaging

WECOM_CORP_ID / WECOM_AGENT_ID / WECOM_SECRET / WECOM_DEFAULT_TOUSER / WECOM_CALLBACK_TOKEN / WECOM_CALLBACK_AES_KEY

WeCom (企业微信) self-built application.

  • What it controls: outbound to WeCom users / departments + signed AES-encrypted callback inbound. WeCom routes both surfaces through the same legacy SHA1+AES envelope as WeChat OA.
  • Consumed by: src/messaging/wecom.ts + src/messaging/inbound/specs/wecom.ts.
  • Format: WECOM_CORP_ID — corp ID from "我的企业" page. WECOM_AGENT_ID — application agent ID (numeric). WECOM_SECRET — application secret. WECOM_DEFAULT_TOUSER — default recipient (@all for the whole agent). WECOM_CALLBACK_TOKEN — Token from "接收消息" callback config. WECOM_CALLBACK_AES_KEY — 43-char EncodingAESKey from same page.
  • Setting home: Settings → Messaging

DINGTALK_WEBHOOK_URL / DINGTALK_WEBHOOK_SECRET

DingTalk (钉钉) custom group robot — outbound webhook with HMAC sign.

  • What it controls: outbound to a DingTalk group via the robot's webhook URL (signed with timestamp + secret per DingTalk's spec). Inbound listens for outgoing-message webhooks DingTalk POSTs back.
  • Consumed by: src/messaging/dingtalk.ts + src/messaging/inbound/specs/dingtalk.ts.
  • Format: DINGTALK_WEBHOOK_URL — the https://oapi.dingtalk.com/robot/send?access_token=… URL. DINGTALK_WEBHOOK_SECRET — the SECxxxx signing secret from "签名" mode.
  • Setting home: Settings → Messaging

DINGTALK_STREAM_APP_KEY / DINGTALK_STREAM_APP_SECRET

Stream Mode inbound.

  • What it controls: enables the client-outbound DingTalk Stream Mode daemon. With both set, the agent opens a gateway WebSocket and receives bot messages over it — no public callback URL needed, so two-way chat works on a no-public-IP machine. Distinct from the robot webhook above: Stream Mode authenticates as the org app (AppKey / AppSecret), while replies still go out via the robot webhook.
  • Consumed by: src/messaging/inbound/dingtalk-daemon.ts.
  • When to set: you want DingTalk two-way chat without exposing a public callback. Find the AppKey / AppSecret on the app's "凭证与基础信息" page in the DingTalk developer console.
  • When unset: DingTalk inbound falls back to the outgoing-webhook route (needs a public callback URL).
  • Format: opaque strings from the DingTalk developer console.
  • Setting home: Settings → Messaging

WECHAT_OA_APP_ID / WECHAT_OA_APP_SECRET / WECHAT_OA_TOKEN / WECHAT_OA_AES_KEY / WECHAT_OA_DEFAULT_OPENID

WeChat OA (公众号) customer-service messaging.

  • What it controls: outbound customer-service messages (must be within the user's 48-hour interaction window — outside that window the platform returns errcode 45015). Inbound: signed + AES-encrypted message events.
  • Consumed by: src/messaging/wechat_oa.ts + src/messaging/inbound/specs/wechat_oa.ts.
  • Format: WECHAT_OA_APP_ID / WECHAT_OA_APP_SECRET — OA AppID + AppSecret. WECHAT_OA_TOKEN — the server-config Token from 公众平台 → 设置 → 服务器配置. WECHAT_OA_AES_KEY — 43-char EncodingAESKey from same page. WECHAT_OA_DEFAULT_OPENID — default recipient openid.
  • Setting home: Settings → Messaging

QQ_BOT_APP_ID / QQ_BOT_APP_SECRET / QQ_BOT_TOKEN / QQ_BOT_DEFAULT_CHANNEL_ID

QQ Bot v2 (Official Bot OpenAPI).

  • RATE LIMIT WARNING: official bots are capped at ONLY 4 active
  • messages per month per bot, plus 200 active DMs per day, plus 20
  • active sub-channel messages per day per channel. Most interactions
  • MUST use passive replies (≤5s after a user-initiated message);
  • active push is reserved for critical alerts.
  • Consumed by: src/messaging/qq.ts + src/messaging/inbound/specs/qq.ts.
  • Format: QQ_BOT_APP_ID — bot AppID (numeric). QQ_BOT_APP_SECRET — bot Secret (used both as outbound auth and as the seed for inbound Ed25519 signature verification). QQ_BOT_TOKEN — bot token (legacy field, retained for compatibility). QQ_BOT_DEFAULT_CHANNEL_ID — default target. Format <kind>:<id> where kind is c2c | group | channel | dm. Bare ids default to channel:.
  • Setting home: Settings → Messaging

LINE_CHANNEL_ACCESS_TOKEN / LINE_CHANNEL_SECRET / LINE_DEFAULT_USER_ID

LINE Messaging API.

  • What it controls: outbound LINE push messages (PAID metered) plus signed inbound webhook events. Reply tokens (free) are not yet wired — every outbound goes through the metered push API.
  • Consumed by: src/messaging/line.ts + src/messaging/inbound/specs/line.ts.
  • Format: LINE_CHANNEL_ACCESS_TOKEN — long-lived bearer from LINE Developers. LINE_CHANNEL_SECRET — channel secret used to verify X-Line-Signature on inbound (HMAC-SHA256, base64). LINE_DEFAULT_USER_ID — default recipient userId / groupId / roomId.
  • Setting home: Settings → Messaging

PR3: Western IM + federation (Mattermost / Teams / Google Chat / BlueBubbles / Matrix)

MATTERMOST_URL / MATTERMOST_BOT_TOKEN / MATTERMOST_DEFAULT_CHANNEL_ID / MATTERMOST_OUTGOING_WEBHOOK_TOKEN

Mattermost — bot-token outbound + outgoing-webhook inbound.

  • CAVEAT: Mattermost's outgoing-webhook feature ONLY fires in PUBLIC
  • channels and only on TRIGGER WORDS configured for the webhook.
  • Private channels and DMs need the WebSocket bot path (future PR).
  • Consumed by: src/messaging/mattermost.ts + src/messaging/inbound/specs/mattermost.ts.
  • Format: MATTERMOST_URL — Mattermost server URL (no trailing slash). MATTERMOST_BOT_TOKEN — personal access token of a bot account. MATTERMOST_DEFAULT_CHANNEL_ID — default target channel. MATTERMOST_OUTGOING_WEBHOOK_TOKEN — token compared against the token field in outgoing-webhook bodies (constant-time).
  • Setting home: Settings → Messaging

TEAMS_BOT_APP_ID / TEAMS_BOT_APP_PASSWORD / TEAMS_BOT_TENANT_ID / TEAMS_DEFAULT_CONVERSATION_ID / TEAMS_DEFAULT_SERVICE_URL

Microsoft Teams — Bot Framework with JWT-validated inbound.

  • Inbound JWT validation pulls JWKS dynamically from
  • https://login.botframework.com/v1/.well-known/openidconfiguration —
  • do NOT hard-code the JWKS URL anywhere; Microsoft rotates it.
  • Consumed by: src/messaging/teams.ts + src/messaging/inbound/specs/teams.ts.
  • Format: TEAMS_BOT_APP_ID — bot's Microsoft App ID GUID. TEAMS_BOT_APP_PASSWORD — bot's Microsoft App password. TEAMS_BOT_TENANT_ID — common for multi-tenant, GUID for single-tenant. TEAMS_DEFAULT_CONVERSATION_ID — default conversation to push to. TEAMS_DEFAULT_SERVICE_URL — default Bot Framework serviceUrl (typically https://smba.trafficmanager.net/teams). Production code should learn this from inbound activities and persist per-conversation; this env var is the bootstrap fallback.
  • Setting home: Settings → Messaging

GOOGLE_CHAT_CREDENTIALS / GOOGLE_CHAT_USE_ADC / GOOGLE_CHAT_PROJECT_NUMBER / GOOGLE_CHAT_DEFAULT_SPACE_ID

Google Chat — Vercel Chat SDK adapter (service-account or ADC; webhook inbound).

  • What it controls: outbound + inbound are served by the shared Vercel Chat SDK Google Chat adapter. Inbound is a Google-signed webhook / Pub/Sub push: the InboundServer forwards /webhooks/google_chat to chat.webhooks.google_chat (needs MESSAGING_INBOUND_ENABLED=1).
  • Consumed by: src/messaging/chatsdk/adapters/google_chat.ts.
  • Format: GOOGLE_CHAT_CREDENTIALS — service-account credentials JSON (or a path to the key file). CLAUDE.md §4: a path MUST live inside the data / sandbox tree; never reference a path outside the operator's control. GOOGLE_CHAT_USE_ADC — set to true to use Application Default Credentials instead of GOOGLE_CHAT_CREDENTIALS. GOOGLE_CHAT_PROJECT_NUMBER — GCP project number used to verify the inbound webhook signature (or set GOOGLE_CHAT_PUBSUB_AUDIENCE for Pub/Sub push). Required for inbound. GOOGLE_CHAT_DEFAULT_SPACE_ID — default space resource name (e.g. spaces/AAAA1234567).
  • Setting home: Settings → Messaging

BLUEBUBBLES_SERVER_URL / BLUEBUBBLES_PASSWORD / BLUEBUBBLES_DEFAULT_CHAT_GUID

BlueBubbles — iMessage bridge over a self-hosted server.

  • Requires the operator to run the BlueBubbles server on a Mac that
  • stays signed into the desired iMessage account. Authentication is
  • a single shared password — pure constant-time compare, no HMAC.
  • Consumed by: src/messaging/bluebubbles.ts + src/messaging/inbound/specs/bluebubbles.ts.
  • Format: BLUEBUBBLES_SERVER_URL — public URL of the BlueBubbles server (typically a tunnel like ngrok / cloudflared). BLUEBUBBLES_PASSWORD — server password (matches ?guid= query). BLUEBUBBLES_DEFAULT_CHAT_GUID — default chat GUID (e.g. iMessage;-;+15551234567).
  • Setting home: Settings → Messaging

MATRIX_HOMESERVER / MATRIX_ACCESS_TOKEN / MATRIX_USER_ID / MATRIX_DEFAULT_ROOM_ID

Matrix — federated client-server API. Inbound runs as a long-poll daemon (no HTTP webhook), gated by MESSAGING_MATRIX_INBOUND.

  • Consumed by: src/messaging/matrix.ts + src/messaging/inbound/matrix-daemon.ts.
  • Format: MATRIX_HOMESERVER — homeserver URL (e.g. https://matrix.org). MATRIX_ACCESS_TOKEN — long-lived access token. Use Bearer header, NOT the deprecated ?access_token= query form. MATRIX_USER_ID — bot user (e.g. @bot:example.org); used to filter self-loops in /sync. MATRIX_DEFAULT_ROOM_ID — default room id (e.g. !abc:example.org).
  • Caveats: this gateway does NOT support end-to-end encryption (E2EE)
  • rooms. Only plaintext rooms emit m.room.message events the
  • daemon will consume.
  • Setting home: Settings → Messaging

MESSAGING_MATRIX_INBOUND

kill-switch for the Matrix /sync daemon.

  • What it controls: when set, app boot starts the long-poll listener that emits Matrix room messages into the agent-loop bridge.
  • Consumed by: src/messaging/inbound/matrix-daemon.ts via the provider registry's inboundDaemon enumeration in src/app.ts.
  • Format: 1/true/yes/on (case-insensitive).
  • Setting home: Settings → Preferences (schema key)

MESSAGING_TELEGRAM_POLLING / MESSAGING_DISCORD_GATEWAY / MESSAGING_SLACK_SOCKET / MESSAGING_MATTERMOST_WS / MESSAGING_QQ_WS / MESSAGING_DINGTALK_STREAM / MESSAGING_LARK_WS

Client-outbound inbound daemons — override switches.

  • These platforms support BOTH a webhook (the platform connects IN to a
  • public URL) and a client-outbound daemon (the agent connects OUT and
  • holds a long connection / poll). The daemon is what makes two-way chat
  • work on a personal machine with no public IP — no tunnel, no third
  • party.
  • By DEFAULT each daemon auto-starts when the platform's outbound
  • credentials are configured AND no public webhook is wired for it
  • (i.e. its webhook signing secret is unset, or MESSAGING_INBOUND_ENABLED
  • is off). Configure a webhook for a platform and it keeps webhook
  • inbound instead. These switches are an explicit override of that
  • auto-decision and are tri-state: - unset / empty → auto (the default above) - 1/true/yes/on → force the daemon ON - 0/false/no/off → force the daemon OFF (stay webhook-only) MESSAGING_TELEGRAM_POLLING — Telegram getUpdates long-poll (src/messaging/inbound/telegram-daemon.ts). Webhook signal: TELEGRAM_WEBHOOK_SECRET. MESSAGING_DISCORD_GATEWAY — Discord Gateway WebSocket; also delivers normal channel / DM messages the Interactions webhook can't (src/messaging/inbound/discord-daemon.ts). Requires the privileged "Message Content" intent enabled in the Discord developer portal. Webhook signal: DISCORD_APPLICATION_PUBLIC_KEY. MESSAGING_SLACK_SOCKET — Slack Socket Mode; requires SLACK_APP_TOKEN (src/messaging/inbound/slack-daemon.ts). Webhook signal: SLACK_SIGNING_SECRET. MESSAGING_MATTERMOST_WS — Mattermost v4 WebSocket bot; also reaches DMs / private channels the outgoing-webhook path can't (src/messaging/inbound/mattermost-daemon.ts). Webhook signal: MATTERMOST_OUTGOING_WEBHOOK_TOKEN. MESSAGING_QQ_WS — QQ v2 gateway WebSocket (src/messaging/inbound/qq-daemon.ts). No webhook-exclusive signal (QQ's webhook reuses the outbound QQ_BOT_APP_SECRET), so the gateway daemon is preferred whenever QQ is configured; set MESSAGING_QQ_WS=0 to use the webhook instead. MESSAGING_DINGTALK_STREAM — DingTalk Stream Mode; requires DINGTALK_STREAM_APP_KEY / _SECRET (src/messaging/inbound/dingtalk-daemon.ts). DINGTALK_WEBHOOK_SECRET signs outbound sends, not webhook inbound, so it does not suppress the daemon; set MESSAGING_DINGTALK_STREAM=0 to use the webhook. MESSAGING_LARK_WS — Lark / Feishu long connection via the official SDK (src/messaging/inbound/lark-daemon.ts). Webhook signal: LARK_VERIFICATION_TOKEN.
  • Setting home: Not a user-facing setting

MESSAGING_INBOUND_TRANSCRIBE

enable voice-message transcription on inbound messages. Requires OPENAI_API_KEY.

  • What it controls: when set to 1/true/yes/on, inbound voice attachments are downloaded, transcribed via OpenAI Whisper, and the transcription populates InboundMessage.text. The original audio is retained in attachments so the downstream consumer can replay it.
  • Consumed by: src/messaging/inbound/transcribe.ts (invoked from the inbound message normalizer in follow-up work).
  • When unset: voice attachments arrive with empty text and the caller is responsible for whatever routing it wants.
  • Format: 1/true/yes/on (case-insensitive).
  • Setting home: Settings → Preferences (schema key)

MESSAGING_VOICE_REPLY

answer inbound voice notes with a spoken reply attachment in addition to the streamed text.

  • What it controls: after the agent's text reply finalizes, the reply is synthesized to audio and sent back to the same channel/thread as a voice (or audio/file, capability-dependent) attachment. Only fires when the inbound message itself contained a transcribed voice attachment. TTS failures never break the text reply.
  • Consumed by: src/messaging/inbound/agent-bridge.ts via the voice-delivery helper. Requires a configured voice provider (ELEVENLABS_API_KEY or OPENAI_API_KEY).
  • Format: 1/true/yes/on (case-insensitive).
  • Setting home: Settings → Preferences (schema key)

ELEVENLABS_API_KEY

ElevenLabs voice platform key.

  • What it controls: preferred provider for speech synthesis (TTS, eleven_turbo_v2_5) and transcription (STT, Scribe) across the gateway /v1/voice/* endpoints, web read-aloud, and messaging voice replies. When set, ElevenLabs is auto-selected over OpenAI for voice (lower latency); OpenAI remains the fallback and the only provider able to mint OGG/Opus voice notes (Telegram).
  • Consumed by: src/voice/resolve.ts.
  • When unset: voice falls back to OPENAI_API_KEY; if that is also unset, voice features are unavailable (clear error, no crash).
  • Format: sk_... from https://elevenlabs.io.
  • Setting home: Not a user-facing setting

VOICE_COMPOSER_STT_PROVIDER / VOICE_COMPOSER_STT_MODEL / VOICE_CONVERSATION_STT_PROVIDER / VOICE_CONVERSATION_STT_MODEL / VOICE_FILE_STT_PROVIDER / VOICE_FILE_STT_MODEL / VOICE_REPLY_TTS_PROVIDER / VOICE_REPLY_TTS_MODEL

Scenario-specific voice providers and models.

  • What it controls: independent provider/model choices for composer dictation, hands-free conversation, complete audio files/messages, and Agent voice replies. Provider values are auto, openai, or elevenlabs.
  • Defaults: composer/conversation: auto + gpt-live-transcribe; files/messages: auto + gpt-transcribe; replies: auto + the resolved provider's recommended TTS model.
  • Compatibility: VOICE_STT_PROVIDER/MODEL remain aliases for the file scenario; VOICE_TTS_PROVIDER/MODEL remain aliases for replies. Scenario-specific variables take precedence.
  • Consumed by: src/voice/resolve.ts and the /v1/voice/* gateway routes.
  • Setting home: Settings → Preferences (schema key)

VOICE_TTS_PROVIDER

pin the speech-synthesis vendor.

  • What it controls: overrides auto-selection (ElevenLabs first, OpenAI fallback) for TTS only.
  • Consumed by: src/voice/resolve.ts (runtime preference voice.ttsProvider).
  • Format: auto | elevenlabs | openai. Default: auto.
  • Setting home: Settings → Preferences (schema key)

VOICE_TTS_VOICE

voice id used when replies are read aloud.

  • What it controls: passed to the PRIMARY TTS provider as its native voice id (ElevenLabs voice id, or OpenAI voice name like alloy). Fallback providers use their own default voice.
  • Consumed by: src/voice/resolve.ts (runtime preference voice.ttsVoice).
  • When unset: the project default voice / OpenAI "alloy".
  • Setting home: Settings → Preferences (schema key)

VOICE_TTS_MODEL

TTS model id for the primary provider.

  • What it controls: the ElevenLabs model (also the default selected in Settings -> Voice models), and the OpenAI model when OpenAI is the primary. ElevenLabs choices: eleven_v3 (most human, default), eleven_multilingual_v2, eleven_turbo_v2_5, eleven_flash_v2_5.
  • Consumed by: src/voice/settings.ts (ElevenLabs base) + src/voice/resolve.ts (OpenAI, runtime preference voice.ttsModel).
  • When unset: eleven_v3 (ElevenLabs) / gpt-4o-mini-tts (OpenAI).
  • Setting home: Settings → Preferences (schema key)

VOICE_TTS_STABILITY / VOICE_TTS_SIMILARITY_BOOST / VOICE_TTS_STYLE / VOICE_TTS_SPEAKER_BOOST / VOICE_TTS_SPEED / VOICE_TTS_FAST_FIRST

Voice delivery defaults (ElevenLabs voice_settings). Each sets the BASE; the Settings -> Voice models sliders override on top, per user.

  • Consumed by: src/voice/settings.ts. VOICE_TTS_STABILITY 0..1 — lower = livelier, higher = steadier (default 0.6) VOICE_TTS_SIMILARITY_BOOST 0..1 — adherence to the voice timbre (default 0.8) VOICE_TTS_STYLE 0..1 — expressiveness / personality (default 0.45) VOICE_TTS_SPEAKER_BOOST 1/0 — clarity boost (default on) VOICE_TTS_SPEED 0.7..1.2 — playback rate (default 0.9) VOICE_TTS_FAST_FIRST 1/0 — read the first sentence of each reply on the fastest model so speech starts sooner (default on)
  • Setting home: Not a user-facing setting

VOICE_STT_PROVIDER

pin the speech-to-text vendor.

  • Consumed by: src/voice/resolve.ts (runtime preference voice.sttProvider).
  • Format: auto | elevenlabs | openai. Default: auto.
  • Setting home: Settings → Preferences (schema key)

VOICE_FFMPEG_PATH

optional ffmpeg binary for voice transcodes.

  • What it controls: AMR voice formats (WeCom, WeChat OA without the built-in transcript) hop through ffmpeg before STT, and WeCom voice replies transcode mp3 → AMR. When unset, "ffmpeg" is looked up on PATH; when neither resolves, those transcodes are skipped and the affected platform degrades gracefully.
  • Consumed by: src/messaging/audio-transcode.ts.
  • Setting home: Not a user-facing setting

VOICE_STT_MODEL

STT model id for the primary provider.

  • Consumed by: src/voice/resolve.ts (runtime preference voice.sttModel).
  • When unset: scribe_v1 (ElevenLabs) / gpt-4o-mini-transcribe (OpenAI).
  • Setting home: Settings → Preferences (schema key)

GLASSNODE_API_KEY

Glassnode on-chain analytics.

  • What it controls: on-chain metric endpoints (SOPR, MVRV, realised cap, flows, etc.).
  • Consumed by: src/tools/providers/glassnode.ts. Gates the research.onchain.glassnode skill via requires_env.
  • When to set: you have a Glassnode subscription and want the agent to cite on-chain indicators directly.
  • When unset: the glassnode skill is hidden from the catalog.
  • Format: opaque API key from https://glassnode.com.
  • Setting home: Settings → API Keys

QDRANT_URL / QDRANT_API_KEY

vector database for research KB.

  • What it controls: (1) the research.knowledge_base skill — teaches the agent to query the operator's curated Qdrant collections (news, projects, people, docs) via curl from the terminal. (2) the kb_search tool — first-class wrapper around the same Qdrant query path, used by institution-mode analysts (news / fundamentals / sentiment) BEFORE falling back to web_search.
  • Consumed by: src/skills/builtin/research-knowledge-base.ts (skill) and src/tools/kb-search.ts (institution-mode tool). Both gate on QDRANT_URL being present; kb_search ALSO requires a configured embeddings provider (EMBEDDING_PROVIDER + EMBEDDING_API_KEY).
  • When to set: you want the agent to query an existing v1-populated Qdrant instance for fresher / narrower news + project facts than open-web search returns.
  • When unset: the knowledge_base skill is hidden from the catalog and the kb_search tool isn't registered. Institution analysts fall back to web_search (zero behavior change).
  • Format: QDRANT_URL is an absolute URL (https://xxx.qdrant.io). QDRANT_API_KEY is optional — only set if your deployment requires auth (Qdrant Cloud does; a local docker usually doesn't).
  • Setting home: Not a user-facing setting (QDRANT_URL)
  • Setting home: Settings → API Keys (QDRANT_API_KEY)

KB_EMBEDDING_PROVIDER / KB_EMBEDDING_API_KEY / KB_EMBEDDING_MODEL / KB_EMBEDDING_DIM

KB-specific Embedder override for kb_search ONLY.

  • What it controls: which embedder is used to embed kb_search query strings before posting them to Qdrant. The embedder MUST match the one that originally populated the Qdrant collections — a dimension mismatch yields a 400 from Qdrant on every call.
  • When to set: only when your kb_search Qdrant instance was populated with a DIFFERENT embedder than the one you use for memory (EMBEDDING_PROVIDER / EMBEDDING_MODEL). Common case: v1 Qdrant populated with OpenAI text-embedding-3-small (1536d) while you run voyage-3 (1024d) for memory.
  • When unset: kb_search falls back to the shared embedder (EMBEDDING_PROVIDER + EMBEDDING_API_KEY + EMBEDDING_MODEL + EMBEDDING_DIM). If memory and KB share the same model, no override is needed.
  • Format: identical accepted values to the EMBEDDING_* family above. KB_EMBEDDING_API_KEY defaults to EMBEDDING_API_KEY when unset (so OpenAI users only need to set the provider + model overrides).
  • Setting home: Not a user-facing setting (KB_EMBEDDING_PROVIDER, KB_EMBEDDING_MODEL, KB_EMBEDDING_DIM)
  • Setting home: Settings → API Keys (KB_EMBEDDING_API_KEY)

E2B_API_KEY

Kernel cloud-browser coordinator (https://e2b.dev).

  • What it controls: lets the workbench start the Kernel cloud Chromium session (coordinator sandbox). Pair with KERNEL_API_KEY. This key does not move shell, files, or execute_code off the gateway host.
  • Consumed by: the workbench cloud-browser runtime (Kernel bootstrap). Resolved at call time (a key added in Settings → API Keys works without a restart).
  • When to set: Desktop/CLI when you want Kernel Live View instead of a local browser. Hosted Web Browser also needs it for the coordinator.
  • When unset: cloud browser placement is unavailable; Desktop/CLI stay on a local browser when the host allows it.
  • Format: opaque key from https://e2b.dev dashboard.
  • Safety: never inject a shared org key into a per-user hosted agent for the sake of running bash. Shell stays on the gateway VM.
  • Setting home: Settings → API Keys

KERNEL_API_KEY

KERNEL_API_KEY, managed Chromium for the Web Browser workbench.

  • What it controls: creates the Kernel cloud Chromium session used by the Web Browser workbench. The same session supplies the embedded Live View and the CDP endpoint used by agent browser tools.
  • Consumed by: the workbench cloud-browser runtime. It resolves at call time, so a key saved in Settings > API Keys applies without a restart.
  • When to set: when Web users need an interactive remote Browser. The runtime also requires E2B_API_KEY for the kernel-browser coordinator.
  • When unset: the Web Browser shows a setup screen with links to the official Kernel key documentation and dashboard. Desktop native Browser sessions remain available.
  • Format: opaque API key created at https://dashboard.onkernel.com.
  • Setting home: Settings → API Keys

WORKBENCH_E2B_SESSION_IDLE_SECONDS

Web cloud-resource pause grace period.

  • What it controls: how long the Gateway waits after the final Web client leaves a Chat or Institution session before pausing that session's cloud Browser. Pause keeps the Kernel session until timeout; shell on the gateway host is unaffected.
  • Consumed by: Preferences computer.cloudSessionIdleSeconds → the Gateway workbench cloud-resource reaper. Desktop native Browser and Computer sessions do not use this setting.
  • Default when unset: 60 seconds (1 minute).
  • When to set: raise it to preserve cloud state across slower session switches, or lower it to pause sooner. Prefer Settings → Preferences; env is an override. Returning before the delay expires cancels the pending pause.
  • Format: a finite number of seconds from 0 through 3600. Invalid or negative values use the 60-second default. Terminals are unaffected.
  • Setting home: Settings → Preferences (schema key)

MINARA_EXECUTION_BOUNDARY

guest VM ownership.

  • What it controls: Selects host filesystem protection or root execution within an owner-controlled VM. The value is fixed at process boot; session modes and tool arguments cannot change it.
  • Consumed by: config/execution-boundary.ts, local file/command checks, script analysis and process wrapping. Browser placement is independent.
  • Default when unset: host: retain desktop/CLI host directory and credential protections.
  • When to set: The E2B template sets owner-vm for its single-tenant guest. The guest owner can control gateway files and credentials; keep platform secrets and authorization outside the VM. Never use on shared machines.
  • Format: host or owner-vm. owner-vm requires Linux and uid 0; invalid values or incompatible process identity fail startup.
  • Setting home: Not a user-facing setting

MINARA_HOST_KIND

override gateway host classification.

  • What it controls: forces the gateway host kind used for Browser/Computer backend selection: desktop | local-cli | hosted-e2b | web-remote.
  • Consumed by: src/computer/host.ts (currentHostKind). Placement, capability endpoints, Chromium launch policy, and private-URL rules all read this classification.
  • Default when unset: inferred from MINARA_DESKTOP_PID / computer bridge / CDP, E2B_SANDBOX_ID or CREDENTIALS_DEK+/data, then GATEWAY_HOST, else local-cli.
  • When to set: tests and operator diagnostics only. Production Desktop and hosted-e2b should rely on the automatic signals.
  • Format: one of: desktop, local-cli, hosted-e2b, web-remote.
  • Setting home: Not a user-facing setting

MINARA_COMPUTER_BACKEND

pin session runtime (local / cloud / docker).

  • What it controls: pins session runtime (browser, shell, and files) to local, cloud, or docker, or leaves auto (Desktop-local-first). Shell and files always follow the gateway process unless you pin docker. cloud only selects the Kernel cloud browser; GUI computer use stays Desktop-only. Hosted hosts always use a cloud browser and run bash on the agent VM.
  • Consumed by: Preferences computer.backend → src/computer/backends.ts (readSessionBackendOverride) and session-runtime placement via SessionRuntimeStore.
  • Default when unset: auto: hosted → local shell + cloud browser; Desktop prefers native bridge when available (even with cloud keys); Desktop without bridge uses cloud browser when E2B_API_KEY + KERNEL_API_KEY are set, else local; local-cli stays local (keys only enable an explicit Cloud browser pin). Docker is never chosen by auto — pin docker explicitly.
  • When to set: prefer Settings → Preferences → Session runtime. cloud forces the Kernel browser (shell stays on this host); docker forces the local container backend (needs MINARA_DOCKER_SANDBOX_IMAGE); local forces the Desktop bridge (fails clearly if missing).
  • Format: auto, local, cloud, or docker. Empty / unset = auto.
  • Setting home: Settings → Preferences (schema key)

MINARA_DOCKER_SANDBOX_IMAGE

Docker execution backend image.

  • What it controls: container image for the sticky docker execution backend (shell + files + execute_code in one container). Pin Preferences computer.backend=docker (or MINARA_COMPUTER_BACKEND=docker) to select it — there is no per-call environment override. Hardened: capabilities dropped except the minimum package managers need, no-new-privileges, PID limit, size-limited /tmp; no host bind mounts, no host env forwarding. One container per chat session, reused across calls, removed after 15 min idle.
  • Consumed by: src/tools/_execution/docker-environment.ts via the ExecutionRouter wired in src/app.ts. Resolved at call time.
  • When to set: you want strong local isolation for untrusted code without a second cloud VM. Requires a running Docker (or Podman) daemon; the CLI is discovered on PATH and at the usual Docker Desktop locations.
  • When unset: the docker backend is unavailable; code/shell runs on the gateway host.
  • Format: any pullable image reference with the language runtimes you need, e.g. python:3.12-slim or node:22-slim.
  • Safety: same posture as local isolation — the container is the security boundary and holds no host credentials unless explicitly provisioned via environment_provision_credentials. Select docker only by pinning Preferences computer.backend=docker (no per-call override).
  • Setting home: Not a user-facing setting

MINARA_GITHUB_APP_CLIENT_ID

public client id for Coding GitHub sign-in.

  • What it controls: overrides the public GitHub App identity shared by Coding Git access and the GitHub plugin. Each user still authorizes their own account and repositories.
  • Consumed by: the Agent infrastructure resolver and Desktop product configuration. Desktop uses environment > packaged configuration > the shared product default; standalone Agent uses environment > default.
  • When to set: only when a deployment uses a different GitHub App with device flow and the required repository permissions.
  • When unset: unset, empty, or whitespace-only values use Minara's public App client id, Iv23libEOaSiY90hGqII. End users do not need to configure this variable. Local SSH remains independent.
  • Format: the optional product-owned GitHub App client id (for example, Iv1.example). This is not a client secret.
  • Setting home: Not a user-facing setting

MINARA_FILTERED_SSH_AGENT

internal Desktop SSH authority marker.

  • What it controls: marks SSH_AUTH_SOCK as a Desktop-owned filtered endpoint that exposes only the identity selected by the owner.
  • Consumed by: src/gateway/api.ts when wiring the local SSH credential provider.
  • When to set: never set it manually; Minara Desktop injects it only while its filtered SSH-agent proxy is active.
  • When unset: the local SSH credential provider stays unavailable rather than trusting an unrestricted ambient SSH agent.
  • Format: the internal value 1; any other value is treated as unset.
  • Setting home: Not a user-facing setting

MINARA_CLOUD_CREDENTIAL_FILES

credential files provisioned into the docker execution container — OPERATOR-DECLARED, upload-only.

  • What it controls: the file set environment_provision_credentials uploads into the remote execution container so code running there can authenticate. The agent cannot choose paths — only this config can. Each entry maps a file INSIDE the data dir to an absolute VM destination. Local paths must be relative to MINARA_DATA_DIR; absolute paths, .. traversal, and symlinks escaping the data dir are rejected entry-by-entry at parse time. Provisioned VM paths are upload-only: environment_pull_file refuses to read them back, and file contents never enter the model context.
  • Consumed by: src/tools/_execution/credential-provision.ts via src/tools/environment-files.ts.
  • When to set: code you run in the cloud VM needs an API key file / token file. Prefer read-only, low-blast-radius credentials — the VM has full network egress. Never declare wallet keys or fund-moving credentials here.
  • When unset: environment_provision_credentials reports no files; cloud runs are credential-free (the default posture).
  • Format: JSON array of {"local": "<relative path>", "remote": "/abs/vm/path"}. Example: [{"local":"cloud-creds/market.json","remote":"/root/.creds/market.json"}]
  • Setting home: Not a user-facing setting

On this page

web_search / web_extract backendEXA_API_KEYFIRECRAWL_API_KEYTAVILY_API_KEYGOAL_MAX_TURNSPOSITION_MEMORY_ENABLEDOPENAI_API_KEYOPENAI_BASE_URLOPENAI_ORG_IDFAL_KEY / FAL_QUEUE_URLMessaging gatewaysMESSAGING_DEFAULT_PROVIDERMESSAGING_MAX_ATTACHMENT_BYTESTELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_IDTELEGRAM_RICH_TEXTSLACK_BOT_TOKEN / SLACK_CHANNEL_IDSLACK_APP_TOKENDISCORD_BOT_TOKEN / DISCORD_CHANNEL_IDHASS_URL / HASS_TOKEN / HASS_NOTIFY_SERVICESMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD / EMAIL_FROM / EMAIL_TOGOOGLE_OAUTH_CLIENT_ID / GOOGLE_OAUTH_CLIENT_SECRETGMAIL_REFRESH_TOKEN / GMAIL_SENDER_EMAIL / GMAIL_TOWHATSAPP_ACCESS_TOKEN / WHATSAPP_PHONE_NUMBER_ID / WHATSAPP_RECIPIENTSIGNAL_CLI_NUMBER / SIGNAL_RECIPIENT / SIGNAL_CLI_BINARYInbound messaging webhook (optional, kill-switched)TELEGRAM_WEBHOOK_SECRETSLACK_SIGNING_SECRETDISCORD_PUBLIC_KEY / DISCORD_APPLICATION_IDWHATSAPP_APP_SECRET / WHATSAPP_VERIFY_TOKENPR2: Asian IM platforms (Lark / WeCom / DingTalk / WeChat OA / QQ / LINE)LARK_APP_ID / LARK_APP_SECRET / LARK_DEFAULT_CHAT_ID / LARK_VERIFICATION_TOKEN / LARK_ENCRYPT_KEY / LARK_DOMAINWECOM_CORP_ID / WECOM_AGENT_ID / WECOM_SECRET / WECOM_DEFAULT_TOUSER / WECOM_CALLBACK_TOKEN / WECOM_CALLBACK_AES_KEYDINGTALK_WEBHOOK_URL / DINGTALK_WEBHOOK_SECRETDINGTALK_STREAM_APP_KEY / DINGTALK_STREAM_APP_SECRETWECHAT_OA_APP_ID / WECHAT_OA_APP_SECRET / WECHAT_OA_TOKEN / WECHAT_OA_AES_KEY / WECHAT_OA_DEFAULT_OPENIDQQ_BOT_APP_ID / QQ_BOT_APP_SECRET / QQ_BOT_TOKEN / QQ_BOT_DEFAULT_CHANNEL_IDLINE_CHANNEL_ACCESS_TOKEN / LINE_CHANNEL_SECRET / LINE_DEFAULT_USER_IDPR3: Western IM + federation (Mattermost / Teams / Google Chat / BlueBubbles / Matrix)MATTERMOST_URL / MATTERMOST_BOT_TOKEN / MATTERMOST_DEFAULT_CHANNEL_ID / MATTERMOST_OUTGOING_WEBHOOK_TOKENTEAMS_BOT_APP_ID / TEAMS_BOT_APP_PASSWORD / TEAMS_BOT_TENANT_ID / TEAMS_DEFAULT_CONVERSATION_ID / TEAMS_DEFAULT_SERVICE_URLGOOGLE_CHAT_CREDENTIALS / GOOGLE_CHAT_USE_ADC / GOOGLE_CHAT_PROJECT_NUMBER / GOOGLE_CHAT_DEFAULT_SPACE_IDBLUEBUBBLES_SERVER_URL / BLUEBUBBLES_PASSWORD / BLUEBUBBLES_DEFAULT_CHAT_GUIDMATRIX_HOMESERVER / MATRIX_ACCESS_TOKEN / MATRIX_USER_ID / MATRIX_DEFAULT_ROOM_IDMESSAGING_MATRIX_INBOUNDMESSAGING_TELEGRAM_POLLING / MESSAGING_DISCORD_GATEWAY / MESSAGING_SLACK_SOCKET / MESSAGING_MATTERMOST_WS / MESSAGING_QQ_WS / MESSAGING_DINGTALK_STREAM / MESSAGING_LARK_WSMESSAGING_INBOUND_TRANSCRIBEMESSAGING_VOICE_REPLYELEVENLABS_API_KEYVOICE_COMPOSER_STT_PROVIDER / VOICE_COMPOSER_STT_MODEL / VOICE_CONVERSATION_STT_PROVIDER / VOICE_CONVERSATION_STT_MODEL / VOICE_FILE_STT_PROVIDER / VOICE_FILE_STT_MODEL / VOICE_REPLY_TTS_PROVIDER / VOICE_REPLY_TTS_MODELVOICE_TTS_PROVIDERVOICE_TTS_VOICEVOICE_TTS_MODELVOICE_TTS_STABILITY / VOICE_TTS_SIMILARITY_BOOST / VOICE_TTS_STYLE / VOICE_TTS_SPEAKER_BOOST / VOICE_TTS_SPEED / VOICE_TTS_FAST_FIRSTVOICE_STT_PROVIDERVOICE_FFMPEG_PATHVOICE_STT_MODELGLASSNODE_API_KEYQDRANT_URL / QDRANT_API_KEYKB_EMBEDDING_PROVIDER / KB_EMBEDDING_API_KEY / KB_EMBEDDING_MODEL / KB_EMBEDDING_DIME2B_API_KEYKERNEL_API_KEYWORKBENCH_E2B_SESSION_IDLE_SECONDSMINARA_EXECUTION_BOUNDARYMINARA_HOST_KINDMINARA_COMPUTER_BACKENDMINARA_DOCKER_SANDBOX_IMAGEMINARA_GITHUB_APP_CLIENT_IDMINARA_FILTERED_SSH_AGENTMINARA_CLOUD_CREDENTIAL_FILES