Skip to main content

Configuration

EstaCoda loads one selected profile configuration per session. There is no global config merge, no project-level overlay, and no credential-pool config surface. The profile you select is the profile you get.

Config lives in:

~/.estacoda/profiles/<profile-id>/config.json

Secrets belong in the selected profile .env or auth.json, never in config.json examples you paste from documentation.

Config families

The profile config supports these top-level families. Not every family is required. Omitted families use safe defaults or remain inactive.

model

Primary model route. Decides which provider and model handle the main inference loop.

{
"model": {
"provider": "openai",
"id": "gpt-4.1",
"apiKeyEnv": "OPENAI_API_KEY",
"maxTokens": 8192
}
}

Equivalent shape:

model:
provider: openai
id: gpt-4.1
maxTokens: 8192

model.maxTokens is the route-level output cap. Unset means provider default. Positive integer numbers and positive integer strings are accepted. Zero, negative values, floats, and non-numeric strings are rejected. Diagnostics show provider default when unset and warn for configured values below 2048.

Request-level maxTokens overrides route config for that provider call only. It does not mutate profile config, session overrides, aliases, fallbacks, or fingerprints.

Provider request parameter names are selected by API mode:

Provider/API modeSent parameter
OpenAI Chat Completionsmax_completion_tokens
Third-party OpenAI-compatible chatmax_tokens
OpenAI Responses APImax_output_tokens

Unset caps send no token parameter.

Provider requests also have timeout controls:

{
"model": {
"provider": "kimi",
"id": "kimi-k2.6",
"timeoutMs": 1800000,
"staleTimeoutMs": 120000
},
"providers": {
"kimi": {
"timeoutMs": 1800000,
"staleTimeoutMs": 120000
}
}
}

timeoutMs is the total provider request budget. It defaults to 1800000 ms, or 30 minutes. staleTimeoutMs is the no-progress budget. It defaults to 120000 ms, or 2 minutes.

Precedence:

model.timeoutMs / model.fallbacks[].timeoutMs
→ providers.<id>.timeoutMs
→ 1800000

model.staleTimeoutMs / model.fallbacks[].staleTimeoutMs
→ providers.<id>.staleTimeoutMs
→ 120000

For non-streaming provider calls, staleTimeoutMs is time-to-response-headers only. After headers arrive, the total timeout governs body parsing. For streaming provider calls, staleTimeoutMs resets after received bytes and catches both first-byte stalls and mid-stream stalls. Auxiliary model timeouts are configured separately through auxiliaryModels.*.timeoutMs; auxiliary stale timeouts and CLI setup flags for provider timeout tuning are not part of this config surface.

modelAliases / model_aliases

Named shortcuts for provider/model combinations.

{
"modelAliases": {
"fast": { "provider": "openai", "model": "gpt-4o-mini" }
}
}

providers

Additional provider routes, fallbacks, and metadata.

{
"providers": {
"fallback": { "provider": "openrouter", "model": "openrouter/auto" }
}
}

The built-in local provider can point at a local or custom OpenAI-compatible endpoint. It defaults to http://localhost:11434/v1 and no auth, so apiKeyEnv is optional:

{
"model": {
"provider": "local",
"id": "qwen2.5-coder"
},
"providers": {
"local": {
"baseUrl": "http://localhost:1234/v1",
"authMethod": "none"
}
}
}

If the endpoint requires a key, store the raw key in the selected profile .env and reference it from config:

{
"providers": {
"local": {
"baseUrl": "https://private-model-gateway.example/v1",
"apiKeyEnv": "OPENAI_COMPATIBLE_API_KEY"
}
}
}

Use a custom provider ID only when you need a separate named OpenAI-compatible route identity:

{
"providers": {
"lmstudio": {
"baseUrl": "http://localhost:1234/v1",
"apiKeyEnv": "OPENAI_COMPATIBLE_API_KEY"
}
}
}

auxiliaryModels

Specialized routes for non-primary tasks. Unsupported auxiliary names throw during config normalization.

RoutePurpose
visionImage analysis
compressionSemantic session compression
assessorSecurity approval assessor
web_extractWeb extraction
session_searchSession recall summarization
mcpMCP tool delegation
memory_flushMemory operations
delegationSubagent delegation
skills_librarySkills distribution
title_generationSession title generation
curatorSkill curation
memory_compactionMemory file compaction
profile_contextProfile context generation

delegation

Subagent delegation config is normalized with defaults when omitted.

