> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pioneer.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenClaw

> Configure OpenClaw to use Pioneer's OpenAI-compatible endpoint, discover models via /v1/models, and run the local gateway with Pioneer Auto.

Pioneer exposes an OpenAI-compatible inference endpoint, so OpenClaw can use Pioneer as a custom provider today. This guide covers the custom-provider setup until Pioneer is available as an official OpenClaw provider.

<Warning>
  OpenClaw is a third-party local agent tool. Keep the gateway bound to loopback unless you have intentionally hardened remote access, channel allowlists, and tool permissions.
</Warning>

### Prerequisites

* OpenClaw installed:

```shellscript theme={null}
npm install -g openclaw@latest
```

* A Pioneer API key from the Pioneer dashboard.
* `jq` installed for converting the live Pioneer model catalog into OpenClaw config.
* Check to see if OpenClaw is available:

```shellscript theme={null}
openclaw --version
```

### Setup steps

1. Save Pioneer auth in OpenClaw
   * Paste your Pioneer API key once. OpenClaw stores it in the local auth profile store and the gateway reuses it across terminal sessions.
     ```shellscript theme={null}
     openclaw models auth paste-api-key --provider pioneer
     ```
     <Note>
       Do not paste real API keys into docs, screenshots, shared shell history, or issue trackers. Rotate the key if it has been exposed.
     </Note>
