+17
-17
docs/index.html
+17
-17
docs/index.html
···
35
35
<tr>
36
36
<td class=table-post>
37
37
<div class="date">
38
+
30/07 — 2025
39
+
</div>
40
+
<a href="/posts/mounting_the_atmosphere" class="post-link">
41
+
<span class="post-link">Mounting The Atmosphere</span>
42
+
</a>
43
+
</td>
44
+
<td class=table-stats>
45
+
<span class="stats-number">
46
+
4.3
47
+
</span>
48
+
<span class=stats-unit>min</span>
49
+
</td>
50
+
</tr>
51
+
52
+
<tr>
53
+
<td class=table-post>
54
+
<div class="date">
38
55
24/05 — 2025
39
56
</div>
40
57
<a href="/posts/configuring_jujutsu" class="post-link">
···
61
78
<td class=table-stats>
62
79
<span class="stats-number">
63
80
3.9
64
-
</span>
65
-
<span class=stats-unit>min</span>
66
-
</td>
67
-
</tr>
68
-
69
-
<tr>
70
-
<td class=table-post>
71
-
<div class="date">
72
-
27/11 — 2024
73
-
</div>
74
-
<a href="/posts/OSC-52" class="post-link">
75
-
<span class="post-link">OSC-52</span>
76
-
</a>
77
-
</td>
78
-
<td class=table-stats>
79
-
<span class="stats-number">
80
-
1.9
81
81
</span>
82
82
<span class=stats-unit>min</span>
83
83
</td>
+146
docs/index.xml
+146
docs/index.xml
···
12
12
<language>en-us</language>
13
13
<copyright>Creative Commons BY-NC-SA 4.0</copyright>
14
14
<item>
15
+
<title>Mounting The Atmosphere</title>
16
+
<description><p><a href="https://tangled.sh/@oppi.li/pdsfs">pdsfs</a> is a tool that
17
+
mounts atproto PDS repositories as a FUSE filesystem.</p>
18
+
<p>A PDS repository<a href="#fn1" class="footnote-ref" id="fnref1"
19
+
role="doc-noteref"><sup>1</sup></a> contains all data published by a
20
+
user to the atmosphere<a href="#fn2" class="footnote-ref" id="fnref2"
21
+
role="doc-noteref"><sup>2</sup></a>. It is exportable as a CAR
22
+
(content-addressable archive) file. pdsfs is a tool that mounts this CAR
23
+
file as a readonly-FUSE filesystem, allowing quick and easy
24
+
exploration.</p>
25
+
<p>To motivate the need for such a program, we could begin by mounting a
26
+
repository:</p>
27
+
<pre><code>λ pdsfs oppi.li
28
+
mounted at &quot;mnt&quot;
29
+
hit enter to unmount and exit...</code></pre>
30
+
<p>oppi.li is my handle in the atmosphere. The tool does some hardwork
31
+
to determine the location of my PDS repository given my handle, but that
32
+
is not important. Let’s have a look around:</p>
33
+
<pre><code>λ ls mnt/
34
+
did:plc:qfpnj4og54vl56wngdriaxug/</code></pre>
35
+
<p>The <code>did:plc:stuff</code> is my DID<a href="#fn3"
36
+
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>.
37
+
Digging deeper:</p>
38
+
<pre><code>λ ls mnt/did\:plc\:qfpnj4og54vl56wngdriaxug/
39
+
app.bsky.actor.profile/ place.stream.chat.message/
40
+
app.bsky.actor.status/ place.stream.chat.profile/
41
+
app.bsky.feed.generator/ place.stream.key/
42
+
app.bsky.feed.like/ place.stream.livestream/
43
+
app.bsky.feed.post/ sh.tangled.actor.profile/
44
+
app.bsky.feed.repost/ sh.tangled.feed.reaction/
45
+
app.bsky.graph.block/ sh.tangled.feed.star/
46
+
app.bsky.graph.follow/ sh.tangled.graph.follow/
47
+
app.rocksky.album/ sh.tangled.knot/
48
+
app.rocksky.artist/ sh.tangled.knot.member/
49
+
.
50
+
.
51
+
.</code></pre>
52
+
<p>We have some data from the repository now. These are “collections”.
53
+
If I want to publish a post to Bluesky, I would write content to the
54
+
<code>app.bsky.feed.post</code> collection in my PDS. This will then be
55
+
indexed by a Bluesky appview (such as <a
56
+
href="https://bsky.app">bsky.app</a> or <a
57
+
href="https://zeppelin.social">zeppelin.social</a>) and show up under my
58
+
profile there.</p>
59
+
<p>pdsfs is kind enough to deserialize the in the PDS repository (stored
60
+
as CBOR normally) to JSON on the filesystem:</p>
61
+
<pre><code>λ cat sh.tangled.repo/3ljidbevrjh22 | jq
62
+
{
63
+
&quot;$type&quot;: &quot;sh.tangled.repo&quot;,
64
+
&quot;addedAt&quot;: &quot;2025-03-03T16:04:13Z&quot;,
65
+
&quot;knot&quot;: &quot;knot1.tangled.sh&quot;,
66
+
&quot;name&quot;: &quot;hello-world&quot;,
67
+
&quot;owner&quot;: &quot;did:plc:3danwc67lo7obz2fmdg6jxcr&quot;
68
+
}</code></pre>
69
+
<p>Thanks pdsfs!</p>
70
+
<p>I publish my music listening habits to my PDS to the
71
+
<code>app.rocksky.scrobble</code> collection, because <a
72
+
href="https://rocksky.app">Rocksky</a> recognizes and indexes this
73
+
collection. I have wired up my personal navidrome instance to write data
74
+
of this form into my PDS everytime I listen to a track. Here are my top
75
+
artists in order:</p>
76
+
<pre><code>λ jq -r &#39;.artist&#39; app.rocksky.scrobble/* | sort | uniq -c | sort -nr
77
+
117 Thank You Scientist
78
+
45 FKJ
79
+
34 Covet
80
+
33 VOLA
81
+
23 Sam Cooke
82
+
22 Dark Tranquillity
83
+
21 Piero Piccioni
84
+
12 Bloodywood
85
+
11 Frank Sinatra
86
+
10 Dream Theater</code></pre>
87
+
<p>It is true, I love Sam Cooke.</p>
88
+
<p>pdsfs allows mounting multiple repositories at a time. Allow me to
89
+
introduce my friends:</p>
90
+
<pre><code>λ pdsfs icyphox.sh anil.recoil.org steveklabnik.com tangled.sh
91
+
using cached CAR file for...did:plc:hwevmowznbiukdf6uk5dwrrq
92
+
using cached CAR file for...did:plc:nhyitepp3u4u6fcfboegzcjw
93
+
download complete for...did:plc:3danwc67lo7obz2fmdg6jxcr
94
+
download complete for...did:plc:wshs7t2adsemcrrd4snkeqli
95
+
mounted at &quot;mnt&quot;
96
+
hit enter to unmount and exit...
97
+
98
+
# -- in a separate shell --
99
+
100
+
λ cat ./mnt/*/app.bsky.actor.profile/* \
101
+
| jq -r &#39;&quot;\(.displayName)\n\(.description)\n---&quot;&#39; \
102
+
| sed &#39;/^$/d&#39;
103
+
Steve Klabnik
104
+
#rustlang, #jj-vcs, atproto, shitposts, urbanism. I
105
+
contain multitudes. Working on #ruelang but just for
106
+
fun. Currently in Austin, TX, but from Pittsburgh.
107
+
Previously in Bushwick, the Mission, LA.
108
+
---
109
+
Anirudh Oppiliappan
110
+
building @tangled.sh — code collaboration platform built
111
+
on atproto helsinki, finland · https://anirudh.fi ·
112
+
(somewhat) effective altruist
113
+
---
114
+
Anil Madhavapeddy
115
+
Professor of Planetary Computing at the University of
116
+
Cambridge @cst.cam.ac.uk, where I co-lead the
117
+
@eeg.cl.cam.ac.uk, and am also to found at
118
+
@conservation.cam.ac.uk. Homepage at
119
+
https://anil.recoil.org
120
+
---
121
+
Tangled
122
+
https://tangled.sh is a git collaboration platform built
123
+
on atproto. Social coding, but for real this time!
124
+
Discord: chat.tangled.sh IRC: #tangled @ libera.chat
125
+
Built by @oppi.li &amp; @icyphox.sh
126
+
---</code></pre>
127
+
<p>All my friends use <a href="https://tangled.sh">tangled.sh</a>, which
128
+
requires them to publish their ssh public key to their PDii (PDSes?).
129
+
Perhaps I would like to add their keys to my allowed_signers file to
130
+
verify their commit signatures:</p>
131
+
<pre><code>λ for dir in ./*/sh.tangled.publicKey;
132
+
do cat $dir/$(ls -r $dir | head -n1) | jq -r &#39;.key&#39;;
133
+
done | tee allowed_signers
134
+
ssh-rsa AAAAB3NzaC1yc2EAAA...dHPqc= steveklabnik@DESKTOP-VV370NK
135
+
ssh-ed25519 AAAAC3NzaC1lZD...g9bAdk icy@wyndle
136
+
ssh-ed25519 AAAAC3NzaC1lZD...BqlM1u anil@recoil.org</code></pre>
137
+
<p>FUSE is quite liberating in that it allows you to represent anything
138
+
as a filesystem. When applications like <code>ls</code> and
139
+
<code>cat</code> are executed, the syscalls to <code>open</code> and
140
+
<code>read</code> are rerouted to your custom fs implementation (pdsfs
141
+
in this case). The custom fs implementation is free to as it pleases, in
142
+
fact the first iteration of pdsfs accessed the network for each
143
+
open/read call to fetch live data from PDii.</p>
144
+
<section id="footnotes" class="footnotes footnotes-end-of-document"
145
+
role="doc-endnotes">
146
+
<hr />
147
+
<ol>
148
+
<li id="fn1"><p>https://atproto.com/guides/data-repos<a href="#fnref1"
149
+
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
150
+
<li id="fn2"><p>https://atproto.com<a href="#fnref2"
151
+
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
152
+
<li id="fn3"><p>https://en.wikipedia.org/wiki/Decentralized_identifier<a
153
+
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
154
+
</ol>
155
+
</section></description>
156
+
<link>https://oppi.li/posts/mounting_the_atmosphere/</link>
157
+
<pubDate>Wed, 30 Jul 2025 20:25:00 +0000</pubDate>
158
+
<guid>https://oppi.li/posts/mounting_the_atmosphere/</guid>
159
+
</item>
160
+
<item>
15
161
<title>Configuring Jujutsu</title>
16
162
<description><p>There are a lot of reasons to use <a
17
163
href="https://github.com/jj-vcs/jj">jujutsu</a>, but this post is not
+17
docs/posts/index.html
+17
docs/posts/index.html
···
27
27
<tr>
28
28
<td class=table-post>
29
29
<div class="date">
30
+
30/07 — 2025
31
+
</div>
32
+
<a href="/posts/mounting_the_atmosphere" class="post-link">
33
+
<span class="post-link">Mounting The Atmosphere</span>
34
+
</a>
35
+
</td>
36
+
<td class=table-stats>
37
+
<span class="stats-number">
38
+
4.3
39
+
</span>
40
+
<span class=stats-unit>min</span>
41
+
</td>
42
+
</tr>
43
+
44
+
<tr>
45
+
<td class=table-post>
46
+
<div class="date">
30
47
24/05 — 2025
31
48
</div>
32
49
<a href="/posts/configuring_jujutsu" class="post-link">
+208
docs/posts/mounting_the_atmosphere/index.html
+208
docs/posts/mounting_the_atmosphere/index.html
···
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<link rel="stylesheet" href="/style.css">
5
+
<link rel="stylesheet" href="/syntax.css">
6
+
<meta charset="UTF-8">
7
+
<meta name="viewport" content="initial-scale=1">
8
+
<meta content="#ffffff" name="theme-color">
9
+
<meta name="HandheldFriendly" content="true">
10
+
<meta property="og:title" content="Mounting The Atmosphere">
11
+
<meta property="og:type" content="website">
12
+
<meta property="og:description" content="a static site {for, by, about} me ">
13
+
<meta property="og:url" content="https://oppi.li/posts/mounting_the_atmosphere">
14
+
<link rel="icon" type="image/x-icon" href="/favicon.png">
15
+
<title>Mounting The Atmosphere · oppi.li</title>
16
+
<body>
17
+
<div class="posts">
18
+
<div class="post">
19
+
<a href="/" class="post-end-link">Home</a>
20
+
<span>/</span>
21
+
<a href="/posts" class="post-end-link">Posts</a>
22
+
<span>/</span>
23
+
<a class="post-end-link">Mounting The Atmosphere</a>
24
+
<a class="stats post-end-link" href="https://tangled.sh/@oppi.li/site/raw/main/posts/mounting_the_atmosphere.md
25
+
">View Raw</a>
26
+
<div class="separator"></div>
27
+
<div class="date">
28
+
30/07 — 2025
29
+
<div class="stats">
30
+
<span class="stats-number">
31
+
60.34
32
+
</span>
33
+
<span class="stats-unit">cm</span>
34
+
 
