about things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

lexicons#

lexicons are atproto's schema system. they define what records look like and what APIs accept.

NSIDs#

a Namespace ID identifies a lexicon:

fm.plyr.track
app.bsky.feed.post
com.atproto.repo.createRecord

format is reverse-DNS. the domain owner controls that namespace. this prevents collisions and makes ownership clear.

defining a lexicon#

{
  "$type": "com.atproto.lexicon",
  "id": "fm.plyr.track",
  "defs": {
    "main": {
      "type": "record",
      "key": "tid",
      "record": {
        "type": "object",
        "required": ["title", "artist", "audioUrl", "createdAt"],
        "properties": {
          "title": {"type": "string"},
          "artist": {"type": "string"},
          "audioUrl": {"type": "string", "format": "uri"},
          "album": {"type": "string"},
          "duration": {"type": "integer"},
          "createdAt": {"type": "string", "format": "datetime"}
        }
      }
    }
  }
}

from plyr.fm/lexicons/track.json

record keys#

  • tid: timestamp-based ID. for records where users have many (tracks, likes, posts).
  • literal:self: singleton. for records where users have one (profile).
"key": "tid"           // generates 3jui7akfj2k2a
"key": "literal:self"  // always "self"

knownValues#

extensible enums. the schema declares known values but validators won't reject unknown ones:

"listType": {
  "type": "string",
  "knownValues": ["album", "playlist", "liked"]
}

this allows schemas to evolve without breaking existing records. new values can be added; old clients just won't recognize them.

from plyr.fm list lexicon

namespace discipline#

plyr.fm uses environment-aware namespaces:

environment namespace
production fm.plyr
staging fm.plyr.stg
development fm.plyr.dev

never hardcode namespaces. configure via settings so dev/staging don't pollute production data.

important: don't reuse another app's lexicons even for similar concepts. plyr.fm defines fm.plyr.like rather than using app.bsky.feed.like. this maintains namespace isolation and avoids coupling to another app's schema evolution.

shared lexicons#

for true interoperability, multiple apps can agree on a common schema:

audio.ooo.track  # shared schema for audio content

plyr.fm writes to audio.ooo.track (production) so other audio apps can read the same records. this follows the pattern at standard.site.

benefits:

  • one schema for discovery, any app can read it
  • content is portable - tracks live in your PDS, playable anywhere
  • platform-specific features live as extensions, not forks

from plyr.fm shared audio lexicon research

schema evolution#

atproto schemas can only:

  • add optional fields
  • add new knownValues

you cannot:

  • remove fields
  • change required fields
  • change field types

plan schemas carefully. once published, breaking changes aren't possible.

why this matters#

lexicons enable the "cooperative computing" model:

  • apps agree on schemas → they can read each other's data
  • namespace ownership → no collisions, clear responsibility
  • extensibility → schemas evolve without breaking
  • shared lexicons → true cross-app interoperability