Skip to content

Configuration Reference

All xopc configuration is centralized in ~/.xopc/xopc.json.

Quick Start

Run the interactive setup wizard:

bash
xopc onboard

Or create manually:

json
{
  "agents": {
    "defaults": {
      "model": "anthropic/claude-sonnet-4-5",
      "max_tokens": 8192,
      "temperature": 0.7
    }
  },
  "providers": {
    "anthropic": "${ANTHROPIC_API_KEY}"
  }
}

Full Configuration Example

json
{
  "agents": {
    "defaults": {
      "workspace": "~/.xopc/workspace",
      "model": {
        "primary": "anthropic/claude-sonnet-4-5",
        "fallbacks": ["openai/gpt-4o", "minimax/minimax-m2.1"]
      },
      "max_tokens": 8192,
      "temperature": 0.7,
      "max_tool_iterations": 20
    }
  },
  "providers": {
    "openai": "${OPENAI_API_KEY}",
    "anthropic": "${ANTHROPIC_API_KEY}",
    "groq": "${GROQ_API_KEY}",
    "google": "${GOOGLE_API_KEY}",
    "minimax": "${MINIMAX_API_KEY}"
  },
  "channels": {
    "telegram": {
      "enabled": true,
      "accounts": {
        "personal": {
          "name": "Personal Bot",
          "botToken": "BOT_TOKEN",
          "dmPolicy": "allowlist",
          "groupPolicy": "open",
          "allowFrom": [123456789],
          "streamMode": "partial"
        }
      }
    }
  },
  "gateway": {
    "host": "0.0.0.0",
    "port": 18790
  },
  "tools": {
    "web": {
      "search": {
        "maxResults": 5,
        "providers": [{ "type": "brave", "apiKey": "BSA_your_key_here" }]
      }
    }
  },
  "tools": {
    "media": {
      "audio": {
        "enabled": true,
        "provider": "alibaba",
        "alibaba": {
          "apiKey": "${DASHSCOPE_API_KEY}",
          "model": "paraformer-v2"
        }
      }
    }
  },
  "messages": {
    "tts": {
      "enabled": true,
      "provider": "openai",
      "trigger": "inbound",
      "openai": {
        "apiKey": "${OPENAI_API_KEY}",
        "model": "tts-1",
        "voice": "alloy"
      }
    }
  },
  "heartbeat": {
    "enabled": true,
    "intervalMs": 300000
  }
}

Configuration Sections

agents

Agent configuration has three parts: optional default id, shared defaults, and per-identity list entries. Routing and session keys use the first segment of the session key as the agent id; the effective profile for that turn merges defaults with the matching enabled list row (model, workspace, tools, prompts, etc.).

Top-level agents fields

FieldTypeDescription
defaultstringOptional. Default agent id when the session key or API does not specify one. If omitted: first list entry with default: true, else first enabled entry in list, else main.
defaultsobjectBaseline settings merged into every agent (see agents.defaults below).
listarrayRegistered identities; each object can override fields for that id.

agents.list entries

Each entry must include id. Other fields are optional overrides (same shapes as in defaults where applicable).

FieldTypeDescription
idstringAgent id (also the first segment of the session key).
defaultbooleanOptional. When true, marks this entry as the default agent when top-level agents.default is unset.
namestringDisplay name.
enabledbooleanDefault true. When false, the id is ignored for routing defaults and effective profile resolution falls back to the default agent.
workspacestringPer-agent Markdown workspace root (~ expanded). Tool cwd, daily memory/, and user files. Profile Markdown (SOUL.md, …) lives under agents/<id>/profile/. Inbound/TTS blobs and curated memories/ live under agents/<id>/ (agent home), not as siblings of unrelated trees inside this directory.
agentDirstringOptional. Overrides the internal agent state directory (credentials, agent.json, inbox, pid) — default <stateDir>/agents/<id>/agent.
modelstring | objectSame as agents.defaults.model (string or { primary, fallbacks }).
thinkingDefaultstringOptional. One of off, minimal, low, medium, high, xhigh, adaptive.
reasoningDefaultstringOptional. off, on, stream.
verboseDefaultstringOptional. off, on, full.
systemPromptOverridestringOptional. When set, replaces the usual base system prompt; skills block is still appended (subject to skills allowlist).
skillsstring[]Optional. Allowlist of skill names for <available_skills>; when set, only those skills are advertised.
toolsobjectOptional. { "disable": ["tool_name", ...] } — built-in tools to omit by tool name (e.g. shell, web_search, session_search, image; use extensions to disable extension tools).
paramsobjectOptional. Reserved for future use.