KeyDefaultBehavior
maxSpawnDepth1Maximum recursive child delegation depth. leaf children cannot delegate.
maxConcurrentChildren3Maximum active children in a batch.
maxDelegateCallsPerTurn3Per-provider-turn cap for separate delegate_task calls.
maxBatchTasks10Maximum tasks[] length.
childTimeoutSeconds600Child timeout floor is 30 seconds.
heartbeatSeconds30Parent heartbeat interval while child work runs.
heartbeatStaleCyclesIdle3Idle stale-heartbeat threshold.
heartbeatStaleCyclesInTool6In-tool stale-heartbeat threshold.
recoverJsonStringTaskstrueStrictly recover JSON-string tasks arrays.
diagnostics.enabledtrueWrite bounded timeout/stale diagnostics where a profile diagnostics root exists.
diagnostics.includePromptPreviewfalseFull prompt previews stay off by default.
outcomeMemory.enabledfalseOpt-in bounded delegation outcome memory.
defaultAllowedRiskClassesread-only-local, read-only-networkDefault child tool risk classes after parent-visible intersection.
defaultExcludedToolsetsbrowser, media, mcpToolsets stripped from default child schemas.
defaultAllowedToolsetsemptyNo broad default toolset grant.
blockedToolNames / blockedToolPrefixesbuilt-in deny listExact/prefix tool stripping before child schemas are built.
childRuntimerecall/learning/compression disabled, project context boundedSuppresses parent-like runtime features in child loops.

terminal.run, write/process control, memory/session search, skill/config/cron/trust mutation, and credential surfaces are stripped by default. terminal.inspect is read-only-local and may be child-visible only when parent-visible and allowed by the read-only policy. Delegation config participates in the runtime fingerprint so schema-affecting changes rebuild provider tool schemas.

web

Web research backend selection.

{
"web": {
"searchBackend": "brave",
"extractBackend": "fetch",
"brave": {
"apiKeyEnv": "BRAVE_SEARCH_API_KEY"
}
}
}

Selection is capability-specific:

web.searchBackend / web.extractBackend / web.crawlBackend
→ web.backend
→ auto-detect available providers
→ unavailable

Explicit config wins. If web.searchBackend names an unavailable provider, web.search reports that provider's unavailable reason instead of silently falling back.

KeyTypeNotes
web.backendstringLegacy/general web provider preference used when no capability-specific backend is set.
web.searchBackendstringSearch provider preference. Live search providers are brave and ddgs.
web.extractBackendstringExtraction provider preference. fetch is the guarded live extraction fallback.
web.crawlBackendstringCrawl provider preference. No live crawl provider is implemented in this release.
web.brave.apiKeyEnvstringEnv-var reference for Brave Search. Defaults to BRAVE_SEARCH_API_KEY. Do not store the raw API key in config.

Brave Search is a credentialed external provider and uses the same env-reference/deferred-secret setup pattern as model providers. DDGS uses the managed Python capability ddgs; install or verify it explicitly with estacoda python-env setup ddgs and estacoda python-env verify ddgs. Runtime web.search does not install Python packages automatically.

Firecrawl, Parallel, Tavily, Exa, and SearXNG remain registered stubs and report unavailable when configured.

compression

Semantic session compression. Experimental-only in v0.1.0.

{
"compression": {
"enabled": false,
"experimental": false,
"threshold": 0.50,
"targetRatio": 0.20,
"protectFirstTurns": 3,
"protectLastTurns": 20
}
}

Both enabled and experimental must be true for compression to activate.

externalMemory / external_memory

Optional external recall and mirror writes. Disabled by default.

{
"externalMemory": {
"enabled": false,
"provider": "file",
"timeoutMs": 750,
"maxResults": 3,
"maxChars": 2500,
"mirrorWrites": false
}
}

Only the built-in file provider is implemented. Absolute paths are rejected.

browser

Browser backend selection.

{
"browser": {
"backend": "local-cdp",
"supervised": true,
"autoLaunch": true,
"launchExecutable": "/path/to/chrome",
"launchArgs": ["--headless=new"],
"chromeFlags": ["--no-first-run"],
"summarizeSnapshots": "auto",
"snapshotSummarizeThreshold": 8000
}
}

local-cdp supports manual CDP connections and supervised auto-launch. Use launchExecutable, launchArgs, and chromeFlags for structured launch configuration. launchCommand remains accepted only as deprecated compatibility data and is not shell-parsed.

