Skip to content

04 Configuration

Nikolay Vyahhi edited this page Feb 19, 2026 · 3 revisions

Configuration

Relevant source files

The following files were used as context for generating this wiki page:

This page provides an overview of ZeroClaw's configuration system, including how configuration is loaded, the priority hierarchy of configuration sources, and how config integrates with major subsystems. For detailed reference of all configuration options, see Configuration File Reference. For environment variable overrides, see Environment Variables. For encrypted secret storage, see Secret Management. For workspace directory structure and management, see Workspace Management.


Purpose and Scope

ZeroClaw's configuration system follows a three-tier priority model: environment variables override config.toml settings, which override built-in defaults. Configuration is centralized in a single Config struct that orchestrates initialization of all subsystems including providers, channels, tools, memory backends, and security policies.

The configuration system supports:

  • File-based configuration via ~/.zeroclaw/config.toml
  • Environment variable overrides for API keys and runtime settings
  • Encrypted secret storage using ChaCha20-Poly1305
  • Multi-workspace support with active workspace markers
  • Interactive onboarding wizard for first-time setup
  • Quick non-interactive setup for automation

Configuration Sources and Priority

ZeroClaw resolves configuration from three sources in descending priority order:

graph TD
    EnvVars["Environment Variables<br/>(Highest Priority)"]
    ConfigFile["config.toml<br/>(Medium Priority)"]
    Defaults["Built-in Defaults<br/>(Lowest Priority)"]
    
    EnvVars -->|overrides| ConfigFile
    ConfigFile -->|overrides| Defaults
    Defaults -->|used when not set| FinalConfig["Final Config"]
    ConfigFile -->|used when not set| FinalConfig
    EnvVars -->|used when set| FinalConfig
Loading

Sources: src/config/schema.rs:48-144, src/channels/mod.rs:34-35

Priority Resolution Examples

Config Key config.toml Environment Variable Final Value
api_key "sk-from-file" OPENROUTER_API_KEY="sk-from-env" "sk-from-env"
default_model "claude-sonnet-4-5" (not set) "claude-sonnet-4-5"
default_temperature (not set) (not set) 0.7 (default)

The Config::load_or_init() method implements this priority cascade. See Configuration Loading Process below for details.

Sources: src/config/schema.rs:1620-1750, src/onboard/wizard.rs:61-196


Configuration File Structure

The primary configuration file is ~/.zeroclaw/config.toml. The file is organized into logical sections corresponding to subsystems:

Top-Level Configuration Sections

graph LR
    ConfigToml["config.toml"]
    
    ConfigToml --> Provider["[provider]<br/>default_provider, api_key"]
    ConfigToml --> Agent["[agent]<br/>max_tool_iterations, compact_context"]
    ConfigToml --> Channels["[channels_config]<br/>telegram, discord, slack, etc."]
    ConfigToml --> Memory["[memory]<br/>backend, auto_save, embedding_*"]
    ConfigToml --> Security["[autonomy]<br/>level, workspace_only"]
    ConfigToml --> Runtime["[runtime]<br/>adapter, docker_config"]
    ConfigToml --> Tools["[composio], [browser], [http_request]"]
    ConfigToml --> Gateway["[gateway]<br/>port, require_pairing"]
    ConfigToml --> Scheduler["[scheduler], [cron], [heartbeat]"]
    ConfigToml --> Secrets["[secrets]<br/>encrypt"]
Loading

Sources: src/config/schema.rs:48-144

Config Struct Hierarchy

The Config struct is defined in src/config/schema.rs:48-144 with the following major sections:

pub struct Config {
    // Core provider settings
    pub api_key: Option<String>,
    pub default_provider: Option<String>,
    pub default_model: Option<String>,
    pub default_temperature: f64,
    
    // Subsystem configurations
    pub agent: AgentConfig,
    pub autonomy: AutonomyConfig,
    pub channels_config: ChannelsConfig,
    pub memory: MemoryConfig,
    pub runtime: RuntimeConfig,
    pub gateway: GatewayConfig,
    pub composio: ComposioConfig,
    pub browser: BrowserConfig,
    pub hardware: HardwareConfig,
    pub proxy: ProxyConfig,
    
    // Advanced features
    pub model_routes: Vec<ModelRouteConfig>,
    pub agents: HashMap<String, DelegateAgentConfig>,
    pub secrets: SecretsConfig,
    // ... and more
}

Each section is a dedicated struct with its own defaults. For example, MemoryConfig (src/config/schema.rs:2244-2329) contains settings for the memory backend, embedding models, vector search weights, and cache configuration.

