Skip to content

Echo Agent Configuration Reference

security

Field snake type default choices description
security.profile security.profile Literal personal_cli personal_cli/daemon/public_gateway Overall security profile preset

channels

Field snake type default choices description
channels.telegram.enabled channels.telegram.enabled bool false Enable the Telegram channel
channels.telegram.token channels.telegram.token str "" Telegram bot API token
channels.telegram.allowFrom channels.telegram.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.telegram.proxy channels.telegram.proxy str None null
channels.telegram.groupPolicy channels.telegram.group_policy Literal mention open/mention Group reply policy: open = all messages, mention = only when @-mentioned
channels.telegram.reactionsEnabled channels.telegram.reactions_enabled bool true Whether to add emoji reactions to messages
channels.telegram.dataDir channels.telegram.data_dir str "" Directory persisting Telegram state (long-poll offset, prevents re-fetch after restart); defaults to ~/.echo-agent/data/telegram
channels.discord.enabled channels.discord.enabled bool false Enable the Discord channel
channels.discord.token channels.discord.token str "" Discord bot token
channels.discord.allowFrom channels.discord.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.discord.groupPolicy channels.discord.group_policy Literal mention open/mention Group reply policy: open = all messages, mention = only when @-mentioned
channels.discord.reactionsEnabled channels.discord.reactions_enabled bool true Whether to add emoji reactions to messages
channels.webhook.enabled channels.webhook.enabled bool false Enable the webhook channel
channels.webhook.host channels.webhook.host str 0.0.0.0 Webhook server bind address
channels.webhook.port channels.webhook.port int 8080 Webhook server listen port
channels.webhook.secret channels.webhook.secret str "" Secret used to verify inbound request signatures
channels.webhook.path channels.webhook.path str /webhook HTTP path on which webhooks are received
channels.webhook.maxPending channels.webhook.max_pending int 1000 Maximum number of pending webhook requests queued
channels.cli.enabled channels.cli.enabled bool true Enable the CLI channel
channels.cron.enabled channels.cron.enabled bool false Enable the cron channel
channels.slack.enabled channels.slack.enabled bool false Enable the Slack channel
channels.slack.botToken channels.slack.bot_token str "" Slack bot token (xoxb-)
channels.slack.appToken channels.slack.app_token str "" Slack app-level token (xapp-) for Socket Mode
channels.slack.allowFrom channels.slack.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.slack.reactionsEnabled channels.slack.reactions_enabled bool true Whether to add emoji reactions to messages
channels.whatsapp.enabled channels.whatsapp.enabled bool false Enable the WhatsApp channel
channels.whatsapp.verifyToken channels.whatsapp.verify_token str "" WhatsApp webhook verification token
channels.whatsapp.accessToken channels.whatsapp.access_token str "" WhatsApp Cloud API access token
channels.whatsapp.phoneNumberId channels.whatsapp.phone_number_id str "" WhatsApp phone number ID used for sending
channels.whatsapp.webhookPath channels.whatsapp.webhook_path str /whatsapp HTTP path on which WhatsApp webhooks are received
channels.whatsapp.host channels.whatsapp.host str 0.0.0.0 WhatsApp server bind address
channels.whatsapp.port channels.whatsapp.port int 8081 WhatsApp server listen port
channels.whatsapp.appSecret channels.whatsapp.app_secret str "" WhatsApp App Secret for webhook HMAC signature verification
channels.whatsapp.allowFrom channels.whatsapp.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.whatsapp.groupPolicy channels.whatsapp.group_policy str mention Group response policy: all=respond to all, mention=only respond when mentioned
channels.weixin.enabled channels.weixin.enabled bool false Enable the Weixin channel
channels.weixin.accountId channels.weixin.account_id str "" Weixin customer-service account ID
channels.weixin.token channels.weixin.token str "" Weixin access authentication token
channels.weixin.baseUrl channels.weixin.base_url str https://ilinkai.weixin.qq.com Weixin API base URL
channels.weixin.cdnBaseUrl channels.weixin.cdn_base_url str https://novac2c.cdn.weixin.qq.com/c2c Weixin media CDN base URL
channels.weixin.allowFrom channels.weixin.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.weixin.dmPolicy channels.weixin.dm_policy str open Direct-message reply policy
channels.weixin.dataDir channels.weixin.data_dir str "" Local data directory for the Weixin channel
channels.weixin.typingIndicator channels.weixin.typing_indicator bool true Send a typing indicator to the user while a message is being processed
channels.qqbot.enabled channels.qqbot.enabled bool false Enable the QQ bot channel
channels.qqbot.appId channels.qqbot.app_id str "" QQ bot AppID
channels.qqbot.appSecret channels.qqbot.app_secret str "" QQ bot AppSecret
channels.qqbot.allowFrom channels.qqbot.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.qqbot.sandbox channels.qqbot.sandbox bool false Use the QQ sandbox environment
channels.qqbot.markdownSupport channels.qqbot.markdown_support bool true Send as QQ native Markdown (msg_type=2) and keep inline markers like bold/code. On by default; if the bot lacks native Markdown permission, the first message is rejected and auto-retried as plain text, and later messages to that target skip markdown (re-probed after 24h). Tables/headings/HR are downgraded to readable plain text regardless. When off, always sends plain text
channels.qqbot.mediaEnabled channels.qqbot.media_enabled bool true Enable media (image/file) sending and receiving
channels.qqbot.mediaMaxFileSizeMb channels.qqbot.media_max_file_size_mb int 20 Maximum size per uploaded media file (MB)
channels.qqbot.mediaUploadCacheSize channels.qqbot.media_upload_cache_size int 500 Maximum number of cached media upload results
channels.qqbot.mediaParseTags channels.qqbot.media_parse_tags bool true Parse media tags embedded in messages
channels.feishu.enabled channels.feishu.enabled bool false Enable the Feishu channel
channels.feishu.appId channels.feishu.app_id str "" Feishu app ID
channels.feishu.appSecret channels.feishu.app_secret str "" Feishu app secret
channels.feishu.verificationToken channels.feishu.verification_token str "" Feishu event callback verification token
channels.feishu.encryptionKey channels.feishu.encryption_key str "" Feishu event encryption key
channels.feishu.webhookPath channels.feishu.webhook_path str /feishu HTTP path on which Feishu events are received
channels.feishu.host channels.feishu.host str 0.0.0.0 Feishu server bind address
channels.feishu.port channels.feishu.port int 8083 Feishu server listen port
channels.feishu.groupPolicy channels.feishu.group_policy str mention Group trigger policy: mention=respond only when @mentioned, all=respond to every message
channels.feishu.botOpenId channels.feishu.bot_open_id str "" Bot's own open_id for group chat mention filtering
channels.dingtalk.enabled channels.dingtalk.enabled bool false Enable the DingTalk channel
channels.dingtalk.appKey channels.dingtalk.app_key str "" DingTalk app key
channels.dingtalk.appSecret channels.dingtalk.app_secret str "" DingTalk app secret
channels.dingtalk.robotCode channels.dingtalk.robot_code str "" DingTalk robot code
channels.dingtalk.allowFrom channels.dingtalk.allow_from list [] Allowlist of user IDs permitted to interact (empty = all)
channels.email.enabled channels.email.enabled bool false Enable the email channel
channels.email.imapHost channels.email.imap_host str "" IMAP server host for receiving mail
channels.email.imapPort channels.email.imap_port int 993 IMAP server port for receiving mail
channels.email.smtpHost channels.email.smtp_host str "" SMTP server host for sending mail
channels.email.smtpPort channels.email.smtp_port int 465 SMTP server port for sending mail
channels.email.username channels.email.username str "" Mailbox login username
channels.email.password channels.email.password str "" Mailbox login password or app token
channels.email.useSsl channels.email.use_ssl bool true Use SSL when connecting to mail servers
channels.email.pollIntervalSeconds channels.email.poll_interval_seconds int 30 Interval between new-mail polls (seconds)
channels.email.allowFrom channels.email.allow_from list [] Allowlist of sender addresses permitted to interact (empty = all)
channels.wecom.enabled channels.wecom.enabled bool false Enable the WeCom channel
channels.wecom.corpId channels.wecom.corp_id str "" WeCom corporation ID
channels.wecom.agentId channels.wecom.agent_id str "" WeCom application AgentId
channels.wecom.secret channels.wecom.secret str "" WeCom application secret
channels.wecom.token channels.wecom.token str "" WeCom callback verification token
channels.wecom.encodingAesKey channels.wecom.encoding_aes_key str "" EncodingAESKey for WeCom encrypted callbacks; empty means plaintext mode
channels.wecom.webhookPath channels.wecom.webhook_path str /wecom HTTP path on which WeCom events are received
channels.wecom.host channels.wecom.host str 0.0.0.0 WeCom server bind address
channels.wecom.port channels.wecom.port int 8084 WeCom server listen port
channels.matrix.enabled channels.matrix.enabled bool false Enable the Matrix channel
channels.matrix.homeserver channels.matrix.homeserver str "" Matrix homeserver URL
channels.matrix.userId channels.matrix.user_id str "" Matrix bot user ID
channels.matrix.accessToken channels.matrix.access_token str "" Matrix access token
channels.matrix.allowRooms channels.matrix.allow_rooms list [] Allowlist of room IDs the bot responds in (empty = all)
channels.matrix.reactionsEnabled channels.matrix.reactions_enabled bool true Whether to add emoji reactions to messages
channels.sendProgress channels.send_progress bool true Send progress updates to the user
channels.sendToolHints channels.send_tool_hints bool true Send tool-invocation hints to the user
channels.streamChannels channels.stream_channels list ['cli', 'telegram', 'discord', 'slack', 'gateway:*'] Channels for which streaming incremental replies are enabled
channels.streamFlushChars channels.stream_flush_chars int 180 Character count that triggers a streaming flush
channels.streamFlushIntervalMs channels.stream_flush_interval_ms int 1500 Maximum interval between streaming flushes (ms)
channels.streamParagraphMode channels.stream_paragraph_mode bool true Flush streaming output on paragraph boundaries
channels.streamLocalFlushChars channels.stream_local_flush_chars int 24 Flush threshold for local channels (cli/gateway); 0 reuses the shared value
channels.streamLocalFlushIntervalMs channels.stream_local_flush_interval_ms int 100 Maximum interval between flushes for local channels (cli/gateway), in ms
channels.streamLocalChannels channels.stream_local_channels list ['cli', 'gateway:*'] Channels that use the local low-latency streaming tier (supports prefix:*)
channels.streamOptimisticChannels channels.stream_optimistic_channels list ['gateway:cli'] Channels allowed to stream optimistically (pre-tool draft sent then retracted); only channels that can redraw in place
channels.transcriptionApiKey channels.transcription_api_key str "" API key for the voice transcription service

