Multica Docs

Environment variables

Common server, storage, integration, and runtime configuration for self-hosting Multica.

Multica reads environment variables at process startup. After changing one, restart the affected API, web, or daemon process. Docker Compose's docker compose restart does not re-read .env; recreate containers with up -d for changes to take effect.

This page lists deployment-facing configuration only; test variables and internal run variables are not covered here. It is a grouped reference — for full deployment steps, see the self-host quickstart.

Minimum production configuration

DATABASE_URL=postgres://user:password@postgres:5432/multica?sslmode=require
JWT_SECRET=<long-random-secret>
APP_ENV=production
FRONTEND_ORIGIN=https://multica.example.com
MULTICA_APP_URL=https://multica.example.com
MULTICA_PUBLIC_URL=https://api.multica.example.com

You also need to pick an email service, otherwise verification codes and invitations are only written to the server log.

JWT_SECRET is required in production: with APP_ENV=production the backend refuses to boot if it is empty or a known placeholder (generate one with openssl rand -hex 32). Do not set MULTICA_DEV_VERIFICATION_CODE.

API and database

VariableDefaultDescription
DATABASE_URLlocal multica databasePostgreSQL connection string
DATABASE_MAX_CONNS25Maximum database connections per API process
DATABASE_MIN_CONNS5Minimum connections each API process keeps
DATABASE_SEARCH_WORK_MEM_MB64PostgreSQL work_mem ceiling in MB for each search plan node; set 1-64 to lower it or 0 to keep the database/session default
DATABASE_REPLICA_URLemptyOptional PostgreSQL read-only replica connection string; new connections are validated as read-only, while businesses must explicitly opt into eventual-consistency reads in code
DATABASE_REPLICA_MAX_CONNS10Maximum replica connections per API process
DATABASE_REPLICA_MIN_CONNS0Minimum replica connections each API process keeps
MULTICA_DATABASE_STARTUP_TIMEOUT3mContainer-level retry budget shared by migration and API startup; set to 0 for one fail-fast attempt per phase
MULTICA_DATABASE_CONNECT_TIMEOUT5sFallback timeout for each startup connection attempt; native pgx connect_timeout, PGCONNECT_TIMEOUT, or service settings take precedence
PORT8080API listen port
JWT_SECRETrequired in productionSecret for sign-in JWTs and some signing flows; production refuses to boot on empty or known placeholders
APP_ENVemptySet to production in production
AUTH_TOKEN_TTL720h (30 days)Lifetime of browser JWTs and cookies; accepts a Go duration or a positive integer of seconds. Sessions slide: one in continuous use is re-issued rather than expiring, from the halfway point of its lifetime onward. Values below 60s are clamped to 60s
LOG_LEVELapplication defaultLog level
MULTICA_SHUTDOWN_HOLD_DURATION0How long to wait after a termination signal before graceful shutdown begins
MULTICA_RUNTIME_RECONNECT_GRACE3hHow long an offline runtime may reconnect before its in-flight runs fail; values below 150s are clamped

When setting a shutdown hold on Kubernetes, terminationGracePeriodSeconds must exceed the hold plus the time the actual shutdown needs.

The primary and replica connection limits are independent. Budget their sum across every API process against the PostgreSQL cluster's connection ceiling. Replica connections are recycled after five minutes by default to refresh read-only validation after promotion. Replica connection failures transparently fall back to primary and open a short passive circuit; no background database probe is added. Replica reads have no application-enforced staleness bound, so monitor lag in the database layer and keep consistency-sensitive reads on primary.

Public URLs and browser access