Sources: src/config/schema.rs:48-144, src/config/schema.rs:2244-2329


Configuration Loading Process

Load-or-Initialize Flow

sequenceDiagram
    participant Main as "main.rs"
    participant ConfigLoader as "Config::load_or_init()"
    participant FileSystem as "Filesystem"
    participant EnvVars as "Environment"
    participant SecretStore as "SecretStore"
    participant Subsystems as "Subsystems"
    
    Main->>ConfigLoader: load_or_init()
    ConfigLoader->>FileSystem: Check ~/.zeroclaw/config.toml
    
    alt config.toml exists
        FileSystem-->>ConfigLoader: Return file contents
        ConfigLoader->>ConfigLoader: Parse TOML to Config struct
        
        alt secrets.encrypt = true
            ConfigLoader->>SecretStore: decrypt_secrets()
            SecretStore-->>ConfigLoader: Decrypted values
        end
        
        ConfigLoader->>EnvVars: Read OPENROUTER_API_KEY, etc.
        EnvVars-->>ConfigLoader: Environment overrides
        ConfigLoader->>ConfigLoader: Apply env overrides
    else config.toml missing
        ConfigLoader->>ConfigLoader: Create default Config
        ConfigLoader->>FileSystem: Write config.toml
    end
    
    ConfigLoader-->>Main: Return Config
    Main->>Subsystems: Initialize with Config
Loading

Sources: src/config/schema.rs:1620-1750, src/channels/mod.rs:846-1027

Initialization Sequence

The configuration loading sequence involves several steps:

  1. Workspace Resolution: Determine active workspace directory

    • Check ZEROCLAW_WORKSPACE environment variable
    • Look for active_workspace.toml marker
    • Default to ~/.zeroclaw/workspace
  2. Config File Parsing: Read config.toml from workspace parent directory

    • If missing, create with defaults
    • Parse TOML to Config struct
  3. Secret Decryption: If secrets.encrypt = true, decrypt encrypted fields

    • Load encryption key from ~/.zeroclaw/secret.key
    • Decrypt api_key, composio.api_key, channel tokens, etc.
  4. Environment Variable Application: Override config values with env vars

    • OPENROUTER_API_KEYconfig.api_key
    • ANTHROPIC_API_KEY → provider-specific override
    • ZEROCLAW_* prefixed variables
  5. Validation: Validate configuration consistency

    • Check required fields for enabled features
    • Validate proxy URLs, rate limits, etc.

Sources: src/config/schema.rs:1620-1750, src/config/schema.rs:1938-2027


Workspace Directory

The workspace directory is the primary working directory for ZeroClaw. Default location: ~/.zeroclaw/workspace.

Workspace Structure

~/.zeroclaw/
├── config.toml              # Main configuration file
├── secret.key               # Encryption key (when secrets.encrypt=true)
├── active_workspace.toml    # Optional: marks active workspace
└── workspace/               # Active workspace directory
    ├── AGENTS.md           # Agent identity (OpenClaw format)
    ├── SOUL.md             # Personality definition
    ├── TOOLS.md            # Tool usage guidelines
    ├── IDENTITY.md         # User preferences
    ├── USER.md             # User information
    ├── MEMORY.md           # Curated long-term memory
    ├── state/              # Runtime state
    │   ├── jobs.db         # Cron job database
    │   ├── memory.db       # SQLite memory backend
    │   └── models_cache.json
    ├── skills/             # Skill definitions
    └── memory/             # Daily memory files (optional)

The workspace directory serves multiple purposes:

  • Identity files: OpenClaw or AIEOS format identity definitions loaded into system prompt
  • State storage: Persistent databases for memory, cron jobs, health checks
  • Tool scoping: When workspace_only = true, file tools are restricted to workspace subtree

Sources: src/channels/mod.rs:846-1027, src/onboard/wizard.rs:769-824

For multi-workspace setups and workspace switching, see Workspace Management.


Integration with Subsystems

Configuration flows from the Config struct to all major subsystems during initialization.

Subsystem Initialization Map

