# 6. OpenClaw 設定參考

### 6.1 主設定結構 `/root/.openclaw/openclaw.json`

```json5
{
  "meta": { "lastTouchedVersion": "2026.2.25" },

  // Agent 預設設定
  "agents": {
    "defaults": {
      "model": {
        "primary": "google-antigravity/gemini-3-flash"
      },
      "workspace": "/root/.openclaw/workspace",
      "compaction": { "mode": "safeguard" },
      "maxConcurrent": 4,
      "subagents": { "maxConcurrent": 8 }
    }
  },

  // Telegram 頻道
  "channels": {
    "telegram": {
      "enabled": true,
      "botToken": "<your-bot-token>",
      "dmPolicy": "pairing",   // 只有配對裝置可以 DM
      "groupPolicy": "allowlist",
      "streamMode": "partial"
    }
  },

  // Gateway 設定
  "gateway": {
    "port": 18789,
    "mode": "local",
    "bind": "loopback",  // 只接受本機連線，由 nginx 代理
    "auth": {
      "mode": "token",
      "token": "<access-token>"
    }
  },

  // 訊息設定
  "messages": {
    "ackReactionScope": "group-mentions"
  }
}
```

### 6.2 多 Agent / 多模型設定（獨立 Bot Token 方案）

> **踩坑紀錄（2026-02-24 ~ 02-25，v2026.2.17）**
> - 文件範例用 `agentId`，但實際 schema 要用 **`id`**（否則報 `Unrecognized key: "agentId"`）
> - `bindings` 需要 **`match` 包裝層**，不是直接放 `channel` / `accountId`
> - 新 Bot 必須**先完成 config + 重啟 Gateway 後**才按 `/start`，否則配對碼不會回傳
> - 各獨立 agent 的 `auth-profiles.json` 不會自動共享，需手動複製
> - **（2026-02-25 新增）** 當使用 `accounts` 區塊後，頂層 `botToken` **不再被當作獨立通道啟動**。所有 Bot（包含主 Bot）都必須放入 `accounts` 內，否則 `channels list` 不會列出、provider 也不會啟動。主 Bot 建議使用 `"default"` 作為 accountId。
> - **（2026-02-25 新增）** `agents.list` 只有具名 agent（如 life-assistant）時，**隱含的預設 agent 不會掃描 workspace skills**。必須在 `agents.list` 明確加入 `main` agent（含 workspace 路徑），並在 `bindings` 加入 `{ "agentId": "main", "match": { "channel": "telegram", "accountId": "default" } }` 綁定。否則 workspace skills（如 daily-briefing）不會載入。

#### 正確的 config 格式（已驗證可用）

```json5
{
  // 1. channels：所有 Bot Token 都放在 accounts 下
  //    頂層 botToken 在使用 accounts 後不再啟動為獨立通道
  "channels": {
    "telegram": {
      "enabled": true,
      "dmPolicy": "pairing",
      "groupPolicy": "allowlist",
      "streamMode": "partial",
      "accounts": {
        "default": {                          // 主 Bot（@Cimon168_bot）
          "botToken": "<主 Bot Token>"
        },
        "life-bot": {                         // accountId，自訂名稱
          "botToken": "<新 Bot Token>"        // @Cimon_life_bot
        }
      }
    }
  },

  // 2. agents.list：用 "id" 不是 "agentId"
  //    主 agent 也必須明確列出，否則 workspace skills 不會載入
  "agents": {
    "list": [
      {
        "id": "main",                        // 主 agent，必須明確列出
        "name": "主 Agent",
        "model": { "primary": "cliapi/gpt-5.3-codex" },
        "workspace": "/home/selig/.openclaw/workspace"
      },
      {
        "id": "life-assistant",              // <- 必須用 "id"
        "name": "生活助理",
        "model": { "primary": "cliapi/gpt-5.3-codex" },
        "workspace": "/home/selig/.openclaw/agents/life-assistant"
      }
    ],
    "defaults": { "..." }
  },

  // 3. bindings：match 包裝層（channel + accountId 放 match 內）
  //    每個 account 都需要綁定到對應 agent
  "bindings": [
    {
      "agentId": "main",                    // 主 Bot → main agent
      "match": {
        "channel": "telegram",
        "accountId": "default"
      }
    },
    {
      "agentId": "life-assistant",           // 這裡用 agentId
      "match": {                             // <- 必須有 match 物件
        "channel": "telegram",
        "accountId": "life-bot"              // 對應 accounts 裡的 key
      }
    }
  ]
}
```

#### 安裝步驟

```bash
# 1. BotFather /newbot → 取得 Token
# 2. 建立 agent 目錄
mkdir -p ~/.openclaw/agents/<agent-name>/{agent,sessions}
# 3. 修改 ~/.openclaw/openclaw.json（按上方格式）
# 4. 重啟 Gateway
systemctl --user restart openclaw-gateway
# 5. 確認 log 無錯誤
journalctl --user -u openclaw-gateway --since "30 sec ago" --no-pager
# 6. 在 Telegram 新 Bot 發送 /start → 取得配對碼
# 7. 配對
openclaw pairing approve telegram <CODE>
```

