Changelog
What was decided in the specifications, and when, newest first. The specifications say only the rules; this is where their history lives. Core stays 1.0 (draft) and the modules keep their versions until they are final, so everything below is part of those versions.
2026-10-27: what real tools need
A review walked the tools on deejay.tools, the DJ library converters and three demo apps built on a home's Access API through the specification. What it changed:
Core
- Items gain
note(the person's own text),composers,album_artists(display text next toalbum),release_typeon releases (album,single,ep,compilation, an open list), and the read-onlyplay_countandlast_played_at, which a home derives from listens. keyis written in ID3v2.4TKEYnotation (Am,F#,Dbm,o); enharmonic spellings are equal. Camelot and Open Key are for display.- Identifiers gain
iswc(T3452468001). filegainsaudio_hashandfingerprint(both{ "algorithm", "value" },fingerprintmoved from the DJ module). The same hash in one source is a moved file; on two sources, one item. A shared fingerprint is a suggestion.- Lists gain folders (
folder,parent,position),color, andfilterfor smart lists. A colour is a tag: an unordered list with acolor. Entries gainnote. Rolehistoryfor history playlists. No core listkind, noversion(mix name) field, no relations between tracks:iswcand catalogs cover "other versions of this song". - Ordered lists may repeat an item where the list's platform allows it.
- The platform registry gives each platform's
refform, and whether it is global or personal. A Bandcamprefis Bandcamp's numeric track or album id. - Combining adds
audio_hashas a firm match,fingerprintas a suggestion, and label plus catalogue number for releases, except represses (different copies on the same source). Lists'parentandfilterreferences follow the lists they name. - Listening history is kept by the home in ListenBrainz's format, apart from the collection.
- A home's namespace keeps everything about the collection (hidden tracks and lists too), in files and through Access alike; only the state of changes not yet sent to a source stays inside the home. Exporting and letting a new home read through Access carry the same data.
- An app may ask for what it sends to be held, and a held item keeps everything sent.
extis for what the person would miss if they left the app, never an app's cache. A guide to where a property goes (nowhere, an app's namespace, a module's, the core). A future Credits module will use DDEX's role names.- No vendor in normative text: a home's namespace is
com.example.homein examples. - A link on a registered platform (or a source with a descriptor) is a copy, on a source the home
adds if the person has none: the platform's ids are stable and shared, so the copy can be played
and matches exactly when the person later buys or saves it there. A shop page has no shared id, so
its link goes in
via. The source descriptor rule is unchanged.
Access
- Entries of ordered lists are addressed by position, with a list
version(a member andETag, never in files); a staleversionis409 version_conflict. Moving an entry is one request. Entrynotecan be changed. A repeat an ordered list's platform refuses is reported inunchanged, like every idempotent write, not asalready. GET /lists/cananswerscanfor every list in one request; every response carrying a list carriescan;/changesreports a list whosecanchanged. Smart lists answeradd: false./megainsuser.name.data_bytescovers only an app's own namespace, per app per record; module data has each module's own minimum (DJ: 1 MB per copy).- Who may write a namespace: the home's own, the home only; a module's, any app with the scope; an
app's own, that app (by its
client_iddomain, or the first app to write it). Everyone reads everything, and the person's own edits are never restricted.403 namespace_not_yours. - Apps may write
ratingas the person's value. Measured values go on the copy they came from. - Listens:
POST /listensin ListenBrainz's submit format,GET /listens, scopeslistens:writeandlistens:read. - Apps may be known by an address they own (OAuth Client ID Metadata Documents), alongside registered clients.
POST /items?hold=trueasks for the item to be held. An item needs a link or identifiers. A link on a registered platform is a copy (the home adds the source if needed); a shop's link goes invia.- Webhooks are left to each home. Device sign-in waits until an app without a web address needs it.
DJ
- DJ data lives on the copy whose audio was measured, file or stream.
- One timing basis: milliseconds from the first real sample, after the gapless header's delay and padding.
- Cue kinds
hot,memory,loop,fade_in,fade_out,load, an open list. - Compact beat grids,
[at_ms, bpm, beat_in_bar], markers only where something changes. The grid'sbpmplaces beats; the item's is for display. analysisgainsenergy,audio(previeworfull),bpmandkey.- Waveforms are never stored. Stems separated on the fly are the app's; stem files are file copies.
Other modules
- Feeds: a people's feed carries entry notes and never item notes. Recommendations are a feed.
- Folder: an item's body is its core
note, a list's is itsdescription; lists gainfolder,position,colorand a derivedparentlink;iswc,composers,album_artistsandrelease_typeare properties. - Catalog and Commerce: resolvers answer by copy as well as by identifier, for the platforms asked.
- Delivery: files on the person's own devices are out of scope.
2026-10-20
- Core. Ids are local, and collections combine by contents: sources by platform and stable
account(newaccount_namefor display;localsources never match on their own), copies by source andref, items by a shared copy, then MusicBrainz, ISRC or UPC, then title and artists as a suggestion only. Conflicts are settled by the person, never by timestamps. - A collection may be all releases. Copies gain
position(vinyl sides), and tracks on sources without track ids use<release ref>/<position>. Physical copies gainformat,format_details,conditionandlocation; releases gaincatalog_numberandcountry. - Ownership is a claim, and the person's correction wins (provenance origin
user). New rolewanted. Roles stay few; apps use namespaced values of their own (com.example.app/borrowed), shown as the nearest core value. - Dates: how item, copy and entry
added_atrelate;updated_atremoved (kept as unknown data from older files); provenance on copies and entries, with new originsestimatedandinferred. - The header carries no sync state;
countssplitsrecordingsandreleases; optional collectionname. - New modules: Share (sending music to someone) and Collector (a copy's history).
- Access. The cursor travels in the
OMC-Cursorheader of/collection, never in the file;canper app and list, never stored; lookups by content;POST /import; add-only apps (library:add); views by record type. DJ gains mixes. - Feeds. Feeds are JSON Feed 1.1 (and optionally Atom or RSS) with OMC records in their entries; push is WebSub; homes may publish a person's list as a feed.
- Folder.
omcandidreplaceomc_typeandomc_id(still read); notes made by hand (no id, a template,shelf); the collection'snamenames the folder.
2026-10-19
- Homes, apps and sources: a collection has exactly one home, apps change it in place within a view
the person gives each connection, and sources are places with their own copy that the home syncs
with. Connections, views, sync positions, change attribution and id maps are the home's state and
never appear in records or files.
viais written once, for people, on items and lists. - How core fields and extensions relate: core stands alone, an extension refines and never contradicts, core wins, a missing extension is derived from core. A host ignores writes to its own namespace instead of refusing them.
- List entries carry an optional copy
refon lists that live on a source, and an unordered list holds an item once per copy there. Found rebuilding real playlists from a home's export: Spotify Liked Songs held 38 pairs of copies the home knew as one recording each. - From a real collection of 7,567 items and 411 lists:
titlemay be empty (platforms return tracks they no longer serve without one), and a local file'srefmust at least replace the home directory with~when the producer doesn't know the source folder. The Folder module round-trips that whole collection record for record. - Access. Telling an app's own writes apart, with
byon change entries and a cursor on write responses. - Folder. Readers accept standard Markdown links and every Obsidian link style. The layout is free, so a folder per artist or letter needs no specifying. Tested on a 7,991-record collection rearranged by artist (354 repeated file names) and as a pile of randomly named notes.
2026-10-18
Found while building the reference validator, the examples and the first Access implementation:
- Lists on a source get an optional
ref(the source's own list id).savedallows one favourites list per kind of item (Spotify Liked Songs and Saved Albums). Ownership values are an open list like roles and kinds. - A host's own
extnamespace is the host's and read-only to apps; app data is everything that isn't the host's own field. PATCH is an RFC 7396 merge patch, host fields must be sent unchanged (422 field_not_writable), and host-managed dates are ignored. - A host may refuse data it can't keep (size, copies on sources it can't hold, entry data) with an error, never silently.
- The export header is per export; keeping unknown data applies to records.
- The platform registry gains
itunesandshelf. - Access scopes
library:read,lists:read,lists:write,library:write.