VariableDefaultDescription
FRONTEND_ORIGINemptyFrontend origin users visit; used for CORS, cookies, and invitation links
MULTICA_APP_URLfalls back to FRONTEND_ORIGINUser-reachable web URL; CLI sign-in and account-link URLs use it
MULTICA_PUBLIC_URLemptyPublic API URL; used for webhook URLs and runtime connection instructions
MULTICA_DAEMON_SERVER_URLfalls back to MULTICA_PUBLIC_URL, then MULTICA_APP_URL / FRONTEND_ORIGINServer URL the API process inserts into multica setup self-host; set it when daemons reach the API at a different URL than the public webhook URL
CORS_ALLOWED_ORIGINSemptyExtra allowed HTTP origins, comma-separated
ALLOWED_ORIGINSfalls back to CORS / frontend originsWebSocket origin allowlist, comma-separated
COOKIE_DOMAINemptyRequired when the frontend and API use different hosts and the browser talks to the API domain directly; keep empty for single-domain deployments

MULTICA_DAEMON_SERVER_URL is returned by the unauthenticated /api/config endpoint and is visible to clients. Treat it as public configuration; never put credentials, tokens, or other secrets in it.

When the frontend and API run on different hosts and the browser talks to the API domain directly, you must set COOKIE_DOMAIN — otherwise the browser cannot read the CSRF cookie: every write request returns 403 CSRF validation failed while reads work fine. Use the narrowest parent domain that covers both hosts (.agent.example.com over .example.com). It spreads the sign-in session cookie to every host under that domain, which is only acceptable when all of those hosts are operated by the same trusted party. After changing it, clear the old cookies on both hosts and sign in again. If you follow the same-origin recipe in the self-host quickstart (the browser only visits the app domain), keep it empty. Do not use an IP address — browsers ignore cookies whose Domain is an IP.

Self-hosted deployments must set FRONTEND_ORIGIN. Without it, invitation links, cookie security attributes, and WebSocket origin checks can all disagree with your actual domain.

Email and sign-in

Resend

VariableDefaultDescription
RESEND_API_KEYemptySetting it enables Resend
RESEND_FROM_EMAILnoreply@multica.aiSender address; must belong to a verified domain

SMTP

SMTP takes priority over Resend whenever SMTP_HOST is non-empty.

VariableDefaultDescription
SMTP_HOSTemptySMTP host; setting it enables SMTP
SMTP_PORT25Common values: 25, 587, 465
SMTP_USERNAMEemptyUsername; leave empty for anonymous relays
SMTP_PASSWORDemptyPassword
SMTP_FROM_EMAILfalls back to RESEND_FROM_EMAILEnvelope From and message From
SMTP_TLSstarttlsimplicit, smtps, or ssl means implicit TLS; port 465 enables it automatically
SMTP_TLS_INSECUREfalseSkips certificate verification; trusted internal networks only
SMTP_EHLO_NAMEhostnameEHLO/FQDN required by strict relays

Google OAuth

VariableDefaultDescription
GOOGLE_CLIENT_IDemptyGoogle OAuth client ID
GOOGLE_CLIENT_SECRETemptyGoogle OAuth client secret
GOOGLE_REDIRECT_URIhttp://localhost:3000/auth/callbackMust exactly match the callback URL in the Google Console

Signup scope

VariableDefaultDescription
ALLOW_SIGNUPtrueWhether new accounts can be created when no allowlist is configured
ALLOWED_EMAILSemptyFull email addresses allowed to sign up, comma-separated
ALLOWED_EMAIL_DOMAINSemptyEmail domains allowed to sign up, comma-separated
DISABLE_WORKSPACE_CREATIONfalseBlocks all users from creating workspaces; no owner/admin exception
MULTICA_DEV_VERIFICATION_CODEemptyFixed 6-digit test code for non-production environments

For the exact allowlist evaluation order, see Sign-in and signup.

Attachment storage

When S3_BUCKET is unset, Multica uses local disk.

S3 or compatible storage

