-
Notifications
You must be signed in to change notification settings - Fork 3.6k
04.1 Configuration File Reference
Relevant source files
The following files were used as context for generating this wiki page:
This page provides a complete reference for all configuration options available in config.toml. For initial setup instructions, see Onboarding Wizard. For environment variable overrides, see Environment Variables. For secret encryption, see Secret Management.
ZeroClaw uses a TOML configuration file located at ~/.zeroclaw/config.toml by default. The workspace directory is ~/.zeroclaw/workspace.
Configuration Priority (highest to lowest):
- Environment Variables - Override config.toml settings
- config.toml - User-defined configuration
- Built-in Defaults - Fallback values defined in code
Multi-Workspace Support:
Use ZEROCLAW_WORKSPACE environment variable or active_workspace.toml marker file to specify alternate workspace directories. See Workspace Management for details.
Sources: src/config/schema.rs:46-144
The following diagram maps configuration sections to their Rust struct definitions:
graph TB
ConfigFile["config.toml"]
ConfigFile --> TopLevel["Top-Level Fields"]
ConfigFile --> Provider["Provider Settings"]
ConfigFile --> Channels["channels_config"]
ConfigFile --> Agent["agent"]
ConfigFile --> Memory["memory"]
ConfigFile --> Tools["Tool Configs"]
ConfigFile --> Security["Security Configs"]
ConfigFile --> Automation["Automation Configs"]
ConfigFile --> Advanced["Advanced Configs"]
TopLevel --> api_key["api_key: Option<String>"]
TopLevel --> api_url["api_url: Option<String>"]
TopLevel --> default_provider["default_provider: Option<String>"]
TopLevel --> default_model["default_model: Option<String>"]
TopLevel --> default_temperature["default_temperature: f64"]
Provider --> reliability["reliability: ReliabilityConfig"]
Provider --> model_routes["model_routes: Vec<ModelRouteConfig>"]
Provider --> query_classification["query_classification: QueryClassificationConfig"]
Channels --> telegram["telegram: Option<TelegramConfig>"]
Channels --> discord["discord: Option<DiscordConfig>"]
Channels --> slack["slack: Option<SlackConfig>"]
Channels --> matrix["matrix: Option<MatrixConfig>"]
Channels --> email["email: Option<EmailConfig>"]
Channels --> whatsapp["whatsapp: Option<WhatsAppConfig>"]
Channels --> lark["lark: Option<LarkConfig>"]
Channels --> ChannelsEtc["+ 6 more channels"]
Agent --> compact_context["compact_context: bool"]
Agent --> max_tool_iterations["max_tool_iterations: usize"]
Agent --> max_history_messages["max_history_messages: usize"]
Agent --> parallel_tools["parallel_tools: bool"]
Memory --> backend["backend: String"]
Memory --> auto_save["auto_save: bool"]
Memory --> hygiene_enabled["hygiene_enabled: bool"]
Memory --> embedding_provider["embedding_provider: String"]
Tools --> browser["browser: BrowserConfig"]
Tools --> http_request["http_request: HttpRequestConfig"]
Tools --> web_search["web_search: WebSearchConfig"]
Tools --> composio["composio: ComposioConfig"]
Security --> autonomy["autonomy: AutonomyConfig"]
Security --> secrets["secrets: SecretsConfig"]
Security --> gateway["gateway: GatewayConfig"]
Security --> tunnel["tunnel: TunnelConfig"]
Automation --> cron["cron: CronConfig"]
Automation --> scheduler["scheduler: SchedulerConfig"]
Automation --> heartbeat["heartbeat: HeartbeatConfig"]
Advanced --> proxy["proxy: ProxyConfig"]
Advanced --> identity["identity: IdentityConfig"]
Advanced --> cost["cost: CostConfig"]
Advanced --> hardware["hardware: HardwareConfig"]
Advanced --> peripherals["peripherals: PeripheralsConfig"]
Advanced --> agents["agents: HashMap<String, DelegateAgentConfig>"]
Sources: src/config/schema.rs:48-144
# Provider API key (can be overridden by provider-specific env vars)
api_key = "sk-..."
# Optional: Base URL override for provider API (e.g., remote Ollama)
api_url = "http://10.0.0.1:11434"
# Default provider name (openrouter, anthropic, openai, ollama, etc.)
default_provider = "openrouter"
# Default model identifier
default_model = "anthropic/claude-sonnet-4.6"
# Default temperature (0.0-1.0)
default_temperature = 0.7| Field | Type | Default | Description |
|---|---|---|---|
api_key |
Option<String> |
None |
Provider API key (encrypted when secrets.encrypt = true) |
api_url |
Option<String> |
None |
Base URL override for provider API endpoint |
default_provider |
Option<String> |
Required | Provider name (see Built-in Providers) |
default_model |
Option<String> |
Required | Model identifier for the provider |
default_temperature |
f64 |
0.7 |
Sampling temperature (0.0 = deterministic, 1.0 = creative) |
Environment Variable Overrides:
-
OPENROUTER_API_KEY,ANTHROPIC_API_KEY,OPENAI_API_KEY, etc. overrideapi_keyfor specific providers -
OLLAMA_BASE_URLoverridesapi_urlfor Ollama provider
Sources: src/config/schema.rs:56-61
[reliability]
max_retries = 3
initial_retry_delay_ms = 1000
max_retry_delay_ms = 60000
retry_multiplier = 2.0
retry_on_rate_limit = true
fallback_models = []
api_keys_rotation = []| Field | Type | Default | Description |
|---|---|---|---|
max_retries |
u32 |
3 |
Maximum retry attempts for failed requests |
initial_retry_delay_ms |
u64 |
1000 |
Initial backoff delay in milliseconds |
max_retry_delay_ms |
u64 |
60000 |
Maximum backoff delay (exponential backoff cap) |
retry_multiplier |
f64 |
2.0 |
Backoff multiplier for each retry |
retry_on_rate_limit |
bool |
true |
Retry on HTTP 429 rate limit errors |
fallback_models |
Vec<String> |
[] |
Models to try if primary model fails |
api_keys_rotation |
Vec<String> |
[] |
API keys to rotate through on failure |
Sources: src/config/schema.rs:73
[[model_routes]]
hint = "code-heavy"
provider = "openai"
model = "gpt-4o"
weight = 1.0| Field | Type | Description |
|---|---|---|
hint |
String |
Routing hint identifier (e.g., "code-heavy", "fast", "reasoning") |
provider |
String |
Provider to route to |
model |
String |
Model to use for this hint |
weight |
f64 |
Weight for load balancing (not currently used) |
Sources: src/config/schema.rs:82-83
[query_classification]
enabled = false
rules = [
{ patterns = ["debug", "fix bug"], hint = "code-heavy" }
]| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable automatic query classification |
rules |
Vec<ClassificationRule> |
[] |
Pattern-to-hint mapping rules |
ClassificationRule Structure:
| Field | Type | Description |
|---|---|---|
patterns |
Vec<String> |
Keywords/phrases to match in user message |
hint |
String |
Model route hint to apply on match |
Sources: src/config/schema.rs:87
All channel configurations are nested under [channels_config]. Each channel is optional and can be enabled by providing its configuration.
graph LR
ChannelsConfig["ChannelsConfig"]
ChannelsConfig --> Telegram["telegram: TelegramConfig"]
ChannelsConfig --> Discord["discord: DiscordConfig"]
ChannelsConfig --> Slack["slack: SlackConfig"]
ChannelsConfig --> Matrix["matrix: MatrixConfig"]
ChannelsConfig --> Email["email: EmailConfig"]
ChannelsConfig --> WhatsApp["whatsapp: WhatsAppConfig"]
ChannelsConfig --> Lark["lark: LarkConfig"]
ChannelsConfig --> Mattermost["mattermost: MattermostConfig"]
ChannelsConfig --> IMessage["imessage: IMessageConfig"]
ChannelsConfig --> IRC["irc: IrcConfig"]
ChannelsConfig --> DingTalk["dingtalk: DingTalkConfig"]
ChannelsConfig --> QQ["qq: QQConfig"]
ChannelsConfig --> Signal["signal: SignalConfig"]
Telegram --> TGFields["bot_token: String<br/>allowed_users: Vec<String><br/>stream_mode: StreamMode<br/>mention_only: bool"]
Discord --> DCFields["bot_token: String<br/>guild_id: Option<String><br/>allowed_users: Vec<String><br/>mention_only: bool"]
Slack --> SLFields["bot_token: String<br/>app_token: Option<String><br/>allowed_users: Vec<String>"]
Sources: src/config/schema.rs:96, src/channels/mod.rs:1-31
[channels_config.telegram]
bot_token = "123456789:ABC..."
allowed_users = ["alice", "bob"]
stream_mode = "draft" # "none" | "draft" | "chunk"
draft_update_interval_ms = 1000
mention_only = false| Field | Type | Default | Description |
|---|---|---|---|
bot_token |
String |
Required | Telegram Bot API token from @BotFather |
allowed_users |
Vec<String> |
[] |
Allowed Telegram usernames (deny-by-default) |
stream_mode |
StreamMode |
"draft" |
Streaming mode for responses |
draft_update_interval_ms |
u64 |
1000 |
Milliseconds between draft message updates |
mention_only |
bool |
false |
Only respond when bot is mentioned |
StreamMode Options:
-
"none"- No streaming (wait for complete response) -
"draft"- Update draft message as response arrives -
"chunk"- Send multiple messages as chunks arrive
Sources: src/config/mod.rs:15
[channels_config.discord]
bot_token = "MTAxNjc..."
guild_id = "123456789"
allowed_users = ["user#1234"]
listen_to_bots = false
mention_only = true| Field | Type | Default | Description |
|---|---|---|---|
bot_token |
String |
Required | Discord bot token |
guild_id |
Option<String> |
None |
Optional guild/server ID to restrict to |
allowed_users |
Vec<String> |
[] |
Allowed Discord user IDs or discriminators |
listen_to_bots |
bool |
false |
Whether to respond to other bots |
mention_only |
bool |
false |
Only respond when bot is @mentioned |
Sources: src/config/mod.rs:15
[channels_config.slack]
bot_token = "xoxb-..."
app_token = "xapp-..." # Required for Socket Mode
allowed_users = ["U12345"]| Field | Type | Description |
|---|---|---|
bot_token |
String |
Slack Bot User OAuth Token |
app_token |
Option<String> |
App-level token for Socket Mode |
allowed_users |
Vec<String> |
Allowed Slack user IDs |
Sources: src/config/mod.rs:15
[channels_config.matrix]
homeserver_url = "https://matrix.org"
username = "@bot:matrix.org"
password = "..."
allowed_users = ["@alice:matrix.org"]| Field | Type | Description |
|---|---|---|
homeserver_url |
String |
Matrix homeserver URL |
username |
String |
Bot Matrix ID |
password |
String |
Bot password |
allowed_users |
Vec<String> |
Allowed Matrix user IDs |
Sources: src/config/mod.rs:15
[channels_config.email]
imap_server = "imap.gmail.com"
imap_port = 993
smtp_server = "smtp.gmail.com"
smtp_port = 587
username = "bot@example.com"
password = "..."
allowed_senders = ["alice@example.com"]| Field | Type | Default | Description |
|---|---|---|---|
imap_server |
String |
Required | IMAP server hostname |
imap_port |
u16 |
993 |
IMAP port (typically 993 for SSL) |
smtp_server |
String |
Required | SMTP server hostname |
smtp_port |
u16 |
587 |
SMTP port (typically 587 for STARTTLS) |
username |
String |
Required | Email account username |
password |
String |
Required | Email account password |
allowed_senders |
Vec<String> |
[] |
Allowed sender email addresses |
Sources: src/channels/mod.rs:4-5
[channels_config.whatsapp]
api_key = "EAABsb..."
phone_number_id = "1234567890"
webhook_verify_token = "random_secret"
allowed_numbers = ["+1234567890"]| Field | Type | Description |
|---|---|---|
api_key |
String |
Meta WhatsApp API access token |
phone_number_id |
String |
WhatsApp Business phone number ID |
webhook_verify_token |
String |
Verification token for webhook setup |
allowed_numbers |
Vec<String> |
Allowed phone numbers in E.164 format |
Sources: src/config/schema.rs:1, src/channels/mod.rs:15
[channels_config.lark]
app_id = "cli_..."
app_secret = "..."
encrypt_key = "..." # Optional
verification_token = "..." # Optional
allowed_users = ["ou_123"]
use_feishu = false # true for Feishu (China), false for Lark (International)
receive_mode = "websocket" # "websocket" | "webhook"
port = 3001 # Only for webhook mode| Field | Type | Default | Description |
|---|---|---|---|
app_id |
String |
Required | Lark/Feishu app ID |
app_secret |
String |
Required | Lark/Feishu app secret |
encrypt_key |
Option<String> |
None |
Optional encryption key for webhook |
verification_token |
Option<String> |
None |
Optional verification token for webhook |
allowed_users |
Vec<String> |
[] |
Allowed user IDs |
use_feishu |
bool |
false |
Use Feishu (China) endpoints instead of Lark |
receive_mode |
LarkReceiveMode |
"websocket" |
Message receive mode |
port |
Option<u16> |
None |
Port for webhook mode |
Sources: src/config/mod.rs:15
Mattermost, iMessage, IRC, DingTalk, QQ, Signal - Each follows similar patterns with channel-specific authentication and allowlist fields. See Channel Implementations for complete details.
Sources: src/channels/mod.rs:1-31
[agent]
compact_context = false
max_tool_iterations = 10
max_history_messages = 50
parallel_tools = false
tool_dispatcher = "auto" # "auto" | "native" | "prompt"| Field | Type | Default | Description |
|---|---|---|---|
compact_context |
bool |
false |
Use reduced context for 13B or smaller models |
max_tool_iterations |
usize |
10 |
Maximum tool call loop iterations |
max_history_messages |
usize |
50 |
Maximum conversation history size |
parallel_tools |
bool |
false |
Execute multiple tool calls in parallel |
tool_dispatcher |
String |
"auto" |
Tool dispatch strategy |
Tool Dispatcher Modes:
-
"auto"- Use provider's native function calling if available, else prompt-guided -
"native"- Force native function calling (fails if unsupported) -
"prompt"- Force prompt-guided tool calling (works with any model)
Sources: src/config/schema.rs:243-280
[memory]
backend = "sqlite" # "sqlite" | "postgres" | "lucid" | "markdown" | "none"
auto_save = true
hygiene_enabled = true
archive_after_days = 7
purge_after_days = 30
conversation_retention_days = 30
# Embedding configuration for vector search
embedding_provider = "openai" # "openai" | "ollama" | "none"
embedding_model = "text-embedding-3-small"
embedding_dimensions = 1536
vector_weight = 0.7
keyword_weight = 0.3
min_relevance_score = 0.4
embedding_cache_size = 10000
chunk_max_tokens = 512
# Response caching
response_cache_enabled = false
response_cache_ttl_minutes = 60
response_cache_max_entries = 5000
# Memory snapshots
snapshot_enabled = false
snapshot_on_hygiene = false
auto_hydrate = true
# SQLite tuning
sqlite_open_timeout_secs = 5| Field | Type | Default | Description |
|---|---|---|---|
backend |
String |
"sqlite" |
Memory backend implementation |
auto_save |
bool |
true |
Automatically save conversations to memory |
hygiene_enabled |
bool |
true |
Enable automatic cleanup of old entries |
archive_after_days |
u32 |
7 |
Days before archiving old entries |
purge_after_days |
u32 |
30 |
Days before permanently deleting entries |
conversation_retention_days |
u32 |
30 |
Days to retain conversation history |
embedding_provider |
String |
"none" |
Provider for generating embeddings |
embedding_model |
String |
"text-embedding-3-small" |
Model for embeddings |
embedding_dimensions |
usize |
1536 |
Embedding vector dimensions |
vector_weight |
f64 |
0.7 |
Weight for vector similarity in hybrid search |
keyword_weight |
f64 |
0.3 |
Weight for keyword matching in hybrid search |
min_relevance_score |
f64 |
0.4 |
Minimum relevance score for recall results |
embedding_cache_size |
usize |
10000 |
Number of embeddings to cache in memory |
chunk_max_tokens |
usize |
512 |
Maximum tokens per memory chunk |
response_cache_enabled |
bool |
false |
Enable response caching |
response_cache_ttl_minutes |
u64 |
60 |
Cache entry TTL |
response_cache_max_entries |
usize |
5000 |
Maximum cached entries |
snapshot_enabled |
bool |
false |
Enable memory snapshots |
snapshot_on_hygiene |
bool |
false |
Auto-snapshot before hygiene cleanup |
auto_hydrate |
bool |
true |
Auto-restore from snapshots on startup |
sqlite_open_timeout_secs |
Option<u32> |
None |
SQLite connection timeout |
Backend Options:
- sqlite - Full-featured SQL backend with FTS5 and vector search
- postgres - PostgreSQL backend for production deployments
- lucid - Lightweight Lucid-based backend (deprecated)
-
markdown - File-based storage in
workspace/memory/*.md - none - No memory (stateless mode)
Sources: src/config/schema.rs:99
[browser]
enabled = false
allowed_domains = ["example.com", "github.com"]
session_name = "default"
backend = "agent_browser" # "agent_browser" | "rust_native" | "computer_use" | "auto"
native_headless = true
native_webdriver_url = "http://127.0.0.1:9515"
native_chrome_path = "/usr/bin/google-chrome"
[browser.computer_use]
endpoint = "http://127.0.0.1:8787/v1/actions"
api_key = ""
timeout_ms = 15000
allow_remote_endpoint = false
window_allowlist = []
max_coordinate_x = 1920
max_coordinate_y = 1080| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable browser automation tools |
allowed_domains |
Vec<String> |
[] |
Domains the browser can access |
session_name |
Option<String> |
None |
Browser session identifier |
backend |
String |
"agent_browser" |
Browser automation backend |
native_headless |
bool |
true |
Run browser in headless mode |
native_webdriver_url |
String |
"http://127.0.0.1:9515" |
WebDriver URL for rust_native |
native_chrome_path |
Option<String> |
None |
Chrome/Chromium binary path |
Computer Use Sidecar Settings:
| Field | Type | Default | Description |
|---|---|---|---|
endpoint |
String |
"http://127.0.0.1:8787/v1/actions" |
Computer-use API endpoint |
api_key |
Option<String> |
None |
Bearer token for sidecar |
timeout_ms |
u64 |
15000 |
Per-action timeout |
allow_remote_endpoint |
bool |
false |
Allow non-localhost endpoints |
window_allowlist |
Vec<String> |
[] |
Allowed window titles |
max_coordinate_x |
Option<i64> |
None |
Max X coordinate boundary |
max_coordinate_y |
Option<i64> |
None |
Max Y coordinate boundary |
Sources: src/config/schema.rs:642-740
[http_request]
enabled = false
allowed_domains = ["api.example.com"]
max_response_size = 1000000 # 1MB
timeout_secs = 30| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable HTTP request tool |
allowed_domains |
Vec<String> |
[] |
Domains the tool can access |
max_response_size |
usize |
1000000 |
Maximum response size in bytes |
timeout_secs |
u64 |
30 |
Request timeout in seconds |
Sources: src/config/schema.rs:743-767
[web_search]
enabled = true
provider = "duckduckgo" # "duckduckgo" | "brave"
brave_api_key = "" # Required if provider = "brave"
max_results = 5
timeout_secs = 15| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Enable web search tool |
provider |
String |
"duckduckgo" |
Search provider |
brave_api_key |
Option<String> |
None |
Brave Search API key |
max_results |
usize |
5 |
Maximum search results (1-10) |
timeout_secs |
u64 |
15 |
Request timeout |
Sources: src/config/schema.rs:770-811
[composio]
enabled = false
api_key = "" # Composio API key
entity_id = "default"| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable Composio integration |
api_key |
Option<String> |
None |
Composio API key (encrypted) |
entity_id |
String |
"default" |
Entity ID for multi-user setups |
Composio provides OAuth-managed access to 1000+ third-party applications (Gmail, GitHub, Notion, Slack, etc.) without storing raw OAuth tokens locally. See Composio Integration for usage details.
Sources: src/config/schema.rs:598-625, src/tools/composio.rs:18-27
[autonomy]
level = "supervised" # "readonly" | "supervised" | "full"
workspace_only = true
forbidden_paths = ["/etc", "/sys", "/proc"]
allowed_commands = [] # Empty = all commands allowed| Field | Type | Default | Description |
|---|---|---|---|
level |
AutonomyLevel |
"supervised" |
Agent autonomy mode |
workspace_only |
bool |
true |
Restrict file operations to workspace directory |
forbidden_paths |
Vec<String> |
System dirs | Paths that cannot be accessed |
allowed_commands |
Vec<String> |
[] |
Command allowlist (empty = all allowed) |
Autonomy Levels:
- readonly - Agent can read files but cannot execute tools that modify state
- supervised - Agent can execute tools but may require approval
- full - Agent can execute all tools autonomously
Sources: src/config/schema.rs:67, src/security/mod.rs
[secrets]
encrypt = true| Field | Type | Default | Description |
|---|---|---|---|
encrypt |
bool |
true |
Encrypt API keys and tokens in config.toml |
When enabled, secrets are encrypted using ChaCha20-Poly1305 AEAD with a key stored in ~/.zeroclaw/secret.key. See Secret Management for details.
Sources: src/config/schema.rs:628-640
[gateway]
port = 3000
host = "127.0.0.1"
require_pairing = true
allow_public_bind = false
paired_tokens = [] # Managed automatically
# Rate limiting
pair_rate_limit_per_minute = 10
webhook_rate_limit_per_minute = 60
trust_forwarded_headers = false
rate_limit_max_keys = 10000
# Idempotency
idempotency_ttl_secs = 300
idempotency_max_keys = 10000| Field | Type | Default | Description |
|---|---|---|---|
port |
u16 |
3000 |
Gateway HTTP port |
host |
String |
"127.0.0.1" |
Bind address |
require_pairing |
bool |
true |
Require pairing before accepting requests |
allow_public_bind |
bool |
false |
Allow binding to non-localhost addresses |
paired_tokens |
Vec<String> |
[] |
Paired bearer tokens (auto-managed) |
pair_rate_limit_per_minute |
u32 |
10 |
Max /pair requests per minute per IP |
webhook_rate_limit_per_minute |
u32 |
60 |
Max /webhook requests per minute per IP |
trust_forwarded_headers |
bool |
false |
Trust X-Forwarded-For headers |
rate_limit_max_keys |
usize |
10000 |
Max distinct IPs tracked by rate limiter |
idempotency_ttl_secs |
u64 |
300 |
Webhook idempotency key TTL |
idempotency_max_keys |
usize |
10000 |
Max idempotency keys in memory |
Security Notes:
- Gateway binds to localhost by default for security
- Pairing generates a 6-digit code for client authentication
- Set
allow_public_bind = trueonly when using a trusted tunnel
Sources: src/config/schema.rs:502-596
[tunnel]
provider = "none" # "none" | "tailscale" | "cloudflare" | "ngrok" | "custom"
custom_command = ""| Field | Type | Default | Description |
|---|---|---|---|
provider |
String |
"none" |
Tunnel provider |
custom_command |
Option<String> |
None |
Custom tunnel command (for provider = "custom") |
Sources: src/config/schema.rs:105
[cron]
enabled = true
storage_file = "cron_jobs.json"| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Enable cron job scheduler |
storage_file |
String |
"cron_jobs.json" |
Cron job storage file name |
Cron jobs are managed via the cron_add, cron_list, cron_remove, cron_update, cron_run, and cron_runs tools. See Cron Job Configuration for usage.
Sources: src/config/schema.rs:94
[scheduler]
enabled = true
max_concurrent_jobs = 4| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Enable background job scheduler |
max_concurrent_jobs |
usize |
4 |
Maximum concurrent scheduled jobs |
Sources: src/config/schema.rs:76
[heartbeat]
enabled = false
interval_secs = 3600
channels = ["telegram"]
message = "System operational"| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable periodic heartbeat messages |
interval_secs |
u64 |
3600 |
Heartbeat interval in seconds |
channels |
Vec<String> |
[] |
Channels to send heartbeat to |
message |
String |
"System operational" |
Heartbeat message template |
Sources: src/config/schema.rs:90
[proxy]
enabled = false
http_proxy = "http://proxy.example.com:8080"
https_proxy = "http://proxy.example.com:8080"
all_proxy = "socks5://proxy.example.com:1080"
no_proxy = ["localhost", "127.0.0.1"]
scope = "zeroclaw" # "environment" | "zeroclaw" | "services"
services = ["provider.*", "channel.telegram"]| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable proxy support |
http_proxy |
Option<String> |
None |
HTTP proxy URL |
https_proxy |
Option<String> |
None |
HTTPS proxy URL |
all_proxy |
Option<String> |
None |
Fallback proxy for all schemes |
no_proxy |
Vec<String> |
[] |
Bypass proxy for these domains |
scope |
ProxyScope |
"zeroclaw" |
Proxy application scope |
services |
Vec<String> |
[] |
Service selectors (when scope = "services") |
Proxy Scopes:
- environment - Use system environment proxy variables only
- zeroclaw - Apply proxy to all ZeroClaw connections
- services - Apply proxy selectively to matching services
Service Selectors:
Use glob-style patterns: "provider.*", "channel.telegram", "tool.browser", etc.
Supported service keys: See src/config/schema.rs:12-37 for complete list.
Sources: src/config/schema.rs:813-1029
[identity]
format = "openclaw" # "openclaw" | "aieos"
aieos_path = "identity.json"
aieos_inline = "" # JSON string (alternative to file)| Field | Type | Default | Description |
|---|---|---|---|
format |
String |
"openclaw" |
Identity format |
aieos_path |
Option<String> |
None |
Path to AIEOS JSON file (relative to workspace) |
aieos_inline |
Option<String> |
None |
Inline AIEOS JSON (alternative to file) |
Identity Formats:
- openclaw - Use workspace markdown files (AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, MEMORY.md)
- aieos - Use AIEOS JSON structure for identity and behavior
Sources: src/config/schema.rs:283-309
[cost]
enabled = false
daily_limit_usd = 10.0
monthly_limit_usd = 100.0
warn_at_percent = 80
allow_override = false
[cost.prices]
"anthropic/claude-sonnet-4-20250514" = { input = 3.0, output = 15.0 }
"openai/gpt-4o" = { input = 5.0, output = 15.0 }| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable cost tracking |
daily_limit_usd |
f64 |
10.0 |
Daily spending limit in USD |
monthly_limit_usd |
f64 |
100.0 |
Monthly spending limit in USD |
warn_at_percent |
u8 |
80 |
Warn when spending reaches this percent |
allow_override |
bool |
false |
Allow --override flag to exceed limits |
prices |
HashMap<String, ModelPricing> |
Defaults | Per-model pricing (USD per 1M tokens) |
ModelPricing Structure:
| Field | Type | Description |
|---|---|---|
input |
f64 |
Input token price per 1M tokens |
output |
f64 |
Output token price per 1M tokens |
Sources: src/config/schema.rs:311-450
[hardware]
enabled = false
transport = "serial" # "none" | "native" | "serial" | "probe"
serial_port = "/dev/ttyACM0"
baud_rate = 115200
probe_target = "STM32F401RE"
workspace_datasheets = false| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable hardware access |
transport |
HardwareTransport |
"none" |
Hardware communication transport |
serial_port |
Option<String> |
None |
Serial port path |
baud_rate |
u32 |
115200 |
Serial baud rate |
probe_target |
Option<String> |
None |
Debug probe target chip |
workspace_datasheets |
bool |
false |
Enable datasheet RAG for pin lookups |
Transport Modes:
- none - No hardware access
- native - Native GPIO access (Raspberry Pi)
- serial - Serial communication (Arduino, STM32)
- probe - Debug probe (ARM Cortex-M)
Sources: src/config/schema.rs:173-241
[peripherals]
enabled = false
datasheet_dir = "datasheets"
[[peripherals.boards]]
board = "nucleo-f401re"
transport = "serial"
path = "/dev/ttyACM0"
baud = 115200| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Enable peripheral board support |
datasheet_dir |
Option<String> |
None |
Datasheet directory for RAG |
boards |
Vec<PeripheralBoardConfig> |
[] |
Board configurations |
PeripheralBoardConfig Structure:
| Field | Type | Default | Description |
|---|---|---|---|
board |
String |
Required | Board type (nucleo-f401re, rpi-gpio, esp32) |
transport |
String |
"serial" |
Transport mode |
path |
Option<String> |
None |
Device path (e.g., /dev/ttyACM0) |
baud |
u32 |
115200 |
Baud rate |
Sources: src/config/schema.rs:453-500
[agents.researcher]
provider = "ollama"
model = "llama3"
system_prompt = "You are a research assistant."
api_key = ""
temperature = 0.3
max_depth = 3
[agents.coder]
provider = "openrouter"
model = "anthropic/claude-sonnet-4-20250514"
temperature = 0.7
max_depth = 2Each [agents.<name>] section defines a sub-agent configuration for the delegate tool.
| Field | Type | Default | Description |
|---|---|---|---|
provider |
String |
Required | Provider for this sub-agent |
model |
String |
Required | Model for this sub-agent |
system_prompt |
Option<String> |
None |
Custom system prompt |
api_key |
Option<String> |
None |
API key override |
temperature |
Option<f64> |
0.7 |
Temperature override |
max_depth |
u32 |
3 |
Max recursion depth for nested delegation |
See Delegation Tools for usage.
Sources: src/config/schema.rs:146-171, src/tools/delegate.rs:1-267
[runtime]
adapter = "native" # "native" | "docker"| Field | Type | Default | Description |
|---|---|---|---|
adapter |
String |
"native" |
Runtime adapter for tool execution |
Runtime Adapters:
- native - Direct subprocess execution on host
- docker - Sandboxed execution in Docker containers
See Runtime Adapters for details.
Sources: src/config/schema.rs:70
The following diagram shows how configuration is loaded and merged:
flowchart TD
Start([Config::load_or_init])
Start --> CheckFile{config.toml<br/>exists?}
CheckFile -->|No| InitDefaults["Create default config<br/>Config::default()"]
CheckFile -->|Yes| ParseTOML["Parse TOML<br/>toml::from_str()"]
InitDefaults --> CheckEncrypt
ParseTOML --> CheckEncrypt{secrets.encrypt?}
CheckEncrypt -->|Yes| LoadSecretKey["Load secret.key<br/>SecretStore::load()"]
CheckEncrypt -->|No| ApplyEnv
LoadSecretKey --> DecryptSecrets["Decrypt secrets<br/>ChaCha20Poly1305"]
DecryptSecrets --> ApplyEnv["Apply environment<br/>variable overrides"]
ApplyEnv --> ValidateProxy{proxy.enabled?}
ValidateProxy -->|Yes| ProxyValidation["ProxyConfig::validate()"]
ValidateProxy -->|No| SetRuntime
ProxyValidation --> ProxyScope{proxy.scope?}
ProxyScope -->|environment| EnvProxyOnly["Use system env proxy"]
ProxyScope -->|zeroclaw| ApplyGlobal["Apply to all requests"]
ProxyScope -->|services| ApplySelective["Apply to matching services"]
EnvProxyOnly --> SetRuntime
ApplyGlobal --> SetRuntime["set_runtime_proxy_config()"]
ApplySelective --> SetRuntime
SetRuntime --> ReturnConfig["Return Config"]
Sources: src/config/schema.rs:1120-1200, src/config/schema.rs:1202-1315
Configuration validation occurs at multiple stages:
graph TB
LoadConfig["Config::load_or_init()"]
LoadConfig --> ValidateTOML["TOML syntax validation<br/>toml::from_str()"]
ValidateTOML --> ValidateSecrets["Secret decryption<br/>SecretStore"]
ValidateSecrets --> ValidateProxy["Proxy validation<br/>ProxyConfig::validate()"]
ValidateProxy --> ValidateChannels["Channel validation<br/>bot_token, credentials"]
ValidateChannels --> ValidateProvider["Provider validation<br/>create_provider()"]
ValidateProvider --> ValidateMemory["Memory validation<br/>create_memory()"]
ValidateMemory --> InitSubsystems["Initialize subsystems"]
ValidateTOML -.failure.-> ConfigError["anyhow::Error"]
ValidateSecrets -.failure.-> ConfigError
ValidateProxy -.failure.-> ConfigError
ValidateChannels -.failure.-> ConfigError
ValidateProvider -.failure.-> ConfigError
ValidateMemory -.failure.-> ConfigError
ConfigError --> UserFeedback["Display error message<br/>with field name"]
Sources: src/config/schema.rs:1120-1315
# Fastest path to operational agent
api_key = "sk-..."
default_provider = "openrouter"
default_model = "anthropic/claude-sonnet-4.6"# Production-ready setup with monitoring and rate limiting
api_key = "sk-..."
default_provider = "openrouter"
default_model = "anthropic/claude-sonnet-4.6"
default_temperature = 0.7
[secrets]
encrypt = true
[autonomy]
level = "supervised"
workspace_only = true
[gateway]
require_pairing = true
allow_public_bind = false
pair_rate_limit_per_minute = 10
webhook_rate_limit_per_minute = 60
[memory]
backend = "sqlite"
auto_save = true
hygiene_enabled = true
embedding_provider = "openai"
embedding_model = "text-embedding-3-small"
[reliability]
max_retries = 3
retry_on_rate_limit = true
fallback_models = ["anthropic/claude-3.5-sonnet"]
[cost]
enabled = true
daily_limit_usd = 50.0
monthly_limit_usd = 500.0
[heartbeat]
enabled = true
interval_secs = 3600
channels = ["telegram"]# Multiple communication channels
api_key = "sk-..."
default_provider = "openrouter"
default_model = "anthropic/claude-sonnet-4.6"
[channels_config.telegram]
bot_token = "123:ABC..."
allowed_users = ["alice", "bob"]
stream_mode = "draft"
[channels_config.discord]
bot_token = "MTAx..."
guild_id = "123456789"
allowed_users = ["user#1234"]
mention_only = true
[channels_config.slack]
bot_token = "xoxb-..."
app_token = "xapp-..."
allowed_users = ["U12345"]# Delegate agents for specialized tasks
api_key = "sk-..."
default_provider = "openrouter"
default_model = "anthropic/claude-sonnet-4.6"
[agents.researcher]
provider = "openrouter"
model = "perplexity/sonar-pro"
system_prompt = "You are a research assistant. Provide detailed, well-sourced information."
temperature = 0.3
max_depth = 2
[agents.coder]
provider = "openrouter"
model = "anthropic/claude-sonnet-4.6"
system_prompt = "You are a code generation expert. Write clean, efficient code."
temperature = 0.7
max_depth = 2
[agents.summarizer]
provider = "openrouter"
model = "openai/gpt-4o-mini"
system_prompt = "You are a summarization expert. Provide concise summaries."
temperature = 0.5
max_depth = 1Sources: src/onboard/wizard.rs:300-463
Complete example configuration with commonly used settings:
# ~/.zeroclaw/config.toml
# ── Core Settings ────────────────────────────────────────────────
api_key = "sk-or-v1-..."
default_provider = "openrouter"
default_model = "anthropic/claude-sonnet-4.6"
default_temperature = 0.7
# ── Security ─────────────────────────────────────────────────────
[secrets]
encrypt = true
[autonomy]
level = "supervised"
workspace_only = true
forbidden_paths = ["/etc", "/sys", "/proc", "/boot"]
allowed_commands = []
[gateway]
port = 3000
host = "127.0.0.1"
require_pairing = true
allow_public_bind = false
pair_rate_limit_per_minute = 10
webhook_rate_limit_per_minute = 60
# ── Channels ─────────────────────────────────────────────────────
[channels_config.telegram]
bot_token = "123456789:ABC..."
allowed_users = ["alice"]
stream_mode = "draft"
draft_update_interval_ms = 1000
mention_only = false
# ── Agent Configuration ──────────────────────────────────────────
[agent]
compact_context = false
max_tool_iterations = 10
max_history_messages = 50
parallel_tools = false
# ── Memory ───────────────────────────────────────────────────────
[memory]
backend = "sqlite"
auto_save = true
hygiene_enabled = true
archive_after_days = 7
purge_after_days = 30
embedding_provider = "openai"
embedding_model = "text-embedding-3-small"
embedding_dimensions = 1536
vector_weight = 0.7
keyword_weight = 0.3
min_relevance_score = 0.4
# ── Provider Reliability ─────────────────────────────────────────
[reliability]
max_retries = 3
initial_retry_delay_ms = 1000
max_retry_delay_ms = 60000
retry_multiplier = 2.0
retry_on_rate_limit = true
fallback_models = []
# ── Tools ────────────────────────────────────────────────────────
[browser]
enabled = false
allowed_domains = []
backend = "agent_browser"
[http_request]
enabled = false
allowed_domains = []
max_response_size = 1000000
timeout_secs = 30
[web_search]
enabled = true
provider = "duckduckgo"
max_results = 5
timeout_secs = 15
[composio]
enabled = false
api_key = ""
entity_id = "default"
# ── Cost Tracking ────────────────────────────────────────────────
[cost]
enabled = false
daily_limit_usd = 10.0
monthly_limit_usd = 100.0
warn_at_percent = 80
# ── Scheduling ───────────────────────────────────────────────────
[cron]
enabled = true
storage_file = "cron_jobs.json"
[heartbeat]
enabled = false
interval_secs = 3600
channels = []
message = "System operational"
# ── Advanced ─────────────────────────────────────────────────────
[proxy]
enabled = false
scope = "zeroclaw"
[identity]
format = "openclaw"
[hardware]
enabled = false
transport = "none"
[peripherals]
enabled = falseSources: src/config/schema.rs:48-144, src/onboard/wizard.rs:104-143