35
+
<span class="stats-number">
36
+
4.3
37
+
</span>
38
+
<span class="stats-unit">min</span>
39
+
</div>
40
+
</div>
41
+
<h1>
42
+
Mounting The Atmosphere
43
+
</h1>
44
+
<div class="post-text">
45
+
<p><a href="https://tangled.sh/@oppi.li/pdsfs">pdsfs</a> is a tool that
46
+
mounts atproto PDS repositories as a FUSE filesystem.</p>
47
+
<p>A PDS repository<a href="#fn1" class="footnote-ref" id="fnref1"
48
+
role="doc-noteref"><sup>1</sup></a> contains all data published by a
49
+
user to the atmosphere<a href="#fn2" class="footnote-ref" id="fnref2"
50
+
role="doc-noteref"><sup>2</sup></a>. It is exportable as a CAR
51
+
(content-addressable archive) file. pdsfs is a tool that mounts this CAR
52
+
file as a readonly-FUSE filesystem, allowing quick and easy
53
+
exploration.</p>
54
+
<p>To motivate the need for such a program, we could begin by mounting a
55
+
repository:</p>
56
+
<pre><code>λ pdsfs oppi.li
57
+
mounted at "mnt"
58
+
hit enter to unmount and exit...</code></pre>
59
+
<p>oppi.li is my handle in the atmosphere. The tool does some hardwork
60
+
to determine the location of my PDS repository given my handle, but that
61
+
is not important. Let’s have a look around:</p>
62
+
<pre><code>λ ls mnt/
63
+
did:plc:qfpnj4og54vl56wngdriaxug/</code></pre>
64
+
<p>The <code>did:plc:stuff</code> is my DID<a href="#fn3"
65
+
class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a>.
66
+
Digging deeper:</p>
67
+
<pre><code>λ ls mnt/did\:plc\:qfpnj4og54vl56wngdriaxug/
68
+
app.bsky.actor.profile/ place.stream.chat.message/
69
+
app.bsky.actor.status/ place.stream.chat.profile/
70
+
app.bsky.feed.generator/ place.stream.key/
71
+
app.bsky.feed.like/ place.stream.livestream/
72
+
app.bsky.feed.post/ sh.tangled.actor.profile/
73
+
app.bsky.feed.repost/ sh.tangled.feed.reaction/
74
+
app.bsky.graph.block/ sh.tangled.feed.star/
75
+
app.bsky.graph.follow/ sh.tangled.graph.follow/
76
+
app.rocksky.album/ sh.tangled.knot/
77
+
app.rocksky.artist/ sh.tangled.knot.member/
78
+
.
79
+
.
80
+
.</code></pre>
81
+
<p>We have some data from the repository now. These are “collections”.
82
+
If I want to publish a post to Bluesky, I would write content to the
83
+
<code>app.bsky.feed.post</code> collection in my PDS. This will then be
84
+
indexed by a Bluesky appview (such as <a
85
+
href="https://bsky.app">bsky.app</a> or <a
86
+
href="https://zeppelin.social">zeppelin.social</a>) and show up under my
87
+
profile there.</p>
88
+
<p>pdsfs is kind enough to deserialize the in the PDS repository (stored
89
+
as CBOR normally) to JSON on the filesystem:</p>
90
+
<pre><code>λ cat sh.tangled.repo/3ljidbevrjh22 | jq
91
+
{
92
+
"$type": "sh.tangled.repo",
93
+
"addedAt": "2025-03-03T16:04:13Z",
94
+
"knot": "knot1.tangled.sh",
95
+
"name": "hello-world",
96
+
"owner": "did:plc:3danwc67lo7obz2fmdg6jxcr"
97
+
}</code></pre>
98
+
<p>Thanks pdsfs!</p>
99
+
<p>I publish my music listening habits to my PDS to the
100
+
<code>app.rocksky.scrobble</code> collection, because <a
101
+
href="https://rocksky.app">Rocksky</a> recognizes and indexes this
102
+
collection. I have wired up my personal navidrome instance to write data
103
+
of this form into my PDS everytime I listen to a track. Here are my top
104
+
artists in order:</p>
105
+
<pre><code>λ jq -r '.artist' app.rocksky.scrobble/* | sort | uniq -c | sort -nr
106
+
117 Thank You Scientist
107
+
45 FKJ
108
+
34 Covet
109
+
33 VOLA
110
+
23 Sam Cooke
111
+
22 Dark Tranquillity
112
+
21 Piero Piccioni
113
+
12 Bloodywood
114
+
11 Frank Sinatra
115
+
10 Dream Theater</code></pre>
116
+
<p>It is true, I love Sam Cooke.</p>
117
+
<p>pdsfs allows mounting multiple repositories at a time. Allow me to
118
+
introduce my friends:</p>
119
+
<pre><code>λ pdsfs icyphox.sh anil.recoil.org steveklabnik.com tangled.sh
120
+
using cached CAR file for...did:plc:hwevmowznbiukdf6uk5dwrrq
121
+
using cached CAR file for...did:plc:nhyitepp3u4u6fcfboegzcjw
122
+
download complete for...did:plc:3danwc67lo7obz2fmdg6jxcr
123
+
download complete for...did:plc:wshs7t2adsemcrrd4snkeqli
124
+
mounted at "mnt"
125
+
hit enter to unmount and exit...
126
+
127
+
# -- in a separate shell --
128
+
129
+
λ cat ./mnt/*/app.bsky.actor.profile/* \
130
+
| jq -r '"\(.displayName)\n\(.description)\n---"' \
131
+
| sed '/^$/d'
132
+
Steve Klabnik
133
+
#rustlang, #jj-vcs, atproto, shitposts, urbanism. I
134
+
contain multitudes. Working on #ruelang but just for
135
+
fun. Currently in Austin, TX, but from Pittsburgh.
136
+
Previously in Bushwick, the Mission, LA.
137
+
---
138
+
Anirudh Oppiliappan
139
+
building @tangled.sh — code collaboration platform built
140
+
on atproto helsinki, finland · https://anirudh.fi ·
141
+
(somewhat) effective altruist
142
+
---
143
+
Anil Madhavapeddy
144
+
Professor of Planetary Computing at the University of
145
+
Cambridge @cst.cam.ac.uk, where I co-lead the
146
+
@eeg.cl.cam.ac.uk, and am also to found at
147
+
@conservation.cam.ac.uk. Homepage at
148
+
https://anil.recoil.org
149
+
---
150
+
Tangled
151
+
https://tangled.sh is a git collaboration platform built
152
+
on atproto. Social coding, but for real this time!
153
+
Discord: chat.tangled.sh IRC: #tangled @ libera.chat
154
+
Built by @oppi.li & @icyphox.sh
155
+
---</code></pre>
156
+
<p>All my friends use <a href="https://tangled.sh">tangled.sh</a>, which
157
+
requires them to publish their ssh public key to their PDii (PDSes?).
158
+
Perhaps I would like to add their keys to my allowed_signers file to
159
+
verify their commit signatures:</p>
160
+
<pre><code>λ for dir in ./*/sh.tangled.publicKey;
161
+
do cat $dir/$(ls -r $dir | head -n1) | jq -r '.key';
162
+
done | tee allowed_signers
163
+
ssh-rsa AAAAB3NzaC1yc2EAAA...dHPqc= steveklabnik@DESKTOP-VV370NK
164
+
ssh-ed25519 AAAAC3NzaC1lZD...g9bAdk icy@wyndle
165
+
ssh-ed25519 AAAAC3NzaC1lZD...BqlM1u anil@recoil.org</code></pre>
166
+
<p>FUSE is quite liberating in that it allows you to represent anything
167
+
as a filesystem. When applications like <code>ls</code> and
168
+
<code>cat</code> are executed, the syscalls to <code>open</code> and
169
+
<code>read</code> are rerouted to your custom fs implementation (pdsfs
170
+
in this case). The custom fs implementation is free to as it pleases, in
171
+
fact the first iteration of pdsfs accessed the network for each
172
+
open/read call to fetch live data from PDii.</p>
173
+
<section id="footnotes" class="footnotes footnotes-end-of-document"
174
+
role="doc-endnotes">
175
+
<hr />
176
+
<ol>
177
+
<li id="fn1"><p>https://atproto.com/guides/data-repos<a href="#fnref1"
178
+
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
179
+
<li id="fn2"><p>https://atproto.com<a href="#fnref2"
180
+
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
181
+
<li id="fn3"><p>https://en.wikipedia.org/wiki/Decentralized_identifier<a
182
+
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
183
+
</ol>
184
+
</section>
185
+
186
+
</div>
187
+
188
+
<div class="intro">
189
+
Hi.
190
+
<div class="hot-links">
191
+
<a href="/index.xml" class="feed-button">Subscribe</a>
192
+
</div>
193
+
<p>I'm Akshay, programmer, pixel-artist & programming-language enthusiast.</p>
194
+
<p>I am currently building <a href="https://tangled.sh">tangled.sh</a> — a new social-enabled code-collaboration platform.</p>
195
+
<p>Reach out at oppili@libera.chat.</p>
196
+
</div>
197
+
198
+
<a href="/" class="post-end-link">Home</a>
199
+
<span>/</span>
200
+
<a href="/posts" class="post-end-link">Posts</a>
201
+
<span>/</span>
202
+
<a class="post-end-link">Mounting The Atmosphere</a>
203
+
<a class="stats post-end-link" href="https://tangled.sh/@oppi.li/site/raw/main/posts/mounting_the_atmosphere.md
204
+
">View Raw</a>
205
+
</div>
206
+
</div>
207
+
</body>
208
+
</html>
+151
posts/mounting_the_atmosphere.md
+151
posts/mounting_the_atmosphere.md
···
1
+
[pdsfs](https://tangled.sh/@oppi.li/pdsfs) is a tool that
2
+
mounts atproto PDS repositories as a FUSE filesystem.
3
+
4
+
A PDS repository[^0] contains all data published by a user to
5
+
the atmosphere[^1]. It is exportable as a CAR
6
+
(content-addressable archive) file. pdsfs is a tool that
7
+
mounts this CAR file as a readonly-FUSE filesystem, allowing
8
+
quick and easy exploration.
9
+
10
+
To motivate the need for such a program, we could begin by
11
+
mounting a repository:
12
+
13
+
λ pdsfs oppi.li
14
+
mounted at "mnt"
15
+
hit enter to unmount and exit...
16
+
17
+
oppi.li is my handle in the atmosphere. The tool does some
18
+
hardwork to determine the location of my PDS repository
19
+
given my handle, but that is not important. Let's have a
20
+
look around:
21
+
22
+
λ ls mnt/
23
+
did:plc:qfpnj4og54vl56wngdriaxug/
24
+
25
+
The `did:plc:stuff` is my DID[^2]. Digging deeper:
26
+
27
+
λ ls mnt/did\:plc\:qfpnj4og54vl56wngdriaxug/
28
+
app.bsky.actor.profile/ place.stream.chat.message/
29
+
app.bsky.actor.status/ place.stream.chat.profile/
30
+
app.bsky.feed.generator/ place.stream.key/
31
+
app.bsky.feed.like/ place.stream.livestream/
32
+
app.bsky.feed.post/ sh.tangled.actor.profile/
33
+
app.bsky.feed.repost/ sh.tangled.feed.reaction/
34
+
app.bsky.graph.block/ sh.tangled.feed.star/
35
+
app.bsky.graph.follow/ sh.tangled.graph.follow/
36
+
app.rocksky.album/ sh.tangled.knot/
37
+
app.rocksky.artist/ sh.tangled.knot.member/
38
+
.
39
+
.
40
+
.
41
+
42
+
We have some data from the repository now. These are
43
+
"collections". If I want to publish a post to Bluesky, I
44
+
would write content to the `app.bsky.feed.post` collection
45
+
in my PDS. This will then be indexed by a Bluesky appview
46
+
(such as [bsky.app](https://bsky.app) or
47
+
[zeppelin.social](https://zeppelin.social)) and show up
48
+
under my profile there.
49
+
50
+
pdsfs is kind enough to deserialize the in the PDS
51
+
repository (stored as CBOR normally) to JSON on the
52
+
filesystem:
53
+
54
+
λ cat sh.tangled.repo/3ljidbevrjh22 | jq
55
+
{
56
+
"$type": "sh.tangled.repo",
57
+
"addedAt": "2025-03-03T16:04:13Z",
58
+
"knot": "knot1.tangled.sh",
59
+
"name": "hello-world",
60
+
"owner": "did:plc:3danwc67lo7obz2fmdg6jxcr"
61
+
}
62
+
63
+
Thanks pdsfs!
64
+
65
+
I publish my music listening habits to my PDS to the
66
+
`app.rocksky.scrobble` collection, because
67
+
[Rocksky](https://rocksky.app) recognizes and indexes this
68
+
collection. I have wired up my personal navidrome instance
69
+
to write data of this form into my PDS everytime I listen to
70
+
a track. Here are my top artists in order:
71
+
72
+
λ jq -r '.artist' app.rocksky.scrobble/* | sort | uniq -c | sort -nr
73
+
117 Thank You Scientist
74
+
45 FKJ
75
+
34 Covet
76
+
33 VOLA
77
+
23 Sam Cooke
78
+
22 Dark Tranquillity
79
+
21 Piero Piccioni
80
+
12 Bloodywood
81
+
11 Frank Sinatra
82
+
10 Dream Theater
83
+
84
+
It is true, I love Sam Cooke.
85
+
86
+
pdsfs allows mounting multiple repositories at a time. Allow
87
+
me to introduce my friends:
88
+
89
+
λ pdsfs icyphox.sh anil.recoil.org steveklabnik.com tangled.sh
90
+
using cached CAR file for...did:plc:hwevmowznbiukdf6uk5dwrrq
91
+
using cached CAR file for...did:plc:nhyitepp3u4u6fcfboegzcjw
92
+
download complete for...did:plc:3danwc67lo7obz2fmdg6jxcr
93
+
download complete for...did:plc:wshs7t2adsemcrrd4snkeqli
94
+
mounted at "mnt"
95
+
hit enter to unmount and exit...
96
+
97
+
# -- in a separate shell --
98
+
99
+
λ cat ./mnt/*/app.bsky.actor.profile/* \
100
+
| jq -r '"\(.displayName)\n\(.description)\n---"' \
101
+
| sed '/^$/d'
102
+
Steve Klabnik
103
+
#rustlang, #jj-vcs, atproto, shitposts, urbanism. I
104
+
contain multitudes. Working on #ruelang but just for
105
+
fun. Currently in Austin, TX, but from Pittsburgh.
106
+
Previously in Bushwick, the Mission, LA.
107
+
---
108
+
Anirudh Oppiliappan
109
+
building @tangled.sh — code collaboration platform built
110
+
on atproto helsinki, finland · https://anirudh.fi ·
111
+
(somewhat) effective altruist
112
+
---
113
+
Anil Madhavapeddy
114
+
Professor of Planetary Computing at the University of
115
+
Cambridge @cst.cam.ac.uk, where I co-lead the
116
+
@eeg.cl.cam.ac.uk, and am also to found at
117
+
@conservation.cam.ac.uk. Homepage at
118
+
https://anil.recoil.org
119
+
---
120
+
Tangled
121
+
https://tangled.sh is a git collaboration platform built
122
+
on atproto. Social coding, but for real this time!
123
+
Discord: chat.tangled.sh IRC: #tangled @ libera.chat
124
+
Built by @oppi.li & @icyphox.sh
125
+
---
126
+
127
+
All my friends use [tangled.sh](https://tangled.sh), which
128
+
requires them to publish their ssh public key to their PDii
129
+
(PDSes?). Perhaps I would like to add their keys to my
130
+
allowed_signers file to verify their commit signatures:
131
+
132
+
λ for dir in ./*/sh.tangled.publicKey;
133
+
do cat $dir/$(ls -r $dir | head -n1) | jq -r '.key';
134
+
done | tee allowed_signers
135
+
ssh-rsa AAAAB3NzaC1yc2EAAA...dHPqc= steveklabnik@DESKTOP-VV370NK
136
+
ssh-ed25519 AAAAC3NzaC1lZD...g9bAdk icy@wyndle
137
+
ssh-ed25519 AAAAC3NzaC1lZD...BqlM1u anil@recoil.org
138
+
139
+
FUSE is quite liberating in that it allows you to represent
140
+
anything as a filesystem. When applications like `ls` and
141
+
`cat` are executed, the syscalls to `open` and `read` are
142
+
rerouted to your custom fs implementation (pdsfs in this
143
+
case). The custom fs implementation is free to as it
144
+
pleases, in fact the first iteration of pdsfs accessed the
145
+
network for each open/read call to fetch live data from
146
+
PDii.
147
+
148
+
149
+
[^0]: https://atproto.com/guides/data-repos
150
+
[^1]: https://atproto.com
151
+
[^2]: https://en.wikipedia.org/wiki/Decentralized_identifier