Files
openclaw/docs/cli/voicecall.md
T
Peter Steinberger 75fcaba919 fix(voice-call): survive gateway in-process restart and stop CLI dead-ends (#125458)
* fix(voice-call): survive gateway in-process restart and stop CLI dead-ends

The gateway's in-process restart (SIGUSR1 config reload) reuses the cached
plugin registry, so service stop/start run on the same retained voice-call
registration. Generation fencing from #120289 treated that restart as a stale
actor: stop retired the generation forever, the next start silently bailed,
and every voicecall.* RPC answered UNAVAILABLE "runtime generation is
retired" while the webhook never rebound.

- Registrations now hold a replaceable generation: service start after stop
  mints a fresh generation, takes over a running slot owned by a retired
  predecessor, and reports start failures to service health instead of
  silently returning.
- The voicecall CLI classifies gateway failures with typed guards instead of
  message substrings: standalone/store fallback only when the gateway is
  genuinely absent; reachable-but-failed (request errors, auth, timeout)
  exits with actionable text; a standalone webhook port collision explains
  that a running Gateway probably owns the port instead of raw EADDRINUSE.
- Plugin SDK gateway-runtime exports structural isGatewayTransportError /
  isGatewayClientRequestError guards (+2 documented surface budget).
- Regression coverage: same-registration stop/start restart, retired-owner
  takeover, typed CLI fallback classification, and a real token-auth gateway
  server routing voicecall.status through callGatewayFromCli.

* refactor(voice-call): split CLI modules and dedupe gateway fallbacks

Collapse the four duplicated gateway-or-runtime command blocks (speak, dtmf,
end, continue fallback) into one generic runGatewayManagerCommand helper —
the continue command owns its legacy-method fallback and operation polling
via a gatewayCall closure, so the helper carries no per-command policy.
Smoke reuses the shared initiateVoiceCall path instead of a bespoke
fallback.

Split the 988-line cli.ts into concept modules (cli-gateway-call,
cli-call-log, cli-command-io) and drop its grandfathered max-lines
suppression plus the now-stale max-lines and assertion-safety baseline
entries (shrink-only ratchet maintenance).

Behavior-frozen: stdout/exit semantics unchanged; net -2 production LOC.

* fix(voice-call): redact gateway URLs in CLI operational errors

ClawSweeper P1: the operational-error formatter interpolated the raw
connectionDetails.url, so a configured gateway URL with userinfo or query
tokens would print credentials into terminal output. Redact the composed
message once with the canonical net-policy redactor (also covers
remote-controlled close-reason text), exported through the plugin SDK
gateway-runtime subpath (+1 documented surface budget). Regression test
covers a credential-bearing URL in both the URL and message fields.
2026-08-17 18:59:19 -07:00

9.6 KiB

summary, read_when, title
summary read_when title
CLI reference for `openclaw voicecall` (voice-call plugin command surface)
You use the voice-call plugin and want every CLI entry point
You need flag tables and defaults for setup, smoke, call, continue, speak, dtmf, end, status, tail, latency, expose, and start
Voicecall

openclaw voicecall

voicecall is a plugin-provided command. It only appears when the voice-call plugin is installed and enabled.

When the Gateway is running, operational commands (call, start, continue, speak, dtmf, end, status) route to that Gateway's voice-call runtime. If no Gateway is reachable, they fall back to a standalone CLI runtime. status uses the persisted call store instead of starting that runtime.

Fallback is limited to transport-level absence. If the Gateway responds with a request or authentication error, or does not answer before the timeout, the command exits nonzero and points to openclaw gateway status; it does not start a second webhook server. If standalone fallback cannot bind the configured serve.port, the error identifies the likely running Gateway instead of printing a raw EADDRINUSE failure.

Subcommands

openclaw voicecall setup    [--json]
openclaw voicecall smoke    [-t <phone>] [--message <text>] [--mode <m>] [--yes] [--json]
openclaw voicecall call     -m <text> [-t <phone>] [--mode <m>]
openclaw voicecall start    --to <phone> [--message <text>] [--mode <m>]
openclaw voicecall continue --call-id <id> --message <text>
openclaw voicecall speak    --call-id <id> --message <text>
openclaw voicecall dtmf     --call-id <id> --digits <digits>
openclaw voicecall end      --call-id <id>
openclaw voicecall status   [--call-id <id>] [--json]
openclaw voicecall tail     [--file <path>] [--since <n>] [--poll <ms>]
openclaw voicecall latency  [--file <path>] [--last <n>]
openclaw voicecall expose   [--mode <m>] [--path <p>] [--port <port>] [--serve-path <p>]
Subcommand Description
setup Show provider and webhook readiness checks.
smoke Run readiness checks; place a live test call only with --yes.
call Initiate an outbound voice call.
start Alias for call with --to required and --message optional.
continue Speak a message and wait for the next response.
speak Speak a message without waiting for a response.
dtmf Send DTMF digits to an active call.
end Hang up an active call.
status Inspect active calls (or one by --call-id).
tail Tail calls.jsonl (useful during provider tests).
latency Summarize turn-latency metrics from calls.jsonl.
expose Toggle Tailscale serve/funnel for the webhook endpoint.

Setup and smoke

setup

Prints human-readable readiness checks by default. Pass --json for scripts.

openclaw voicecall setup
openclaw voicecall setup --json

smoke

Runs the same readiness checks. Places a real phone call only when both --to and --yes are present.

Flag Default Description
-t, --to <phone> (none) Phone number to call for a live smoke.
--message <text> OpenClaw voice call smoke test. Message to speak during the smoke call.
--mode <mode> notify Call mode: notify or conversation.
--yes false Actually place the live outbound call.
--json false Print machine-readable JSON.
openclaw voicecall smoke
openclaw voicecall smoke --to "+15555550123"        # dry run
openclaw voicecall smoke --to "+15555550123" --yes  # live notify call
For external providers (`plivo`, `telnyx`, `twilio`), `setup` and `smoke` require a public webhook URL from `publicUrl`, a tunnel, or Tailscale exposure. A loopback or private serve fallback is rejected because carriers cannot reach it.

Call lifecycle

call

Initiate an outbound voice call.

Flag Required Default Description
-m, --message <text> yes (none) Message to speak when the call connects.
-t, --to <phone> no config toNumber E.164 phone number to call.
--mode <mode> no conversation Call mode: notify (hang up after message) or conversation (stay open).
openclaw voicecall call --to "+15555550123" --message "Hello"
openclaw voicecall call -m "Heads up" --mode notify

start

Alias for call with a different default flag shape.

Flag Required Default Description
--to <phone> yes (none) Phone number to call.
--message <text> no (none) Message to speak when the call connects.
--mode <mode> no conversation Call mode: notify or conversation.

continue

Speak a message and wait for a response.

Flag Required Description
--call-id <id> yes Call ID.
--message <text> yes Message to speak.

speak

Speak a message without waiting for a response.

Flag Required Description
--call-id <id> yes Call ID.
--message <text> yes Message to speak.

dtmf

Send DTMF digits to an active call.

Flag Required Description
--call-id <id> yes Call ID.
--digits <digits> yes DTMF digits (for example ww123456# for waits).

end

Hang up an active call.

Flag Required Description
--call-id <id> yes Call ID.

status

Inspect active calls.

Flag Default Description
--call-id <id> (none) Restrict output to one call.
--json false Print machine-readable JSON.
openclaw voicecall status
openclaw voicecall status --json
openclaw voicecall status --call-id <id>

Logs and metrics

tail

Tail the voice-call JSONL log. Prints the last --since lines on start, then streams new lines as they are written.

Flag Default Description
--file <path> resolved from plugin store Path to calls.jsonl.
--since <n> 25 Lines to print before tailing.
--poll <ms> 250 (minimum 50) Poll interval in milliseconds.

latency

Summarize turn-latency and listen-wait metrics from calls.jsonl. Output is JSON with recordsScanned, turnLatency, and listenWait summaries.

Flag Default Description
--file <path> resolved from plugin store Path to calls.jsonl.
--last <n> 200 (minimum 1) Number of recent records to analyze.

Exposing webhooks

expose

Enable, disable, or change the Tailscale serve/funnel configuration for the voice webhook. When realtime or streaming audio is enabled, the command also exposes or clears that mode's WebSocket stream path.

Flag Default Description
--mode <mode> funnel off, serve (tailnet), or funnel (public).
--path <path> config tailscale.path or --serve-path Tailscale path to expose.
--port <port> config serve.port or 3334 Local webhook port.
--serve-path <path> config serve.path or /voice/webhook Local webhook path.
openclaw voicecall expose --mode serve
openclaw voicecall expose --mode funnel
openclaw voicecall expose --mode off
Only expose the webhook endpoint to networks you trust. Prefer Tailscale Serve over Funnel when possible.