#### 目前已部署的 Agent

| Agent ID | Bot | 用途 | Model |
|----------|-----|------|-------|
| main | @Cimon168_bot | 工作/專案/協調 | cliapi/gpt-5.3-codex |
| life-assistant | @Cimon_life_bot | 生活安排 | cliapi/gpt-5.3-codex |

### 6.3 CLIProxyAPI 連線設定

CLIProxyAPI 作為 OpenAI-compatible proxy，讓 OpenClaw 可以使用多種 AI 帳號：

```json5
// 在 openclaw.json 加入 custom provider
{
  "models": {
    "providers": {
      "cliapi": {
        "baseUrl": "http://127.0.0.1:8317/v1",
        "apiKey": "<management-key>",
        "api": "openai-completions"
      }
    }
  }
}
```

CLIProxyAPI 管理介面：`http://192.168.31.169:8317/management.html`

### 6.3.1 CLIProxyAPI LLM 輪換規則

> 原始碼位置：`sdk/cliproxy/auth/selector.go`、`config.yaml`

#### 輪換策略：Round-Robin（按請求次數）

**不是依時間輪換**，而是每一個 API request 進來就推進一格。

```
每個 (provider, model) 組合 → 獨立計數器 (cursor)
cursor → 每次請求 +1
選取：available[cursor % len(available)]
```

目前設定（`/home/docker/CLIProxyAPI/config.yaml`）：

```yaml
routing:
  strategy: "round-robin"   # 另一選項：fill-first（固定燒第一個帳號）
request-retry: 3            # 失敗後最多重試 3 次（自動換下一個憑證）
max-retry-interval: 30      # 冷卻等待上限 30 秒
quota-exceeded:
  switch-project: true      # Quota 超限時自動切換帳號
  switch-preview-model: true
```

#### 失敗重試（Fallback）

觸發條件（HTTP 狀態碼）：`403 / 408 / 500 / 502 / 503 / 504`

- 遇到錯誤 → cursor 繼續推進 → 下次自動選到不同憑證
- 不是獨立的「備援」邏輯，而是 round-robin 繼續走的自然結果

#### 冷卻機制（Quota 超限）

- 憑證觸發 **429** → 進入冷卻，指數退避（底數 1s，上限 30min）
- 冷卻中的憑證從可用池排除，round-robin 只從未冷卻憑證中選
- 冷卻時間到後自動恢復可用

#### 活躍 Provider（目前）

| Provider | 模型類型 |
|----------|---------|
| Grok (xai) | grok-4 系列、grok-code、grok-imagine |
| api.navy | qwen3.5、claude-sonnet-4.6、text-embedding |

### 6.3.2 CLIProxyAPI 模型清單自動更新

當 CLIProxyAPI 新增/移除 AI provider 後，OpenClaw 不會自動偵測到新模型。需要更新 `openclaw.json` 中的 `models.providers.cliapi.models` 陣列。

**自動更新腳本**：`~/clawd/scripts/refresh-llm-list.sh`

```bash
# 手動執行
bash ~/clawd/scripts/refresh-llm-list.sh

# 排程：每週日 02:00（crontab）
0 2 * * 0 /home/selig/clawd/scripts/refresh-llm-list.sh >> /var/log/refresh-llm-list.log 2>&1
```

**腳本流程**：
1. 從 CLIProxyAPI `/v1/models` 取得最新模型清單
2. 依模型名稱自動分級（high/mid/low → 不同 cost 設定）
3. 備份 `openclaw.json` → `openclaw.json.bak`
4. 更新模型陣列，保留其他設定不變
5. 重啟 Gateway
6. 輸出差異（新增/移除的模型）

**日誌**：`/var/log/refresh-llm-list.log`

**模型分級規則**：
| 級別 | 關鍵字 | input cost | contextWindow |
|------|--------|-----------|---------------|
| high | opus, pro-high, thinking, codex-max, pro-preview | 0.3 | 1M |
| mid | sonnet, grok, qwen, 預設 | 0.14 | 128K |
| low | haiku, flash-lite, embedding, mini | 0.07 | 128K |
| GPT | gpt-* | 0.2 | 128K |

### 6.3.3 發送 Telegram 訊息（通知 Agent）

```bash
# 發送訊息到指定群組或用戶
sudo openclaw message send --channel telegram --target <chat-id> -m "訊息內容"

# 群組 ID 對照
# kaiwu（開物）：-5178404192
# tiangong（天工）：-5249018181
# yucheng（玉成）：-5296222979

# 範例：通知開物群組
sudo openclaw message send --channel telegram --target -5178404192 -m "preview 網站已上線"

# 附帶圖片
sudo openclaw message send --channel telegram --target -5178404192 -m "截圖" --media /path/to/image.png

# 靜音發送（不觸發通知音）
sudo openclaw message send --channel telegram --target -5178404192 -m "背景通知" --silent
```