models

Field snake type default choices description
models.defaultModel models.default_model str "" Default model used when no route matches
models.providers models.providers list [] List of model provider configurations
models.providers[].name models.providers[].name str "" Provider name referenced by routes
models.providers[].apiKey models.providers[].api_key str "" Provider API key
models.providers[].apiKeyEnv models.providers[].api_key_env str "" Read the API key from this environment variable so a host can inject an ephemeral secret without persisting it
models.providers[].apiBase models.providers[].api_base str "" Provider API base URL
models.providers[].models models.providers[].models list [] Models served by this provider
models.providers[].extraHeaders models.providers[].extra_headers dict {} Extra HTTP headers attached to requests
models.providers[].maxRetries models.providers[].max_retries int 3 Max retries on transient errors (exponential backoff)
models.providers[].timeoutSeconds models.providers[].timeout_seconds int 120 Per-request timeout (seconds)
models.providers[].streamIncludeUsage models.providers[].stream_include_usage bool true Send stream_options.include_usage on streaming requests (for token/cost accounting); set false for OpenAI-compatible endpoints that reject the field
models.providers[].rateLimitRpm models.providers[].rate_limit_rpm int 0 Provider request-per-minute cap (0 = unlimited)
models.providers[].credentialPool models.providers[].credential_pool list [] Pool of API keys rotated for this provider
models.routes models.routes list [] List of task-to-model routing rules
models.routes[].model models.routes[].model str "" Model name used by this route
models.routes[].provider models.routes[].provider str "" Provider name bound to this route
models.routes[].taskTypes models.routes[].task_types list [] Task types that match this route
models.routes[].fallbackModels models.routes[].fallback_models list [] Fallback models when the primary fails
models.routes[].maxTokens models.routes[].max_tokens int 8192 Maximum tokens generated for this route
models.routes[].temperature models.routes[].temperature float 0.7 Sampling temperature for this route
models.routes[].contextWindow models.routes[].context_window int 0 Explicit context-window override for this route's model (0 = unset, resolved automatically); takes precedence over the built-in registry and global fallback
models.fallbackModel models.fallback_model str "" Global fallback model
models.modelWindows models.model_windows dict {} Map of model id to context-window tokens (auto-captured by setup from provider metadata, or hand-set); ranks below a route override and above the built-in registry

tools

