From 294051381471ec560a2cb56c03346da5510e2d27 Mon Sep 17 00:00:00 2001 From: Brad Barnett <127794626+bdbarnett@users.noreply.github.com> Date: Mon, 9 Nov 2026 23:08:45 -0600 Subject: [PATCH] Roadmap: every app and library, shipped items out The roadmap opened by saying three applications live here; there are over twenty. It now opens with what it covers, names the sound module's library, links Ostinato's and Synth Station's roadmaps beside appkit's, controlkit's and sayso's, and says Vamp already plays a USB-host keyboard (recording is what's left). appkit is already in the mip index, so its publishing bullet is now just the pip package, and the front-panel bullet is cut to three lines. sayso's roadmap was mostly a list of what's implemented, plus decisions and a dated note; the README already covers what works, so the roadmap keeps only the planned items. Docs only. --- ROADMAP.md | 24 ++++++++----- lib/appkit/ROADMAP.md | 11 +++--- lib/sayso/README.md | 2 +- lib/sayso/ROADMAP.md | 82 +++++++++---------------------------------- 4 files changed, 37 insertions(+), 82 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index a181d8c..c4a4046 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,12 +1,13 @@ # Roadmap -Three applications live here: a sound module, Ostinato the sequencer, and -Vamp, which plays Ostinato's songs on a board. The first is a sound module: a box that plays whatever a DAW, -sequencer or keyboard sends it over MIDI, the way a hardware tone module does. -It grows one part at a time, on the desktop interpreters first. +What's planned for the apps and libraries here. An app or library with a +longer list keeps its own roadmap beside its code, linked below. ## Sound module +The sound module (`lib/soundmodule`) plays whatever a DAW, sequencer or +keyboard sends it over MIDI, the way a hardware tone module does. + - Patch and macro names that DAWs can read, from the catalog files audioinstruments publishes with each release. - A SysEx request that returns the module's instruments, patches, effects and @@ -14,13 +15,12 @@ It grows one part at a time, on the desktop interpreters first. - On an ESP32-P4 as a USB MIDI device, with 24 voices at 48 kHz stereo. - Over BLE MIDI. - Reverb and chorus as true sends per channel, once the sampler can mix its - voices into a send bus. Today CC91 and CC93 set one master level, the mean - of the channels in use. + voices into a send bus. Today CC91 and CC93 set one master level. ## Vamp -- A MIDI keyboard such as the DMK-25 on the board's USB host port, playing - and recording into the selected track. +- Recording from a MIDI keyboard such as the DMK-25 on the board's USB host + port into the selected track. It already plays from one. - Undo in the window that knows about edits made on other panels. - The timed voice pool that schedules notes ahead of the audio moving into audioinstruments, once a second player needs it. @@ -29,6 +29,11 @@ It grows one part at a time, on the desktop interpreters first. - A published copy of the app on the web, so it installs without running a local server. +- The rest is in [Ostinato's roadmap](apps/ostinato/ROADMAP.md). + +## Synth Station + +- [Synth Station's roadmap](apps/synthstation/ROADMAP.md). ## Stompbox @@ -42,7 +47,8 @@ It grows one part at a time, on the desktop interpreters first. ## Libraries -- sayso's own list is in [lib/sayso/ROADMAP.md](lib/sayso/ROADMAP.md). - Ship songmodel's front panel page to boards. The wheel carries `page.html`, but a `mip` install or a frozen build has only the Python, so today Vamp copies the page across itself. +- [appkit](lib/appkit/ROADMAP.md), [controlkit](lib/controlkit/ROADMAP.md) + and [sayso](lib/sayso/ROADMAP.md) keep their own roadmaps. diff --git a/lib/appkit/ROADMAP.md b/lib/appkit/ROADMAP.md index 04f2da3..1a3589e 100644 --- a/lib/appkit/ROADMAP.md +++ b/lib/appkit/ROADMAP.md @@ -1,9 +1,6 @@ # Roadmap -- **Publishing.** appkit in the mip index with the other packages here, and - later a pip package. -- **A model for a front panel.** An app can expose a model (describe, apply, - telemetry, command) and the launcher exposes one too (the app list, which - app is up, switch), so hmilink can serve them to a phone, a browser or a - second screen. Apps without a model pay nothing. Model-first becomes the - recommended way to write an app in these docs, not a requirement. +- **A pip package.** appkit is already in the mip index. +- **A model for a front panel.** An app and the launcher expose a model + (describe, apply, telemetry, command), so hmilink can serve them to a phone, + a browser or a second screen. Apps without a model pay nothing. diff --git a/lib/sayso/README.md b/lib/sayso/README.md index b136b4d..1911c90 100644 --- a/lib/sayso/README.md +++ b/lib/sayso/README.md @@ -362,5 +362,5 @@ Some playback controls require Spotify Premium and an active device. for the current user and `playlist.items` for playlist entries. See [`PORTABILITY.md`](PORTABILITY.md) for details. -See [`ROADMAP.md`](ROADMAP.md) for implemented areas, next steps, and open design questions. +See [`ROADMAP.md`](ROADMAP.md) for what's planned. See `PORTABILITY.md` for CPython, MicroPython, and CircuitPython boundary notes. diff --git a/lib/sayso/ROADMAP.md b/lib/sayso/ROADMAP.md index 8b8d8b2..2353047 100644 --- a/lib/sayso/ROADMAP.md +++ b/lib/sayso/ROADMAP.md @@ -1,65 +1,17 @@ -# sayso Roadmap - -This project currently has a lightweight Spotify Web API object layer, auth helpers, -transport helpers, read methods, selected write methods, examples, and live tests. - -## Implemented - -- Spec-driven Spotify object classes from `SPOTIFY_OBJECT_SPECS` -- Nested object wrapping for object, object list, typed object, and page fields -- Lazy hydration from simplified objects to full objects (`_get` / `_peek`) -- `Page.__getitem__`, `CursorPaging`, and page-backed `object_by_key` properties -- `Artist.albums` and `Playlist.items` wired to client page methods -- Discovery scripts (`sayso_*_discovery.py`) for object-graph walkthroughs -- Offline object-layer unit tests in [`tests/sayso/test_objects.py`](../../tests/sayso/test_objects.py) -- February 2026 Dev Mode API notes in [`PORTABILITY.md`](PORTABILITY.md) -- `SpotifyObject.__str__()` pretty-prints raw object data for `print()` -- Client Credentials auth -- Authorization Code auth helpers consolidated in `sayso.auth` -- PKCE verifier/challenge helpers -- `TokenCache` for access/refresh token persistence -- `sayso.local.json` config file for app credentials -- `examples/write_examples.json` for optional write-example settings -- `SpotifyClient()` config-file bootstrap from `sayso.local.json` -- Automatic browser OAuth on first `SpotifyClient()` call when needed -- OAuth error translation into `SpotifyAuthError` -- CPython interactive OAuth flow in `sayso.auth` -- Manual callback URL parsing and lower-level OAuth examples -- Automatic HTTP backend selection (`requests` or CircuitPython `adafruit_requests`) -- JSON and raw-body write transports; non-JSON 2xx responses treated as success -- Read methods for major Spotify object families, paging, search, playback, library, and user endpoints -- Write methods for saved-library items, follows, playlists, and playback controls -- `SnapshotResult` for playlist mutation responses -- Draft schema-to-object-spec generator script -- Endpoint coverage report that parses `lib/sayso/client.py` and compares it to OpenAPI (`--map` prints path-to-method names) -- First-class client methods for all OpenAPI paths currently reported by Spotify's schema -- Example scripts for client credentials, OAuth, user-library usage, playback controls, and guarded write calls -- Live integration tests against the Spotify Web API (playlists, saved paging, artist albums, recently played) -- 401 retry after token refresh in `SpotifyClient` request helpers -- Offline client retry tests in [`tests/sayso/test_client.py`](../../tests/sayso/test_client.py) -- Lazy `Playlist.items` via `LazyPageRef` (metadata without fetch; load on access) -- `HydrationError` for contextual object-layer fetch failures -- MicroPython on Linux validated with discovery scripts and the Spotify app -- MicroPython on an ESP32-P4 board validated with the Spotify app -- The Spotify LVGL MicroPython app, now in the [apps repo](https://github.com/PyDevices/apps/tree/main/apps/spotify) -- The Spotify app follows a local earful speaker through its state events (`Device.events()`): while the board is Spotify's active device the screen shows each pause, skip and seek as earful reports it, and the Web API is only asked when playback moves elsewhere -- `transport.get_bytes()` for binary downloads (for example cover art) -- Socket-based OAuth callback fallback for MicroPython -- Offline transport tests in [`tests/sayso/test_transport.py`](../../tests/sayso/test_transport.py) - -## Good Next Steps - -- Validate CircuitPython on embedded hardware; record the result in `PORTABILITY.md`. -- Keep the schema generator aligned with hand-curated object_by_key overrides and February 2026 endpoint removals. -- Optionally deprecate removed Dev Mode client methods (`user()`, legacy `playlist_tracks()`) in docstrings and endpoint coverage output. - -## Resolved Decisions - -- **Global client** — keep `set_client()` / `SpotifyClient(auto_set=True)`; objects do not carry a per-instance client. -- **Token storage** — keep `TokenCache` and default `tokens.json` paths as they are. -- **Examples** — keep `examples/` as source-only in the repo for now (no packaging or docs migration yet). - -## Open Design Questions - -- Are there additional non-playlist mutation response shapes worth modeling? -- Should write methods validate Spotify limits such as max IDs per request, or leave that to API errors? +# sayso roadmap + +What's working today is in the [README](README.md) and +[PORTABILITY.md](PORTABILITY.md). + +- **CircuitPython on a board.** sayso runs on a CircuitPython board as it + does on MicroPython, with the result recorded in `PORTABILITY.md`. +- **Removed endpoints marked.** Client methods Spotify no longer serves to + Dev Mode apps, such as `user()` and the old `playlist_tracks()`, say so in + their docstrings and in the endpoint coverage report. +- **Generated specs that match the hand-curated ones.** The schema generator + keeps the `object_by_key` overrides and Spotify's endpoint removals. +- **More mutation results.** Write methods return a result object, as + playlist changes return `SnapshotResult`, wherever Spotify's response is + worth having. +- **Spotify's limits checked before a request,** such as the most IDs one + request takes, so a write fails with a clear error instead of the API's.