Debugging OpenClaw: Runtime Overrides, Traces, and Profiling

Learn to debug OpenClaw with runtime config overrides, session trace output, and plugin lifecycle tracing. Essential for developers troubleshooting streaming output and gateway behavior.

Read this when

  • You need to inspect raw model output for reasoning leakage
  • You want to run the Gateway in watch mode while iterating
  • You need a repeatable debugging workflow
  • You are diagnosing Node or tsx startup errors

Debugging aids for streaming output, gateway iteration, and startup profiling.

Runtime debug overrides

/debug applies runtime-only config overrides, affecting memory rather than disk. It is off by default; turn it on with commands.debug: true.

/debug show
/debug set channels.whatsapp.responsePrefix="[openclaw]"
/debug unset channels.whatsapp.responsePrefix
/debug reset

/debug reset removes all overrides and reverts to the configuration stored on disk.

Session trace output

/trace surfaces plugin-specific trace and debug lines for a single session without activating full verbose mode. It is meant for plugin diagnostics like Active Memory debug summaries; rely on /verbose for routine status and tool output.

/trace
/trace on
/trace off

Plugin lifecycle trace

Set OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1 to get a stage-by-stage breakdown of plugin metadata, discovery, registry, runtime mirror, config mutation, and refresh operations. Output goes to stderr, so JSON command results remain parseable. Plugin load errors include their stack trace while this trace is active.

OPENCLAW_PLUGIN_LIFECYCLE_TRACE=1 openclaw plugins install tokenjuice --force
[plugins:lifecycle] phase="config read" ms=6.83 status=ok command="install"
[plugins:lifecycle] phase="slot selection" ms=94.31 status=ok command="install" pluginId="tokenjuice"
[plugins:lifecycle] phase="registry refresh" ms=51.56 status=ok command="install" reason="source-changed"

Reach for this before a CPU profiler. From a source checkout, gauge the built runtime with node dist/entry.js ... after pnpm build; pnpm openclaw ... also captures source-runner overhead.

For synchronous module-load timing, use the shared diagnostics surface rather than a separate plugin-only environment switch:

OPENCLAW_DIAGNOSTICS=plugin.load-profile openclaw plugins list

CLI startup and command profiling

Checked-in startup benchmarks:

pnpm test:startup:bench:smoke
pnpm tsx scripts/bench-cli-startup.ts --preset real --case status --runs 3
pnpm tsx scripts/bench-cli-startup.ts --preset real --cpu-prof-dir .artifacts/cli-cpu

For one-off profiling through the standard source runner, configure OPENCLAW_RUN_NODE_CPU_PROF_DIR:

OPENCLAW_RUN_NODE_CPU_PROF_DIR=.artifacts/cli-cpu pnpm openclaw status

The source runner adds Node CPU profile flags and writes a .cpuprofile for the command. Use this before adding temporary instrumentation to command code.

For startup stalls that look like synchronous filesystem or module-loader work, add Node's sync I/O trace flag through the source runner:

OPENCLAW_TRACE_SYNC_IO=1 pnpm openclaw gateway --force

pnpm gateway:watch keeps this flag off by default for the watched Gateway child; set OPENCLAW_TRACE_SYNC_IO=1 when you want sync I/O trace output in watch mode as well.

Gateway watch mode

pnpm gateway:watch

By default this starts or restarts a tmux session named openclaw-gateway-watch-<profile> (for instance openclaw-gateway-watch-main), with a port suffix like openclaw-gateway-watch-dev-19001 added only when OPENCLAW_GATEWAY_PORT differs from the default port 18789. It auto-attaches from interactive terminals; non-interactive shells, CI, and agent exec calls stay detached and print attach instructions instead:

tmux attach -t openclaw-gateway-watch-main
# Read recent output without attaching
tmux capture-pane -ep -t openclaw-gateway-watch-main -S -200

