This specification is for developers creating or adapting a reader. It defines what a client can mean by Compatible Aède against the interfaces available today. It is a client integration contract, not a certification programme or a promise that every CLI feature has an HTTP equivalent.
MUST is required for the declared profile. SHOULD is recommended; document a deliberate exception. MAY is optional. The requirements apply to behaviour, including failure paths, rather than to a particular programming language, UI or audio library. The linked route and transport documents remain authoritative for field names, limits and error codes.
Declare a profile#
| Profile | Required scope | What the claim means |
|---|---|---|
| Aède Catalog v1 | Common rules, native authentication and catalog rules. | A reader of the current native graph API, including catalog refresh and attributed facts. It does not claim audio playback. |
| Aède Native Player v1 | Every Catalog v1 requirement, native personal data and native PCM playback requirements. | A player using Aède's current server-side audio processing and consumption-based history, with the current native personal features. This is the complete native client profile defined here. |
| Aède Subsonic | Common rules where relevant, adapter authentication and the supported Subsonic operations actually declared by the client. | A client of the compatibility adapter. Declare browsing, original audio, artwork and personal features separately; this is not a claim of complete Subsonic/OpenSubsonic coverage or native graph/DSP support. |
A client MAY combine profiles, for example Native Player v1 with adapter artwork and static-playlist views. It MUST keep each interface's credentials, identifiers, audio processing and history semantics separate. There is no public native-reference ↔ adapter-ID resolution route; independent views are possible, but do not promise automatic entity matching or reconstruct opaque IDs from implementation details. A Subsonic-only integration must be described as such rather than as Native Player v1.
Record the client version, tested Aède version, API/profile version, tested platforms/devices, optional features and known limitations in the client's documentation. Distinguish automated protocol verification from playback actually tested on a device. There is no client-feature negotiation endpoint for native v1; GET /api/v1/status reports api_version, not a list of enabled client capabilities. An unavailable optional feature must stay unavailable in the UI.
For a hypothetical integration, a declaration could read: “Example Player version X supports Aède Native Player v1 against Aède version Y on macOS, with adapter artwork and private static playlists. This client does not implement the optional interactive seeking/checkpoint extension. Protocol checks pass; device playback was tested on output Z.” Fill this example with the actual client's measured results.
Common requirements#
| ID | Requirement |
|---|---|
| C1 | The client MUST use documented interfaces. It MUST NOT edit Aède's JSON stores, remove its lock, write music tags or replace source audio/artwork as a side effect of browsing or playback. Store format versions are independent of HTTP versions. |
| C2 | The client MUST treat names, tags, notes and external text as untrusted content: render text literally, escape markup when needed and never execute it as HTML, shell instructions or a file-opening command. |
| C3 | The client MUST scope catalog caches by configured server connection and personal caches by authenticated account. Native login returns account.id; adapter clients must separate account/key configurations. On sign-out or account/server change, stop playback and detach private views and cached personal data. Native v1 exposes no installation UUID: resetting/replacing a connection configuration must invalidate its cache rather than assume that an address always represents the same data. |
| C4 | The client MUST expose a failed request as a failure. It MUST NOT replace an error with an empty library, fabricate a missing fact or silently ignore a refused setting. Retry reads with bounded backoff; honor Retry-After where supplied. Do not blindly retry mutations after an uncertain response. |
| C5 | The client MUST keep credentials out of generated diagnostics, shared exports and telemetry, and mask secret fields by default. Native bearer tokens MUST NOT appear in URLs. Adapter credentials require query/form transport, so redact complete requests accordingly. Persistent client secrets SHOULD use the OS credential store; transient native sessions should remain in memory. |
| C6 | Remote access MUST use HTTPS/WSS with normal certificate and hostname verification. Preserve the configured authority and port. Native clients MAY omit Origin; a supplied browser origin MUST satisfy the documented same-origin boundary. Do not bypass Host/Origin checks, trust forwarded headers or disable TLS validation to make a connection work. |
| C7 | Catalog navigation MUST NOT trigger external metadata lookups without an explicit user-requested feature. Local facts, external claims and derived values MUST remain distinguishable, with attribution retained for any external content the client displays. |
See HTTP semantics, remote access, the API reference and the complete route reference.
Native authentication and account scope#
| ID | Requirement |
|---|---|
| A1 | With accounts configured, the client MUST sign in through POST /api/auth/v1/session and send exactly one Authorization: Bearer <session> header on native requests and WebSocket upgrades. Adapter API keys and the legacy installation token are not substitutes for an account session on /api/me/v1. |
| A2 | The client MUST handle absolute expiry, inactivity expiry, revocation and server restart. On authentication failure (401 unauthorized or playback authentication_expired), close protected live streams, remove the unusable session and ask for authentication again. Other failures, such as invalid settings or busy workers, must not be mistaken for session expiry. A reconnect MUST NOT silently create a new playback/listening event. |
| A3 | Personal operations MUST use /api/me/v1 and the server-derived owner. The client MUST NOT supply another owner or use /api/admin/v1 to obtain another account's personal view. Administrator installation work is an optional, explicitly separate local feature. |
| A4 | An auditor MUST have a read-only client experience: catalog and their own personal reads are allowed; playback and personal mutations are unavailable. The client MUST handle server-side 403 even if a previously cached role allowed an action. |
| A5 | Sign-out MUST call session revocation when the server is reachable, stop protected playback and clear the local session even if the connection fails. Password changes invalidate sessions; do not keep presenting the old session as usable. |
The account contract defines login bodies, roles, expiry, throttling and password changes. Catalog-only clients MAY support anonymous loopback HTTP when the server permits it; they MUST also support the account-backed case before claiming Catalog v1. HTTPS always requires accounts.
A standard browser WebSocket cannot set this bearer header. The current native playback contract therefore requires a client transport that can set it. A website must not substitute a query token or cookie and claim compatibility: browser authentication/transport needs its own future contract.
Native catalog, identity and synchronization#
| ID | Requirement |
|---|---|
| G1 | The client MUST preserve the entities and links exposed by native v1: a release is a local edition, a recording is a performance, a track places that performance in an edition, and a work is a composition. It MUST keep different same-title editions/performances distinct and follow work, recording, release-group and artist links where present. An album hierarchy MAY be a view; it must not replace identity. |
| G2 | The client MUST copy reference tokens as received and URL-encode them when used as parameters. Do not derive IDs from dense catalog positions, display names, MBIDs alone or a parsed filesystem path. References belong to this catalog; track/file movement can change them. A missing current reference MUST be surfaced and refreshed, never reassigned to an arbitrary same-name item. |
| G3 | The client MUST use documented pagination and selector rules, including complete detail arrays versus paginated lists. For a consistent multi-page load, compare scanned_at between pages and restart when it changes. Native v1 offers no snapshot across requests; do not claim an atomic catalog/source snapshot. |
| G4 | The client MUST distinguish unknown (null or explicit unknown status), absent relationships (empty arrays), an empty successful page and a failed request. Name ambiguity (409 ambiguous_entity) requires choosing a returned reference, not silently selecting the first candidate. |
| G5 | The client MUST preserve the meaning of local facts and available attributed origins/analyses, including confidence, trust, stale state and source/version fields. A stale analysis must not be presented as a current measurement; a derived country abbreviation must not become an official ISO code. Do not infer a composer's role from album-artist membership. |
| G6 | The client MUST ignore additive response fields and recover its catalog view after replacement/removal and reconnect. It SHOULD subscribe to /api/v1/events for prompt refresh; bounded polling is an acceptable alternative. Events are best effort notifications, not graph patches or a durable replay log. |
Use catalog routes, graph navigation, search, inspection and events. The native API exposes selected graph views, not every core credit/relation/source-review operation. Do not invent a route for the remainder.
Local path and cover_path fields describe server-side files; they are not download URLs or permission to access the client's filesystem. Native v1 has no binary artwork route. A combined client MAY use the adapter's advertised cover IDs and artwork endpoint, under its separate authentication contract.
Native personal features#
Native Player v1 MUST provide an owner-private view of the current personal features, using the shapes and limits defined there:
| ID | Requirement |
|---|---|
| P1 | Favourites, ratings, notes and user tags MUST be read and updated through /api/me/v1/annotation. Preserve fields omitted by an edit; explicit removal and omitted values differ. Native ratings are 1–5 or null to remove, whereas adapter setRating uses 0 for removal. |
| P2 | The client MUST show the owner's native history with measured/declarative fields as returned, and distinguish the retained event log from all-time counts. Adapter scrobbles contribute to counts but are not native Play rows; an ephemeral now-playing report is neither. |
| P3 | Saved query collections MUST remain expressions evaluated for the current owner. They MUST NOT be relabelled as ordered static playlists. Native collection edits/deletion must use their documented methods and report failure without claiming a successful save. |
| P4 | The client MUST handle busy stores/workers without replacing server data from an obsolete cache. Optimistic UI edits must reconcile with the returned result or visibly revert/report an uncertain outcome. Native v1 provides no client merge/revision token for competing editors. |
Native v1 does not expose static-playlist persistence. A combined client MAY add private ordered playlists through the adapter; repeated track entries and their order must survive a round trip. A missing track must not silently disappear from a saved playlist. Native relation annotations and source-review decisions remain CLI-only.
Native PCM playback and accurate history#
The PCM playback v1 contract is authoritative for wire messages and deadlines. Native Player v1 MUST implement the complete start → format → audio → EOF → recorded/close lifecycle, not just receive a WebSocket's bytes. The finite-queue and interactive extensions are optional for this profile; clients implementing them MUST also follow their boundaries, format changes and per-occurrence history rules. Declaring interactive seek/edit/resume requires the additional checks below; it does not change the baseline single-track profile.
| ID | Requirement |
|---|---|
| L1 | Open /api/me/v1/playback with the account session, then start exactly one current catalogued track. Validate and display the requested normalization, sample-rate and tone settings. Wait for format before interpreting audio; it describes the transmitted format, which may differ from the source file. |
| L2 | Decode binary messages as complete interleaved f32le frames with the advertised channel count/rate. Preserve order and channel alignment. Count frames, not bytes or individual channel samples; binary message boundaries are not musical boundaries. |
| L3 | Maintain a bounded output queue and send nondecreasing cumulative ack.frames only for frames the output has actually consumed, never exceeding received frames. Socket receipt or device-queue submission is not consumption. Discarded/skipped frames MUST NOT be acknowledged. If device conversion changes the rate, map consumed output back to transmitted input frames rather than sending the device's frame count. Equal repeated acknowledgements are permitted but do not count as progress. |
| L4 | Respect the acknowledgement window and consumption deadline, including pause, device failure and slow output. Repeated acknowledgements/pings do not represent progress. A long pause can end the playback socket; reconnect must be explicit. Seeking and checkpoint resume require the interactive extension rather than invented commands in the original single-track mode. |
| L5 | At EOF, consume the remaining PCM, including a converter tail, acknowledge the final transmitted frame count and wait for the recorded confirmation before claiming history was saved. Close/failure may produce an incomplete listen; revocation or changed source can prevent publication. An uncertain confirmation is not permission to submit the same listen again. |
| L6 | The client MUST NOT also POST native history or send an adapter scrobble for that same native socket listen. Aède already records at most one acknowledged Play per occurrence, including separate repeated queue entries. Client acknowledgements are declarations of consumption, not proof that a human heard the sound. |
| L7 | The client MUST make extra client-side normalization/EQ/resampling explicit and avoid applying the same chosen processing twice. Server PCM has already passed through the selected shared DSP/downmix/guard. It MUST NOT be labelled as the original encoded file, bit-perfect output or a guaranteed physical true-peak ceiling. |
| L8 | Stop, skip, disconnect, logout and output-device failure MUST stop the corresponding playback and discard unconsumed queued PCM. A single-track request uses one socket. A client MAY opt into finite tracks queues and MUST then handle occurrence boundaries, cumulative acknowledgements, per-occurrence confirmations and acknowledged format changes. Preserve output state across compatible joins. Seeking, future-tail editing and checkpoint resume require the optional interactive contract; physical gaplessness remains unverified. |
The client owns its output device and clock. It SHOULD acknowledge in small regular batches with enough margin for the documented deadline, keep device work bounded, and measure dropouts, latency and frame consumption on the intended hardware. Protocol tests alone do not establish listening quality or physical gapless playback.
For example, 38,400 bytes of stereo f32le at 48,000 Hz represent 38400 / (2 × 4) = 4800 frames, or 100 ms. After consuming that first batch, send {"type":"ack","frames":4800}; after consuming another identical batch, send 9600, not 4800. Use the format's rate for history accounting, not catalog duration or the device's possibly different rate. The server's playback regressions exercise full EOF, incomplete listens, invalid counters, revocation, changed sources and the rate-conversion tail; they are useful integration references, not substitutes for client tests.
Optional interactive seek, queue editing and resume#
A client declaring the interactive extension MUST request interactive: true, use stable occurrence IDs and track the current epoch/revision. It MUST attach the actual consumed counter atomically to seek, edit_queue and stop; prefetched audio is not consumption. After reset, it MUST discard old PCM from application and device buffers, reset its epoch counter, send reset_ack and wait for the new format before interpreting audio. It MUST reject stale local state rather than retry an edit against a new revision without user intent. Future-tail edits cannot remove the active occurrence or consumed prefix.
Persistent resume is optional even within interactive mode. The client MUST scope its chosen profile by server/account, request resume explicitly after reconnecting, retain the returned settings/offset and treat missing/stale checkpoints as visible errors. A checkpoint is not listening history. It MUST NOT count the preceding socket’s audio again, claim a resumed partial occurrence as a complete listen, or promise that every acknowledged frame survives a crash. Saved queue data belongs to private personal state and backups; server restart alone never starts audio.
Acceptance MUST exercise backward/forward seeking with unconsumed buffered audio, stale epochs/revisions, reset acknowledgement before new PCM, duplicate track references and retained occurrence IDs, queue add/reorder/remove, stop, profile/account isolation, logout/revocation, restart with explicit reauthentication/resume, missing/changed sources and interrupted checkpoint writes. Verify exact listened duration without skipped/discarded frames or duplicate history. Physical device buffer clearing still needs a real client/output test. See the interactive wire contract.
Optional synchronized lyrics#
Lyrics are an optional addition to the native catalog/player profiles. A client declaring this feature MUST use the separate GET /api/v1/lyrics?track=… response, preserve its complete text/source category and distinguish absent lyrics from an error. It MUST keep literal text safe in its UI, clear account-scoped cached data on logout and refresh stale sources. A non-timed document MUST remain readable without invented timing.
For synchronized display, the client MUST use its consumed per-track audio position, including pause, repeat and any seeking supported by its chosen audio transport. It MUST NOT advance from network arrival or server wall-clock time. Native finite queues require mapping cumulative consumption through occurrence boundaries; device-rate conversion must preserve that mapping. Group equal timestamps in source order, sort cues chronologically, display no cue before the first timestamp and let timed empty cues clear the previous words. LRC offset is already applied. Preserve untimed lines in the full-text view. See the clock rules.
The endpoint does not add lyrics messages to PCM or methods to the adapter. A client MUST NOT advertise a Subsonic lyrics extension based on this native feature alone. Lyrics do not create another listen or change acknowledgements/history.
Subsonic/OpenSubsonic adapter profile#
Follow the adapter guide for the current method list, limits, IDs and error meanings. Do not infer support from a protocol name or from getLicense alone.
| ID | Requirement |
|---|---|
| S1 | Use a separate revocable application key for the client. Prefer apiKey where supported; legacy u+p is allowed only with the complete application key in p and the matching account name in u. Do not send the native account password or transform the key into an unsupported MD5 token. enc: is encoding, not encryption. |
| S2 | The client SHOULD read public extension discovery where its protocol library permits it; known legacy key transport remains valid without that call. It MUST use only documented supported methods/settings, send the requested protocol version and client name, and inspect XML/JSON subsonic-response.status and errors even when HTTP is 200. Preserve repeatable list parameters and never duplicate scalar credentials/options. |
| S3 | Keep adapter opaque IDs separate from native references and refresh IDs after missing entities. Do not infer cross-interface identity from a shared display name alone. The adapter projects albums/songs/artists; it does not convey every native graph relation, analysis or source field. |
| S4 | Request original audio with supported options. The client owns decoding, device conversion and any optional DSP; the server transfers original bytes without native PCM processing. Byte-range seeking is a client operation over the encoded file, not native PCM seek. Missing codec support or refused conversion MUST be visible. |
| S5 | When artwork is enabled, use an advertised cover ID. A thumbnail request changes the response only; it MUST NOT imply that downloaded source artwork was reduced or rewritten. A client MAY cache private thumbnails under the account/server cache scope. |
| S6 | When personal features are declared, round-trip the owner's favourites/ratings and ordered private playlists without losing repetitions, or choosing another owner. Auditors may browse metadata/artwork but cannot play/download or mutate personal data. |
| S7 | A submitted scrobble MUST remain a track/time declaration with unknown played duration/completion. Streaming alone records no listen. Do not invent listened milliseconds from catalog duration or promote now-playing to history. Submissions are not idempotent, so uncertain retries must not silently double-count. |
| S8 | Unsupported sorts, queues, transcoding and optional panels MUST be unavailable or report their unsupported state. Configure a supported album sort; a fabricated scan-based created proxy is not an album-added timestamp and does not enable newest. |
An adapter-only player MAY normalize locally if clearly described; it must not claim to use Aède's native server DSP. A hybrid player must choose one history path per listen and must not translate an unmeasured adapter scrobble into a native Play with invented duration.
Acceptance matrix#
Run these checks against an isolated server/data folder and disposable accounts; never corrupt or rewrite the user's music to test error handling. Required checks apply to the declared profile and supported optional features. Keep the results with the tested client/server versions, platform and date.
| Check | Profiles | Reproducible acceptance case |
|---|---|---|
| Authentication and scope | All authenticated profiles; personal/audio cases where implemented | Use user A, user B and an auditor, and verify permitted catalog reads. Where personal/audio features exist, A's favourite/notes/history must not appear in B's personal view; refused owner selection/mutation must not save data, and auditor playback must be unavailable/refused. |
| Expiry and revocation | All authenticated profiles | Revoke a session/key while reading/playing, and restart the server. Protected access stops; native sessions require login again, while unrevoked adapter keys survive an ordinary restart. |
| Transport and secret handling | All | Check valid HTTPS plus wrong authority, untrusted certificate and foreign Origin. Refusals remain visible; no verification bypass is introduced. Inspect logs/error reports for redacted credentials. |
| Identity and graph | Native | Use two same-title editions and a recording linked to multiple tracks; navigate recording/work/release-group links and keep their identities distinct. Move a fixture file, rescan and surface the stale reference without arbitrary reassignment. |
| Pages and live changes | Native | Use more than one page, including an empty page past the end. Replace/remove/rescan the catalog between page requests and reconnect notifications; restart an inconsistent page load and handle absent catalog distinctly from an empty one. |
| Provenance and unavailable facts | Native | Show unknown origin, attributed stored origin and stale/current imported analysis separately. Missing information remains unknown; viewing it triggers no external lookup. |
| Input, ambiguity and pressure | All | Exercise ambiguous names, unsupported setting, malformed reference, worker/store saturation and an interrupted response. Display stable errors; bounded read retries do not create mutation loops. |
| Personal round trip | Native Player; adapter personal option | Edit one field without clearing the others, remove a rating, reload and switch accounts. Verify query collections separately from ordered duplicate-preserving playlists, where implemented. |
| PCM framing and device counter | Native Player | Play mono/stereo fixtures at differing source/device rates; verify complete frame alignment, transmitted-to-device consumption accounting and no acknowledgement on receipt/enqueue alone. |
| PCM complete/partial history | Native Player | Consume all EOF frames and check completed history with the acknowledged milliseconds. When the optional finite-queue extension is implemented, verify separate occurrence records including duplicates, stop in a later track and preserve earlier completed listens, and check compatible joins plus acknowledged mono/stereo changes. Consume nothing and check no event. Confirm no second history/scrobble submission. |
| PCM stalled/error paths | Native Player | Halt consumption, disconnect, fail the output device, revoke the session and change an isolated source fixture. Respect closure/errors, discard queued audio and do not claim an unconfirmed complete listen. |
| Synchronized lyrics | Native lyrics option | Use out-of-order/repeated timestamps, offset, mixed plain/timed lines and a timed blank cue. Check pre-first-cue silence, pause, forward/backward moves when supported, repeat and queue boundaries against consumed audio. Missing/stale/oversized sources remain distinct, source files are unchanged and logout clears cached text. |
| Processing and physical playback | Native Player | Compare off/track/album and tone choices, unsupported layout/rate handling and device-rate conversion. Measure actual output continuity/dropouts on the declared hardware; report unmeasured quality properties. |
| Original audio/artwork | Adapter media options | Compare downloaded original bytes with fixture hashes, exercise full/single-range/unsatisfiable-range responses and request a thumbnail. Source audio/artwork hashes remain unchanged. |
| Adapter declarations | Adapter scrobble/now-playing option | Check submission count/log without a fabricated duration, no count for now-playing, expiry and account isolation. Simulate a lost response and preserve the explicit uncertain outcome. |
| Additive compatibility | All | Add unknown response fields/event kinds in a protocol fixture and retain required-field processing. Reject unsupported requests in the UI instead of inventing a fallback success. |
Automate parser, identity, account isolation, error and frame-accounting cases. Complement them with manual UI checks and actual playback on each supported output/backend. The server's own tests establish server behaviour; they do not certify a third-party client's implementation.
Before publishing a completed Aède Native Player v1 compatibility claim, every MUST requirement in C, A, G, P and L must be covered with its corresponding acceptance cases passing. Any unverified required case limits the announcement to a provisional integration, with that case explicitly listed. For Catalog v1, apply C/A/G; for Aède Subsonic, apply the relevant C/S rules and state the supported methods/features and their validation status.
Use this release checklist alongside the detailed results:
- Declare profile, client/server versions and optional interfaces.
- Map every applicable MUST requirement to a passing check; mark any unverified claim as provisional.
- Verify owner isolation, revocation, transport validation and secret redaction.
- Verify refresh, stale identities, unknown facts and visible errors.
- Verify the chosen audio/history path without duplicate processing or duplicate listens.
- Record actual device/platform testing and the remaining limitations.
Future contracts and limits of the claim#
Standalone bookmarks, static playlists, binary artwork, prose delivery, complete credit/relation exploration and browser cookie/WebSocket authentication do not yet have native v1 contracts. Native remote seeking, future-tail editing and private checkpoint resume have the optional interactive contract above; this is not a general playlist/bookmark API. They are not hidden requirements for the current Native Player v1 profile, and existing CLI features do not authorize invented HTTP routes. Local lyrics have the optional native contract above. Some capabilities, notably artwork/static playlists/original downloads, already have a separate adapter contract.
Future native interfaces need documented semantics, permissions, errors, tests and compatibility rules before a client can declare them supported. An additive v1 route/field does not immediately become a new mandatory part of this profile; changing its mandatory scope requires revising this specification. Breaking HTTP changes belong to a new API version. Follow the roadmap and the current state, while treating the linked published contracts as the implementation target.