ModuleDraft 0.2, for comment

On this page
  1. Standards this module reuses
  2. Layout
  3. Notes
  4. Items
  5. Lists
  6. Sources
  7. Collection
  8. Module records
  9. Names written before
  10. Notes made by hand
  11. Boards (JSON Canvas)
  12. Bases
  13. Reading a folder: contents first
  14. Converting
  15. Conformance
  16. Open questions

Folder module (draft 0.2)

Status: draft for comment. Namespace: org.openmusiccollection.folder. Needs: Core 1.0.

A music collection should outlive every app that touches it. This module lays a collection out as a folder of plain-text files the person keeps wherever they like (a disk, Dropbox, iCloud, a git repository). The files are readable in any text editor, and the folder opens as an Obsidian vault as it is. It follows Steph Ango's file over app idea: apps come and go, files can last, so the files are what the person owns.

The folder and the collection file hold exactly the same collection: either can be converted into the other without losing anything, including the person's own notes and properties.

Standards this module reuses

It invents as little as possible. Where Obsidian already has an open or documented format, the folder uses it unchanged:

StandardUsed for
CommonMark MarkdownEvery note
YAML 1.2 frontmatter as Obsidian Properties: flat names; text, list, number and checkbox values; links written "[[Note]]"The fields of items, lists, sources and the collection
Obsidian wikilinks ([[Note]])References: a list's entries, an item's sources
JSON Canvas 1.0 (MIT), .canvas filesAn optional visual board for a list, such as a DJ set with its transitions
Obsidian Bases (.base, YAML)An optional ready-made table of the collection. Not normative

Obsidian Properties are flat: no nested values. So each note keeps the fields that fit as properties, and puts the rest (copies, provenance, extensions) in one fenced JSON block, still in plain text.

Layout

My Music/
├── Collection.md                      the header
├── Collection.base                    optional: a table of the collection in Obsidian
├── Items/Mira Holt - Night Drive.md   one note per recording
├── Releases/Mira Holt - Night Drive EP.md   one note per release (album, single, EP)
├── Lists/Late sets.md                 one note per list
├── Lists/Late sets.canvas             optional: a board for the list
├── Sources/Spotify.md                 one note per source
├── Records/Mira Holt.md               module records, such as follows
└── Templates/Record.md                optional: a template for typing a record by hand

This layout is what producers write. Readers don't depend on it: everything that matters is in the notes' contents (see Reading a folder). The person, or another app, can rename notes, move them into any folders (a folder per artist, per year) or leave them all in one pile, and the collection reads back the same.

File names are for people:

NoteName
Item<artists> - <title>; more than 40 characters of artists become <first artist> +<n>
List, source<name>
Module record<name>
  • Characters that file systems or wikilinks don't allow (/ \ : * ? " < > | # ^ [ ]) become -.
  • Names longer than 120 characters are cut in the middle (…), keeping the end, which often tells songs apart ("… II. Aristophanes. Allegretto"). Trailing spaces and dots are removed: they break links, and Windows refuses them.
  • When a song and a release share a name (a single and its song), the release adds (release) and the song keeps the plain name.
  • Names that clash are told apart by the song, never by a counter: an item adds its album, then its year, then its length (Ojerime - Jetset (Bad Influence), … (4m01s)); a list adds its source's name; a source its account. Only when nothing else differs does a name get a short hash of the id. A name depends only on its record and on the records that share it, never on their order.
  • A producer MUST NOT give two notes the same file.

Notes

Items

---
omc: item
id: i1
kind: recording
title: Night Drive
artists:
  - Mira Holt
album: Night Drive EP
duration_ms: 312000
bpm: 124
key: Am
isrc: QZES72600001
sources:
  - "[[Spotify]]"
  - "[[Bandcamp]]"
tags:
  - late night
---

Heard it at the Basement in March. The breakdown at 2:40 is the moment.

```omc
{
  "copies": [
    { "source": "s1", "ref": "0exampleTrackId000001", "url": "https://open.spotify.com/track/0exampleTrackId000001" },
    { "source": "s2", "ref": "2854920395", "ownership": "digital" }
  ]
}
```

