{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreideisbiykrk45c2tp7333mgruknn3ful2x54bdqc6q6o2q2gb7voq",
    "uri": "at://did:plc:6u4awktizhivwgqxl5j67h4k/app.bsky.feed.post/3mmzf7hkwmrt2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreidwbs7nqb5g7czqkiokfpfedub3get2xjn7uj4t4fuiccxzdqzdhe"
    },
    "mimeType": "image/webp",
    "size": 62176
  },
  "description": "My now-playing kiosk has a long install document, and it's a long document. Three hundred and ninety-three lines, eight sequential phases, six environment variables that each gate a different optional install path, and a fifty-line section on a particular display whose touch input lives on a separate USB cable from its video. In addition to this, I wrote a Claude Code skills bundle that walks the same install conversationally.\n\n\nThe two ship together in the repo right now. The long doc is the fa",
  "path": "/skills-instead-of-setup-docs/",
  "publishedAt": "2026-05-29T20:35:55.000Z",
  "site": "https://www.subaud.io",
  "tags": [
    "now-playing kiosk",
    "repo",
    "INSTALL.md",
    "uv",
    "pi/.env.example",
    "github.com/schuettc/now-playing",
    ".claude/skills/",
    "README"
  ],
  "textContent": "My now-playing kiosk has a long install document, and it's a long document. Three hundred and ninety-three lines, eight sequential phases, six environment variables that each gate a different optional install path, and a fifty-line section on a particular display whose touch input lives on a separate USB cable from its video. In addition to this, I wrote a Claude Code skills bundle that walks the same install conversationally.\n\nThe two ship together in the repo right now. The long doc is the fallback for anyone not using Claude Code; the skills are the path I would recommend every Claude Code user to take.\n\n## What setup looks like without the skills\n\nThe INSTALL.md is honest about the work. The first thing it asks you to do is wire an audio chain — a turntable, a phono preamp, two RCA Y-splitters, a Behringer UFO202 USB audio interface, the Pi, and a display. Then prepare the Pi: flash an SD card, set the hostname so `nowplaying-pi.local` resolves, configure passwordless sudo and SSH, install system packages. Then `git clone`, install uv, `uv sync` with the right extras for the optional features you want. Then go get a Discogs personal access token. Then run a catalog sync that hits Discogs's rate-limited API once for every record you own. Then configure your Sonos zone. Then verify the capture pipeline manually with a Python one-liner. Then install two systemd units. Then open the kiosk URL. Then — if you bought the touch display the project's tuned for — go back and wire its second USB cable for touch input, add Chromium command-line flags, and possibly calibrate.\n\nThe environment matters in a different way for every variable. The pi/.env.example is forty-four lines because every variable has a comment explaining what feature it gates and what you lose without it:\n\n\n    # Discogs personal access token (https://www.discogs.com/settings/developers)\n    # Recommended — token enables the full album-context layer (track/album/\n    # tracklist metadata, side timer, album-locked recognition, BEST GUESS card,\n    # sticky disambiguation). Without it, the kiosk falls back to a Shazam-only\n    # display (artist + title + album + cover art from Apple's CDN) and loses\n    # every tracklist-dependent feature.\n    DISCOGS_TOKEN=replace_me\n\n    # Optional: Last.fm scrobbling. When all three are set, confirmed tracks\n    # auto-scrobble to your Last.fm profile.\n    # LASTFM_API_KEY=\n    # LASTFM_API_SECRET=\n    # LASTFM_SESSION_KEY=\n\n    # Optional: Anthropic API key activates LLM-assisted decisions...\n    # ANTHROPIC_API_KEY=sk-ant-...\n\n    # Optional: enable the local-fingerprint cascade...\n    # FINGERPRINT_ENABLED=false\n\n\nSome of those variables also drag extra install steps with them. Setting `ANTHROPIC_API_KEY` means running `uv sync --extra llm`. Setting `FINGERPRINT_ENABLED=true` means `uv sync --extra fingerprint`. Setting the three Last.fm variables means running a one-off Python script that opens a browser to do the auth dance and writes a session key back into the env file.\n\nNone of this is gratuitous. The kiosk is a real hardware project and these are the real steps. But putting it all in a 393-line document means I have to keep the document current as the project evolves, hope the reader follows it in order, and write a separate troubleshooting doc for when they don't.\n\n## What I shipped instead\n\nAlongside `docs/INSTALL.md` the repo ships a `.claude/skills/` directory with ten skills. They activate automatically when someone uses Claude Code in the repo — there's no need to invoke them by name. The user describes what they're doing and the right skill fires.\n\n\n    .claude/skills/\n    ├── README.md\n    ├── nowplaying-setup/             # coordinator\n    ├── nowplaying-setup-hardware/    # phase 1\n    ├── nowplaying-setup-pi/          # phase 2\n    ├── nowplaying-setup-sonos/       # phase 3\n    ├── nowplaying-setup-accounts/    # phase 4\n    ├── nowplaying-setup-install/     # phase 5\n    ├── nowplaying-setup-services/    # phase 6\n    ├── nowplaying-setup-lastfm/      # optional\n    ├── nowplaying-troubleshoot/\n    ├── nowplaying-diagnose/\n    └── nowplaying-status/\n\n\nEach skill is a `SKILL.md` with YAML frontmatter. The `description` field tells Claude when to activate the skill. Mine for `nowplaying-setup-hardware` reads:\n\n\n    description: Use when the user is wiring up the physical audio chain\n      for Now Playing — connecting their turntable, RIAA preamp, RCA\n      splitter, Sonos line-in, and USB audio capture device, or attaching\n      the kiosk display and touch USB cable. Triggers on phrases like\n      \"wire the audio\", \"connect the turntable\", \"how do I split the\n      signal\", \"what cables do I need\", \"set up the hardware\", \"connect\n      the display\".\n\n\nWhen the user says _\"I want to wire up the turntable\"_ or _\"what cables do I need,\"_ that skill activates and Claude follows its content. The body of the skill is a runbook — the same content I'd have written in INSTALL.md, but addressed to Claude as a guide rather than to the user as a sequence of bullet points to follow on their own.\n\nThe coordinator skill (`nowplaying-setup`) is what makes the bundle feel different from a doc. Its job is to figure out where the user already is and route them to the right phase. The first thing it does isn't to ask questions — it probes:\n\n\n    ssh nowplaying-pi 'test -f ~/now-playing/pi/data/discogs.sqlite && echo OK'\n    ssh nowplaying-pi 'systemctl is-active nowplaying-orchestrator nowplaying-kiosk'\n\n\nIf the Discogs catalog is already synced, Phase 4 is done. If the services are already running, the install is complete and Claude tells the user to open the kiosk URL. Only when a probe is inconclusive does the coordinator ask the user a question, and only one at a time. If you come back the next day, the coordinator probes again and picks up where you are.\n\n## What it looks like in practice\n\nA worked example. The user types _\"help me set up the now-playing kiosk on a fresh pi.\"_\n\nThe coordinator activates. It hasn't probed yet, because no host is configured, so it asks one question: _\"Are you driving this from your Mac via SSH, or working directly on the Pi?\"_ The user says SSH from a Mac. The coordinator notes that and asks about the hardware — _\"Is the audio chain wired up yet — turntable feeding both your Sonos line-in and the USB capture device on the Pi?\"_ On a no, it hands off to `nowplaying-setup-hardware`.\n\nThat phase skill walks the user through the splitter wiring, the Sonos and UFO202 connections, and the optional display cabling. It checks: _run`ssh nowplaying-pi 'lsusb | grep BEHRINGER'` — does the UFO202 enumerate?_ When a device comes back, the phase verifies and returns control to the coordinator, which moves to the next probe. By the end of the conversation the kiosk is running, and the user never had to flip between sections of a 400-line document or guess which step they were on.\n\nA traditional INSTALL.md makes all of this serial: read sections 1 through 8, run the commands in order, and hope you don't need to come back. The skills version is stateful — each phase verifies the world before declaring itself done, and the coordinator re-probes between phases instead of trusting the user's memory.\n\n## Not just install — operations too\n\nThree more skills handle the long tail after install: `nowplaying-troubleshoot`, `nowplaying-diagnose`, and `nowplaying-status`.\n\n`nowplaying-troubleshoot` is what used to be a TROUBLESHOOTING.md. When the user reports a symptom — _\"the kiosk shows the clock when a record is playing\"_ — the skill maps the symptom to a failure mode and walks structured diagnostics. It runs the same `systemctl` and `journalctl` commands I'd have put at the top of TROUBLESHOOTING.md, then steps through the most-likely causes in order.\n\n`nowplaying-diagnose` is the read-only counterpart. The user asks _\"what's the orchestrator doing right now?\"_ and Claude runs the live-log filter and interprets the output line by line. The skill encodes the meaning of every log line type the orchestrator emits — _\"`recognize: method=shazam …` — Shazam returned a match; primary path\"_ — so the user doesn't have to learn the log format themselves.\n\n`nowplaying-status` is the simplest one. _\"What's playing right now?\"_ — Claude curls the orchestrator's `/api/now-playing` endpoint and reports the current track. No setup, no debugging, just a question.\n\nThese three together cover most of what a user would want from a runtime-support document. The pattern is the same as the install bundle: a focused skill per situation, activated by phrasing, with the operational knowledge encoded as content Claude reads.\n\n## What this doesn't replace\n\nThe skills only fire for users running Claude Code. Anyone else — someone evaluating the project on GitHub, reading along to see if it's worth installing — needs a real document, and the long INSTALL.md is still doing that job in this repo.\n\nThere are also cases where a skill is the wrong shape. Anything that needs to be reviewed offline (security policy, license, contributor agreement), anything that's better as a single linkable URL (an architecture overview, a reference card), and anything that doesn't fit a conversational walkthrough — none of that wants to be a skill. The skills are for the operational docs: install, troubleshoot, inspect. Reference and overview material is still better as markdown.\n\n## Source\n\nThe kiosk source is at github.com/schuettc/now-playing. The skills bundle is at .claude/skills/, with a README covering the activation pattern and editing conventions.",
  "title": "Skills Instead of Setup Docs",
  "updatedAt": "2026-06-06T02:00:23.880Z"
}