Skill: caopulan/openclaw-config (version 0.1.0)

--- name: openclaw-config description: Edit and validate OpenClaw Gateway config (openclaw.json / JSON5). Use when adding/changing config keys (gateway.*, agents.*, models.*, channels.*, tools.*, skills.*, plugins.*, $include) or diagnosing openclaw doctor/config validation errors, to avoid schema mismatches that prevent the Gateway from starting or weaken security policies. --- # OpenClaw Config ## Overview Safely edit `~/.openclaw/openclaw.json` (or the path set by `OPENCLAW_CONFIG_PATH`) using a schema-first workflow. Validate before and after changes to avoid invalid keys/types that can break startup or change security behavior. ## Workflow (Safe Edit) 1. **Identify the active config path** - Precedence: `OPENCLAW_CONFIG_PATH` > `OPENCLAW_STATE_DIR/openclaw.json` > `~/.openclaw/openclaw.json` - The config file is **JSON5** (comments + trailing commas allowed). 2. **Get an authoritative schema (do not guess keys)** - If the Gateway is running: use `openclaw gateway call config.schema --params '{}'` to fetch a JSON Schema matching the running version. - Otherwise: use `openclaw/openclaw` source-of-truth, primarily: - `src/config/zod-schema.ts` (`OpenClawSchema` root keys like `gateway`/`skills`/`plugins`) - `src/config/zod-schema.*.ts` (submodules: channels/providers/models/agents/tools) - `docs/gateway/configuration.md` (repo docs + examples) 3. **Apply changes with the smallest safe surface** - Prefer small edits: `openclaw config get|set|unset` (dot path or bracket notation). - If the Gateway is online and you want "write + validate + restart" in one step: use RPC `config.patch` (merge patch) or `config.apply` (replaces the entire config; use carefully). - For complex setups, split config with `$include` (see below). 4. **Validate strictly** - Run `openclaw doctor`, then fix issues using the reported `path` + `message`. - Do not run `openclaw doctor --fix/--yes` without explicit user consent (it writes to config/state files). ## Guardrails (Avoid Schema Bugs) - **Most objects are strict** (`.strict()`): unknown keys usually fail validation and the Gateway will refuse to start. - `channels` is `.passthrough()`: extension channels (matrix/zalo/nostr, etc.) can add custom keys, but most provider configs remain strict. - `env` is `.catchall(z.string())`: you can put string env vars directly under `env`, and you can also use `env.vars`. - **Secrets**: prefer environment variables/credential files. Avoid committing long-lived tokens/API keys into `openclaw.json`. ## $include (Modular Config) `$include` is resolved before schema validation and lets you split config across JSON5 files: - Supports `"$include": "./base.json5"` or `"$include": ["./a.json5", "./b.json5"]` - Relative paths are resolved against the directory of the current config file. - Deep-merge rules (per implementation): - objects: merge recursively - arrays: **concatenate** (not replace) - primitives: later value wins - If sibling keys exist alongside `$include`, sibling keys override included values. - Limits: max depth 10; circular includes are detected and rejected. ## Common Recipes (Examples) 1. Set default workspace ```bash openclaw config set agents.defaults.workspace '"~/.openclaw/workspace"' --json openclaw doctor ``` 2. Change Gateway port ```bash openclaw config set gateway.port 18789 --json openclaw doctor ``` 3. Split config (example) ```json5 // ~/.openclaw/openclaw.json { "$include": ["./gateway.json5", "./channels/telegram.json5"], } ``` 4. Telegram open DMs (must explicitly allow senders) > Schema constraint: when `dmPolicy="open"`, `allowFrom` must include `"*"`. ```bash openclaw config set channels.telegram.dmPolicy '"open"' --json openclaw config set channels.telegram.allowFrom '["*"]' --json openclaw doctor ``` 5. Discord token (config or env fallback) ```bash # Option A: write to config openclaw config set channels.discord.token '"YOUR_DISCORD_BOT_TOKEN"' --json # Option B: env var fallback (still recommend a channels.discord section exists) # export DISCORD_BOT_TOKEN="..." openclaw doctor ``` 6. Enable web_search (Brave / Perplexity) ```bash openclaw config set tools.web.search.enabled true --json openclaw config set tools.web.search.provider '"brave"' --json # Recommended: provide the key via env var (or write tools.web.search.apiKey) # export BRAVE_API_KEY="..." openclaw doctor ``` ## Resources Load these when you need a field index or source locations: - `references/openclaw-config-fields.md` (root key index + key field lists with sources) - `references/schema-sources.md` (how to locate schema + constraints in openclaw repo) - `scripts/openclaw-config-check.sh` (print config path + run doctor)