omc and id. omc says what kind of OMC record the note is (item, list, source, collection, or a module record's type); id is the record's id. The id is this collection's id for the record: links and list entries depend on it, so don't change it by hand, and don't copy it into a new note (give a new note a fresh id, or none, see Notes made by hand). It is not a global identifier: the same song in someone else's collection has another id.

Properties. Item fields that fit as properties are written as properties, with the core's names and values:

  • kind, title, artists (list), album, album_artists (list), composers (list), release_type, duration_ms, release_date (text: OMC dates may be partial), label, catalog_number, country, genres (list), bpm, key, artwork_url, rating, added_at (text, as in the core), play_count, last_played_at;
  • the identifiers isrc, upc, musicbrainz and iswc, taken out of ids.

The note's text is the item's note, without the omc block.

sources lists links to the notes of the sources the item has copies on, and releases to the notes of the releases its copies came from (so a release's note lists its songs as backlinks). Both are written for people (they make Obsidian's backlinks and graph work) and derived: producers write them, importers MUST ignore them; the data is in the copies.

The omc block. A fenced code block with the info string omc, holding a JSON object with the record's remaining members: copies, provenance, via, other ids, ext, and members the producer doesn't know. There is at most one per note, and none when nothing remains.

The person's own data. Any other property (tags, aliases, anything the person adds) is the person's. Importers keep these in the record's ext["org.openmusiccollection.folder"].properties, as written, and producers write them back as properties. So a collection file carries them to any app, and back into a folder unchanged. A person typing a property never has to pick a namespace.

Lists

---
omc: list
id: l1
ordered: true
role: curated
position: 2
source: "[[Spotify]]"
parent: "[[Gigs]]"
ref: 0examplePlaylistId0001
---

For the long drive home. Opened with these at the March gig.

## Entries

1. [[Mira Holt - Night Drive]] <!-- omc {"item":"i1","ref":"0exampleTrackId000001","added_at":"2026-03-02T21:10:00Z","note":"Open with this"} -->
2. [[Lumen Arcade - Glass Tides]] <!-- omc {"item":"i2"} -->

```omc
{ "source": "s1", "parent": "l7" }
```
  • Properties:
    • ordered (checkbox), folder (checkbox), position, color, role, ref, created_at;
    • The list's name is its name property; producers also use it as the file name.
    • source (a link to the source note), parent (a link to the folder's note) and board (a link to the list's board) are derived, for people: the source's and the folder's ids are in the omc block, and importers ignore the links as data. A list typed by hand, with no ids in a block, has its source and parent links followed.
    • A filter is in the omc block.
  • Entries are the list items under a heading Entries (any level): numbered for an ordered list, bulleted for an unordered one, in order.
    • Each has a link to the item's note, for people, and its data on the same line in an HTML comment, <!-- omc {…} -->, starting with the item's id ("item"), then ref, added_at, note, ext. Moving a line moves its data.
    • The id decides which item an entry is: see Reading a folder.
  • The rest of the body is the list's description. A folder (folder: true) is a list note with no entries; its lists link to it in parent.

Sources

Properties omc: source, id, platform, name, account, account_name, descriptor; an omc block for ext and unknown members. The core has no note on sources, so the body is the person's own, kept in ext["org.openmusiccollection.folder"].notes.

Collection

Collection.md holds the header:

  • Properties: omc: collection, version, generated_at, and name when the collection has one. Producers use the name as the folder's name when they create it (a vault called "Anna's records");
  • The omc block: generator, counts, modules and ext.

counts describes the files at the time they were written. Importers recompute it.

Module records

Properties omc: <type> (for example org.openmusiccollection.feeds/follow) and id, plus the record's flat text, number, checkbox and list-of-text members as properties; the rest in the omc block.

Names written before

Folders written by draft 0.1 used omc_type and omc_id. Readers MUST still accept them (a note with either pair is read the same), and producers write omc and id.

Before the core had note, an item's body was kept in ext["org.openmusiccollection.folder"].notes, and a list's in the same place, with description as a property. Readers read an item's body as note, and a list's description property, when there is one, as description, with the body kept as before. Producers write a collection file's older notes back as the body.

Notes made by hand

A folder is meant to be edited by people, so a note typed by hand is read like any other:

  • Without an id. A note with omc and no id gets one when it is read (derived from its path, so it stays the same until the note moves). omc-folder add-ids writes fresh ids into such notes once, so links to them keep working after a rename.
  • A template. A producer MAY write Templates/Record.md, a release note (omc: item, kind: release) with its other properties left empty, for Obsidian's Templates feature, so a note made from it is an ordinary record. Readers skip the folder Templates at the folder's root.
  • A shelf. A release note with a shelf property naming a source note (shelf: "[[My records]]") gets a copy on that source, with ownership: physical and the note's id as ref, unless the omc block already has copies. So a person can catalogue a record with properties alone:
---
omc: item
kind: release
title: Night Drive EP
artists:
  - Mira Holt
release_date: "2026"
shelf: "[[My records]]"
---
Bought at the Basement gig, signed.

The shelf property is kept as written, and a producer writes it back.

Boards (JSON Canvas)

A list MAY have a board: a JSON Canvas file, linked from the list's board property ("[[Late sets.canvas]]"), written next to the note with the same name. Readers follow the link and fall back to a .canvas with the note's name beside it.

  • File nodes point at item notes; text nodes and edges carry whatever the person adds, such as transitions, cue notes or a mix plan.
  • The board is the person's view of the list. The entries in the note stay authoritative.
  • Importers keep the board whole in the list's ext["org.openmusiccollection.folder"].canvas, and producers write it back unchanged.
  • A producer MAY draw a board for an ordered list that has none: one file node per entry, left to right, with an edge from each to the next.

Bases

A producer MAY write Collection.base, a table of items for Obsidian, and MUST NOT overwrite an existing one. It is a convenience for Obsidian users, not part of the collection.

Reading a folder: contents first

A reader MUST get the same collection from a folder whatever its file names, folders and links look like: notes renamed by hand, moved by a sync tool or another app, or piled into one folder.

  1. What a note is comes from omc and id, never from its name or folder. Notes in any folder are read; notes and files without omc are the person's and are left alone; hidden folders (.obsidian, .git) are skipped. Both .md and .markdown are read.

  2. What a record points at comes from ids in the contents: an entry's "item", a list's source in its block, an item's copies. When an entry's link and its id disagree, the id wins and the reader reports it; to point an entry at another item, replace the whole line.

  3. Links are followed only where there is no id (a line typed by hand, a list made by hand). Readers accept every link style Obsidian writes and standard Markdown links:

    • a bare name, [[Night Drive]], which must match exactly one note;
    • a path from the folder's root, [[Items/Night Drive]];
    • a path relative to the linking note, [[../Items/Night Drive]];
    • [Night Drive](../Items/Night%20Drive.md).

    Aliases (|…) and headings (#…) are ignored, and names match without regard to case or the .md.

  4. Copies of a note (two notes with the same omc and id, as sync tools leave behind as "conflicted copies") are read once when their contents are the same.

  5. Loosely written values are read for what they mean: "124" as a number where the core wants a number, "true" as a checkbox, a single text value as a one-value list. Readers say when they do.

Converting

FromToRule
A collection fileA folderWrite every record as above. Null members are left out (absent and null mean the same).
A folderA collection fileRead every Markdown note with omc; rebuild each record from properties, the omc block, entries and the person's data; resolve links to ids. When any record carries the person's data, list this module in the header's modules.

Converting a file to a folder and back MUST give the same records, null members aside. The reference tool checks this on every example.

Conformance

  • A folder is valid when converting it gives a valid collection file.
  • Two notes with the same omc and id and different contents are an error.
  • An entry without an id whose link matches several notes, or none, is an error (several) or a warning (none, read as the link's name).

Open questions

  1. Should an item's tags map to genres, or stay the person's own?

  2. Two apps editing the same folder at once (the person's editor and a music app): last write per file wins. Is that enough?

  3. Writing into an existing folder. A producer that updates a folder should keep every note where it is and under the name it has (finding it by id), and name only new notes, so names and the person's own links never change under them. What happens to the note of a record the collection no longer has: delete it, or move it to an archive folder?

  4. The layout puts recordings in Items/ and releases in Releases/, so there "items" means only songs. Tracks/ or Recordings/ instead?

What was decided, and when, is in the changelog.