You’ve got OpenClaw installed. Your agents are spinning up. And then you hit a configuration problem: LLM connection fails, gateway won’t bind, skills aren’t loading. You stare at that one file—~/.openclaw/openclaw.json—and realize: you have no idea what half these settings actually do.
That ends now.
Here’s the truth: openclaw.json is your system’s nervous system. Gateway bindings determine how your agents talk to the world. LLM backend settings control which AI model your agents think with. Skills configuration decides what tools are available. Get it wrong, and your system won’t even boot. Get it right, and you’ve got a bulletproof foundation.
Let’s break down every section, explain what actually matters, and show you real examples you can use immediately.
File Location & Structure
First, the basics:
Location: ~/.openclaw/openclaw.json
That ~ means your home directory. On Linux/Mac, that’s /home/username/ or /Users/username/. On Windows, it’s C:\Users\username\. OpenClaw creates this file during initialization, but you’ll customize it for your setup.
File format: Standard JSON. That means strict syntax—quotes around keys, commas between properties, no trailing commas. A single typo and the parser explodes. Use a JSON validator if you’re unsure.
Override behavior: Some settings can be overridden via environment variables. The precedence is:
- Environment variables (highest priority)
- openclaw.json settings
- Hardcoded defaults
This matters because you might want different configurations in different environments (dev, staging, production) without editing the JSON file.
The Five Core Sections
Here’s the structure at a glance:
{
"version": "1.0.0",
"gateway": { ... },
"llm": { ... },
"skills": { ... },
"memory": { ... },
"runtime": { ... }
}
Each section controls a different aspect of your system. Let’s walk through them.
Section 1: Version
Boring but important:
"version": "1.0.0"
This tells OpenClaw which schema version this file is written in. When OpenClaw updates its schema (adds new fields, deprecates old ones), it uses this to know how to handle your file. Don’t change this unless you’re explicitly migrating configurations between versions.
Current valid versions:
1.0.0– Initial release- Future versions will be backward compatible with migration notes
Section 2: Gateway Configuration
This is where you define how your agents connect to the outside world.
What It Controls
The gateway is the networking layer. It handles:
- Port binding (which port OpenClaw listens on)
- API authentication (if you’re exposing OpenClaw via HTTP)
- TLS/SSL settings (encrypted connections)
- Timeout and connection limits
- Request/response middleware
- Load balancing across multiple agent instances
- Reverse proxy and header forwarding
The gateway is your system’s front door. Misconfigure it and your entire agent fleet becomes unreachable, authenticated access breaks, or you expose yourself to security vulnerabilities.
Minimal Configuration
"gateway": {
"bind": "127.0.0.1",
"port": 8080,
"protocol": "http"
}
This says: “Listen on localhost, port 8080, over HTTP.” It’s the simplest possible setup.
When to use this: Development, local testing, internal networks only. Never expose HTTP to the internet. This configuration blocks all external access, which is actually perfect for testing because you don’t accidentally expose your agents to the world while debugging.
What happens under the hood: OpenClaw starts a HTTP server bound to 127.0.0.1 (loopback, your machine only). Any request to https://automateanddeploy.com or http://127.0.0.1:8080 reaches your agents. Requests from other machines, other networks—they all get connection refused. Safe, but isolated.
Production Configuration
"gateway": {
"bind": "0.0.0.0",
"port": 443,
"protocol": "https",
"tls": {
"certFile": "/etc/openclaw/certs/server.crt",
"keyFile": "/etc/openclaw/certs/server.key",
"minVersion": "1.2"
},
"auth": {
"type": "bearer",
"secret": "${OPENCLAW_AUTH_SECRET}"
},
"limits": {
"maxConnections": 1000,
"requestTimeout": 30000,
"keepAliveTimeout": 60000
}
}
Let’s break this down:
bind: “0.0.0.0” – Listen on all available network interfaces. This makes OpenClaw accessible from other machines. Use 127.0.0.1 to restrict to localhost.
port: 443 – Standard HTTPS port. Requires root/admin on most systems.
protocol: “https” – Force encrypted connections.
tls section – Certificate paths and minimum TLS version. Your cert and key files need to exist and be readable.
auth section – Authentication type (bearer for token-based) and the secret (here, loaded from environment variable). This prevents unauthorized access.
limits section – Connection pooling and timeout settings. requestTimeout: 30000 means requests timeout after 30 seconds if no response.
Environment Variable Substitution
Notice "${OPENCLAW_AUTH_SECRET}". OpenClaw supports environment variable substitution:
export OPENCLAW_AUTH_SECRET="your-secret-key-here"
Then in the JSON, use "${VARIABLE_NAME}" syntax. This keeps secrets out of the config file.
Common Gateway Issues & Fixes
Issue: “Address already in use”
- Solution: Change port. Check what’s using the old one with
lsof -i :8080(Unix) ornetstat -ano(Windows).
Issue: “Permission denied” on port 443
- Solution: Either run as root/admin, or use a port > 1024 (e.g., 8443) and proxy through nginx/Apache.
Issue: Certificate validation errors
- Solution: Ensure cert and key files exist, are readable, and are valid. Use
openssl x509 -in certfile.crt -text -nooutto inspect.
Section 3: LLM Backend Configuration
Here’s the critical part: which AI model your agents use for reasoning and generation.
Structure Overview
"llm": {
"backend": "anthropic",
"models": [
{
"name": "default",
"provider": "anthropic",
"apiType": "rest",
"apiKey": "${ANTHROPIC_API_KEY}",
"apiUrl": "https://api.anthropic.com/v1",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 4096,
"temperature": 0.7
}
],
"fallback": {
"enabled": true,
"models": ["claude-3-opus-20250219"]
}
}
Key Fields
backend: Primary LLM backend. Valid values:
anthropic– Claude modelsopenai– GPT modelsollama– Local LLM servercustom– Custom API-compatible endpoint
models array: You can define multiple models. The first is default; others are fallbacks or alternatives.
name: Internal reference. “default” is used if no model specified.
provider: Which API provider. Usually matches backend, but allows mixing providers.
apiType: Communication protocol.
rest– HTTP REST APIwebsocket– Persistent connection
apiKey: Authentication token. Use environment variables for security.
apiUrl: API endpoint. Different providers have different URLs.
modelId: The actual model identifier. Different for each provider.
maxTokens: Maximum tokens in a single response. Lower values = cheaper, shorter responses.
temperature: Randomness in responses (0.0 = deterministic, 1.0 = creative).
Real-World Examples
Example 1: Claude via Anthropic API
"llm": {
"backend": "anthropic",
"models": [
{
"name": "default",
"provider": "anthropic",
"apiType": "rest",
"apiKey": "${ANTHROPIC_API_KEY}",
"apiUrl": "https://api.anthropic.com/v1",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 4096,
"temperature": 0.7
}
]
}
Setup: Create an Anthropic account, generate an API key, set environment variable:
export ANTHROPIC_API_KEY="sk-ant-..."
Example 2: Local Ollama Server
"llm": {
"backend": "ollama",
"models": [
{
"name": "default",
"provider": "ollama",
"apiType": "rest",
"apiUrl": "https://automateanddeploy.com:11434",
"modelId": "llama2:13b",
"maxTokens": 2048,
"temperature": 0.5
}
]
}
Setup: Install Ollama, run ollama serve, then pull a model:
ollama pull llama2:13b
Example 3: Multiple Models with Fallback
"llm": {
"backend": "anthropic",
"models": [
{
"name": "default",
"provider": "anthropic",
"apiType": "rest",
"apiKey": "${ANTHROPIC_API_KEY}",
"apiUrl": "https://api.anthropic.com/v1",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 4096,
"temperature": 0.7
},
{
"name": "fast",
"provider": "anthropic",
"apiType": "rest",
"apiKey": "${ANTHROPIC_API_KEY}",
"apiUrl": "https://api.anthropic.com/v1",
"modelId": "claude-3-haiku-20250307",
"maxTokens": 1024,
"temperature": 0.5
}
],
"fallback": {
"enabled": true,
"models": ["fast"],
"trigger": "rate_limit"
}
}
This setup uses Claude Sonnet as default, falls back to Haiku if rate-limited. This is smart because Haiku is cheaper and faster—perfect for recovery when you’ve hit rate limits on the primary model.
Tuning LLM Parameters: The Hidden Layer
maxTokens controls response length. You might think “higher is better,” but there’s a cost equation here:
- Higher maxTokens (4096+): Better for complex reasoning, detailed responses, longer outputs. But you pay for every token, and the API request takes longer. Use for tasks where quality matters more than speed.
- Lower maxTokens (512): Fast responses, cheap, perfect for simple queries. But you risk truncated responses. If your agent needs to write detailed code or explain complex concepts, this will bite you.
The sweet spot for most teams is 1024-2048. You get reasonable output length without paying for tokens you don’t use.
temperature controls randomness. This is where most people misunderstand:
- temperature: 0.0: Deterministic. Same input always produces same output. Perfect for testing, CI/CD, fact-based tasks. Bad if you want variety or creative problem-solving.
- temperature: 0.5: Balanced. Some variation but still reliable. Default for most agents.
- temperature: 1.0: Highly creative. Good for brainstorming, creative writing. Bad if you need consistency.
If you’re debugging why your agent behaves erratically, check temperature first. A temperature of 0.9 on responses that should be deterministic will drive you crazy.
Advanced LLM Configuration: Retry and Timeout Strategies
The fields we showed are just the basics. Here’s what experienced practitioners configure when they need production reliability:
"llm": {
"models": [
{
"name": "default",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 2048,
"temperature": 0.7,
"timeout": 30000,
"retries": 3,
"retryBackoff": "exponential",
"retryDelayMs": 500
}
]
}
timeout: How long (milliseconds) to wait for a response before giving up. 30 seconds is reasonable for most APIs. If you have a slow network or the LLM is under load, increase this.
retries: How many times to retry a failed request. 3 is reasonable. Each retry adds a delay, so be careful not to retry forever—you’ll lock up your agent.
retryBackoff: Retry strategy. “exponential” means each retry waits longer (500ms, 1000ms, 2000ms). “linear” adds the same delay each time. Exponential is better because it gives the API time to recover from transient failures.
retryDelayMs: Starting delay for retries. If set to 500, first retry waits 500ms, second waits 1000ms, third waits 2000ms (exponential). Choose based on your tolerance for latency.
Environment Variable Precedence
{
"llm": {
"models": [
{
"apiKey": "${ANTHROPIC_API_KEY}"
}
]
}
}
When OpenClaw starts:
- Look for
ANTHROPIC_API_KEYenvironment variable - If not found, use literal string
${ANTHROPIC_API_KEY}(which will fail) - Parse error, agent fails to initialize
Always set your environment variables before starting OpenClaw.
Section 4: Skills Configuration
Skills are reusable capabilities your agents can invoke. This section controls how skills are discovered and loaded.
Structure
"skills": {
"builtin": true,
"extraDirs": [
"/home/user/.openclaw/custom-skills",
"/opt/openclaw/shared-skills"
],
"loadingPrecedence": "external-first",
"autoReload": true,
"namespace": "skills"
}
Key Fields
builtin: Whether to load built-in OpenClaw skills (file ops, API calls, etc.).
extraDirs: Additional directories to scan for custom skills. OpenClaw searches these in order.
loadingPrecedence:
builtin-first– Built-in skills shadow custom ones with same nameexternal-first– Custom skills override built-in ones
Choose based on your needs. external-first lets you customize core behavior.
autoReload: If true, OpenClaw watches skill directories for changes and reloads without restart. Great for development; disable in production for stability.
namespace: Prefix for skill invocation. With namespace: "skills", you invoke skills as skills:name-of-skill.
Custom Skills Example
Suppose you have custom skills in ~/.openclaw/custom-skills/. Directory structure:
~/.openclaw/custom-skills/
├── db-query.js
├── slack-notify.js
└── manifest.json
Each .js file is a skill. manifest.json describes them:
{
"skills": [
{
"name": "db-query",
"description": "Query your database",
"inputs": {
"sql": { "type": "string", "required": true },
"timeout": { "type": "number", "default": 5000 }
},
"outputs": {
"type": "array"
}
},
{
"name": "slack-notify",
"description": "Send Slack message",
"inputs": {
"channel": { "type": "string", "required": true },
"message": { "type": "string", "required": true }
}
}
]
}
Then in openclaw.json:
"skills": {
"builtin": true,
"extraDirs": ["~/.openclaw/custom-skills"],
"loadingPrecedence": "external-first"
}
Now agents can invoke skills:db-query and skills:slack-notify.
Why You’d Change Skills Configuration
The default configuration ("builtin": true, "autoReload": false, "loadingPrecedence": "builtin-first") works for simple setups. But here’s when you’d change it:
Change autoReload to true: You’re developing custom skills and want to test without restarting OpenClaw. Disable it in production (it uses file system watchers, which have overhead and can miss changes on network filesystems).
Change loadingPrecedence to external-first: You want to override a built-in skill (dangerous but sometimes necessary). For example, if the built-in “send-email” skill doesn’t support your mail server, you can create your own version and have it loaded first. This is powerful but risky—if you mess up your custom skill, your entire agent breaks.
Add more extraDirs: Your company has a shared skills library for all teams, plus team-specific skills, plus your agent’s custom skills. Multiple directories let you layer them. OpenClaw checks them in order, so list them from most specific (your agent’s skills) to most general (company-wide skills).
Disable builtin: In ultra-secure environments, you might want to disable built-in skills and only use whitelisted custom ones. This is paranoid but sometimes necessary for compliance. Set "builtin": false and rely entirely on extraDirs.
Skill Development Best Practices
- Version your skills: Name them with versions if they change frequently (e.g.,
db-query-v2.js). When you roll out a breaking change, you can keep both versions in parallel and gradually migrate agents. - Document inputs/outputs: In manifest.json, be precise about types and requirements. This isn’t just for documentation—OpenClaw uses this to validate calls from agents.
- Add error handling: Skills should gracefully handle bad inputs and API failures. If your skill crashes, it takes the entire agent down. Use try-catch and return structured error objects.
- Test in isolation: Verify each skill works before adding to manifest. Write a simple test script that calls the skill directly, bypassing the OpenClaw framework. This catches bugs early.
- Monitor skill execution: Log every call with inputs, outputs, and timing. You’ll want to know which skills are slow, which ones fail, and which ones agents use most.
Common Skills Misconfigurations
Mistake 1: Directory doesn’t exist
{
"extraDirs": ["/opt/company-skills/v2"]
}
If this directory doesn’t exist, OpenClaw silently skips it. Then your agent can’t find the skills it needs. Always create directories before starting OpenClaw, or ensure your deployment process creates them.
Mistake 2: loadingPrecedence with no understanding of precedent
If you set "loadingPrecedence": "external-first" but have a skill with the same name as a built-in skill, your custom version wins. But if your custom version is buggy, you’ve silently broken OpenClaw’s core functionality. Test this carefully.
Mistake 3: Manifest.json is invalid JSON
If your manifest has syntax errors, OpenClaw can’t parse it, and all skills in that directory fail to load. Use jq to validate before deploying:
jq . /opt/custom-skills/manifest.json > /dev/null && echo "Valid" || echo "Invalid"
Mistake 4: Skills with side effects
A skill that modifies files or sends emails should have guard rails. What if an agent calls it with the wrong parameters? Or calls it in a loop? Skills should be idempotent or at least fail gracefully. Document side effects clearly in the manifest.
Section 5: Memory Configuration
How OpenClaw stores and manages agent memory across sessions.
Structure
"memory": {
"persistencePath": "~/.openclaw/memory",
"maxMemorySize": 52428800,
"softThresholdTokens": 40000,
"cachingEnabled": true,
"compressionEnabled": true,
"archiveOldLogs": true,
"archiveAfterDays": 30
}
Key Fields
persistencePath: Where daily logs and long-term memory files live. Should be readable/writable by the OpenClaw process.
maxMemorySize: Hard limit on total memory directory size (in bytes). 52428800 = 50MB. When exceeded, oldest logs get archived.
softThresholdTokens: Trigger for memory flush. At 40k tokens, OpenClaw compresses old context into daily logs.
cachingEnabled: Whether to cache frequently accessed memory segments. Speeds up repeated queries.
compressionEnabled: Whether to compress old daily logs. Saves disk space.
archiveOldLogs: Whether to move old logs to archive directory.
archiveAfterDays: Move logs older than this many days to archive.
Example: Tight Constraints
"memory": {
"persistencePath": "/tmp/openclaw-memory",
"maxMemorySize": 10485760,
"softThresholdTokens": 20000,
"cachingEnabled": true,
"compressionEnabled": true,
"archiveOldLogs": true,
"archiveAfterDays": 7
}
This keeps memory footprint small—10MB max, aggressive archiving after 7 days. Good for containerized deployments.
Example: Unlimited History
"memory": {
"persistencePath": "~/.openclaw/memory",
"maxMemorySize": 1099511627776,
"softThresholdTokens": 100000,
"cachingEnabled": true,
"compressionEnabled": false,
"archiveOldLogs": false
}
This prioritizes keeping history (1TB limit, no archiving). Good for research and analysis work where historical context matters.
Why You’d Change Memory Settings
softThresholdTokens: This is crucial to understand. When your agent’s working memory reaches this threshold, OpenClaw starts flushing old context to daily logs. Why does this matter?
- Too high (e.g., 100k): Your agent can hold more context, which means better reasoning over longer conversations. But if you set this higher than your LLM’s context window (which would be silly), you’ll waste memory. Also, flushing happens less often, so memory pressure builds up.
- Too low (e.g., 10k): Frequent flushing means old context gets compressed into daily logs often. This saves memory but might lose nuance. If you have a 100k token context limit, setting this to 10k is overkill.
The rule of thumb: set it to 40-50% of your LLM’s context limit. If you’re using Claude Opus (200k tokens), set it to 80-100k. If you’re using Haiku (100k tokens), set it to 40-50k.
compressionEnabled: Should you compress old logs? The math:
- true: Old logs get gzipped, saving ~70% disk space. But reading them requires decompression (slight latency hit). Good for disk-constrained deployments.
- false: No compression, takes more space, but instant access. Good if disk is cheap and you need maximum search speed.
Most teams should enable compression. Disk space is precious on cloud deployments.
maxMemorySize: This is your hard ceiling. When exceeded, oldest logs get deleted. Why would you set this low?
- Production servers: You don’t want memory to grow unbounded. Set a reasonable limit (50-100MB for most deployments).
- Containerized deployments: Containers have limited disk. Keep this conservative (10-20MB).
- Development machines: You can be loose here (100-500MB). You want history for debugging.
archiveAfterDays: How long before old logs get moved to an archive subdirectory?
- Shorter archival (7 days): Fast memory cleanup, but you lose recent history quickly.
- Longer archival (90 days): Better for root cause analysis. You can look back months and see what went wrong.
A reasonable default is 30 days. Old enough to preserve useful history, young enough to keep the active memory directory manageable.
Section 6: Runtime Configuration
Low-level system behavior. This is where you tune how OpenClaw actually runs on your hardware.
Structure
"runtime": {
"logLevel": "info",
"debugMode": false,
"concurrencyLimit": 10,
"requestIdPrefix": "req_",
"threadPoolSize": 4,
"enableMetrics": true,
"metricsPort": 9090
}
Key Fields
logLevel: Verbosity of system logs. This directly impacts performance and debugging ability.
debug– Everything. Every API call, every state change, every decision point. Extremely verbose, slows down the system because logging has overhead. Use only when debugging specific issues.info– Important events (default). Agent startups, skill invocations, errors. Good balance for production.warn– Only warnings and errors. If something goes wrong, you’ll know. But you won’t see normal operation. Use if you’re drowning in logs and only care about failures.error– Only errors. Minimizes overhead but you miss context. Only use if your system is extremely resource-constrained.
Pro tip: set to info in production, but have a way to temporarily bump to debug for troubleshooting (environment variable override, configuration hotload, etc.).
debugMode: If true, enable stack traces and verbose error messages. This is different from logLevel. Debug mode gives you full stack traces when things crash, which is invaluable for root cause analysis. But it also impacts performance. Disable in production unless you’re actively troubleshooting.
concurrencyLimit: Maximum concurrent agent tasks. This is critical to understand. It’s not the number of agents—it’s the number of tasks they can execute simultaneously.
- Too low (e.g., 2): Your agents can only run 2 tasks at a time. If you have 5 agents each trying to run a task, 3 of them queue up and wait. Bad for responsiveness.
- Too high (e.g., 100): You’re running 100 tasks simultaneously, each consuming CPU and memory. You might exhaust resources and the whole system tanks. Bad for stability.
The formula: (Number of agents) × (Average concurrent tasks per agent) × 1.5 (for headroom). If you have 5 agents each doing 2-3 concurrent tasks, use 15-25. If you have 20 agents each doing 1 task, use 30.
requestIdPrefix: Prefix for tracing requests through logs. When you enable this, every request gets a unique ID like req_abc123def456. Then you can search logs for that ID and see the entire request lifecycle. Use this in production—it’s invaluable for debugging multi-step workflows.
threadPoolSize: Number of worker threads. This is where your CPU cores matter.
- If you have 4 CPU cores and set threadPoolSize to 8, your OS will context-switch between threads, which has overhead.
- If you have 8 CPU cores and set threadPoolSize to 2, you’re underutilizing your hardware.
- The sweet spot: match your CPU core count. If you’re not sure, check
nprocon Unix or Task Manager on Windows.
For containerized deployments where your container can’t see all host cores, match the container’s CPU limit. If you have a 2-CPU container, use threadPoolSize of 2.
enableMetrics: Expose Prometheus-style metrics on metricsPort. Metrics include:
- Agent task counts (running, queued, completed)
- Response times (p50, p95, p99)
- Error rates
- Memory usage
- API call counts per agent
If you’re running agents in production, enable this. Feed metrics into Prometheus or Datadog, and you’ll see problems before users do.
metricsPort: Port to expose metrics. Only accessible on localhost by default. If you need to scrape metrics from a monitoring server, set this to a non-privileged port (e.g., 9090) and ensure your monitoring server can reach it.
Common Runtime Misconfigurations
Mistake 1: threadPoolSize > CPU cores
If you have 4 cores and set threadPoolSize to 16, you’re creating false concurrency. The OS will time-slice between threads, which adds context-switch overhead. Set it to your actual core count.
Mistake 2: concurrencyLimit too low for team use
If you set concurrencyLimit to 5 but have 10 engineers all sending requests, 5 of them queue up. Responsiveness suffers. Calculate it based on your load and leave headroom.
Mistake 3: debugMode enabled in production
Stack traces are useful for debugging, but they slow down error handling. Disable in production unless actively troubleshooting.
Mistake 4: logLevel set to debug permanently
Debug logging is expensive. Every log call is an I/O operation. If you enable it permanently, your throughput will drop noticeably. Set it to info and bump to debug only when needed.
Mistake 5: Not enabling metrics
Metrics are your early warning system. Without them, you’re flying blind. Enable them always (the performance impact is minimal).
Complete Annotated Example
Here’s a production-ready configuration with comments:
{
"version": "1.0.0",
// Network configuration
"gateway": {
"bind": "0.0.0.0",
"port": 8080,
"protocol": "https",
"tls": {
"certFile": "/etc/openclaw/certs/server.crt",
"keyFile": "/etc/openclaw/certs/server.key",
"minVersion": "1.2"
},
"auth": {
"type": "bearer",
"secret": "${OPENCLAW_AUTH_SECRET}"
},
"limits": {
"maxConnections": 500,
"requestTimeout": 30000,
"keepAliveTimeout": 60000
}
},
// AI Model configuration
"llm": {
"backend": "anthropic",
"models": [
{
"name": "default",
"provider": "anthropic",
"apiType": "rest",
"apiKey": "${ANTHROPIC_API_KEY}",
"apiUrl": "https://api.anthropic.com/v1",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 4096,
"temperature": 0.7
},
{
"name": "fast",
"provider": "anthropic",
"apiType": "rest",
"apiKey": "${ANTHROPIC_API_KEY}",
"apiUrl": "https://api.anthropic.com/v1",
"modelId": "claude-3-haiku-20250307",
"maxTokens": 1024,
"temperature": 0.5
}
],
"fallback": {
"enabled": true,
"models": ["fast"]
}
},
// Skills (reusable capabilities)
"skills": {
"builtin": true,
"extraDirs": [
"/opt/openclaw/company-skills",
"/home/team/.openclaw/custom-skills"
],
"loadingPrecedence": "external-first",
"autoReload": false,
"namespace": "skills"
},
// Memory and persistence
"memory": {
"persistencePath": "/var/lib/openclaw/memory",
"maxMemorySize": 104857600,
"softThresholdTokens": 40000,
"cachingEnabled": true,
"compressionEnabled": true,
"archiveOldLogs": true,
"archiveAfterDays": 30
},
// Runtime behavior
"runtime": {
"logLevel": "info",
"debugMode": false,
"concurrencyLimit": 20,
"requestIdPrefix": "prod_",
"threadPoolSize": 8,
"enableMetrics": true,
"metricsPort": 9090
}
}
Validation & Troubleshooting
Validating Your Config
Before deploying, validate your JSON:
cat ~/.openclaw/openclaw.json | jq . > /dev/null && echo "Valid" || echo "Invalid"
Common Mistakes
Trailing comma in object:
"llm": {
"backend": "anthropic",
// Missing comma above causes error
}
Missing quotes on keys:
{
"backend": "anthropic" // Error: keys need quotes
}
Incorrect environment variable:
{
"apiKey": "$ANTHROPIC_API_KEY" // Error: needs ${} wrapper
}
Non-existent directory:
{
"persistencePath": "/nonexistent/path" // Error: directory must exist or be creatable
}
Performance Tuning
For High Throughput
{
"gateway": {
"limits": {
"maxConnections": 2000,
"requestTimeout": 60000
}
},
"runtime": {
"concurrencyLimit": 50,
"threadPoolSize": 16
},
"memory": {
"cachingEnabled": true,
"softThresholdTokens": 50000
}
}
For Low Resource Usage
{
"gateway": {
"limits": {
"maxConnections": 50,
"requestTimeout": 15000
}
},
"runtime": {
"concurrencyLimit": 2,
"threadPoolSize": 2,
"logLevel": "warn"
},
"memory": {
"maxMemorySize": 10485760,
"softThresholdTokens": 20000,
"compressionEnabled": true
}
}
Validation, Testing & Verification
Once you’ve written your config, don’t just hope it works. Validate it systematically.
Step 1: JSON Syntax Validation
jq . ~/.openclaw/openclaw.json > /dev/null && echo "JSON valid" || echo "JSON invalid"
If this fails, you have syntax errors. Use jq to see what’s wrong:
jq . ~/.openclaw/openclaw.json
It’ll point to the exact line with the issue.
Step 2: Environment Variable Check
# Before starting OpenClaw, verify all required env vars exist
echo "Checking ANTHROPIC_API_KEY..."
[ -z "$ANTHROPIC_API_KEY" ] && echo "Missing!" || echo "Found"
This prevents the cryptic “authentication failed” messages later.
Step 3: Gateway Connectivity Test
Start OpenClaw and verify the gateway binds correctly:
# Check if port is listening
lsof -i :8080
# Should show:
# openclaw 12345 user 3u IPv4 0x... 0t0 TCP *:8080 (LISTEN)
Step 4: LLM Backend Test
Use OpenClaw’s CLI to test model connectivity:
openclaw test-llm --model default
This sends a simple prompt to your configured LLM. If it works, you’re good. If it fails, check:
- API key in environment
- API URL reachability
- Model ID validity
Step 5: Skills Loading Test
Verify custom skills loaded:
openclaw list-skills
# Should show:
# Built-in skills: 42
# Custom skills: 6
# Total: 48
Step 6: Memory System Initialization
Check that memory directories exist and are writable:
ls -la ~/.openclaw/memory/
# Should show: daily logs, archives, and cache directories
Configuration Scenarios by Use Case
Scenario 1: Personal Assistant (Single Machine)
{
"gateway": {
"bind": "127.0.0.1",
"port": 8080,
"protocol": "http"
},
"llm": {
"backend": "anthropic",
"models": [
{
"name": "default",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 4096,
"temperature": 0.7
}
]
},
"skills": {
"builtin": true,
"autoReload": true
},
"memory": {
"softThresholdTokens": 40000,
"archiveAfterDays": 30
},
"runtime": {
"logLevel": "info",
"concurrencyLimit": 2
}
}
This is minimal, local, and developer-friendly. autoReload is on so you can test skills immediately.
Scenario 2: Team Workspace (Shared Server)
{
"gateway": {
"bind": "192.168.1.100",
"port": 8080,
"protocol": "https",
"tls": {
"certFile": "/etc/openclaw/certs/server.crt",
"keyFile": "/etc/openclaw/certs/server.key"
},
"auth": {
"type": "bearer",
"secret": "${OPENCLAW_TEAM_TOKEN}"
}
},
"llm": {
"backend": "anthropic",
"models": [
{
"name": "default",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 4096
}
],
"fallback": {
"enabled": true,
"models": ["fast"]
}
},
"skills": {
"builtin": true,
"extraDirs": ["/opt/team-skills"],
"loadingPrecedence": "external-first",
"autoReload": false
},
"memory": {
"persistencePath": "/var/lib/openclaw/memory",
"maxMemorySize": 104857600,
"softThresholdTokens": 50000,
"archiveAfterDays": 30
},
"runtime": {
"logLevel": "warn",
"concurrencyLimit": 20,
"enableMetrics": true,
"metricsPort": 9090
}
}
This is production-grade: HTTPS, auth, shared skills, monitoring, and reasonable concurrency.
Scenario 3: CI/CD Integration
{
"gateway": {
"bind": "127.0.0.1",
"port": 8080,
"protocol": "http"
},
"llm": {
"backend": "ollama",
"models": [
{
"name": "default",
"apiUrl": "https://automateanddeploy.com:11434",
"modelId": "llama2:13b",
"maxTokens": 2048,
"temperature": 0.0
}
]
},
"skills": {
"builtin": true,
"extraDirs": ["/ci/openclaw-skills"],
"autoReload": false
},
"memory": {
"softThresholdTokens": 30000,
"cachingEnabled": false
},
"runtime": {
"logLevel": "error",
"debugMode": false,
"concurrencyLimit": 5
}
}
This trades latency for cost. Ollama (local models) runs on-machine. Temperature 0.0 ensures deterministic behavior in CI. Lower logging and higher memory flush threshold save resources.
Common Configuration Mistakes
Mistake 1: Hardcoding Secrets
// WRONG
{
"llm": {
"models": [
{
"apiKey": "sk-ant-v4-xxx..."
}
]
}
}
Never hardcode API keys. Use environment variables.
Mistake 2: maxConnections Too Low for Team Use
// Wrong for 5 engineers
{
"gateway": {
"limits": {
"maxConnections": 10
}
}
}
Each engineer’s session might use 2-3 concurrent connections. For 5 engineers, 100+ is reasonable.
Mistake 3: softThresholdTokens Set Too High
// Causes issues
{
"memory": {
"softThresholdTokens": 200000
}
}
If your LLM has a 100k token context limit, setting flush threshold to 200k is meaningless. Stay 20-30k below actual limits.
Mistake 4: Skills Directory Doesn’t Exist
// Fails silently
{
"skills": {
"extraDirs": ["/nonexistent/skills"]
}
}
Always verify directories exist before starting. OpenClaw creates memory directories but not custom ones.
Mistake 5: Wrong TLS Certificate Path
// Silent failure at startup
{
"gateway": {
"tls": {
"certFile": "/etc/certs/server.pem"
}
}
}
If path doesn’t exist, the whole gateway fails. Always validate certificate files exist and are readable.
Configuration Best Practices
1. Use Environment Variables for Secrets
{
"llm": {
"models": [
{
"apiKey": "${ANTHROPIC_API_KEY}"
}
]
},
"gateway": {
"auth": {
"secret": "${OPENCLAW_AUTH_SECRET}"
}
}
}
Then in your shell:
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENCLAW_AUTH_SECRET="your-secret-key"
2. Version Your Config
Keep backup versions:
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.20260317-backup
Before making big changes, backup. It’s saved my bacon more than once.
3. Use Comments (As JSONC)
While standard JSON doesn’t support comments, many tools understand JSONC (JSON with Comments):
{
// Primary API endpoint
"gateway": {
"bind": "0.0.0.0",
"port": 8080,
// Always use TLS in production
},
}
Some tools will strip comments automatically. Check your OpenClaw version.
4. Separate Dev and Prod Configs
~/.openclaw/
├── openclaw.json # Local development
├── openclaw.prod.json # Production
└── openclaw.ci.json # CI/CD
Then load the right one:
cp ~/.openclaw/openclaw.prod.json ~/.openclaw/openclaw.json
openclaw start
5. Document Your Choices
In MEMORY.md, record why you chose your config:
## OpenClaw Configuration Decisions
- **Concurrency Limit: 20**
- Team size: 5 engineers
- Each session: 2-3 concurrent tasks
- Headroom: 2x for spike handling
- **Memory Threshold: 40k tokens**
- LLM context: 100k tokens
- Working memory: ~40% of context
- Flush at 80% to avoid surprises
- **LLM Model: Claude Sonnet**
- Speed: 5-10 tokens/sec
- Cost: ~$0.003 per 1k tokens
- Fallback: Haiku for rate limit handling
This helps future you (and team members) understand “why” not just “what.”
Migrating Between Configurations
When you need to change your setup (e.g., moving from local to cloud), don’t just edit the file.
Safe Migration Steps
- Backup current state
bash
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.old
cp -r ~/.openclaw/memory ~/.openclaw/memory.backup
- Test new config with simulation
bash
openclaw validate-config ~/new-openclaw.json
- Migrate memory if needed
bash
# Copy old memory to new location (if changing persistencePath)
cp -r ~/.openclaw/memory/* /new/memory/path/
- Dry-run with new config
bash
openclaw start --config ~/new-openclaw.json --dry-run
- Switchover
bash
# If all checks pass
cp ~/new-openclaw.json ~/.openclaw/openclaw.json
openclaw restart
- Monitor and validate
bash
# Watch logs for errors
tail -f ~/.openclaw/openclaw.log
openclaw test-llm --model default
Performance Tuning from Configuration
Your config directly impacts performance.
For Maximum Speed:
- Increase threadPoolSize (match CPU cores)
- Decrease softThresholdTokens (less to carry in context)
- Enable caching:
"cachingEnabled": true - Disable debug mode:
"debugMode": false
For Maximum Reliability:
- Increase requestTimeout (slower network = need more time)
- Set concurrencyLimit conservatively (fewer simultaneous tasks = less contention)
- Enable compression:
"compressionEnabled": true - Disable autoReload for skills:
"autoReload": false
For Maximum Efficiency (Cost):
- Use cheaper model for fallback:
"claude-3-haiku" - Reduce maxTokens per response
- Archive aggressively:
"archiveAfterDays": 7 - Compress memory:
"compressionEnabled": true
Debugging Common Configuration Issues
Even with best practices, things go wrong. Here’s how to diagnose.
Issue: “Address Already in Use”
You start OpenClaw and it crashes with “Address already in use.”
# Find what's using your port
lsof -i :8080
# Kill the old process
kill -9 12345
# Or change the port in openclaw.json
# "port": 8081
Issue: “Authentication Failed”
LLM requests fail with “Authentication failed” but your API key is set.
# Verify the environment variable is actually set
echo $ANTHROPIC_API_KEY
# If empty, you didn't export it
export ANTHROPIC_API_KEY="sk-ant-..."
# If it's set, check the API URL
# Wrong: "apiUrl": "https://anthropic.com/v1"
# Right: "apiUrl": "https://api.anthropic.com/v1"
Issue: Skills Not Loading
You’ve written a custom skill but openclaw list-skills doesn’t show it.
# Check the directory exists
ls /opt/openclaw/company-skills
# Verify manifest.json is valid JSON
jq . /opt/openclaw/company-skills/manifest.json
# Check OpenClaw has read permission
ls -la /opt/openclaw/company-skills/
# Should show -r-- or -rw-
# Restart OpenClaw
openclaw restart
# Check logs
tail -f ~/.openclaw/openclaw.log | grep -i skill
Issue: Memory Directory Fails to Initialize
OpenClaw starts but memory operations fail.
# Check directory exists and is writable
ls -la ~/.openclaw/memory/
mkdir -p ~/.openclaw/memory
chmod 755 ~/.openclaw/memory
# If on a server, check disk space
df -h ~/.openclaw/memory/
# Check file permissions (should be readable by openclaw user)
ls -la ~/.openclaw/memory/
Issue: Configuration Changes Don’t Take Effect
You edit openclaw.json but nothing changes.
# OpenClaw reads config at startup, not continuously
# You must restart
openclaw restart
# Or explicitly load new config
openclaw start --config /path/to/new/openclaw.json
# Don't just reload; actually stop and start
openclaw stop
openclaw start
Advanced Configuration Patterns
Pattern 1: Environment-Specific Configs
Use shell variables to manage different environments:
# development.sh
export ENVIRONMENT=development
export ANTHROPIC_API_KEY="..."
export LOG_LEVEL=debug
openclaw start --config ~/.openclaw/openclaw.dev.json
# production.sh
export ENVIRONMENT=production
export ANTHROPIC_API_KEY="..."
export LOG_LEVEL=warn
openclaw start --config ~/.openclaw/openclaw.prod.json
Pattern 2: Configuration Inheritance
Create a base config and extend it:
// openclaw.base.json
{
"version": "1.0.0",
"gateway": {
"protocol": "https"
},
"llm": {
"backend": "anthropic"
}
}
// openclaw.dev.json (load after base)
{
"gateway": {
"bind": "127.0.0.1",
"port": 8080
},
"runtime": {
"debugMode": true
}
}
Then load both:
openclaw start --config ~/.openclaw/openclaw.base.json --config-overrides ~/.openclaw/openclaw.dev.json
Pattern 3: Dynamic Configuration Reloading
Some teams use a config manager to auto-update settings:
# In a CI pipeline or config management system
# 1. Generate new openclaw.json
generate-config.sh > openclaw.json.new
# 2. Validate it
jq . openclaw.json.new > /dev/null || exit 1
# 3. Swap files
mv openclaw.json.new ~/.openclaw/openclaw.json
# 4. Signal reload
kill -HUP $(pgrep openclaw)
This allows you to change settings without restarting (if OpenClaw supports HUP signals—check your version).
Configuration Monitoring
Monitor your configuration for drift or problems.
Config Audit Script
#!/bin/bash
# audit-openclaw-config.sh
echo "=== OpenClaw Configuration Audit ==="
# Check JSON validity
echo -n "JSON Syntax: "
jq . ~/.openclaw/openclaw.json > /dev/null && echo "PASS" || echo "FAIL"
# Check required files exist
echo -n "TLS Certificate: "
[ -f "$(jq -r '.gateway.tls.certFile' ~/.openclaw/openclaw.json)" ] && echo "PASS" || echo "FAIL"
# Check environment variables
echo -n "API Key Set: "
[ -n "$ANTHROPIC_API_KEY" ] && echo "PASS" || echo "FAIL"
# Check directory permissions
echo -n "Memory Directory Writable: "
[ -w ~/.openclaw/memory ] && echo "PASS" || echo "FAIL"
# Check port availability
PORT=$(jq -r '.gateway.port' ~/.openclaw/openclaw.json)
echo -n "Port $PORT Available: "
lsof -i :$PORT > /dev/null && echo "FAIL (in use)" || echo "PASS"
# Check skill directories exist
echo "Skill Directories:"
jq -r '.skills.extraDirs[]' ~/.openclaw/openclaw.json | while read dir; do
[ -d "$dir" ] && echo " ✓ $dir" || echo " ✗ $dir (missing)"
done
Run it regularly:
bash audit-openclaw-config.sh
This catches configuration drift before it becomes a problem.
Next Steps
Your openclaw.json is your system’s blueprint. Get it right once, and your agents run smoothly. Get it wrong, and you’ll spend hours debugging auth failures, memory issues, or skill loading problems.
The three-tier memory system (from the previous article) and this configuration layer are what make OpenClaw’s agent architecture actually work. Memory gives you persistence; configuration gives you control.
Once both are understood, you’re ready to build. Start with the personal assistant scenario, validate each layer, then scale up as your needs grow.
The configuration file looks like a lot, but it’s really just five sections:
- Gateway: How your agents talk to the world
- LLM: What brain your agents use
- Skills: What tools they can invoke
- Memory: How they remember
- Runtime: How they behave operationally
Master these five, and you’ve mastered OpenClaw’s core architecture.
-iNet