Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# 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
controls, shaped after MIDI-CI Property Exchange.
- 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.
Expand All @@ -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

Expand All @@ -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.
11 changes: 4 additions & 7 deletions lib/appkit/ROADMAP.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion lib/sayso/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
82 changes: 17 additions & 65 deletions lib/sayso/ROADMAP.md
Original file line number Diff line number Diff line change
@@ -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.
Loading