The same optional keys can appear under agents.defaults for global defaults (e.g. agents.defaults.tools.disable merged with per-agent disables).

Note: On-disk paths (~/.xopc/agents/<id>/ for sessions and internal state, per-agent Markdown workspace under agents.defaults.workspace/<agentId> or <stateDir>/workspace/<agentId>) are derived from config.json (agents.list, agents.defaults, optional agentDir overrides). Use xopc agents add / agents delete to manage entries and directories; there is no separate agent “registry” outside config.

agents.defaults

FieldTypeDefaultDescription
workspacestring~/.xopc/workspaceParent directory for Markdown workspaces; each agent resolves to <expanded>/<agentId>/ (e.g. ~/.xopc/workspace/main)
modelstring/objectanthropic/claude-sonnet-4-5Default model
max_tokensnumber8192Maximum output tokens
temperaturenumber0.7Temperature (0-2)
max_tool_iterationsnumber20Max tool call iterations
imageModelstring | objectVision model for the image and browser_use tools and for describing inbound images when the session model does not support vision. Same formats as model (string or { primary, fallbacks }). See Image & vision.
imageGenerationModelstring | objectImage generation chain for image_generate (e.g. openai/gpt-image-1, dashscope/wan2.6-t2i). Same formats as model. See Image & vision.
mediaMaxMbnumberOptional. Max size in MB when the image tool loads files from disk or URLs.

agents.defaults.model

Model configuration supports two formats:

Simple format:

json
{
  "model": "anthropic/claude-sonnet-4-5"
}

Object format (with fallbacks):

json
{
  "model": {
    "primary": "anthropic/claude-sonnet-4-5",
    "fallbacks": ["openai/gpt-4o", "minimax/minimax-m2.1"]
  }
}

Model ID format: provider/model-id (e.g., anthropic/claude-opus-4-5).

The same { primary, fallbacks } object shape applies to imageModel and imageGenerationModel when you want ordered fallbacks for vision or image generation.

agents.defaults.memory

Curated long-term memory under agents/<agentId>/memories/ (MEMORY.md / USER.md), optional stub external provider for wiring tests, and controls for prefetch injection (fenced <memory-context> prefix on user turns). See Curated memory.

FieldTypeDefaultDescription
enabledbooleantrueMaster switch. When false: no curated snapshot, no curated_memory tool, no external memory provider, no prefetch/sync.
useEnhancedSystembooleantrueWhen false: disable curated snapshot and curated_memory; agents/<id>/profile/MEMORY.md still applies.
userProfileEnabledbooleantrueWhen false: omit USER.md from the system prompt; curated_memory cannot mutate the user target (read still allowed).
memoryCharLimitnumber2200Max characters for MEMORY.md entries (total).
userCharLimitnumber1375Max characters for USER.md entries (total).
providerstringnoneExternal provider: none or stub (ignored when enabled is false).
injectionFrequencystringevery-turnPrefetch injection: every-turn or first-turn (first user message of the session only).
contextCadencenumber1When injectionFrequency is every-turn, inject prefetch on turns 1, 1+N, 1+2N, … (minimum 1).
dialecticCadencenumberReserved for future external sync cadence (not wired yet).

agents.defaults.sessionSearch

Cross-session transcript search via the session_search tool (when session persistence is available).

FieldTypeDefaultDescription
summaryModelstringModel ref for per-session summaries (e.g. openai/gpt-4o-mini). Overrides env XOPC_SESSION_SEARCH_MODEL when set.

agents.defaults.browser

The unified browser_use tool is registered when enabled is true. Install Chromium once for local mode: npx playwright install chromium. Tool behavior and URL policy: Tools — Browser.

FieldTypeDefaultDescription
enabledbooleanWhen true, registers browser automation tools.
headlessbooleantrue (when browser enabled)Run browser without a visible window.
allowPrivateUrlsbooleanWhen true, allows navigation to private IP ranges; cloud metadata / IMDS and suspicious token-in-URL patterns stay blocked.
commandTimeoutnumber30Seconds per browser command (minimum 5).
cloudProviderstringlocal | browserbase | browser-use. Omit or local for in-process Playwright.
cdpUrlstringOptional WebSocket URL to an existing browser (CDP); bypasses cloudProvider when set.
dialogPolicystringmust_respond | auto_dismiss | auto_accept — how JS dialogs are handled with the CDP supervisor.
dialogTimeoutSecondsnumber300Timeout for auto dialog handling (minimum 1).

providers

Configure LLM provider API keys. Use environment variable references:

json
{
  "providers": {
    "openai": "${OPENAI_API_KEY}",
    "anthropic": "${ANTHROPIC_API_KEY}",
    "groq": "${GROQ_API_KEY}"
  }
}

Built-in provider ids match @earendil-works/pi-ai KnownProvider. Env var names are defined in src/providers/env-keys.ts (PROVIDER_ENV_MAP); the table below mirrors that file. Other vendors (e.g. DashScope-only HTTP APIs) use models.json, not xopc.jsonproviders, unless you add a custom id there.

Provider idEnvironment variables (first match wins where listed)
amazon-bedrockAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION (and other AWS envs per pi-ai / SDK)
anthropicANTHROPIC_OAUTH_TOKEN, ANTHROPIC_API_KEY
azure-openai-responsesAZURE_OPENAI_API_KEY, AZURE_OPENAI_BASE_URL
cloudflare-ai-gatewayCLOUDFLARE_API_KEY (model URLs may also need account/gateway ids—see pi-ai model baseUrl)
cloudflare-workers-aiCLOUDFLARE_API_KEY
cerebrasCEREBRAS_API_KEY
dashscopeDASHSCOPE_API_KEY (image/STT/TTS; not an LLM KnownProvider in pi-ai)
deepseekDEEPSEEK_API_KEY
fireworksFIREWORKS_API_KEY
github-copilotCOPILOT_GITHUB_TOKEN, GH_TOKEN, GITHUB_TOKEN, GITHUB_COPILOT_TOKEN
googleGEMINI_API_KEY, GOOGLE_API_KEY
google-antigravityANTIGRAVITY_API_KEY
google-gemini-cliGEMINI_CLI_TOKEN, GOOGLE_TOKEN
google-vertexGOOGLE_CLOUD_API_KEY, GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_LOCATION
groqGROQ_API_KEY
huggingfaceHF_TOKEN, HUGGINGFACE_TOKEN
kimi-codingKIMI_API_KEY, MOONSHOT_API_KEY
minimaxMINIMAX_API_KEY
minimax-cnMINIMAX_CN_API_KEY, MINIMAX_API_KEY
mistralMISTRAL_API_KEY
moonshotaiMOONSHOT_API_KEY
moonshotai-cnMOONSHOT_API_KEY
openaiOPENAI_API_KEY
openai-codex(no env map row—use OAuth / xopc auth login openai-codex)
opencodeOPENCODE_API_KEY
opencode-goOPENCODE_API_KEY
openrouterOPENROUTER_API_KEY
togetherTOGETHER_API_KEY
vercel-ai-gatewayAI_GATEWAY_API_KEY, VERCEL_AI_GATEWAY_API_KEY
xaiXAI_API_KEY
xiaomiXIAOMI_API_KEY
xiaomi-token-plan-cnXIAOMI_TOKEN_PLAN_CN_API_KEY
xiaomi-token-plan-amsXIAOMI_TOKEN_PLAN_AMS_API_KEY
xiaomi-token-plan-sgpXIAOMI_TOKEN_PLAN_SGP_API_KEY
zaiZAI_API_KEY

For why there are four Xiaomi ids, see Models — Built-in LLM providers.

Note: Environment variables take priority over config file values.

See Models Documentation for custom provider configuration.


bindings

Optional array of rules that assign an agentId to incoming traffic. Rules are sorted by priority (higher first). Each rule’s match requires an exact channel value (e.g. telegram); peerId may use * glob patterns. If nothing matches, routing uses the default agent id: agents.default if set, else the first enabled entry in agents.list, else main. See Session Routing System.


session

FieldTypeDefaultDescription
dmScopestringmainHow DM sessions are merged or split: main, per-peer, per-channel-peer, per-account-channel-peer
identityLinksobject-Map of canonical id → ["channel:peerId", ...] aliases for cross-channel identity
storageobject-Optional session store tuning (pruneAfterMs, maxEntries)

