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_searchandweb_extractwhen 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 platformexaPassthrough. 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_searchandweb_extractwhen Tavily is not available./searchreturns titles/URLs;/scrapereturns 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_searchandweb_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_KEYwhich writes theopenaiApiKeyprofile 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-Organizationon 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(or0/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 aC...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:writescope. - 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 Messagespermissions (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 leadingnotify.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.sendscope (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) — thechannelargument ofsend_messageoverrides 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-clitool available on the host. - When unset: The signal channel MCP tools are unavailable until the gateway is configured.
- Runtime dependency:
signal-climust 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 forsignal-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-mslot, 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_tokenechoed 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_xxxxxfrom Lark developer console. LARK_APP_SECRET — opaque secret from the same console. LARK_DEFAULT_CHAT_ID — defaultoc_xxxxxchat 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) oropen.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 (
@allfor 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 — theSECxxxxsigning 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 tochannel:. - 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
tokenfield 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 —
commonfor multi-tenant, GUID for single-tenant. TEAMS_DEFAULT_CONVERSATION_ID — default conversation to push to. TEAMS_DEFAULT_SERVICE_URL — default Bot Framework serviceUrl (typicallyhttps://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
trueto 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.messageevents 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 populatesInboundMessage.text. The original audio is retained inattachmentsso 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
textand 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, orelevenlabs. - 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.glassnodeskill viarequires_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) thekb_searchtool — 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_searchquery 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_searchQdrant 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, ordocker, or leavesauto(Desktop-local-first). Shell and files always follow the gateway process unless you pindocker.cloudonly 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
dockerexplicitly. - When to set: prefer Settings → Preferences → Session runtime.
cloudforces the Kernel browser (shell stays on this host);dockerforces the local container backend (needs MINARA_DOCKER_SANDBOX_IMAGE);localforces the Desktop bridge (fails clearly if missing). - Format:
auto,local,cloud, ordocker. 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-callenvironmentoverride. 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-slimornode: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_credentialsuploads 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_filerefuses 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