Skip to main content
@rocksky/sdk is built on atcute: RockskyClient does unauthenticated AppView reads, and Agent logs in with an app password and writes app.rocksky.* records to the user’s PDS. It also ships a local dedup index and Jetstream real-time sync.
Version 0.4.0 is a breaking rewrite on atcute — it is a native AT Protocol client, not the old HTTP wrapper. See the package CHANGELOG.

Install

Requires Node ≥ 22 (global WebSocket / fetch) or Bun.

Quickstart

API

Reads — RockskyClient: the client now covers the whole app.rocksky.* read surface. Typed methods include profile, scrobbles, songs, albums, artists, topTracks, topArtists, search, globalStats, lovedSongs, catalogAlbums, catalogArtists, catalogSongs, albumTracks, artistAlbums, artistTracks, scrobbleFeed, scrobble (single by uri), follows, followers, knownFollowers. Raw (unknown-returning) detail / long-tail methods cover the rest: album, artist, song, feed, playlists, playlist, stats, wrapped, scrobblesChart, recommendations, neighbours, shouts, and more. Every named method is sugar over the universal escape hatch rk.get(nsid, params), which calls ANY read query by nsid and returns unknown. Typed date-window charts: topTracksInterval(limit, offset, interval) and topArtistsInterval(...) take a DateInterval built with the Interval factories — Interval.allTime(), Interval.lastDays(n), Interval.lastWeeks(n), Interval.lastMonths(n), Interval.lastYears(n), Interval.range(start, end). topTracks / topArtists remain all-time shorthands.
matchSong(title, artist, mbId?, isrc?): resolves a bare title + artist into full canonical metadata (album, artwork, duration, MBID, ISRC, links). Auth-gated reads: pass an optional bearer access token — new RockskyClient(appview, token) — sent as Authorization: Bearer <token>. Writes — Agent: two scrobble paths — scrobble(rec) writes full metadata you already have, and scrobbleMatch(input, appview?) takes a ScrobbleMatchInput object ({ title, artist, album?, mbId?, isrc?, timestamp? } — title/artist required; album overrides the resolved album, mbId/isrc are match anchors, timestamp is a scrobbled-at Unix-seconds time; the optional appview overrides the AppView used for matching) and resolves full metadata via matchSong first, then writes — e.g. agent.scrobbleMatch({ title: "Chaser", artist: "Calibro 35" }). Plus createSong / createAlbum / createArtist, like, follow, shout / replyShout, setNowPlaying / clearNowPlaying, delete. Identity hashes: songHash, albumHash, artistHash.

Duplicate prevention & real-time sync

An optional local index (embedded classic-level LevelDB) prevents duplicate writes and stays live off the firehose: