From ff9cb0f679ef35ce82ee509ed3f0d4bcf7b21855 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 18 Jul 2026 03:54:45 +0100 Subject: [PATCH] fix(onboarding): leave session.dmScope unset so the personal-agent default "main" applies (#110225) * fix(onboarding): leave session.dmScope unset so the personal-agent default "main" applies * chore(onboarding): document deliberate dmScope personal-agent default * docs(security): align formal-verification dmScope claim with the personal-agent default --- docs/gateway/security/index.md | 2 +- docs/reference/wizard.md | 2 +- docs/security/formal-verification.md | 2 +- docs/start/wizard-cli-reference.md | 2 +- docs/start/wizard.md | 2 +- src/commands/onboard-config.test.ts | 5 +++-- src/commands/onboard-config.ts | 10 +++------- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/gateway/security/index.md b/docs/gateway/security/index.md index 644bcd6b7a93..63517f229b06 100644 --- a/docs/gateway/security/index.md +++ b/docs/gateway/security/index.md @@ -197,7 +197,7 @@ By default, OpenClaw routes all DMs into the main session for cross-device conti | `per-account-channel-peer` | Like above, split further by account (multi-account channels). | | `per-peer` | Each sender gets one session across all channels of the same type. | -Local CLI onboarding writes `session.dmScope: "per-channel-peer"` when unset, and preserves any explicit existing value. +Local CLI onboarding preserves an explicit `session.dmScope` and otherwise leaves it unset, so the `"main"` default applies: all direct messages across channels share the agent's rolling main session (the personal-agent default). For shared or multi-user inboxes, set `session.dmScope: "per-channel-peer"`; `openclaw security audit` recommends isolation when it detects multi-user DM traffic. This is a messaging-context boundary, not a host-admin boundary. If users are mutually adversarial and share the same Gateway host/config, run separate gateways per trust boundary instead. diff --git a/docs/reference/wizard.md b/docs/reference/wizard.md index 0488ba6de3a3..340fab43e0c4 100644 --- a/docs/reference/wizard.md +++ b/docs/reference/wizard.md @@ -238,7 +238,7 @@ Typical fields in `~/.openclaw/openclaw.json`: - `agents.defaults.model` / `models.providers` (if Minimax chosen) - `tools.profile` (local onboarding defaults to `"coding"` when unset; existing explicit values are preserved) - `gateway.*` (mode, bind, auth, tailscale) -- `session.dmScope` (local onboarding defaults this to `"per-channel-peer"` when unset; existing explicit values are preserved. Details: [CLI Setup Reference](/start/wizard-cli-reference#outputs-and-internals)) +- `session.dmScope` (onboarding preserves explicit values and otherwise leaves it unset, so the `"main"` default keeps all direct messages across channels in the agent's rolling main session—the personal-agent default. For shared or multi-user inboxes, use `"per-channel-peer"`; `openclaw security audit` recommends isolation when it detects multi-user DM traffic. Details: [CLI Setup Reference](/start/wizard-cli-reference#outputs-and-internals)) - `channels.telegram.botToken`, `channels.discord.token`, `channels.matrix.*`, `channels.signal.*`, `channels.imessage.*` - Channel DM allowlists when you opt in during the channel prompts. Discord, Matrix, Microsoft Teams, and Slack resolve names to IDs when possible; other channels take IDs directly (for example numeric Telegram sender IDs or WhatsApp phone numbers). - `skills.install.nodeManager` diff --git a/docs/security/formal-verification.md b/docs/security/formal-verification.md index 979d21a120e9..acf372383545 100644 --- a/docs/security/formal-verification.md +++ b/docs/security/formal-verification.md @@ -123,7 +123,7 @@ Follow-on models that tighten fidelity around real-world failure modes: non-atom ### Routing dmScope precedence and identityLinks -**Claim:** routing keeps DM sessions isolated by default and only collapses sessions when explicitly configured, via channel precedence and identity links. Channel-specific `dmScope` overrides win over global defaults; `identityLinks` collapse sessions only within explicit linked groups, not across unrelated peers. +**Claim:** `dmScope` precedence and identity links behave deterministically: the default `main` scope shares one rolling session across a single owner's DMs (the personal-agent default), while any configured isolating scope (`per-peer`, `per-channel-peer`, `per-account-channel-peer`) keeps DM sessions strictly separated. Channel-specific `dmScope` overrides win over global defaults; `identityLinks` collapse sessions only within explicit linked groups, not across unrelated peers. Multi-user inboxes are expected to opt into an isolating scope (the runtime security audit recommends this when it detects multi-user DM traffic). | Result | Targets | | -------------- | ------------------------------------------------------------------------- | diff --git a/docs/start/wizard-cli-reference.md b/docs/start/wizard-cli-reference.md index 67eb3f300b6e..e2e0aa72327a 100644 --- a/docs/start/wizard-cli-reference.md +++ b/docs/start/wizard-cli-reference.md @@ -325,7 +325,7 @@ Typical fields in `~/.openclaw/openclaw.json`: - `agents.defaults.model` / `models.providers` (if Minimax chosen) - `tools.profile` (local onboarding defaults to `"coding"` when unset; existing explicit values are preserved) - `gateway.*` (mode, bind, auth, tailscale) -- `session.dmScope` (local onboarding defaults this to `per-channel-peer` when unset; existing explicit values are preserved) +- `session.dmScope` (onboarding preserves explicit values and otherwise leaves it unset, so the `main` default keeps all direct messages across channels in the agent's rolling main session—the personal-agent default. For shared or multi-user inboxes, use `per-channel-peer`; `openclaw security audit` recommends isolation when it detects multi-user DM traffic) - `channels.telegram.botToken`, `channels.discord.token`, `channels.matrix.*`, `channels.signal.*`, `channels.imessage.*` - Channel allowlists (Discord, iMessage, Signal, Slack, Telegram, WhatsApp) when you opt in during prompts; Discord and Slack also resolve entered names to IDs - `skills.install.nodeManager` diff --git a/docs/start/wizard.md b/docs/start/wizard.md index b68ee53f69ab..638b89333eb8 100644 --- a/docs/start/wizard.md +++ b/docs/start/wizard.md @@ -113,7 +113,7 @@ flow and skip that prompt. - Gateway port **18789** - Gateway auth **Token** (auto-generated, even on loopback) - Tool policy: `tools.profile: "coding"` for new setups (an existing explicit profile is preserved) - - DM isolation: `session.dmScope: "per-channel-peer"` for new setups. Details: [CLI setup reference](/start/wizard-cli-reference#outputs-and-internals) + - DM sessions: onboarding preserves an explicit `session.dmScope` and otherwise leaves it unset, so the `"main"` default keeps all direct messages across channels in the agent's rolling main session—the personal-agent default. For shared or multi-user inboxes, use `"per-channel-peer"`; `openclaw security audit` recommends isolation when it detects multi-user DM traffic. Details: [CLI setup reference](/start/wizard-cli-reference#outputs-and-internals) - Tailscale exposure **Off** - Telegram and WhatsApp DMs default to **allowlist**: Telegram asks for a numeric Telegram user ID, WhatsApp asks for a phone number diff --git a/src/commands/onboard-config.test.ts b/src/commands/onboard-config.test.ts index 73652a57aabb..6f06dd1ef12f 100644 --- a/src/commands/onboard-config.test.ts +++ b/src/commands/onboard-config.test.ts @@ -4,11 +4,12 @@ import type { OpenClawConfig } from "../config/config.js"; import { applyLocalSetupWorkspaceConfig } from "./onboard-config.js"; describe("applyLocalSetupWorkspaceConfig", () => { - it("sets secure dmScope default when unset", () => { + it("leaves dmScope unset when not configured", () => { const baseConfig: OpenClawConfig = {}; const result = applyLocalSetupWorkspaceConfig(baseConfig, "/tmp/workspace"); - expect(result.session?.dmScope).toBe("per-channel-peer"); + expect(result.session?.dmScope).toBeUndefined(); + expect(result).not.toHaveProperty("session.dmScope"); expect(result.gateway?.mode).toBe("local"); expect(result.agents?.defaults?.workspace).toBe("/tmp/workspace"); expect(result.tools?.profile).toBe("coding"); diff --git a/src/commands/onboard-config.ts b/src/commands/onboard-config.ts index a204ea919920..e7f1e37e5755 100644 --- a/src/commands/onboard-config.ts +++ b/src/commands/onboard-config.ts @@ -1,15 +1,15 @@ /** Shared config mutations used by interactive and non-interactive onboarding. */ import { setConfigValueAtPath } from "../config/config-paths.js"; -import type { DmScope } from "../config/types.base.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { ToolProfileId } from "../config/types.tools.js"; -/** Default DM scoping selected during local onboarding. */ -const ONBOARDING_DEFAULT_DM_SCOPE: DmScope = "per-channel-peer"; /** Default tool profile selected during local onboarding. */ const ONBOARDING_DEFAULT_TOOLS_PROFILE: ToolProfileId = "coding"; /** Applies local gateway/workspace defaults without overwriting explicit user defaults. */ +// Deliberately writes no session.dmScope: the schema default "main" (one rolling +// personal-agent session across channels) is the product default. Multi-user DM +// isolation is opt-in; `openclaw security audit` nudges it when traffic warrants. export function applyLocalSetupWorkspaceConfig( baseConfig: OpenClawConfig, workspaceDir: string, @@ -27,10 +27,6 @@ export function applyLocalSetupWorkspaceConfig( ...baseConfig.gateway, mode: "local", }, - session: { - ...baseConfig.session, - dmScope: baseConfig.session?.dmScope ?? ONBOARDING_DEFAULT_DM_SCOPE, - }, tools: { ...baseConfig.tools, profile: baseConfig.tools?.profile ?? ONBOARDING_DEFAULT_TOOLS_PROFILE,