Details and examples: Session Routing System.


channels

Communication channels configuration.

Keys under channels depend on which channel types you use. Built-in Telegram and Weixin accept the shapes documented in Channel configuration. Other keys may come from extensions—follow each extension’s README.

channels.telegram

Multi-account Telegram configuration:

json
{
  "channels": {
    "telegram": {
      "enabled": true,
      "accounts": {
        "personal": {
          "name": "Personal Bot",
          "botToken": "BOT_TOKEN",
          "dmPolicy": "allowlist",
          "groupPolicy": "open",
          "allowFrom": [123456789],
          "streamMode": "partial"
        }
      }
    }
  }
}
FieldTypeDefaultDescription
enabledbooleanfalseEnable Telegram
accountsobject-Multi-account config
accounts.<id>.namestring-Display name
accounts.<id>.botTokenstring-Bot token
accounts.<id>.dmPolicystringopenDM policy
accounts.<id>.groupPolicystringopenGroup policy
accounts.<id>.allowFromarray[]Allowed user IDs
accounts.<id>.streamModestringpartialStream mode

DM policies (pairing | allowlist | open | disabled):

  • pairing (recommended): unknown users are not passed to the agent until their Telegram / Feishu / Weixin sender id is allowed. Allow sources are allowFrom in config plus entries in the per-channel credential file created after you run xopc channels pairing approve. First contact receives a pairing code in DM. See Channels — DM pairing and CLI — channels.
  • allowlist: same merge rules as pairing for the allow list, but no pairing code message; unknown senders are dropped.
  • open: any user can DM (avoid on public bots).
  • disabled: DMs are rejected.

Group Policies: open | allowlist | disabled

Stream Modes: off | partial | block

channels.feishu

json
{
  "channels": {
    "feishu": {
      "enabled": true,
      "appId": "APP_ID",
      "appSecret": "APP_SECRET",
      "verificationToken": "VERIFICATION_TOKEN"
    }
  }
}

gateway

HTTP API gateway configuration.

FieldTypeDefaultDescription
bindstringloopbackauto, loopback, lan, tailnet, custom
customBindHoststring-IPv4 address when bind is custom
portnumber18790Port number
modestringlocallocal or remote (CLI target)
remoteobject-Persistent remote URL/token for CLI when mode=remote
tailscaleobject{ mode: off }serve / funnel / off — see network.md
tlsobject-Native HTTPS (optional)
authobject-Authentication config
corsOriginsstring[][]Browser origin allowlist

gateway.auth

FieldTypeDefaultDescription
modestringtokenAuth mode: none, token, password
tokenstringauto-generatedBearer / X-Api-Key credential when mode: "token"
passwordstring-Password credential when mode: "password"
rateLimitobjectenabledBrute-force protection for failed auth attempts

Notes:

  • gateway.auth.token and gateway.auth.password are mutually exclusive; setting both is rejected at startup.
  • In token mode, if no token is configured, xopc generates a random token at startup.
  • Weak / placeholder tokens (for example your-secret-token-here) and tokens shorter than 16 chars are rejected.
  • You can override auth from env: XOPC_GATEWAY_AUTH_MODE, XOPC_GATEWAY_TOKEN, XOPC_GATEWAY_PASSWORD.

gateway.auth.rateLimit

FieldTypeDefaultDescription
enabledbooleantrueEnable auth failure rate limiting
maxAttemptsnumber5Max failed attempts within the window
windowMsnumber900000Rolling window in milliseconds
blockDurationMsnumber300000Temporary block duration in milliseconds

gateway.corsOrigins

