Skip to content

CLI: reduce startup overhead for health and status --json#30940

Merged
vincentkoc merged 22 commits intoopenclaw:mainfrom
vincentkoc:vincentkoc-code/rpi-fast-route-5871
Mar 1, 2026
Merged

CLI: reduce startup overhead for health and status --json#30940
vincentkoc merged 22 commits intoopenclaw:mainfrom
vincentkoc:vincentkoc-code/rpi-fast-route-5871

Conversation

@vincentkoc
Copy link
Member

@vincentkoc vincentkoc commented Mar 1, 2026

Summary

  • make route plugin preloading argv-aware so status --json skips plugin preloading
  • remove eager plugin preload for health fast-route
  • skip channel table synthesis in scanStatus when --json is used
  • add route tests for conditional preload behavior
  • add root-only version invocation detection in argv helpers
  • add entry fast-path so root --version/-V/-v bypasses full CLI bootstrap
  • add argv tests for root version fast-path detection
  • parallelize status --json security audit with status scan work
  • add a parallel JSON scan path that overlaps independent probes/checks
  • fix CI issues from fast-path follow-ups (top-level return + StatusScanResult typing)
  • enable Node module compile cache at startup using module.enableCompileCache() with safe no-throw behavior
  • add startup tuning docs for Pi and low-power VM hosts (NODE_COMPILE_CACHE, OPENCLAW_NO_RESPAWN)

Testing

  • pnpm tsgo
  • pnpm test src/commands/status.test.ts src/cli/argv.test.ts src/cli/program/routes.test.ts
  • pnpm build

Benchmark Snapshot (local)

  • node dist/entry.js --version: ~1025ms -> ~89ms average
  • node dist/entry.js status --json: ~4913ms -> ~3787ms average
  • node dist/entry.js status: ~6939ms -> ~5914ms average

Fixes: #5871

@openclaw-barnacle openclaw-barnacle bot added cli CLI command changes commands Command implementations size: XS maintainer Maintainer-authored PR labels Mar 1, 2026
@vincentkoc
Copy link
Member Author

Fixed the two failing checks on latest head (45f0bfba8b):

  1. A 'return' statement can only be used within a function body.

    • Updated src/entry.ts to avoid top-level return in the version fast-path branch.
  2. Type ... is not assignable to type 'StatusScanResult'.

    • Updated src/commands/status.scan.ts so JSON fast-path returns channels with the expected shape { rows, details }.
    • Removed dead/non-narrowed opts.json paths in the non-JSON branch.

Validation run locally:

  • pnpm tsgo
  • pnpm test src/commands/status.test.ts src/cli/argv.test.ts src/cli/program/routes.test.ts
  • pnpm build

@openclaw-barnacle openclaw-barnacle bot added the docs Improvements or additions to documentation label Mar 1, 2026
@openclaw-barnacle openclaw-barnacle bot added the scripts Repository scripts label Mar 1, 2026
@vincentkoc
Copy link
Member Author

Related prior work: #27973 by @lupuletic covers the same startup problem space and informed this iteration.

This PR currently carries the subset we validated end-to-end here (route/preload changes, --version fast path, status scan concurrency, compile-cache enable, and docs updates). If maintainers want, we can follow up by selectively porting any remaining ideas from #27973 that are still missing after merge.

@vincentkoc vincentkoc marked this pull request as ready for review March 1, 2026 20:46
@aisle-research-bot
Copy link

aisle-research-bot bot commented Mar 1, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🔵 Low Environment-controlled Node compile cache enabled at startup (unsafe when run with elevated privileges)

1. 🔵 Environment-controlled Node compile cache enabled at startup (unsafe when run with elevated privileges)

Property Value
Severity Low
CWE CWE-73
Location src/entry.ts:45-52

Description

src/entry.ts enables Node’s module compile cache at process start unless NODE_DISABLE_COMPILE_CACHE is truthy:

  • The cache location is controlled by Node, and can be influenced via environment (notably NODE_COMPILE_CACHE).
  • This project does not constrain/validate the cache directory before calling enableCompileCache().
  • The docs explicitly recommend setting NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache.