2. Discover and register Pioneer models
   * Pioneer's supported inference models can change over time. Use the OpenAI-compatible `GET /v1/models` catalog as the source of truth and convert it directly into OpenClaw model config.
   * This command reads the Pioneer key from the OpenClaw auth profile saved in step 1, uses it for the catalog fetch, and writes the discovered model catalog into `~/.openclaw/openclaw.json`.
     ```shellscript theme={null}
     AUTH_DB="$(openclaw models auth list --provider pioneer --json | jq -r '.authStatePath')"
     case "$AUTH_DB" in
       "~/"*) AUTH_DB="$HOME/${AUTH_DB#"~/"}" ;;
     esac
     PIONEER_API_KEY="$(sqlite3 "$AUTH_DB" "select json_extract(store_json, '$.profiles.\"pioneer:manual\".key') from auth_profile_store where store_key = 'primary';")"
     : "${PIONEER_API_KEY:?Run openclaw models auth paste-api-key --provider pioneer first}"
     CONFIG_FILE="$(openclaw config file)"
     case "$CONFIG_FILE" in
       "~/"*) CONFIG_FILE="$HOME/${CONFIG_FILE#"~/"}" ;;
     esac
     [ -f "$CONFIG_FILE" ] || printf '{}\n' > "$CONFIG_FILE"
     curl -fsS "https://api.pioneer.ai/v1/models" \
       -H "Authorization: Bearer $PIONEER_API_KEY" \
       | jq --slurpfile current "$CONFIG_FILE" -c '
         def model_name:
           (.display_name // .name // .id)
           | split("/") | last
           | gsub("_"; " ")
           | gsub("-"; " ")
           | sub(" (?<major>[0-9]+) (?<minor>[0-9]+)(?= |$)"; " \(.major).\(.minor)")
           | gsub("\\bGpt\\b"; "GPT")
           | gsub("\\bOss\\b"; "OSS")
           | gsub("\\bAi\\b"; "AI")
           | gsub("(?<n>[0-9]+(\\.[0-9]+)?)b\\b"; "\(.n)B");
         def openclaw_model_id($id):
           if $id | startswith("pioneer/") then $id else "pioneer/" + $id end;PIONEER_API_KEY="$(sqlite3 "$AUTH_DB" "select json_extract(store_json, '$.profiles.\"pioneer:manual\".key') from auth_profile_store where store_key = 'primary';")"
     : "${PIONEER_API_KEY:?Run openclaw models auth paste-api-key --provider pioneer first}"
     CONFIG_FILE="$(openclaw config file)"
     case "$CONFIG_FILE" in
       "~/"*) CONFIG_FILE="$HOME/${CONFIG_FILE#"~/"}" ;;
     esac
     [ -f "$CONFIG_FILE" ] || printf '{}\n' > "$CONFIG_FILE"
     curl -fsS "https://api.pioneer.ai/v1/models" \
       -H "Authorization: Bearer $PIONEER_API_KEY" \
       | jq --slurpfile current "$CONFIG_FILE" -c '
         def model_name:
           (.display_name // .name // .id)
           | split("/") | last
           | gsub("_"; " ")
           | gsub("-"; " ")
           | sub(" (?<major>[0-9]+) (?<minor>[0-9]+)(?= |$)"; " \(.major).\(.minor)")
           | gsub("\\bGpt\\b"; "GPT")
           | gsub("\\bOss\\b"; "OSS")
           | gsub("\\bAi\\b"; "AI")
           | gsub("(?<n>[0-9]+(\\.[0-9]+)?)b\\b"; "\(.n)B");
         def openclaw_model_id($id):
           if $id | startswith("pioneer/") then $id else "pioneer/" + $id end;
         (
           [
             {
               id: "pioneer/auto",
               name: "Pioneer Auto",
               input: ["text"],
               contextWindow: 1000000,
               maxTokens: 16000
             }
           ] + (
             [
               .data[]
               | select(.deprecated != true)
               | select(.id != null)
               | select(.id | startswith("anthropic/") | not)
               | select(.id != "pioneer/auto" and .id != "auto")
               | {
                   id: .id,
                   name: model_name,
                   input: (["text"] + (if .capabilities.image_input.supported == true then ["image"] else [] end)),
                   contextWindow: (.max_input_tokens // .context_window // 128000),
                   maxTokens: (.max_tokens // 16000)
                 }
             ]
             | unique_by(.id)
             | sort_by(.id)
           )
         ) as $pioneer_models
         | ($current[0].agents.defaults.models // {}) as $current_agent_models
         | {
             models: {
               providers: {
                 pioneer: {
                   baseUrl: "https://api.pioneer.ai/v1",
                   api: "openai-completions",
                   models: $pioneer_models
                 }
               }
             },
             agents: {
               defaults: {
                 model: {primary: "pioneer/auto"},
                 models: (
                   ($current_agent_models | with_entries(select(.key | startswith("pioneer/") | not)))
                   + (
                     $pioneer_models
                     | map({key: openclaw_model_id(.id), value: {alias: .name}})
                     | from_entries
                   )
                 )
               }
             }
           }' \
       | openclaw config patch \
           --stdin \
           --replace-path models.providers.pioneer.models \
           --replace-path agents.defaults.models
     ```
     ```shellscript theme={null}
     AUTH_DB="$(openclaw models auth list --provider pioneer --json | jq -r '.authStatePath')"
     case "$AUTH_DB" in
       "~/"*) AUTH_DB="$HOME/${AUTH_DB#"~/"}" ;;
     esac
     PIONEER_API_KEY="$(sqlite3 "$AUTH_DB" "select json_extract(store_json, '$.profiles.\"pioneer:manual\".key') from auth_profile_store where store_key = 'primary';")"
     : "${PIONEER_API_KEY:?Run openclaw models auth paste-api-key --provider pioneer first}"
     CONFIG_FILE="$(openclaw config file)"
     case "$CONFIG_FILE" in
       "~/"*) CONFIG_FILE="$HOME/${CONFIG_FILE#"~/"}" ;;
     esac
     [ -f "$CONFIG_FILE" ] || printf '{}\n' > "$CONFIG_FILE"
     curl -fsS "https://api.pioneer.ai/v1/models" \
       -H "Authorization: Bearer $PIONEER_API_KEY" \
       | jq --slurpfile current "$CONFIG_FILE" -c '
         def dedupe:
           reduce .[] as $item ([]; if index($item) then . else . + [$item] end);
         def catalog_models:
           (.models // []) as $models
           | if (($models | type) == "array" and ($models | length) > 0) then $models else (.data // []) end;
         def model_id:
           .slug // .id;
         def model_name:
           (.display_name // .name // .id // .slug)
           | split("/") | last
           | gsub("_"; " ")
           | gsub("-"; " ")
           | sub(" (?<major>[0-9]+) (?<minor>[0-9]+)(?= |$)"; " \(.major).\(.minor)")
           | gsub("\\bGpt\\b"; "GPT")
           | gsub("\\bOss\\b"; "OSS")
           | gsub("\\bAi\\b"; "AI")
           | gsub("(?<n>[0-9]+(\\.[0-9]+)?)b\\b"; "\(.n)B");
         def bool_supported($value):
           $value == true or (($value | type) == "object" and $value.supported == true);
         def input_modalities:
           . as $row
           | (
               [
                 ($row.input // $row.inputs // $row.modalities // $row.input_modalities // $row.inputModalities // $row.capabilities.input // $row.capabilities.inputs // $row.capabilities.modalities // [])
                 | .[]?
                 | select(type == "string")
                 | ascii_downcase
                 | select(. == "text" or . == "image" or . == "audio" or . == "video")
               ]
               | dedupe
             ) as $inputs
           | (if ($inputs | length) > 0 then $inputs else ["text"] end) as $base
           | if ($row.capabilities.image_input.supported == true and (($base | index("image")) | not)) then $base + ["image"] else $base end;
         def reasoning_levels:
           [
             (.supported_reasoning_levels // .reasoning_levels // .supported_reasoning_efforts // .supportedReasoningLevels // .supportedReasoningEfforts // [])
             | .[]?
             | if type == "string" then . else (.effort // .id // .level // .name // empty) end
             | select(type == "string" and length > 0)
           ] | dedupe;
         def supports_reasoning:
           (reasoning_levels | length) > 0
           or bool_supported(.reasoning)
           or bool_supported(.supports_reasoning)
           or bool_supported(.supportsReasoning)
           or bool_supported(.thinking)
           or bool_supported(.capabilities.reasoning)
           or bool_supported(.capabilities.thinking);
         def openclaw_model_id($id):
           if $id | startswith("pioneer/") then $id else "pioneer/" + $id end;
         (
           [
             {
               id: "pioneer/auto",
               name: "Pioneer Auto",
               input: ["text"],
               contextWindow: 1000000,
               maxTokens: 16000
             }
           ] + (
             [
               catalog_models[]
               | select(.deprecated != true)
               | select(.object == null or .object == "model")
               | select(model_id != null)
               | select(model_id | startswith("anthropic/") | not)
               | select(model_id != "pioneer/auto" and model_id != "auto")
               | (reasoning_levels) as $levels
               | ({
                   id: model_id,
                   name: model_name,
                   reasoning: supports_reasoning,
                   input: input_modalities,
                   contextWindow: (.max_input_tokens // .context_window // .contextWindow // .context_length // .contextLength // 128000),
                   maxTokens: (.max_output_tokens // .max_tokens // .maxTokens // .max_completion_tokens // .maxCompletionTokens // 16000)
                 } + (if ($levels | length) > 0 then {compat: {supportedReasoningEfforts: $levels}} else {} end))
             ]
             | unique_by(.id)
             | sort_by(.id)
           )
         ) as $pioneer_models
         | ($current[0].agents.defaults.models // {}) as $current_agent_models
         | {
             models: {
               providers: {
                 pioneer: {
                   baseUrl: "https://api.pioneer.ai/v1",
                   api: "openai-completions",
                   models: $pioneer_models
                 }
               }
             },
             agents: {
               defaults: {
                 model: {primary: "pioneer/auto"},
                 models: (
                   ($current_agent_models | with_entries(select(.key | startswith("pioneer/") | not)))
                   + (
                     $pioneer_models
                     | map({key: openclaw_model_id(.id), value: {alias: .name}})
                     | from_entries
                   )
                 )
               }
             }
           }' \
       | openclaw config patch \
           --stdin \
           --replace-path models.providers.pioneer.models \
           --replace-path agents.defaults.models
     ```
     ```shellscript theme={null}
     AUTH_DB="$(openclaw models auth list --provider pioneer --json | jq -r '.authStatePath')"
     case "$AUTH_DB" in
       "~/"*) AUTH_DB="$HOME/${AUTH_DB#"~/"}" ;;
     esac
     PIONEER_API_KEY="$(sqlite3 "$AUTH_DB" "select json_extract(store_json, '$.profiles.\"pioneer:manual\".key') from auth_profile_store where store_key = 'primary';")"
     : "${PIONEER_API_KEY:?Run openclaw models auth paste-api-key --provider pioneer first}"
     CONFIG_FILE="$(openclaw config file)"
     case "$CONFIG_FILE" in
       "~/"*) CONFIG_FILE="$HOME/${CONFIG_FILE#"~/"}" ;;
     esac
     [ -f "$CONFIG_FILE" ] || printf '{}\n' > "$CONFIG_FILE"
     curl -fsS "https://api.pioneer.ai/v1/models" \
       -H "Authorization: Bearer $PIONEER_API_KEY" \
       | jq --slurpfile current "$CONFIG_FILE" -c '
         def dedupe:
           reduce .[] as $item ([]; if index($item) then . else . + [$item] end);
         def catalog_models:
           (.models // []) as $models
           | if (($models | type) == "array" and ($models | length) > 0) then $models else (.data // []) end;
         def model_id:
           .slug // .id;
         def model_name:
           (.display_name // .name // .id // .slug)
           | split("/") | last
           | gsub("_"; " ")
           | gsub("-"; " ")
           | sub(" (?<major>[0-9]+) (?<minor>[0-9]+)(?= |$)"; " \(.major).\(.minor)")
           | gsub("\\bGpt\\b"; "GPT")
           | gsub("\\bOss\\b"; "OSS")
           | gsub("\\bAi\\b"; "AI")
           | gsub("(?<n>[0-9]+(\\.[0-9]+)?)b\\b"; "\(.n)B");
         def bool_supported($value):
           $value == true or (($value | type) == "object" and $value.supported == true);
         def input_modalities:
           . as $row
           | (
               [
                 ($row.input // $row.inputs // $row.modalities // $row.input_modalities // $row.inputModalities // $row.capabilities.input // $row.capabilities.inputs // $row.capabilities.modalities // [])
                 | .[]?
                 | select(type == "string")
                 | ascii_downcase
                 | select(. == "text" or . == "image" or . == "audio" or . == "video")
               ]
               | dedupe
             ) as $inputs
           | (if ($inputs | length) > 0 then $inputs else ["text"] end) as $base
           | if ($row.capabilities.image_input.supported == true and (($base | index("image")) | not)) then $base + ["image"] else $base end;
         def reasoning_levels:
           [
             (.supported_reasoning_levels // .reasoning_levels // .supported_reasoning_efforts // .supportedReasoningLevels // .supportedReasoningEfforts // [])
             | .[]?
             | if type == "string" then . else (.effort // .id // .level // .name // empty) end
             | select(type == "string" and length > 0)
           ] | dedupe;
         def supports_reasoning:
           (reasoning_levels | length) > 0
           or bool_supported(.reasoning)
           or bool_supported(.supports_reasoning)
           or bool_supported(.supportsReasoning)
           or bool_supported(.thinking)
           or bool_supported(.capabilities.reasoning)
           or bool_supported(.capabilities.thinking);
         def openclaw_model_id($id):
           if $id | startswith("pioneer/") then $id else "pioneer/" + $id end;
         (
           [
             {
               id: "pioneer/auto",
               name: "Pioneer Auto",
               input: ["text"],
               contextWindow: 1000000,
               maxTokens: 16000
             }
           ] + (
             [
               catalog_models[]
               | select(.deprecated != true)
               | select(.object == null or .object == "model")
               | select(model_id != null)
               | select(model_id | startswith("anthropic/") | not)
               | select(model_id != "pioneer/auto" and model_id != "auto")
               | (reasoning_levels) as $levels
               | ({
                   id: model_id,
                   name: model_name,
                   reasoning: supports_reasoning,
                   input: input_modalities,
                   contextWindow: (.max_input_tokens // .context_window // .contextWindow // .context_length // .contextLength // 128000),
                   maxTokens: (.max_output_tokens // .max_tokens // .maxTokens // .max_completion_tokens // .maxCompletionTokens // 16000)
                 } + (if ($levels | length) > 0 then {compat: {supportedReasoningEfforts: $levels}} else {} end))
             ]
             | unique_by(.id)
             | sort_by(.id)
           )
         ) as $pioneer_models
         | ($current[0].agents.defaults.models // {}) as $current_agent_models
         | {
             models: {
               providers: {
                 pioneer: {
                   baseUrl: "https://api.pioneer.ai/v1",
                   api: "openai-completions",
                   models: $pioneer_models
                 }
               }
             },
             agents: {
               defaults: {
                 model: {primary: "pioneer/auto"},
                 models: (
                   ($current_agent_models | with_entries(select(.key | startswith("pioneer/") | not)))
                   + (
                     $pioneer_models
                     | map({key: openclaw_model_id(.id), value: {alias: .name}})
                     | from_entries
                   )
                 )
               }
             }
           }' \
       | openclaw config patch \
           --stdin \
           --replace-path models.providers.pioneer.models \
           --replace-path agents.defaults.models
     ```
   * The command manually adds `pioneer/auto` for Pioneer Auto, then reads the top-level `.models[]` catalog when present and falls back to the top-level `.models[]` catalog when present and falls back to `.data[]`, deduplicates by `id`, filters `anthropic/*` Claude Code discovery aliases so OpenClaw does not show duplicate models, and exposes every Pioneer model under `agents.defaults.models` for the model picker and `openclaw models status`.
   * OpenClaw uses `/think` for reasoning controls. Models that advertise `supported_reasoning_levels`, `reasoning`, `supports_reasoning`, or `thinking` metadata are registered with `reasoning: true`; when Pioneer advertises exact reasoning levels, the command also writes `compat.supportedReasoningEfforts` so OpenClaw can include levels such as `xhigh`.
   * OpenClaw uses `/think` for reasoning controls. Models that advertise `supported_reasoning_levels`, `reasoning`, `supports_reasoning`, or `thinking` metadata are registered with `reasoning: true`; when Pioneer advertises exact reasoning levels, the command also writes `compat.supportedReasoningEfforts` so OpenClaw can include levels such as `xhigh`.
   * To refresh the catalog later, re-run the same command. It replaces the Pioneer provider models and Pioneer agent allowlist while preserving non-Pioneer agent model entries.