FieldTypeDefaultDescription
gateway.corsOriginsstring[][]Browser origin allowlist (exact origins, e.g. http://localhost:5173)

Security behavior:

  • Browser requests with an Origin header are rejected when origin checks fail.
  • Non-browser requests without Origin are validated by the auth middleware instead.
  • Setting corsOrigins to "*" is allowed but flagged by startup security audit logs.

Channel connect defer

Fields live under gateway.* (channelConnectDeferMode, channelConnectDeferIds, channelConnectDeferSkipIds). When you run xopc gateway (the GatewayServer path), outbound-heavy channel plugins (Telegram, Weixin, Feishu) can defer ChannelPlugin.start() until after the HTTP listener has bound, so the control plane and static UI come up first. Plugin authors opt in via meta.deferConnectUntilAfterListen on the channel plugin.

FieldTypeDefaultDescription
channelConnectDeferMode"auto" | "off" | "explicit"(unset →) autoauto — defer set = enabled channels whose plugin meta requests defer, minus channelConnectDeferSkipIds. off — never defer; all channels start() in phase 1. explicit — defer only ids listed in channelConnectDeferIds (empty list → defer none).
channelConnectDeferIdsstring[]-Max 24 entries. Used when channelConnectDeferMode is explicit.
channelConnectDeferSkipIdsstring[]-Max 24 entries. Removed from the defer set after auto or explicit resolution.

Startup logs (structured, phase: "gateway.channel_startup"):

  • stage: "phase1" — includes channelInitMs, deferPlanMs, channelPhase1StartMs, replayOutboundMs (or null when replay runs after listen), channelConnectDeferMode, channelConnectDeferSource (meta | explicit | off), and deferredChannelIds.
  • stage: "phase2" — after HTTP listen: channelPhase2DeferredMs, replayOutboundMs, onHttpListeningTotalMs, plus the same defer mode/source snapshot.

Useful filters: gateway.channel_startup or phase-1 complete / phase-2 complete in log text.

See also Gateway — Channel startup and HTTP listen order.


tools

Tool configurations.

tools.web

FieldTypeDefaultDescription
searchobject-Web search config
browseobject-Web browsing config
FieldTypeDefaultDescription
maxResultsnumber5Default result count when the tool omits count
providersarray[]Ordered list of search backends (brave, tavily, bing, searxng). Empty → HTML fallback only.

Each provider entry: type, optional apiKey, optional url (SearXNG base URL), optional disabled.


tools.media.audio (STT)

Speech-to-Text configuration for inbound voice messages. Lives under tools.media.audio (the gateway REST surface still exposes it as stt for backwards-friendly form payloads).

FieldTypeDefaultDescription
enabledbooleanfalseEnable STT
providerstringalibabaPrimary provider: alibaba, openai
alibabaobject-Alibaba DashScope config
openaiobject-OpenAI Whisper config
fallbackobject-Fallback configuration
timeoutMsnumber60000Hard per-call HTTP timeout (ms)

tools.media.audio.alibaba

FieldTypeDefaultDescription
apiKeystring-DashScope API key (env: DASHSCOPE_API_KEY)
modelstringparaformer-v2Model id

tools.media.audio.openai

FieldTypeDefaultDescription
apiKeystring-OpenAI API key (env: OPENAI_API_KEY)
modelstringwhisper-1Whisper model id

tools.media.audio.fallback

FieldTypeDefaultDescription
enabledbooleantrueEnable fallback
orderarray["alibaba", "openai"]Fallback order

On failure, the runtime tries each provider in order and records structured attempts (provider, outcome, latency, reason) for diagnostics. All HTTP calls go through the shared media-shared/http chassis with SSRF guard (fetchWithTimeoutGuarded).

Example:

json
{
  "tools": {
    "media": {
      "audio": {
        "enabled": true,
        "provider": "alibaba",
        "alibaba": {
          "apiKey": "${DASHSCOPE_API_KEY}",
          "model": "paraformer-v2"
        },
        "fallback": {
          "enabled": true,
          "order": ["alibaba", "openai"]
        }
      }
    }
  }
}

messages.tts (TTS)

Text-to-Speech configuration for assistant voice replies and the optional text_to_speech agent tool. Lives under messages.tts (the gateway REST surface still exposes it as tts).

FieldTypeDefaultDescription
enabledbooleanfalseEnable TTS (and registration of text_to_speech when true)
providerstringopenaiPrimary provider: openai, alibaba, edge, minimax, tts-local-cli, or any extension-registered SpeechProviderPlugin id
triggerstringalwaysoff, always, inbound, tagged
maxTextLengthnumber512Max characters sent to TTS providers. Conservative default chosen to fit every built-in provider (Alibaba qwen-tts caps at 512). Raise per-provider if your primary supports longer input.
timeoutMsnumber60000Per-request HTTP timeout (ms). Range 1000180000. MiniMax internally bumps to ≥150s for its async polling flow.
fallbackobject-Provider fallback order
summarizationobject-LLM summarization before TTS when text exceeds threshold
modelOverridesobject-Allow [[tts:...]] directives from the model
openaiobject-OpenAI TTS config
alibabaobject-Alibaba DashScope TTS config
edgeobject-Microsoft Edge TTS (no API key)
minimaxobject-MiniMax T2A async TTS config
tts-local-cliobject-Local CLI provider (bundled extension)

messages.tts.openai

FieldTypeDefaultDescription
apiKeystring-OpenAI API key (env: OPENAI_API_KEY)
baseUrlstringhttps://api.openai.com/v1Override base URL (env: OPENAI_TTS_BASE_URL) for OpenAI-compatible vendors
modelstringtts-1Model: tts-1, tts-1-hd, gpt-4o-mini-tts
voicestringalloyVoice: alloy, echo, fable, onyx, nova, shimmer, coral, verse, …

messages.tts.alibaba

FieldTypeDefaultDescription
apiKeystring-DashScope API key (env: DASHSCOPE_API_KEY)
modelstringqwen-ttsTTS model id
voicestringlongxiaochunVoice id (Cherry, Ethan, longxiaochun, longxiaobai, …)

messages.tts.edge

FieldTypeDefaultDescription
enabledbooleantrueWhen false, Edge is excluded from the provider chain
voicestringen-US-MichelleNeuralEdge voice id
langstringen-USBCP-47 language
outputFormatstringaudio-24khz-48kbitrate-mono-mp3Edge output format string
proxystring-Optional HTTP(S) proxy for Edge

messages.tts.minimax

FieldTypeDefaultDescription
apiKeystring-MiniMax API key (env: MINIMAX_API_KEY)
baseUrlstringhttps://api.minimaxi.com/v1Override base URL
modelstringspeech-2.8-hdModel id (speech-2.8-hd, speech-2.8-turbo, …)
voicestringmale-qn-qingseVoice id
groupIdstring-Forward-compat slot for enterprise tier

messages.tts.tts-local-cli

Provided by the bundled tts-local-cli extension (see extensions/tts-local-cli/xopc.extension.json for the authoritative JSON Schema). Spawns any local TTS binary (mlx-audio, sherpa-onnx-tts, piper, …) via shell template and reads the output file.

FieldTypeDefaultDescription
commandstringrequiredShell command template; supports , , , placeholders (case-insensitive)
argsstring[][]Extra args appended after the parsed command
cwdstring-Working directory for the spawned process
outputFormatenumwavFile extension produced by the CLI: mp3 | opus | wav
timeoutMsnumber120000Hard kill timeout (ms)
envobject-Extra env vars merged into the spawned process env (Record<string,string>)

The Voice settings UI exposes the common fields (command, cwd, outputFormat, timeoutMs); args and env are advanced fields — edit ~/.xopc/xopc.json directly to set them.

messages.tts.fallback

FieldTypeDefaultDescription
enabledbooleantrueTry other providers on failure
orderarray["openai","alibaba","edge","minimax"]Order after deduplicating primary

The fallback list accepts any registered SpeechProviderPlugin id, including extension providers like tts-local-cli.

messages.tts.summarization

FieldTypeDefaultDescription
enabledbooleantrueSummarize long text via LLM before TTS
thresholdnumbersame as maxTextLengthMin length to trigger summarization
targetLengthnumbersame as maxTextLengthTarget length after summarization
modelstring-Model ref for summarization; env XOPC_TTS_SUMMARIZE_MODEL if unset

Trigger modes:

  • off: No automatic TTS on outbound
  • always: TTS when outbound rules pass
  • inbound: TTS only when the user message carried voice (transcribedVoice)
  • tagged: TTS only when assistant text contains [[tts]]

See Voice (STT/TTS) for Telegram group voice + mention behavior, /tts status, and channel formats.


mcp

Outbound MCP server registry (agent consumes external MCP tools).

FieldTypeDefaultDescription
sessionIdleTtlMsnumber600000Per-session MCP runtime idle TTL (10 min); 0 disables eviction
serversobject{}Server id → connection definition (stdio or HTTP)

See MCP for configuration, Web UI, and security notes.


heartbeat

Periodic health check configuration.

FieldTypeDefaultDescription
enabledbooleantrueEnable heartbeat
intervalMsnumber300000Interval in ms (5 min)

cron

Scheduled tasks configuration.

FieldTypeDefaultDescription
enabledbooleantrueEnable cron
jobsarray[]List of cron jobs

See Cron Documentation for job configuration.


extensions

Extension enable/disable configuration.

json
{
  "extensions": {
    "enabled": ["telegram-channel", "weather-tool"],
    "disabled": ["deprecated-extension"],
    "telegram-channel": {
      "token": "bot-token-here"
    },
    "weather-tool": true
  }
}
FieldTypeDescription
enabledstring[]List of extension IDs to enable
disabledstring[](Optional) List of extension IDs to disable
[extension-id]object/booleanExtension-specific configuration

See Extensions Documentation for details.


Environment Variables

xopc supports environment variables for sensitive data:

VariableDescription
OPENAI_API_KEYOpenAI API key
ANTHROPIC_API_KEYAnthropic API key
ANTHROPIC_OAUTH_TOKENAnthropic OAuth token (when used)
GOOGLE_API_KEY / GEMINI_API_KEYGoogle AI (Gemini) API keys
GROQ_API_KEYGroq API key
CEREBRAS_API_KEYCerebras API key
DEEPSEEK_API_KEYDeepSeek API key
MINIMAX_API_KEYMiniMax API key
MOONSHOT_API_KEYMoonshot / Kimi-family keys (see PROVIDER_ENV_MAP for moonshotai* vs kimi-coding)
FIREWORKS_API_KEYFireworks AI
TOGETHER_API_KEYTogether AI
CLOUDFLARE_API_KEYCloudflare Workers AI / AI Gateway
XIAOMI_API_KEYXiaomi MiMo (API billing); token-plan variants use XIAOMI_TOKEN_PLAN_*_API_KEY
AI_GATEWAY_API_KEYVercel AI Gateway (alias VERCEL_AI_GATEWAY_API_KEY)
DASHSCOPE_API_KEYAlibaba DashScope (STT/TTS, image gen)
XOPC_TTS_SUMMARIZE_MODELModel ref for TTS long-text summarization when tts.summarization.model is unset
TELEGRAM_BOT_TOKENTelegram bot token
XOPC_CONFIGCustom config file path
XOPC_WORKSPACECustom workspace directory
XOPC_SESSION_SEARCH_MODELDefault model for session_search summaries when agents.defaults.sessionSearch.summaryModel is unset
XOPC_LOG_LEVELLog level (trace/debug/info/warn/error/fatal)
XOPC_LOG_DIRLog directory path
XOPC_LOG_CONSOLEEnable console output (true/false)
XOPC_LOG_FILEEnable file output (true/false)
XOPC_LOG_RETENTION_DAYSDays to retain log files
XOPC_PRETTY_LOGSPretty print logs for development

Environment variables take priority over config file values.


Configuration Management

Validate Configuration

bash
xopc config validate
# legacy alias:
xopc config --validate

View Configuration

bash
xopc config show
# legacy alias:
xopc config --show

Edit values with xopc config set / xopc config unset, or open xopc config path in your editor.


FAQ

Q: How to use multiple providers?

Use the providers configuration to define multiple API keys. The agent automatically selects the appropriate provider based on the model ID:

json
{
  "providers": {
    "openai": "${OPENAI_API_KEY}",
    "anthropic": "${ANTHROPIC_API_KEY}"
  },
  "agents": {
    "defaults": {
      "model": "anthropic/claude-sonnet-4-5"
    }
  }
}

Q: How to use Ollama (local models)?

Configure custom provider in ~/.xopc/models.json:

json
{
  "providers": {
    "ollama": {
      "baseUrl": "http://localhost:11434/v1",
      "api": "openai-completions",
      "apiKey": "ollama",
      "models": [
        { "id": "llama3.1:8b" }
      ]
    }
  }
}

See Models Documentation for details.

Q: How to configure OAuth?

xopc supports OAuth authentication for certain providers:

Kimi (Device Code Flow):

json
{
  "providers": {
    "kimi": {
      "auth": {
        "type": "oauth",
        "clientId": "your-client-id"
      }
    }
  }
}

Kimi uses Device Code Flow - the CLI will prompt you to visit auth.kimi.com and enter a code.

Q: How to use environment variables?

Use ${VAR_NAME} syntax in config:

json
{
  "providers": {
    "openai": "${OPENAI_API_KEY}",
    "anthropic": "${ANTHROPIC_API_KEY}"
  }
}

Or set environment variables directly without adding to config.

Released under the MIT License.