From 0fe13a9d5f7cb92e4c50d9c64ee275bd027e37e2 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sun, 17 May 2026 18:57:54 +0200 Subject: [PATCH] docs: track CLAUDE.md as the repo onboarding contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings the file into version control so it survives a laptop switch. Aim: a self-contained briefing that doesn't rely on per-machine auto-memory or local scratch files. Notable content: - "How a new session should start" — concrete read order - "Load-bearing gotchas" — the ETag header literal must stay capitalised; rewriting to Go's canonical "Etag" breaks real speakers (encoded in handlers_etag_test.go as caseSensitiveETag/normalizedEtag) - "What never goes into this repo" — explicit list of data classes that must never be committed (real IPs, MACs, account IDs, Bose binaries, captures), since the repo is public - Pre-push quality gate codified: golangci-lint clean before git push - Trademark disclaimer for "SoundTouch" / "Bose" Drops the stale ".impeccable.md" reference (no such file in the tree) and trims the destructive-ops safety prose to the rules that actually apply during a session. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6342503 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,186 @@ +# CLAUDE.md + +Entry point for any Claude Code (or human) session working on this +repository. Read it before touching code. + +## What this project is + +Go library and toolset for controlling Bose SoundTouch speakers via +the local network API, plus a local cloud-service emulator. Bose +discontinued the SoundTouch cloud — this project keeps existing +speakers usable without it. + +**Module:** `github.com/gesellix/bose-soundtouch` + +Two binaries: + +- `soundtouch-cli` — command-line control of one or more speakers + (status, play, presets, groups, migration, …). +- `soundtouch-service` — local replacement for `streaming.bose.com` + and the `bmx` services, default port `8000`. + +Per-session pickup notes live in two local files at the repo root: + +- `NEXT.md` — current "pick up here" log of open items. +- `DONE.md` — archive of recently resolved items. + +Both are `.gitignore`d on purpose; they don't follow the repo. + +## How a new session should start + +1. Read this file. +2. Read `NEXT.md` if it's present — that's where running context lives. +3. Skim `README.md` for the user-facing pitch. +4. Skim `docs/` for the area you're touching. Long-form notes + (analysis, guides, troubleshooting) live there, not in the code. +5. Run `make check` once to confirm the local environment compiles, + vets, and tests cleanly. + +## Build, test, run + +```bash +# Build +make build # CLI + service for current platform +make build-all # Cross-platform builds (Linux, macOS, Windows) +make install # Install to $GOPATH/bin + +# Quality +make test # Unit tests +make test-coverage # Coverage reports +make check # fmt + vet + test +make lint # golangci-lint + +# Development +make dev-service # Run local service on port 8000 +make dev-discover # Discover devices on the LAN +make dev-info HOST= # Get device info + +# Docker +make docker-build +make docker-run-host +``` + +**Pre-push quality gate:** `make lint` (golangci-lint) must be clean +before `git push`. CI runs it on every PR; running it locally first +saves a round-trip. `make check` covers `lint` is its own target — +combine as needed. + +## Project structure + +``` +cmd/ + soundtouch-cli/ # CLI tool for device control + soundtouch-service/ # Local cloud service emulator + soundtouch-web/ # Web UI (TuneIn browser, device control) + soundtouch-backup/ # On-device backup helper + example-*/ # Usage examples +pkg/ + client/ # HTTP + WebSocket client for the SoundTouch Web API + models/ # XML/JSON data structures + discovery/ # Device discovery (mDNS + UPnP, unified interface) + config/ # Configuration management + service/ + bmx/ # Bose Media eXchange service emulation + marge/ # Device-management service emulation + handlers/ # HTTP request handlers + proxy/ # HTTP proxy with request recording + datastore/ # Persistent device data storage + certmanager/ # TLS certificate management + setup/ # Device migration and configuration + spotify/ # Spotify integration + stockholm/ # Optional Stockholm frontend bridge +examples/ # Feature demonstration programs +docs/ # Long-form analysis, guides, troubleshooting +.junie/ # Communication-style guidelines (see below) +``` + +## Key technologies + +- **Go 1.26+** +- **chi v5** — HTTP router +- **gorilla/websocket** — WebSocket for real-time events +- **hashicorp/mdns** — mDNS device discovery +- **miekg/dns** — DNS operations and a custom DNS server +- **urfave/cli/v2** — CLI framework + +## Architecture notes + +- `pkg/client` is the core library for device API calls (HTTP + WebSocket). +- `pkg/service` is the local cloud replacement; routes wire to the + handlers in `pkg/service/handlers/` via chi middleware. +- Discovery supports both mDNS and UPnP/SSDP behind a unified interface. +- The SoundTouch Web API uses XML on the wire; internal service-to-service + messages use JSON. +- Tests cover unit, integration, parity (local vs. official Bose API + recordings), and regression. Reproducer tests should be refactored + into permanent regression or documentation tests rather than deleted. + +## Load-bearing gotchas + +### `ETag` header literal must stay capitalised + +Bose speakers emit the response header with exact capitalisation +`ETag`. Go's `http.Header.Set` canonicalises to `Etag` (lowercase `t`). +Real speakers parse strictly — `Etag` is rejected. The codebase +deliberately bypasses the canonicalisation path; do **not** rewrite +the string literal `"ETag"` to `"Etag"` anywhere in `pkg/service/handlers/` +or in tests. + +The contrast is encoded in two named constants in +`pkg/service/handlers/handlers_etag_test.go`: + +```go +const normalizedEtag = "Etag" // what http.Header.Set produces +const caseSensitiveETag = "ETag" // what the speaker actually expects +``` + +Linter suppressions on the canonical-header check live alongside the +test code. Static-analysis warnings about `"ETag"` are expected; +don't "fix" them. + +### Destructive git or filesystem actions need explicit confirmation + +`git reset --hard`, `git checkout` that would overwrite local changes, +`git clean -fd`, `rm -rf` on non-build paths, `git stash drop` — all +should be proposed in writing with their consequences before running, +unless the user has already authorised that specific action in this +session. Prefer reversible alternatives (`git stash` over +`git reset --hard`). + +## What never goes into this repo + +This repository is public. The following must never be committed: + +- **Real LAN IPs** of personal networks. Use RFC-5737 documentation + ranges in examples and fixtures: `192.0.2.0/24`, `198.51.100.0/24`, + `203.0.113.0/24`. +- **Real MAC addresses** or speaker device IDs from anyone's actual + hardware. Use `AA:BB:CC:DD:EE:FF` or `DEVICEID01` style placeholders. +- **Bose account IDs**, serial numbers, or tokens belonging to anyone + other than the committer's own test devices — and even those should + be sanitised before publication when feasible. +- **Bose firmware binaries, NAND dumps, or decompiled Bose code.** +- **Wi-Fi SSIDs or credentials**, captured or otherwise. +- **Network captures, traces, or logs** that include data from + accounts or devices other than your own test hardware. +- **Personal identifiers**: real names of speakers ("LivingRoom", + custom device names), private email addresses, household member + names visible in source IDs. + +If you spot any of the above already in the tree, treat it as a +sanitisation task: stop, flag it to the maintainer, propose a +remediation commit before continuing. + +## Disclaimers + +"SoundTouch" and "Bose" are registered trademarks of Bose Corporation. +This project is an unofficial, community-built effort, not affiliated +with, endorsed by, or authorised by Bose. + +## Communication style + +When working with a human user in this repo, follow the brief direct- +answer norms in [.junie/guidelines.md](.junie/guidelines.md): +prioritise direct answers, avoid reverting to earlier task context +when the user asks something out-of-scope, no assumptions in place of +real information.