VariableDefaultDescription
S3_BUCKETemptyBucket name; do not use the full hostname
S3_REGIONus-west-2Region the bucket lives in
AWS_ACCESS_KEY_IDSDK default credential chainStatic access key
AWS_SECRET_ACCESS_KEYSDK default credential chainStatic secret key
AWS_ENDPOINT_URLemptyS3-compatible endpoint such as MinIO
S3_USE_PATH_STYLEtrue with a custom endpointWhether to use path-style addressing
ATTACHMENT_DOWNLOAD_MODEautoauto, cloudfront, presign, or proxy
ATTACHMENT_DOWNLOAD_URL_TTL30mLifetime of signed download URLs

Use ATTACHMENT_DOWNLOAD_MODE=proxy when the endpoint — an internal MinIO, for example — is not reachable from the browser.

Local disk

VariableDefaultDescription
LOCAL_UPLOAD_DIR./data/uploadsDirectory for files and metadata; needs a persistent volume
LOCAL_UPLOAD_BASE_URLemptyOptional public base URL; when empty, in-app relative URLs are returned

CloudFront

VariableDescription
CLOUDFRONT_DOMAINCDN domain
CLOUDFRONT_KEY_PAIR_IDCloudFront key pair ID
CLOUDFRONT_PRIVATE_KEYFull private key
CLOUDFRONT_PRIVATE_KEY_SECRETUse when reading the private key from Secrets Manager

Redis and rate limiting

VariableDefaultDescription
REDIS_URLemptyThe one connection URL used by all Redis-backed features, including shared rate limiting, realtime events, channel WebSocket leases, and token caches
REDIS_CLUSTER_MODEfalseForces the Redis Cluster client, including for a single configuration endpoint; cluster mode requires database 0 and REALTIME_RELAY_MODE=sharded
REDIS_DISABLE_CLIENT_NAMEfalseSet true when a managed Redis blocks CLIENT SETNAME
RATE_LIMIT_AUTH5Per-IP requests per minute to send a verification code or start Google sign-in
RATE_LIMIT_AUTH_VERIFY20Per-IP code verifications per minute
RATE_LIMIT_INVITATION_ACTOR_10M10Workspace invitations each inviter may create per 10-minute sliding window; 0 disables this gate
RATE_LIMIT_INVITATION_WORKSPACE_24H50Workspace invitations all admins may create per workspace per 24-hour sliding window; 0 disables this gate
RATE_LIMIT_INVITATION_RECIPIENT_24H6Invitations one normalized recipient email may receive across workspaces per 24-hour sliding window; 0 disables this gate
RATE_LIMIT_TRUSTED_PROXIESemptyComma-separated proxy CIDRs allowed to provide X-Forwarded-For
MULTICA_TRUSTED_PROXIESemptyTrusted proxy CIDRs for automation webhooks and realtime connections

Deployments behind a reverse proxy must list their real proxy ranges. Do not blanket-trust all sources, or clients can forge forwarded IPs.

The auth rate limits require REDIS_URL; without it, the startup log notes that auth rate limiting is disabled. Invitation limits still run in process-local memory without Redis and become shared across replicas when Redis is configured. If configured Redis becomes temporarily unavailable, auth rate limiting fails open, while invitation creation returns a retryable 503 instead of sending email without protection.

External integrations