The pane relies on tmux remain-on-exit, so startup failures remain available for attach or capture rather than deleting the session. Re-running pnpm gateway:watch respawns that pane.

The tmux pane runs the raw watcher:

node scripts/watch-node.mjs gateway --force

Before watching the configured/default port, the tmux wrapper stops the active profile's installed Gateway service. This hands the port to the source watcher without launchd, systemd, or Scheduled Task respawning and replacing it. The service stays installed; restore it after the watch session with:

pnpm openclaw gateway start

When an explicit --port or OPENCLAW_GATEWAY_PORT differs from the installed service's effective port, the wrapper leaves the service running so both Gateways can operate side by side.

Foreground mode without tmux:

pnpm gateway:watch:raw
# or
OPENCLAW_GATEWAY_WATCH_TMUX=0 pnpm gateway:watch

Raw mode does not manage the installed service. Run pnpm openclaw gateway stop first when it uses the same port.

Keep tmux management but disable auto-attach:

OPENCLAW_GATEWAY_WATCH_ATTACH=0 pnpm gateway:watch

Profile watched Gateway CPU time when debugging startup/runtime hotspots:

pnpm gateway:watch --benchmark

The watch wrapper consumes --benchmark before invoking the Gateway and writes one V8 .cpuprofile per Gateway child exit under .artifacts/gateway-watch-profiles/. Stop or restart the watched gateway to flush the current profile, then open it with Chrome DevTools or Speedscope:

npx speedscope .artifacts/gateway-watch-profiles/*.cpuprofile
  • --benchmark-dir <path>: write profiles elsewhere.
  • --benchmark-no-force: skip the default --force port cleanup and fail fast if the Gateway port is already in use.

Benchmark mode suppresses sync-I/O trace spam by default. Set OPENCLAW_TRACE_SYNC_IO=1 with --benchmark to get both CPU profiles and sync-I/O stack traces; in benchmark mode those trace blocks go to gateway-watch-output.log under the benchmark directory (filtered from the terminal pane), while normal Gateway logs stay visible.

The tmux wrapper carries common non-secret runtime selectors into the pane, including OPENCLAW_PROFILE, OPENCLAW_CONFIG_PATH, OPENCLAW_STATE_DIR, OPENCLAW_GATEWAY_PORT, and OPENCLAW_SKIP_CHANNELS. Put provider credentials in your normal profile/config, or use raw foreground mode for one-off ephemeral secrets.

If the watched Gateway exits during startup, the watcher runs openclaw doctor --fix --non-interactive once and restarts the Gateway child. Set OPENCLAW_GATEWAY_WATCH_AUTO_DOCTOR=0 to see the original startup failure without the dev-only repair pass.

The managed tmux pane shows Gateway logs in color by default. To turn off ANSI output, set FORCE_COLOR=0 when you launch pnpm gateway:watch.

Build-relevant files under src/, extension source files, extension package.json and openclaw.plugin.json metadata, tsconfig.json, package.json, and tsdown.config.ts all trigger a watcher restart. Changes to extension metadata restart the gateway without a rebuild, while source and config changes still rebuild dist first.

Gateway CLI flags go after gateway:watch and carry through on every restart. Re-running the same watch command respawns the named tmux pane; the raw watcher holds a single-watcher lock, so duplicate watcher parents get replaced rather than accumulating.

Dev profile + dev gateway (--dev)

Two separate --dev flags:

  • Global --dev (profile): isolates state under ~/.openclaw-dev and sets the gateway port default to 19001 (derived ports move with it).
  • gateway --dev: makes the Gateway create a default config and workspace automatically when they are absent (and skip bootstrap).

Suggested workflow (dev profile and dev bootstrap):

pnpm gateway:dev
OPENCLAW_PROFILE=dev openclaw tui

If there is no global install, invoke the CLI through pnpm openclaw ....

What this accomplishes:

  1. Profile isolation (global --dev)

    • OPENCLAW_PROFILE=dev
    • OPENCLAW_STATE_DIR=~/.openclaw-dev
    • OPENCLAW_CONFIG_PATH=~/.openclaw-dev/openclaw.json
    • OPENCLAW_GATEWAY_PORT=19001 (browser and canvas ports shift accordingly)
  2. Dev bootstrap (gateway --dev)

    • Writes a minimal config when one is missing (gateway.mode=local, bind loopback).
    • Points agents.defaults.workspace at the dev workspace and sets agents.defaults.skipBootstrap=true.
    • Populates missing workspace files: AGENTS.md, SOUL.md, IDENTITY.md, USER.md.
    • Default identity: C3-PO (protocol droid).
    • pnpm gateway:dev additionally configures OPENCLAW_SKIP_CHANNELS=1 to skip channel providers.

By default, all Gateways ignore ambient channel environment triggers, so credentials inherited from the launching shell do not connect to channel services without explicit intent. A channels.<id> configuration block still enables that channel and can use environment variables for its credentials. Pass --ambient-channels to restore ambient channel auto-configuration for that run; --dev-ambient-channels remains as a deprecated alias.

Reset flow (fresh start):

pnpm gateway:dev:reset

Note

--dev is a global profile flag and gets consumed by some runners. To spell it out explicitly, use the env var form:

OPENCLAW_PROFILE=dev openclaw gateway --dev --reset

--reset removes config, credentials, sessions, and the dev workspace (moved to trash, not deleted), then recreates the default dev setup.

Tip

If a non-dev gateway is already running (launchd or systemd), stop it first:

openclaw gateway stop

Raw stream logging

OpenClaw can log the raw assistant stream before any filtering or formatting. This is the best way to see whether reasoning arrives as plain text deltas or as separate thinking blocks.

Enable it via CLI:

pnpm gateway:watch --raw-stream

Optional path override:

pnpm gateway:watch --raw-stream --raw-stream-path ~/.openclaw/logs/raw-stream.jsonl

Equivalent env vars:

OPENCLAW_RAW_STREAM=1
OPENCLAW_RAW_STREAM_PATH=~/.openclaw/logs/raw-stream.jsonl

Default file: ~/.openclaw/logs/raw-stream.jsonl

Safety notes

  • Raw stream logs may contain full prompts, tool output, and user data.
  • Keep logs local and delete them after debugging.
  • If you share logs, scrub secrets and PII first.

Debugging in VSCode

Source maps are necessary because the build hashes generated filenames. The included launch.json targets the Gateway service:

  1. Rebuild and Debug Gateway - removes /dist and rebuilds with debugging enabled before starting the Gateway.
  2. Debug Gateway - debugs an existing build without touching /dist.

Setup

  1. Open Run and Debug (Activity Bar, or Ctrl+Shift+D).
  2. Choose Rebuild and Debug Gateway and press Start Debugging.

To handle the build/debug cycle manually instead:

  1. Enable source maps in a terminal:
    • Linux/macOS: export OUTPUT_SOURCE_MAPS=1
    • Windows (PowerShell): $env:OUTPUT_SOURCE_MAPS="1"
    • Windows (CMD): set OUTPUT_SOURCE_MAPS=1
  2. Rebuild: pnpm clean:dist && pnpm build
  3. Choose Debug Gateway and press Start Debugging.

Set breakpoints in src/ TypeScript files; the debugger maps them to compiled JavaScript through source maps.

Notes

  • Rebuild and Debug Gateway removes /dist and, on each startup, performs a complete pnpm build that includes source maps.
  • With Debug Gateway, you can pause or resume without touching /dist, though the build process must be handled in a separate terminal.
  • For debugging other CLI subcommands, adjust launch.json and args.
  • If you need the built CLI for other purposes, such as dashboard --no-open when your debug session generates a fresh auth token, launch it from a different terminal via node ./openclaw.mjs or a shortcut like alias openclaw-build="node $(pwd)/openclaw.mjs".
1,517 words · updated Aug 17, 2026