### 6.4 Session Scope 設定

```json5
{
  "agents": {
    "defaults": {
      "session": {
        // 推薦：每個 Telegram 用戶獨立 session，防止資訊洩漏
        "dmScope": "per-channel-peer",
        // 每日 04:00 自動重置 session
        "reset": { "schedule": "0 4 * * *" }
      }
    }
  }
}
```

### 6.5 Auth Profiles（模型認證）

位置：`/root/.openclaw/agents/main/auth-profiles.json`

```json5
{
  "version": 1,
  "profiles": {
    "anthropic:manual": {
      "type": "token",
      "provider": "anthropic",
      "token": "sk-ant-..."
    },
    "cliapi:main": {
      "type": "api-key",
      "provider": "openai-compat",
      "apiKey": "<key>",
      "baseUrl": "http://127.0.0.1:8317/v1"
    }
  }
}
```

### 6.6 Heartbeat（心跳巡查）

Agent 定期自動觸發巡查，執行 `HEARTBEAT.md` 中定義的任務。

**預設間隔**（原始碼邏輯）：
- `gateway.auth.mode = "oauth"` → `1h`
- 其他模式（token、local） → `30m`

**設定方式**：
```json5
{
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m"    // 所有 agent 預設間隔（支援 "15m", "1h", "2h" 等）
      }
    },
    "list": [
      {
        "id": "main",
        "heartbeat": {
          "every": "15m"  // 個別 agent 覆寫
        }
      }
    ]
  }
}
```

**指令**：
```bash
# 查看目前設定
openclaw config get agents.defaults.heartbeat

# 修改全域間隔
openclaw config set agents.defaults.heartbeat.every "15m"

# 修改單一 agent（需知道 list index，如 main 是 index 0）
openclaw config set agents.list.0.heartbeat.every "20m"
```

**巡查內容**：定義在各 agent workspace 的 `HEARTBEAT.md`，例如：
- `~/.openclaw/workspace/HEARTBEAT.md`（主 agent）
- `~/.openclaw/agents/life-assistant/HEARTBEAT.md`（生活助理）

**Telegram 頻道 heartbeat 可見性**：
```json5
{
  "channels": {
    "telegram": {
      "heartbeat": "silent"  // "visible" | "silent" | "hidden"
    }
  }
}
```

### 6.7 Exec Approvals（指令執行審批）

Agent 執行 shell 指令（`exec` tool）時的安全策略。**兩個地方都需要設定**：

#### 主控制：`openclaw.json` → `tools.exec`

這是**真正的 policy 控制點**，決定 agent 能否自動執行指令：

```json5
{
  "tools": {
    "exec": {
      "security": "full",   // "deny" | "allowlist" | "full"
      "ask": "off"           // "off" | "on-miss" | "always"
    }
  }
}
```

| security | 行為 |
|----------|------|
| `deny` | 封鎖所有 exec（sandbox 預設） |
| `allowlist` | 只允許白名單內的指令（**gateway/node 未設時的預設值**） |
| `full` | 允許所有指令 |

| ask | 行為 |
|-----|------|
| `off` | 永不詢問 |
| `on-miss` | 指令不在白名單時才詢問（**預設值**） |
| `always` | 每次都詢問 |

```bash
# 設定指令
openclaw config set tools.exec.security full
openclaw config set tools.exec.ask off
# 重啟 Gateway 生效
systemctl --user restart openclaw-gateway
```

#### 輔助儲存：`~/.openclaw/exec-approvals.json`

儲存 allowlist（已核准的指令清單）和 socket 資訊，**不是主要 policy 控制點**：

```bash
# 查看
openclaw approvals get
# 設定（覆寫整個檔案）
openclaw approvals set --stdin < file.json
```

> **踩坑（2026-03-02）**：只設定 `exec-approvals.json` 的 `defaults.security=full` + `defaults.ask=off` **不會生效**。必須在 `openclaw.json` 的 `tools.exec` 設定才是真正的控制點。未設定 `tools.exec` 時，預設為 `security: "allowlist"` + `ask: "on-miss"`，導致 Telegram agent 每次執行指令都需要手動批准，而 Telegram 無法批准 → 120 秒超時。

#### Safe Bins（免審批的安全指令）

以下 stdin-only 工具即使在 `allowlist` 模式下也不需要白名單：
- `jq`, `cat`, `head`, `tail`, `cut`, `uniq`, `tr`, `wc`
- 可透過 `tools.exec.safeBins` 自訂
- 信任目錄：`/bin`, `/usr/bin`（可透過 `tools.exec.safeBinTrustedDirs` 擴充）