IntegrationVariableDescription
GitHubGITHUB_APP_SLUGGitHub App slug
GitHubGITHUB_WEBHOOK_SECRETWebhook HMAC and connect-state signing secret
GitHubGITHUB_APP_IDNeeded for CI status and mergeability on PR cards and the "pick from GitHub" repository picker
GitHubGITHUB_APP_PRIVATE_KEYFull PEM private key paired with the App ID; same uses as above
LarkMULTICA_LARK_SECRET_KEYBase64-encoded 32-byte credential encryption key
SlackMULTICA_SLACK_SECRET_KEYBase64-encoded 32-byte token encryption key
TelegramMULTICA_TELEGRAM_SECRET_KEYBase64-encoded 32-byte Bot token encryption key
ComposioCOMPOSIO_API_KEYEnables Composio tool connections
ComposioCOMPOSIO_CALLBACK_BASE_URLCallback API URL; can fall back to MULTICA_PUBLIC_URL
ComposioCOMPOSIO_STATE_SECRETOAuth state signing secret; can be derived from JWT_SECRET
Self-hosted GitMULTICA_VCS_INTEGRATION_ENABLEDForgejo/Gitea/GitLab integration switch; enabled by default in compose
Self-hosted GitMULTICA_VCS_SECRET_KEYBase64-encoded 32-byte encryption key (openssl rand -base64 32); the feature is entirely unavailable without it
PluginsMULTICA_PLUGIN_SECRET_KEYBase64-encoded 32-byte key for stored secrets and encrypted surface launch URLs
PluginsMULTICA_PLUGIN_SURFACE_ORIGINDedicated cookie-free browser origin routed to this backend; must differ from app/API origins and preserve Host
PluginsMULTICA_PLUGIN_API_URLComplete versioned Plugin Public API base URL, such as https://plugin-api.example.com/v1; falls back to MULTICA_PUBLIC_URL + /v1
PluginsMULTICA_PLUGIN_DIROptional absolute directory used to publish local plugin bundles during development

Without GITHUB_APP_ID and the private key, PRs still link, mirror, and trigger merge-to-done normally, but cards show no CI or mergeability status, and the "pick from GitHub" repository entry is disabled.

For setup steps, see GitHub integration, Lark bot, Slack bot, and Telegram bot.

Server-side LLM

This group configures server-side assist generation, such as conversation titles; it is not the AI coding tool credentials agents use to execute runs.

VariableDefaultDescription
MULTICA_LLM_API_KEYemptyOpenAI-compatible API key
MULTICA_LLM_BASE_URLemptyOpenAI-compatible endpoint
MULTICA_LLM_DEFAULT_MODELgpt-5.6-lunaUsed when a request does not specify a model
MULTICA_LLM_MAX_RETRIES2Retry ceiling per call; 0 disables retries, 15 cap it at N

MULTICA_LLM_MAX_RETRIES is the single source for the retry policy. Leave it unset for the default of 2, set 0 to send exactly one request per call, or set 1–5 to cap retries at that many. It is a ceiling, not a quota: only retryable failures consume it, and a success or the caller's own deadline can end the call sooner. Any other value — negative, non-numeric, or above 5 — fails startup instead of being corrected silently. The ceiling is a latency budget: backoff starts at 0.5s and doubles to an 8s cap, so a larger budget would outlast the callers' own deadlines and turn a retryable failure into a timeout. Retries cover connection failures and HTTP 408, 409, 429 and 5xx; all other 4xx responses are returned as-is. The server logs the effective policy at startup as llm retry policy, with no credentials in the line.

Two features use this layer, and each one sends chat content to the endpoint you configure:

  • Chat auto-titling — the first user message of a new chat session, sent verbatim. Attachments are never included.
  • Follow-up questions (the suggestion buttons under an agent reply) — the tail of the conversation: up to 6 messages, with the reply being answered capped at 3000 characters and each older message at 800.

When both the API key and the base URL are empty, this layer is disabled and makes no upstream request at all — neither feature above sends anything. That is the supported configuration when your policy does not allow this layer to send chat content off the deployment: chat sessions keep the title the client derives from the first message, the follow-up question buttons do not appear, and everything else is unaffected.

This covers the assist layer only. Running an agent is a separate data path: when an agent answers a chat, your daemon executes that agent's AI coding tool using the tool's own credentials, and does not forward the MULTICA_LLM_* settings above to it. (The run-scoped Multica connection variables the agent needs are injected by the daemon separately.) Emptying the variables above does not affect that path — govern it through the agent's runtime configuration.

Daemon configuration

The variables below are read on the computer that runs your agents, not in the API container.