Security impact (local):

  • If the CLI is ever executed with elevated privileges while inheriting an untrusted environment (e.g., sudo -E openclaw ..., misconfigured sudoers env_keep+=NODE_COMPILE_CACHE, or a service wrapper that passes user-controlled env), an attacker can point NODE_COMPILE_CACHE at a directory they control.
  • The privileged process will then write compile-cache artifacts into that directory and may later read them back. This creates a classic privileged process + attacker-controlled filesystem path risk.
  • Depending on Node’s compile-cache file handling, this can enable one or more of:
    • privileged writes to attacker-chosen paths (via symlink/hardlink tricks inside the cache directory),
    • tampering with data later consumed by a privileged Node process.

Vulnerable code:

normalizeEnv();
if (!isTruthyEnvValue(process.env.NODE_DISABLE_COMPILE_CACHE)) {
  try {
    enableCompileCache();
  } catch {// Best-effort only; never block startup.
  }
}

Related documentation change (risk amplifier): recommending NODE_COMPILE_CACHE under /var/tmp:

export NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
mkdir -p /var/tmp/openclaw-compile-cache

Recommendation

Treat the compile cache directory as a security boundary when privileges may differ.

Code mitigations (recommended):

  1. Disable compile cache when running as root (or any elevated effective uid), unless explicitly opted in:
import { enableCompileCache } from "node:module";

const isRoot = typeof process.getuid === "function" && process.getuid() === 0;

if (isRoot) {// Avoid honoring attacker-controlled cache paths when privileged.// Either disable entirely:
  process.env.NODE_DISABLE_COMPILE_CACHE = "1";// or at least ignore any externally provided location:
  delete process.env.NODE_COMPILE_CACHE;
}

if (!isTruthyEnvValue(process.env.NODE_DISABLE_COMPILE_CACHE)) {
  enableCompileCache();
}
  1. If you want compile cache even when privileged, validate that NODE_COMPILE_CACHE (if set) points to a directory owned by the current uid and is not group/world-writable; otherwise ignore it.

Documentation mitigations:

  • Avoid recommending shared temp locations for NODE_COMPILE_CACHE in contexts where commands may be run with sudo/as root.
  • If keeping /var/tmp, instruct users to create the directory with restrictive permissions, e.g. install -d -m 0700 /var/tmp/openclaw-compile-cache.

Analyzed PR: #30940 at commit 7653bce

Last updated on: 2026-03-01T21:28:44Z

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5e0902cc2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 1, 2026

Greptile Summary

Implements comprehensive CLI startup performance optimizations:

  • Adds fast-path for root --version/-V/-v invocations that bypasses full CLI bootstrap by directly importing version module
  • Makes route plugin preloading argv-aware so status --json skips expensive plugin loading (human-readable output still loads plugins for channel table)
  • Removes eager plugin preload for health fast-route
  • Parallelizes independent async operations in status --json path (tailscale, update checks, agent status, gateway probe, and summary run concurrently)
  • Overlaps security audit with status scan in JSON mode rather than running sequentially
  • Enables Node module compile cache at startup using module.enableCompileCache() with safe no-throw behavior
  • Adds benchmark harness and documentation for startup tuning on low-power hosts

The implementation properly handles dependencies between async operations, maintains type safety, and includes appropriate test coverage. Error handling uses try-catch where needed to ensure resilience.

Confidence Score: 5/5

  • This PR is safe to merge with no critical issues found
  • The performance optimizations are well-implemented with proper error handling, maintain correctness while improving startup times, include comprehensive test coverage for new functionality, and add helpful documentation for users on low-power hosts
  • No files require special attention

Last reviewed commit: b3cfcc0

@vincentkoc vincentkoc merged commit 79f818e into openclaw:main Mar 1, 2026
14 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7653bce241

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 10 to 12
const routeHealth: RouteSpec = {
match: (path) => path[0] === "health",
loadPlugins: true,
run: async (argv) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore plugin preload for routed health command

The fast-route now runs health without preloading plugins, but prepareRoutedCommand only initializes the registry when loadPlugins is set, and healthCommand relies on listChannelPlugins() for channel-account fallback selection and linked-channel logSelfId output. On the default route-first path this leaves the registry empty, so openclaw health can silently omit channel-specific diagnostics that were previously shown.

Useful? React with 👍 / 👎.

@vincentkoc vincentkoc deleted the vincentkoc-code/rpi-fast-route-5871 branch March 1, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes commands Command implementations docs Improvements or additions to documentation maintainer Maintainer-authored PR scripts Repository scripts size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: CLI is extremely slow on pi4b

1 participant