path: agents/openai.yaml
content: interface:
  display_name: "OpenClaw Config"
  short_description: "Help edit and validate OpenClaw config"


path: references/openclaw-config-fields.md
content: # OpenClaw Config Field Index (openclaw.json)

Reference source version: `openclaw/openclaw@875324e` (2026-02-07). Fields can change across versions, so prefer `config.schema` from the running Gateway when possible.

Config file: `~/.openclaw/openclaw.json` (JSON5)
- Override path via `OPENCLAW_CONFIG_PATH`
- Split config via `$include` (semantics in `src/config/includes.ts`)

## Root Keys (OpenClawSchema)

The root object is strict; aside from `$include` preprocessing, unknown keys fail validation.

- `meta`: metadata written by the system (`lastTouchedVersion`, `lastTouchedAt`)
- `env`: shell env import + env var sugar (string catchall)
- `wizard`: wizard run metadata
- `diagnostics`: diagnostics/otel/cacheTrace
- `logging`: log level/output/redaction
- `update`: update channel + check-on-start
- `browser`: Browser/CDP settings
- `ui`: UI styling + assistant name/avatar
- `auth`: auth profiles/order/cooldowns
- `models`: model providers/definitions
- `nodeHost`: node host settings (currently includes browserProxy)
- `agents`: agents.defaults + agents.list
- `tools`: global tool policy + exec/web/media/links
- `bindings`: route channel/account/peer to agents
- `broadcast`: broadcast strategy + peer->agentId mapping
- `audio`: audio settings (e.g., transcription)
- `media`: media pipeline settings (e.g., preserveFilenames)
- `messages`: message behavior/prefixing (see session schema)
- `commands`: chat command settings (see session schema)
- `approvals`: approvals policy (see approvals schema)
- `session`: session policy (see session schema)
- `cron`: cron store/concurrency
- `hooks`: hooks server + gmail/internal mappings
- `web`: web socket/reconnect settings
- `channels`: channel providers (whatsapp/telegram/discord/slack/...)
- `discovery`: mdns/wideArea
- `canvasHost`: Canvas Host
- `talk`: talk/TTS shortcuts
- `gateway`: gateway service/auth/remote/tls/http endpoints/nodes
- `memory`: memory backend/citations/qmd
- `skills`: skills loading/install/entries
- `plugins`: plugins loading/entries/installs

## gateway (Commonly Edited Keys)

Source: `gateway` section in `src/config/zod-schema.ts`.

- `gateway.port`: number
- `gateway.mode`: `"local" | "remote"`
- `gateway.bind`: `"auto" | "lan" | "loopback" | "custom" | "tailnet"`
- `gateway.controlUi`:
  - `enabled`, `basePath`, `root`, `allowedOrigins`
  - `allowInsecureAuth`, `dangerouslyDisableDeviceAuth`
- `gateway.auth`:
  - `mode`: `"token" | "password"`
  - `token`, `password`, `allowTailscale`
