All clawq configuration lives in a single JSON file at ~/.clawq/config.json (or $CLAWQ_HOME/config.json if the CLAWQ_HOME environment variable is set). This page covers every configuration section, the interactive wizard, programmatic access via the CLI, and environment variables.

Configuration Methods

Interactive Wizard

The recommended way to configure clawq for the first time:

clawq onboard       # full onboarding wizard
clawq config wizard # re-run the wizard any time

The wizard walks through provider, model, security, channels, gateway, and memory settings. When run in a TTY, it launches a full interactive TUI. When piped or redirected, it falls back to generating a starter template.

Channel Setup Wizards

For configuring individual channels, use the dedicated setup wizards:

clawq setup discord     # Discord bot token, guilds, users, intents
clawq setup telegram    # Telegram bot token, allowed users
clawq setup slack       # Slack bot token, app token, signing secret
clawq setup github      # GitHub PAT, repos, webhook paths
clawq setup teams       # MS Teams app credentials
clawq setup tunnel      # Tunnel provider configuration
clawq setup summarizer  # Autosummarizer settings

CLI Set/Get/Show/Tree

Manage individual values by dot-path:

# Set a value
clawq config set providers.openrouter.api_key "sk-..."
clawq config set agent_defaults.primary_model "openrouter:openai/gpt-4o"
clawq config set channels.telegram.accounts.main.bot_token "123:ABC..."

# Read a value
clawq config get providers.openrouter.default_model

# Show full config (secrets redacted)
clawq config show

# Show a specific section
clawq config show security
clawq config show channels

# View config as a tree hierarchy
clawq config tree
clawq config tree gateway
clawq config tree keys         # structure only, no values

In chat channels, use /config menu to interactively browse config sections, /config show <section> to display a section, or /config tree <section> to view the tree hierarchy.

Manual Editing

$EDITOR ~/.clawq/config.json

After editing, validate with:

clawq doctor

Live Reload

When the daemon is running (clawq agent), config changes are picked up automatically — the daemon polls the file every 10 seconds and reloads when it detects a modification. Changes to provider settings, agent defaults, memory limits, heartbeat timing, and security flags take effect without a restart.

You can also force an immediate reload by sending SIGHUP:

kill -HUP $(cat ~/.clawq/daemon_state.json | jq .pid)

Structural changes that affect startup (enabling/disabling channels, changing gateway port/host) still require a daemon restart.

Environment Variables

