···11-pdsfs
22------
11+pdsfs - mount an atproto PDS repository as a FUSE filesystem.
3244-mount an atproto PDS repository as a fuse3 filesystem.
33+a PDS repository[0] contains all data published by a user to
44+the atmosphere[1]. it is exportable as a CAR
55+(content-addressable archive) file. pdsfs is a tool that
66+mounts this CAR file as a readonly-FUSE filesystem, allowing
77+quick and easy exploration.
5899+to motivate the need for such a program, we could begin by
1010+mounting a repository:
61177-usage
88------
9121010- cargo run -- [DIDs|handles ...] [-m mountpoint]
1313+ λ pdsfs oppi.li
1414+ mounted at "mnt"
1515+ hit enter to unmount and exit...
1616+1717+1818+oppi.li is my handle in the atmosphere. the tool does some
1919+hardwork to determine the location of my PDS repository
2020+given my handle, but that is not important. lets have a look
2121+around:
2222+2323+2424+ λ ls mnt/
2525+ did:plc:qfpnj4og54vl56wngdriaxug/
2626+2727+2828+the did:plc:stuff is my DID. lets dig deeper:
2929+3030+3131+ λ ls mnt/did\:plc\:qfpnj4og54vl56wngdriaxug/
3232+ app.bsky.actor.profile/ place.stream.chat.message/
3333+ app.bsky.actor.status/ place.stream.chat.profile/
3434+ app.bsky.feed.generator/ place.stream.key/
3535+ app.bsky.feed.like/ place.stream.livestream/
3636+ app.bsky.feed.post/ sh.tangled.actor.profile/
3737+ app.bsky.feed.repost/ sh.tangled.feed.reaction/
3838+ app.bsky.graph.block/ sh.tangled.feed.star/
3939+ app.bsky.graph.follow/ sh.tangled.graph.follow/
4040+ app.rocksky.album/ sh.tangled.knot/
4141+ app.rocksky.artist/ sh.tangled.knot.member/
4242+ .
4343+ .
4444+ .
4545+4646+4747+we have some data from the repository now. these are
4848+"collections". if i want to publish a post to bluesky, i
4949+would write content to the "app.bsky.feed.post" collection
5050+in my PDS. this will then be indexed by a bluesky appview
5151+(bsky.app or zeppelin.social to name a few) and show up
5252+under my profile there.
5353+5454+pdsfs is kind enough to deserialize the data stored (as
5555+CBOR) in the PDS repository to JSON:
5656+5757+5858+ λ cat sh.tangled.repo/3ljidbevrjh22 | jq
5959+ {
6060+ "$type": "sh.tangled.repo",
6161+ "addedAt": "2025-03-03T16:04:13Z",
6262+ "knot": "knot1.tangled.sh",
6363+ "name": "hello-world",
6464+ "owner": "did:plc:3danwc67lo7obz2fmdg6jxcr"
6565+ }
6666+6767+6868+thanks pdsfs!
11691212-example
1313--------
7070+i publish my music listening habits to my PDS to the
7171+"app.rocksky.scrobble" collection, because rocksky[4]
7272+recognizes and indexes this collection. i have wired up my
7373+personal navidrome instance to write data of this form into
7474+my PDS everytime i listen to a track. here are my top
7575+artists in order:
14761515- $ cargo run -- oppi.li icyphox.sh
1616- ⠏ [00:00:00] using cached CAR file for...did:plc:qfpnj4og54vl56wngdriaxug
1717- ⠏ [00:00:00] using cached CAR file for...did:plc:hwevmowznbiukdf6uk5dwrrq
7777+7878+ λ cat app.rocksky.scrobble/* | jq -r '.artist' | sort | uniq -c | sort -nr
7979+ 117 Thank You Scientist
8080+ 45 FKJ
8181+ 34 Covet
8282+ 33 VOLA
8383+ 23 Sam Cooke
8484+ 22 Dark Tranquillity
8585+ 21 Piero Piccioni
8686+ 12 Bloodywood
8787+ 11 Frank Sinatra
8888+ 10 Dream Theater
8989+9090+9191+it is true, i love sam cooke.
9292+9393+pdsfs allows mounting multiple repositories at a time. allow
9494+me to introduce my friends:
9595+9696+9797+ λ pdsfs icyphox.sh anil.recoil.org steveklabnik.com tangled.sh
9898+ using cached CAR file for...did:plc:hwevmowznbiukdf6uk5dwrrq
9999+ using cached CAR file for...did:plc:nhyitepp3u4u6fcfboegzcjw
100100+ download complete for...did:plc:3danwc67lo7obz2fmdg6jxcr
101101+ download complete for...did:plc:wshs7t2adsemcrrd4snkeqli
18102 mounted at "mnt"
19103 hit enter to unmount and exit...
20104211052222- $ cat foo/**/sh.tangled.publicKey/* | jq -r '.key'
2323- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICJPYX06+qKr9IHWfkgCtHbExoBOOwS/+iAWbog9bAdk icy@wyndle
2424- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMj1Dn9YuFo2BNr993ymBa6nzyyIKAURIqMbUtfI8+4X op@mantis
2525- .
2626- .
2727- .
106106+ # -- in a separate shell --
107107+108108+109109+ λ cat ./mnt/*/app.bsky.actor.profile/* \
110110+ | jq -r '"\(.displayName)\n\(.description)\n---"' \
111111+ | sed '/^$/d'
112112+ Steve Klabnik
113113+ #rustlang, #jj-vcs, atproto, shitposts, urbanism. I
114114+ contain multitudes. Working on #ruelang but just for
115115+ fun. Currently in Austin, TX, but from Pittsburgh.
116116+ Previously in Bushwick, the Mission, LA.
117117+ ---
118118+ Anirudh Oppiliappan
119119+ building @tangled.sh — code collaboration platform built
120120+ on atproto helsinki, finland · https://anirudh.fi ·
121121+ (somewhat) effective altruist
122122+ ---
123123+ Anil Madhavapeddy
124124+ Professor of Planetary Computing at the University of
125125+ Cambridge @cst.cam.ac.uk, where I co-lead the
126126+ @eeg.cl.cam.ac.uk, and am also to found at
127127+ @conservation.cam.ac.uk. Homepage at
128128+ https://anil.recoil.org
129129+ ---
130130+ Tangled
131131+ https://tangled.sh is a git collaboration platform built
132132+ on atproto. Social coding, but for real this time!
133133+ Discord: chat.tangled.sh IRC: #tangled @ libera.chat
134134+ Built by @oppi.li & @icyphox.sh
135135+ ---
136136+137137+138138+all my friends use tangled.sh, which requires them to
139139+publish their ssh public key to their PDii (PDSes?). perhaps
140140+i would like to add their keys to my allowed_signers file to
141141+verify their commit signatures:
142142+143143+144144+ λ for dir in ./*/sh.tangled.publicKey;
145145+ do cat $dir/$(ls -r $dir | head -n1) | jq -r '.key';
146146+ done | tee allowed_signers
147147+ ssh-rsa AAAAB3NzaC1yc2EAAA...dHPqc= steveklabnik@DESKTOP-VV370NK
148148+ ssh-ed25519 AAAAC3NzaC1lZD...g9bAdk icy@wyndle
149149+ ssh-ed25519 AAAAC3NzaC1lZD...BqlM1u anil@recoil.org
150150+151151+152152+153153+---
154154+28155156156+FUSE is quite liberating in that it allows you to represent
157157+anything as a filesystem. when applications like ls and cat
158158+are executed, the system calls to open and read are rerouted
159159+to your custom fs implementation (pdsfs in this case). the
160160+custom fs implementation is free to as it pleases, in fact
161161+the first iteration of pdsfs accessed the network for each
162162+open/read call to fetch live data from PDii.
2916330164165165+[0]: https://atproto.com/guides/data-repos
166166+[1]: https://atproto.com
167167+[2]: https://docs.bsky.app/docs/api/com-atproto-sync-get-repo
168168+[3]: https://tangled.sh/keys/oppi.li
169169+[4]: https://rocksky.app