- `gateway.trustedProxies`: string[]
- `gateway.tailscale`: `{ mode: "off" | "serve" | "funnel", resetOnExit }`
- `gateway.remote`:
  - `url`, `transport`: `"ssh" | "direct"`
  - `token`, `password`, `tlsFingerprint`
  - `sshTarget`, `sshIdentity`
- `gateway.reload`: `{ mode: "off" | "restart" | "hot" | "hybrid", debounceMs }`
- `gateway.tls`: `{ enabled, autoGenerate, certPath, keyPath, caPath }`
- `gateway.http.endpoints`:
  - `chatCompletions.enabled`
  - `responses.enabled`, `responses.maxBodyBytes`
  - `responses.files` / `responses.images` (allowUrl/allowedMimes/maxBytes/maxRedirects/timeoutMs, etc.)
- `gateway.nodes`:
  - `browser.mode`: `"auto" | "manual" | "off"`
  - `browser.node`: string
  - `allowCommands`, `denyCommands`: string[]

## skills / plugins (Install + Entries)

Source: `skills` / `plugins` sections in `src/config/zod-schema.ts`.

`skills`:
- `skills.allowBundled`: string[]
- `skills.load`: `{ extraDirs, watch, watchDebounceMs }`
- `skills.install`: `{ preferBrew, nodeManager: "npm"|"pnpm"|"yarn"|"bun" }`
- `skills.entries.<id>`:
  - `enabled`: boolean
  - `apiKey`: string
  - `env`: record<string,string>
  - `config`: record<string,unknown>

`plugins`:
- `plugins.enabled`: boolean
- `plugins.allow` / `plugins.deny`: string[]
- `plugins.load.paths`: string[]
- `plugins.slots.memory`: string
- `plugins.entries.<id>`: `{ enabled, config }`
- `plugins.installs.<id>`:
  - `source`: `"npm" | "archive" | "path"`
  - `spec`, `sourcePath`, `installPath`, `version`, `installedAt`

## channels / models / agents / tools (Use Schema Files)

These sections are large and can change quickly; locate keys via schema files instead of guessing:

- `channels`: `src/config/zod-schema.providers.ts` + `src/config/zod-schema.providers-core.ts`
  - Note: `channels` is passthrough (allows extension channel keys)
  - But each provider object (telegram/discord/slack/...) is usually strict
- `models`: `ModelsConfigSchema` in `src/config/zod-schema.core.ts`
- `agents`: `src/config/zod-schema.agents.ts` / `src/config/zod-schema.agent-defaults.ts` / `src/config/zod-schema.agent-runtime.ts`
- `tools`: `ToolsSchema` in `src/config/zod-schema.agent-runtime.ts`


path: references/schema-sources.md
content: # OpenClaw Config: Schema Sources

This skill is designed to prevent schema bugs (wrong key/type/missing constraint) that can stop the OpenClaw Gateway from starting or cause unsafe behavior changes.
The config format is **JSON5**, and most config objects are **strict** (unknown keys fail validation).

Reference source version: `openclaw/openclaw@875324e` (cloned on 2026-02-07).
Fields can change across versions, so prefer the schema from the OpenClaw version you are actually running.

## Priority: How To Confirm A Field Exists

1. When the Gateway is running (recommended)
   - Fetch the JSON Schema:
     - `openclaw gateway call config.schema --params '{}'`
   - Use `jq` or grep/search on the schema to confirm the field path exists before writing keys.

2. When the Gateway is not running / you need source-level constraints
   - Clone source:
     - `git clone https://github.com/openclaw/openclaw.git`
   - Key schema files:
     - Root schema: `src/config/zod-schema.ts` (`OpenClawSchema`)
     - `$include` semantics: `src/config/includes.ts`
     - agents/tools: `src/config/zod-schema.agents.ts`, `src/config/zod-schema.agent-defaults.ts`, `src/config/zod-schema.agent-runtime.ts`
     - models: `src/config/zod-schema.core.ts` (`ModelsConfigSchema`)
     - channels: `src/config/zod-schema.providers.ts`, `src/config/zod-schema.providers-core.ts`, `src/config/zod-schema.providers-whatsapp.ts`
     - session/messages/commands: `src/config/zod-schema.session.ts`
     - approvals: `src/config/zod-schema.approvals.ts`
   - Repo docs with lots of examples:
     - `docs/gateway/configuration.md`

