Command Reference
All subcommands, listed by service. Dependency badges: 🟢 doesn't need the daemon · 🟡 needs the daemon running · 🔵 manages the daemon itself. Every command supports the global flags (--profile / --format / --quiet / --no-color); see Command System & Output.
config — Configuration management 🟢
| Command | Description |
|---|---|
config init | Interactive first-run wizard: generates config.json + a gateway token, prints a phone-side config summary, brings up the daemon in the background, and registers login autostart (macOS launchd / Linux systemd user service / Windows Task Scheduler — all user-level, no admin privileges needed). Supports --non-interactive --from-file <config.json> (- reads stdin), --force to overwrite, --no-start (only register autostart, don't start the daemon now), and --no-autostart (start the daemon now but skip registering autostart). |
config show | Show the current profile's config (sensitive fields masked). --show-secrets prints them in plaintext (requires a TTY + confirmation). |
config set <key> <value> | Set a single config value; supports dotted paths (daemon.port, notification.ignoredApps uses a comma-separated list). |
config unset <key> | Remove a single config value. |
yoooclaw config init
yoooclaw config set daemon.port 18365
yoooclaw config show --format jsoncloud.host is the cloud host shared by light effects, light rules, and ASR. Left empty it follows PHONE_NOTIFICATIONS_ENV; set it and it wins, and the Relay tunnel URL is derived from it too while that URL is still in its built-in default form — which is what prevents the "tunnel connected but light effects 401" mismatch. Full precedence in Debugging: Environment / host mismatch.
yoooclaw config set cloud.host openclaw-service.yoooclaw.com
yoooclaw config unset cloud.host # clear it to follow the env var againprofile — Multi-profile management 🟢
| Command | Description |
|---|---|
profile list | List all profiles, marking the active one. |
profile use <name> | Switch the active profile. |
profile create <name> | Create a new profile (via the config init wizard; also supports --no-start/--no-autostart). |
profile delete <name> | Delete a profile (can't delete the active one; requires --yes). |
When switching or deleting a profile, the CLI first stops the old profile's daemon (waiting for its Relay consumer lock to actually release) before switching — if the old profile was OS-managed autostart, the matching OS service is stopped too; if the new profile was already running, it's restarted. This prevents the old profile's daemon from continuing to consume the account's Relay traffic and writing production notifications/recordings into a profile you've already switched away from.
auth — Credentials and authentication
| Command | Description |
|---|---|
auth set-api-key <key> 🟢 | Set / rotate the account-level default api-key (- reads from stdin, avoiding shell history). If apiKeys[] already exists, only updates the default entry; --keychain writes to the OS keychain. |
auth add-api-key <key> 🟢 | Add a new labeled api-key. --label <label> is required ([a-z0-9-]{1,32}), --default marks it default, --force overwrites a label with the same name. |
auth list-api-keys 🟢 | List api-key entries, mode, and defaultLabel, with keys auto-masked. |
auth remove-api-key <label> 🟢 | Remove the api-key for the given label. If you remove the default, the first remaining key automatically becomes the new default. |
auth set-default-api-key <label> 🟢 | Switch the default api-key; used by cloud ASR fallback and legacy single-key calls. |
auth status 🟢 | Show whether an api-key / gateway token exists, its source (env/keychain/file), mode, defaultLabel, and whether the daemon is reachable. Doesn't call the daemon. Keys with a suspicious shape (not starting with ock-) are named by label under warnings — such keys connect to Relay fine, but plugin-side APIs like light effects and ASR return 401. |
auth token-rotate 🟡 | Generate and write a new gateway token (per auth.tokenRef). --length <n> for byte length, default 32. |
auth check 🟡 | End-to-end auth check: calls the daemon's /daemon/status with the local token to verify consistency. |
echo 'ock_xxx' | yoooclaw auth set-api-key -
yoooclaw auth add-api-key <ock_phone_a> --label phone-a --default
yoooclaw auth add-api-key <ock_phone_b> --label phone-b
yoooclaw auth list-api-keys
yoooclaw auth set-default-api-key phone-b
yoooclaw auth status --format jsonMultiple keys live in the shared apiKeys[] field of ~/.yoooclaw/credentials.json, effective across profiles. While the daemon is running it hot-reloads via a file watch; if the watch is unreliable, run yoooclaw daemon reload to re-read credentials and incrementally refresh the Relay tunnels. Each key's label becomes the clientLabel on inbound data, filterable with --client <label> on the query commands.
daemon — Daemon management 🔵
| Command | Description |
|---|---|
daemon start | Start the daemon; forks a detached background process by default, or is started by the user service manager when autostart is enabled. --bind <host>, --port <n>, --no-detach (for systemd/launchd), --log-level <level>. Refuses to start while the Hermes plugin holds the current profile's writer lock, returning YOOOCLAW_DAEMON_DISABLED_BY_PLUGIN (see Writer lock below). |
daemon stop | Send SIGTERM, then SIGKILL after waiting up to 10s. |
daemon restart | Equivalent to stop + start, preserving the original start arguments. |
daemon reload | Doesn't restart the process; re-reads the api-key CredentialSet and incrementally starts / stops / reconnects Relay tunnels. |
daemon status | Print PID, listen address, start time, relay status, number of light rules, latest ingest, memory usage, the cloud block (which host light effects / ASR actually talk to), and a supervision block (whether it's OS-managed autostart, desired vs. actual state). |
daemon logs | Follow the daemon log. -f, --follow, --lines <n> (default 100), --level <level>, --supervisor (show the OS service's own startup log at ~/.yoooclaw/logs/daemon-supervisor.log instead, separate from the regular daemon log), --diagnostics (one combined report of the daemon log, supervisor log, lock file / process identity and autostart state, plus — on Linux — this boot's systemd service state and journal). --lines accepts 1–1000. |
daemon autostart enable | Register user-level login autostart (macOS launchd / Linux systemd user service / Windows Task Scheduler) and start the daemon immediately. --no-start registers only, without starting; --boot (Linux only) also enables linger for the current user so the daemon starts at boot even with nobody logged in. |
daemon autostart disable | Stop the daemon and remove the autostart registration. |
daemon autostart status | Show desired vs. actual OS-service state, detecting drift (e.g. the executable path moved after an upgrade, the executable no longer exists, or the unit isn't enabled). On Linux it also returns linger, unitEnabled, bootEnabled (true only when both are) and bootWarning. |
yoooclaw daemon start
yoooclaw daemon status --format json
yoooclaw daemon logs --lines 200 --level error
yoooclaw daemon logs --supervisor # OS service startup log, not the daemon's own log
yoooclaw daemon logs --diagnostics --lines 100 # one report for autostart / reload issues
yoooclaw daemon autostart enable --boot # Linux: start at boot with nobody logged in
yoooclaw daemon autostart status --format jsondaemon start / daemon restart auto-detect whether the current daemon is OS-managed and route through the supervisor instead of an ad hoc process spawn when it is; daemon doctor gained a daemon-autostart check (--fix can auto-repair things like an executable-path drift after an upgrade); profile use and uninstall both handle the autostart registration first — see profile above and Maintenance commands below. A failed or broken autostart registration returns YOOOCLAW_AUTOSTART_UNAVAILABLE; if autostart enable fails while the daemon wasn't running, the CLI first brings up a standalone daemon so the connection keeps working, then reports "daemon restored but login autostart not configured" — retry after leaving the restricted Agent environment.
A few autostart-related behaviors:
- Disabling autostart doesn't disable linger:
autostart disableonly removes this app's service; linger enabled by--bootstays so other services of the same user aren't affected.doctorreports abootWarningwhen autostart is desired but the boot prerequisites aren't met. - Upgrades from older versions register autostart: older releases had no persisted autostart preference. After an upgrade (
install.sh/install.ps1), autostart is registered for the initialized active profile — even if the daemon happened to be stopped; an explicitautostart disable, or the Hermes plugin currently owning storage, is never overridden. - Diagnostic events:
service.entry/daemon.readyrecord version, PID, profile, config path and the actual listen port;status.observed/reload.requestdistinguish a missing lock, an unreadable lock, a dead process, and executable or command-line mismatches;credentials.reload_appliedrecords sources, labels, masked SHA-256 fingerprints and tunnel add/remove results before and after a reload (it only means the local config was applied — look for a subsequentconnected). Logs never contain full keys, gateway tokens or credential file contents. If there isn't even aservice.entry, look at the systemd / journal part of--diagnosticsfirst — a process that never started can't write its own log. - Linux installer guard: when upgrading from an Agent shell that can't reach the current user's systemd (no login-session environment), the installer first tries to recover it from
/run/user/<uid>; if that still fails it keeps the old daemon and binary and aborts the update instead of stopping a daemon it can't bring back. There's also a hidden internal command,daemon run-service, which is the entry point the OS service definition itself calls — not meant for everyday manual use.
The cloud block in daemon status answers "the config says A, so why is it talking to B":
{ "cloud": { "env": "production", "host": "openclaw-service.yoooclaw.com",
"source": "cloud.host",
"lightApiUrl": "https://…", "lightRuleApi": "https://…" } }source is one of env / cloud.host / relay.url / default, naming exactly who decided this host.
Writer lock and Hermes plugin mode
~/.yoooclaw/profiles/<profile>/writer.lock is the single-writer mutex for that profile's storage (an OS advisory lock, released automatically when the process dies). When the Hermes plugin runs in daemonless mode the plugin process holds it, and daemon start / daemon run-foreground are refused:
{ "ok": false, "error": { "code": "YOOOCLAW_DAEMON_DISABLED_BY_PLUGIN",
"message": "storage is owned by hermes-plugin (pid …)" } }Read-only commands (notification *, recording list/status/events, image *, log) never touch the lock and work normally in plugin mode. Disabling the plugin releases the lock, and daemon start returns you to standalone mode with no data migration required. --ingress proxied is exempt — that daemon is hosted by the host application itself.
On Windows, if probing this lock fails (e.g. a permission error), the behavior is fail-closed:
daemon start/daemon run-foregroundrefuse to start and returnYOOOCLAW_STORAGE_UNAVAILABLE, instead of assuming "not held" and proceeding — which would risk writing to the same storage concurrently with a running Hermes plugin.
owner — Relay / storage ownership handoff 🟡
The CLI and the Hermes plugin exclusively share the same profile storage and Relay tunnel — whoever holds the writer lock is the "owner." Most of the time you just use whichever one you installed and never touch this; this command group is only for explicitly handing Relay ownership back to the standalone CLI when both the CLI and the Hermes plugin are installed on the same machine.
| Command | Description |
|---|---|
owner activate cli | Disables the Hermes yoooclaw / yoooclaw_app plugins (--hermes-profile <name> to target a specific Hermes profile), restarts the Hermes gateway if needed to force it to release the writer lock / Relay connection, waits for the release, then starts the standalone CLI daemon to take over. --no-start completes the handoff without starting the daemon. Unless autostart was explicitly disabled, the takeover starts the daemon through the OS user service (supervised: true). If the account-level Relay consumer lock (standalone-relay.flock) is still held by another standalone daemon, it refuses (YOOOCLAW_DAEMON_ALREADY_RUNNING) — stop that process or user service first. |
By default, install.sh / install.ps1 preserves whatever owned Relay before the upgrade when upgrading the CLI — if the plugin held the lock before, it still does after; only passing --activate / -Activate explicitly (or setting the env var YOOOCLAW_ACTIVATE_OWNER=cli) hands ownership to the standalone CLI after install, and it also accepts --hermes-profile <name>. If a standalone CLI daemon was already running before an upgrade, the installer stops it, swaps the binary, and restarts it under its original profile (with automatic rollback/restart on failure) — so a routine upgrade never silently drops Relay ownership.
yoooclaw owner activate cli
yoooclaw owner activate cli --hermes-profile work --no-startnotification — Notification queries 🟢
| Command | Description |
|---|---|
notification search | Query by criteria, newest first. --from/--to <iso8601>, --app, --sender, --conversation-type group|private, --keyword, --client <label>, --limit (default 100). |
notification summary | Aggregate statistics + sample summaries, for an Agent to summarize. Supports --client <label>, plus --sample <n> (default 30), --top <n> (default 10). When --limit is explicitly passed, only the most recent N are aggregated. |
notification summary-job | A chunked notification summarization job: slice a large batch of notifications → summarize chunk by chunk → merge the result. Subcommands below, see summary-job. |
notification stats | Aggregate by dimension. --from/--to <YYYY-MM-DD>, --app, --client <label>, --dim date|app|sender|hour|client|all. |
notification storage-path | Print the absolute path of the notifications directory. |
notification +today | Today's notifications. Supports --client <label>. |
notification +recent | Notifications from the last hour. Supports --client <label>. |
notification +unread | (Reserved) Unread notifications — requires a read-state model that hasn't landed yet; currently returns YOOOCLAW_NOT_IMPLEMENTED. |
--app supports Chinese/English aliases: 微信/wechat, 飞书/feishu/lark, 钉钉/dingtalk, 企业微信/wecom, qq, etc.
yoooclaw notification search --app wechat --keyword meeting --format ndjson
yoooclaw notification summary --top 10 --format jsonnotification summary-job — Chunked notification summarization 🟢
A workflow for large batches of notifications: "slice → summarize chunk by chunk → merge". summary is fine for small, one-shot aggregation; when there are a lot of notifications and you need to feed a model chunk by chunk, use summary-job: create builds the job and slices it, next claims a pending chunk to summarize, commit writes that chunk's summary back, and once everything's done, result merges the final output. You can also use run to skip the model entirely and finish automatically with extractive summarization.
| Command | Description |
|---|---|
notification summary-job create | Create a job, sliced by query. Reuses all the notification query flags (--from/--to, --app, --sender, --conversation-type, --keyword, --client, --limit, defaulting --limit to 1000), plus --chunk-size <n> (items per chunk, default 150) and --max-content <n> (max characters per item's title/body, default 120). |
notification summary-job status <id> | View job status and per-chunk progress. |
notification summary-job next <id> | Claim or retry the next chunk to summarize; returns the chunk content and a chunkId. |
notification summary-job commit <id> | Write a chunk's summary back and mark it complete. --chunk-id <id> (required, from next), plus either --summary <text> or --summary-file <path> for the summary. |
notification summary-job run <id> | Auto-process pending chunks with extractive summarization (no model needed). --max-chunks <n> (max chunks to process this run, default 20), --include-result (output the markdown result once done). |
notification summary-job result <id> | Merge the committed chunk summaries and return the final result. |
notification summary-job cancel <id> | Cancel the job (keeping already-written chunks and summaries). |
# Agent-driven: create the job → loop next/commit → merge
JOB=$(yoooclaw notification summary-job create --app wechat --limit 2000 --format json)
yoooclaw notification summary-job next <id> # get a chunk, feed it to a model for summarization
yoooclaw notification summary-job commit <id> --chunk-id <chunk> --summary "chunk summary…"
yoooclaw notification summary-job result <id> --format json
# no-model case: finish automatically with extractive summarization
yoooclaw notification summary-job run <id> --include-result --format jsonsync — Sync notifications to a memory system 🟢
A checkpoint protocol for external memory systems to pull notifications in batches. scan / next share a set of date-range flags: --all (process every date after the checkpoint), --date <YYYY-MM-DD> (a single date), --from-date / --to-date (a range); if none are passed, only today (local time) is processed by default.
| Command | Description |
|---|---|
sync scan | Scan for unprocessed notifications; by default returns only today's (local) pending summary, or use range flags to widen the scan. |
sync next | A general-purpose batch iterator: returns the next unprocessed batch (≤100 items) within range plus a commitCommand; returns done=true once everything's processed. Used together with the range flags. |
sync fetch --date <YYYY-MM-DD> | Fetch details of unprocessed notifications for a given date. --max-end-index <n> for idempotent slicing. |
sync commit --date <YYYY-MM-DD> | Mark the current batch as processed. --end-index <n> for a precise commit. |
Historical notifications imported via transfer import carry transfer.memoryPolicy="skip-history" and don't enter memory sync: scan / next / fetch exclude them from counts and returned lists, but they still occupy checkpoint positions and endIndex advances over raw indexes; a batch made up entirely of imported items returns skippedOnly: true — just commit it as usual.
# Iterator style: next returns the next batch + a commit command directly; done=true once finished
yoooclaw sync next --all --format json
yoooclaw sync commit --date 2026-06-17 --end-index 42recording — Recording management
recording now unifies two data sources: smart_hardware (transcripts reported by phone-side recording hardware — the original pipeline) and capture_app (meeting recordings from the desktop "YoooClaw Capture" app, stored under voice/recordings-jsonl/). The query commands all gained a --source all|capture_app|smart_hardware filter (default all); returned items carry source_type / source_name to identify the source, plus has_audio / has_transcript / has_summary / missing_artifacts to indicate which artifacts actually exist for that record. The transcript shape differs between sources: hardware is a flat transcript, Capture is transcripts[].sentences[] (with begin_time/end_time/speaker_id); recording events only covers the hardware source's status event stream — Capture has no equivalent.
| Command | Description |
|---|---|
recording list 🟢 | List all recordings, newest effective recording time first. --source all|capture_app|smart_hardware, --status <status> (only meaningful for the hardware source), --client <label> (filters by api-key label; only affects the hardware source, Capture is unaffected), --from <ISO8601|YYYY-MM-DD> (inclusive) / --to <ISO8601|YYYY-MM-DD> (exclusive) filter by recording time. An empty range returns an empty list rather than falling back to the latest recording. |
recording status <id> 🟢 | Details for a single recording (metadata, file paths, ASR status, errors). If the same ID exists in both sources, --source is required to disambiguate, or it returns NOT_FOUND. |
recording storage-path 🟢 | Print the absolute path of the recordings storage directory. |
recording setup-asr 🟢 | Configure ASR transcription parameters. The only currently available mode is --mode api; local remains in the flag/schema for compatibility with older requests, but the Go beta rejects local Whisper mode. Supports --api-key, --endpoint, --language, --non-interactive. |
recording events 🟢 | Query the hardware source's recording state event stream (Capture has no event stream). --id <recordingId>, --since <10m|1h|24h>, --watch, --limit <n> (default 200). |
recording +latest 🟢 | Show details for the most recent recording (the latest across both sources). |
recording +today 🟢 | List today's recordings on the local calendar day. Supports --source, --status, --client <label>. |
The standalone CLI's daemon receives hardware-source transcripts and summaries written by the app / cloud via recordings.result.write (optionally downloading the audio in the background if an ossUrl is included), landing them in the current profile's recordings/. Local re-transcription is triggered via recordings.retranscribe: the asr-config.json written by setup-asr is compatible with a request-level asr parameter; when mode=api and no apiKey was written, it falls back to the account-level ock- key. The current Go beta only supports api / model-proxy ASR.
Recording time follows the actual capture time reported in the result payload (not transcript-generation time), and cross-timezone timestamps are parsed into real instants before sorting so "latest" never picks the wrong one. duration_sec is a whole number of seconds; duration_display is the matching human-readable form (16s, 1m 16s, 1h 1m 1s); Capture items additionally carry a millisecond-precision duration_ms. Once the audio finishes downloading, file_size_display reports size in an Android Formatter.formatShortFileSize()-compatible format; the retired file_size_bytes field is no longer emitted. Filenames under transcripts/ and summaries/ now follow the convention <YYYYMMDDHH>_<title>_<id>.md (time-and-title-first, so filename sort is chronological); files written before the upgrade keep their old names — there's no bulk migration. Audio downloads use the Alibaba Cloud OSS SDK v2 multipart downloader (8 MiB parts, concurrency 3, Range + ETag validation), so a flaky network resumes from the checkpoint within the current download run instead of deleting the partial file and starting over; 5 GiB max per audio file, and recovery after a process restart is still re-initiated by the recording recovery flow. recordings.result.write gained an optional ossTaskId (the upload service's task ID, ≤256 characters, must come with an audio URL; not the same as transcript.source.taskId, which is the ASR task ID): on a 403 the daemon uses the api-key that wrote the recording to ask the cloud for a fresh signed URL and retries — the api-key is never sent to OSS. It's stored in the recording index and echoed in the write response, recording list/status and recording.status events (omitted when absent); a new write without ossTaskId clears the old one so an old task is never used to refresh a new URL. Recordings ingested via /gateway/recordings.* are now correctly tagged with the clientLabel of the api-key that wrote them (it previously always fell through to "default"); the read side (recordings.list, recording status/events, and the recording.status events pushed back over Relay) is scoped the same way — a client connected over a Relay tunnel or a specific api-key only sees/mutates its own recordings, while loopback / gateway-token requests are unrestricted, and label-less or legacy default entries stay visible to every client for upgrade compatibility. synced-web-page and the /web-pages/index//web-pages/status endpoints got the same auth-context scoping.
yoooclaw recording setup-asr --mode api --language auto --non-interactive
yoooclaw recording events --since 1h --limit 50 --format json
yoooclaw recording events --id 2026-03-23_14-32 --watch
yoooclaw recording list --from 2026-07-01 --to 2026-08-01 --format json
yoooclaw recording +today --source capture_app --format tablevoice — Voice input (dictation) history queries 🟢
Queries the voice input / dictation history saved on this machine: the final text inserted for each dictation, which app it went into, the recognized language and status, plus optional local audio. Pure reads of the current profile's voice/audio-jsonl/YYYY-MM-DD.jsonl (sharded by day); no daemon needed, and it never accesses another computer's data. Note that this is not meeting recordings — meeting recordings (YoooClaw Capture / smart hardware) go through recording * above.
| Command | Description |
|---|---|
voice list | List dictation history, newest first. With no filters it defaults to a rolling last 72 hours (stated explicitly in the JSON); --all explicitly queries the full history. No default item cap; use --limit to bound it. Filters: --from / --to (ISO 8601 with timezone or YYYY-MM-DD, start inclusive, end exclusive), --app <app_id|app_name> (exact match, no fuzzy aliases), --status, --language, --has-audio (only records whose local audio file actually exists). |
voice search <keyword> | Search the final inserted text; without time filters it searches all saved history. Use --app to filter by destination app — don't put app names in the keyword. |
voice show <id> | One complete record. id / voice_id is a stable string, not a database row number; missing audio doesn't invalidate the text. |
voice apps | List destination apps that have appeared; defaults to the last 7 days (--all for full history), deduped by app_id, returning both app_id and app_name. |
voice +latest | The latest record across all history. |
voice +today | Dictation history for the local calendar day. |
voice storage-path | Print the dictation-history JSONL and artifact directory paths. |
yoooclaw voice apps --format json # get app_id first
yoooclaw voice list --app com.microsoft.VSCode --format json
yoooclaw voice list --from 2026-10-09T09:00:00+08:00 --to 2026-10-09T10:00:00+08:00
yoooclaw voice search "project" --app com.microsoft.VSCodeFor "what did I just say" requests, an Agent should pass an explicit last-hour
--from/--torather than substituting an older "latest" item. Saved dictation history also isn't a measure of real usage and isn't suitable for statistics —voice statswas removed in 0.9.0 with no replacement, and the CLI never falls back to reading the oldvoice.sqlite3.
image — Image management 🟢
Images are downloaded from OSS to images/files/ by the daemon in the background; query commands do pure reads of images/index.json.
| Command | Description |
|---|---|
image list | List images. --status syncing|synced|sync_failed, --app, --from/--to <iso8601>, --client <label>, --limit. |
image status <id> | Details for a single image. |
image path <id> | Print the local file's absolute path (for feeding an Agent's multimodal model). --thumbnail returns the thumbnail. Returns YOOOCLAW_IMAGE_NOT_READY if the download hasn't finished. |
image storage-path | Print the absolute path of the images storage directory. |
image +latest | Show details for the most recent image. |
synced-web-page — Captured web-page queries 🟢
A browser extension captures page content and delivers it to the daemon over Relay (POST /web-pages), where it's saved as Markdown + metadata. This command group only reads that local index — it never touches the Internet. It was previously named web; that was renamed to synced-web-page because it read as "live web search."
| Command | Description |
|---|---|
synced-web-page list | List all captured pages newest-capturedAt-first. --from <ISO8601> (inclusive) / --to <ISO8601> (exclusive) filter by capture time; pass a timezone-qualified timestamp. |
synced-web-page search <keyword> | Search title, site name, URL, canonical URL, and Markdown body. --limit <n> (default 20). |
synced-web-page path <urlHash> | Print the absolute path of the page's Markdown file, resolved by URL hash (a unique prefix is accepted). |
synced-web-page storage-path | Print the absolute path of the web-page storage directory. |
yoooclaw synced-web-page list --from 2026-07-29T00:00:00+08:00 --format json
yoooclaw synced-web-page search "JavaScript" --limit 20
yoooclaw synced-web-page path <urlHash>Each list entry returns urlHash, title, siteName, canonicalUrl, capturedAt, firstCapturedAt (first-capture time), captureCount (how many times it's been re-captured), relativePath, hasArchive, and clientLabel. Re-capturing the same URL keeps a single entry and increments captureCount instead of writing a duplicate.
light — Light-effect hardware control 🟡
| Command | Description |
|---|---|
light send | Send a light-effect command. One of --segments <json> (light parameters), --preset <name> (built-in preset such as red-steady / red-strobe-3 / green-steady), or --rule <name> (a saved lightrule); --repeat, --repeat-times <n>; --reason (why / push body), --title (push title; generated from reason or the effect when omitted). |
- Text only: second-gen hardware with a screen shows this delivery's
title/reason. Passing only--title/--reasonwith no light parameters is treated as text-only screen delivery: one 8-second, brightness-0 explicit-off segment, no repeat (it may turn off lighting that's currently on). - Segment defaults: in one-shot effects an omitted
brightnessdefaults to 128 and an omittedcolorto white{r:255,g:255,b:255}; explicitnull/0/ invalid values are still strictly validated, and saved rules are unaffected. light +blinkhas been removed; useyoooclaw light send --preset red-strobe-3as the connectivity test.- When the standalone daemon has no connected light-effect device session, the command returns
accepted: true, delivered: false(the phone side needs to be online / relayed).
yoooclaw light send --preset green-steady --title "Task done" --reason "Build passed"
yoooclaw light send --title "Meeting" --reason "15:00 product review" # show text on the screen onlylightrule — Light-effect rule management 🟡
Rules are compiled, evaluated, and triggered by the cloud Notification Intelligence service; lightrule management commands call that cloud API directly (not the local daemon), so run yc auth set-api-key <apiKey> first. The cloud host they hit is the same one used by light effects and ASR, decided by cloud.host.
| Command | Description |
|---|---|
lightrule list | List all rules and their status. |
lightrule show <id> | Details for a single rule. |
lightrule create | Compile a rule from natural language via the cloud Agent. --intent <text> is required. The text must include a notification/message/incoming-call trigger signal or the command errors — use light send for a one-shot flash instead. |
lightrule update <id> | Update an existing rule; unspecified fields keep their current value. --intent (recompiles and replaces the whole rule; cannot be mixed with other fields) or --title/--description/--segments <json>/--repeat/--repeat-times <n>. Use the enable / disable subcommands to toggle a rule. |
lightrule delete <id> | Delete a rule (--yes skips confirmation). |
lightrule enable <id> / disable <id> | Enable / disable a single rule. |
lightrule +on / +off | Enable / disable all rules. |
yoooclaw lightrule create --intent "Flash red 3 times when WeChat messages arrive"
yoooclaw lightrule update <id> --intent "Change it to a green breathing effect"
yoooclaw lightrule list --format jsonWhen light effects or light rules return
401 Invalid plugin API Key, the error message appends the current environment, the masked key, and the next action. In practice this 401 almost always means the key and the environment don't match (api-keys are issued per environment), not that the key expired — comparecloud.envfromdaemon statusagainst the environment the phone app is on.
todo — Cloud todos 🟢
Manages the cloud todos shown in the app directly, no daemon needed; credentials and environment come from the existing account api-key and cloud.host. Add --format json for structured results.
| Command | Description |
|---|---|
todo list | Query todos. --is-done true|false|null, --start-time / --end-time (ISO with timezone, or null), --keyword, --page-no, --page-size. Defaults to open items with no time bound. |
todo get <todoId> | One todo's details. |
todo create | Create a todo. --title, --due-at (the start time: ISO with offset for timed items, YYYY-MM-DD for all-day, null for no time), --is-full-day true|false (inferred from the --due-at format when omitted). Returns a requestKey. |
todo update <todoId> | Change --title / --due-at / --is-full-day; --is-done true completes, --is-done false reopens. |
todo delete <todoId...> | Delete the given todos; --confirmed is required. |
Every subcommand also accepts --json-file <file> (- for stdin) carrying a JSON object; it can't be combined with field flags.
yc --format json todo list --is-done false
yc --format json todo create --title 'Product review' --due-at '2026-10-10T15:00:00+08:00' --is-full-day false
yc --format json todo update 841 --is-done true
yc --format json todo delete 841 --confirmed- Idempotent replay: when a create's outcome is unknown (timeout, dropped connection), only replay it with the returned
--request-key <key>and identical arguments, to avoid duplicates. - Partial success: multi-step operations such as combined updates that partially succeed return
ok: false, per-stage results and a non-zero exit code — never reported as a full success. - An Agent answering "today" should pass explicit local-day
--start-time/--end-time; the companionyoooclaw-todoSkill defines natural-language routing, where to view a created todo (the app home todo card / todo list), and confirmation before deletion.
monitor — Scheduled notification monitoring tasks 🟡
Scheduled task definitions driven by cron expressions (currently persists definitions and enabled state).
| Command | Description |
|---|---|
monitor list | List all monitor tasks. |
monitor show <name> | Task details. |
monitor create <name> | Create a task. --description, --match-rules <json>, --schedule <cron> are all required. |
monitor delete <name> | Delete a task (--yes). |
monitor enable <name> / disable <name> | Enable / pause a task. |
tunnel — Relay tunnel 🟡
| Command | Description |
|---|---|
tunnel status | Query the Relay connection status (connected / reconnectAttempt / disconnect reason / stale + currentUrl + expectedUrl). With multiple keys, returns tunnels[]; --client <label> shows only the specified tunnel. See Debugging & Troubleshooting. |
tunnel reconnect | Force a disconnect and reconnect. --client <label> reconnects only the specified label; if omitted, reconnects all tunnels. |
tunnel +test | End-to-end connectivity self-test: the daemon sends itself an echo notification over local loopback, verifying the ingest + auth chain. --client <label> writes with the specified api-key. |
log — Log search 🟢
| Command | Description |
|---|---|
log [keyword] | Search the daemon logs. --from/--to <YYYY-MM-DD>, --limit (default 50), --level. |
log +errors | Error-level logs since yesterday. |
gateway — Protocol self-test 🟡
| Command | Description |
|---|---|
gateway test | Simulate the phone calling the daemon's /notifications, verifying connectivity / auth. --from-phone-ip <ip>, --via-relay. |
api — Raw HTTP escape hatch 🟡
yoooclaw api GET /daemon/status
yoooclaw api POST /images --data @img.json
yoooclaw api POST /light/send --data '{"preset":"red-strobe-3"}'--data supports @filename (read from a file), - (read from stdin), or inline JSON; --header <key:value> can be repeated.
The raw API tries to preserve the daemon's original HTTP semantics as much as possible; scripts consuming it should check both the response body's ok and the HTTP status, not just the process exit code.
skills — Agent skill management 🟢
Installs the SKILL.md files shipped with the package into an Agent's skills discovery directory, so the Agent can drive yoooclaw commands on its own. See Agent Skill for details.
| Command | Description |
|---|---|
skills list | List the built-in Skills shipped with the CLI and their trigger descriptions. |
skills targets | List the supported Agent skills directories and auto-detection results. |
skills install | Install into an Agent's skills directory. --agent <agent> (auto / claude / codex / custom, default auto), --target <dir>, --copy, --force. |
yoooclaw skills list
yoooclaw skills targets
yoooclaw skills install # auto-detect the single available Agent and install
yoooclaw skills install --agent codextransfer — Data transfer
Moves local data between two environments (a new computer, a reinstall, another profile, or between the standalone CLI and the OpenClaw plugin). It transfers notifications, recordings (transcripts / summaries) and synced web pages, optionally audio / images / raw HTML archives; memory, credentials and configuration are not transferred. The package format is the same as the OpenClaw plugin's ntf transfer (schema 1) — packages and capability files work in both directions.
| Command | Description |
|---|---|
transfer export 🟢 | Export a package by reading local files directly; no daemon needed. Scope: --include notifications,recordings,web-pages,images (first three by default), --from / --to (timezone required, start inclusive / end exclusive), --with-audio / --with-images / --with-html; --dry-run previews counts and size only; --target-capabilities <file> preflights against the target. --via oss packs a tar.gz, uploads it and returns a transfer taskId; --via local (default) with --out <new path> writes locally — a .tar.gz / .tgz path produces a single archive, anything else a package directory. |
transfer import 🟡 | Runs the import inside the target daemon. --task <taskId> resolves the download URL, downloads, verifies and imports (--dry-run downloads and previews only); --file <package> only stages + verifies + previews and never merges, returning localTransferId / planId / per-action counts and a nextCommand; --local <id> --plan <id> executes a previewed plan, and --resume continues an interrupted or PARTIAL import. |
transfer capabilities 🟡 | Read the target's (running daemon's) transfer capabilities; --out saves a file for the source side's export --target-capabilities. |
transfer complete | When the upload bytes were sent but the completion confirmation failed, retry it with the --task <taskId> --object-key <objectKey> from the error; it doesn't re-upload or create another task. |
# Default: cloud relay (source side)
yoooclaw transfer export --dry-run --format json
yoooclaw transfer export --via oss --format json # → taskId
# Target side
yoooclaw transfer import --task <taskId> --format json
# Offline: local package
yoooclaw transfer export --out ~/yoooclaw-pkg.tar.gz --with-audio
yoooclaw transfer import --file ~/yoooclaw-pkg.tar.gz
yoooclaw transfer import --local <localTransferId> --plan <planId>Key constraints:
- Cloud relay uses the current profile's account api-key and cloud environment; source and target api-keys must belong to the same account and environment. Uploads use the Alibaba Cloud OSS SDK's resumable multipart upload with STS credentials renewed during the upload; downloads resume via Range requests. Resumption only works within the same command — not after a process restart. Creating a task consumes quota (at most 3 per day), so don't re-run
exporton failure; usetransfer completefor a failed confirmation. - The server owns cloud packages: they're deleted automatically 24 hours after the upload completes, regardless of whether they were imported; the CLI has no cloud delete command. Signed download URLs are only used inside the command and never appear in output.
- Privacy: packages are plaintext (tar.gz is packaging, not encryption) — keep task IDs and packages safe and don't share them.
- The target is never overwritten: existing target records are never overwritten, and differing records are reported as
conflict; imported notifications are re-bucketed by the target's timezone and markedskip-historyso they skip memory sync (see sync). A successful import cleans its local staging automatically; PARTIAL or failed imports keep the staged package andreport.jsonunder<profile>/transfers/for--resume, and previews that were never imported are pruned after 7 days. - One marker on the source: export writes a
.transfer-originfile into each source data directory so multi-hop transfers keep their original source identity;--dry-rundoesn't write it, and source records are never modified or removed. - Compatibility: targets older than CLI 0.12.0 / plugin 1.18.0 only accept package directories — exporting a tar.gz with
--target-capabilitiesfails withYOOOCLAW_TRANSFER_ARCHIVE_UNSUPPORTED_BY_TARGET. A daemon older than the CLI returnsYOOOCLAW_TRANSFER_UNSUPPORTED;daemon restartfixes it. Oversized scopes are refused at export time (YOOOCLAW_TRANSFER_PACKAGE_TOO_MANY_RECORDS/_MANIFEST_TOO_LARGE) — narrow them with--include/--from/--to.
The companion yoooclaw-data-transfer Skill turns an export into "a privacy warning + one copyable import sentence" (帮我导入这份迁移数据:<taskId>, translated to the user's language), which the user simply sends to the target-side Agent.
Maintenance commands
| Command | Description |
|---|---|
migrate from-openclaw 🟢 | Migrate notifications / recordings / rules / images and api-keys from ~/.openclaw/plugins/phone-notifications/ into ~/.yoooclaw/, automatically backing up beforehand. --dry-run, --source <path>. |
update self 🟢 | Check the npm registry, compare versions, and prompt (doesn't auto-update). The response's dist identifies the current install source (npm / native), and command gives the matching upgrade command: the npm form returns npm update -g @yoooclaw/cli, native binaries return curl ... install.sh | sh -s -- --version <v> --force on macOS / Linux and install.ps1 ... -Version <v> -Force on Windows. --beta, --json. |
doctor 🟢/🟡 | Environment self-check: Go runtime, directory permissions, keychain, daemon (warns when the lock file exists but the process is gone or fails identity checks), daemon-autostart (missing / not-enabled service or one pointing at an old binary is --fix-able; on Linux a bootWarning when boot prerequisites aren't met), config. --json, --fix. Network self-checks (relay / OSS) are left to gateway test / tunnel +test. |
uninstall 🔵 | Uninstall the CLI: first removes the OS-level autostart registration (see daemon autostart), stops the daemon for every profile, removes the binary (yoooclaw and yc) and config (each profile's config.json, credentials.json, active-profile, daemon.lock at both the account and profile level), keeping notification / recording / image data by default. --data also wipes the data (clears ~/.yoooclaw); --yes skips confirmation. A native Windows install also removes the user PATH entry and install directory (including cross-drive installs), and reports an error rather than silently skipping on failure. The npm install form can't remove its own binary and will prompt you to run npm uninstall -g @yoooclaw/cli. |
yoooclaw migrate from-openclaw --dry-run
yoooclaw doctor --format json
yoooclaw uninstall # stop the daemon + remove binary and config, keep data
yoooclaw uninstall --data --yes # wipe data too, no confirmation