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
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:gpt-5.4"
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
In chat channels, use /config menu to interactively browse config sections, or /config show <section> directly.
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
| Variable | Purpose |
|---|---|
CLAWQ_HOME | Override the clawq data directory (default: ~/.clawq). All config, database, logs, and state files are stored here. Propagated through daemon restarts. |
CLAWQ_MASTER_KEY | Passphrase for encrypting/decrypting API keys at rest (AES-256-GCM via PBKDF2) |
CLAWQ_UPDATE_BINARY_URL | URL for fetching binary updates when clawq update is used. Supports direct binary download or GitHub release URLs. |
CLAWQ_TUNNEL_COMMAND | Full command to invoke for custom tunnel provider (used when tunnel.provider is "custom") |
CLAWQ_TUNNEL_URL_REGEX | Regex with a capture group used to extract the public URL from the custom tunnel command’s output |
CLAWQ_TUNNEL_URL | Static URL override for Cloudflare quick tunnels when URL extraction is not needed |
CLAWQ_DEBUG_HTTP | Set 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_TOKEN | Bearer token for remote runner authentication against the gateway’s /mcp and /runner/ask endpoints. Auto-set for background tasks. |
CLAWQ_MCP_URL | MCP-over-HTTP endpoint URL (e.g. http://127.0.0.1:8080/mcp). Auto-set for background tasks. |
CLAWQ_RUNNER_ASK_URL | Simple 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. |
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"
}
}
}
| Field | Required | Description |
|---|---|---|
api_key | Yes | API key (or $ENC:... encrypted value) |
base_url | No | API base URL (defaults to OpenAI) |
kind | No | Provider kind override (for example openai-codex) |
default_model | No | Default 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_tokens | No | Provider reasoning budget when supported |
oai_thinking_style | No | OAI-compatible reasoning tag style; defaults to none |
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:gpt-5.4").
Migration: remove default_provider from your config.json and ensure
agent_defaults.primary_model is set to a canonical provider:model string.
clawq will warn at startup if this field is still present.
:::
{
"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.
| Field | Description |
|---|---|
accounts.<name>.bot_token | Bot token from @BotFather |
accounts.<name>.allow_from | Array of allowed chat IDs, or ["*"] for all users |
accounts.<name>.totp.enabled | Require TOTP pairing for non-allowlisted users |
accounts.<name>.totp.secret | Shared TOTP secret used by clawq otp-show |
accounts.<name>.totp.session_ttl_hours | How long a successful pairing stays valid |
Discord fields:
| Field | Description |
|---|---|
enabled | Enable/disable this channel |
bot_token | Bot token from Discord Developer Portal |
application_id | Application ID from Discord Developer Portal |
Slack fields:
| Field | Description |
|---|---|
enabled | Enable/disable this channel |
bot_token | Bot token (xoxb-...) |
app_token | App-level token (xapp-...) for Socket Mode |
signing_secret | Signing secret for Events API HMAC verification |
GitHub fields:
| Field | Description |
|---|---|
auth.type | Authentication type, currently pat |
auth.token | GitHub Personal Access Token used for API replies and PR file fetches |
repos[].name | Required canonical owner/repo identity for that webhook path |
repos[].webhook_secret | Shared secret used for GitHub HMAC verification |
repos[].webhook_path | Inbound webhook path; must be unique across configured repos |
repos[].agent_name | Optional named agent override |
repos[].allow_users | GitHub usernames allowed for user-generated or arbitrary-content events |
repos[].react_to | Event allowlist for that repo path; empty means accept all delivered events |
repos[].include_pr_files | Fetch 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):
- Per-session model override (
clawq session model SESSION set MODEL) - Channel-specific default model (
clawq channel set-model NAME MODEL) - Global
agent_defaults.primary_model
All 17 channel types are supported: telegram, discord, slack, github, teams, matrix, mattermost, dingtalk, imessage, signal, irc, email, whatsapp, nostr, lark, line, onebot.
security
{
"security": {
"workspace_only": true,
"tools_enabled": true,
"audit_enabled": true,
"encrypt_secrets": false,
"rate_limit_rpm": 60,
"audit_retention_days": 90
}
}
| Field | Default | Description |
|---|---|---|
workspace_only | true | Restrict file operations to workspace directory |
tools_enabled | true | Enable agent tool invocations |
audit_enabled | true | Enable audit logging of tool invocations and security events |
encrypt_secrets | false | Encrypt API keys at rest using CLAWQ_MASTER_KEY |
rate_limit_rpm | 60 | Requests per minute rate limit |
audit_retention_days | 90 | Days 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. |
gateway
{
"gateway": {
"host": "127.0.0.1",
"port": 13451,
"require_pairing": true,
"auth_token": null,
"max_pair_attempts": 5,
"pair_lockout_seconds": 300
}
}
| Field | Default | Description |
|---|---|---|
host | 127.0.0.1 | Gateway bind address |
port | 13451 | Gateway port |
require_pairing | true | Require browser/API clients to pair before posting chat requests |
auth_token | unset | Static bearer token or x-api-key alternative for scripted access |
max_pair_attempts | 5 | Failed OTP attempts allowed before temporary lockout |
pair_lockout_seconds | 300 | Lockout 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
}
}
| Field | Default | Description |
|---|---|---|
backend | sqlite | Memory backend type |
search_enabled | false | Enable hybrid vector + FTS search |
embedding_provider | — | Provider for generating embeddings |
embedding_model | — | Model for generating embeddings |
vector_weight | 50 | Weight for vector similarity results (must sum to 100 with keyword_weight) |
keyword_weight | 50 | Weight for keyword FTS results |
ttl_days | 365 | Days before memory entries expire |
resilience
{
"resilience": {
"timeout_s": 120.0,
"max_retries": 2,
"base_delay_s": 1.0,
"fallback_provider": "groq"
}
}
| Field | Default | Description |
|---|---|---|
timeout_s | 120.0 | Timeout for LLM API calls in seconds |
max_retries | 2 | Maximum retry attempts with exponential backoff |
base_delay_s | 1.0 | Base delay between retries |
fallback_provider | — | Provider name to use if primary fails |
mcp
{
"mcp": {
"enabled": true,
"exposed_tools": ["file_read", "file_write", "shell_exec"]
}
}
| Field | Default | Description |
|---|---|---|
enabled | true | Enable the MCP server (JSON-RPC via stdio) |
exposed_tools | all | Array of tool names to expose (omit for all) |
runner_relay_enabled | true | Enable HTTP endpoints (/mcp, /runner/ask, /runner/token) for remote runner question relay |
runner_token_ttl_hours | 24 | TTL in hours for runner bearer tokens |
runner_question_timeout_s | 300 | Timeout 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:
| Field | Description |
|---|---|
name | Unique identifier for the server |
command | Executable to spawn |
args | Array of arguments passed to the command |
env | Object of extra environment variables injected into the process |
HTTP-based server fields:
| Field | Description |
|---|---|
name | Unique identifier for the server |
url | HTTP or HTTPS URL of the MCP endpoint |
headers | Object 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": ""
}
}
| Field | Default | Description |
|---|---|---|
provider | "cloudflare" | Tunnel provider: cloudflare, tailscale, ngrok, or custom |
enabled | false | Enable the tunnel |
url | "" | Static URL override (skips dynamic URL extraction) |
managed | false | Use 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.
| Field | Default | Description |
|---|---|---|
enable_question_notes | true | After 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_modeluses the legacy format - In
clawq statusoutput - When using
config set agent_defaults.primary_model - In
/model set(prints a format hint) models set-defaultand/model set-defaultauto-normalize to canonical format
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
}
}
| Field | Default | Description |
|---|---|---|
enabled | true | Global master switch for heartbeat delivery |
interval_seconds | 250 | Seconds between heartbeat ticks |
quiet_start | 23 | Hour (0-23) when quiet period begins |
quiet_end | 8 | Hour (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
}
}
| Field | Default | Description |
|---|---|---|
ec_enabled | false (true for -dev builds) | Enable the error correction watcher |
scan_interval_s | 30.0 | Seconds 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_s | 300.0 | Cooldown between EC runs |
max_errors_per_batch | 10 | Max errors per scan batch |
ignore_patterns | [] | Regex patterns to ignore in logs |
auto_fix_enabled | false | Automatically 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"
}
}
| Field | Description |
|---|---|
notify_channel | Channel type for outbound notifications (e.g. telegram) |
notify_target | Target identifier (e.g. chat ID) for proactive sends |
web_search
{
"web_search": {
"search_provider": "brave",
"search_api_key": "BSA...",
"num_results": 5
}
}
| Field | Description |
|---|---|
search_provider | "brave" or "ddg" (DuckDuckGo) |
search_api_key | API key for the search provider |
num_results | Number of results to return |
search_base_url | Optional endpoint override (e.g. for SearXNG) |
zai_mcp
{
"zai_mcp": {
"enabled": true,
"websearch_enabled": true,
"webfetch_enabled": true
}
}
| Field | Default | Description |
|---|---|---|
enabled | true (when section present) | Enable Z.ai MCP-powered web tools |
api_key | auto-detected | Bearer token; auto-detected from providers.zai or providers.zai_coding if absent |
websearch_enabled | true | Register zai_websearch tool |
webfetch_enabled | true | Register 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": ""
}
}
| Field | Description |
|---|---|
stt_enabled | Enable speech-to-text |
tts_enabled | Enable text-to-speech |
stt_provider | STT provider name |
tts_provider | TTS provider name |
tts_model | TTS model identifier |
tts_voice | Voice selection |
audio_dir | Directory 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
}
}
| Field | Default | Description |
|---|---|---|
enabled | — | Enable the web channel routes |
path_prefix | "/web" | URL path prefix for web channel endpoints |
totp_secret | — | Optional TOTP secret for web channel auth |
token_ttl_hours | 24 | Token validity period in hours |
telemetry
{
"telemetry": {
"enabled": false,
"endpoint": "",
"service_name": "clawq"
}
}
| Field | Description |
|---|---|
enabled | Enable telemetry reporting |
endpoint | Telemetry collection endpoint URL |
service_name | Service 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
}
]
}
| Field | Required | Description |
|---|---|---|
pattern | Yes | Match 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_name | Yes | Named agent configuration to route to |
priority | No | Integer 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
}
}
| Field | Default | Description |
|---|---|---|
max_size_mb | 10 | Maximum daemon log file size before rotation |
max_files | 5 | Number of historical log files to retain |
debug_http | false | Save 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
}
}
| Field | Default | Description |
|---|---|---|
enabled | true | Enable turn observer for stuck/looping detection |
model | "groq:openai/gpt-oss-120b" | Model for observer analysis |
check_every_n_messages | 5 | Check frequency |
round1_window | 8 | Recent messages to analyze in round 1 |
round2_window | 30 | Extended window for round 2 analysis |
thinking_token_threshold | 5000 | Thinking token threshold |
consecutive_errors_threshold | 3 | Error count before intervention |
repeat_call_threshold | 2 | Repeated tool call threshold |
summarizer
{
"summarizer": {
"enabled": true,
"threshold_chars": 1500
}
}
| Field | Default | Description |
|---|---|---|
enabled | true | Enable autosummarizer for long tool output |
model | "groq:openai/gpt-oss-120b" | Model for summarization |
escalation_model | — | Optional stronger model for escalation |
threshold_chars | 1500 | Character threshold to trigger summarization |
p1_max_chars | 200000 | Max chars for phase 1 |
p2_max_chars | 12000 | Max chars for phase 2 |
context_window_messages | 4 | Messages of context to include |
excluded_tools | ["tool_search", ...] | Tools exempt from summarization |
max_age_days | 30 | Days 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.
| File | Purpose |
|---|---|
EGO.md | Agent identity and core principles. Takes highest precedence when instructions conflict. |
AGENTS.md | Operating protocol and routing instructions. Read on every turn. |
SOUL.md | Extended personality and behavioral guidelines. |
TOOLS.md | Agent-specific tool notes and usage guidance. |
IDENTITY.md | Optional supplementary identity context. |
USER.md | User profile, preferences, and working style. |
HEARTBEAT.md | Instructions read and executed on each heartbeat tick. |
MEMORY.md | Curated 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:
- Set
security.encrypt_secretstotrue - Set the
CLAWQ_MASTER_KEYenvironment variable with a strong passphrase - Run
clawq auth encryptto encrypt all plaintext API keys - Keys are stored as
$ENC:...values and automatically decrypted at runtime