3. Start the local gateway and open the Web UI
   * The model-discovery command already sets `pioneer/auto` as the default model. You do not need to run `openclaw models set pioneer/auto` separately.
   * Use the LaunchAgent service for normal local setup. Do not run `openclaw gateway run` unless you are intentionally debugging in the foreground.
     ```shellscript theme={null}
     openclaw config set gateway.mode local
     GATEWAY_TOKEN="$(openclaw config get gateway.auth.token 2>/dev/null || true)"
     if [ -z "$GATEWAY_TOKEN" ] || [ "$GATEWAY_TOKEN" = "null" ]; then
       GATEWAY_TOKEN="$(openssl rand -hex 32)"
       openclaw config set gateway.auth.token "$GATEWAY_TOKEN"
     fiGATEWAY_TOKEN="$(openclaw config get gateway.auth.token 2>/dev/null || true)"
     if [ -z "$GATEWAY_TOKEN" ] || [ "$GATEWAY_TOKEN" = "null" ]; then
       GATEWAY_TOKEN="$(openssl rand -hex 32)"
       openclaw config set gateway.auth.token "$GATEWAY_TOKEN"
     fi
     openclaw gateway install --force
     openclaw gateway restart
     openclaw dashboard
     unset GATEWAY_TOKEN
     ```
   * This avoids the noisy full `openclaw doctor` flow during normal setup. `openclaw gateway install --force` keeps the macOS LaunchAgent service definition current, including the service environment. `openclaw gateway restart` then applies the Pioneer model config and gateway token.
   * `openclaw dashboard` may print a clean URL such as `http://127.0.0.1:18789/` while copying a token-authenticated URL to your clipboard.
   * In the Web UI, choose a reasoning-capable Pioneer model and use the thinking selector to switch levels. From the CLI or chat input, send `/think low`, `/think medium`, `/think high`, or `/think off`. Send `/think` with no argument to see the current effective level.
   * In the Web UI, choose a reasoning-capable Pioneer model and use the thinking selector to switch levels. From the CLI or chat input, send `/think low`, `/think medium`, `/think high`, or `/think off`. Send `/think` with no argument to see the current effective level.