VariableDefaultDescription
MULTICA_SERVER_URLws://localhost:8080/wsMultica API / WebSocket URL; also accepts http(s)
MULTICA_DAEMON_DEVICE_NAMEhostnameDevice name shown in the runtime list
MULTICA_AGENT_RUNTIME_NAMELocal AgentRuntime display name
MULTICA_DAEMON_POLL_INTERVAL30sRun polling interval when no wake event arrives
MULTICA_DAEMON_WS_CLAIM_POLL_INTERVAL3mUpper bound for healthy WebSocket claim safety polls, configured independently of MULTICA_DAEMON_POLL_INTERVAL; downward jitter makes the normal default 2m30s2m45s, while old servers and uncertain claims retain the ordinary poll interval
MULTICA_DAEMON_HEARTBEAT_INTERVAL15sHeartbeat interval
MULTICA_DAEMON_MAX_CONCURRENT_TASKS20Concurrent run ceiling per daemon
MULTICA_AGENT_TIMEOUT0Absolute time limit per run; 0 means no limit
MULTICA_AGENT_IDLE_WATCHDOG2hSilence ceiling with no output and no tool execution; 0 disables the watchdog entirely
MULTICA_AGENT_TOOL_WATCHDOGsame as MULTICA_AGENT_IDLE_WATCHDOGSilence ceiling for a single tool call; set it only to give tools more room than the model gets, 0 never force-stops a tool call. Cursor background shells stay in flight until their owned processes exit; at this boundary the daemon stops those processes and gives Cursor a fresh watchdog budget to produce its terminal result. If process ownership or cleanup cannot be verified, the ordinary run-cancellation policy applies
MULTICA_OPENCODE_IDLE_WATCHDOG10mOpenCode-specific silence threshold
MULTICA_CODEX_SEMANTIC_INACTIVITY_TIMEOUTsame as MULTICA_AGENT_IDLE_WATCHDOGCodex semantic-silence threshold. Codex's own timer cannot see that a tool is running, so it tracks the larger of the idle / tool budgets instead of holding a separate, shorter ceiling
MULTICA_CODEX_FIRST_TURN_TIMEOUT0Explicit override for the Codex first-turn no-progress ceiling; 0 keeps the default. The effective first-turn wait stays bounded by MULTICA_CODEX_SEMANTIC_INACTIVITY_TIMEOUT and the overall execution timeout — set MULTICA_CODEX_SEMANTIC_INACTIVITY_TIMEOUT strictly above this value (with some margin), or the wait is truncated to it and the model-catalog startup retry is skipped. Equal values are not enough: the semantic timer is armed first, so at equal durations the retry can still be lost
MULTICA_CODEX_HANDSHAKE_TIMEOUT30s; thread/start, thread/resume: 60sCodex app-server startup handshake ceilings. An explicit value overrides both budgets globally
MULTICA_CODEX_TURN_INTERRUPT_TIMEOUT2sGrace period after cancellation for Codex app-server to acknowledge turn/interrupt and emit turn/completed, preserving final token usage before forced process cleanup. On unusually slow hosts, tune this from the interrupt latency recorded in daemon logs
MULTICA_DAEMON_AUTO_UPDATECloud true; self-hosted falseWhether to check for and apply CLI updates automatically
MULTICA_DAEMON_AUTO_UPDATE_INTERVAL6hUpdate check interval
MULTICA_DAEMON_AUTO_RELOADtrueWhether to restart into a multica binary replaced on disk out of band (brew upgrade, a re-download, a local build). Independent of MULTICA_DAEMON_AUTO_UPDATE
MULTICA_WORKSPACES_ROOT~/multica_workspacesRoot directory for run working directories
MULTICA_AGENT_TEMP_BASE/tmp (Linux/macOS)Linux/macOS only. Parent directory for private per-run temp dirs; must be an existing, writable absolute directory, and an invalid value fails run startup instead of falling back to /tmp. Pick a short path — child tools may bind AF_UNIX sockets under it, and sun_path is limited to 108 bytes on Linux and 104 on macOS
MULTICA_KEEP_ENV_AFTER_TASKfalseKeep run directories for debugging

For the internal context that the daemon injects into agent tasks, see Task runtime environment.