KeyTypeNotes
browser.launchExecutablestringPreferred explicit Chrome/Chromium executable path for supervised local CDP auto-launch.
browser.launchArgsstring arrayStructured launch arguments. Repeat --launch-arg in CLI setup to append.
browser.chromeFlagsstring arrayStructured Chrome flags. Repeat --chrome-flag in CLI setup to append.
browser.launchCommandstringDeprecated compatibility data only. Not split, guessed, or shell-parsed.
browser.hybridRoutingbooleanRoutes public HTTP(S) URLs to cloud and allowed private/internal URLs to local when configured. Does not bypass URL safety.
browser.cloudFallbackbooleanAllows eligible Browserbase failures to fall back to local. Spend approval failures do not fall back.
browser.cloudSpendApprovedboolean or "pending"Explicit approval for billable cloud browser session creation. Credentials alone do not approve spend.
browser.summarizeSnapshotsboolean or "auto"Controls whether oversized rendered snapshots may be summarized.
browser.snapshotSummarizeThresholdnumberRendered snapshot character threshold before summarization is considered.

Browserbase is implemented through the browser backend and requires BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID, and explicit browser.cloudSpendApproved: true before billable sessions can be created. estacoda browser approve-cloud sets approval, and estacoda browser revoke-cloud disables it. Config alone does not create Browserbase sessions. browser-use, Firecrawl browser, and Camofox remain deferred providers.

Hybrid routing follows the browser URL-safety policy: private/internal URLs remain blocked unless security.allowPrivateUrls is explicitly true, metadata endpoints are always blocked, and unsafe redirects are blanked to about:blank when possible or the unsafe session is closed.

imageGen / image_gen

Image generation provider and model.

{
"imageGen": {
"provider": "fal",
"model": "fal-ai/flux-2/klein/9b",
"useGateway": false
}
}

Supported providers: fal, byteplus, openai.

tts

Text-to-speech provider and voice settings.

{
"tts": {
"enabled": true,
"provider": "edge",
"edge": {
"voice": "en-US-AriaNeural",
"speed": 1.0
}
}
}

Implemented TTS: OpenAI, ElevenLabs, MiniMax, Gemini, xAI, and Edge. Edge requires no API key, but it is networked: synthesis text is sent to Microsoft's Edge speech service, and output is MP3 (audio/mpeg). Local/offline TTS providers neutts and kittentts, and Mistral TTS, are deferred.

Interactive setup asks for the TTS provider only. It uses runtime defaults for models, voices, and provider settings, and collects hosted provider API keys through masked input. Config stores env-var references such as apiKeyEnv, while profile-local secret values are written to .env only after reviewed apply. Direct operator CLI flags such as estacoda voice setup --tts-model, --tts-api-key-env, and --tts-api-key remain available for scripted setup.

stt

Speech-to-text provider and model.

{
"stt": {
"enabled": true,
"provider": "openai",
"openai": {
"model": "gpt-4o-mini-transcribe",
"apiKeyEnv": "VOICE_TOOLS_OPENAI_KEY"
}
}
}

Stable hosted STT: OpenAI, Groq, xAI. Local STT supports command and faster-whisper. Mistral STT is deferred.

Interactive setup asks for the STT provider only. It uses runtime defaults for models and provider settings, and collects hosted provider API keys through masked input. Config stores env-var references such as apiKeyEnv, while profile-local secret values are written to .env only after reviewed apply. Direct operator CLI flags such as estacoda voice setup --stt-model, --stt-api-key-env, and --stt-api-key remain available for scripted setup.

In v0.1.0, stt.provider: "local" defaults to managed faster-whisper:

{
"stt": {
"provider": "local",
"local": {
"engine": "faster-whisper",
"model": "base",
"pythonBinary": "/optional/custom/python",
"fasterWhisper": {
"enabled": true,
"model": "base",
"device": "auto",
"computeType": "default",
"hfHome": "/optional/model-cache",
"allowModelDownload": true,
"gatewayAllowModelDownload": true,
"queueDepth": 1,
"timeoutMs": 300000
}
}
}
}

Omit pythonBinary for the managed path resolved under ~/.estacoda/python-env, or set it to an operator-owned Python when using estacoda voice setup --stt-provider local --python-binary /path/to/python. The default model cache is ~/.estacoda/cache/huggingface; it is separate from the venv.

Gateway model downloads inherit allowModelDownload. Because allowModelDownload defaults to true, gateway-triggered first-run downloads are allowed by default; set gatewayAllowModelDownload: false only when gateway voice messages must require a cached model.

Command mode is explicit:

{
"stt": {
"provider": "local",
"local": {
"engine": "command",
"command": "/path/to/transcriber {input}"
}
}
}

engine: "command" wins and does not use managed faster-whisper.

voice

Gateway auto-TTS behavior.

{
"voice": {
"autoTts": false,
"autoTtsMaxCharsPerReply": 1200,
"autoTtsMaxCharsPerHourPerChat": 5000
}
}

mcpServers / mcp_servers

MCP server definitions.

