mount an atproto PDS repository as a FUSE filesystem
Rust 96.4%
Other 3.6%
14 2 0

Clone this repository

https://tangled.org/oppi.li/pdsfs
git@tangled.org:oppi.li/pdsfs

For self-hosted knots, clone URLs may differ based on your setup.

readme.txt
pdsfs - mount an atproto PDS repository as a FUSE filesystem.

a PDS repository[0] contains all data published by a user to
the atmosphere[1]. it is exportable as a CAR
(content-addressable archive) file. pdsfs is a tool that
mounts this CAR file as a readonly-FUSE filesystem, allowing
quick and easy exploration.

to motivate the need for such a program, we could begin by
mounting a repository:


    λ pdsfs oppi.li
    mounted at "mnt"
    hit enter to unmount and exit...


oppi.li is my handle in the atmosphere. the tool does some
hardwork to determine the location of my PDS repository
given my handle, but that is not important. lets have a look
around:


    λ ls mnt/
    did:plc:qfpnj4og54vl56wngdriaxug/


the did:plc:stuff is my DID. lets dig deeper:


    λ ls mnt/did\:plc\:qfpnj4og54vl56wngdriaxug/
    app.bsky.actor.profile/            place.stream.chat.message/
    app.bsky.actor.status/             place.stream.chat.profile/
    app.bsky.feed.generator/           place.stream.key/
    app.bsky.feed.like/                place.stream.livestream/
    app.bsky.feed.post/                sh.tangled.actor.profile/
    app.bsky.feed.repost/              sh.tangled.feed.reaction/
    app.bsky.graph.block/              sh.tangled.feed.star/
    app.bsky.graph.follow/             sh.tangled.graph.follow/
    app.rocksky.album/                 sh.tangled.knot/
    app.rocksky.artist/                sh.tangled.knot.member/
    .
    .
    .


we have some data from the repository now. these are
"collections". if i want to publish a post to bluesky, i
would write content to the "app.bsky.feed.post" collection
in my PDS. this will then be indexed by a bluesky appview
(bsky.app or zeppelin.social to name a few) and show up
under my profile there.

pdsfs is kind enough to deserialize the data stored (as
CBOR) in the PDS repository to JSON:


    λ cat sh.tangled.repo/3ljidbevrjh22 | jq
    {
      "$type": "sh.tangled.repo",
      "addedAt": "2025-03-03T16:04:13Z",
      "knot": "knot1.tangled.sh",
      "name": "hello-world",
      "owner": "did:plc:3danwc67lo7obz2fmdg6jxcr"
    }


thanks pdsfs!

i publish my music listening habits to my PDS to the
"app.rocksky.scrobble" collection, because rocksky[4]
recognizes and indexes this collection. i have wired up my
personal navidrome instance to write data of this form into
my PDS everytime i listen to a track. here are my top
artists in order:


    λ cat app.rocksky.scrobble/* | jq -r '.artist' | sort | uniq -c | sort -nr
        117 Thank You Scientist
         45 FKJ
         34 Covet
         33 VOLA
         23 Sam Cooke
         22 Dark Tranquillity
         21 Piero Piccioni
         12 Bloodywood
         11 Frank Sinatra
         10 Dream Theater


it is true, i love sam cooke.

pdsfs allows mounting multiple repositories at a time. allow
me to introduce my friends:


    λ pdsfs icyphox.sh anil.recoil.org steveklabnik.com tangled.sh
    using cached CAR file for...did:plc:hwevmowznbiukdf6uk5dwrrq
    using cached CAR file for...did:plc:nhyitepp3u4u6fcfboegzcjw
    download complete for...did:plc:3danwc67lo7obz2fmdg6jxcr
    download complete for...did:plc:wshs7t2adsemcrrd4snkeqli
    mounted at "mnt"
    hit enter to unmount and exit...


    # -- in a separate shell --


    λ cat ./mnt/*/app.bsky.actor.profile/* \
      | jq -r '"\(.displayName)\n\(.description)\n---"' \
      | sed '/^$/d'
    Steve Klabnik
    #rustlang, #jj-vcs, atproto, shitposts, urbanism. I
    contain multitudes. Working on #ruelang but just for
    fun. Currently in Austin, TX, but from Pittsburgh.
    Previously in Bushwick, the Mission, LA.
    ---
    Anirudh Oppiliappan
    building @tangled.sh — code collaboration platform built
    on atproto helsinki, finland · https://anirudh.fi ·
    (somewhat) effective altruist
    ---
    Anil Madhavapeddy
    Professor of Planetary Computing at the University of
    Cambridge @cst.cam.ac.uk, where I co-lead the
    @eeg.cl.cam.ac.uk, and am also to found at
    @conservation.cam.ac.uk. Homepage at
    https://anil.recoil.org
    ---
    Tangled
    https://tangled.sh is a git collaboration platform built
    on atproto. Social coding, but for real this time!
    Discord: chat.tangled.sh IRC: #tangled @ libera.chat
    Built by @oppi.li & @icyphox.sh
    ---


all my friends use tangled.sh, which requires them to
publish their ssh public key to their PDii (PDSes?). perhaps
i would like to add their keys to my allowed_signers file to
verify their commit signatures:


    λ for dir in ./*/sh.tangled.publicKey;
        do cat $dir/$(ls -r $dir | head -n1) | jq -r '.key';
      done | tee allowed_signers
    ssh-rsa AAAAB3NzaC1yc2EAAA...dHPqc= steveklabnik@DESKTOP-VV370NK
    ssh-ed25519 AAAAC3NzaC1lZD...g9bAdk icy@wyndle
    ssh-ed25519 AAAAC3NzaC1lZD...BqlM1u anil@recoil.org



---


FUSE is quite liberating in that it allows you to represent
anything as a filesystem. when applications like ls and cat
are executed, the system calls to open and read are rerouted
to your custom fs implementation (pdsfs in this case). the
custom fs implementation is free to as it pleases, in fact
the first iteration of pdsfs accessed the network for each
open/read call to fetch live data from PDii.


[0]: https://atproto.com/guides/data-repos
[1]: https://atproto.com
[2]: https://docs.bsky.app/docs/api/com-atproto-sync-get-repo
[3]: https://tangled.sh/keys/oppi.li
[4]: https://rocksky.app