Zonefoundry Local Sonos
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...
Like a lobster shell, security has layers — review code before you run it.
License
Runtime requirements
Install
go install github.com/kisssam6886/zonefoundry/cmd/zf@latestSKILL.md
ZoneFoundry Local Sonos
Use 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.
Use this skill when
- the user wants to connect Sonos for the first time
- the user wants to check whether local Sonos control is ready
- the user wants to play, pause, skip, change volume, or inspect status
- the user wants to add songs to the current queue without interrupting playback
- the user wants to inspect or recover queue / transport problems
- the user wants to check music-service readiness or continue a pending local link flow
Do not use this skill for
- Sonos account creation or billing flows
- cloud relay, hosted bot subscription, or multi-tenant product logic
- arbitrary chat unrelated to Sonos control
Core model
Treat zf as the execution layer.
bot / agent / web onboarding -> zf -> Sonos
- the bot or agent translates intent and explains results
zfhandles discovery, playback, queueing, diagnostics, readiness checks, and recovery
Hard rules (MUST follow)
-
Always obey
nextCommand: Ifzf setup --format jsonreturns anextCommandfield, execute that command immediately. -
Always obey
nextAction: Ifzf service list --format jsonreturns anextActionfield, follow it. IfnextAction=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
Language rule
- keep user-facing replies in the user's language
- keep literal room names and service names exactly as the user sees them on Sonos
- use English examples by default, then add Chinese examples only when they improve clarity
First-run quickstart
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:
- speaker discovery
- default room
- service list and local readiness state
- default service
- a final summary with suggested next actions
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"
Environment gate
Before promising persistent local bot control, confirm there is an always-on device in the same LAN as Sonos.
Valid local nodes:
- Mac or Windows PC
- NAS
- mini PC
- Raspberry Pi
- Docker host
- Home Assistant host
If the user only has a phone:
- explain that Sonos itself can still be used normally
- guide service add/login through the official Sonos iOS / Android app
- treat Sonos Web App as a supplementary control surface, not the main onboarding path
- do not promise persistent local bot control or always-on automation
Short rule:
- Sonos itself does not require a desktop app
- persistent ZoneFoundry agent or bot flows do require an always-on local node
Minimum safe commands
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>".
Safe command mapping
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"
Playback rules
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:
- Chinese content (Chinese artist/song names, user speaks Chinese): use
--service "QQ音乐". No fallback — QQ has the best Chinese catalog coverage. - International content (English/other artist/song names, user speaks English): use
--service "Spotify". If Spotify is unavailable, fallback to--service "Apple Music". - If the user explicitly names a service, always honour that.
- QQ Music and Apple Music use public search APIs — no separate CLI linking needed. Just play directly.
- Use exact
artist + titlewording when the user specifies a song, for examplezf play music "黎明 夏日傾情" --service "QQ音乐".
Important distinction:
- if the user says "play X", use
zf play music "X"and expect a replace-style action - if the user says "add X", "queue X", "append X", or "play X after this", use
zf play music "X" --enqueue - if the wording is ambiguous and something is already playing,
--enqueueis usually the safer default
Natural-language examples:
- "play Taylor Swift" ->
zf play music "Taylor Swift" - "add five Adele songs" ->
zf play music "Adele" --enqueue --limit 5 - "播郑秀文" ->
zf play music "郑秀文" - "再加一首陈奕迅" ->
zf play music "陈奕迅" --enqueue
Lyrics rule
When 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.
Announcement rule
If the user asks for a short spoken interruption such as:
- "read a one-minute news brief"
- "announce the meeting starts in 5 minutes"
- "播一分钟新闻"
- "20 分钟后提醒我开会"
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
Important announcement rules:
- Always use direct mode (the default). Do NOT pass
--mode queue-insert. Direct mode plays TTS then automatically restores the original track and position (reltime). - Concatenate multiple items into one
zf saycall. If the user asks for "5 news headlines", compose all 5 headlines into a single text block and callzf sayonce. Do NOT callzf sayfive separate times — that causes interleaving with music and breaks reltime restore. - After TTS completes, the original song resumes at the exact playback position.
Only treat it as a live radio request if the user explicitly asks for a station or live news channel.
Queue hygiene rule
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.
Service readiness rule
Most music services work without separate CLI-side linking:
- QQ Music: uses public search API → always ready, no linking needed
- Apple Music: uses public search API → always ready, no linking needed
- Spotify: depends on household setup; try playing directly first
- NetEase Cloud Music (网易云音乐): uses SMAPI; may need initial linking via
zf setup
Users 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
New-session rule
If a new session starts and the user says things like:
- "done"
- "complete"
- "I logged in already"
- "已经绑好啦"
- "我登录好了"
do not force the whole onboarding conversation again.
Prefer this order:
- try playing the user's request directly
- fall back to
zf setup --format jsononly if playback fails and context is unclear
Failure routing
Read structured JSON errors first:
error.codeerror.messageerror.details
Do not classify every playback failure as auth or copyright.
Known patterns:
- if the same song plays in a helper room but not in the target room, suspect room-local queue or transport pollution first
- if you see
TRANSITIONINGor partial queue failure, do not loop infinite retries - if queue pollution is suspected, prefer explicit queue inspection and recovery commands
- if deeper room-local pollution is confirmed,
zf group rebuild --name "<target>" --via "<helper>"is the stronger recovery path
Boundaries
- Sonos official mobile apps remain the default path for adding and logging in to content services
- Sonos Web App is a supplementary control surface, not the primary onboarding path
group rebuildis a recovery tool, not proof that the original defect is fixed- exact
RelTimerestoration is not a guaranteed stable capability - OpenClaw skill updates and local
zfruntime updates may require a new session to fully refresh
When to ask the user something
Ask only when required:
- choose a default room
- confirm a preferred music service
- confirm helper-room usage for
group rebuild
Do not ask the user to learn repo internals or memorize command names.
User-facing tone
Good examples:
- "I'll first check whether this machine can discover your Sonos speakers on the LAN."
- "I found these rooms: Office, Kitchen. Which one should be the default?"
- "我先检查这台机器能不能发现你局域网里的 Sonos。"
- "我找到这些房间:客厅、浴室。你想默认控制哪一个?"
Avoid:
- "Please install the Sonos controller" as a blanket answer
- "Learn the zf CLI first"
- "Not configured" before running preflight
Read these references when needed
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
Files
6 totalComments
Loading comments…
