Configuration Reference
GoClaw is configured via goclaw.json in the working directory.
Full Configuration Example
{
"llm": {
"providers": {
"anthropic": {
"driver": "anthropic",
"apiKey": "sk-ant-...",
"promptCaching": true
}
},
"agent": {
"models": ["anthropic/claude-sonnet-4-20250514"]
},
"subagent": {
"models": []
}
},
"channels": {
"telegram": {
"enabled": true,
"botToken": "123456:ABC..."
},
"whatsapp": {
"enabled": false
},
"http": {
"enabled": true,
"listen": ":1337"
}
},
"stt": {
"provider": "whispercpp",
"whispercpp": {
"model": "ggml-tiny.en.bin",
"modelsDir": "~/.goclaw/stt/whisper"
}
},
"voicellm": {
"enabled": false,
"default": "xai",
"providers": {
"xai": {
"driver": "xai",
"apiKey": "xai-...",
"voice": "Eve"
}
}
},
"session": {
"store": "sqlite",
"storePath": "~/.goclaw/sessions.db",
"inherit": false,
"inheritPath": "",
"inheritFrom": "",
"summarization": {
"ollama": {
"url": "http://localhost:11434",
"model": "qwen2.5:7b",
"timeoutSeconds": 600,
"contextTokens": 131072
},
"fallbackModel": "claude-3-haiku-20240307",
"failureThreshold": 3,
"resetMinutes": 30,
"retryIntervalSeconds": 60,
"checkpoint": {
"enabled": true,
"thresholds": [25, 50, 75],
"turnThreshold": 10,
"minTokensForGen": 5000
},
"compaction": {
"reserveTokens": 4000,
"maxMessages": 500,
"preferCheckpoint": true,
"keepPercent": 50,
"minMessages": 20,
"freshTailCount": 10,
"freshTailMaxTokens": 4000,
"lcm": {
"preset": "balanced",
"enabled": true,
"summaryInjectionMode": "frontier",
"maxInjectedSummaryTokens": 4000,
"summaryMaxOverageFactor": 3
}
}
},
"memoryFlush": {
"enabled": true,
"showInSystemPrompt": true,
"thresholds": [
{"percent": 50, "prompt": "Consider noting key decisions.", "injectAs": "system", "oncePerCycle": true},
{"percent": 75, "prompt": "Write important context now.", "injectAs": "user", "oncePerCycle": true}
]
}
},
"memory": {
"enabled": true,
"dbPath": "",
"paths": [],
"query": {
"maxResults": 6,
"minScore": 0.35,
"vectorWeight": 0.7,
"keywordWeight": 0.3
}
},
"skills": {
"enabled": true,
"watch": true,
"watchDebounceMs": 500,
"entries": {}
},
"tools": {
"exec": {
"timeout": 1800,
"bubblewrap": {
"enabled": false
}
},
"browser": {
"enabled": false
},
"web": {
"braveApiKey": "",
"useBrowser": "auto",
"profile": "default",
"headless": true
},
"subagent": {
"enabled": true
}
},
"media": {
"dir": "~/.goclaw/media",
"maxSize": 104857600,
"cleanup": {
"enabled": true,
"interval": 300
},
"quotas": {
"global": 53687091200,
"uploads": 536870912,
"keeper": 536870912
},
"categories": {
"browser": {
"ttl": 86400,
"quota": 536870912
},
"downloads": {
"ttl": 86400,
"quota": 536870912
}
}
},
"promptCache": {
"pollInterval": 60
},
"gateway": {
"workingDir": "~/.goclaw/workspace",
"logFile": "~/.goclaw/goclaw.log",
"pidFile": "~/.goclaw/goclaw.pid",
"delegatedRuns": {
"enabled": true,
"maxSpawnDepth": 4,
"maxActiveChildrenPerParent": 4,
"maxConcurrentRuns": 16,
"defaultTimeoutSeconds": 300,
"maxTimeoutSeconds": 1800
}
},
"acp": {
"defaultDriver": "grok",
"drivers": {
"cursor": {
"model": "claude-4.6-opus-high-thinking"
},
"grok": {
"model": "grok-build"
}
}
}
}
Configuration Sections
Core
| Section | Description | Documentation |
|---|---|---|
agent | Agent name, emoji, personality | Below |
llm | LLM provider settings and purpose chains | LLM Providers |
session | Session storage, compaction, checkpoints | Session Management |
memory | Semantic memory search | Memory Search |
memoryGraph | Knowledge graph extraction and bulletins | Memory Graph |
transcript | Conversation transcript indexing | Transcript Search |
Channels
| Section | Description | Documentation |
|---|---|---|
channels.telegram | Telegram bot configuration | Telegram |
channels.whatsapp | WhatsApp via linked device | |
channels.http | Web UI, chat, and voice | Web UI |
channels.tui | Terminal UI settings | TUI |
Voice & Audio
| Section | Description | Documentation |
|---|---|---|
stt | Speech-to-text transcription | Below |
voicellm | Real-time voice conversations | Voice |
Tools
| Section | Description | Documentation |
|---|---|---|
tools.exec | Shell command execution | Tools |
tools.browser | Browser automation | Browser Tool |
tools.web | Web search and fetch | Tools |
tools.subagent | Owner-only subagent and fanout tools | Delegated Runs |
tools.xaiImagine | xAI image generation | Tools |
tools.xaiVideo | xAI video generation | Tools |
skills | Skills system | Skills |
Dependency note: subagent tools only appear when both tools.subagent.enabled=true and gateway.delegatedRuns.enabled=true.
System
| Section | Description | Documentation |
|---|---|---|
media | Temporary media storage | Below |
promptCache | Workspace file caching | Below |
a2a | Agent-to-agent networking over libp2p | A2A Networking |
acp | ACP driver defaults and model preferences | ACP Sessions |
gateway | Server settings | Below |
auth | Role elevation via external script | User Auth Tool |
roles | Role-based access control definitions | Roles |
cron | Scheduled jobs and heartbeat | Cron |
safety | Panic stop phrases | Security |
sandbox | Execution isolation (bubblewrap/seatbelt) | Sandbox |
supervision | Ghostwriting and guidance | Supervision |
homeassistant | Home Assistant integration | Home Assistant |
Quick Reference
LLM Settings
{
"llm": {
"providers": {
"anthropic": {
"driver": "anthropic",
"apiKey": "sk-ant-...",
"promptCaching": true
},
"xai": {
"driver": "xai",
"authMethod": "device-code",
"authProfile": "xai:default"
},
"hugot-local": {
"driver": "hugot",
"embeddingOnly": true
}
},
"agent": {
"models": ["anthropic/claude-sonnet-4-20250514"]
},
"subagent": {
"models": []
},
"embeddings": {
"models": ["hugot-local/KnightsAnalytics/all-MiniLM-L6-v2"]
}
}
}
| Field | Type | Description |
|---|---|---|
providers | object | Named provider instances (alias → config) |
agent | object | Model chain for main conversation |
subagent | object | Model chain used internally for subagent and fanout runs (falls back to agent) |
summarization | object | Model chain for compaction/checkpoints |
embeddings | object | Model chain for semantic search |
GoClaw keeps a built-in local embeddings provider named hugot-local in llm.providers. If llm.embeddings.models is empty, GoClaw seeds the default local embeddings model automatically. If you already configured an embeddings chain, GoClaw leaves it unchanged.
For xAI Grok and OpenAI/Codex, setup can store account login tokens in an encrypted auth profile instead of placing tokens in goclaw.json. In Web or TUI setup, choose device-code for the remote-friendly pairing flow or oauth for browser login. The provider config stores only authMethod (api-key, device-code, or oauth) and authProfile (xai:default or openai-codex:default); GoClaw keeps the actual OAuth refresh/access tokens in ~/.goclaw/auth-profiles.enc.json.
Auth profile encryption keys are resolved in this order:
GOCLAW_AUTH_PROFILE_SECRET_KEY: 32-byte key encoded as base64/base64url or 64 hex characters.GOCLAW_AUTH_PROFILE_SECRET_FILE: path to a file containing the same key format.~/.goclaw/auth-profile.key: generated automatically with0600permissions when no env-backed key is configured.
The setup editor also exposes auth profile IDs for xAI image/video tools, so they can reuse the same xAI login when configured. Browser OAuth supports a manual redirect URL/code paste path when a loopback callback is not reachable.
See LLM Providers for full configuration details.
Telegram Settings
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "123456:ABC..."
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable Telegram bot |
botToken | string | - | Bot token from @BotFather |
The setup wizard (goclaw setup) can detect TELEGRAM_BOT_TOKEN from your environment and offer to use it.
When Telegram is enabled in goclaw setup, the browser and TUI setup flows now include an owner-pairing step. GoClaw shows a one-time code and waits for the owner to send that exact code to the bot. The resolved Telegram user ID is staged in setup state and written to users.json only when you finish the wizard or save changes from setup edit mode.
WhatsApp Settings
{
"channels": {
"whatsapp": {
"enabled": true
}
}
}
WhatsApp uses the linked device protocol (no business API required). The setup wizard and setup editor can now drive this directly with a live QR pairing flow in both the browser and TUI. The linked owner JID/phone is staged in setup state and written to users.json only when you finish the wizard or save changes from setup edit mode.
HTTP Settings
{
"channels": {
"http": {
"enabled": true,
"listen": ":1337"
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | true when unset | Enable HTTP/Web UI |
listen | string | :1337 | Listen address (:port or host:port) |
Session Storage
{
"session": {
"store": "sqlite",
"storePath": "~/.goclaw/sessions.db",
"inherit": true,
"inheritPath": "~/.openclaw/agents/main/sessions",
"inheritFrom": "main"
}
}
| Field | Type | Default | Description |
|---|---|---|---|
store | string | "sqlite" | Storage backend (always sqlite) |
storePath | string | ~/.goclaw/sessions.db | SQLite database path |
inherit | bool | true | Enable OpenClaw session inheritance |
inheritPath | string | - | Path to OpenClaw sessions directory |
inheritFrom | string | - | Session key to inherit from |
See Session Management for compaction, checkpoints, memory flush, fresh-tail retention, and Lossless Context Management.
Media Storage
{
"media": {
"dir": "~/.goclaw/media",
"maxSize": 104857600,
"cleanup": {
"enabled": true,
"interval": 300
},
"quotas": {
"global": 2147483648,
"uploads": 536870912,
"keeper": 536870912
},
"categories": {
"browser": {
"ttl": 86400,
"quota": 536870912
},
"camera": {
"ttl": 3600,
"quota": 536870912
},
"generated": {
"ttl": 604800,
"quota": 1073741824
},
"downloads": {
"ttl": 86400,
"quota": 536870912
},
"voice": {
"ttl": 3600,
"quota": 536870912
}
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
dir | string | ~/.goclaw/media | Base media directory |
maxSize | int | 104857600 | Max size for a single saved file (100 MB) |
cleanup.enabled | bool | true | Run background cleanup for temporary categories |
cleanup.interval | int | 300 | Cleanup interval in seconds |
quotas.global | int | 53687091200 | Total quota across all categories (50 GB) |
quotas.uploads | int | 536870912 | Soft quota for uploads (preserved, warning only) |
quotas.keeper | int | 536870912 | Soft quota for keeper (preserved, warning only) |
categories.browser.ttl | int | 86400 | Browser artifact retention in seconds |
categories.browser.quota | int | 536870912 | Browser quota in bytes |
categories.camera.ttl | int | 3600 | Camera retention in seconds |
categories.camera.quota | int | 536870912 | Camera quota in bytes |
categories.generated.ttl | int | 604800 | Generated media retention in seconds |
categories.generated.quota | int | 1073741824 | Generated media quota in bytes |
categories.downloads.ttl | int | 86400 | Download retention in seconds |
categories.downloads.quota | int | 536870912 | Downloads quota in bytes |
categories.voice.ttl | int | 3600 | Voice output retention in seconds |
categories.voice.quota | int | 536870912 | Voice quota in bytes |
Top-level media policies are category-aware:
uploadsandkeeperare preserved and never auto-deletedbrowser,camera,generated,downloads, andvoiceare temporary and may be cleaned based on TTL and quota- nested paths inherit the policy of their top-level category
The setup UI exposes live usage, Refresh Usage, and Clean Now actions for media storage. Agents can also inspect the same live state through the media tool with action: "info".
Prompt Cache
{
"promptCache": {
"pollInterval": 60
}
}
| Field | Type | Default | Description |
|---|---|---|---|
pollInterval | int | 60 | Hash check interval in seconds (0 = disabled) |
The prompt cache watches workspace identity files (SOUL.md, AGENTS.md, etc.) for changes.
Gateway
{
"gateway": {
"workingDir": "~/.goclaw/workspace",
"logFile": "~/.goclaw/goclaw.log",
"pidFile": "~/.goclaw/goclaw.pid",
"delegatedRuns": {
"enabled": true,
"maxSpawnDepth": 4,
"maxActiveChildrenPerParent": 4,
"maxConcurrentRuns": 16
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
workingDir | string | ~/.goclaw/workspace | Workspace directory |
logFile | string | - | Log file path |
pidFile | string | - | PID file path |
delegatedRuns.enabled | bool | true | Enable subagents, fanout, and other delegated background runs |
delegatedRuns.maxSpawnDepth | int | 4 | Max parent-child subagent depth (0 = unlimited) |
delegatedRuns.maxActiveChildrenPerParent | int | 4 | Max active child runs per parent (0 = unlimited) |
delegatedRuns.maxConcurrentRuns | int | 16 | Max delegated/background runs at once (0 = unlimited) |
delegatedRuns.defaultTimeoutSeconds | int | 300 | Default time limit for delegated runs when a tool/job does not set one |
delegatedRuns.maxTimeoutSeconds | int | 1800 | Maximum delegated run timeout for safety (0 = unlimited) |
A2A Settings
GoClaw’s A2A subsystem lets one GoClaw node talk to another over libp2p. This covers peer discovery, relay-backed communication, pairing payloads, and remote task handoff.
{
"a2a": {
"enabled": true,
"defaultTransport": "libp2p",
"libp2p": {
"enabled": true,
"listenAddrs": [
"/ip4/0.0.0.0/tcp/0",
"/ip4/0.0.0.0/udp/0/quic-v1"
],
"discovery": {
"rendezvousEnabled": true,
"bootstrapSeedTXT": "p2p_boot.goclaw.org",
"registerIntervalSeconds": 30,
"queryIntervalSeconds": 30
},
"relay": {
"enableClient": true,
"enableServer": false,
"enableAutoRelay": true,
"enableHolePunch": true,
"enableBackgroundDirectUpgrade": true,
"directUpgradeTimeoutSeconds": 3,
"directUpgradeCooldownSeconds": 30
}
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable the A2A subsystem |
defaultTransport | string | "libp2p" | Active transport. Current release supports libp2p |
libp2p.enabled | bool | false | Enable the libp2p transport |
libp2p.listenAddrs | string[] | local TCP + QUIC ephemeral ports | Listen addresses for the local node |
libp2p.announceAddrs | string[] | [] | Optional explicit advertised addresses |
libp2p.discovery.bootstrapPeers | string[] | [] | Explicit bootstrap multiaddrs |
libp2p.discovery.bootstrapSeedTXT | string | p2p_boot.goclaw.org | DNS TXT fallback for bootstrap discovery when bootstrapPeers is empty |
libp2p.discovery.rendezvousEnabled | bool | true | Enable GoClaw rendezvous registration and lookup |
libp2p.discovery.registerIntervalSeconds | int | 30 | Registration refresh interval |
libp2p.discovery.queryIntervalSeconds | int | 30 | Rendezvous query interval |
libp2p.relay.enableClient | bool | true | Allow relay-backed connectivity |
libp2p.relay.enableServer | bool | false | Offer relay service from this node |
libp2p.relay.enableAutoRelay | bool | true | Use bootstrap peers as relay candidates |
libp2p.relay.enableHolePunch | bool | true | Allow libp2p hole punching |
libp2p.relay.enableBackgroundDirectUpgrade | bool | true | After a relay-backed outbound request, try a short background direct dial for future traffic when direct candidates are known |
libp2p.relay.directUpgradeTimeoutSeconds | int | 3 | Timeout for one background direct-upgrade attempt |
libp2p.relay.directUpgradeCooldownSeconds | int | 30 | Minimum time between background direct-upgrade attempts per peer |
Behavior notes:
- Relay remains the immediate working path when direct connectivity is not ready yet.
- Background direct upgrade does not delay the live
ping,submit,resume, orcanceloperation that triggered it. - This setting improves future connection quality only when the direct upgrade succeeds.
For full A2A usage and behavior, see A2A Networking .
ACP Sessions
ACP has its own top-level acp config section in goclaw.json and its own dedicated setup-editor section in both the web UI and the TUI.
{
"acp": {
"defaultDriver": "grok",
"drivers": {
"cursor": {
"model": "claude-4.6-opus-high-thinking"
},
"grok": {
"model": "grok-build"
}
}
}
}
Current scope:
cursorandgrokdrivers- local stdio transport only
- session-scoped attachment rather than global process configuration
| Field | Type | Default | Description |
|---|---|---|---|
defaultDriver | string | grok | ACP driver used when attach omits an explicit driver (cursor or grok) |
drivers.cursor.model | string | claude-4.6-opus-high-thinking | Friendly Cursor model alias to apply after attach |
drivers.grok.model | string | grok-build | Friendly Grok model alias to apply after attach (xAI’s chat proxy currently 404s on grok-build-latest for some teams) |
Each saved driver model is a single effective string. The setup editors offer per-driver curated known-model dropdowns plus a custom entry path, but only the final drivers.<driver>.model string is written into config.
The Refresh Cursor Models / Refresh Grok Models actions rebuild an in-memory model catalog for the current running process by talking to that ACP agent. The refreshed catalog repopulates the dropdown in the setup editors but is not persisted into goclaw.json.
Refresh failures leave the currently visible list unchanged. Each driver’s refresh action is always shown; if the driver cannot refresh models live (e.g. the binary is missing on PATH or the cached login is missing for Grok), the action returns a normal error.
If you are looking for ACP workflow and command details, see ACP Sessions and Channel Commands .
Speech-to-Text (STT)
{
"stt": {
"provider": "whispercpp",
"whispercpp": {
"model": "ggml-tiny.en.bin",
"modelsDir": "~/.goclaw/stt/whisper"
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
provider | string | "whispercpp" | Provider: whispercpp, openai, groq, google |
whispercpp.model | string | ggml-tiny.en.bin | Model filename |
whispercpp.modelsDir | string | ~/.goclaw/stt/whisper | Models directory |
openai.apiKey | string | - | OpenAI API key (for Whisper API) |
groq.apiKey | string | - | Groq API key |
google.apiKey | string | - | Google Cloud API key |
Local whisper.cpp is the default and runs offline. Models are downloaded via the setup wizard or goclaw setup edit. The .deb package includes ggml-tiny.en.bin at /usr/share/goclaw/stt/.
Voice LLM (Real-time Voice)
{
"voicellm": {
"enabled": true,
"default": "xai",
"serverVAD": true,
"idleTimeout": 300,
"providers": {
"xai": {
"driver": "xai",
"apiKey": "xai-...",
"voice": "Eve",
"sampleRate": 48000
}
}
}
}
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable real-time voice |
default | string | - | Default provider name |
serverVAD | bool | true | Server-side voice activity detection |
idleTimeout | int | 300 | Idle timeout in seconds |
providers | object | - | Named provider configs |
Provider config:
| Field | Type | Default | Description |
|---|---|---|---|
driver | string | - | xai |
apiKey | string | - | Provider API key |
voice | string | Eve | Voice name (Eve, Ara, Rex, Sal, Leo) |
sampleRate | int | 48000 | Audio sample rate |
See Voice for full documentation including prompt customization and browser requirements.
No Environment Variables for Runtime Config
Secrets and settings are read only from goclaw.json (and users.json). Environment variables are not used at runtime, to avoid unexpected overrides.
During setup: If you run goclaw setup and have ANTHROPIC_API_KEY, TELEGRAM_BOT_TOKEN, or BRAVE_API_KEY set in your environment (e.g. from OpenClaw), the wizard will detect them and ask whether to use each one. If you accept, they are written into goclaw.json. After that, runtime uses only the config file.
Auth (Role Elevation)
{
"auth": {
"enabled": true,
"script": "/home/user/.goclaw/scripts/auth.sh",
"credentialHints": [
{"key": "customer_id", "label": "Customer ID", "required": true},
{"key": "phone", "label": "phone number"},
{"key": "email", "label": "email address"}
],
"allowedRoles": ["customer", "user"],
"rateLimit": 3,
"timeout": 10
}
}
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable the user_auth tool |
script | string | - | Path to authentication script |
credentialHints | object[] | [] | Credentials the script accepts |
credentialHints[].key | string | - | JSON field name |
credentialHints[].label | string | key | Friendly name for agent to use |
credentialHints[].required | boolean | false | Mark as required |
allowedRoles | string[] | [] | Roles the script can return |
rateLimit | int | 3 | Max auth attempts per minute |
timeout | int | 10 | Script timeout in seconds |
The user_auth tool allows guest users to authenticate mid-session and be elevated to a higher role. The credentialHints tell the agent what information to ask for (with friendly labels) and which credentials are required.
See User Auth Tool for full documentation.
Security: config file and credentials
Sandbox and location
Config is sandboxed from the agent. The read, write, and edit tools cannot access goclaw.json, users.json, or openclaw.json. These filenames are on a denied list
in the file-tools sandbox and are blocked even if they appear inside the workspace. The agent cannot read or modify API keys or user credentials through file tools.
Config is stored outside the workspace directory in the normal layout. The default config path is ~/.goclaw/goclaw.json; the default workspace (where the agent reads/writes) is ~/.goclaw/workspace or a path you set (e.g. a project directory). So the config file is not inside the agent’s workspace. If you use a local goclaw.json in the current directory, it can be alongside the workspace but remains inaccessible to the agent because of the denied list. For stricter setups, keep goclaw.json in ~/.goclaw/ with mode 0600 and avoid committing it.
Environment variable references
GoClaw does not automatically scan environment variables for API keys. However, you can explicitly reference env vars using ${VAR_NAME} syntax:
{
"llm": {
"providers": {
"anthropic": {
"apiKey": "${ANTHROPIC_API_KEY}"
}
}
}
}
- At runtime —
${VAR}references are expanded when starting the gateway or CLI commands - In setup wizard — The literal
${VAR_NAME}text is preserved for editing - Missing vars — GoClaw fails with a clear error if a referenced variable is not set
This is useful for Kubernetes, Docker, CI/CD pipelines, and other deployment systems that inject secrets via environment.
For the full rationale (why explicit references rather than auto-scanning, security considerations, best practice), see Environment variables and secrets .
Users Configuration
User access is configured in users.json:
{
"users": [
{
"name": "Alice",
"role": "owner",
"identities": [
{"provider": "telegram", "id": "123456789"}
]
},
{
"name": "Ratpup",
"role": "user",
"identities": [
{"provider": "telegram", "id": "987654321"}
],
"permissions": ["read", "write", "exec"]
}
]
}
| Field | Description |
|---|---|
name | Display name |
role | "owner" (full access) or "user" (limited) |
identities | Array of identity providers and IDs |
permissions | Tool whitelist for non-owner users |
sandbox | false to bypass file sandboxing |
thinking | true to show tool calls by default |
thinkingLevel | Thinking intensity (off/minimal/low/medium/high) |
See Roles for detailed access control documentation.
See Also
- Session Management — Compaction, checkpoints, memory flush
- LLM Providers — Multi-provider setup
- Tools — Tool configuration
- A2A Networking — A2A overview, relay behavior, and manual usage
- ACP Sessions — ACP runtime attachment and workflow
- Skills — Skills system
- Architecture — System overview