Each AI coding tool accepts MULTICA_<PROVIDER>_PATH and MULTICA_<PROVIDER>_MODEL to override the command path and default model. QwenPaw and MiniMax Code have no model variable because Multica never sends them a model; MiniMax Code's path variable is MULTICA_MCODE_PATH — see AI coding tools comparison. DeepSeek Harness supports MULTICA_DSH_PATH and MULTICA_DSH_MODEL (a model id from the dsh catalog, e.g. deepseek-official/deepseek-chat). DeepSeek Harness additionally accepts MULTICA_DSH_PROFILE_BUNDLE: a comma-separated list of bundles to install into its multica profile when that profile is missing, tried in order, where each entry is an npm spec, a directory, or a packed tarball. It is unset by default, and the --stdio protocol Multica drives is what that profile supplies, so an unset variable leaves the DSH installation untouched and the daemon reports the missing profile instead of registering an unusable runtime. Multica's own bridge is not on a public npm registry yet, so choosing a value is covered in Install an agent runtime; whatever you set is installed into every daemon host's DSH home without further confirmation, so treat it as a supply-chain decision. The install MULTICA_DSH_PROFILE_BUNDLE enables is bounded on purpose: it runs at most once per daemon lifetime, only when the probe reports the profile genuinely absent, and a failure is logged with the package manager's own output and retried only after a daemon restart. A probe that times out, or answers with a protocol version this daemon does not drive, is reported and never installed over — the daemon does not overwrite a profile that is deliberately there. To diagnose, search the daemon log for DSH runtime profile; to undo an install, delete $DSH_HOME/profiles/multica (default ~/.dsh/profiles/multica). MULTICA_DSH_PLUGIN_PATH overrides the directory the install resolves pnpm from. DSH Desktop keeps the pnpm that dsh plugin forwards to inside its own runtime-commands directory on both macOS and Windows, and the daemon finds and prepends it automatically — including the versioned layout a newer Desktop uses — so this variable is only needed for an installation the daemon cannot find, or to make the install use a pnpm of your own. Setting it replaces the search entirely: if the directory does not exist, the install falls back to whatever pnpm is on the daemon's PATH rather than to the bundled one. Linux has no DSH Desktop, so there the install always uses PATH. Dim supports MULTICA_DIM_PATH and MULTICA_DIM_MODEL (a model id from the dim catalog). ZeroClaw supports MULTICA_ZEROCLAW_PATH but has no model variable; its agent profile owns the model selection. Machine-wide default arguments via MULTICA_<PROVIDER>_ARGS are currently supported for five tools: Claude Code, Codex, CodeBuddy, Qwen Code, and QwenPaw. The variables are MULTICA_CLAUDE_ARGS, MULTICA_CODEX_ARGS, MULTICA_CODEBUDDY_ARGS, MULTICA_QWEN_ARGS, and MULTICA_QWENPAW_ARGS. For example:

MULTICA_CLAUDE_PATH=/opt/bin/claude
MULTICA_CLAUDE_ARGS=--max-turns 40

Cursor's verified background cleanup requires Linux 6.9 or newer (process-group pidfds), macOS kernel support for process identity queries and audit-token signalling, or a successfully assigned nested Job Object on Windows. On macOS, each process is signalled using a kernel-checked PID version; no same-session group join is required. These macOS APIs are private and checked at capture time. A launch that cannot be claimed returns its original tool result and uses the ordinary idle watchdog, including when the tool watchdog is 0. Already-claimed work remains in flight if cleanup cannot be confirmed. With the tool watchdog set to 0 there is no such boundary at all: claimed background work keeps the run in flight for as long as it lives, so the run is bounded only by MULTICA_AGENT_TIMEOUT, which is 0 by default.