Field snake type default choices description
tools.profile tools.profile Literal full minimal/messaging/coding/full Preset tool profile
tools.allow tools.allow list [] Explicit allowlist of tools overriding the profile
tools.alsoAllow tools.also_allow list [] Tools additionally allowed on top of the profile
tools.deny tools.deny list [] Explicit blocklist of tools
tools.exec.enabled tools.exec.enabled bool true Enable the shell/process execution tool
tools.exec.maxOutputChars tools.exec.max_output_chars int 2000000 Acquisition character cap for command output (not the model-facing cap, which is spill.maxInlineChars)
tools.exec.host tools.exec.host Literal sandbox auto/local/sandbox/container/remote Host environment in which commands execute
tools.exec.security tools.exec.security Literal allowlist deny/allowlist/full Command execution security mode
tools.exec.ask tools.exec.ask Literal on_miss off/on_miss/always When to ask for approval before running a command
tools.exec.safeBins tools.exec.safe_bins list ['awk', 'cat', 'date', 'echo', 'find', 'grep', 'head', 'ls', 'pwd', 'rg', 'sed', 'sort', 'tail', 'tr', 'uniq', 'wc'] Commands allowed without approval under allowlist mode
tools.exec.allowedCommands tools.exec.allowed_commands list [] Additional allowlist of commands permitted to run
tools.exec.blockedCommands tools.exec.blocked_commands list [] Blocklist of commands forbidden from running
tools.web.enabled tools.web.enabled bool false Enable the web access tool
tools.web.proxy tools.web.proxy str None null
tools.web.timeoutSeconds tools.web.timeout_seconds int 30 Web request timeout (seconds)
tools.web.searchApiKey tools.web.search_api_key str "" Search service API key
tools.web.searchProvider tools.web.search_provider Literal brave brave/tavily/serpapi/searxng/serply Web search service provider (serply uses the Serply SERP API: https://serply.io, docs https://serply.io/docs)
tools.web.searchApiBase tools.web.search_api_base str "" Search service API base URL
tools.web.allowPrivateAddresses tools.web.allow_private_addresses bool false Allow web_fetch to reach private/loopback addresses (SSRF risk)
tools.browser.enabled tools.browser.enabled bool true Enable browser automation tool (default on; auto-degrades if playwright/chromium missing)
tools.browser.maxSessions tools.browser.max_sessions int 3 Max concurrent browser sessions per owner
tools.browser.maxTotalSessions tools.browser.max_total_sessions int 10 Global cap on concurrent browser sessions across all owners (each is a Chromium context); <=0 disables
tools.browser.sessionIdleTimeoutSec tools.browser.session_idle_timeout_sec int 300 Idle seconds before a browser session is reaped
tools.browser.maxSnapshotChars tools.browser.max_snapshot_chars int 8000 Accessibility snapshot text truncation limit (chars)
tools.browser.headless tools.browser.headless bool true Headless mode (required on servers)
tools.browser.navTimeoutSec tools.browser.nav_timeout_sec int 30 Per-navigation timeout (seconds)
tools.browser.allowPrivateAddresses tools.browser.allow_private_addresses bool false Allow navigating to private addresses (default blocked, reuses SSRF policy)
tools.browser.dialogPolicy tools.browser.dialog_policy str dismiss Native dialog auto-handling policy: dismiss or accept (unhandled dialogs block the page)
tools.browser.allowEvaluate tools.browser.allow_evaluate bool true Allow the evaluate action to run JS in the page. The expression blacklist stops careless use, not deliberate obfuscation; turn this off where in-page code execution is unacceptable
tools.browser.allowUnsafeEvaluate tools.browser.allow_unsafe_evaluate bool false Skip evaluate's sensitive-expression checks (cookie/storage reads, script navigation). Default denied
tools.browser.persistLoginState tools.browser.persist_login_state bool false Persist browser login state (cookies/localStorage) into the workspace for reuse
tools.browser.viewportWidth tools.browser.viewport_width int 1280 Browser viewport width (px)
tools.browser.viewportHeight tools.browser.viewport_height int 800 Browser viewport height (px)
tools.browser.userAgent tools.browser.user_agent str "" Custom User-Agent; empty uses the Chromium default
tools.restrictToWorkspace tools.restrict_to_workspace bool false Restrict file operations to the workspace
tools.safeWriteRoot tools.safe_write_root str "" Root directory under which writes are permitted
tools.inboundDocumentEnabled tools.inbound_document_enabled bool true Auto download, decrypt and parse inbound document attachments
tools.inboundDocumentMaxChars tools.inbound_document_max_chars int 8000 Char cap for auto-injecting inbound document text; beyond it, inject a summary and hint read_document
tools.mcpServers tools.mcp_servers dict {} MCP server configurations keyed by name (the key feeds tool names and credential filenames; letters, digits, dot, dash, underscore only)
tools.mcpServers{}.command tools.mcp_servers{}.command str "" Command launching the MCP server over stdio (mutually exclusive with url)
tools.mcpServers{}.args tools.mcp_servers{}.args list [] Arguments for the MCP server launch command
tools.mcpServers{}.env tools.mcp_servers{}.env dict {} Environment variables for the MCP server process; ${VAR}/$VAR expanded
tools.mcpServers{}.url tools.mcp_servers{}.url str "" MCP server URL for Streamable HTTP transport (mutually exclusive with command)
tools.mcpServers{}.headers tools.mcp_servers{}.headers dict {} Custom headers for the MCP HTTP connection; ${VAR} expanded
tools.mcpServers{}.auth tools.mcp_servers{}.auth Literal "" /oauth Auth mode: empty for none (or preset headers), 'oauth' for OAuth 2.1 PKCE
tools.mcpServers{}.trustLevel tools.mcp_servers{}.trust_level Literal untrusted untrusted/trusted Trust level for this server. untrusted (default): tools are gated at exec or above and server-supplied readOnlyHint cannot lower it; trusted: annotations are honoured. Only set trusted for servers you control.
tools.mcpServers{}.enabled tools.mcp_servers{}.enabled bool true Enable this MCP server
tools.mcpServers{}.timeout tools.mcp_servers{}.timeout int 120 MCP tool call timeout (seconds)
tools.mcpServers{}.connectTimeout tools.mcp_servers{}.connect_timeout int 60 Connection and initialize handshake timeout (seconds)
tools.mcpServers{}.toolsInclude tools.mcp_servers{}.tools_include list [] Allowlist of MCP tools to expose (empty = all)
tools.mcpServers{}.toolsExclude tools.mcp_servers{}.tools_exclude list [] Blocklist of MCP tools to exclude
tools.mcpSecurityPolicy tools.mcp_security_policy Literal block warn/block MCP injection-scan policy: block rejects suspicious tools, warn only logs. Covers tool name, description and inputSchema descriptions/titles
tools.imageGen.enabled tools.image_gen.enabled bool true Enable the image generation tool (unset skips registration even if a key is present)
tools.imageGen.backend tools.image_gen.backend str openai Image generation backend
tools.imageGen.apiKey tools.image_gen.api_key str "" OpenAI-compatible backend API key
tools.imageGen.apiBase tools.image_gen.api_base str "" OpenAI-compatible backend API base URL
tools.imageGen.model tools.image_gen.model str "" Image generation model name
tools.imageGen.falKey tools.image_gen.fal_key str "" FAL.ai backend access key
tools.imageGen.falModel tools.image_gen.fal_model str "" FAL.ai image generation model name
tools.tts.enabled tools.tts.enabled bool true Enable the TTS tool (unset skips registration; stored credentials are kept)
tools.tts.openaiApiKey tools.tts.openai_api_key str "" OpenAI TTS API key
tools.tts.openaiApiBase tools.tts.openai_api_base str "" OpenAI TTS API base URL
tools.tts.model tools.tts.model str "" TTS model name
tools.tts.defaultBackend tools.tts.default_backend str edge Default text-to-speech backend
tools.tts.defaultVoice tools.tts.default_voice str "" Default synthesis voice
tools.codeExec.enabled tools.code_exec.enabled bool true Enable the code execution tool
tools.codeExec.timeoutSeconds tools.code_exec.timeout_seconds int 30 Code execution timeout (seconds)
tools.codeExec.allowedLanguages tools.code_exec.allowed_languages list ['python', 'javascript', 'bash'] Languages permitted for code execution
tools.mcp.enabled tools.mcp.enabled bool true Enable MCP tool integration (false skips every configured MCP server)

execution

Field snake type default choices description
execution.defaultExecutor execution.default_executor Literal sandbox local/sandbox/container/remote Default command executor type
execution.sandboxRoot execution.sandbox_root str /tmp/echo-agent-sandbox Root directory for the sandbox executor
execution.containerImage execution.container_image str "" Image used by the container executor
execution.remoteHost execution.remote_host str "" Target host for the remote executor
execution.remoteUser execution.remote_user str root Login user for the remote executor
execution.remoteKeyPath execution.remote_key_path str "" SSH private key path for the remote executor
execution.remoteStrictHostKey execution.remote_strict_host_key Literal accept-new no/accept-new/yes SSH strict host key checking policy
execution.remoteConnectTimeout execution.remote_connect_timeout int 10 Remote executor connection timeout (seconds)
execution.networkPolicy execution.network_policy Literal deny allow/deny/restricted Network access policy for the execution environment
execution.maxBackgroundTasks execution.max_background_tasks int 64 Max concurrent background tasks; over limit discardable dropped, durable queued

permissions

Field snake type default choices description
permissions.adminUsers permissions.admin_users list [] Global administrator users
permissions.approval.requireApproval permissions.approval.require_approval list ['cronjob', 'delegate_task', 'dep_install', 'exec', 'execute_code', 'process', 'skill_install', 'skill_manage', 'spawn_task'] Tools/actions that require approval before running. The risk tier (EXEC/DANGEROUS) already requires approval on its own; this list only adds tools and can never exempt one. delegate_task/spawn_task are listed because a worker they dispatch can call exec, and the dispatch is the last point where the caller's own authority is still known
permissions.approval.autoApprove permissions.approval.auto_approve list [] Tools/actions auto-approved without prompting
permissions.approval.autoDeny permissions.approval.auto_deny list [] Tools/actions auto-denied
permissions.approval.defaultPolicy permissions.approval.default_policy Literal approve approve/deny/ask Default approval policy when no rule matches
permissions.approval.waitTimeoutSeconds permissions.approval.wait_timeout_seconds int 300 Timeout while waiting for human approval (seconds)
permissions.approval.cliAutoApprove permissions.approval.cli_auto_approve bool true Auto-approve actions on the CLI channel
permissions.approval.trustedChannels permissions.approval.trusted_channels list [] Trusted channels exempt from approval
permissions.approval.mode permissions.approval.mode Literal smart manual/smart/off Approval mode: manual, smart, or off
permissions.approval.smartModel permissions.approval.smart_model str "" Model used to judge approvals in smart mode
permissions.approval.unattendedPolicy permissions.approval.unattended_policy Literal deny deny/allow_safe Approval policy when running unattended
permissions.elevated.enabled permissions.elevated.enabled bool false Enable the elevated-permission mechanism
permissions.elevated.allowFrom permissions.elevated.allow_from dict {} Per-channel mapping of users allowed to elevate

credentials

Field snake type default choices description
credentials.encryptionKeyEnv credentials.encryption_key_env str ECHO_AGENT_CREDENTIAL_KEY Environment variable holding the credential encryption key
credentials.requireEncryption credentials.require_encryption bool true Require credential encryption

session

Field snake type default choices description
session.maxHistoryMessages session.max_history_messages int 500 Maximum history messages retained per session
session.expiryHours session.expiry_hours int 72 Session expiry time (hours)
session.contextWindowTokens session.context_window_tokens int 0 Global fallback context-window budget (0 = unset, so an unknown model lands on the 256K modern baseline; only an explicit positive value takes effect, for private/local models that cannot be resolved dynamically, and it ranks below models.dev and the built-in registry)
session.compressionWindowCap session.compression_window_cap int 200000 Compression-budget cap (0 = uncapped): the model's real window drives the display, but compression triggers against min(real_window, cap) so a large-window model does not let context balloon before compressing, which would raise per-request cost and latency
session.introductionEnabled session.introduction_enabled bool true Send a self-introduction on new sessions
session.imClarifyPendingTtlSeconds session.im_clarify_pending_ttl_seconds int 300 TTL (seconds) for an IM follow-up question; after this, the next message is treated as new rather than an answer to the pending question
session.introductionTemplate session.introduction_template str "" Self-introduction template
session.historyImageTtlMinutes session.history_image_ttl_minutes int 30 Time-to-live for images in history (minutes)
session.historyImageLimit session.history_image_limit int 4 Maximum images retained in history
session.historyImageSkipIfCurrent session.history_image_skip_if_current bool true Skip history images when the current turn already has one
session.groupSessionScope session.group_session_scope Literal per_user per_user/shared Group session scope: per_user = isolate per sender (default), shared = whole group shares one session

memory

Field snake type default choices description
memory.enabled memory.enabled bool true Enable cognitive memory
memory.scopePolicy memory.scope_policy Literal session legacy/session Memory scope policy
memory.crossChannelOwner memory.cross_channel_owner bool true Cross-channel owner memory: when on, senders listed in principal_bindings share owner memory across 1:1 DMs on any channel; unlisted senders and groups stay per-session. Off = all per-session.
memory.ownerKey memory.owner_key str owner Owner memory scope key (single-subject default owner; rarely needs changing)
memory.allowModelEnvironmentWrites memory.allow_model_environment_writes bool false Allow the model memory tool to write ENVIRONMENT memory or global-tagged entries (these bypass scope, globally visible). Off by default; the model may only write its own scope's USER memory.
memory.principalBindings memory.principal_bindings list [] Owner identity bindings: each "channel:sender_id"; listed senders' 1:1 DMs map to the owner memory scope for cross-channel sharing; others stay per-session. Security assumption: only for channels whose sender_id is platform-guaranteed unforgeable (e.g. Telegram/Slack); otherwise anyone spoofing that id reads owner memory. Effective only when cross_channel_owner is on.
memory.retrievalOnMiss memory.retrieval_on_miss Literal degrade degrade/sync Behavior on retrieval cache miss: degrade=bounded sync retrieval with keyword fallback, sync=full synchronous retrieval
memory.retrievalMissTimeoutSeconds memory.retrieval_miss_timeout_seconds float 0.8 Time budget (s) for bounded sync retrieval on cache miss in degrade mode; falls back to local keyword search on timeout; 0=skip entirely (legacy)
memory.cacheTtlSeconds memory.cache_ttl_seconds float 60.0 Retrieval prefetch cache freshness TTL in seconds
memory.cacheJaccardMin memory.cache_jaccard_min float 0.3 Min Jaccard similarity between current and cached query; below is a miss
memory.consolidationThreshold memory.consolidation_threshold int 20 Entry threshold that triggers memory consolidation
memory.narrativeEpisodeCount memory.narrative_episode_count int 3 Number of recent episode summaries injected as the snapshot narrative layer (carries cross-entry temporal/causal narrative)
memory.vectorEnabled memory.vector_enabled bool true Enable vector-based memory retrieval
memory.vectorDimensions memory.vector_dimensions int 0 Memory embedding vector dimensions; 0 = follow the active embedding model
memory.maxUserMemories memory.max_user_memories int 1000 Maximum stored memories per user
memory.maxEnvMemories memory.max_env_memories int 500 Maximum stored environment memories
memory.memoryNudgeInterval memory.memory_nudge_interval int 10 Turn interval for nudging the model to store memories
memory.importanceDecayDays memory.importance_decay_days float 30.0 Memory importance decay period (days)
memory.snapshotEnabled memory.snapshot_enabled bool true Inject memory snapshots into context
memory.snapshotLayering memory.snapshot_layering bool true Snapshot layering: the always-on core keeps only top-K (by effective importance) plus explicitly pinned entries; the long tail is no longer injected into the system prompt every turn but surfaces via query-driven recall. Disable to revert to the legacy full snapshot (USER≤50/ENV≤30). Addresses the query-independent 'always-on profile looks unrelated' injection path.
memory.snapshotUserCoreMax memory.snapshot_user_core_max int 12 Max USER entries in the always-on core when layering is on (top-K + pinned). The long tail surfaces via recall.
memory.snapshotEnvCoreMax memory.snapshot_env_core_max int 8 Max ENVIRONMENT entries in the always-on core when layering is on (top-K + pinned).
memory.contradictionDetection memory.contradiction_detection bool true Enable memory contradiction detection
memory.sleepConsolidation memory.sleep_consolidation bool true Enable idle-time (sleep) memory consolidation
memory.archivalThreshold memory.archival_threshold float 0.05 Archival score threshold; entries below it move to the archival tier
memory.forgetThreshold memory.forget_threshold float 0.01 Forget score threshold; entries below it are forgotten
memory.lineageMaxVersions memory.lineage_max_versions int 3 Max superseded versions kept per key lineage; older ones move to archival for forgetting
memory.lineageRetentionDays memory.lineage_retention_days int 90 Retention days for superseded versions; stale ones move to archival even under the version cap
memory.maxWorkingMemory memory.max_working_memory int 20 Maximum working-memory entries
memory.embeddingBackend memory.embedding_backend Literal auto auto/local/provider Embedding backend: auto=probe provider at startup, fall back to fastembed on failure; local=use local fastembed directly; provider=force provider, error out if probe fails
memory.embeddingModel memory.embedding_model str "" Embedding model used for memory vectorization
memory.localEmbeddingModel memory.local_embedding_model str BAAI/bge-small-zh-v1.5 Local fastembed fallback model when no embed-capable provider exists; empty string disables the fallback
memory.hfEmbeddingEndpoint memory.hf_embedding_endpoint str https://hf-mirror.com HuggingFace download endpoint for the local fastembed model; defaults to the hf-mirror.com mirror for CN networks. Set to https://huggingface.co for the official source, or empty to leave any existing HF_ENDPOINT env var untouched
memory.embedTimeoutSeconds memory.embed_timeout_seconds float 1.5 Query-embedding timeout (seconds); falls back to keyword search on timeout
memory.rrfMinSimilarity memory.rrf_min_similarity float 0.3 RRF vector-recall similarity floor (tunable). Vector hits below this cosine occupy no rank slot, contribute no RRF term, and do not count as a vector-admission path — keeping low-similarity hits from polluting real candidates. For normalized sentence embeddings 0.25 is 'barely related'; 0.30 is a safer floor. The BM25 side instead uses a discriminative-token gate (a single common CJK char never admits) rather than a score floor (different scale).
memory.rerankEnabled memory.rerank_enabled bool true Enable cross-encoder reranking. RRF only fuses rank order; a cross-encoder scores (query,doc) jointly — the relevance gold standard. When on, the fused top-K is reranked (top-K only, cheap); timeout/failure falls back to the RRF order. Default on: the reranker model (~941MB, sha256-verified) is prefetched at install time from the self-hosted mirrors (Gitee split volumes first, then the whole file from GitHub) and then served offline; if the prefetch was missed the runtime downloads it with backoff. Until it is ready each turn degrades to the RRF order without blocking the reply. Disable to drop the model and the per-turn rerank latency entirely.
memory.rerankModel memory.rerank_model str BAAI/bge-reranker-base Cross-encoder rerank model (a fastembed TextCrossEncoder model name). For CN/multilingual use BAAI/bge-reranker-base or jinaai/jina-reranker-v2-base-multilingual.
memory.rerankTopK memory.rerank_top_k int 10 Number of fused top-K candidates the reranker rescores; the rest keep RRF order. Bounds rerank cost. Default 10: the cross-encoder is CPU-only and a base-size model spends tens of ms per (query,doc) pair, so K=20 routinely blows the inference budget and wastes the whole pass; the recall quota is only 5 memories + 3 episodes, so K=10 already covers twice the quota and going higher buys latency, not ranking changes.
memory.rerankMinScore memory.rerank_min_score float 0.0 Rerank absolute relevance floor (0 = reorder only, drop nothing). When >0, reranked candidates below it are dropped (within the top-K only; if the floor drops everything it falls back to unfiltered, so a miscalibrated threshold can't empty recall).
memory.rerankTimeoutSeconds memory.rerank_timeout_seconds float 5.0 Per-call wait budget (seconds) for reranker INFERENCE; on timeout this turn keeps the RRF order. Inference only — model load/download uses rerank_load_timeout_seconds. (When both shared one value, 2s was neither enough to load a ~1GB model nor enough for a base-size model to score the top-K on CPU, so every turn degraded.)
memory.rerankLoadTimeoutSeconds memory.rerank_load_timeout_seconds float 60.0 Per-wait budget (seconds) for reranker model load/download, symmetric with embed_load_timeout_seconds. A timeout is not a failure: the background load continues, this turn keeps the RRF order, and the model is picked up transparently once ready. Setting it as low as the inference budget (2s) makes every wait time out and wastes the startup warmup.
memory.embedLoadTimeoutSeconds memory.embed_load_timeout_seconds float 60.0 Local embedding model first-load/download timeout (seconds); on timeout the embedder is marked failed and degrades to keyword search, preventing a hung download from starving the process
memory.localEmbeddingCacheDir memory.local_embedding_cache_dir str ~/.echo-agent/models/fastembed fastembed cache directory for the local embedding model; install-time prefetch and runtime share this path for offline cache hits. Defaults to a stable location under echo-home (not the volatile tempdir fastembed uses by default). Empty leaves fastembed's default (FASTEMBED_CACHE_PATH or tempdir) untouched
memory.localEmbeddingMaxLoadAttempts memory.local_embedding_max_load_attempts int 5 Max load attempts for the local embedding model before staying keyword-only until restart; prevents one network blip from permanently degrading the process
memory.localEmbeddingRetryBackoffSeconds memory.local_embedding_retry_backoff_seconds float 30.0 Backoff (seconds) before re-attempting a failed local embedding model load, so a failure does not re-trigger a load on every message
memory.contradictionScanOnStore memory.contradiction_scan_on_store bool false Scan for contradictions at memory store time
memory.autoResolveContradictions memory.auto_resolve_contradictions bool false Auto-resolve same-key contradictions (newest-wins) during sleep consolidation; off by default
memory.reflectionEnabled memory.reflection_enabled bool true Enable sleep-time reflection (distillation + LLM conflict adjudication), piggybacking on sleep consolidation

knowledge

Field snake type default choices description
knowledge.enabled knowledge.enabled bool true Enable knowledge-base retrieval
knowledge.docsDir knowledge.docs_dir str data/knowledge Knowledge base documents directory
knowledge.indexPath knowledge.index_path str data/knowledge_index.json Knowledge base index file path
knowledge.autoIndex knowledge.auto_index bool true Automatically index the documents directory
knowledge.chunkSize knowledge.chunk_size int 1200 Document chunk size (characters)
knowledge.chunkOverlap knowledge.chunk_overlap int 120 Overlap between adjacent chunks (characters)
knowledge.maxResults knowledge.max_results int 5 Maximum knowledge retrieval results returned
knowledge.allowedExtensions knowledge.allowed_extensions list ['.md', '.txt', '.rst', '.json', '.yaml', '.yml', '.py', '.pdf', '.docx', '.xlsx', '.pptx'] Document extensions eligible for indexing

multiAgent

Field snake type default choices description
multiAgent.enabled multi_agent.enabled bool true Enable multi-agent delegation
multiAgent.maxDepth multi_agent.max_depth int 3 Maximum delegation nesting depth
multiAgent.maxParallelWorkers multi_agent.max_parallel_workers int 4 Maximum parallel workers
multiAgent.maxIterations multi_agent.max_iterations int 12 Default maximum iterations per worker
multiAgent.auditPath multi_agent.audit_path str data/delegation_audit.jsonl Delegation audit log path
multiAgent.workerProfiles multi_agent.worker_profiles list [] List of worker profile configurations
multiAgent.workerProfiles[].id multi_agent.worker_profiles[].id str "" Worker profile ID
multiAgent.workerProfiles[].name multi_agent.worker_profiles[].name str "" Worker profile name
multiAgent.workerProfiles[].description multi_agent.worker_profiles[].description str "" Worker profile description
multiAgent.workerProfiles[].instructions multi_agent.worker_profiles[].instructions str "" Worker profile system instructions
multiAgent.workerProfiles[].defaultTools multi_agent.worker_profiles[].default_tools list [] Default tools available to the worker
multiAgent.workerProfiles[].model multi_agent.worker_profiles[].model str "" Model used by the worker
multiAgent.workerProfiles[].maxIterations multi_agent.worker_profiles[].max_iterations int 12 Maximum iterations per worker task
multiAgent.workerProfiles[].maxTokens multi_agent.worker_profiles[].max_tokens int 8192 Maximum tokens generated by the worker
multiAgent.workerProfiles[].temperature multi_agent.worker_profiles[].temperature float 0.4 Worker sampling temperature

scheduler

Field snake type default choices description
scheduler.enabled scheduler.enabled bool true Enable the task scheduler
scheduler.maxConcurrentJobs scheduler.max_concurrent_jobs int 10 Maximum concurrent scheduled jobs

checkpoint

Field snake type default choices description
checkpoint.enabled checkpoint.enabled bool true Enable pre-edit shadow-git checkpoint safety net (auto-degrades if git missing)
checkpoint.storePath checkpoint.store_path str ~/.echo-agent/checkpoints/store Path to the shadow git store
checkpoint.maxSnapshotsPerWorkspace checkpoint.max_snapshots_per_workspace int 20 Max snapshots retained per workspace
checkpoint.maxTotalSizeMb checkpoint.max_total_size_mb int 500 Total store size cap in MB; exceeding triggers gc
checkpoint.maxFileSizeMb checkpoint.max_file_size_mb int 10 Files larger than this (MB) are excluded from snapshots

validation

Field snake type default choices description
validation.enabled validation.enabled bool true Enable post-write incremental validation feedback (auto-degrades if checkers missing)
validation.timeoutSec validation.timeout_sec float 5.0 Per-file validation timeout in seconds; times out silently
validation.maxDiagnostics validation.max_diagnostics int 10 Max diagnostics appended to the tool result
validation.maxFileSizeKb validation.max_file_size_kb int 512 Files larger than this (KB) skip validation

mediaUnderstanding

Field snake type default choices description
mediaUnderstanding.audioEnabled media_understanding.audio_enabled bool true Enable inbound audio/voice transcription (auto-degrades if no provider)
mediaUnderstanding.audioProvider media_understanding.audio_provider str auto Transcribe backend: auto (probe) / cloud / local (faster-whisper)
mediaUnderstanding.minAudioSizeKb media_understanding.min_audio_size_kb float 1.0 Audio smaller than this (KB) skips transcription
mediaUnderstanding.maxAudioSizeKb media_understanding.max_audio_size_kb int 25000 Audio larger than this (KB) skips transcription
mediaUnderstanding.localModelSize media_understanding.local_model_size str base Local faster-whisper model size (tiny/base/small/...)
mediaUnderstanding.videoEnabled media_understanding.video_enabled bool true Enable inbound video understanding (frames + audio; auto-degrades)
mediaUnderstanding.videoFrameCount media_understanding.video_frame_count int 4 Number of frames uniformly sampled from a video
mediaUnderstanding.videoVisionModel media_understanding.video_vision_model str "" Vision model override for video captioning (empty = provider default)
mediaUnderstanding.videoVisionPrompt media_understanding.video_vision_prompt str 简要描述这段视频的画面内容。 Prompt for video frame captioning
mediaUnderstanding.minVideoSizeKb media_understanding.min_video_size_kb float 1.0 Video smaller than this (KB) skips understanding
mediaUnderstanding.maxVideoSizeKb media_understanding.max_video_size_kb int 204800 Video larger than this (KB) skips understanding (~200MB cost guard)
mediaUnderstanding.videoFfmpegConcurrency media_understanding.video_ffmpeg_concurrency int 2 Max concurrent ffmpeg processes for video frame/audio extraction
mediaUnderstanding.transcriptionBaseUrl media_understanding.transcription_base_url str https://api.groq.com/openai/v1 Cloud transcription endpoint base_url (OpenAI-compatible)
mediaUnderstanding.transcriptionModel media_understanding.transcription_model str whisper-large-v3 Cloud transcription model name

runtime

Field snake type default choices description
runtime.singleInstance runtime.single_instance bool true Allow only one channel-consuming instance per workspace (prevents duplicate consumption/replies when a background service and a foreground run coexist); --force overrides it

storage

Field snake type default choices description
storage.databasePath storage.database_path str data/echo_agent.db SQLite database file path
storage.sessionsDir storage.sessions_dir str data/sessions Directory storing session data
storage.memoryDir storage.memory_dir str data/memory Directory storing memory data
storage.logsDir storage.logs_dir str data/logs Directory storing log files
storage.spillDir storage.spill_dir str data/spill Directory storing spilled tool-output artifacts (must be a dedicated workspace-relative subdirectory)

spill

Field snake type default choices description
spill.enabled spill.enabled bool true Spill oversized tool output to disk and show the model a preview only (off falls back to the old behaviour: output is bluntly truncated downstream at 16000 chars, losing the trailing conclusion with no way to retrieve it)
spill.maxInlineChars spill.max_inline_chars int 6000 Model-facing character cap for tool output; larger results are spilled and replaced with a head/tail preview
spill.retentionDays spill.retention_days int 7 Days to retain spill artifacts before deletion
spill.maxTotalMb spill.max_total_mb int 512 Total size cap (MB) for spill artifacts; oldest are deleted first when exceeded
spill.sweepIntervalHours spill.sweep_interval_hours int 6 Interval (hours) between spill artifact sweeps

artifacts

Field snake type default choices description
artifacts.enabled artifacts.enabled bool true Enable session-scoped user artifact tools
artifacts.rootDir artifacts.root_dir str data/artifacts User artifact directory (a dedicated workspace-relative directory)
artifacts.maxChunkChars artifacts.max_chunk_chars int 3000 Maximum characters accepted by one artifact append
artifacts.maxArtifactMb artifacts.max_artifact_mb int 50 Maximum size of one artifact in MB
artifacts.textFallbackMaxChars artifacts.text_fallback_max_chars int 100000 Largest artifact eligible for segmented text fallback when attachments are unsupported
artifacts.textFallbackChunkChars artifacts.text_fallback_chunk_chars int 1700 Chunk size for text fallback delivery (default fits Discord's 2000-character limit)
artifacts.retentionDays artifacts.retention_days int 30 Recommended retention period for finalized artifacts
artifacts.maxTotalMb artifacts.max_total_mb int 1024 Total user artifact size cap in MB (oldest artifacts are removed first)
artifacts.sweepIntervalHours artifacts.sweep_interval_hours int 24 User artifact cleanup interval in hours
artifacts.allowedExtensions artifacts.allowed_extensions list ['.md', '.txt', '.json', '.csv'] Text artifact extensions the model may create

observability

Field snake type default choices description
observability.logLevel observability.log_level str INFO Logging level
observability.traceEnabled observability.trace_enabled bool true Whether to record execution traces (off disables trace files)
observability.maxTraceFiles observability.max_trace_files int 500 Max retained trace files; oldest are rotated out when exceeded; <=0 disables rotation
observability.healthCheckIntervalSeconds observability.health_check_interval_seconds int 60 Health check interval (seconds)
observability.otelEnabled observability.otel_enabled bool true Enable OpenTelemetry metrics export
observability.otelEndpoint observability.otel_endpoint str "" OpenTelemetry export endpoint
observability.otelServiceName observability.otel_service_name str echo-agent OpenTelemetry service name
observability.otelExportIntervalMs observability.otel_export_interval_ms int 5000 OpenTelemetry metrics export interval (ms)
observability.loopWatchdogEnabled observability.loop_watchdog_enabled bool true Enable the event-loop watchdog (detects a frozen loop and self-exits for respawn)
observability.loopWatchdogWarnSeconds observability.loop_watchdog_warn_seconds float 5.0 Seconds of loop stall before warning and dumping thread stacks
observability.loopWatchdogKillSeconds observability.loop_watchdog_kill_seconds float 30.0 Seconds of loop freeze before self-exiting for supervisor respawn
observability.loopWatchdogCheckIntervalSeconds observability.loop_watchdog_check_interval_seconds float 5.0 Interval (s) at which the watchdog thread checks the heartbeat
observability.loopWatchdogMaxRestartsPerHour observability.loop_watchdog_max_restarts_per_hour int 5 Max watchdog self-exits per hour before the circuit breaker suspends restarts

skills

Field snake type default choices description
skills.enabled skills.enabled bool true Enable the skills system
skills.skillsDir skills.skills_dir str skills Skills directory
skills.creationNudgeInterval skills.creation_nudge_interval int 10 Turn interval for nudging skill creation
skills.disabled skills.disabled list [] List of disabled skills
skills.externalDirs skills.external_dirs list [] External directories from which to load skills
skills.allowLazyInstalls skills.allow_lazy_installs bool true Allow lazy on-demand dependency installs for skills
skills.admissionPolicy skills.admission_policy Literal stage_for_review auto_write/stage_for_review/manual_only Skill auto-distillation admission policy
skills.autoWriteRisk skills.auto_write_risk Literal low low/high Highest risk level auto-written under the auto_write policy

compression

Field snake type default choices description
compression.enabled compression.enabled bool true Enable context compression
compression.triggerRatio compression.trigger_ratio float 0.7 Context usage ratio that triggers compression
compression.tailBudgetRatio compression.tail_budget_ratio float 0.4 Budget ratio reserved for tail messages after compression
compression.headProtectCount compression.head_protect_count int 3 Number of head messages protected from compression
compression.summaryTargetRatio compression.summary_target_ratio float 0.2 Target summary length relative to source
compression.summaryMinTokens compression.summary_min_tokens int 2000 Minimum summary tokens
compression.summaryMaxTokens compression.summary_max_tokens int 12000 Maximum summary tokens
compression.summaryModel compression.summary_model str "" Model used to generate summaries
compression.summaryCooldownSeconds compression.summary_cooldown_seconds int 600 Cooldown between compressions (seconds)
compression.toolPruningEnabled compression.tool_pruning_enabled bool true Enable pruning of tool results
compression.toolPruningTailBudgetRatio compression.tool_pruning_tail_budget_ratio float 0.3 Tail budget ratio retained when pruning tool results
compression.maxCompressionCount compression.max_compression_count int 10 Maximum compressions per session

gateway

Field snake type default choices description
gateway.enabled gateway.enabled bool false Enable the gateway service
gateway.host gateway.host str 127.0.0.1 Gateway bind address. Defaults to 127.0.0.1 (this machine only). To serve the network, set 0.0.0.0 AND configure auth.apiTokens — binding non-loopback without a token is refused at startup — and list your proxy domain in auth.allowedHosts if behind a reverse proxy. Note that leaving this empty does NOT mean local: an empty string, like ::, is a wildcard bind equivalent to 0.0.0.0 and is subject to the same rules
gateway.port gateway.port int 58123 Gateway listen port (0 = dynamically assigned; the real port is written to workspace/.echo-agent/gateway.json)
gateway.apiPrefix gateway.api_prefix str /api/v1 Gateway API path prefix
gateway.wsPath gateway.ws_path str /ws Gateway WebSocket path
gateway.wsHeartbeatSeconds gateway.ws_heartbeat_seconds float 30.0 Server-side WebSocket heartbeat interval in seconds (0 = off): the server pings clients and expects a pong, so a connection cannot silently die during a long turn and cause the reply to miss the CLI
gateway.sessionPolicy.mode gateway.session_policy.mode Literal idle daily/idle/both/none Gateway session reset policy
gateway.sessionPolicy.dailyResetHour gateway.session_policy.daily_reset_hour int 4 Hour of day to reset sessions (0-23)
gateway.sessionPolicy.idleTimeoutMinutes gateway.session_policy.idle_timeout_minutes int 1440 Session idle timeout (minutes)
gateway.auth.mode gateway.auth.mode Literal allowlist open/allowlist/pairing Gateway authentication mode
gateway.auth.allowedUsers gateway.auth.allowed_users list [] Allowlist of users permitted to access the gateway
gateway.auth.adminUsers gateway.auth.admin_users list [] Gateway administrator users
gateway.auth.apiTokens gateway.auth.api_tokens list [] Gateway API access tokens
gateway.auth.adminTokens gateway.auth.admin_tokens list [] Tokens required for high-risk admin endpoints (skills import/install/delete and knowledge upload/delete); falls back to api_tokens when empty
gateway.auth.allowedOrigins gateway.auth.allowed_origins list [] Allowlisted browser Origins (cross-site escape hatch). Empty does NOT disable CSRF protection: the WS handshake, POST /message and the admin endpoints reject explicit cross-site browser requests by default. Use this to additionally permit specific Origins (webviews, a dev frontend port); non-browser clients are always unaffected
gateway.auth.tokenHeader gateway.auth.token_header str X-Echo-Agent-Token Request header carrying the API token
gateway.auth.pairingTtlSeconds gateway.auth.pairing_ttl_seconds int 300 Pairing-mode token time-to-live (seconds)
gateway.auth.allowedHosts gateway.auth.allowed_hosts list [] Accepted Host header values. DNS rebinding makes Origin and Host both attacker-controlled strings — comparing them is useless. The only authoritative signal is whether the Host matches a name this gateway was intended to be reached on: loopback addresses when bound to loopback, the proxy domain when behind one. Empty defers to the bind-address default (loopback addresses when bound to loopback; when bound to 0.0.0.0/:: it warns at startup and the admin endpoints — sessions, config, memory writes, tasks, cron, knowledge — reject every browser request). Entries are compared normalized (case-insensitive, port stripped, IPv6 brackets folded); a wildcard such as 0.0.0.0 or :: is not a usable entry and is dropped. Set explicitly for reverse-proxy deployments
gateway.knownPlatforms gateway.known_platforms list ['cli', 'ws', 'api', 'cron', 'dingtalk', 'discord', 'email', 'feishu', 'matrix', 'qqbot', 'slack', 'telegram', 'webhook', 'wechat', 'wecom', 'weixin', 'whatsapp'] Platform values the gateway recognises. A client-reported platform is interpolated into the channel name gateway:{platform}, and channel names carry capability decisions elsewhere (e.g. channels.stream_optimistic_channels asserts a channel can redraw in place), so a value outside this list is folded to "ws" rather than rejected — that keeps existing third-party callers working. Empty list disables folding (legacy fully self-reported behaviour)
gateway.platforms gateway.platforms dict {} Per-platform gateway configurations keyed by platform
gateway.platforms{}.rateLimitRpm gateway.platforms{}.rate_limit_rpm int 30 Per-minute request cap for this platform
gateway.mediaCacheDir gateway.media_cache_dir str data/media_cache Gateway media cache directory
gateway.mediaCacheMaxMb gateway.media_cache_max_mb int 500 Media cache size limit (MB)
gateway.mediaMaxFileMb gateway.media_max_file_mb int 25 Per-file download ceiling (MB). Enforced on both Content-Length and the real byte stream; an over-size download is aborted and its partial file removed
gateway.mediaMaxUrlsPerMessage gateway.media_max_urls_per_message int 10 Maximum media URLs accepted on one message; extras are rejected
gateway.mediaDownloadConcurrency gateway.media_download_concurrency int 4 Maximum parallel media downloads, bounding outbound connections and memory
gateway.mediaAllowPrivateAddresses gateway.media_allow_private_addresses bool false Allow media downloads to reach private/loopback addresses (SSRF risk). Same policy as tools.web.allowPrivateAddresses but a separate switch, since an internal CDN may legitimately need it. Blocked by default; the http/https scheme restriction applies either way
gateway.hooksDir gateway.hooks_dir str "" Gateway hook scripts directory

planning

Field snake type default choices description
planning.enabled planning.enabled bool true Enable task planning
planning.defaultStrategy planning.default_strategy str auto Default planning strategy
planning.maxBranches planning.max_branches int 3 Number of candidate branches the Tree-of-Thought strategy explores
planning.reflectionEnabled planning.reflection_enabled bool true Enable planning reflection

a2A

Field snake type default choices description
a2A.enabled a2a.enabled bool true Enable the A2A (agent-to-agent) interface
a2A.agentName a2a.agent_name str echo-agent Agent name exposed over A2A
a2A.agentDescription a2a.agent_description str A modular AI agent framework Agent description exposed over A2A
a2A.capabilities a2a.capabilities list ['chat', 'tool_use'] Capability tags advertised in the A2A AgentCard
a2A.taskTtlSeconds a2a.task_ttl_seconds float 3600.0 How long terminal A2A tasks are retained (seconds) before reclamation
a2A.maxTasks a2a.max_tasks int 1000 Capacity of the A2A task store; oldest terminal tasks are evicted past it
a2A.activeTaskTtlSeconds a2a.active_task_ttl_seconds float 86400.0 Backstop retention for non-terminal A2A tasks (seconds); a leak guard, not a task deadline

evaluation

Field snake type default choices description
evaluation.datasetPath evaluation.dataset_path str data/eval Evaluation dataset path
evaluation.timeoutPerCase evaluation.timeout_per_case int 120 Timeout per evaluation case (seconds)

bus

Field snake type default choices description
bus.maxQueueSize bus.max_queue_size int 1000 Event bus queue capacity
bus.maxConcurrency bus.max_concurrency int 50 Event bus max concurrent handlers

rateLimit

Field snake type default choices description
rateLimit.sessionRpm rate_limit.session_rpm int 20 Per-session requests-per-minute cap
rateLimit.sessionBurst rate_limit.session_burst int 5 Per-session burst allowance

circuitBreaker

Field snake type default choices description
circuitBreaker.failureThreshold circuit_breaker.failure_threshold int 5 Consecutive failures that trip the breaker
circuitBreaker.recoverySeconds circuit_breaker.recovery_seconds float 60.0 Wait before attempting recovery after tripping (seconds)
circuitBreaker.halfOpenMax circuit_breaker.half_open_max int 2 Probe requests allowed in half-open state

plugins

Field snake type default choices description
plugins.enabled plugins.enabled bool true Enable the plugin system
plugins.allow plugins.allow list [] Allowlist of plugins permitted to load
plugins.deny plugins.deny list [] Blocklist of plugins forbidden from loading
plugins.extraDirs plugins.extra_dirs list [] Additional plugin search directories
plugins.config plugins.config dict {} Per-plugin custom configuration keyed by plugin
plugins.trustedPlugins plugins.trusted_plugins list [] Trusted plugins exempt from permission checks
plugins.permissionMode plugins.permission_mode Literal compat compat/strict Plugin permission mode

ui

Field snake type default choices description
ui.locale ui.locale Literal auto en/zh/auto Interface language

agent

Field snake type default choices description
agent.maxIterations agent.max_iterations int 40 Maximum iterations of the agent main loop
agent.maxOutputContinuations agent.max_output_continuations int 3 Maximum automatic continuations after a model output-length stop
agent.continuationOverlapChars agent.continuation_overlap_chars int 2000 Character window used to remove overlap between continuation chunks
agent.toolConcurrency.enabled agent.tool_concurrency.enabled bool true Run read-only, non-overlapping tool calls concurrently
agent.toolConcurrency.maxConcurrent agent.tool_concurrency.max_concurrent int 4 Max concurrent tools (1 disables concurrency = serial)
agent.heartbeat.enabled agent.heartbeat.enabled bool true Emit periodic progress heartbeat during long-running turns
agent.heartbeat.firstDelaySec agent.heartbeat.first_delay_sec int 30 Silence threshold (sec) before the first heartbeat
agent.heartbeat.minIntervalSec agent.heartbeat.min_interval_sec int 60 Minimum interval (sec) between visible feedback
agent.heartbeat.verbosity agent.heartbeat.verbosity Literal key_milestones key_milestones/every_tool/silent Heartbeat verbosity tier
agent.heartbeat.template agent.heartbeat.template str ⏳ {activity}(已用时 {elapsed}) Heartbeat text template with {elapsed}/{activity}
agent.inspection.enabled agent.inspection.enabled bool false Enable proactive inspection (default off; declare items in INSPECT.md)
agent.inspection.tickIntervalSec agent.inspection.tick_interval_sec int 300 Inspection tick interval (seconds) for scanning due items
agent.inspection.inspectFile agent.inspection.inspect_file str INSPECT.md Inspection checklist filename (workspace-relative)
agent.inspection.maxItemsPerTick agent.inspection.max_items_per_tick int 5 Max due items dispatched to the agent per tick
agent.inspection.deliverChannel agent.inspection.deliver_channel str "" Inspection alert delivery channel (empty falls back to registering session)
agent.inspection.deliverChatId agent.inspection.deliver_chat_id str "" Inspection alert delivery chat id (empty falls back to registering session)

evolution

Field snake type default choices description
evolution.enabled evolution.enabled bool false Enable the self-evolving skill engine
evolution.triggerMode evolution.trigger_mode Literal manual manual/threshold/scheduled Evolution trigger mode
evolution.thresholdTrajectories evolution.threshold_trajectories int 50 Trajectory count triggering threshold mode
evolution.cronExpression evolution.cron_expression str 0 4 * * * Cron expression for scheduled mode
evolution.maxCandidatesPerRun evolution.max_candidates_per_run int 3 Maximum candidates generated per run
evolution.maxTrajectoriesPerRun evolution.max_trajectories_per_run int 200 Maximum trajectories processed per run
evolution.evalDatasetPath evolution.eval_dataset_path str data/eval/baseline.yaml Evolution evaluation baseline dataset path
evolution.regressionThreshold evolution.regression_threshold float 0.05 Score-drop threshold that flags a regression
evolution.requireStrictImprovement evolution.require_strict_improvement bool true Require strict improvement before promotion
evolution.minEvalCases evolution.min_eval_cases int 3 Minimum eval cases required to promote; fewer is inconclusive
evolution.recordTrajectories evolution.record_trajectories bool true Record execution trajectories for evolution
evolution.trajectoryRetentionDays evolution.trajectory_retention_days int 30 Trajectory retention period (days)
evolution.evolverModel evolution.evolver_model str "" Model used to perform evolution
evolution.skillSizeLimitBytes evolution.skill_size_limit_bytes int 50000 Size limit for evolved skills (bytes)
evolution.redactArgs evolution.redact_args bool true Redact tool arguments when recording trajectories
evolution.evalParallel evolution.eval_parallel int 2 Evolution evaluation parallelism
evolution.evalTimeoutSeconds evolution.eval_timeout_seconds int 60 Evolution evaluation per-case timeout (seconds)
evolution.cooldownSecondsAfterPromote evolution.cooldown_seconds_after_promote int 86400 Cooldown after a promotion before evolving again (seconds)
evolution.autoPromote evolution.auto_promote bool true Auto-promote candidates that pass evaluation
evolution.candidateReviewRequired evolution.candidate_review_required bool false Require human review of candidates before promotion

cost

Field snake type default choices description
cost.enabled cost.enabled bool false Enable cost tracking and budget control
cost.dailyBudgetUsd cost.daily_budget_usd float 0.0 Daily cost budget in USD (0 = unlimited)
cost.softThresholdRatio cost.soft_threshold_ratio float 0.8 Budget ratio at which a soft warning is raised
cost.pricingOverrides cost.pricing_overrides dict {} Model pricing override table

workspace

Field snake type default choices description
workspace workspace str ~/.echo-agent Agent workspace root directory