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--forceport 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-devand sets the gateway port default to19001(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:
-
Profile isolation (global
--dev)OPENCLAW_PROFILE=devOPENCLAW_STATE_DIR=~/.openclaw-devOPENCLAW_CONFIG_PATH=~/.openclaw-dev/openclaw.jsonOPENCLAW_GATEWAY_PORT=19001(browser and canvas ports shift accordingly)
-
Dev bootstrap (
gateway --dev)- Writes a minimal config when one is missing (
gateway.mode=local, bind loopback). - Points
agents.defaults.workspaceat the dev workspace and setsagents.defaults.skipBootstrap=true. - Populates missing workspace files:
AGENTS.md,SOUL.md,IDENTITY.md,USER.md. - Default identity: C3-PO (protocol droid).
pnpm gateway:devadditionally configuresOPENCLAW_SKIP_CHANNELS=1to skip channel providers.
- Writes a minimal config when one is missing (
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
--devis 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:
- Rebuild and Debug Gateway - removes
/distand rebuilds with debugging enabled before starting the Gateway. - Debug Gateway - debugs an existing build without touching
/dist.
Setup
- Open Run and Debug (Activity Bar, or
Ctrl+Shift+D). - Choose Rebuild and Debug Gateway and press Start Debugging.
To handle the build/debug cycle manually instead:
- 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
- Linux/macOS:
- Rebuild:
pnpm clean:dist && pnpm build - 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
/distand, on each startup, performs a completepnpm buildthat 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.jsonandargs. - If you need the built CLI for other purposes, such as
dashboard --no-openwhen your debug session generates a fresh auth token, launch it from a different terminal vianode ./openclaw.mjsor a shortcut likealias openclaw-build="node $(pwd)/openclaw.mjs".