graph TD
    Config["Config Struct"]
    
    Config --> Provider["Provider<br/>(default_provider, api_key, reliability)"]
    Config --> Memory["Memory Backend<br/>(memory.backend, memory.auto_save)"]
    Config --> Security["SecurityPolicy<br/>(autonomy.level, autonomy.workspace_only)"]
    Config --> Tools["Tool Registry<br/>(composio, browser, http_request)"]
    Config --> Channels["Channel Implementations<br/>(channels_config.telegram, discord, etc.)"]
    Config --> Runtime["RuntimeAdapter<br/>(runtime.adapter, docker_config)"]
    Config --> Gateway["HTTP Gateway<br/>(gateway.port, gateway.require_pairing)"]
    Config --> Scheduler["Scheduler<br/>(scheduler.*, cron.*)"]
    
    Provider --> Agent["Agent Core"]
    Memory --> Agent
    Security --> Agent
    Tools --> Agent
    
    Channels --> Agent
    Gateway --> Agent
Loading

Sources: src/channels/mod.rs:101-123, src/tools/mod.rs:89-238

Provider Configuration Example

The provider subsystem reads configuration from multiple sources:

// From config.toml
let provider_name = config.default_provider.as_deref().unwrap_or("openrouter");
let model = config.default_model.as_deref().unwrap_or("anthropic/claude-sonnet-4.6");
let api_key = config.api_key.as_deref();

// With reliability settings
let reliability = &config.reliability; // ReliabilityConfig with retries, backoff

// Create resilient provider
let provider = providers::create_resilient_provider(
    provider_name,
    api_key,
    reliability,
)?;

Sources: src/channels/mod.rs:266-308, src/config/schema.rs:2034-2093

Channel Configuration Example

Channels read their specific configuration sections:

// Telegram channel config from [channels_config.telegram]
if let Some(telegram_cfg) = &config.channels_config.telegram {
    let channel = TelegramChannel::new(
        telegram_cfg.bot_token.clone(),
        telegram_cfg.allowed_users.clone(),
        telegram_cfg.stream_mode,
        telegram_cfg.draft_update_interval_ms,
        telegram_cfg.mention_only,
    )?;
    channels.push(Arc::new(channel));
}

Sources: src/config/schema.rs:2405-2462, src/channels/mod.rs:1047-1133

Tool Configuration Example

Tools receive relevant config sections during registry construction:

// Composio tool (optional, requires enabled flag and API key)
if config.composio.enabled {
    if let Some(key) = config.composio.api_key.as_deref() {
        tools.push(Box::new(ComposioTool::new(
            key,
            Some(&config.composio.entity_id),
            security.clone(),
        )));
    }
}

// Browser tool (requires enabled flag)
if config.browser.enabled {
    tools.push(Box::new(BrowserTool::new(
        security.clone(),
        config.browser.allowed_domains.clone(),
        // ... more browser config fields
    )));
}

Sources: src/tools/mod.rs:160-218, src/tools/composio.rs:23-40

Security Policy Configuration

The AutonomyConfig section controls security enforcement:

pub struct AutonomyConfig {
    pub level: AutonomyLevel,           // ReadOnly | Supervised | Full
    pub workspace_only: bool,           // Restrict file ops to workspace
    pub forbidden_paths: Vec<String>,   // Additional blocked paths
    pub allowed_commands: Vec<String>,  // Shell command allowlist
    pub max_actions_per_hour: u32,      // Rate limiting
    // ...
}

The SecurityPolicy is constructed from AutonomyConfig and passed to all tools:

let security = Arc::new(SecurityPolicy::from_config(&config.autonomy, &workspace_dir));
let tools = all_tools(&security, /* ... */);

Sources: src/config/schema.rs:2094-2193, src/tools/mod.rs:72-86


Configuration Diagram: Code Entity Mapping

The following diagram maps configuration concepts to actual code entities:

graph TB
    subgraph "Configuration Files"
        ConfigToml["~/.zeroclaw/config.toml"]
        EnvFile["~/.zeroclaw/workspace/.env"]
        SecretKey["~/.zeroclaw/secret.key"]
    end
    
    subgraph "Config Schema (src/config/schema.rs)"
        ConfigStruct["Config struct<br/>line 48-144"]
        AgentConfig["AgentConfig struct<br/>line 243-280"]
        AutonomyConfig["AutonomyConfig struct<br/>line 2094-2193"]
        ChannelsConfig["ChannelsConfig struct<br/>line 2405-2613"]
        MemoryConfig["MemoryConfig struct<br/>line 2244-2329"]
        ComposioConfig["ComposioConfig struct<br/>line 599-625"]
        BrowserConfig["BrowserConfig struct<br/>line 691-740"]
    end
    
    subgraph "Config Loading (src/config/schema.rs)"
        LoadOrInit["Config::load_or_init()<br/>line 1620-1750"]
        ApplyEnv["apply_env_overrides()<br/>line 1796-1936"]
        SecretStoreDecrypt["SecretStore::decrypt()<br/>line 3446-3509"]
    end
    
    subgraph "Subsystem Initialization"
        CreateProvider["create_resilient_provider()<br/>src/providers/mod.rs"]
        CreateMemory["create_memory()<br/>src/memory/mod.rs"]
        AllTools["all_tools()<br/>src/tools/mod.rs:89-238"]
        BuildChannels["build system prompt, channels<br/>src/channels/mod.rs:1047-1133"]
    end
    
    ConfigToml --> LoadOrInit
    EnvFile --> ApplyEnv
    SecretKey --> SecretStoreDecrypt
    
    LoadOrInit --> ConfigStruct
    ApplyEnv --> ConfigStruct
    SecretStoreDecrypt --> ConfigStruct
    
    ConfigStruct --> AgentConfig
    ConfigStruct --> AutonomyConfig
    ConfigStruct --> ChannelsConfig
    ConfigStruct --> MemoryConfig
    ConfigStruct --> ComposioConfig
    ConfigStruct --> BrowserConfig
    
    ConfigStruct --> CreateProvider
    MemoryConfig --> CreateMemory
    ConfigStruct --> AllTools
    ConfigStruct --> BuildChannels
Loading

Sources: src/config/schema.rs:48-144, src/config/schema.rs:1620-1750, src/channels/mod.rs:1047-1133, src/tools/mod.rs:89-238


Environment Variable Override System

ZeroClaw supports environment variable overrides for most configuration values. The override system follows a naming convention:

Override Naming Patterns

Config Section Environment Variable Pattern Example
Provider API keys {PROVIDER}_API_KEY OPENROUTER_API_KEY
Generic API key ZEROCLAW_API_KEY ZEROCLAW_API_KEY
Model selection ZEROCLAW_MODEL ZEROCLAW_MODEL=gpt-4o
Workspace path ZEROCLAW_WORKSPACE ZEROCLAW_WORKSPACE=/custom/path

Priority for Credentials

Provider credential resolution follows this priority:

  1. Explicit API key in config (config.api_key)
  2. Provider-specific env var (e.g., ANTHROPIC_API_KEY)
  3. Generic env var (ZEROCLAW_API_KEY or OPENROUTER_API_KEY)
  4. OAuth flow (for supported providers)

Sources: src/config/schema.rs:1796-1936, src/channels/mod.rs:34-35

For complete environment variable reference, see Environment Variables.


Onboarding and Quick Setup

ZeroClaw provides two initialization modes:

Interactive Wizard

The interactive wizard (zeroclaw onboard --interactive) guides users through 9 configuration steps:

graph LR
    Start["zeroclaw onboard --interactive"] --> Step1["1. Workspace Setup"]
    Step1 --> Step2["2. AI Provider & API Key"]
    Step2 --> Step3["3. Channels"]
    Step3 --> Step4["4. Tunnel"]
    Step4 --> Step5["5. Tool Mode & Security"]
    Step5 --> Step6["6. Hardware"]
    Step6 --> Step7["7. Memory Configuration"]
    Step7 --> Step8["8. Project Context"]
    Step8 --> Step9["9. Workspace Files"]
    Step9 --> Save["Save config.toml"]
Loading

Sources: src/onboard/wizard.rs:61-196

Quick Setup (Non-Interactive)

For automation or CI/CD, use quick setup:

zeroclaw onboard --api-key "sk-..." --provider openrouter --memory sqlite

This generates a sensible default config instantly without prompts.

Sources: src/onboard/wizard.rs:301-463


Config Validation

The Config struct implements validation for configuration consistency:

impl Config {
    pub fn validate(&self) -> Result<()> {
        // Proxy configuration validation
        self.proxy.validate()?;
        
        // Gateway: disallow public bind without tunnel
        if !self.gateway.host.starts_with("127.") 
            && !self.gateway.allow_public_bind
            && !self.tunnel.enabled() {
            bail!("Gateway bound to public IP without tunnel");
        }
        
        // Memory backend: check embedding provider when using vector search
        if self.memory.backend == "sqlite" 
            && self.memory.embedding_provider == "none" {
            warn!("Vector search disabled without embedding provider");
        }
        
        // ... more validation rules
        Ok(())
    }
}

Validation occurs automatically during Config::load_or_init().

Sources: src/config/schema.rs:1752-1794, src/config/schema.rs:886-921


Related Pages

Sources: src/config/schema.rs:48-144, src/config/mod.rs:1-17, src/channels/mod.rs:34-52, src/onboard/wizard.rs:61-463


Clone this wiki locally