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.
INLINECODE2 -> zf -> INLINECODE4
- - the bot or agent translates intent and explains results
- INLINECODE5 handles discovery, playback, queueing, diagnostics, readiness checks, and recovery
Alternative control methods
In 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.
Hard rules (MUST follow)
- 1. Always obey
nextCommand: If zf setup --format json returns a nextCommand field, execute that command immediately.
- 2. Always obey
nextAction: If zf service list --format json returns a nextAction field, follow it. If nextAction=ready, proceed to play.
- 3. 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.
- 4. 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.
- 5. Keep update paths separate:
CODEBLOCK0
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:
CODEBLOCK1
If it returns status=update_available, update before doing deeper work:
CODEBLOCK2
Then run the one-shot readiness flow:
CODEBLOCK3
INLINECODE14 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:
CODEBLOCK4
If rooms are found but there is no default room, ask the user to choose exactly one visible room and then set it once:
CODEBLOCK5
If there is no default service, ask once and set it:
CODEBLOCK6
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.
CODEBLOCK7
If the user already specified a room, prefer --name "<room>".
Safe command mapping
For user-facing explanations, prefer direct CLI command names.
Examples:
CODEBLOCK8
Playback rules
Prefer the unified play music command for normal playback.
Common service examples:
CODEBLOCK9
Chinese examples:
CODEBLOCK10
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 + title wording when the user specifies a song, for example zf 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 INLINECODE24
- if the wording is ambiguous and something is already playing,
--enqueue is usually the safer default
Natural-language examples:
- - "play Taylor Swift" -> INLINECODE26
- "add five Adele songs" -> INLINECODE27
- "播郑秀文" -> INLINECODE28
- "再加一首陈奕迅" -> INLINECODE29
Lyrics rule
When the user asks about lyrics for the current song, use:
CODEBLOCK11
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.
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):
CODEBLOCK12
TTS language options:
- -
zh (普通话) — default, no flag needed - INLINECODE32 (粤语/Cantonese) — pass INLINECODE33
Example with Cantonese:
CODEBLOCK13
Important announcement rules:
- 1. 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).
- 2. Concatenate multiple items into one
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.
- 3. 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:
CODEBLOCK14
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 INLINECODE40
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:
CODEBLOCK15
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:
- 1. try playing the user's request directly
- fall back to
zf setup --format json only if playback fails and context is unclear
Failure routing
Read structured JSON errors first:
- - INLINECODE43
- INLINECODE44
- INLINECODE45
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
TRANSITIONING or 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
- INLINECODE48 is a recovery tool, not proof that the original defect is fixed
- exact
RelTime restoration is not a guaranteed stable capability - OpenClaw skill updates and local
zf runtime 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 INLINECODE51
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 guidance - INLINECODE54 — command map and recovery rules
- INLINECODE55 — China service-linking notes
ZoneFoundry Local Sonos
当代理、本地机器人或自动化系统希望通过本地 zf CLI 控制 Sonos 时,使用此技能。
本技能以英文优先编写,方便全球用户快速浏览。面向用户的回复请使用用户的语言。中文示例和中国专属就绪说明已包含在有助于理解的位置。
使用此技能的场景
- - 用户首次连接 Sonos
- 用户想要检查本地 Sonos 控制是否就绪
- 用户想要播放、暂停、跳过、调节音量或查看状态
- 用户想要在不中断播放的情况下将歌曲添加到当前队列
- 用户想要检查或恢复队列/传输问题
- 用户想要检查音乐服务就绪状态或继续待处理的本地链接流程
请勿将此技能用于
- - Sonos 账户创建或计费流程
- 云中继、托管机器人订阅或多租户产品逻辑
- 与 Sonos 控制无关的任意聊天
核心模型
将 zf 视为执行层。
机器人 / 代理 / 网页引导 -> zf -> Sonos
- - 机器人或代理负责翻译意图并解释结果
- zf 负责发现、播放、队列、诊断、就绪检查和恢复
替代控制方式
除了代理/CLI 使用方式外,ZoneFoundry 还支持Telegram 机器人作为替代控制界面。用户可以通过手机向机器人发送语音或文本消息,实现免提控制 Sonos。
硬性规则(必须遵守)
- 1. 始终遵循 nextCommand:如果 zf setup --format json 返回了 nextCommand 字段,请立即执行该命令。
- 2. 始终遵循 nextAction:如果 zf service list --format json 返回了 nextAction 字段,请遵循该指示。如果 nextAction=ready,则继续播放。
- 3. 不要因服务链接状态而阻止播放。 QQ 音乐、Apple Music 和大多数服务无需在 CLI 端单独链接——用户通过 Sonos 移动应用绑定服务。如果状态不明确,请先尝试直接播放。
- 4. 不要在面向用户的解释中暴露内部实现细节、仅限高级用户的路由或推测性的变通方案。 请描述用户可见的结果和下一步安全操作。
- 5. 保持更新路径分离:
bash
clawhub update zonefoundry-local-sonos # 刷新此技能
zf update self --check --format json # 检查本地运行时更新
语言规则
- - 面向用户的回复请使用用户的语言
- 保持房间名称和服务名称与用户在 Sonos 上看到的完全一致
- 默认使用英文示例,仅在有助于提高清晰度时添加中文示例
首次运行快速入门
当用户首次提到 Sonos 时,不要立即说未配置。
在每个新会话开始时,首先检查运行时更新:
bash
zf update self --check --format json
如果返回 status=update_available,在进行更深入的工作前先更新:
bash
zf update self --format json
然后运行一次性就绪流程:
bash
zf setup --format json
zf setup 应作为默认的第一步操作,因为它会检查:
- - 音箱发现
- 默认房间
- 服务列表和本地就绪状态
- 默认服务
- 包含建议下一步操作的最终摘要
如果旧版运行时上 zf setup 不可用,请执行此备用预检:
bash
zf doctor --format json
zf discover --format json
zf config get defaultRoom
zf service list --format json
zf config get defaultService
如果找到了房间但没有默认房间,请让用户选择一个可见的房间,然后设置一次:
bash
zf config set defaultRoom Office
如果没有默认服务,请询问一次并设置:
bash
zf config set defaultService Spotify
环境门槛
在承诺持久的本地机器人控制之前,请确认存在一台与 Sonos 处于同一局域网且始终在线的设备。
有效的本地节点:
- - Mac 或 Windows PC
- NAS
- 迷你 PC
- 树莓派
- Docker 主机
- Home Assistant 主机
如果用户只有手机:
- - 说明 Sonos 本身仍可正常使用
- 引导用户通过官方 Sonos iOS/Android 应用添加/登录服务
- 将 Sonos Web 应用视为辅助控制界面,而非主要引导路径
- 不要承诺持久的本地机器人控制或始终在线的自动化
简要规则:
- - Sonos 本身不需要桌面应用
- 持久的 ZoneFoundry 代理或机器人流程确实需要一个始终在线的本地节点
最小安全命令集
默认优先使用 JSON 输出。
bash
zf setup --format json
zf doctor --format json
zf discover --format json
zf status --name --format json
zf queue list --name --format json
如果用户已指定房间,优先使用 --name 。
安全命令映射
对于面向用户的解释,优先使用直接的 CLI 命令名称。
示例:
bash
zf status --name Office --format json
zf pause --name Office
zf next --name Office
zf volume set 20 --name Office
播放规则
对于常规播放,优先使用统一的 play music 命令。
常见服务示例:
bash
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
中文示例:
bash
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 周杰伦
默认服务选择:
- - 中文内容(中文艺人/歌曲名称,用户说中文):使用 --service QQ音乐。无需后备——QQ 拥有最佳的中文曲库覆盖。
- 国际内容(英文/其他语言的艺人/歌曲名称,用户说英文):使用 --service Spotify。如果 Spotify 不可用,则回退到 --service Apple Music。
- 如果用户明确指定了服务,始终尊重用户的选择。
- QQ 音乐和 Apple Music 使用公共搜索 API——无需单独的 CLI 链接。直接播放即可。
- 当用户指定歌曲时,使用精确的 艺人 + 歌曲名 措辞,例如 zf play music 黎明 夏日傾情 --service QQ音乐。
重要区别:
- - 如果用户说播放 X,使用 zf play music X,预期为替换式操作
- 如果用户说添加 X、排队 X、追加 X或播完这个放 X,使用 zf play music X --enqueue
- 如果措辞模糊且已有内容正在播放,--enqueue 通常是更安全的默认选择
自然语言示例:
- - 播放 Taylor Swift -> zf play music Taylor Swift
- 添加五首 Adele 的歌 -> zf play music Adele --enqueue --limit 5
- 播郑秀文 -> zf play music 郑秀文
- 再加一首陈奕迅 -> zf play music 陈奕迅 --enqueue
歌词规则
当用户询问当前歌曲的歌词时,使用:
bash
zf lyric --name --format json
当运行时支持时,此命令会获取当前播放曲目的歌词。如需获取带时间戳的原始 LRC,请添加 --raw。
QQ 音乐歌词现已可靠工作(MID 解析问题已修复)。QQ 音乐和网易云音乐的曲目在可用时都会返回带翻译的歌词。
播报规则
如果用户要求简短的语音打断,例如:
- - 读一分钟新闻简报
- 通知会议五分钟后开始
- 播一分钟新闻
- 20 分钟后提醒我开会
默认使用简短的 TTS 或提醒路径,而非搜索电台。
当前稳定的播报路径(直接模式,默认):
bash
zf say --name --format json
TTS 语言选项:
- - zh(普通话)—— 默认,无需指定标志
- yue(粤语)—— 传入 --lang yue
粤语