Install
openclaw skills install zonefoundry-local-sonosClawHub Security found sensitive or high-impact capabilities. Review the scan results before using.
Use this skill when an agent needs to control Sonos through ZoneFoundry `zf` on a same-LAN node. Start with readiness checks, then map user requests to safe playback, queue, service-linking, and recovery commands.
openclaw skills install zonefoundry-local-sonosUse this skill when an agent, local bot, or automation wants to control Sonos through the local zf CLI.
This skill is written English-first so global users can scan it quickly. Keep user-facing replies in the user's language. Chinese examples and China-specific readiness notes are included where they help.
Treat zf as the execution layer.
bot / agent / web onboarding -> zf -> Sonos
zf handles discovery, playback, queueing, diagnostics, readiness checks, and recoveryIn addition to agent / CLI usage, ZoneFoundry supports a Telegram Bot as an alternative control surface. Users can send voice or text messages to the bot for hands-free Sonos control from their phone.
Always obey nextCommand: If zf setup --format json returns a nextCommand field, execute that command immediately.
Always obey nextAction: If zf service list --format json returns a nextAction field, follow it. If nextAction=ready, proceed to play.
Do not block playback on service linking status. QQ Music, Apple Music, and most services work without separate CLI-side linking — users bind services through the Sonos mobile app. If state is unclear, try playing directly first.
Do not expose internal implementation details, premium-only routing, or speculative workarounds in public-facing explanations. Describe user-visible outcomes and the next safe action instead.
Keep update paths separate:
clawhub update zonefoundry-local-sonos # refresh this skill
zf update self --check --format json # check local runtime update
When the user mentions Sonos for the first time, do not immediately say "not configured".
At the start of every new session, check runtime updates first:
zf update self --check --format json
If it returns status=update_available, update before doing deeper work:
zf update self --format json
Then run the one-shot readiness flow:
zf setup --format json
zf setup should be the default first move because it checks:
If zf setup is unavailable on an older runtime, do this fallback preflight:
zf doctor --format json
zf discover --format json
zf config get defaultRoom
zf service list --format json
zf config get defaultService
If rooms are found but there is no default room, ask the user to choose exactly one visible room and then set it once:
zf config set defaultRoom "Office"
If there is no default service, ask once and set it:
zf config set defaultService "Spotify"
Before promising persistent local bot control, confirm there is an always-on device in the same LAN as Sonos.
Valid local nodes:
If the user only has a phone:
Short rule:
Prefer JSON output by default.
zf setup --format json
zf doctor --format json
zf discover --format json
zf status --name "<room>" --format json
zf queue list --name "<room>" --format json
If the user already specified a room, prefer --name "<room>".
For user-facing explanations, prefer direct CLI command names.
Examples:
zf status --name "Office" --format json
zf pause --name "Office"
zf next --name "Office"
zf volume set 20 --name "Office"
Prefer the unified play music command for normal playback.
Common service examples:
zf play music "Miles Davis" --format json
zf play music "Taylor Swift" --service Spotify --format json
zf play music "Adele" --service "Apple Music" --format json
zf play music "黎明 夏日傾情" --service "Apple Music" --format json
zf play music "黎明" --enqueue --service "Apple Music" --limit 5 --format json
zf queue list --name "Office" --format json
zf queue remove 3 --name "Office"
zf say "Dinner is ready" --name "Kitchen" --mode queue-insert --format json
Chinese examples:
zf play music "周杰伦" --service "网易云音乐" --format json
zf play music "郑秀文" --enqueue --service "QQ音乐" --limit 5 --format json
zf play music "郑秀文 舍不得你" --service "QQ音乐" --format json
zf ncm lucky --name "客厅" "郑秀文" --format json
zf smapi search --name "客厅" --service "QQ音乐" --category tracks --open --index 1 --format json "周杰伦"
Default service selection:
--service "QQ音乐". No fallback — QQ has the best Chinese catalog coverage.--service "Spotify". If Spotify is unavailable, fallback to --service "Apple Music".artist + title wording when the user specifies a song, for example zf play music "黎明 夏日傾情" --service "QQ音乐".Important distinction:
zf play music "X" and expect a replace-style actionzf play music "X" --enqueue--enqueue is usually the safer defaultNatural-language examples:
zf play music "Taylor Swift"zf play music "Adele" --enqueue --limit 5zf play music "郑秀文"zf play music "陈奕迅" --enqueueWhen the user asks about lyrics for the current song, use:
zf lyric --name "<room>" --format json
This fetches lyrics for the currently playing track when supported by the runtime. For raw LRC with timestamps, add --raw.
QQ Music lyrics now work reliably (MID resolution fixed). Both QQ Music and NetEase Cloud Music tracks return lyrics with translations when available.
If the user asks for a short spoken interruption such as:
default to a short TTS or reminder path, not radio search.
Current stable announcement path (direct mode, default):
zf say "<text>" --name "<room>" --format json
TTS language options:
zh (普通话) — default, no flag neededyue (粤语/Cantonese) — pass --lang yueExample with Cantonese:
zf say "今日新闻" --name "<room>" --lang yue --format json
Important announcement rules:
--mode queue-insert.
Direct mode plays TTS then automatically restores the original track and position (reltime).zf say call. If the user asks for
"5 news headlines", compose all 5 headlines into a single text block and call
zf say once. Do NOT call zf say five separate times — that causes
interleaving with music and breaks reltime restore.Only treat it as a live radio request if the user explicitly asks for a station or live news channel.
After adding songs via zf play music with --enqueue or after any queue-related playback,
run an automatic queue prune to remove copyright-blocked tracks:
zf queue prune --name "<room>" --format json
This removes greyed-out tracks (e.g. "应版权方要求暂不能播放") from the queue. Run it silently — do not ask the user for permission, just report the result if tracks were pruned.
Most music services work without separate CLI-side linking:
zf setupUsers bind music services through the Sonos mobile app — there is no desktop binding.
Do not tell users "service not linked" if zf play music works. Try playing first, diagnose only on failure.
If you need a reliable probe, prefer:
zf doctor service --service "Spotify" --query "Miles Davis" --format json
If a new session starts and the user says things like:
do not force the whole onboarding conversation again.
Prefer this order:
zf setup --format json only if playback fails and context is unclearRead structured JSON errors first:
error.codeerror.messageerror.detailsDo not classify every playback failure as auth or copyright.
Known patterns:
TRANSITIONING or partial queue failure, do not loop infinite retrieszf group rebuild --name "<target>" --via "<helper>" is the stronger recovery pathgroup rebuild is a recovery tool, not proof that the original defect is fixedRelTime restoration is not a guaranteed stable capabilityzf runtime updates may require a new session to fully refreshAsk only when required:
group rebuildDo not ask the user to learn repo internals or memorize command names.
Good examples:
Avoid:
Bundled reference files (same repo, references/ subdirectory):
onboarding-boundary.md — product scope and onboarding guidancecommand-map.md — command map and recovery ruleschina-service-linking.md — China service-linking notes