## Fast Navigation (Do Not Guess Keys)

Run from the openclaw repo root:

```bash
rg -n "export const OpenClawSchema" src/config/zod-schema.ts
rg -n "\\bgateway:\\s*z" src/config/zod-schema.ts
rg -n "\\bskills:\\s*z" src/config/zod-schema.ts
rg -n "\\bplugins:\\s*z" src/config/zod-schema.ts

rg -n "export const ChannelsSchema" src/config/zod-schema.providers.ts
rg -n "DiscordConfigSchema|TelegramConfigSchema|SlackConfigSchema" src/config/zod-schema.providers-core.ts

rg -n "export const ModelsConfigSchema" src/config/zod-schema.core.ts
rg -n "export const ToolsSchema" src/config/zod-schema.agent-runtime.ts
```

## How To Read Validation Errors

`openclaw doctor` issues usually include:
- `path`: failing field path (most important)
- `message`: why it failed (type mismatch, unknown key, missing required key, cross-field constraint, etc.)

Fix strategy:
- **Unknown key**: the key does not exist in the schema (or is misspelled). Confirm the correct name in schema.
- **Type mismatch**: change to the schema's expected type (number/string/boolean/object/array).
- **Constraint failure (superRefine)**: satisfy related fields described by the message (for example: some channels require `allowFrom` to include `"*"` when `dmPolicy="open"`).


path: scripts/openclaw-config-check.sh
content: #!/usr/bin/env bash
set -euo pipefail

resolve_config_path() {
  if [[ -n "${OPENCLAW_CONFIG_PATH:-}" ]]; then
    echo "${OPENCLAW_CONFIG_PATH}"
    return 0
  fi

  local state_dir
  state_dir="${OPENCLAW_STATE_DIR:-${CLAWDBOT_STATE_DIR:-$HOME/.openclaw}}"
  echo "${state_dir%/}/openclaw.json"
}

resolve_mode() {
  if [[ -n "${OPENCLAW_CONFIG_PATH:-}" ]]; then
    echo "OPENCLAW_CONFIG_PATH"
    return 0
  fi
  if [[ -n "${OPENCLAW_STATE_DIR:-}" || -n "${CLAWDBOT_STATE_DIR:-}" ]]; then
    echo "OPENCLAW_STATE_DIR"
    return 0
  fi
  echo "default"
}

CONFIG_PATH="$(resolve_config_path)"
MODE="$(resolve_mode)"

echo "Config path (${MODE}): ${CONFIG_PATH}"

if [[ -f "${CONFIG_PATH}" ]]; then
  echo
  echo "Config file:"
  ls -la "${CONFIG_PATH}"

  # Permissions check (macOS + Linux)
  perms=""
  if perms="$(stat -f '%A' "${CONFIG_PATH}" 2>/dev/null)"; then
    :
  elif perms="$(stat -c '%a' "${CONFIG_PATH}" 2>/dev/null)"; then
    :
  else
    perms=""
  fi
  if [[ -n "${perms}" ]]; then
    echo "Permissions: ${perms}"
    if [[ "${perms}" =~ ^[0-9]+$ ]] && (( perms > 600 )); then
      echo "WARNING: config perms are >600; consider: chmod 600 \"${CONFIG_PATH}\""
    fi
  fi
else
  echo "Config file does not exist."
fi

echo
if command -v openclaw >/dev/null 2>&1; then
  echo "Running: openclaw doctor"
  openclaw doctor
else
  echo "openclaw CLI not found in PATH; skipping: openclaw doctor"
fi



Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)