Skip to content

Usage & Lifecycle

Switching environments

The Relay endpoint is per yoooclaw profile (relay.url / cloud.host in each profile's config.json). Use env to switch the active profile and rebuild the websocket service group in one step:

bash
hermes yoooclaw env            # show the active environment + Relay status
hermes yoooclaw env test       # switch to the `test` profile
hermes yc env test             # equivalent short alias
hermes yoooclaw env default    # switch back to the `default` (prod) profile

/yoooclaw env <profile> and /yc env <profile> do the same from a chat session. The built-in default, test, and development profiles are initialized on first use with the matching Relay endpoint. Changing the profile changes the lifecycle generation, so the watchdog releases the old profile's storage writer lock, claims the new one, and rebuilds the tunnels — exactly one profile is claimed at any time. An unknown profile name fails without disturbing the current connection.

The Relay apiKey stays account-global (~/.yoooclaw/credentials.json), independent of profile. Switch it with:

bash
yoooclaw auth set-default-api-key <label>

CLI profiles use openclaw-service*.yoooclaw.com for the Relay tunnel; APP chat shares the same connection. The installer repairs stale legacy URLs if an old plugin version persisted them into CLI profiles.

Daemonless storage model

In plugin mode there is no CLI daemon. The plugin process is both the tunnel owner and the sole writer of the profile's storage:

Plugin modeStandalone CLI mode
TriggerHermes loads the yoooclaw / yoooclaw_app pluginsCLI-only install, you run daemon start yourself
Storage writerThe plugin process (sole)The daemon (sole)
Tunnel ownerThe pluginThe daemon's own Relay WS
CLI read-only commandsWork normally (read files directly)Work normally
yoooclaw daemon startRefused: YOOOCLAW_DAEMON_DISABLED_BY_PLUGINWorks normally

The two modes are mutually exclusive via ~/.yoooclaw/profiles/<profile>/writer.lock — an OS advisory lock, released automatically when the process dies, in the same lock namespace across languages (Python plugin / Go CLI). On startup the plugin stops any leftover daemon and then claims the lock; disabling the plugin releases it, and yoooclaw daemon start returns you to standalone mode with no data migration required (the storage layout is a contract both sides share).

There's also a separate account-level Relay consumer lock (standalone-relay.flock, compatible with the CLI-side lock of the same name), outside the profile directory, that must be acquired before opening any Relay connection — this prevents two profiles, or the plugin and the standalone CLI, from consuming the same account's Relay stream at once and double-writing messages. If the active-profile pointer references a manually-deleted profile directory, it now safely falls back to default instead of erroring.

Inbound frames land directly in the plugin's in-process storage engine: /notifications, recordings.result.write, images.sync, and friends are written following the CLI's directory contract (tmp file + atomic replace), and events like recording.status are forwarded to the tunnel over an in-process event bus rather than a local HTTP callback. lightrules.* and /light/send frames become embedded-CLI subprocess calls — the rule files belong to the CLI, which avoids a second writer.

Explicitly not available in plugin mode: recordings.retranscribe and asr.init return YOOOCLAW_NOT_IMPLEMENTED (in the Hermes setup, ASR is done on the App side).

Lifecycle management

The plugin manages the storage claim and the openclaw-service tunnels as a single transaction boundary. On startup it computes a lifecycle generation (the first 24 hex chars of a SHA-256) from the plugin version, active profile, Relay environment, PHONE_NOTIFICATIONS_ENV, openclaw-service URL, and api-key fingerprint. Any change makes the generation mismatch and triggers a rebuild of the whole group.

bash
hermes yoooclaw lifecycle status
hermes yoooclaw lifecycle restart
hermes yc lifecycle status

lifecycle restart doesn't reconnect on the spot: it sets a restart flag, and the watchdog rebuilds the tunnels (disconnect + connect) on its next poll, by default within 5 seconds.

The lifecycle snapshot schema is now v3, adding pid, instanceId, hermesProfile, profile, heartbeatAt, lastControlRequestId, lastControlStatus, and pendingControlRequestId. When --hermes-profile/HERMES_PROFILE is set, the snapshot is split per Hermes profile (lifecycle/<hermesProfile>.json) instead of a single flat lifecycle.json. There's also a new cross-process control file (control/<profile>.json): a short-lived, one-off CLI invocation can write to it to request a gateway restart, which the long-running gateway process picks up and ACKs in its own snapshot. hermes yoooclaw lifecycle status now reads this persisted snapshot and reports running/stale/stopped/mismatch based on heartbeat freshness (stale past 30 seconds by default), rather than synthesizing "stopped" whenever no local transport happens to be registered. The Relay handshake also now carries clientType/version/capabilities (e.g. agent-commands-v1) and a stable instanceId, which helps when debugging multi-process/multi-instance setups.

The APP adapter runs a watchdog while connected: a generation change rebuilds the group, and so does the Relay websocket staying disconnected past YOOOCLAW_HERMES_WS_RESTART_AFTER (default 30 seconds). Set YOOOCLAW_HERMES_LIFECYCLE_WATCH_INTERVAL to tune the poll interval (default 5 seconds); failed recoveries use exponential backoff capped by YOOOCLAW_HERMES_LIFECYCLE_MAX_BACKOFF (default 60 seconds).

A failed storage claim (the writer lock is held by another process) does not block connecting: chat and queries keep working, ingest just takes the fallback path, and the reason is recorded in the log and in lifecycle status.

Surface area

The tool plugin exposes notification, recording (recording_list also supports from/to filtering by recording time), captured web-page (synced_web_page_list / search / path / storage_path, with from/to time-range filtering on capturedAt — this group of tools used to be named web_*, but since that read as Hermes's built-in live web_search, it was renamed to synced_web_page_*), image, Relay, light-control, light-rule CRUD, status reporting (the tool is still named daemon_status; in daemonless mode it reports the storage claim and tunnel state), and doctor tools. The APP platform adapter connects directly to Relay and translates the existing OpenClaw-compatible chat.send, chat.history, chat.abort, and sessions.* RPC frames into Hermes messages and APP-owned session state.

Most setups never need to touch these — they matter when you're adjusting timeouts, disabling an automatic behavior, or doing local development:

VariableDefaultEffect
YOOOCLAW_HERMES_CLAIM_STORAGEonSet to 0 to stop the plugin from claiming local storage at load; ingest then takes the fallback path. When unset it inherits the value of YOOOCLAW_HERMES_AUTO_START_DAEMON (legacy name).
YOOOCLAW_HERMES_DIRECT_INGESTonSet to 0 to send ingest back down the old daemon-HTTP path (kill switch).
YOOOCLAW_HERMES_WS_RESTART_AFTER30 (seconds)How long the Relay websocket must stay disconnected before the whole group restarts.
YOOOCLAW_HERMES_LIFECYCLE_WATCH_INTERVAL5 (seconds)Watchdog poll interval.
YOOOCLAW_HERMES_LIFECYCLE_MAX_BACKOFF60 (seconds)Cap on exponential backoff after failed recoveries.
YOOOCLAW_HERMES_LIFECYCLE_MISMATCH_STREAK2How many consecutive mismatch readings are required before a rebuild (avoids over-reacting to probe noise).
YOOOCLAW_CLI_PATHunsetExplicitly points at a CLI binary, entirely bypassing the embedded CLI's PATH injection — only meant for local development against a non-embedded CLI build.
YOOOCLAW_HERMES_INSTALL_CLIonSet to 0 to disable PATH injection (shim install) at plugin load.
YOOOCLAW_HERMES_INSTALL_SKILLSonSet to 0 to disable the bundled-skills copy step.
HERMES_PROFILEunsetNames the Hermes profile to target when Hermes runs under a named profile — the installer and gateway-restart commands use it to locate config and split the lifecycle snapshot; equivalent to the installer's --hermes-profile.

Next steps