diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6b0876596fd..3534d41f0e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -105,7 +105,6 @@ Docs: https://docs.openclaw.ai
- Agents/usage tracking: stop forcing `supportsUsageInStreaming: false` on non-native OpenAI-completions providers so compatible backends report token usage and cost again instead of showing all zeros. (#46500) Fixes #46142. Thanks @ademczuk.
- Plugins/subagents: preserve gateway-owned plugin subagent access across runtime, tool, and embedded-runner load paths so gateway plugin tools and context engines can still spawn and manage subagents after the loader cache split. (#46648) Thanks @jalehman.
- Control UI/overview: keep the language dropdown aligned with the persisted locale during dashboard startup so refreshing the page does not fall back to English before locale hydration completes. (#48019) Thanks @git-jxj.
-- Agents/compaction: rerun transcript repair after `session.compact()` so orphaned `tool_result` blocks cannot survive compaction and break later Anthropic requests. (#16095) thanks @claw-sylphx.
## 2026.3.13
@@ -184,7 +183,6 @@ Docs: https://docs.openclaw.ai
- Auth/login lockout recovery: clear stale `auth_permanent` and `billing` disabled state for all profiles matching the target provider when `openclaw models auth login` is invoked, so users locked out by expired or revoked OAuth tokens can recover by re-authenticating instead of waiting for the cooldown timer to expire. (#43057)
- Auto-reply/context-engine compaction: persist the exact embedded-run metadata compaction count for main and followup runner session accounting, so metadata-only auto-compactions no longer undercount multi-compaction runs. (#42629) thanks @uf-hy.
- Auth/Codex CLI reuse: sync reused Codex CLI credentials into the supported `openai-codex:default` OAuth profile instead of reviving the deprecated `openai-codex:codex-cli` slot, so doctor cleanup no longer loops. (#45353) thanks @Gugu-sugar.
-- WhatsApp/group replies: recognize implicit reply-to-bot mentions when WhatsApp sends the quoted sender in `@lid` format, including device-suffixed self identities. (#23029) Thanks @sparkyrider.
## 2026.3.12
@@ -276,7 +274,6 @@ Docs: https://docs.openclaw.ai
- Agents/Anthropic replay: drop replayed assistant thinking blocks for native Anthropic and Bedrock Claude providers so persisted follow-up turns no longer fail on stored thinking blocks. (#44843) Thanks @jmcte.
- Docs/Brave pricing: escape literal dollar signs in Brave Search cost text so the docs render the free credit and per-request pricing correctly. (#44989) Thanks @keelanfh.
- Feishu/file uploads: preserve literal UTF-8 filenames in `im.file.create` so Chinese and other non-ASCII filenames no longer appear percent-encoded in chat. (#34262) Thanks @fabiaodemianyang and @KangShuaiFu.
-- Agents/compaction safeguard: trim large kept `toolResult` payloads consistently for budgeting, pruning, and identifier seeding, then restore preserved payloads after prune so oversized safeguard summaries stay stable. (#44133) thanks @SayrWolfridge.
## 2026.3.11
diff --git a/README.md b/README.md
index fee53d83065..418e2a070af 100644
--- a/README.md
+++ b/README.md
@@ -23,10 +23,10 @@ It answers you on the channels you already use (WhatsApp, Telegram, Slack, Disco
If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.
-[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Wizard](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
+[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Onboarding](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
-Preferred setup: run the onboarding wizard (`openclaw onboard`) in your terminal.
-The wizard guides you step by step through setting up the gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
+Preferred setup: run `openclaw onboard` in your terminal.
+OpenClaw Onboard guides you step by step through setting up the gateway, workspace, channels, and skills. It is the recommended CLI setup path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
Works with npm, pnpm, or bun.
New install? Start here: [Getting started](https://docs.openclaw.ai/start/getting-started)
@@ -58,7 +58,7 @@ npm install -g openclaw@latest
openclaw onboard --install-daemon
```
-The wizard installs the Gateway daemon (launchd/systemd user service) so it stays running.
+OpenClaw Onboard installs the Gateway daemon (launchd/systemd user service) so it stays running.
## Quick start (TL;DR)
@@ -132,7 +132,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
- **[Live Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
- **[First-class tools](https://docs.openclaw.ai/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions.
- **[Companion apps](https://docs.openclaw.ai/platforms/macos)** — macOS menu bar app + iOS/Android [nodes](https://docs.openclaw.ai/nodes).
-- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — wizard-driven setup with bundled/managed/workspace skills.
+- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — onboarding-driven setup with bundled/managed/workspace skills.
## Star History
@@ -143,7 +143,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
### Core platform
- [Gateway WS control plane](https://docs.openclaw.ai/gateway) with sessions, presence, config, cron, webhooks, [Control UI](https://docs.openclaw.ai/web), and [Canvas host](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
-- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [wizard](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor).
+- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [onboarding](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor).
- [Pi agent runtime](https://docs.openclaw.ai/concepts/agent) in RPC mode with tool streaming and block streaming.
- [Session model](https://docs.openclaw.ai/concepts/session): `main` for direct chats, group isolation, activation modes, queue modes, reply-back. Group rules: [Groups](https://docs.openclaw.ai/channels/groups).
- [Media pipeline](https://docs.openclaw.ai/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.openclaw.ai/nodes/audio).
@@ -422,7 +422,7 @@ Use these when you’re past the onboarding flow and want the deeper reference.
- [Run the Gateway by the book with the operational runbook.](https://docs.openclaw.ai/gateway)
- [Learn how the Control UI/Web surfaces work and how to expose them safely.](https://docs.openclaw.ai/web)
- [Understand remote access over SSH tunnels or tailnets.](https://docs.openclaw.ai/gateway/remote)
-- [Follow the onboarding wizard flow for a guided setup.](https://docs.openclaw.ai/start/wizard)
+- [Follow OpenClaw Onboard for a guided setup.](https://docs.openclaw.ai/start/wizard)
- [Wire external triggers via the webhook surface.](https://docs.openclaw.ai/automation/webhook)
- [Set up Gmail Pub/Sub triggers.](https://docs.openclaw.ai/automation/gmail-pubsub)
- [Learn the macOS menu bar companion details.](https://docs.openclaw.ai/platforms/mac/menu-bar)
diff --git a/docs/channels/bluebubbles.md b/docs/channels/bluebubbles.md
index 9c2f0eb6de4..bf328656ff3 100644
--- a/docs/channels/bluebubbles.md
+++ b/docs/channels/bluebubbles.md
@@ -126,7 +126,7 @@ launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plist
## Onboarding
-BlueBubbles is available in the interactive setup wizard:
+BlueBubbles is available in interactive onboarding:
```
openclaw onboard
diff --git a/docs/channels/feishu.md b/docs/channels/feishu.md
index 41882e78264..ad018aa4d03 100644
--- a/docs/channels/feishu.md
+++ b/docs/channels/feishu.md
@@ -30,9 +30,9 @@ openclaw plugins install @openclaw/feishu
There are two ways to add the Feishu channel:
-### Method 1: setup wizard (recommended)
+### Method 1: onboarding (recommended)
-If you just installed OpenClaw, run the setup wizard:
+If you just installed OpenClaw, run onboarding:
```bash
openclaw onboard
diff --git a/docs/channels/nostr.md b/docs/channels/nostr.md
index 46888da0352..c8d5d69753b 100644
--- a/docs/channels/nostr.md
+++ b/docs/channels/nostr.md
@@ -16,7 +16,7 @@ Nostr is a decentralized protocol for social networking. This channel enables Op
### Onboarding (recommended)
-- The setup wizard (`openclaw onboard`) and `openclaw channels add` list optional channel plugins.
+- Onboarding (`openclaw onboard`) and `openclaw channels add` list optional channel plugins.
- Selecting Nostr prompts you to install the plugin on demand.
Install defaults:
diff --git a/docs/channels/telegram.md b/docs/channels/telegram.md
index b5700213830..2758982b8d7 100644
--- a/docs/channels/telegram.md
+++ b/docs/channels/telegram.md
@@ -115,7 +115,7 @@ Token resolution order is account-aware. In practice, config values win over env
`channels.telegram.allowFrom` accepts numeric Telegram user IDs. `telegram:` / `tg:` prefixes are accepted and normalized.
`dmPolicy: "allowlist"` with empty `allowFrom` blocks all DMs and is rejected by config validation.
- The setup wizard accepts `@username` input and resolves it to numeric IDs.
+ Onboarding accepts `@username` input and resolves it to numeric IDs.
If you upgraded and your config contains `@username` allowlist entries, run `openclaw doctor --fix` to resolve them (best-effort; requires a Telegram bot token).
If you previously relied on pairing-store allowlist files, `openclaw doctor --fix` can recover entries into `channels.telegram.allowFrom` in allowlist flows (for example when `dmPolicy: "allowlist"` has no explicit IDs yet).
diff --git a/docs/cli/index.md b/docs/cli/index.md
index 9c4b58d1c35..8700655c766 100644
--- a/docs/cli/index.md
+++ b/docs/cli/index.md
@@ -318,22 +318,22 @@ Initialize config + workspace.
Options:
- `--workspace
`: agent workspace path (default `~/.openclaw/workspace`).
-- `--wizard`: run the setup wizard.
-- `--non-interactive`: run wizard without prompts.
-- `--mode `: wizard mode.
+- `--wizard`: run onboarding.
+- `--non-interactive`: run onboarding without prompts.
+- `--mode `: onboard mode.
- `--remote-url `: remote Gateway URL.
- `--remote-token `: remote Gateway token.
-Wizard auto-runs when any wizard flags are present (`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`).
+Onboarding auto-runs when any onboarding flags are present (`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`).
### `onboard`
-Interactive wizard to set up gateway, workspace, and skills.
+Interactive onboarding for gateway, workspace, and skills.
Options:
- `--workspace `
-- `--reset` (reset config + credentials + sessions before wizard)
+- `--reset` (reset config + credentials + sessions before onboarding)
- `--reset-scope ` (default `config+creds+sessions`; use `full` to also remove workspace)
- `--non-interactive`
- `--mode `
diff --git a/docs/cli/onboard.md b/docs/cli/onboard.md
index 899ccd82713..0b0e9c78beb 100644
--- a/docs/cli/onboard.md
+++ b/docs/cli/onboard.md
@@ -1,5 +1,5 @@
---
-summary: "CLI reference for `openclaw onboard` (interactive setup wizard)"
+summary: "CLI reference for `openclaw onboard` (interactive onboarding)"
read_when:
- You want guided setup for gateway, workspace, auth, channels, and skills
title: "onboard"
@@ -7,11 +7,11 @@ title: "onboard"
# `openclaw onboard`
-Interactive setup wizard (local or remote Gateway setup).
+Interactive onboarding for local or remote Gateway setup.
## Related guides
-- CLI onboarding hub: [Setup Wizard (CLI)](/start/wizard)
+- CLI onboarding hub: [Onboarding (CLI)](/start/wizard)
- Onboarding overview: [Onboarding Overview](/start/onboarding-overview)
- CLI onboarding reference: [CLI Setup Reference](/start/wizard-cli-reference)
- CLI automation: [CLI Automation](/start/wizard-cli-automation)
diff --git a/docs/cli/setup.md b/docs/cli/setup.md
index d8992ba8a43..e13cd89e5b2 100644
--- a/docs/cli/setup.md
+++ b/docs/cli/setup.md
@@ -1,7 +1,7 @@
---
summary: "CLI reference for `openclaw setup` (initialize config + workspace)"
read_when:
- - You’re doing first-run setup without the full setup wizard
+ - You’re doing first-run setup without full CLI onboarding
- You want to set the default workspace path
title: "setup"
---
@@ -13,7 +13,7 @@ Initialize `~/.openclaw/openclaw.json` and the agent workspace.
Related:
- Getting started: [Getting started](/start/getting-started)
-- Wizard: [Onboarding](/start/onboarding)
+- CLI onboarding: [Onboarding (CLI)](/start/wizard)
## Examples
@@ -22,7 +22,7 @@ openclaw setup
openclaw setup --workspace ~/.openclaw/workspace
```
-To run the wizard via setup:
+To run onboarding via setup:
```bash
openclaw setup --wizard
diff --git a/docs/concepts/models.md b/docs/concepts/models.md
index e85e605456f..f3b7797eedb 100644
--- a/docs/concepts/models.md
+++ b/docs/concepts/models.md
@@ -34,9 +34,9 @@ Related:
- Use fallbacks for cost/latency-sensitive tasks and lower-stakes chat.
- For tool-enabled agents or untrusted inputs, avoid older/weaker model tiers.
-## Setup wizard (recommended)
+## Onboarding (recommended)
-If you don’t want to hand-edit config, run the setup wizard:
+If you don’t want to hand-edit config, run onboarding:
```bash
openclaw onboard
diff --git a/docs/gateway/authentication.md b/docs/gateway/authentication.md
index c25501e6cdd..8a7eae00194 100644
--- a/docs/gateway/authentication.md
+++ b/docs/gateway/authentication.md
@@ -49,7 +49,7 @@ openclaw models status
openclaw doctor
```
-If you’d rather not manage env vars yourself, the setup wizard can store
+If you’d rather not manage env vars yourself, onboarding can store
API keys for daemon use: `openclaw onboard`.
See [Help](/help) for details on env inheritance (`env.shellEnv`,
diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md
index 170c0a94219..235d4a18a7b 100644
--- a/docs/gateway/configuration-reference.md
+++ b/docs/gateway/configuration-reference.md
@@ -2950,7 +2950,7 @@ Notes:
## Wizard
-Metadata written by CLI wizards (`onboard`, `configure`, `doctor`):
+Metadata written by CLI guided setup flows (`onboard`, `configure`, `doctor`):
```json5
{
diff --git a/docs/gateway/configuration.md b/docs/gateway/configuration.md
index a699e74652f..3ead49f6817 100644
--- a/docs/gateway/configuration.md
+++ b/docs/gateway/configuration.md
@@ -38,7 +38,7 @@ See the [full reference](/gateway/configuration-reference) for every available f
```bash
- openclaw onboard # full setup wizard
+ openclaw onboard # full onboarding flow
openclaw configure # config wizard
```
diff --git a/docs/gateway/security/index.md b/docs/gateway/security/index.md
index 68be08fbed5..7741707a62b 100644
--- a/docs/gateway/security/index.md
+++ b/docs/gateway/security/index.md
@@ -738,7 +738,7 @@ In minimal mode, the Gateway still broadcasts enough for device discovery (`role
Gateway auth is **required by default**. If no token/password is configured,
the Gateway refuses WebSocket connections (fail‑closed).
-The setup wizard generates a token by default (even for loopback) so
+Onboarding generates a token by default (even for loopback) so
local clients must authenticate.
Set a token so **all** WS clients must authenticate:
diff --git a/docs/help/faq.md b/docs/help/faq.md
index b32b1aac8c5..cc52aafd604 100644
--- a/docs/help/faq.md
+++ b/docs/help/faq.md
@@ -36,7 +36,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [How do I install OpenClaw on a VPS?](#how-do-i-install-openclaw-on-a-vps)
- [Where are the cloud/VPS install guides?](#where-are-the-cloudvps-install-guides)
- [Can I ask OpenClaw to update itself?](#can-i-ask-openclaw-to-update-itself)
- - [What does the setup wizard actually do?](#what-does-the-setup-wizard-actually-do)
+ - [What does onboarding actually do?](#what-does-onboarding-actually-do)
- [Do I need a Claude or OpenAI subscription to run this?](#do-i-need-a-claude-or-openai-subscription-to-run-this)
- [Can I use Claude Max subscription without an API key](#can-i-use-claude-max-subscription-without-an-api-key)
- [How does Anthropic "setup-token" auth work?](#how-does-anthropic-setuptoken-auth-work)
@@ -317,7 +317,7 @@ Install docs: [Install](/install), [Installer flags](/install/installer), [Updat
### What's the recommended way to install and set up OpenClaw
-The repo recommends running from source and using the setup wizard:
+The repo recommends running from source and using onboarding:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
@@ -627,7 +627,7 @@ More detail: [Install](/install) and [Installer flags](/install/installer).
### How do I install OpenClaw on Linux
-Short answer: follow the Linux guide, then run the setup wizard.
+Short answer: follow the Linux guide, then run onboarding.
- Linux quick path + service install: [Linux](/platforms/linux).
- Full walkthrough: [Getting Started](/start/getting-started).
@@ -685,7 +685,7 @@ openclaw gateway restart
Docs: [Update](/cli/update), [Updating](/install/updating).
-### What does the setup wizard actually do
+### What does onboarding actually do
`openclaw onboard` is the recommended setup path. In **local mode** it walks you through:
@@ -723,7 +723,7 @@ If you want the clearest and safest supported path for production, use an Anthro
### How does Anthropic setuptoken auth work
-`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in the wizard or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
+`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in onboarding or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
### Where do I find an Anthropic setuptoken
@@ -733,7 +733,7 @@ It is **not** in the Anthropic Console. The setup-token is generated by the **Cl
claude setup-token
```
-Copy the token it prints, then choose **Anthropic token (paste setup-token)** in the wizard. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
+Copy the token it prints, then choose **Anthropic token (paste setup-token)** in onboarding. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
### Do you support Claude subscription auth (Claude Pro or Max)
@@ -767,15 +767,15 @@ Yes - via pi-ai's **Amazon Bedrock (Converse)** provider with **manual config**.
### How does Codex auth work
-OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). The wizard can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Wizard](/start/wizard).
+OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). Onboarding can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Onboarding (CLI)](/start/wizard).
### Do you support OpenAI subscription auth Codex OAuth
Yes. OpenClaw fully supports **OpenAI Code (Codex) subscription OAuth**.
OpenAI explicitly allows subscription OAuth usage in external tools/workflows
-like OpenClaw. The setup wizard can run the OAuth flow for you.
+like OpenClaw. Onboarding can run the OAuth flow for you.
-See [OAuth](/concepts/oauth), [Model providers](/concepts/model-providers), and [Wizard](/start/wizard).
+See [OAuth](/concepts/oauth), [Model providers](/concepts/model-providers), and [Onboarding (CLI)](/start/wizard).
### How do I set up Gemini CLI OAuth
@@ -844,7 +844,7 @@ without WhatsApp/Telegram.
`channels.telegram.allowFrom` is **the human sender's Telegram user ID** (numeric). It is not the bot username.
-The setup wizard accepts `@username` input and resolves it to a numeric ID, but OpenClaw authorization uses numeric IDs only.
+Onboarding accepts `@username` input and resolves it to a numeric ID, but OpenClaw authorization uses numeric IDs only.
Safer (no third-party bot):
@@ -1909,7 +1909,7 @@ openclaw onboard --install-daemon
Notes:
-- The setup wizard also offers **Reset** if it sees an existing config. See [Wizard](/start/wizard).
+- Onboarding also offers **Reset** if it sees an existing config. See [Onboarding (CLI)](/start/wizard).
- If you used profiles (`--profile` / `OPENCLAW_PROFILE`), reset each state dir (defaults are `~/.openclaw-`).
- Dev reset: `openclaw gateway --dev --reset` (dev-only; wipes dev config + credentials + sessions + workspace).
diff --git a/docs/index.md b/docs/index.md
index 7c69600f55d..25162bc9676 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -33,7 +33,7 @@ title: "OpenClaw"
Install OpenClaw and bring up the Gateway in minutes.
-
+
Guided setup with `openclaw onboard` and pairing flows.
diff --git a/docs/install/docker.md b/docs/install/docker.md
index a9f6b578bd0..f4913a5138a 100644
--- a/docs/install/docker.md
+++ b/docs/install/docker.md
@@ -51,7 +51,7 @@ From repo root:
This script:
- builds the gateway image locally (or pulls a remote image if `OPENCLAW_IMAGE` is set)
-- runs the setup wizard
+- runs onboarding
- prints optional provider setup hints
- starts the gateway via Docker Compose
- generates a gateway token and writes it to `.env`
diff --git a/docs/install/index.md b/docs/install/index.md
index 21adfdaa592..7130cf9faac 100644
--- a/docs/install/index.md
+++ b/docs/install/index.md
@@ -33,7 +33,7 @@ For VPS/cloud hosts, avoid third-party "1-click" marketplace images when possibl
- Downloads the CLI, installs it globally via npm, and launches the setup wizard.
+ Downloads the CLI, installs it globally via npm, and launches onboarding.
diff --git a/docs/install/northflank.mdx b/docs/install/northflank.mdx
index d3157d72e74..03a41d1013b 100644
--- a/docs/install/northflank.mdx
+++ b/docs/install/northflank.mdx
@@ -21,7 +21,7 @@ and you configure everything via the `/setup` web wizard.
## What you get
- Hosted OpenClaw Gateway + Control UI
-- Web setup wizard at `/setup` (no terminal commands)
+- Web setup at `/setup` (no terminal commands)
- Persistent storage via Northflank Volume (`/data`) so config/credentials/workspace survive redeploys
## Setup flow
@@ -32,7 +32,7 @@ and you configure everything via the `/setup` web wizard.
4. Click **Run setup**.
5. Open the Control UI at `https:///openclaw`
-If Telegram DMs are set to pairing, the setup wizard can approve the pairing code.
+If Telegram DMs are set to pairing, web setup can approve the pairing code.
## Getting chat tokens
diff --git a/docs/install/railway.mdx b/docs/install/railway.mdx
index 73f23fbe48a..1548069b4fd 100644
--- a/docs/install/railway.mdx
+++ b/docs/install/railway.mdx
@@ -29,13 +29,13 @@ Railway will either:
Then open:
-- `https:///setup` — setup wizard (password protected)
+- `https:///setup` — web setup (password protected)
- `https:///openclaw` — Control UI
## What you get
- Hosted OpenClaw Gateway + Control UI
-- Web setup wizard at `/setup` (no terminal commands)
+- Web setup at `/setup` (no terminal commands)
- Persistent storage via Railway Volume (`/data`) so config/credentials/workspace survive redeploys
- Backup export at `/setup/export` to migrate off Railway later
@@ -70,7 +70,7 @@ Set these variables on the service:
3. (Optional) Add Telegram/Discord/Slack tokens.
4. Click **Run setup**.
-If Telegram DMs are set to pairing, the setup wizard can approve the pairing code.
+If Telegram DMs are set to pairing, web setup can approve the pairing code.
## Getting chat tokens
diff --git a/docs/install/render.mdx b/docs/install/render.mdx
index ae945687025..7e43bfca012 100644
--- a/docs/install/render.mdx
+++ b/docs/install/render.mdx
@@ -73,7 +73,7 @@ The Blueprint defaults to `starter`. To use free tier, change `plan: free` in yo
## After deployment
-### Complete the setup wizard
+### Complete web setup
1. Navigate to `https://.onrender.com/setup`
2. Enter your `SETUP_PASSWORD`
diff --git a/docs/install/updating.md b/docs/install/updating.md
index a8161cc07f0..dd3128c553e 100644
--- a/docs/install/updating.md
+++ b/docs/install/updating.md
@@ -22,7 +22,7 @@ curl -fsSL https://openclaw.ai/install.sh | bash
Notes:
-- Add `--no-onboard` if you don’t want the setup wizard to run again.
+- Add `--no-onboard` if you don’t want onboarding to run again.
- For **source installs**, use:
```bash
diff --git a/docs/platforms/raspberry-pi.md b/docs/platforms/raspberry-pi.md
index 2050b6395b4..7b5e22f89c6 100644
--- a/docs/platforms/raspberry-pi.md
+++ b/docs/platforms/raspberry-pi.md
@@ -321,7 +321,7 @@ Since the Pi is just the Gateway (models run in the cloud), use API-based models
## Auto-Start on Boot
-The setup wizard sets this up, but to verify:
+Onboarding sets this up, but to verify:
```bash
# Check service is enabled
diff --git a/docs/providers/ollama.md b/docs/providers/ollama.md
index 5a1eb2bd27e..c3ea5aa7d3c 100644
--- a/docs/providers/ollama.md
+++ b/docs/providers/ollama.md
@@ -16,15 +16,15 @@ Ollama is a local LLM runtime that makes it easy to run open-source models on yo
## Quick start
-### Onboarding wizard (recommended)
+### Onboarding (recommended)
-The fastest way to set up Ollama is through the setup wizard:
+The fastest way to set up Ollama is through onboarding:
```bash
openclaw onboard
```
-Select **Ollama** from the provider list. The wizard will:
+Select **Ollama** from the provider list. Onboarding will:
1. Ask for the Ollama base URL where your instance can be reached (default `http://127.0.0.1:11434`).
2. Let you choose **Cloud + Local** (cloud models and local models) or **Local** (local models only).
diff --git a/docs/reference/wizard.md b/docs/reference/wizard.md
index 5bfa3da7f9f..fce13301ea9 100644
--- a/docs/reference/wizard.md
+++ b/docs/reference/wizard.md
@@ -1,24 +1,24 @@
---
-summary: "Full reference for the CLI setup wizard: every step, flag, and config field"
+summary: "Full reference for CLI onboarding: every step, flag, and config field"
read_when:
- - Looking up a specific wizard step or flag
+ - Looking up a specific onboarding step or flag
- Automating onboarding with non-interactive mode
- - Debugging wizard behavior
-title: "Setup Wizard Reference"
-sidebarTitle: "Wizard Reference"
+ - Debugging onboarding behavior
+title: "Onboarding Reference"
+sidebarTitle: "Onboarding Reference"
---
-# Setup Wizard Reference
+# Onboarding Reference
-This is the full reference for the `openclaw onboard` CLI wizard.
-For a high-level overview, see [Setup Wizard](/start/wizard).
+This is the full reference for `openclaw onboard`.
+For a high-level overview, see [Onboarding (CLI)](/start/wizard).
## Flow details (local mode)
- If `~/.openclaw/openclaw.json` exists, choose **Keep / Modify / Reset**.
- - Re-running the wizard does **not** wipe anything unless you explicitly choose **Reset**
+ - Re-running onboarding does **not** wipe anything unless you explicitly choose **Reset**
(or pass `--reset`).
- CLI `--reset` defaults to `config+creds+sessions`; use `--reset-scope full`
to also remove workspace.
@@ -31,9 +31,9 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
- **Anthropic API key**: uses `ANTHROPIC_API_KEY` if present or prompts for a key, then saves it for daemon use.
- - **Anthropic OAuth (Claude Code CLI)**: on macOS the wizard checks Keychain item "Claude Code-credentials" (choose "Always Allow" so launchd starts don't block); on Linux/Windows it reuses `~/.claude/.credentials.json` if present.
+ - **Anthropic OAuth (Claude Code CLI)**: on macOS onboarding checks Keychain item "Claude Code-credentials" (choose "Always Allow" so launchd starts don't block); on Linux/Windows it reuses `~/.claude/.credentials.json` if present.
- **Anthropic token (paste setup-token)**: run `claude setup-token` on any machine, then paste the token (you can name it; blank = default).
- - **OpenAI Code (Codex) subscription (Codex CLI)**: if `~/.codex/auth.json` exists, the wizard can reuse it.
+ - **OpenAI Code (Codex) subscription (Codex CLI)**: if `~/.codex/auth.json` exists, onboarding can reuse it.
- **OpenAI Code (Codex) subscription (OAuth)**: browser flow; paste the `code#state`.
- Sets `agents.defaults.model` to `openai-codex/gpt-5.2` when model is unset or `openai/*`.
- **OpenAI API key**: uses `OPENAI_API_KEY` if present or prompts for a key, then stores it in auth profiles.
@@ -55,7 +55,7 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
- More detail: [Moonshot AI (Kimi + Kimi Coding)](/providers/moonshot)
- **Skip**: no auth configured yet.
- Pick a default model from detected options (or enter provider/model manually). For best quality and lower prompt-injection risk, choose the strongest latest-generation model available in your provider stack.
- - Wizard runs a model check and warns if the configured model is unknown or missing auth.
+ - Onboarding runs a model check and warns if the configured model is unknown or missing auth.
- API key storage mode defaults to plaintext auth-profile values. Use `--secret-input-mode ref` to store env-backed refs instead (for example `keyRef: { source: "env", provider: "default", id: "OPENAI_API_KEY" }`).
- OAuth credentials live in `~/.openclaw/credentials/oauth.json`; auth profiles live in `~/.openclaw/agents//agent/auth-profiles.json` (API keys + OAuth).
- More detail: [/concepts/oauth](/concepts/oauth)
@@ -106,7 +106,7 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
- macOS: LaunchAgent
- Requires a logged-in user session; for headless, use a custom LaunchDaemon (not shipped).
- Linux (and Windows via WSL2): systemd user unit
- - Wizard attempts to enable lingering via `loginctl enable-linger ` so the Gateway stays up after logout.
+ - Onboarding attempts to enable lingering via `loginctl enable-linger ` so the Gateway stays up after logout.
- May prompt for sudo (writes `/var/lib/systemd/linger`); it tries without sudo first.
- **Runtime selection:** Node (recommended; required for WhatsApp/Telegram). Bun is **not recommended**.
- If token auth requires a token and `gateway.auth.token` is SecretRef-managed, daemon install validates it but does not persist resolved plaintext token values into supervisor service environment metadata.
@@ -128,8 +128,8 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
-If no GUI is detected, the wizard prints SSH port-forward instructions for the Control UI instead of opening a browser.
-If the Control UI assets are missing, the wizard attempts to build them; fallback is `pnpm ui:build` (auto-installs UI deps).
+If no GUI is detected, onboarding prints SSH port-forward instructions for the Control UI instead of opening a browser.
+If the Control UI assets are missing, onboarding attempts to build them; fallback is `pnpm ui:build` (auto-installs UI deps).
## Non-interactive mode
@@ -183,12 +183,12 @@ openclaw agents add work \
## Gateway wizard RPC
-The Gateway exposes the wizard flow over RPC (`wizard.start`, `wizard.next`, `wizard.cancel`, `wizard.status`).
+The Gateway exposes the onboarding flow over RPC (`wizard.start`, `wizard.next`, `wizard.cancel`, `wizard.status`).
Clients (macOS app, Control UI) can render steps without re‑implementing onboarding logic.
## Signal setup (signal-cli)
-The wizard can install `signal-cli` from GitHub releases:
+Onboarding can install `signal-cli` from GitHub releases:
- Downloads the appropriate release asset.
- Stores it under `~/.openclaw/tools/signal-cli//`.
@@ -223,12 +223,12 @@ Typical fields in `~/.openclaw/openclaw.json`:
WhatsApp credentials go under `~/.openclaw/credentials/whatsapp//`.
Sessions are stored under `~/.openclaw/agents//sessions/`.
-Some channels are delivered as plugins. When you pick one during setup, the wizard
+Some channels are delivered as plugins. When you pick one during setup, onboarding
will prompt to install it (npm or a local path) before it can be configured.
## Related docs
-- Wizard overview: [Setup Wizard](/start/wizard)
+- Onboarding overview: [Onboarding (CLI)](/start/wizard)
- macOS app onboarding: [Onboarding](/start/onboarding)
- Config reference: [Gateway configuration](/gateway/configuration)
- Providers: [WhatsApp](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](/channels/discord), [Google Chat](/channels/googlechat), [Signal](/channels/signal), [BlueBubbles](/channels/bluebubbles) (iMessage), [iMessage](/channels/imessage) (legacy)
diff --git a/docs/start/getting-started.md b/docs/start/getting-started.md
index 3fc64e5087d..bd3f554cdc4 100644
--- a/docs/start/getting-started.md
+++ b/docs/start/getting-started.md
@@ -52,13 +52,13 @@ Check your Node version with `node --version` if you are unsure.
-
+
```bash
openclaw onboard --install-daemon
```
- The wizard configures auth, gateway settings, and optional channels.
- See [Setup Wizard](/start/wizard) for details.
+ Onboarding configures auth, gateway settings, and optional channels.
+ See [Onboarding (CLI)](/start/wizard) for details.
@@ -114,8 +114,8 @@ Full environment variable reference: [Environment vars](/help/environment).
## Go deeper
-
- Full CLI wizard reference and advanced options.
+
+ Full CLI onboarding reference and advanced options.
First run flow for the macOS app.
diff --git a/docs/start/hubs.md b/docs/start/hubs.md
index 9833b467378..882f547f65a 100644
--- a/docs/start/hubs.md
+++ b/docs/start/hubs.md
@@ -19,7 +19,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
- [Getting Started](/start/getting-started)
- [Quick start](/start/quickstart)
- [Onboarding](/start/onboarding)
-- [Wizard](/start/wizard)
+- [Onboarding (CLI)](/start/wizard)
- [Setup](/start/setup)
- [Dashboard (local Gateway)](http://127.0.0.1:18789/)
- [Help](/help)
diff --git a/docs/start/onboarding-overview.md b/docs/start/onboarding-overview.md
index 1e94a4db64a..1e60ce9cef5 100644
--- a/docs/start/onboarding-overview.md
+++ b/docs/start/onboarding-overview.md
@@ -14,21 +14,21 @@ and how you prefer to configure providers.
## Choose your onboarding path
-- **CLI wizard** for macOS, Linux, and Windows (via WSL2).
+- **CLI onboarding** for macOS, Linux, and Windows (via WSL2).
- **macOS app** for a guided first run on Apple silicon or Intel Macs.
-## CLI setup wizard
+## CLI onboarding
-Run the wizard in a terminal:
+Run onboarding in a terminal:
```bash
openclaw onboard
```
-Use the CLI wizard when you want full control of the Gateway, workspace,
+Use CLI onboarding when you want full control of the Gateway, workspace,
channels, and skills. Docs:
-- [Setup Wizard (CLI)](/start/wizard)
+- [Onboarding (CLI)](/start/wizard)
- [`openclaw onboard` command](/cli/onboard)
## macOS app onboarding
@@ -41,7 +41,7 @@ Use the OpenClaw app when you want a fully guided setup on macOS. Docs:
If you need an endpoint that is not listed, including hosted providers that
expose standard OpenAI or Anthropic APIs, choose **Custom Provider** in the
-CLI wizard. You will be asked to:
+CLI onboarding. You will be asked to:
- Pick OpenAI-compatible, Anthropic-compatible, or **Unknown** (auto-detect).
- Enter a base URL and API key (if required by the provider).
diff --git a/docs/start/quickstart.md b/docs/start/quickstart.md
index 238af2881e3..f4b96893fe6 100644
--- a/docs/start/quickstart.md
+++ b/docs/start/quickstart.md
@@ -16,7 +16,7 @@ Quick start is now part of [Getting Started](/start/getting-started).
Install OpenClaw and run your first chat in minutes.
-
- Full CLI wizard reference and advanced options.
+
+ Full CLI onboarding reference and advanced options.
diff --git a/docs/start/setup.md b/docs/start/setup.md
index bf127cc0ad0..7e3ec6dfc2d 100644
--- a/docs/start/setup.md
+++ b/docs/start/setup.md
@@ -10,7 +10,7 @@ title: "Setup"
If you are setting up for the first time, start with [Getting Started](/start/getting-started).
-For wizard details, see [Onboarding Wizard](/start/wizard).
+For onboarding details, see [Onboarding (CLI)](/start/wizard).
Last updated: 2026-01-01
diff --git a/docs/start/wizard-cli-automation.md b/docs/start/wizard-cli-automation.md
index 884d49e143b..f373f3d4bc6 100644
--- a/docs/start/wizard-cli-automation.md
+++ b/docs/start/wizard-cli-automation.md
@@ -33,7 +33,7 @@ openclaw onboard --non-interactive \
Add `--json` for a machine-readable summary.
Use `--secret-input-mode ref` to store env-backed refs in auth profiles instead of plaintext values.
-Interactive selection between env refs and configured provider refs (`file` or `exec`) is available in the setup wizard flow.
+Interactive selection between env refs and configured provider refs (`file` or `exec`) is available in the onboarding flow.
In non-interactive `ref` mode, provider env vars must be set in the process environment.
Passing inline key flags without the matching env var now fails fast.
@@ -210,6 +210,6 @@ Notes:
## Related docs
-- Onboarding hub: [Setup Wizard (CLI)](/start/wizard)
+- Onboarding hub: [Onboarding (CLI)](/start/wizard)
- Full reference: [CLI Setup Reference](/start/wizard-cli-reference)
- Command reference: [`openclaw onboard`](/cli/onboard)
diff --git a/docs/start/wizard-cli-reference.md b/docs/start/wizard-cli-reference.md
index 36bd836a13f..a08204c0f20 100644
--- a/docs/start/wizard-cli-reference.md
+++ b/docs/start/wizard-cli-reference.md
@@ -10,7 +10,7 @@ sidebarTitle: "CLI reference"
# CLI Setup Reference
This page is the full reference for `openclaw onboard`.
-For the short guide, see [Setup Wizard (CLI)](/start/wizard).
+For the short guide, see [Onboarding (CLI)](/start/wizard).
## What the wizard does
@@ -294,6 +294,6 @@ Signal setup behavior:
## Related docs
-- Onboarding hub: [Setup Wizard (CLI)](/start/wizard)
+- Onboarding hub: [Onboarding (CLI)](/start/wizard)
- Automation and scripts: [CLI Automation](/start/wizard-cli-automation)
- Command reference: [`openclaw onboard`](/cli/onboard)
diff --git a/docs/start/wizard.md b/docs/start/wizard.md
index 7bbe9df64cf..3ea6ff55255 100644
--- a/docs/start/wizard.md
+++ b/docs/start/wizard.md
@@ -1,15 +1,15 @@
---
-summary: "CLI setup wizard: guided setup for gateway, workspace, channels, and skills"
+summary: "CLI onboarding: guided setup for gateway, workspace, channels, and skills"
read_when:
- - Running or configuring the setup wizard
+ - Running or configuring CLI onboarding
- Setting up a new machine
-title: "Setup Wizard (CLI)"
+title: "Onboarding (CLI)"
sidebarTitle: "Onboarding: CLI"
---
-# Setup Wizard (CLI)
+# Onboarding (CLI)
-The setup wizard is the **recommended** way to set up OpenClaw on macOS,
+CLI onboarding is the **recommended** way to set up OpenClaw on macOS,
Linux, or Windows (via WSL2; strongly recommended).
It configures a local Gateway or a remote Gateway connection, plus channels, skills,
and workspace defaults in one guided flow.
@@ -35,7 +35,7 @@ openclaw agents add
-The setup wizard includes a web search step where you can pick a provider
+CLI onboarding includes a web search step where you can pick a provider
(Perplexity, Brave, Gemini, Grok, or Kimi) and paste your API key so the agent
can use `web_search`. You can also configure this later with
`openclaw configure --section web`. Docs: [Web tools](/tools/web).
@@ -43,7 +43,7 @@ can use `web_search`. You can also configure this later with
## QuickStart vs Advanced
-The wizard starts with **QuickStart** (defaults) vs **Advanced** (full control).
+Onboarding starts with **QuickStart** (defaults) vs **Advanced** (full control).
@@ -61,7 +61,7 @@ The wizard starts with **QuickStart** (defaults) vs **Advanced** (full control).
-## What the wizard configures
+## What onboarding configures
**Local mode (default)** walks you through these steps:
@@ -84,9 +84,9 @@ The wizard starts with **QuickStart** (defaults) vs **Advanced** (full control).
7. **Skills** — Installs recommended skills and optional dependencies.
-Re-running the wizard does **not** wipe anything unless you explicitly choose **Reset** (or pass `--reset`).
+Re-running onboarding does **not** wipe anything unless you explicitly choose **Reset** (or pass `--reset`).
CLI `--reset` defaults to config, credentials, and sessions; use `--reset-scope full` to include workspace.
-If the config is invalid or contains legacy keys, the wizard asks you to run `openclaw doctor` first.
+If the config is invalid or contains legacy keys, onboarding asks you to run `openclaw doctor` first.
**Remote mode** only configures the local client to connect to a Gateway elsewhere.
@@ -95,7 +95,7 @@ It does **not** install or change anything on the remote host.
## Add another agent
Use `openclaw agents add ` to create a separate agent with its own workspace,
-sessions, and auth profiles. Running without `--workspace` launches the wizard.
+sessions, and auth profiles. Running without `--workspace` launches onboarding.
What it sets:
@@ -106,7 +106,7 @@ What it sets:
Notes:
- Default workspaces follow `~/.openclaw/workspace-`.
-- Add `bindings` to route inbound messages (the wizard can do this).
+- Add `bindings` to route inbound messages (onboarding can do this).
- Non-interactive flags: `--model`, `--agent-dir`, `--bind`, `--non-interactive`.
## Full reference
@@ -115,7 +115,7 @@ For detailed step-by-step breakdowns and config outputs, see
[CLI Setup Reference](/start/wizard-cli-reference).
For non-interactive examples, see [CLI Automation](/start/wizard-cli-automation).
For the deeper technical reference, including RPC details, see
-[Wizard Reference](/reference/wizard).
+[Onboarding Reference](/reference/wizard).
## Related docs
diff --git a/docs/web/control-ui.md b/docs/web/control-ui.md
index 204d68605d2..d35b245d814 100644
--- a/docs/web/control-ui.md
+++ b/docs/web/control-ui.md
@@ -28,7 +28,7 @@ Auth is supplied during the WebSocket handshake via:
- `connect.params.auth.token`
- `connect.params.auth.password`
The dashboard settings panel keeps a token for the current browser tab session and selected gateway URL; passwords are not persisted.
- The setup wizard generates a gateway token by default, so paste it here on first connect.
+ Onboarding generates a gateway token by default, so paste it here on first connect.
## Device pairing (first connection)
diff --git a/docs/zh-CN/cli/index.md b/docs/zh-CN/cli/index.md
index 46be3ef8ab1..0533d75d6c6 100644
--- a/docs/zh-CN/cli/index.md
+++ b/docs/zh-CN/cli/index.md
@@ -324,22 +324,22 @@ openclaw [--dev] [--profile ]
选项:
- `--workspace `:智能体工作区路径(默认 `~/.openclaw/workspace`)。
-- `--wizard`:运行设置向导。
-- `--non-interactive`:无提示运行向导。
-- `--mode `:向导模式。
+- `--wizard`:运行新手引导。
+- `--non-interactive`:无提示运行新手引导。
+- `--mode `:新手引导模式。
- `--remote-url `:远程 Gateway 网关 URL。
- `--remote-token `:远程 Gateway 网关 token。
-只要存在任意向导标志(`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`),就会自动运行向导。
+只要存在任意新手引导标志(`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`),就会自动运行新手引导。
### `onboard`
-用于设置 gateway、工作区和 Skills 的交互式向导。
+用于设置 gateway、工作区和 Skills 的交互式新手引导。
选项:
- `--workspace `
-- `--reset`(在运行向导前重置配置 + 凭据 + 会话)
+- `--reset`(在运行新手引导前重置配置 + 凭据 + 会话)
- `--reset-scope `(默认 `config+creds+sessions`;使用 `full` 还会删除工作区)
- `--non-interactive`
- `--mode `
diff --git a/docs/zh-CN/cli/onboard.md b/docs/zh-CN/cli/onboard.md
index 66588b9d795..1cee84571c9 100644
--- a/docs/zh-CN/cli/onboard.md
+++ b/docs/zh-CN/cli/onboard.md
@@ -1,7 +1,7 @@
---
read_when:
- 你想通过引导式设置来配置 Gateway 网关、工作区、身份验证、渠道和 Skills
-summary: "`openclaw onboard` 的 CLI 参考(交互式设置向导)"
+summary: "`openclaw onboard` 的 CLI 参考(交互式新手引导)"
title: onboard
x-i18n:
generated_at: "2026-03-16T06:21:32Z"
@@ -14,11 +14,11 @@ x-i18n:
# `openclaw onboard`
-交互式设置向导(本地或远程 Gateway 网关设置)。
+交互式新手引导(本地或远程 Gateway 网关设置)。
## 相关指南
-- CLI 新手引导中心:[设置向导(CLI)](/start/wizard)
+- CLI 新手引导中心:[CLI 新手引导](/start/wizard)
- 新手引导概览:[新手引导概览](/start/onboarding-overview)
- CLI 新手引导参考:[CLI 设置参考](/start/wizard-cli-reference)
- CLI 自动化:[CLI 自动化](/start/wizard-cli-automation)
diff --git a/docs/zh-CN/cli/setup.md b/docs/zh-CN/cli/setup.md
index 18936b3bd24..6aa0fe99c3a 100644
--- a/docs/zh-CN/cli/setup.md
+++ b/docs/zh-CN/cli/setup.md
@@ -1,6 +1,6 @@
---
read_when:
- - 你正在进行首次运行设置,但不使用完整的设置向导
+ - 你正在进行首次运行设置,但不使用完整的 CLI 新手引导
- 你想设置默认工作区路径
summary: "`openclaw setup` 的 CLI 参考(初始化配置 + 工作区)"
title: setup
@@ -20,7 +20,7 @@ x-i18n:
相关内容:
- 入门指南:[入门指南](/start/getting-started)
-- 向导:[新手引导](/start/onboarding)
+- CLI 新手引导:[CLI 新手引导](/start/wizard)
## 示例
@@ -29,7 +29,7 @@ openclaw setup
openclaw setup --workspace ~/.openclaw/workspace
```
-通过 setup 运行向导:
+通过 setup 运行新手引导:
```bash
openclaw setup --wizard
diff --git a/docs/zh-CN/help/faq.md b/docs/zh-CN/help/faq.md
index 8543ea01f22..18b936e2cc8 100644
--- a/docs/zh-CN/help/faq.md
+++ b/docs/zh-CN/help/faq.md
@@ -39,7 +39,7 @@ x-i18n:
- [如何在 VPS 上安装 OpenClaw?](#how-do-i-install-openclaw-on-a-vps)
- [云/VPS 安装指南在哪里?](#where-are-the-cloudvps-install-guides)
- [可以让 OpenClaw 自行更新吗?](#can-i-ask-openclaw-to-update-itself)
- - [新手引导向导具体做了什么?](#what-does-the-onboarding-wizard-actually-do)
+ - [新手引导具体做了什么?](#新手引导具体做了什么)
- [运行 OpenClaw 需要 Claude 或 OpenAI 订阅吗?](#do-i-need-a-claude-or-openai-subscription-to-run-this)
- [能否使用 Claude Max 订阅而不需要 API 密钥?](#can-i-use-claude-max-subscription-without-an-api-key)
- [Anthropic "setup-token" 认证如何工作?](#how-does-anthropic-setuptoken-auth-work)
@@ -310,14 +310,14 @@ openclaw doctor
### 安装和设置 OpenClaw 的推荐方式是什么
-仓库推荐从源码运行并使用新手引导向导:
+仓库推荐从源码运行并使用新手引导:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
openclaw onboard --install-daemon
```
-向导还可以自动构建 UI 资源。新手引导后,通常在端口 **18789** 上运行 Gateway 网关。
+新手引导还可以自动构建 UI 资源。新手引导后,通常在端口 **18789** 上运行 Gateway 网关。
从源码安装(贡献者/开发者):
@@ -334,7 +334,7 @@ openclaw onboard
### 新手引导后如何打开仪表板
-向导现在会在新手引导完成后立即使用带令牌的仪表板 URL 打开浏览器,并在摘要中打印完整链接(带令牌)。保持该标签页打开;如果没有自动启动,请在同一台机器上复制/粘贴打印的 URL。令牌保持在本地主机上——不会从浏览器获取任何内容。
+新手引导现在会在完成后立即使用带令牌的仪表板 URL 打开浏览器,并在摘要中打印完整链接(带令牌)。保持该标签页打开;如果没有自动启动,请在同一台机器上复制/粘贴打印的 URL。令牌保持在本地主机上,不会从浏览器获取任何内容。
### 如何在本地和远程环境中验证仪表板令牌
@@ -562,7 +562,7 @@ curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git
### 如何在 Linux 上安装 OpenClaw
-简短回答:按照 Linux 指南操作,然后运行新手引导向导。
+简短回答:按照 Linux 指南操作,然后运行新手引导。
- Linux 快速路径 + 服务安装:[Linux](/platforms/linux)。
- 完整指南:[入门](/start/getting-started)。
@@ -614,7 +614,7 @@ openclaw gateway restart
文档:[更新](/cli/update)、[更新指南](/install/updating)。
-### 新手引导向导具体做了什么
+### 新手引导具体做了什么
`openclaw onboard` 是推荐的设置路径。在**本地模式**下,它引导你完成:
@@ -642,7 +642,7 @@ Claude Pro/Max 订阅**不包含 API 密钥**,因此这是订阅账户的正
### Anthropic setup-token 认证如何工作
-`claude setup-token` 通过 Claude Code CLI 生成一个**令牌字符串**(在 Web 控制台中不可用)。你可以在**任何机器**上运行它。在向导中选择 **Anthropic token (paste setup-token)** 或使用 `openclaw models auth paste-token --provider anthropic` 粘贴。令牌作为 **anthropic** 提供商的认证配置文件存储,像 API 密钥一样使用(无自动刷新)。更多详情:[OAuth](/concepts/oauth)。
+`claude setup-token` 通过 Claude Code CLI 生成一个**令牌字符串**(在 Web 控制台中不可用)。你可以在**任何机器**上运行它。在新手引导中选择 **Anthropic token (paste setup-token)** 或使用 `openclaw models auth paste-token --provider anthropic` 粘贴。令牌作为 **anthropic** 提供商的认证配置文件存储,像 API 密钥一样使用(无自动刷新)。更多详情:[OAuth](/concepts/oauth)。
### 在哪里获取 Anthropic setup-token
@@ -652,7 +652,7 @@ Claude Pro/Max 订阅**不包含 API 密钥**,因此这是订阅账户的正
claude setup-token
```
-复制它打印的令牌,然后在向导中选择 **Anthropic token (paste setup-token)**。如果你想在 Gateway 网关主机上运行,使用 `openclaw models auth setup-token --provider anthropic`。如果你在其他地方运行了 `claude setup-token`,在 Gateway 网关主机上使用 `openclaw models auth paste-token --provider anthropic` 粘贴。参阅 [Anthropic](/providers/anthropic)。
+复制它打印的令牌,然后在新手引导中选择 **Anthropic token (paste setup-token)**。如果你想在 Gateway 网关主机上运行,使用 `openclaw models auth setup-token --provider anthropic`。如果你在其他地方运行了 `claude setup-token`,在 Gateway 网关主机上使用 `openclaw models auth paste-token --provider anthropic` 粘贴。参阅 [Anthropic](/providers/anthropic)。
### 是否支持 Claude 订阅认证(Claude Pro/Max)
@@ -673,13 +673,13 @@ claude setup-token
### Codex 认证如何工作
-OpenClaw 通过 OAuth(ChatGPT 登录)支持 **OpenAI Code (Codex)**。向导可以运行 OAuth 流程,并在适当时将默认模型设置为 `openai-codex/gpt-5.2`。参阅[模型提供商](/concepts/model-providers)和[向导](/start/wizard)。
+OpenClaw 通过 OAuth(ChatGPT 登录)支持 **OpenAI Code (Codex)**。新手引导可以运行 OAuth 流程,并在适当时将默认模型设置为 `openai-codex/gpt-5.2`。参阅[模型提供商](/concepts/model-providers)和[CLI 新手引导](/start/wizard)。
### 是否支持 OpenAI 订阅认证(Codex OAuth)
-是的。OpenClaw 完全支持 **OpenAI Code (Codex) 订阅 OAuth**。新手引导向导可以为你运行 OAuth 流程。
+是的。OpenClaw 完全支持 **OpenAI Code (Codex) 订阅 OAuth**。新手引导可以为你运行 OAuth 流程。
-参阅 [OAuth](/concepts/oauth)、[模型提供商](/concepts/model-providers)和[向导](/start/wizard)。
+参阅 [OAuth](/concepts/oauth)、[模型提供商](/concepts/model-providers)和[CLI 新手引导](/start/wizard)。
### 如何设置 Gemini CLI OAuth
@@ -1632,7 +1632,7 @@ openclaw onboard --install-daemon
注意:
-- 新手引导向导在看到现有配置时也提供**重置**选项。参阅[向导](/start/wizard)。
+- 新手引导在看到现有配置时也提供**重置**选项。参阅[CLI 新手引导](/start/wizard)。
- 如果你使用了配置文件(`--profile` / `OPENCLAW_PROFILE`),重置每个状态目录(默认为 `~/.openclaw-`)。
- 开发重置:`openclaw gateway --dev --reset`(仅限开发;清除开发配置 + 凭据 + 会话 + 工作区)。
diff --git a/docs/zh-CN/index.md b/docs/zh-CN/index.md
index 3999dc6fda4..1444fd2f3da 100644
--- a/docs/zh-CN/index.md
+++ b/docs/zh-CN/index.md
@@ -40,7 +40,7 @@ x-i18n:
安装 OpenClaw 并在几分钟内启动 Gateway 网关。
-
+
通过 `openclaw onboard` 和配对流程进行引导式设置。
diff --git a/docs/zh-CN/start/getting-started.md b/docs/zh-CN/start/getting-started.md
index 39e3fb3829f..0707dd7b1d0 100644
--- a/docs/zh-CN/start/getting-started.md
+++ b/docs/zh-CN/start/getting-started.md
@@ -60,13 +60,13 @@ x-i18n:
-
+
```bash
openclaw onboard --install-daemon
```
- 向导会配置认证、Gateway 网关设置和可选渠道。
- 详情请参见 [Setup Wizard](/start/wizard)。
+ 新手引导会配置认证、Gateway 网关设置和可选渠道。
+ 详情请参见 [CLI 新手引导](/start/wizard)。
@@ -122,8 +122,8 @@ x-i18n:
## 深入了解
-
- 完整的 CLI 向导参考和高级选项。
+
+ 完整的 CLI 新手引导参考和高级选项。
macOS 应用的首次运行流程。
diff --git a/docs/zh-CN/start/hubs.md b/docs/zh-CN/start/hubs.md
index b303102dcc0..c5dce882420 100644
--- a/docs/zh-CN/start/hubs.md
+++ b/docs/zh-CN/start/hubs.md
@@ -26,7 +26,7 @@ x-i18n:
- [入门指南](/start/getting-started)
- [快速开始](/start/quickstart)
- [新手引导](/start/onboarding)
-- [向导](/start/wizard)
+- [CLI 新手引导](/start/wizard)
- [安装配置](/start/setup)
- [仪表盘(本地 Gateway 网关)](http://127.0.0.1:18789/)
- [帮助](/help)
diff --git a/docs/zh-CN/start/onboarding-overview.md b/docs/zh-CN/start/onboarding-overview.md
index 524bd8b33f5..ed301f41f5f 100644
--- a/docs/zh-CN/start/onboarding-overview.md
+++ b/docs/zh-CN/start/onboarding-overview.md
@@ -21,21 +21,21 @@ OpenClaw 支持多种新手引导路径,具体取决于 Gateway 网关运行
## 选择你的新手引导路径
-- 适用于 macOS、Linux 和 Windows(通过 WSL2)的 **CLI 向导**。
+- 适用于 macOS、Linux 和 Windows(通过 WSL2)的 **CLI 新手引导**。
- 适用于 Apple silicon 或 Intel Mac 的 **macOS 应用**,提供引导式首次运行体验。
-## CLI 设置向导
+## CLI 新手引导
-在终端中运行向导:
+在终端中运行新手引导:
```bash
openclaw onboard
```
当你希望完全控制 Gateway 网关、工作区、
-渠道和 Skills 时,请使用 CLI 向导。文档:
+渠道和 Skills 时,请使用 CLI 新手引导。文档:
-- [设置向导(CLI)](/start/wizard)
+- [CLI 新手引导](/start/wizard)
- [`openclaw onboard` 命令](/cli/onboard)
## macOS 应用新手引导
@@ -48,7 +48,7 @@ openclaw onboard
如果你需要一个未列出的端点,包括那些
公开标准 OpenAI 或 Anthropic API 的托管提供商,请在
-CLI 向导中选择 **Custom Provider**。系统会要求你:
+在 CLI 新手引导中选择 **Custom Provider**。系统会要求你:
- 选择兼容 OpenAI、兼容 Anthropic,或 **Unknown**(自动检测)。
- 输入基础 URL 和 API 密钥(如果提供商需要)。
diff --git a/docs/zh-CN/start/wizard.md b/docs/zh-CN/start/wizard.md
index 0be36f3cdfb..b168e580b62 100644
--- a/docs/zh-CN/start/wizard.md
+++ b/docs/zh-CN/start/wizard.md
@@ -1,10 +1,10 @@
---
read_when:
- - 运行或配置设置向导
+ - 运行或配置 CLI 新手引导
- 设置一台新机器
sidebarTitle: "Onboarding: CLI"
-summary: CLI 设置向导:用于 Gateway 网关、工作区、渠道和 Skills 的引导式设置
-title: 设置向导(CLI)
+summary: CLI 新手引导:用于 Gateway 网关、工作区、渠道和 Skills 的引导式设置
+title: CLI 新手引导
x-i18n:
generated_at: "2026-03-16T06:28:38Z"
model: gpt-5.4
@@ -14,9 +14,9 @@ x-i18n:
workflow: 15
---
-# 设置向导(CLI)
+# CLI 新手引导
-设置向导是在 macOS、
+CLI 新手引导是在 macOS、
Linux 或 Windows(通过 WSL2;强烈推荐)上设置 OpenClaw 的**推荐**方式。
它可在一次引导式流程中配置本地 Gateway 网关或远程 Gateway 网关连接,以及渠道、Skills
和工作区默认值。
@@ -42,7 +42,7 @@ openclaw agents add
-设置向导包含一个 web search 步骤,你可以选择一个提供商
+CLI 新手引导包含一个 web search 步骤,你可以选择一个提供商
(Perplexity、Brave、Gemini、Grok 或 Kimi),并粘贴你的 API 密钥,以便智能体
可以使用 `web_search`。你也可以稍后通过
`openclaw configure --section web` 进行配置。文档:[Web 工具](/tools/web)。
@@ -50,7 +50,7 @@ openclaw agents add
## 快速开始与高级模式
-向导开始时会让你选择**快速开始**(默认值)或**高级模式**(完全控制)。
+新手引导开始时会让你选择**快速开始**(默认值)或**高级模式**(完全控制)。
@@ -68,7 +68,7 @@ openclaw agents add
-## 向导会配置什么
+## 新手引导会配置什么
**本地模式(默认)**会引导你完成以下步骤:
@@ -91,9 +91,9 @@ openclaw agents add
7. **Skills** —— 安装推荐的 Skills 和可选依赖项。
-重新运行向导**不会**清除任何内容,除非你显式选择 **Reset**(或传入 `--reset`)。
+重新运行新手引导**不会**清除任何内容,除非你显式选择 **Reset**(或传入 `--reset`)。
CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,请使用 `--reset-scope full`。
-如果配置无效或包含旧版键,向导会先要求你运行 `openclaw doctor`。
+如果配置无效或包含旧版键,新手引导会先要求你运行 `openclaw doctor`。
**远程模式**只会配置本地客户端以连接到其他地方的 Gateway 网关。
@@ -102,7 +102,7 @@ CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,
## 添加另一个智能体
使用 `openclaw agents add ` 创建一个单独的智能体,它拥有自己的工作区、
-会话和认证配置文件。不带 `--workspace` 运行会启动向导。
+会话和认证配置文件。不带 `--workspace` 运行会启动新手引导。
它会设置:
@@ -113,7 +113,7 @@ CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,
说明:
- 默认工作区遵循 `~/.openclaw/workspace-`。
-- 添加 `bindings` 以路由入站消息(向导可以完成这项操作)。
+- 添加 `bindings` 以路由入站消息(新手引导可以完成这项操作)。
- 非交互式标志:`--model`、`--agent-dir`、`--bind`、`--non-interactive`。
## 完整参考
@@ -122,7 +122,7 @@ CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,
[CLI 设置参考](/start/wizard-cli-reference)。
有关非交互式示例,请参见 [CLI 自动化](/start/wizard-cli-automation)。
有关更深入的技术参考(包括 RPC 细节),请参见
-[向导参考](/reference/wizard)。
+[新手引导参考](/reference/wizard)。
## 相关文档
diff --git a/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts b/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts
index 4f40bda112c..418d5ebee83 100644
--- a/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts
+++ b/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts
@@ -127,17 +127,14 @@ export function applyGroupGating(params: ApplyGroupGatingParams) {
conversationId: params.conversationId,
});
const requireMention = activation !== "always";
- const selfJid = params.msg.selfJid?.replace(/:\d+/, "");
- const selfLid = params.msg.selfLid?.replace(/:\d+/, "");
- // replyToSenderJid may carry either a standard JID or an @lid identifier.
- const replySenderJid = params.msg.replyToSenderJid?.replace(/:\d+/, "");
+ const selfJid = params.msg.selfJid?.replace(/:\\d+/, "");
+ const replySenderJid = params.msg.replyToSenderJid?.replace(/:\\d+/, "");
const selfE164 = params.msg.selfE164 ? normalizeE164(params.msg.selfE164) : null;
const replySenderE164 = params.msg.replyToSenderE164
? normalizeE164(params.msg.replyToSenderE164)
: null;
const implicitMention = Boolean(
(selfJid && replySenderJid && selfJid === replySenderJid) ||
- (selfLid && replySenderJid && selfLid === replySenderJid) ||
(selfE164 && replySenderE164 && selfE164 === replySenderE164),
);
const mentionGate = resolveMentionGating({
diff --git a/extensions/whatsapp/src/auto-reply/web-auto-reply-monitor.test.ts b/extensions/whatsapp/src/auto-reply/web-auto-reply-monitor.test.ts
index 474b2215066..412648b3180 100644
--- a/extensions/whatsapp/src/auto-reply/web-auto-reply-monitor.test.ts
+++ b/extensions/whatsapp/src/auto-reply/web-auto-reply-monitor.test.ts
@@ -112,7 +112,7 @@ describe("applyGroupGating", () => {
accountId: "default",
body: "following up",
timestamp: Date.now(),
- selfJid: "15551234567:1@s.whatsapp.net",
+ selfJid: "15551234567@s.whatsapp.net",
selfE164: "+15551234567",
replyToId: "m0",
replyToBody: "bot said hi",
@@ -125,29 +125,6 @@ describe("applyGroupGating", () => {
expect(result.shouldProcess).toBe(true);
});
- it("treats LID-format reply-to-bot as implicit mention", () => {
- const cfg = makeConfig({});
- const { result } = runGroupGating({
- cfg,
- msg: createGroupMessage({
- id: "m1-lid",
- to: "+15550000",
- accountId: "default",
- body: "following up",
- timestamp: Date.now(),
- selfJid: "15551234567@s.whatsapp.net",
- selfLid: "1234567890123:1@lid",
- selfE164: "+15551234567",
- replyToId: "m0",
- replyToBody: "bot said hi",
- replyToSender: "1234567890123@lid",
- replyToSenderJid: "1234567890123@lid",
- }),
- });
-
- expect(result.shouldProcess).toBe(true);
- });
-
it.each([
{ id: "g-new", command: "/new" },
{ id: "g-status", command: "/status" },
diff --git a/extensions/whatsapp/src/inbound/monitor.ts b/extensions/whatsapp/src/inbound/monitor.ts
index 990d8a65f4a..5337c5d6a43 100644
--- a/extensions/whatsapp/src/inbound/monitor.ts
+++ b/extensions/whatsapp/src/inbound/monitor.ts
@@ -66,7 +66,6 @@ export async function monitorWebInbox(options: {
}
const selfJid = sock.user?.id;
- const selfLid = sock.user?.lid;
const selfE164 = selfJid ? jidToE164(selfJid) : null;
const debouncer = createInboundDebouncer({
debounceMs: options.debounceMs ?? 0,
@@ -373,7 +372,6 @@ export async function monitorWebInbox(options: {
groupParticipants: inbound.groupParticipants,
mentionedJids: mentionedJids ?? undefined,
selfJid,
- selfLid,
selfE164,
fromMe: Boolean(msg.key?.fromMe),
location: enriched.location ?? undefined,
diff --git a/extensions/whatsapp/src/inbound/types.ts b/extensions/whatsapp/src/inbound/types.ts
index 25a7edaae0c..c9c97810bad 100644
--- a/extensions/whatsapp/src/inbound/types.ts
+++ b/extensions/whatsapp/src/inbound/types.ts
@@ -30,7 +30,6 @@ export type WebInboundMessage = {
groupParticipants?: string[];
mentionedJids?: string[];
selfJid?: string | null;
- selfLid?: string | null;
selfE164?: string | null;
fromMe?: boolean;
location?: NormalizedLocation;
diff --git a/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts b/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts
index 427d7bd1d86..7e8b5c26887 100644
--- a/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts
+++ b/extensions/whatsapp/src/monitor-inbox.streams-inbound-messages.test.ts
@@ -118,12 +118,7 @@ describe("web monitor inbox", () => {
await tick();
expect(onMessage).toHaveBeenCalledWith(
- expect.objectContaining({
- body: "ping",
- from: "+999",
- to: "+123",
- selfLid: "123:1@lid",
- }),
+ expect.objectContaining({ body: "ping", from: "+999", to: "+123" }),
);
expect(sock.readMessages).toHaveBeenCalledWith([
{
@@ -186,12 +181,7 @@ describe("web monitor inbox", () => {
expect(getPNForLID).toHaveBeenCalledWith("999@lid");
expect(onMessage).toHaveBeenCalledWith(
- expect.objectContaining({
- body: "ping",
- from: "+999",
- to: "+123",
- selfLid: "123:1@lid",
- }),
+ expect.objectContaining({ body: "ping", from: "+999", to: "+123" }),
);
await listener.close();
diff --git a/extensions/whatsapp/src/monitor-inbox.test-harness.ts b/extensions/whatsapp/src/monitor-inbox.test-harness.ts
index 5dc61e9e4ac..43bc731c459 100644
--- a/extensions/whatsapp/src/monitor-inbox.test-harness.ts
+++ b/extensions/whatsapp/src/monitor-inbox.test-harness.ts
@@ -44,7 +44,7 @@ export type MockSock = {
getPNForLID: AnyMockFn;
};
};
- user: { id: string; lid?: string };
+ user: { id: string };
};
function createResolvedMock() {
@@ -66,7 +66,7 @@ function createMockSock(): MockSock {
getPNForLID: vi.fn().mockResolvedValue(null),
},
},
- user: { id: "123@s.whatsapp.net", lid: "123:1@lid" },
+ user: { id: "123@s.whatsapp.net" },
};
}
diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts
index ea6bc0c5299..ba001a6746a 100644
--- a/src/agents/pi-embedded-runner/compact.ts
+++ b/src/agents/pi-embedded-runner/compact.ts
@@ -64,10 +64,7 @@ import { ensureRuntimePluginsLoaded } from "../runtime-plugins.js";
import { resolveSandboxContext } from "../sandbox.js";
import { repairSessionFileIfNeeded } from "../session-file-repair.js";
import { guardSessionManager } from "../session-tool-result-guard-wrapper.js";
-import {
- repairToolUseResultPairing,
- sanitizeToolUseResultPairing,
-} from "../session-transcript-repair.js";
+import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js";
import {
acquireSessionWriteLock,
resolveSessionLockMaxHoldFromTimeout,
@@ -957,22 +954,6 @@ export async function compactEmbeddedPiSessionDirect(
},
},
);
- // Re-run tool_use/tool_result pairing repair after compaction.
- // Compaction can remove assistant messages containing tool_use blocks
- // while leaving orphaned tool_result blocks behind, which causes
- // Anthropic API 400 errors: "unexpected tool_use_id found in tool_result blocks".
- // See: https://github.com/openclaw/openclaw/issues/15691
- if (transcriptPolicy.repairToolUseResultPairing) {
- const postCompactRepair = repairToolUseResultPairing(session.messages);
- if (postCompactRepair.droppedOrphanCount > 0 || postCompactRepair.moved) {
- session.agent.replaceMessages(postCompactRepair.messages);
- log.info(
- `[compaction] post-compact repair: dropped ${postCompactRepair.droppedOrphanCount} orphaned tool_result(s), ` +
- `${postCompactRepair.droppedDuplicateCount} duplicate(s) ` +
- `(sessionKey=${params.sessionKey ?? params.sessionId})`,
- );
- }
- }
await runPostCompactionSideEffects({
config: params.config,
sessionKey: params.sessionKey,
diff --git a/src/agents/pi-extensions/compaction-safeguard.test.ts b/src/agents/pi-extensions/compaction-safeguard.test.ts
index 0869d05eb3f..882099f3569 100644
--- a/src/agents/pi-extensions/compaction-safeguard.test.ts
+++ b/src/agents/pi-extensions/compaction-safeguard.test.ts
@@ -28,8 +28,6 @@ const mockSummarizeInStages = vi.mocked(compactionModule.summarizeInStages);
const {
collectToolFailures,
formatToolFailuresSection,
- trimToolResultsForSummarization,
- restoreOriginalToolResultsForKeptMessages,
splitPreservedRecentTurns,
formatPreservedTurnsSection,
buildCompactionStructureInstructions,
@@ -47,26 +45,6 @@ const {
SAFETY_MARGIN,
} = __testing;
-function readTextBlocks(message: AgentMessage): string {
- const content = (message as { content?: unknown }).content;
- if (typeof content === "string") {
- return content;
- }
- if (!Array.isArray(content)) {
- return "";
- }
- return content
- .map((block) => {
- if (!block || typeof block !== "object") {
- return "";
- }
- const text = (block as { text?: unknown }).text;
- return typeof text === "string" ? text : "";
- })
- .filter(Boolean)
- .join("\n");
-}
-
function stubSessionManager(): ExtensionContext["sessionManager"] {
const stub: ExtensionContext["sessionManager"] = {
getCwd: () => "/stub",
@@ -256,116 +234,6 @@ describe("compaction-safeguard tool failures", () => {
});
});
-describe("compaction-safeguard toolResult trimming", () => {
- it("truncates oversized tool results and compacts older entries to stay within budget", () => {
- const messages: AgentMessage[] = Array.from({ length: 9 }, (_unused, index) => ({
- role: "toolResult",
- toolCallId: `call-${index}`,
- toolName: "read",
- content: [
- {
- type: "text",
- text: `head-${index}\n${"x".repeat(25_000)}\ntail-${index}`,
- },
- ],
- timestamp: index + 1,
- })) as AgentMessage[];
-
- const trimmed = trimToolResultsForSummarization(messages);
-
- expect(trimmed.stats.truncatedCount).toBe(9);
- expect(trimmed.stats.compactedCount).toBe(1);
- expect(readTextBlocks(trimmed.messages[0])).toBe("");
- expect(trimmed.stats.afterChars).toBeLessThan(trimmed.stats.beforeChars);
- expect(readTextBlocks(trimmed.messages[8])).toContain("head-8");
- expect(readTextBlocks(trimmed.messages[8])).toContain(
- "[...tool result truncated for compaction budget...]",
- );
- expect(readTextBlocks(trimmed.messages[8])).toContain("tail-8");
- });
-
- it("restores kept tool results after prune for both toolCallId and toolUseId", () => {
- const originalMessages: AgentMessage[] = [
- { role: "user", content: "keep these tool results", timestamp: 1 },
- {
- role: "toolResult",
- toolCallId: "call-1",
- toolName: "read",
- content: [{ type: "text", text: "original call payload" }],
- timestamp: 2,
- } as AgentMessage,
- {
- role: "toolResult",
- toolUseId: "use-1",
- toolName: "exec",
- content: [{ type: "text", text: "original use payload" }],
- timestamp: 3,
- } as unknown as AgentMessage,
- ];
- const prunedMessages: AgentMessage[] = [
- originalMessages[0],
- {
- role: "toolResult",
- toolCallId: "call-1",
- toolName: "read",
- content: [{ type: "text", text: "trimmed call payload" }],
- timestamp: 2,
- } as AgentMessage,
- {
- role: "toolResult",
- toolUseId: "use-1",
- toolName: "exec",
- content: [{ type: "text", text: "trimmed use payload" }],
- timestamp: 3,
- } as unknown as AgentMessage,
- ];
-
- const restored = restoreOriginalToolResultsForKeptMessages({
- prunedMessages,
- originalMessages,
- });
-
- expect(readTextBlocks(restored[1])).toBe("original call payload");
- expect(readTextBlocks(restored[2])).toBe("original use payload");
- });
-
- it("extracts identifiers from the trimmed kept payloads after prune restore", () => {
- const hiddenIdentifier = "DEADBEEF12345678";
- const restored = restoreOriginalToolResultsForKeptMessages({
- prunedMessages: [
- { role: "user", content: "recent ask", timestamp: 1 },
- {
- role: "toolResult",
- toolCallId: "call-1",
- toolName: "read",
- content: [{ type: "text", text: "placeholder" }],
- timestamp: 2,
- } as AgentMessage,
- ],
- originalMessages: [
- { role: "user", content: "recent ask", timestamp: 1 },
- {
- role: "toolResult",
- toolCallId: "call-1",
- toolName: "read",
- content: [
- {
- type: "text",
- text: `visible head ${"a".repeat(16_000)}${hiddenIdentifier}${"b".repeat(16_000)} visible tail`,
- },
- ],
- timestamp: 2,
- } as AgentMessage,
- ],
- });
-
- const trimmed = trimToolResultsForSummarization(restored).messages;
- const identifierSeedText = trimmed.map((message) => readTextBlocks(message)).join("\n");
-
- expect(extractOpaqueIdentifiers(identifierSeedText)).not.toContain(hiddenIdentifier);
- });
-});
-
describe("computeAdaptiveChunkRatio", () => {
const CONTEXT_WINDOW = 200_000;
diff --git a/src/agents/pi-extensions/compaction-safeguard.ts b/src/agents/pi-extensions/compaction-safeguard.ts
index a8c73f2efcd..4461b97d3e0 100644
--- a/src/agents/pi-extensions/compaction-safeguard.ts
+++ b/src/agents/pi-extensions/compaction-safeguard.ts
@@ -407,179 +407,6 @@ function formatPreservedTurnsSection(messages: AgentMessage[]): string {
return `\n\n## Recent turns preserved verbatim\n${lines.join("\n")}`;
}
-type ToolResultSummaryTrimStats = {
- truncatedCount: number;
- compactedCount: number;
- beforeChars: number;
- afterChars: number;
-};
-
-const COMPACTION_SUMMARY_TOOL_RESULT_MAX_CHARS = 2_500;
-const COMPACTION_SUMMARY_TOOL_RESULT_TOTAL_CHARS_BUDGET = 20_000;
-const COMPACTION_SUMMARY_TOOL_RESULT_TRUNCATION_NOTICE =
- "[...tool result truncated for compaction budget...]";
-const COMPACTION_SUMMARY_TOOL_RESULT_COMPACTED_NOTICE =
- "[tool result compacted due to global compaction budget]";
-const COMPACTION_SUMMARY_TOOL_RESULT_NON_TEXT_NOTICE = "[non-text tool result content omitted]";
-
-function getToolResultTextFromContent(content: unknown): string {
- if (!Array.isArray(content)) {
- return "";
- }
- const parts: string[] = [];
- for (const block of content) {
- if (!block || typeof block !== "object") {
- continue;
- }
- const text = (block as { text?: unknown }).text;
- if (typeof text === "string" && text.length > 0) {
- parts.push(text);
- }
- }
- return parts.join("\n");
-}
-
-function hasNonTextToolResultContent(content: unknown): boolean {
- if (!Array.isArray(content)) {
- return false;
- }
- return content.some((block) => {
- if (!block || typeof block !== "object") {
- return false;
- }
- const t = (block as { type?: unknown }).type;
- return t !== "text";
- });
-}
-
-function replaceToolResultContentForSummary(msg: AgentMessage, text: string): AgentMessage {
- return {
- ...(msg as unknown as Record),
- content: [{ type: "text", text }],
- } as AgentMessage;
-}
-
-function trimToolResultsForSummarization(messages: AgentMessage[]): {
- messages: AgentMessage[];
- stats: ToolResultSummaryTrimStats;
-} {
- const next = [...messages];
- let truncatedCount = 0;
- let compactedCount = 0;
- let beforeChars = 0;
-
- for (let i = 0; i < next.length; i += 1) {
- const msg = next[i];
- if ((msg as { role?: unknown }).role !== "toolResult") {
- continue;
- }
- const content = (msg as { content?: unknown }).content;
- const text = getToolResultTextFromContent(content);
- const hasNonText = hasNonTextToolResultContent(content);
- beforeChars += text.length;
-
- let normalized = text;
- if (normalized.length === 0 && hasNonText) {
- normalized = COMPACTION_SUMMARY_TOOL_RESULT_NON_TEXT_NOTICE;
- }
-
- if (normalized.length > COMPACTION_SUMMARY_TOOL_RESULT_MAX_CHARS) {
- const separator = `\n\n${COMPACTION_SUMMARY_TOOL_RESULT_TRUNCATION_NOTICE}\n\n`;
- const available = Math.max(0, COMPACTION_SUMMARY_TOOL_RESULT_MAX_CHARS - separator.length);
- const tailBudget = Math.floor(available * 0.35);
- const headBudget = Math.max(0, available - tailBudget);
- const head = normalized.slice(0, headBudget);
- const tail = tailBudget > 0 ? normalized.slice(-tailBudget) : "";
- normalized = `${head}${separator}${tail}`;
- truncatedCount += 1;
- }
-
- if (hasNonText || normalized !== text) {
- next[i] = replaceToolResultContentForSummary(msg, normalized);
- }
- }
-
- let runningChars = 0;
- for (let i = next.length - 1; i >= 0; i -= 1) {
- const msg = next[i];
- if ((msg as { role?: unknown }).role !== "toolResult") {
- continue;
- }
- const text = getToolResultTextFromContent((msg as { content?: unknown }).content);
- if (runningChars + text.length <= COMPACTION_SUMMARY_TOOL_RESULT_TOTAL_CHARS_BUDGET) {
- runningChars += text.length;
- continue;
- }
- const placeholderLen = COMPACTION_SUMMARY_TOOL_RESULT_COMPACTED_NOTICE.length;
- const remainingBudget = Math.max(
- 0,
- COMPACTION_SUMMARY_TOOL_RESULT_TOTAL_CHARS_BUDGET - runningChars,
- );
- const replacementText =
- remainingBudget >= placeholderLen ? COMPACTION_SUMMARY_TOOL_RESULT_COMPACTED_NOTICE : "";
- next[i] = replaceToolResultContentForSummary(msg, replacementText);
- runningChars += replacementText.length;
- compactedCount += 1;
- }
-
- let afterChars = 0;
- for (const msg of next) {
- if ((msg as { role?: unknown }).role !== "toolResult") {
- continue;
- }
- afterChars += getToolResultTextFromContent((msg as { content?: unknown }).content).length;
- }
-
- return {
- messages: next,
- stats: { truncatedCount, compactedCount, beforeChars, afterChars },
- };
-}
-
-function getToolResultStableId(message: AgentMessage): string | null {
- if ((message as { role?: unknown }).role !== "toolResult") {
- return null;
- }
- const toolCallId = (message as { toolCallId?: unknown }).toolCallId;
- if (typeof toolCallId === "string" && toolCallId.length > 0) {
- return `call:${toolCallId}`;
- }
- const toolUseId = (message as { toolUseId?: unknown }).toolUseId;
- if (typeof toolUseId === "string" && toolUseId.length > 0) {
- return `use:${toolUseId}`;
- }
- return null;
-}
-
-function restoreOriginalToolResultsForKeptMessages(params: {
- prunedMessages: AgentMessage[];
- originalMessages: AgentMessage[];
-}): AgentMessage[] {
- const originalByStableId = new Map();
- for (const message of params.originalMessages) {
- const stableId = getToolResultStableId(message);
- if (!stableId) {
- continue;
- }
- const bucket = originalByStableId.get(stableId) ?? [];
- bucket.push(message);
- originalByStableId.set(stableId, bucket);
- }
-
- return params.prunedMessages.map((message) => {
- const stableId = getToolResultStableId(message);
- if (!stableId) {
- return message;
- }
- const bucket = originalByStableId.get(stableId);
- if (!bucket || bucket.length === 0) {
- return message;
- }
- const restored = bucket.shift();
- return restored ?? message;
- });
-}
-
function wrapUntrustedInstructionBlock(label: string, text: string): string {
return wrapUntrustedPromptDataBlock({
label,
@@ -928,18 +755,6 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
const modelContextWindow = resolveContextWindowTokens(model);
const contextWindowTokens = runtime?.contextWindowTokens ?? modelContextWindow;
const turnPrefixMessages = preparation.turnPrefixMessages ?? [];
- const prefixTrimmedForBudget = trimToolResultsForSummarization(turnPrefixMessages);
- if (
- prefixTrimmedForBudget.stats.truncatedCount > 0 ||
- prefixTrimmedForBudget.stats.compactedCount > 0
- ) {
- log.warn(
- `Compaction safeguard: pre-trimmed prefix toolResult payloads for budgeting ` +
- `(truncated=${prefixTrimmedForBudget.stats.truncatedCount}, compacted=${prefixTrimmedForBudget.stats.compactedCount}, ` +
- `chars=${prefixTrimmedForBudget.stats.beforeChars}->${prefixTrimmedForBudget.stats.afterChars})`,
- );
- }
- const prefixMessagesForSummary = prefixTrimmedForBudget.messages;
let messagesToSummarize = preparation.messagesToSummarize;
const recentTurnsPreserve = resolveRecentTurnsPreserve(runtime?.recentTurnsPreserve);
const qualityGuardEnabled = runtime?.qualityGuardEnabled ?? false;
@@ -959,44 +774,28 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
let droppedSummary: string | undefined;
if (tokensBefore !== undefined) {
- const budgetTrimmedForSummary = trimToolResultsForSummarization(messagesToSummarize);
- if (
- budgetTrimmedForSummary.stats.truncatedCount > 0 ||
- budgetTrimmedForSummary.stats.compactedCount > 0
- ) {
- log.warn(
- `Compaction safeguard: pre-trimmed toolResult payloads for budgeting ` +
- `(truncated=${budgetTrimmedForSummary.stats.truncatedCount}, compacted=${budgetTrimmedForSummary.stats.compactedCount}, ` +
- `chars=${budgetTrimmedForSummary.stats.beforeChars}->${budgetTrimmedForSummary.stats.afterChars})`,
- );
- }
const summarizableTokens =
- estimateMessagesTokens(budgetTrimmedForSummary.messages) +
- estimateMessagesTokens(prefixMessagesForSummary);
+ estimateMessagesTokens(messagesToSummarize) + estimateMessagesTokens(turnPrefixMessages);
const newContentTokens = Math.max(0, Math.floor(tokensBefore - summarizableTokens));
// Apply SAFETY_MARGIN so token underestimates don't trigger unnecessary pruning
const maxHistoryTokens = Math.floor(contextWindowTokens * maxHistoryShare * SAFETY_MARGIN);
if (newContentTokens > maxHistoryTokens) {
- const originalMessagesBeforePrune = messagesToSummarize;
const pruned = pruneHistoryForContextShare({
- messages: budgetTrimmedForSummary.messages,
+ messages: messagesToSummarize,
maxContextTokens: contextWindowTokens,
maxHistoryShare,
parts: 2,
});
if (pruned.droppedChunks > 0) {
- const historyRatio = (summarizableTokens / contextWindowTokens) * 100;
+ const newContentRatio = (newContentTokens / contextWindowTokens) * 100;
log.warn(
- `Compaction safeguard: summarizable history uses ${historyRatio.toFixed(
+ `Compaction safeguard: new content uses ${newContentRatio.toFixed(
1,
)}% of context; dropped ${pruned.droppedChunks} older chunk(s) ` +
`(${pruned.droppedMessages} messages) to fit history budget.`,
);
- messagesToSummarize = restoreOriginalToolResultsForKeptMessages({
- prunedMessages: pruned.messages,
- originalMessages: originalMessagesBeforePrune,
- });
+ messagesToSummarize = pruned.messages;
// Summarize dropped messages so context isn't lost
if (pruned.droppedMessagesList.length > 0) {
@@ -1010,19 +809,8 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
Math.floor(contextWindowTokens * droppedChunkRatio) -
SUMMARIZATION_OVERHEAD_TOKENS,
);
- const droppedTrimmed = trimToolResultsForSummarization(pruned.droppedMessagesList);
- if (
- droppedTrimmed.stats.truncatedCount > 0 ||
- droppedTrimmed.stats.compactedCount > 0
- ) {
- log.warn(
- `Compaction safeguard: trimmed dropped toolResult payloads before summarize ` +
- `(truncated=${droppedTrimmed.stats.truncatedCount}, compacted=${droppedTrimmed.stats.compactedCount}, ` +
- `chars=${droppedTrimmed.stats.beforeChars}->${droppedTrimmed.stats.afterChars})`,
- );
- }
droppedSummary = await summarizeInStages({
- messages: droppedTrimmed.messages,
+ messages: pruned.droppedMessagesList,
model,
apiKey,
signal,
@@ -1054,21 +842,8 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
});
messagesToSummarize = summaryTargetMessages;
const preservedTurnsSection = formatPreservedTurnsSection(preservedRecentMessages);
- const latestUserAsk = extractLatestUserAsk([
- ...messagesToSummarize,
- ...prefixMessagesForSummary,
- ]);
- const summaryTrimmed = trimToolResultsForSummarization(messagesToSummarize);
- if (summaryTrimmed.stats.truncatedCount > 0 || summaryTrimmed.stats.compactedCount > 0) {
- log.warn(
- `Compaction safeguard: trimmed toolResult payloads before summarize ` +
- `(truncated=${summaryTrimmed.stats.truncatedCount}, compacted=${summaryTrimmed.stats.compactedCount}, ` +
- `chars=${summaryTrimmed.stats.beforeChars}->${summaryTrimmed.stats.afterChars})`,
- );
- }
-
- const identifierSourceMessages = [...summaryTrimmed.messages, ...prefixMessagesForSummary];
- const identifierSeedText = identifierSourceMessages
+ const latestUserAsk = extractLatestUserAsk([...messagesToSummarize, ...turnPrefixMessages]);
+ const identifierSeedText = [...messagesToSummarize, ...turnPrefixMessages]
.slice(-10)
.map((message) => extractMessageText(message))
.filter(Boolean)
@@ -1078,7 +853,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
// Use adaptive chunk ratio based on message sizes, reserving headroom for
// the summarization prompt, system prompt, previous summary, and reasoning budget
// that generateSummary adds on top of the serialized conversation chunk.
- const allMessages = [...summaryTrimmed.messages, ...prefixMessagesForSummary];
+ const allMessages = [...messagesToSummarize, ...turnPrefixMessages];
const adaptiveRatio = computeAdaptiveChunkRatio(allMessages, contextWindowTokens);
const maxChunkTokens = Math.max(
1,
@@ -1100,9 +875,9 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
let summaryWithPreservedTurns = "";
try {
const historySummary =
- summaryTrimmed.messages.length > 0
+ messagesToSummarize.length > 0
? await summarizeInStages({
- messages: summaryTrimmed.messages,
+ messages: messagesToSummarize,
model,
apiKey,
signal,
@@ -1116,9 +891,9 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
: buildStructuredFallbackSummary(effectivePreviousSummary, summarizationInstructions);
summaryWithoutPreservedTurns = historySummary;
- if (preparation.isSplitTurn && prefixMessagesForSummary.length > 0) {
+ if (preparation.isSplitTurn && turnPrefixMessages.length > 0) {
const prefixSummary = await summarizeInStages({
- messages: prefixMessagesForSummary,
+ messages: turnPrefixMessages,
model,
apiKey,
signal,
@@ -1218,8 +993,6 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
export const __testing = {
collectToolFailures,
formatToolFailuresSection,
- trimToolResultsForSummarization,
- restoreOriginalToolResultsForKeptMessages,
splitPreservedRecentTurns,
formatPreservedTurnsSection,
buildCompactionStructureInstructions,
diff --git a/src/agents/session-transcript-repair.test.ts b/src/agents/session-transcript-repair.test.ts
index 6ed5fdedb73..eea82268d7d 100644
--- a/src/agents/session-transcript-repair.test.ts
+++ b/src/agents/session-transcript-repair.test.ts
@@ -488,143 +488,3 @@ describe("stripToolResultDetails", () => {
expect(out).toBe(input);
});
});
-
-describe("post-compaction orphaned tool_result removal (#15691)", () => {
- it("drops orphaned tool_result blocks left after compaction removes tool_use messages", () => {
- const input = castAgentMessages([
- {
- role: "assistant",
- content: [{ type: "text", text: "Here is a summary of our earlier conversation..." }],
- },
- {
- role: "toolResult",
- toolCallId: "toolu_compacted_1",
- toolName: "Read",
- content: [{ type: "text", text: "file contents" }],
- isError: false,
- },
- {
- role: "toolResult",
- toolCallId: "toolu_compacted_2",
- toolName: "exec",
- content: [{ type: "text", text: "command output" }],
- isError: false,
- },
- { role: "user", content: "now do something else" },
- {
- role: "assistant",
- content: [
- { type: "text", text: "I'll read that file" },
- { type: "toolCall", id: "toolu_active_1", name: "Read", arguments: { path: "foo.ts" } },
- ],
- },
- {
- role: "toolResult",
- toolCallId: "toolu_active_1",
- toolName: "Read",
- content: [{ type: "text", text: "actual content" }],
- isError: false,
- },
- ]);
-
- const result = repairToolUseResultPairing(input);
-
- expect(result.droppedOrphanCount).toBe(2);
- const toolResults = result.messages.filter((message) => message.role === "toolResult");
- expect(toolResults).toHaveLength(1);
- expect((toolResults[0] as { toolCallId?: string }).toolCallId).toBe("toolu_active_1");
- expect(result.messages.map((message) => message.role)).toEqual([
- "assistant",
- "user",
- "assistant",
- "toolResult",
- ]);
- });
-
- it("handles synthetic tool_result from interrupted request after compaction", () => {
- const input = castAgentMessages([
- {
- role: "assistant",
- content: [{ type: "text", text: "Compaction summary of previous conversation." }],
- },
- {
- role: "toolResult",
- toolCallId: "toolu_interrupted",
- toolName: "unknown",
- content: [
- {
- type: "text",
- text: "[openclaw] missing tool result in session history; inserted synthetic error result for transcript repair.",
- },
- ],
- isError: true,
- },
- { role: "user", content: "continue please" },
- ]);
-
- const result = repairToolUseResultPairing(input);
-
- expect(result.droppedOrphanCount).toBe(1);
- expect(result.messages.some((message) => message.role === "toolResult")).toBe(false);
- expect(result.messages.map((message) => message.role)).toEqual(["assistant", "user"]);
- });
-
- it("preserves valid tool_use/tool_result pairs while removing orphans", () => {
- const input = castAgentMessages([
- {
- role: "assistant",
- content: [
- { type: "toolCall", id: "toolu_valid", name: "Read", arguments: { path: "a.ts" } },
- ],
- },
- {
- role: "toolResult",
- toolCallId: "toolu_valid",
- toolName: "Read",
- content: [{ type: "text", text: "content of a.ts" }],
- isError: false,
- },
- { role: "user", content: "thanks, what about b.ts?" },
- {
- role: "toolResult",
- toolCallId: "toolu_gone",
- toolName: "Read",
- content: [{ type: "text", text: "content of old file" }],
- isError: false,
- },
- {
- role: "assistant",
- content: [{ type: "text", text: "Let me check b.ts" }],
- },
- ]);
-
- const result = repairToolUseResultPairing(input);
-
- expect(result.droppedOrphanCount).toBe(1);
- const toolResults = result.messages.filter((message) => message.role === "toolResult");
- expect(toolResults).toHaveLength(1);
- expect((toolResults[0] as { toolCallId?: string }).toolCallId).toBe("toolu_valid");
- });
-
- it("returns original array when no orphans exist", () => {
- const input = castAgentMessages([
- {
- role: "assistant",
- content: [{ type: "toolCall", id: "toolu_1", name: "Read", arguments: { path: "x.ts" } }],
- },
- {
- role: "toolResult",
- toolCallId: "toolu_1",
- toolName: "Read",
- content: [{ type: "text", text: "ok" }],
- isError: false,
- },
- { role: "user", content: "good" },
- ]);
-
- const result = repairToolUseResultPairing(input);
-
- expect(result.droppedOrphanCount).toBe(0);
- expect(result.messages).toStrictEqual(input);
- });
-});
diff --git a/src/cli/config-cli.ts b/src/cli/config-cli.ts
index 0469952d322..5167658040a 100644
--- a/src/cli/config-cli.ts
+++ b/src/cli/config-cli.ts
@@ -396,7 +396,7 @@ export function registerConfigCli(program: Command) {
const cmd = program
.command("config")
.description(
- "Non-interactive config helpers (get/set/unset/file/validate). Run without subcommand for the setup wizard.",
+ "Non-interactive config helpers (get/set/unset/file/validate). Run without subcommand for guided setup.",
)
.addHelpText(
"after",
@@ -405,7 +405,7 @@ export function registerConfigCli(program: Command) {
)
.option(
"--section ",
- "Configure wizard sections (repeatable). Use with no subcommand.",
+ "Configuration sections for guided setup (repeatable). Use with no subcommand.",
(value: string, previous: string[]) => [...previous, value],
[] as string[],
)
diff --git a/src/cli/program/command-registry.ts b/src/cli/program/command-registry.ts
index 89d59bfb7ee..1955e851357 100644
--- a/src/cli/program/command-registry.ts
+++ b/src/cli/program/command-registry.ts
@@ -56,7 +56,7 @@ const coreEntries: CoreCliEntry[] = [
commands: [
{
name: "onboard",
- description: "Interactive setup wizard for gateway, workspace, and skills",
+ description: "Interactive onboarding for gateway, workspace, and skills",
hasSubcommands: false,
},
],
@@ -70,7 +70,7 @@ const coreEntries: CoreCliEntry[] = [
{
name: "configure",
description:
- "Interactive setup wizard for credentials, channels, gateway, and agent defaults",
+ "Interactive configuration for credentials, channels, gateway, and agent defaults",
hasSubcommands: false,
},
],
@@ -84,7 +84,7 @@ const coreEntries: CoreCliEntry[] = [
{
name: "config",
description:
- "Non-interactive config helpers (get/set/unset/file/validate). Default: starts setup wizard.",
+ "Non-interactive config helpers (get/set/unset/file/validate). Default: starts guided setup.",
hasSubcommands: true,
},
],
diff --git a/src/cli/program/core-command-descriptors.ts b/src/cli/program/core-command-descriptors.ts
index 8756c7bf7d4..ed7a0b10cdb 100644
--- a/src/cli/program/core-command-descriptors.ts
+++ b/src/cli/program/core-command-descriptors.ts
@@ -12,18 +12,18 @@ export const CORE_CLI_COMMAND_DESCRIPTORS = [
},
{
name: "onboard",
- description: "Interactive setup wizard for gateway, workspace, and skills",
+ description: "Interactive onboarding for gateway, workspace, and skills",
hasSubcommands: false,
},
{
name: "configure",
- description: "Interactive setup wizard for credentials, channels, gateway, and agent defaults",
+ description: "Interactive configuration for credentials, channels, gateway, and agent defaults",
hasSubcommands: false,
},
{
name: "config",
description:
- "Non-interactive config helpers (get/set/unset/file/validate). Default: starts setup wizard.",
+ "Non-interactive config helpers (get/set/unset/file/validate). Default: starts guided setup.",
hasSubcommands: true,
},
{
diff --git a/src/cli/program/register.configure.ts b/src/cli/program/register.configure.ts
index e93fb2386ed..0236503a4f2 100644
--- a/src/cli/program/register.configure.ts
+++ b/src/cli/program/register.configure.ts
@@ -11,7 +11,7 @@ import { runCommandWithRuntime } from "../cli-utils.js";
export function registerConfigureCommand(program: Command) {
program
.command("configure")
- .description("Interactive setup wizard for credentials, channels, gateway, and agent defaults")
+ .description("Interactive configuration for credentials, channels, gateway, and agent defaults")
.addHelpText(
"after",
() =>
diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts
index 0cd2828553b..3909707f263 100644
--- a/src/cli/program/register.onboard.ts
+++ b/src/cli/program/register.onboard.ts
@@ -63,7 +63,7 @@ function pickOnboardProviderAuthOptionValues(
export function registerOnboardCommand(program: Command) {
const command = program
.command("onboard")
- .description("Interactive wizard to set up the gateway, workspace, and skills")
+ .description("Interactive onboarding for the gateway, workspace, and skills")
.addHelpText(
"after",
() =>
@@ -72,7 +72,7 @@ export function registerOnboardCommand(program: Command) {
.option("--workspace ", "Agent workspace directory (default: ~/.openclaw/workspace)")
.option(
"--reset",
- "Reset config + credentials + sessions before running wizard (workspace only with --reset-scope full)",
+ "Reset config + credentials + sessions before running onboard (workspace only with --reset-scope full)",
)
.option("--reset-scope ", "Reset scope: config|config+creds+sessions|full")
.option("--non-interactive", "Run without prompts", false)
@@ -81,8 +81,8 @@ export function registerOnboardCommand(program: Command) {
"Acknowledge that agents are powerful and full system access is risky (required for --non-interactive)",
false,
)
- .option("--flow ", "Wizard flow: quickstart|advanced|manual")
- .option("--mode ", "Wizard mode: local|remote")
+ .option("--flow ", "Onboard flow: quickstart|advanced|manual")
+ .option("--mode ", "Onboard mode: local|remote")
.option("--auth-choice ", `Auth: ${AUTH_CHOICE_HELP}`)
.option(
"--token-provider ",
diff --git a/src/cli/program/register.setup.ts b/src/cli/program/register.setup.ts
index 33893d945bb..3546a2adbdf 100644
--- a/src/cli/program/register.setup.ts
+++ b/src/cli/program/register.setup.ts
@@ -20,9 +20,9 @@ export function registerSetupCommand(program: Command) {
"--workspace ",
"Agent workspace directory (default: ~/.openclaw/workspace; stored as agents.defaults.workspace)",
)
- .option("--wizard", "Run the interactive onboarding wizard", false)
- .option("--non-interactive", "Run the wizard without prompts", false)
- .option("--mode ", "Wizard mode: local|remote")
+ .option("--wizard", "Run interactive onboarding", false)
+ .option("--non-interactive", "Run onboarding without prompts", false)
+ .option("--mode ", "Onboard mode: local|remote")
.option("--remote-url ", "Remote Gateway WebSocket URL")
.option("--remote-token ", "Remote Gateway token (optional)")
.action(async (opts, command) => {
diff --git a/src/commands/auth-choice.apply.plugin-provider.ts b/src/commands/auth-choice.apply.plugin-provider.ts
index 746eb219fff..da125a4065d 100644
--- a/src/commands/auth-choice.apply.plugin-provider.ts
+++ b/src/commands/auth-choice.apply.plugin-provider.ts
@@ -238,7 +238,7 @@ export async function applyAuthChoicePluginProvider(
const provider = resolveProviderMatch(providers, options.providerId);
if (!provider) {
await params.prompter.note(
- `${options.label} auth plugin is not available. Enable it and re-run the wizard.`,
+ `${options.label} auth plugin is not available. Enable it and re-run onboarding.`,
options.label,
);
return { config: nextConfig };
diff --git a/src/cron/isolated-agent/subagent-followup.ts b/src/cron/isolated-agent/subagent-followup.ts
index a337fe528b7..b83bc7e1040 100644
--- a/src/cron/isolated-agent/subagent-followup.ts
+++ b/src/cron/isolated-agent/subagent-followup.ts
@@ -3,11 +3,14 @@ import { readLatestAssistantReply } from "../../agents/tools/agent-step.js";
import { SILENT_REPLY_TOKEN } from "../../auto-reply/tokens.js";
import { callGateway } from "../../gateway/call.js";
-const FAST_TEST_MODE = process.env.OPENCLAW_TEST_FAST === "1";
-
-const CRON_SUBAGENT_WAIT_MIN_MS = FAST_TEST_MODE ? 10 : 30_000;
-const CRON_SUBAGENT_FINAL_REPLY_GRACE_MS = FAST_TEST_MODE ? 50 : 5_000;
-const CRON_SUBAGENT_GRACE_POLL_MS = FAST_TEST_MODE ? 8 : 200;
+function resolveCronSubagentTimings() {
+ const fastTestMode = process.env.OPENCLAW_TEST_FAST === "1";
+ return {
+ waitMinMs: fastTestMode ? 10 : 30_000,
+ finalReplyGraceMs: fastTestMode ? 50 : 5_000,
+ gracePollMs: fastTestMode ? 8 : 200,
+ };
+}
const SUBAGENT_FOLLOWUP_HINTS = [
"subagent spawned",
@@ -121,8 +124,9 @@ export async function waitForDescendantSubagentSummary(params: {
timeoutMs: number;
observedActiveDescendants?: boolean;
}): Promise {
+ const timings = resolveCronSubagentTimings();
const initialReply = params.initialReply?.trim();
- const deadline = Date.now() + Math.max(CRON_SUBAGENT_WAIT_MIN_MS, Math.floor(params.timeoutMs));
+ const deadline = Date.now() + Math.max(timings.waitMinMs, Math.floor(params.timeoutMs));
// Snapshot the currently active descendant run IDs.
const getActiveRuns = () =>
@@ -166,8 +170,8 @@ export async function waitForDescendantSubagentSummary(params: {
// --- Grace period: wait for the cron agent's synthesis ---
// After the subagent announces fire and the cron agent processes them, it
// produces a new assistant message. Poll briefly (bounded by
- // CRON_SUBAGENT_FINAL_REPLY_GRACE_MS) to capture that synthesis.
- const gracePeriodDeadline = Math.min(Date.now() + CRON_SUBAGENT_FINAL_REPLY_GRACE_MS, deadline);
+ // finalReplyGraceMs) to capture that synthesis.
+ const gracePeriodDeadline = Math.min(Date.now() + timings.finalReplyGraceMs, deadline);
const resolveUsableLatestReply = async () => {
const latest = (await readLatestAssistantReply({ sessionKey: params.sessionKey }))?.trim();
@@ -186,7 +190,7 @@ export async function waitForDescendantSubagentSummary(params: {
if (latest) {
return latest;
}
- await new Promise((resolve) => setTimeout(resolve, CRON_SUBAGENT_GRACE_POLL_MS));
+ await new Promise((resolve) => setTimeout(resolve, timings.gracePollMs));
}
// Final read after grace period expires.
diff --git a/src/infra/provider-usage.auth.normalizes-keys.test.ts b/src/infra/provider-usage.auth.normalizes-keys.test.ts
index baf96781c27..261ff0203bc 100644
--- a/src/infra/provider-usage.auth.normalizes-keys.test.ts
+++ b/src/infra/provider-usage.auth.normalizes-keys.test.ts
@@ -50,6 +50,13 @@ describe("resolveProviderAuths key normalization", () => {
process.env.HOME = base;
process.env.USERPROFILE = base;
+ if (process.platform === "win32") {
+ const match = base.match(/^([A-Za-z]:)(.*)$/);
+ if (match) {
+ process.env.HOMEDRIVE = match[1];
+ process.env.HOMEPATH = match[2] || "\\";
+ }
+ }
delete process.env.OPENCLAW_HOME;
process.env.OPENCLAW_STATE_DIR = path.join(base, ".openclaw");
for (const [key, value] of Object.entries(env)) {
diff --git a/src/plugins/bundle-mcp.test.ts b/src/plugins/bundle-mcp.test.ts
index ef109f4abfb..4285b64e660 100644
--- a/src/plugins/bundle-mcp.test.ts
+++ b/src/plugins/bundle-mcp.test.ts
@@ -73,10 +73,13 @@ describe("loadEnabledBundleMcpConfig", () => {
cfg: config,
});
const resolvedServerPath = await fs.realpath(serverPath);
+ const loadedServerPath = loaded.config.mcpServers.bundleProbe?.args?.[0];
expect(loaded.diagnostics).toEqual([]);
expect(loaded.config.mcpServers.bundleProbe?.command).toBe("node");
- expect(loaded.config.mcpServers.bundleProbe?.args).toEqual([resolvedServerPath]);
+ expect(loaded.config.mcpServers.bundleProbe?.args).toHaveLength(1);
+ expect(loadedServerPath).toBeDefined();
+ expect(await fs.realpath(loadedServerPath as string)).toBe(resolvedServerPath);
} finally {
env.restore();
}
diff --git a/src/plugins/marketplace.test.ts b/src/plugins/marketplace.test.ts
index 14d3bda0323..92918e256d4 100644
--- a/src/plugins/marketplace.test.ts
+++ b/src/plugins/marketplace.test.ts
@@ -45,21 +45,22 @@ describe("marketplace plugins", () => {
const { listMarketplacePlugins } = await import("./marketplace.js");
const result = await listMarketplacePlugins({ marketplace: rootDir });
- expect(result).toEqual({
- ok: true,
- sourceLabel: expect.stringContaining(".claude-plugin/marketplace.json"),
- manifest: {
- name: "Example Marketplace",
- version: "1.0.0",
- plugins: [
- {
- name: "frontend-design",
- version: "0.1.0",
- description: "Design system bundle",
- source: { kind: "path", path: "./plugins/frontend-design" },
- },
- ],
- },
+ expect(result.ok).toBe(true);
+ if (!result.ok) {
+ throw new Error("expected marketplace listing to succeed");
+ }
+ expect(result.sourceLabel.replaceAll("\\", "/")).toContain(".claude-plugin/marketplace.json");
+ expect(result.manifest).toEqual({
+ name: "Example Marketplace",
+ version: "1.0.0",
+ plugins: [
+ {
+ name: "frontend-design",
+ version: "0.1.0",
+ description: "Design system bundle",
+ source: { kind: "path", path: "./plugins/frontend-design" },
+ },
+ ],
});
});
});