Files
wangmiao0668000666andAyaan Zaidi 94c89b4350 fix(cli): reject empty node invocation keys before lookup (#145032)
Fixes #145058

## What Problem This Solves

Fixes `openclaw nodes invoke --idempotency-key ""` contacting the Gateway and returning a generic RPC error instead of identifying the empty CLI option.

## User Impact

An explicitly empty key now fails locally with `--idempotency-key` guidance before node lookup or any Gateway connection. Nonempty keys retain their exact bytes, including whitespace-only and padded values. Omitting the option still generates a key. No Gateway schema, pending-action identity, permission, or configuration contract changes.

## Why This Change Was Made

The existing invocation command validates the empty string alongside its other input checks. The original repair was simplified to a three-line guard, preserving the contributor's commits and the existing key-generation path. The CLI reference documents the option's behavior.

## Evidence

- Ran the actual CLI through `scripts/run-node.mjs`, the repository owner of `pnpm openclaw`, against a task-owned recording WebSocket Gateway fixture. Each phase covered 14 plain/JSON cases with isolated state and a loopback-only network fence.
- On pinned main, the empty key opened two connections and reached `node.list` and `node.invoke`; the CLI displayed the fixture-modeled schema error. The rebuilt candidate returned local option guidance with zero connections or requests.
- Whitespace-only, padded, ordinary, and omitted keys reached the wire correctly. Both shell-command denylist controls remained local failures. The fixture and CLI processes settled and disposable state was removed.
- The empty-key regression failed on the original command. All 62 tests in the existing CLI coverage and plugin-registration suites passed on the candidate; focused lint, formatting, both line ratchets, and runtime builds passed.

This is CLI/transport boundary proof, not execution of the real Gateway validator, a native node, or pending-action deduplication. The production file and changed regression region match the tested current-main replay. The first isolated package-manager attempt and an intermediate dirty-checkout rebuild were blocked from downloading dependencies; the final clean, rebuilt checkout passed without widening network access.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-20 15:50:30 +05:30

8.6 KiB

summary, read_when, title
summary read_when title
CLI reference for `openclaw nodes` (status, pairing, invoke, camera/screen/location/notify and the macOS widget panel)
You're managing paired nodes (cameras, screen, or the macOS widget panel)
You need to approve requests or invoke node commands
Nodes CLI

openclaw nodes

Manage paired nodes (devices) and invoke node capabilities.

Related: Nodes overview - Active computer presence - Camera nodes - Image nodes

Common options on every subcommand: --url <url>, --token <token>, --timeout <ms> (default varies by command), --json.

For numeric options such as --location-timeout, --max-age, and --quality, omit the flag to use its default. An explicit empty or whitespace-only value is invalid and fails before node lookup or Gateway requests.

Status

openclaw nodes status
openclaw nodes status --connected
openclaw nodes status --last-connected 24h
openclaw nodes list
openclaw nodes describe --node <idOrNameOrIp>

status and list both accept --connected (only connected nodes) and --last-connected <duration> (for example 24h or 7d, matching only nodes that connected within the duration). Both use the Gateway's recorded last connection time, including recent reconnects and disconnected nodes with known connection history. list shows pending and paired nodes in separate tables. Paired rows carry the most recent connect age (Last Connect). status shows one merged table with per-node capability, version, and last-input detail. A connected macOS node reports activity from interaction with OpenClaw without extra permissions. Optional System-wide presence detection also reports physical activity in other apps and requires Accessibility. The freshest row is marked active. See Active computer presence. describe prints one node's capabilities, permissions, activity, and effective/pending invoke commands.

When host stats are available, status includes a detail fragment such as load 3.2/24 · mem 151/192 GB · disk 1.2 TB free. describe shows the same summary in its Stats row. Load is the 1-minute average followed by CPU count, memory is used/total, and byte values use binary scaling with GB/TB labels. Unavailable load or disk readings are omitted. Offline nodes show the saved snapshot with an age such as (last known 27d ago), measured from the snapshot's original timestamp. See Node host stats.

--node accepts an exact ID, IP address, display name, or ID prefix of at least six characters. Exact ID and IP matches take precedence over names and prefixes. Within the strongest match, connected nodes take precedence. If current clients share a name, use an exact ID to disambiguate. Client type does not choose the target. The legacy migration exception prefers a unique OpenClaw client only when every other tied entry is a known Clawdbot or Moldbot client.

Pairing

openclaw nodes pending
openclaw nodes approve <requestId>
openclaw nodes reject <requestId>
openclaw nodes remove --node <id|name|ip>
openclaw nodes rename --node <id|name|ip> --name <displayName>

These commands manage the node's approved command/capability surface on its paired-device record. Device pairing (openclaw devices approve) gates the node's WebSocket connect handshake.

For manual enrollment, first approve the device request, then restart or rerun a node paused on PAIRING_REQUIRED. Its reconnect creates the separate request shown by nodes pending. Approve that node request, whose ID differs from the device request ID. See Node pairing and status for the complete sequence.

  • remove revokes the device's node role and clears its approved and pending command/capability surfaces. It disconnects the device's node-role sessions. A mixed-role device keeps its record and other roles. A node-only device record is deleted.
  • Removal stays effective even if worker cleanup reports an error: revoked node connections still close.
  • pending only needs operator.pairing scope.
  • gateway.nodes.pairing.autoApproveCidrs can approve explicitly trusted, first-time role: node device pairing. It is off by default and does not approve role upgrades or the separate command surface. That request still appears in nodes pending.
  • gateway.nodes.pairing.sshVerify is on by default. It auto-approves first-time role: node device pairing when the gateway can verify the device key over SSH to the node host. The first capability surface is approved in the same step. See Node pairing.
  • approve scope requirements follow the pending request's declared commands:
    • commandless request: operator.pairing
    • ordinary node commands: operator.pairing + operator.write
    • admin-sensitive commands (system.run, system.run.prepare, system.which, browser.proxy, browser.proxy.upload.v1, fs.listDir, and system.execApprovals.get/set): operator.pairing + operator.admin
  • These requirements classify node commands relayed through node.invoke. The top-level Gateway fs.listDir RPC needs operator.write for workspace-contained host browsing and operator.admin when nodeId is present.
  • remove scope: operator.pairing can remove non-operator node rows. A device-token caller revoking its own node role on a mixed-role device additionally needs operator.admin.

Invoke

openclaw nodes invoke --node <id> --command system.which --params '{"bins":["uname"]}'

Flags:

  • --command <command> (required): e.g. device.info.
  • --params <json>: JSON object string (default {}).
  • --invoke-timeout <ms>: node invoke timeout as a positive integer (default 15000).
  • --timeout <ms>: Gateway transport timeout (default 30000). For a positive invoke timeout, the effective transport timeout is max(timeout, invokeTimeout + 10000), allowing transport grace beyond the node's invoke deadline.
  • --idempotency-key <key>: optional nonempty idempotency key. An explicit empty value fails before node lookup or Gateway requests. Supplied keys retain their exact bytes, including whitespace; omitting the flag generates a key.

The invocation timeout covers Gateway checks, node wake-up, readiness retries, and the node response. Clock adjustments do not reset or extend this elapsed-time budget.

system.run and system.run.prepare are blocked here. Use the exec tool with host=node for shell execution instead. system.which is allowed through invoke.

Notify, push, location, screen

openclaw nodes notify --node <id> --title "Build" --body "Done" --priority timeSensitive
openclaw nodes push --node <id> --title "OpenClaw" --environment sandbox
openclaw nodes location get --node <id> --accuracy precise
openclaw nodes screen record --node <id> --duration 10s --fps 10 --out ./clip.mp4
  • notify sends a local notification on a node that declares system.notify, including macOS, iOS, Android, and direct watchOS nodes. Direct watchOS delivery requires OpenClaw to be active. Requires --title or --body. Options: --sound <name>, --priority <passive|active|timeSensitive>, --delivery <system|overlay|auto> (default system), --invoke-timeout <ms> (default 15000).
  • push sends an APNs test push to an iOS node. Options: --title <text> (default OpenClaw), --body <text>, --environment <sandbox|production> to override the detected APNs environment. Accepted delivery exits 0. A typed APNs rejection preserves the complete text or JSON diagnostic and exits non-zero.
  • location get fetches the node's current location. Options: --max-age <ms> (reuse a cached fix), --accuracy <coarse|balanced|precise>, --location-timeout <ms> (default 10000), --invoke-timeout <ms> (default 20000).
  • screen record captures a short clip and prints the saved path (or writes JSON with --json). Options: --screen <index> (default 0), --duration <ms|10s> (default 10000), --fps <fps> (default 10), --no-audio, --out <path>, --invoke-timeout <ms> (default 120000).
  • Explicit screen output paths are staged beside the destination. They replace it only after a complete write. A failed write leaves an existing file unchanged.

Camera and macOS widget-panel commands have their own docs: Camera nodes, Widget panel. The bundled experimental Canvas plugin registers openclaw nodes canvas with the surviving present, hide, and navigate subcommands.