openclaw/docs/start/setup.md
Vincent Koc caee06871a
docs(gateway): split the security overview by reader job (#141162)
docs/gateway/security/index.md was 89,057 characters, 9,905 words and 25 H2
sections mixing explanation, how-to, reference and vulnerability-report triage
policy for two audiences. The page already lived in a directory with five
siblings, so the split extends that directory rather than creating a parallel
one, and index.md becomes a real index.

New children in docs/gateway/security/ (alongside audit-checks, exposure-runbook,
rate-limiting, secure-file-operations and dependency-locking):

- trust-model.md (Security trust model) - scope, trust boundary matrix, findings
  closed as no-action, gateway/node trust, threat model, reporting.
- running-the-audit.md - the `openclaw security audit` command, what it checks,
  triage order.
- hardened-baseline.md - both copy/paste baselines and the requester-scoped
  controls note.
- access-control.md - DM policy, allowlists, DM session isolation, context
  visibility, command authorization.
- prompt-injection.md - prompt injection, external-content wrapping, bypass flags.
- tool-permissions.md - control-plane tools, node execution, dynamic skills,
  plugins, sandboxing, per-agent access profiles.
- browser-control.md - browser control risks and the SSRF policy.
- network-exposure.md - bind/firewall, Docker/UFW, mDNS, Gateway auth, Tailscale,
  reverse proxy, HSTS, Control UI over HTTP, dangerous flags.
- secrets-and-storage.md - host trust, secrets on disk, credential map,
  permissions, workspace .env, logs and transcripts, secret scanning.
- operator-incident-response.md - contain, rotate, audit, collect.

Anchor strategy

Per-anchor redirects are not possible: redirectSource() in
scripts/lib/docs-redirects.mjs rejects any source containing [?#]. Every anchor
the old page published is therefore kept alive on the index itself as an
authored <a id="..." /> stub inside a "Where each section moved" list, each
pointing at its new home. Ids were computed with parseDocsDocument, not a slug
approximation, so percent-encoded punctuation and compatibility aliases are
preserved exactly. The index publishes no original heading itself, so no stub
can collide with a canonical id.

- pre-split ids on /gateway/security: 80 (57 headings, 20 compatibility
  aliases, 3 accordion targets)
- still published by /gateway/security after the split: 80
- index collisions reported by parseDocsDocument: 0
- stub destinations checked against the destination pages: 60 (all resolve)

Losslessness

Reassembling the child section bodies in original order reproduces the original
body byte for byte. Counts, original body vs children:

- words 9,665 -> 9,664
- characters 87,422 -> 87,491
- code fences 32 -> 32
- markdown links 44 -> 45
- table rows 38 -> 38

The single word/link delta is the one declared prose edit: a cross-reference the
split orphaned, `(see "Per-agent access profiles" above)` in the secure-baseline
section, is now a link to /gateway/security/tool-permissions. The index intro
line "The rest of this page is the deep end" became "The pages below are the
deep end" for the same reason. No security control, threat-model statement,
default or guarantee was reworded, softened or reordered; sections keep their
original relative order within each child.

Also updated: the "Security and sandboxing" nav group in docs/docs.json, eleven
in-repo deep links repointed at the new pages (release notes left untouched, and
their anchors still resolve through the stubs), and
src/docs/environment-docs.test.ts, which asserts on the workspace-dotenv text
that now lives in secrets-and-storage.md.

Closes audit findings: r3-0302, r3-0308
2026-09-08 19:35:27 +00:00

9 KiB

summary read_when title
Advanced setup and development workflows for OpenClaw
Setting up a new machine
You want "latest + greatest" without breaking your personal setup
Setup
If you are setting up for the first time, start with [Getting Started](/start/getting-started). For onboarding details, see [Onboarding (CLI)](/start/wizard).

TL;DR

Pick a setup workflow based on how often you want updates and whether you want to run the Gateway yourself:

  • Tailoring lives outside the repo: keep your config and workspace in ~/.openclaw/openclaw.json and ~/.openclaw/workspace/ so repo updates don't touch them.
  • Stable workflow (recommended for most): install the macOS app and let it run the bundled Gateway.
  • Bleeding edge workflow (dev): run the Gateway yourself via pnpm gateway:watch, then let the macOS app attach in Local mode.

Prereqs (from source)

  • Node 24.16+ LTS or Node 26.1+ (recommended)
  • pnpm required for source checkouts. OpenClaw loads bundled plugins from the extensions/* pnpm workspace packages in dev mode, so root npm install does not prepare the full source tree.
  • Docker (optional; only for containerized setup/e2e - see Docker)

Use the pnpm version pinned in package.json. The workspace applies a seven-day publication cooldown to npm dependencies, with trusted @openai/codex and @openai/codex-* packages exempt. The standalone pnpm toolchain is managed separately.

For npm tooling that reads the project's .npmrc, use npm 11.19 or newer for install and npm pack cooldowns and Codex exclusions. Node runtime support does not imply support for its bundled npm as a source resolver. Published/global installs do not inherit the repository's .npmrc. Source installs continue to use pnpm.

pnpm owns root and plugin-local dependencies, including workspace links and versions that differ between packages. Postinstall and build preparation preserve those trees. If an older checkout pruned plugin-local dependencies, run pnpm install --frozen-lockfile after updating to restore them before testing.

Tailoring strategy (so updates do not hurt)

If you want "100% tailored to me" and easy updates, keep your customization in:

  • Config: ~/.openclaw/openclaw.json (JSON/JSON5-ish)
  • Workspace: ~/.openclaw/workspace (skills, prompts, memories; make it a private git repo)

Bootstrap the config/workspace folders once, without running the full onboarding wizard:

openclaw setup --baseline

No global install yet? Run it from this repo instead:

pnpm openclaw setup --baseline

(Bare openclaw setup, without --baseline, opens an interactive OpenClaw chat on a configured system and falls through to guided onboarding on a fresh one. See Setup CLI for the full routing order.)

Run the Gateway from this repo

After pnpm build, you can run the packaged CLI directly:

node openclaw.mjs gateway --port 18789 --verbose

Stable workflow (macOS app first)

  1. Install + launch OpenClaw.app (menu bar).
  2. Complete the onboarding/permissions checklist (TCC prompts).
  3. Ensure Gateway is Local and running (the app manages it).
  4. Link surfaces (example: WhatsApp):
openclaw channels login
  1. Sanity check:
openclaw health

If onboarding is not available in your build:

  • Run openclaw setup, then openclaw channels login, then start the Gateway manually (openclaw gateway).

Bleeding edge workflow (Gateway in a terminal)

Goal: work on the TypeScript Gateway, get hot reload, keep the macOS app UI attached.

0) (Optional) Run the macOS app from source too

If you also want the macOS app on the bleeding edge:

./scripts/restart-mac.sh

1) Start the dev Gateway

pnpm install
# First run only (or after resetting local OpenClaw config/workspace)
pnpm openclaw setup
pnpm gateway:watch

What gateway:watch does:

  • It starts or restarts the Gateway watch process in a named tmux session, openclaw-gateway-watch-main, and auto-attaches from interactive terminals.
  • Non-interactive shells stay detached and print tmux attach -t openclaw-gateway-watch-main. Run OPENCLAW_GATEWAY_WATCH_ATTACH=0 pnpm gateway:watch to keep an interactive run detached, or pnpm gateway:watch:raw for foreground watch mode.
  • It stops the active profile's installed Gateway service before it takes over that service's configured or default port. This prevents the service supervisor from replacing the source process. The service stays installed. Run pnpm openclaw gateway start when you finish watching.
  • The tmux pane remains available after a startup failure, so another terminal or agent can attach to it or capture its logs.
  • It reloads on relevant source, config, and bundled-plugin metadata changes.
  • If the watched Gateway exits during startup, gateway:watch runs openclaw doctor --fix --non-interactive once and retries. Set OPENCLAW_GATEWAY_WATCH_AUTO_DOCTOR=0 to disable that dev-only repair pass.

TypeScript rebuilds triggered by pnpm openclaw ... or pnpm gateway:watch preserve existing dist/control-ui assets. When the Gateway starts, it rebuilds missing, incomplete, or stale bundled UI assets before serving them. Headless commands do not rebuild the UI. Run pnpm ui:build after ui/ changes, or use pnpm ui:dev while developing the Control UI.

2) Point the macOS app at your running Gateway

In OpenClaw.app:

  • Connection Mode: Local The app will attach to the running gateway on the configured port.

3) Verify

  • In-app Gateway status should read "Using existing gateway …"
  • Or via CLI:
openclaw health

Common footguns

  • Wrong port: Gateway WS defaults to ws://127.0.0.1:18789; keep app + CLI on the same port.
  • Wrong developer CLI: When PATH includes node_modules/.bin, codex can resolve to the workspace-pinned CLI instead of your standalone installation. For developer workers, use the intended executable's absolute path for both --version and exec, and confirm the worker's startup version. A package manifest or a version check in another shell does not identify a running worker. OpenClaw's managed Codex app-server has a separate pinned-version contract; do not change that pin or your model/auth settings to fix developer CLI selection. If the installed workspace package and native executable disagree with the lockfile, repair the install with pnpm install rather than editing node_modules.
  • Where state lives:
    • Channel/provider state: ~/.openclaw/credentials/
    • Model auth profiles: SQLite auth stores (shared: ~/.openclaw/state/openclaw.sqlite; agent-local: ~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite)
    • Sessions and transcripts: ~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite
    • Legacy/archive session artifacts: ~/.openclaw/agents/<agentId>/sessions/
    • Logs: /tmp/openclaw/

Credential storage map

Use this when debugging auth or deciding what to back up:

  • WhatsApp: ~/.openclaw/credentials/whatsapp/<accountId>/creds.json
  • Telegram bot token: config/env or channels.telegram.tokenFile (regular file only; symlinks rejected)
  • Discord bot token: config/env or SecretRef (env/file/exec/store providers)
  • Slack tokens: config/env (channels.slack.*)
  • Pairing allowlists:
    • ~/.openclaw/credentials/<channel>-allowFrom.json (default account)
    • ~/.openclaw/credentials/<channel>-<accountId>-allowFrom.json (non-default accounts)
  • Model auth profiles: shared and agent-local SQLite auth stores; see Auth credential semantics for inheritance and legacy shared-store relocation
  • File-backed secrets payload (optional): ~/.openclaw/secrets.json
  • Legacy OAuth import: ~/.openclaw/credentials/oauth.json More detail: Security.

Updating (without wrecking your setup)

  • Keep ~/.openclaw/workspace and ~/.openclaw/ as "your stuff"; don't put personal prompts/config into the openclaw repo.
  • Updating source: git pull + pnpm install + keep using pnpm gateway:watch.

Linux (systemd user service)

Linux installs use a systemd user service. By default, systemd stops user services on logout/idle, which kills the Gateway. Onboarding attempts to enable lingering for you (may prompt for sudo). If it's still off, run:

sudo loginctl enable-linger $USER

For always-on or multi-user servers, consider a system service instead of a user service (no lingering needed). See Gateway runbook for the systemd notes.