VariablePurpose
CLAWQ_HOMEOverride the clawq data directory (default: ~/.clawq). All config, database, logs, and state files are stored here. Propagated through daemon restarts.
CLAWQ_MASTER_KEYPassphrase for encrypting/decrypting API keys at rest (AES-256-GCM via PBKDF2)
CLAWQ_UPDATE_BINARY_URLURL for fetching binary updates when clawq update is used. Supports direct binary download or GitHub release URLs.
CLAWQ_TUNNEL_COMMANDFull command to invoke for custom tunnel provider (used when tunnel.provider is "custom")
CLAWQ_TUNNEL_URL_REGEXRegex with a capture group used to extract the public URL from the custom tunnel command’s output
CLAWQ_TUNNEL_URLStatic URL override for Cloudflare quick tunnels when URL extraction is not needed
CLAWQ_DEBUG_HTTPSet to 1 to enable HTTP debug logging (saves all requests/responses to HAR files). Same effect as log.debug_http: true in config.
CLAWQ_RUNNER_TOKENBearer token for remote runner authentication against the gateway’s /mcp and /runner/ask endpoints. Auto-set for background tasks.
CLAWQ_MCP_URLMCP-over-HTTP endpoint URL (e.g. http://127.0.0.1:8080/mcp). Auto-set for background tasks.
CLAWQ_RUNNER_ASK_URLSimple REST endpoint URL for non-MCP runners to ask questions (e.g. http://127.0.0.1:8080/runner/ask). Auto-set for background tasks.
OPENCODEX_API_AUTH_TOKENOpenCodex admission token. Must begin with ocx_; used after an explicit provider api_key and before ~/.opencodex/api-token.

When security.encrypt_secrets is true and CLAWQ_MASTER_KEY is set, API keys are automatically decrypted at runtime. Encrypted values are stored with a $ENC: prefix.

Configuration Sections

providers

An object keyed by provider name. The active provider is selected via agent_defaults.primary_model using the provider:model format.

{
  "providers": {
    "openrouter": {
      "api_key": "sk-or-v1-...",
      "base_url": "https://openrouter.ai/api/v1",
      "default_model": "openai/gpt-4o"
    },
    "openai": {
      "api_key": "sk-...",
      "base_url": "https://api.openai.com/v1",
      "default_model": "gpt-4o"
    }
  }
}
FieldRequiredDescription
api_keyAPI-key providers onlyAPI key (or $ENC:... encrypted value). Subscription/OAuth providers such as openai-codex can authenticate with provider-specific credentials instead.
base_urlNoAPI base URL (defaults to OpenAI)
kindNoProvider kind override (for example openai-codex)
default_modelNoDefault model for this provider. Required for quota-based failover: when another provider is deprioritized, only providers with a default_model are eligible alternatives
thinking_budget_tokensNoProvider reasoning budget when supported
oai_thinking_styleNoOAI-compatible reasoning tag style; defaults to none

OpenCodex LAN proxy

OpenCodex is a multi-provider LAN proxy with a built-in endpoint of http://cachy.lan:10100/v1. Configure the provider explicitly, then select a proxy-routed model with the canonical provider:model format:

{
  "providers": {
    "opencodex": {
      "kind": "opencodex",
      "base_url": "http://cachy.lan:10100/v1",
      "default_model": "gpt-5.4"
    }
  },
  "agent_defaults": {
    "primary_model": "opencodex:gpt-5.4"
  }
}

Clawq resolves a valid token in this order: configured api_key, OPENCODEX_API_AUTH_TOKEN, then ~/.opencodex/api-token. Tokens are trimmed and must start with ocx_; keep the token file at mode 0600. If cachy.lan is unavailable, set base_url to http://10.100.1.2:10100/v1.

OpenCodex always uses the OpenAI Responses API over HTTP at <base_url>/responses, sends the admission token as x-opencodex-api-key, and never uses a websocket transport. The Codex CLI settings wire_api, supports_websockets, env_http_headers, and requires_openai_auth are therefore not Clawq config fields. Run clawq models refresh --provider opencodex to discover the proxy’s current routes, including names such as gpt-* and xai/grok-*. Inference requires the full clawq binary; clawq-min rejects this integration-only provider.

Xiaomi MiMo providers (zero-config)

The Xiaomi MiMo providers are OpenAI-compatible (kind: "xiaomi", oai_thinking_style: "reasoning_content") and have built-in base URLs, so they need no config block: if a key is present in the matching environment variable, the provider is synthesized in memory and never written to config.json.

ProviderBase URLKey env var
xiaomihttps://api.xiaomimimo.com/v1XIAOMI_API_KEY
xiaomi-token-plan-cnhttps://token-plan-cn.xiaomimimo.com/v1XIAOMI_TOKEN_PLAN_CN_API_KEY
xiaomi-token-plan-amshttps://token-plan-ams.xiaomimimo.com/v1XIAOMI_TOKEN_PLAN_AMS_API_KEY
xiaomi-token-plan-sgphttps://token-plan-sgp.xiaomimimo.com/v1XIAOMI_TOKEN_PLAN_SGP_API_KEY (also reads ~/.mimo)

Models: public xiaomi offers mimo-v2-flash, mimo-v2-omni, mimo-v2-pro, mimo-v2.5, mimo-v2.5-pro, and mimo-v2.5-pro-ultraspeed; the token-plan providers offer the same set minus mimo-v2-flash.

default_provider

:::caution[Deprecated] default_provider is deprecated as of B425. The provider is already embedded in agent_defaults.primary_model using the provider:model format (e.g. "openrouter:openai/gpt-4o").

Migration: clawq migrates this field automatically on the next load — no manual edit required. If agent_defaults.primary_model has no provider prefix, the default_provider value is folded into it (e.g. default_provider: "openrouter" + primary_model: "openai/gpt-4o" becomes primary_model: "openrouter:openai/gpt-4o"); otherwise the redundant key is simply dropped. Either way default_provider disappears from config.json and the deprecation warning stops firing. :::

{
  "default_provider": "openrouter"
}

This selects which key from providers is used when a request does not choose a provider explicitly. This field is no longer needed when agent_defaults.primary_model uses the provider:model format.

channels

Channel configurations for Telegram, Discord, Slack, GitHub, and other runtime integrations.

{
  "channels": {
    "telegram": {
      "accounts": {
        "main": {
          "bot_token": "7123456789:AAF1k...",
          "allow_from": ["*"],
          "totp": {
            "enabled": true,
            "secret": "BASE32SECRET",
            "session_ttl_hours": 24
          }
        }
      }
    },
    "discord": {
      "enabled": true,
      "bot_token": "MTIz...",
      "application_id": "123456789"
    },
    "slack": {
      "enabled": true,
      "bot_token": "xoxb-...",
      "app_token": "xapp-...",
      "signing_secret": "abc123..."
    },
    "github": {
      "auth": {
        "type": "pat",
        "token": "ghp_..."
      },
      "repos": [
        {
          "name": "acme/backend",
          "webhook_secret": "super-secret-value",
          "webhook_path": "/github/webhook/backend",
          "allow_users": ["octocat"],
          "react_to": ["issue_comment", "workflow_job"],
          "include_pr_files": true
        }
      ]
    }
  }
}

Telegram fields:

Telegram supports multiple named accounts under channels.telegram.accounts.

FieldDescription
accounts.<name>.bot_tokenBot token from @BotFather
accounts.<name>.allow_fromArray of allowed chat IDs, or ["*"] for all users
accounts.<name>.totp.enabledRequire TOTP pairing for non-allowlisted users
accounts.<name>.totp.secretShared TOTP secret used by clawq otp-show
accounts.<name>.totp.session_ttl_hoursHow long a successful pairing stays valid

Discord fields:

FieldDescription
enabledEnable/disable this channel
bot_tokenBot token from Discord Developer Portal
application_idApplication ID from Discord Developer Portal

Slack fields:

FieldDescription
enabledEnable/disable this channel
bot_tokenBot token (xoxb-...)
app_tokenApp-level token (xapp-...) for Socket Mode
signing_secretSigning secret for Events API HMAC verification

GitHub fields:

FieldDescription
auth.typeAuthentication type, currently pat
auth.tokenGitHub Personal Access Token used for API replies and PR file fetches
repos[].nameRequired canonical owner/repo identity for that webhook path
repos[].webhook_secretShared secret used for GitHub HMAC verification
repos[].webhook_pathInbound webhook path; must be unique across configured repos
repos[].agent_nameOptional named agent override
repos[].allow_usersGitHub usernames allowed for user-generated or arbitrary-content events
repos[].react_toEvent allowlist for that repo path; empty means accept all delivered events
repos[].include_pr_filesFetch changed file lists for supported PR/comment flows

GitHub hook files live under ~/.clawq/workspace/gh-hooks/, and verified payload snapshots are written to ~/.clawq/workspace/tmp/github-deliveries/. See the Channels page for a hook file example and event trust model details.

Channel-specific default model:

Each channel can have its own default model that overrides the global primary_model. This is useful when different channels should use different models (e.g. a cheaper model for high-traffic Telegram chats, a stronger model for Discord).

clawq channel set-model discord anthropic:claude-opus-4-6
clawq channel show-model discord
clawq channel clear-model discord

The model resolution hierarchy (highest to lowest priority):

  1. Per-session model override (clawq session model SESSION set MODEL)
  2. Channel-specific default model (clawq channel set-model NAME MODEL)
  3. Global agent_defaults.primary_model

Native/local subagents resolve models separately: explicit task --model, then the agent template model, then agent_defaults.subagent_default_model, then the parent/global default.

Set agent_defaults.max_concurrent_native_agents to a positive integer to cap how many native/local subagents can run at once. Queued native subagents wait until an existing native subagent finishes; external runner background tasks are not counted against this native-only cap.

All 17 channel types are supported: telegram, discord, slack, github, teams, matrix, mattermost, dingtalk, imessage, signal, irc, email, whatsapp, nostr, lark, line, onebot.

connector_history

Optional capture of unaddressed group-chat messages for connectors that support ambient history capture. Persistent entries are stored with room scope, connector type, and timestamp so cleanup and future history queries can filter by room, connector, and time range. The capture and injection paths are gated by both this configuration and the connector capability matrix. Teams and Discord currently support ambient capture; Slack does not, because Slack messages are already delivered through the normal channel flow and no separate ambient-history capture path is implemented.

{
  "connector_history": {
    "enabled": false,
    "persist_to_db": false,
    "max_messages": 50,
    "max_age_days": 7
  }
}
FieldDescription
enabledEnable/disable capture of unaddressed group messages for capable connectors
persist_to_dbPersist captured history in SQLite instead of relying only on in-memory buffers
max_messagesMaximum retained messages per room/connector history scope (1-128)
max_age_daysRetention window used by DB cleanup when persistence is enabled; entries older than this are deleted

Use /inject_connector_history [N] or the inject_connector_history tool from a Teams or Discord group session to load recent captured messages into context.

security

{
  "security": {
    "workspace_only": true,
    "tools_enabled": true,
    "audit_enabled": true,
    "encrypt_secrets": false,
    "sandbox_backend": "auto",
    "hosted_runner_isolation": "off",
    "rate_limit_rpm": 60,
    "audit_retention_days": 90
  }
}
FieldDefaultDescription
workspace_onlytrueRestrict file operations to workspace directory
tools_enabledtrueEnable agent tool invocations
audit_enabledtrueEnable audit logging of tool invocations and security events
encrypt_secretsfalseEncrypt API keys at rest using CLAWQ_MASTER_KEY
rate_limit_rpm60Requests per minute rate limit
audit_retention_days90Days to retain audit log entries
allowed_cwd_patterns["$CLAWQ_WORKSPACE/**", "$USER_HOME/src/projects-clawq/**", "/clawq/path/to/somewhere/else/**"]Glob patterns for directories agents may change_working_dir into. Supports $CLAWQ_WORKSPACE and $USER_HOME pseudo-variables.
sandbox_backend"auto"Sandbox backend for shell/runner isolation: "auto" (detects firejail > bubblewrap > none), "firejail", "bubblewrap", or "none"
hosted_runner_isolation"off"Isolation for hosted codex/claude background runners: "off", "prefer" (sandbox when a backend is available), "require" (fail closed without one). Applies a minimal allowlisted environment plus an argv-level sandbox. See the hosted-runner-isolation operator doc.

gateway

{
  "gateway": {
    "host": "127.0.0.1",
    "port": 13451,
    "require_pairing": true,
    "auth_token": null,
    "max_pair_attempts": 5,
    "pair_lockout_seconds": 300
  }
}
FieldDefaultDescription
host127.0.0.1Gateway bind address
port13451Gateway port
require_pairingtrueRequire browser/API clients to pair before posting chat requests
auth_tokenunsetStatic bearer token or x-api-key alternative for scripted access
max_pair_attempts5Failed OTP attempts allowed before temporary lockout
pair_lockout_seconds300Lockout duration after too many failed pair attempts

The gateway root / serves the embedded web UI. Supporting endpoints include /chat/stream for SSE chat streaming, /commands for slash-command metadata, /ui-version for reload prompts, and /pair for browser pairing.

memory

{
  "memory": {
    "backend": "sqlite",
    "search_enabled": true,
    "embedding_provider": "openai",
    "embedding_model": "text-embedding-3-small",
    "vector_weight": 50,
    "keyword_weight": 50,
    "ttl_days": 365
  }
}
FieldDefaultDescription
backendsqliteMemory backend type
search_enabledfalseEnable hybrid vector + FTS search
embedding_providerProvider for generating embeddings
embedding_modelModel for generating embeddings
vector_weight50Weight for vector similarity results (must sum to 100 with keyword_weight)
keyword_weight50Weight for keyword FTS results
ttl_days365Days before memory entries expire

When an interactive agent calls memory_forget, Clawq removes the key from active memory and appends a recovery copy to $CLAWQ_HOME/workspace/rooms/<session-slug-hash>/memory_archive.jsonl (or ~/.clawq/workspace/rooms/<session-slug-hash>/memory_archive.jsonl). Each JSONL row records the key, category, content, and UTC time the memory was forgotten.

resilience

{
  "resilience": {
    "timeout_s": 120.0,
    "max_retries": 2,
    "base_delay_s": 1.0,
    "fallback_provider": "groq"
  }
}
FieldDefaultDescription
timeout_s120.0Timeout for LLM API calls in seconds
max_retries2Maximum retry attempts with exponential backoff
base_delay_s1.0Base delay between retries
fallback_providerProvider name to use if primary fails

mcp

{
  "mcp": {
    "enabled": true,
    "exposed_tools": ["file_read", "file_write", "shell_exec"]
  }
}
FieldDefaultDescription
enabledtrueEnable the MCP server (JSON-RPC via stdio)
exposed_toolsallArray of tool names to expose (omit for all)
runner_relay_enabledtrueEnable HTTP endpoints (/mcp, /runner/ask, /runner/token) for remote runner question relay
runner_token_ttl_hours24TTL in hours for runner bearer tokens
runner_question_timeout_s300Timeout in seconds for relayed questions before giving up

mcp_servers (MCP Client)

Connect clawq to external MCP servers to discover and invoke their tools. Configuration is read from a separate file at ~/.clawq/mcp_servers.json (a JSON array of server entries):

[
  {
    "name": "my-server",
    "command": "node",
    "args": ["/path/to/server.js"],
    "env": {
      "MY_VAR": "value"
    }
  },
  {
    "name": "remote-server",
    "url": "http://localhost:3000/mcp",
    "headers": {
      "Authorization": "Bearer mytoken"
    }
  }
]

stdio-based server fields:

FieldDescription
nameUnique identifier for the server
commandExecutable to spawn
argsArray of arguments passed to the command
envObject of extra environment variables injected into the process

HTTP-based server fields:

FieldDescription
nameUnique identifier for the server
urlHTTP or HTTPS URL of the MCP endpoint
headersObject of extra request headers (e.g. Authorization)

Tools discovered from external MCP servers are automatically registered and available to the agent during turns.

tunnel

{
  "tunnel": {
    "provider": "cloudflare",
    "enabled": true,
    "url": "",
    "managed": false,
    "tunnel_name": "",
    "config_dir": ""
  }
}
FieldDefaultDescription
provider"cloudflare"Tunnel provider: cloudflare, tailscale, ngrok, or custom
enabledfalseEnable the tunnel
url""Static URL override (skips dynamic URL extraction)
managedfalseUse a named/managed Cloudflare tunnel (requires tunnel_name)
tunnel_name""Name of the Cloudflare named tunnel (used when managed is true)
config_dir""Path to cloudflared config directory (contains config.yml)

Quick tunnel (ad-hoc): Set enabled: true with default settings. clawq spawns cloudflared tunnel --url http://localhost:PORT and extracts the assigned trycloudflare.com URL automatically.

Named/managed tunnel: Set managed: true and tunnel_name to a pre-existing Cloudflare named tunnel. You must first create the tunnel and DNS routes externally via cloudflared tunnel create and cloudflared tunnel route dns. Set url to the public hostname so clawq knows the URL. Optionally set config_dir if config.yml is not in the default location.

Other providers: Set provider to tailscale, ngrok, or custom. For custom tunnels, set CLAWQ_TUNNEL_COMMAND and optionally CLAWQ_TUNNEL_URL_REGEX environment variables.

interactive

{
  "interactive": {
    "enable_question_notes": true
  }
}

Controls behavior of the ask_user_question tool, which lets the agent ask clarifying questions mid-turn via interactive channels.

FieldDefaultDescription
enable_question_notestrueAfter structured answers (select, confirm, rating, number, date), prompt the user with “Add notes? (reply or ‘skip’)”. Set to false to skip the notes prompt

Live reconfiguration: The daemon watches for tunnel config changes on SIGHUP and via file-change polling (every 10 seconds). When tunnel settings change, the daemon automatically stops the old tunnel and starts a new one — no daemon restart required. Use clawq tunnel apply to trigger reconciliation explicitly, or clawq tunnel restart to force a stop-and-restart even without config changes.

Model Format

The canonical format for model references is provider:model (colon separator). Examples: openai:gpt-5.4, anthropic:claude-sonnet-4-6, groq:llama-4-scout-17b-16e.

Legacy format deprecated

The legacy provider/model (slash) format is still accepted but deprecated and will be removed in a future release.

Deprecation warnings appear:

  • On config load when primary_model uses the legacy format
  • In clawq status output
  • When using config set agent_defaults.primary_model
  • In /model set (prints a format hint)
  • models set-default and /model set-default auto-normalize to canonical format

/model set, /model set-default, and models set-default also accept bare model names when the catalog can resolve them unambiguously. If a bare name matches multiple providers, Clawq rejects the change and prints candidate provider:model values to choose from.

Note: providers.*.default_model is the model identifier as understood by that provider’s API (e.g. openai/gpt-4o on OpenRouter) — this is not subject to the format deprecation.

model_context_limits

{
  "model_context_limits": {
    "openai-codex:gpt-5.4": 272000
  }
}

Optional top-level object mapping model names to manual token limits used for context budgeting and history compaction. Configured entries take precedence over built-in defaults.

heartbeat

{
  "heartbeat": {
    "enabled": true,
    "interval_seconds": 250,
    "quiet_start": 23,
    "quiet_end": 8
  }
}
FieldDefaultDescription
enabledtrueGlobal master switch for heartbeat delivery
interval_seconds250Seconds between heartbeat ticks
quiet_start23Hour (0-23) when quiet period begins
quiet_end8Hour (0-23) when quiet period ends

Per-session opt-in required

Sessions must opt in individually via /heartbeat on or clawq session heartbeat SESSION on. Only Telegram, Slack, Discord, and Teams sessions are valid heartbeat targets.

The daemon reads HEARTBEAT.md from the workspace root on each tick.

error_watcher

{
  "error_watcher": {
    "ec_enabled": false,
    "scan_interval_s": 30.0,
    "cooldown_s": 300.0,
    "max_errors_per_batch": 10,
    "auto_fix_enabled": false
  }
}
FieldDefaultDescription
ec_enabledfalse (true for -dev builds)Enable the error correction watcher
scan_interval_s30.0Seconds between daemon log scans
primary_models["anthropic:claude-opus-4-6", "openai-codex:gpt-5.4"]Models for diagnosis
fallback_models["zai_coding:glm-5", "kimi_coding:kimi-for-code"]Fallback models
cooldown_s300.0Cooldown between EC runs
max_errors_per_batch10Max errors per scan batch
ignore_patterns[]Regex patterns to ignore in logs
auto_fix_enabledfalseAutomatically apply fixes
ec_commit_tag"[INTERNAL_EC]"Git commit tag for EC fixes

Auto-fix is off by default

Set auto_fix_enabled: true only after verifying the watcher behaves correctly in your environment. EC fixes are tagged with ec_commit_tag for easy identification and rollback.

notify

{
  "notify": {
    "notify_channel": "telegram",
    "notify_target": "123456789"
  }
}
FieldDescription
notify_channelChannel type for outbound notifications (e.g. telegram)
notify_targetTarget identifier (e.g. chat ID) for proactive sends

egress

{
  "egress": {
    "strictness": "strict",
    "default_allowlist": [
      {"host": "clawq.org", "path": "/llms.txt", "method": "GET", "action": "allow", "log_policy": "no_log"},
      {"host": "clawq.org", "path": "/llms-full.txt", "method": "GET", "action": "allow", "log_policy": "no_log"}
    ]
  }
}
FieldDefaultDescription
strictness"strict""strict" denies unmatched policy-aware HTTP destinations; "permissive" allows unmatched destinations after explicit rules and the default allowlist are checked
default_allowlistClawq llms.txt and llms-full.txt on clawq.orgFallback egress rules evaluated after access-bundle egress_rules; explicit deny rules in higher-priority scopes still win
default_policyaliasBackward-friendly alias for strictness; "deny" maps to "strict", "allow" maps to "permissive"

Egress policy applies to Clawq’s policy-aware HTTP paths such as web_fetch, web_search, http_get, http_request, HTTP MCP startup/tool calls, and other callers that use the policy HTTP client. Shell command network access is controlled separately by the shell sandbox/workspace policy; egress rules do not claim to firewall arbitrary commands run through bash.

{
  "web_search": {
    "search_provider": "brave",
    "search_api_key": "BSA...",
    "num_results": 5
  }
}
FieldDescription
search_provider"brave" or "ddg" (DuckDuckGo)
search_api_keyAPI key for the search provider
num_resultsNumber of results to return
search_base_urlOptional endpoint override (e.g. for SearXNG)

zai_mcp

{
  "zai_mcp": {
    "enabled": true,
    "websearch_enabled": true,
    "webfetch_enabled": true
  }
}
FieldDefaultDescription
enabledtrue (when section present)Enable Z.ai MCP-powered web tools
api_keyauto-detectedBearer token; auto-detected from providers.zai or providers.zai_coding if absent
websearch_enabledtrueRegister zai_websearch tool
webfetch_enabledtrueRegister zai_webfetch tool

voice

{
  "voice": {
    "stt_enabled": true,
    "tts_enabled": false,
    "stt_provider": "openai",
    "tts_provider": "openai",
    "tts_model": "tts-1",
    "tts_voice": "alloy",
    "audio_dir": ""
  }
}
FieldDescription
stt_enabledEnable speech-to-text
tts_enabledEnable text-to-speech
stt_providerSTT provider name
tts_providerTTS provider name
tts_modelTTS model identifier
tts_voiceVoice selection
audio_dirDirectory for audio file storage

When an stt provider is configured (separate from the voice section), voice messages and audio attachments sent to any channel are automatically transcribed with progress messages (“Transcribing…” → “Transcribing… Done!”). Validation limits are hardcoded: max 25 MB file size, max 1 hour duration, and music files (.mp3, .m4a, .flac, .aac, .wma) are skipped unless the filename contains “voice”, “recording”, or “audio_message”.

web_channel

{
  "web_channel": {
    "enabled": true,
    "path_prefix": "/web",
    "token_ttl_hours": 24
  }
}
FieldDefaultDescription
enabledEnable the web channel routes
path_prefix"/web"URL path prefix for web channel endpoints
totp_secretOptional TOTP secret for web channel auth
token_ttl_hours24Token validity period in hours

telemetry

{
  "telemetry": {
    "enabled": false,
    "endpoint": "",
    "service_name": "clawq"
  }
}
FieldDescription
enabledEnable telemetry reporting
endpointTelemetry collection endpoint URL
service_nameService name for telemetry tags

agent_bindings

An array of routing rules that dispatch incoming messages to named agent configurations by matching against a user or channel identifier.

{
  "agent_bindings": [
    {
      "pattern": "user:123456789",
      "agent_name": "coder",
      "priority": 10
    },
    {
      "pattern": "channel:987654321",
      "agent_name": "ops",
      "priority": 5
    },
    {
      "pattern": "default",
      "agent_name": "default",
      "priority": 0
    }
  ]
}
FieldRequiredDescription
patternYesMatch target. Use user:<id> to match a sender, channel:<id> to match a channel, guild:<id> to match a Discord server, or default to match all unmatched messages
agent_nameYesNamed agent configuration to route to
priorityNoInteger priority; higher values are evaluated first. Defaults to 0

Bindings are evaluated in priority order (highest first). The first matching pattern wins. The default pattern serves as a catch-all when no other binding matches.

log

{
  "log": {
    "max_size_mb": 10,
    "max_files": 5,
    "debug_http": false
  }
}
FieldDefaultDescription
max_size_mb10Maximum daemon log file size before rotation
max_files5Number of historical log files to retain
debug_httpfalseSave all HTTP requests/responses to HAR files in ~/.clawq/log-http-debug/. Also activatable via CLAWQ_DEBUG_HTTP=1 env var

observer

{
  "observer": {
    "enabled": true,
    "check_every_n_messages": 5
  }
}
FieldDefaultDescription
enabledtrueEnable turn observer for stuck/looping detection
model"groq:openai/gpt-oss-120b"Model for observer analysis
check_every_n_messages5Check frequency
round1_window8Recent messages to analyze in round 1
round2_window30Extended window for round 2 analysis
thinking_token_threshold5000Thinking token threshold
consecutive_errors_threshold3Error count before intervention
repeat_call_threshold2Repeated tool call threshold

summarizer

{
  "summarizer": {
    "enabled": true,
    "threshold_chars": 1500
  }
}
FieldDefaultDescription
enabledtrueEnable autosummarizer for long tool output
model"groq:openai/gpt-oss-120b"Model for summarization
escalation_modelOptional stronger model for escalation
threshold_chars1500Character threshold to trigger summarization
p1_max_chars200000Max chars for phase 1
p2_max_chars12000Max chars for phase 2
context_window_messages4Messages of context to include
excluded_tools["tool_search", ...]Tools exempt from summarization
max_age_days30Days before summaries expire

Workspace Files

The workspace directory (~/.clawq/workspace/ by default, or $CLAWQ_HOME/workspace/) contains Markdown files that are read at the start of each agent turn and included in the system prompt context.

Per-session workspace subdirectories may also contain runtime artifacts. Forgotten memories are archived to memory_archive.jsonl in the invoking session’s workspace subdirectory so mistakenly removed memories can be recovered later.

FilePurpose
EGO.mdAgent identity and core principles. Takes highest precedence when instructions conflict.
AGENTS.mdOperating protocol and routing instructions. Read on every turn.
SOUL.mdExtended personality and behavioral guidelines.
TOOLS.mdAgent-specific tool notes and usage guidance.
IDENTITY.mdOptional supplementary identity context.
USER.mdUser profile, preferences, and working style.
HEARTBEAT.mdInstructions read and executed on each heartbeat tick.
MEMORY.mdCurated long-term memory. Loaded only in direct, private sessions.

These files are created with sensible defaults by clawq workspace init. Edit them to customize agent behavior without changing config.json. The workspace_only security setting restricts file tool operations to this directory.

Full Example

{
  "providers": {
    "openrouter": {
      "api_key": "sk-or-v1-...",
      "base_url": "https://openrouter.ai/api/v1",
      "default_model": "openai/gpt-4o"
    }
  },
  "channels": {
    "telegram": {
      "accounts": {
        "main": {
          "bot_token": "7123456789:AAF1k...",
          "allow_from": ["*"]
        }
      }
    }
  },
  "security": {
    "workspace_only": true,
    "tools_enabled": true,
    "audit_enabled": true,
    "encrypt_secrets": false
  },
  "gateway": {
    "host": "127.0.0.1",
    "port": 13451,
    "require_pairing": true
  },
  "memory": {
    "backend": "sqlite",
    "search_enabled": false
  },
  "resilience": {
    "timeout_s": 120.0,
    "max_retries": 2
  },
  "tunnel": {
    "provider": "cloudflare",
    "enabled": false
  }
}

Secret Encryption

To encrypt API keys at rest:

  1. Set security.encrypt_secrets to true
  2. Set the CLAWQ_MASTER_KEY environment variable with a strong passphrase
  3. Run clawq auth encrypt to encrypt all plaintext API keys
  4. Keys are stored as $ENC:... values and automatically decrypted at runtime