{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/path/to/server.js"],
"cwd": "/optional/cwd",
"env": { "KEY": "value" },
"includeTools": ["tool1"],
"excludeTools": ["tool2"],
"trust": "conservative",
"timeout": 30000
}
}
}

Trust levels: conservative, read-only-network, read-only-local.

skills

Skill loading and Agent Evolution policy.

{
"skills": {
"autonomy": "suggest",
"externalDirs": ["/optional/external/skill/root"]
}
}

Autonomy modes: none, suggest, proactive, autonomous.

skills.autonomy is the persisted compatibility key for Agent Evolution. It controls reviewable evidence/proposal behavior. autonomous is shadow-only: it records decisions for review but does not auto-promote, auto-rollback, or mutate skill files.

ui

Terminal UI preferences.

{
"ui": {
"theme": "dark",
"locale": "en"
}
}

profile

Profile metadata.

{
"profile": {
"name": "work",
"description": "Production work profile"
}
}

security

Security mode and policy overrides.

{
"security": {
"mode": "adaptive",
"allowPrivateUrls": false,
"websiteBlocklist": {
"domains": ["*.example.com"]
}
}
}

Modes: strict, adaptive, open. Default is adaptive.

channels

Channel adapter configuration. See Channel Configuration for full schema.

{
"channels": {
"telegram": {
"enabled": true,
"botTokenEnv": "ESTACODA_TELEGRAM_BOT_TOKEN",
"streaming": {
"enabled": true,
"editIntervalMs": 750,
"minInitialChars": 24,
"cursor": "▌",
"maxFloodStrikes": 2,
"cleanupFailedAttempts": true,
"transport": "auto",
"freshFinalAfterSeconds": 0
},
"busyPolicy": "reject",
"queueDepth": 3
}
}
}

Guided Telegram setup stores the bot token in the selected profile .env under ESTACODA_TELEGRAM_BOT_TOKEN and writes botTokenEnv: "ESTACODA_TELEGRAM_BOT_TOKEN" to config. The raw Telegram bot token must not appear in config review or setup output.

Telegram streaming is configured under channels.telegram.streaming. It defaults to enabled for configured Telegram channels and affects Telegram delivery only. Set channels.telegram.streaming.enabled to false to opt out. It does not change session state, memory, approvals, tool execution, artifacts, or final response.text.

SettingType / allowed valuesDefaultNotes
channels.telegram.streaming.enabledbooleantrueEnables Telegram streaming for configured Telegram channels. Set to false to opt out.
channels.telegram.streaming.editIntervalMsnon-negative integer750Coalescing interval for Telegram partial edits.
channels.telegram.streaming.minInitialCharsnon-negative integer24Visible filtered character threshold before first partial send.
channels.telegram.streaming.cursorstring"▌"Temporary live cursor appended to partial messages.
channels.telegram.streaming.maxFloodStrikesnon-negative integer2Active-turn flood-control degradation limit.
channels.telegram.streaming.cleanupFailedAttemptsbooleantrueDelete or neutralize provisional streamed messages after provider failure/fallback.
channels.telegram.streaming.transport"auto", "edit", or "draft""auto""auto" selects draft previews for DMs when supported and edit streaming otherwise. "edit" uses ordinary message edits. "draft" uses Telegram draft previews in DMs only when supported by the Bot API.
channels.telegram.streaming.freshFinalAfterSecondsnon-negative integer00 disables fresh-final delivery. A positive value sends the completed answer as a fresh message after a preview has been visible that many seconds, then deletes the preview best-effort.

Telegram streaming runs before normal final-text routing. If streaming cannot deliver the completed answer, ChannelGateway falls back to normal DeliveryRouter delivery. Partial streaming uses lightweight HTML escaping; final delivery uses normal Telegram formatting. Draft previews and rich message delivery depend on Telegram and Bot API support. Rich message delivery is opportunistic and falls back to normal Telegram formatting when unsupported, too long, or ambiguous. Flood control, oversized partial payloads, approval boundaries, artifact boundaries, or final edit failures force normal final text fallback for the active turn only. Streaming remains delivery UX only; final response.text remains authoritative.

Secret handling

  • Provider setup writes raw API keys only to the selected profile .env, never to config.json. Local / Custom endpoints are no-auth by default and write a key only when one is provided.
  • Voice setup review manifests show env-var references only. Raw Voice API keys are not stored in config, shown in review manifests, or inserted into prompt context.
  • Profile .env is chmodded to 0600 when written by the env secret store.
  • Runtime config loads the selected profile .env before execution.
  • Do not paste real secrets into config snippets.

Validation

EstaCoda validates config during load. Invalid values fall back to defaults or clamp to bounds where safe. Missing required credentials produce setup-needed hints, not crashes.