Owned Cursor background processes are also stopped when the run completes normally, so a background server started by that run does not intentionally survive finalization. macOS can recognize late children through retained original-parent identities, but cannot prove a chain whose intermediate processes disappeared before observation. Such processes, work that leaves the tracked group, or persistent ownership/signalling errors can leave background work behind. Unconfirmed cleanup is logged and never grants a successful-cleanup recovery window; unknown processes are not killed based only on their numeric PID or process group.

Precedence is command-line flag → environment variable → ~/.multica/config.json → built-in default. For watchdog behavior, see Daemon and runtimes.

Persisting daemon configuration

Common daemon-side settings can also be written to ~/.multica/config.json instead of relying on shell environment variables; named profiles keep theirs at ~/.multica/profiles/<name>/config.json:

multica config set poll_interval 10s
multica config show

Supported keys:

KeyDefaultDescription
server_urlws://localhost:8080/wsMultica API / WebSocket URL
app_urlemptyWeb URL used for browser sign-in
workspace_idemptyDefault workspace
device_namehostnameDevice name shown in the runtime list
runtime_nameLocal AgentRuntime display name
workspaces_rootprofile-aware path under ~Root directory for run working directories
max_concurrent_tasks20Concurrent run ceiling; 0 or empty means unset
poll_interval30sRun polling interval
ws_claim_poll_interval3mUpper bound for healthy WebSocket claim safety polls, independent of poll_interval; the daemon applies downward-only jitter
heartbeat_interval15sHeartbeat interval
agent_timeoutunlimitedAbsolute time limit per run
codex_semantic_inactivity_timeoutderivedCodex semantic-silence threshold. With nothing set it takes the larger of the idle and tool watchdog budgets; a tool budget of 0 falls back to the idle budget, and only when the whole watchdog suite is disabled does Codex keep its own 10m
codex_handshake_timeout30s; thread/start, thread/resume: 60sCodex app-server startup handshake ceilings. An explicit value overrides both budgets globally
disable_auto_updatefollows environmenttrue turns auto-update off; false clears the local override and returns to the env var or default
auto_update_check_interval6hUpdate check interval
disable_auto_reloadfollows environmenttrue stops the daemon following a binary replaced on disk; false clears the local override. Resolved separately from disable_auto_update

A few value rules:

  • Duration keys accept positive Go durations (such as 10s, 2h); 0s and negative values are rejected. The one exception is agent_timeout: 0s is valid and explicitly disables the run time limit.
  • Passing an empty string clears a persisted value and falls back to the env var or built-in default, for example multica config set poll_interval "".
  • max_concurrent_tasks requires a non-negative integer.
  • Relative workspaces_root values are converted to absolute paths when saved.

Observability and analytics

VariableDefaultDescription
DO_NOT_TRACKempty (telemetry enabled)Set 1 or true (case-insensitive) to stop first-party anonymous self-host telemetry collection and delivery
ANALYTICS_DISABLEDfalseSet true to turn off PostHog reporting
POSTHOG_API_KEYemptyReporting is off when unset; set it to use your own PostHog project
POSTHOG_HOSThttps://us.i.posthog.comPostHog host
METRICS_ADDRemptyPrometheus metrics listen address; empty means not started
REALTIME_METRICS_TOKENemptyBearer token protecting /health/realtime

First-party self-host telemetry sends one deployment-level snapshot per UTC day to the fixed, non-configurable https://telemetry.multica.ai/v1/telemetry/events endpoint. It contains the formal release version; bucketed workspace, distinct-human-member, active-agent, and 24-hour active-daemon counts; and aggregate run counts for the previous 24 hours. It never includes names, email addresses or domains, IP addresses, business identifiers, host/device details, repositories, models/plugins, prompts/output, comments/chats, paths, token/cost data, credentials, errors, stacks, or logs. It is used only to understand self-hosted version adoption, deployment-size ranges, and aggregate usage—not for billing, licensing, authentication, or security decisions.

DO_NOT_TRACK and ANALYTICS_DISABLED are independent. The former controls this first-party anonymous snapshot; the latter controls the optional PostHog integration.

Next steps