4. Verify the setup **(optional)**
   * These checks are useful when validating a fresh setup or debugging a user report:
     ```shellscript theme={null}
     openclaw models status --json \
       | jq '{defaultModel, allowed_count: (.allowed | length), first_allowed: .allowed[0:5]}'
     openclaw models status --probe --probe-provider pioneer
     ```
   * Expected result: `defaultModel` is `pioneer/auto`, `allowed_count` is greater than `1`, and the Pioneer auth probe succeeds.
   * OpenClaw may probe only the default/effective target even when the agent allowlist contains many Pioneer models. That is fine as long as the configured model count is greater than `1` and `pioneer/auto` probes successfully.
5. Run a first agent message from the CLI **(optional)**
   * OpenClaw needs a target session for agent messages. A plain `--message` is not enough.
     ```shellscript theme={null}
     openclaw agent --agent main --session-key cli-test --message "hello"
     ```
   * To continue the same local session:
     ```shellscript theme={null}
     openclaw agent --agent main --session-key cli-test --message "summarize the previous answer"
     ```
   * You can list sessions with:
     ```shellscript theme={null}
     openclaw sessions list
     ```

### Troubleshooting OpenClaw integration

<AccordionGroup>
  <Accordion title="Missing auth - pioneer" icon="key-round">
    OpenClaw does not have a Pioneer auth profile. Run:

    ```shellscript theme={null}
    openclaw models auth paste-api-key --provider pioneer
    openclaw models status --probe --probe-provider pioneer
    ```
  </Accordion>

  <Accordion title="Only pioneer/auto appears in OpenClaw" icon="list-filter">
    The catalog fetch likely did not read the saved OpenClaw auth profile. Confirm the Pioneer profile exists, then rerun the discovery command.

    Confirm the saved auth profile exists:

    ```shellscript theme={null}
    openclaw models auth list --provider pioneer
    ```

    Confirm the catalog exposes the expected Pioneer router models before rerunning the discovery command:

    ```shellscript theme={null}
    AUTH_DB="$(openclaw models auth list --provider pioneer --json | jq -r '.authStatePath')"
    case "$AUTH_DB" in "~/"*) AUTH_DB="$HOME/${AUTH_DB#"~/"}" ;; esac
    PIONEER_API_KEY="$(sqlite3 "$AUTH_DB" "select json_extract(store_json, '$.profiles.\"pioneer:manual\".key') from auth_profile_store where store_key = 'primary';")"

    curl -fsS "https://api.pioneer.ai/v1/models" \
      -H "Authorization: Bearer $PIONEER_API_KEY" \
      | jq -r '.data[].id | select(test("^pioneer/(auto|auto_v1|general)$"))'
    ```

    Expected output includes at least `pioneer/auto`. Versioned router entries such as `pioneer/auto_v1.1`, `pioneer/auto_v1.2`, and `pioneer/general` appear when they are exposed by the production catalog for your key. If the catalog output is correct, rerun the discovery command and restart the gateway.
  </Accordion>

  <Accordion title="Missing env var &#x22;PIONEER_API_KEY&#x22;" icon="terminal">
    This usually means the config points at an environment variable that is not visible to the OpenClaw process or gateway service. Prefer the auth-profile setup:

    ```shellscript theme={null}
    openclaw models auth paste-api-key --provider pioneer
    ```

    If you intentionally use an env reference, confirm the variable is visible to the process that runs OpenClaw:

    ```shellscript theme={null}
    test -n "$PIONEER_API_KEY" && echo "set" || echo "not set"
    ```

    For launchd, `launchctl setenv` does not persist across reboots and may not be enough if OpenClaw uses a generated service environment wrapper.
  </Accordion>

  <Accordion title="Gateway service not loaded" icon="plug-zap">
    Reinstall and restart the LaunchAgent:

    ```shellscript theme={null}
    openclaw gateway install --force
    openclaw gateway restart
    openclaw gateway status
    ```
  </Accordion>

  <Accordion title="No target session selected" icon="message-square">
    Pass a session target:

    ```shellscript theme={null}
    openclaw agent --agent main --session-key cli-test --message "hello"
    ```
  </Accordion>

  <Accordion title="Gateway already running or port 18789 is in use" icon="circle-alert">
    This usually means the LaunchAgent service is already bound to the gateway port. That is normal; do not start a second gateway with `openclaw gateway run`.

    For normal use, restart the service and open the Web UI:

    ```shellscript theme={null}
    openclaw gateway restart
    openclaw dashboard
    ```

    If `gateway status` says the service config is out of date, repair and restart:

    ```shellscript theme={null}
    openclaw doctor --repair
    openclaw gateway restart
    ```

    For foreground debugging only, stop the service first, then run the gateway in the foreground:

    ```shellscript theme={null}
    openclaw gateway stop
    openclaw gateway run
    ```
  </Accordion>

  <Accordion title="Dashboard auth required or gateway token mismatch" icon="shield-alert">
    Use the configured shared gateway token. The Control UI expects the same token from `gateway.auth.token` or `OPENCLAW_GATEWAY_TOKEN`:

    ```shellscript theme={null}
    openclaw config get gateway.auth.token
    ```

    Paste that value into the Web UI `Gateway Token` field and click **Connect**.

    If the command is empty, create a token and restart the gateway:

    ```shellscript theme={null}
    GATEWAY_TOKEN="$(openssl rand -hex 32)"
    openclaw config set gateway.auth.token "$GATEWAY_TOKEN"
    openclaw gateway install --force
    openclaw gateway restart
    openclaw dashboard
    unset GATEWAY_TOKEN
    ```

    Do not manually extract tokens from OpenClaw's SQLite state database.
  </Accordion>

  <Accordion title="Gateway is running but probe fails" icon="activity">
    Check reachability and logs:

    ```shellscript theme={null}
    openclaw gateway status
    openclaw gateway probe
    openclaw logs --follow
    ```
  </Accordion>
</AccordionGroup>
