pdsfs is a tool that mounts atproto PDS repositories as a FUSE filesystem.
A PDS repository contains all data published by a user to the atmosphere. 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. Let’s have a look around:
λ ls mnt/ did:plc:qfpnj4og54vl56wngdriaxug/The did:plc:stuff is my DID. Digging 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 (such as bsky.app or zeppelin.social) and show up under my profile there.
pdsfs is kind enough to deserialize the in the PDS repository (stored as CBOR normally) to JSON on the filesystem:
λ 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 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:
λ jq -r '.artist' app.rocksky.scrobble/* | 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 TheaterIt 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 [email protected]FUSE is quite liberating in that it allows you to represent anything as a filesystem. When applications like ls and cat are executed, the syscalls 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.