the ugly shellscript powering https://oppi.li

new post: mounting the atmosphere

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 2e64ba08 5e3d1669

verified
Changed files
+539 -17
docs
posts
mounting_the_atmosphere
posts
+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
··· 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>&lt;p&gt;&lt;a href="https://tangled.sh/@oppi.li/pdsfs"&gt;pdsfs&lt;/a&gt; is a tool that 17 + mounts atproto PDS repositories as a FUSE filesystem.&lt;/p&gt; 18 + &lt;p&gt;A PDS repository&lt;a href="#fn1" class="footnote-ref" id="fnref1" 19 + role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; contains all data published by a 20 + user to the atmosphere&lt;a href="#fn2" class="footnote-ref" id="fnref2" 21 + role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;. 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.&lt;/p&gt; 25 + &lt;p&gt;To motivate the need for such a program, we could begin by mounting a 26 + repository:&lt;/p&gt; 27 + &lt;pre&gt;&lt;code&gt;λ pdsfs oppi.li 28 + mounted at &amp;quot;mnt&amp;quot; 29 + hit enter to unmount and exit...&lt;/code&gt;&lt;/pre&gt; 30 + &lt;p&gt;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:&lt;/p&gt; 33 + &lt;pre&gt;&lt;code&gt;λ ls mnt/ 34 + did:plc:qfpnj4og54vl56wngdriaxug/&lt;/code&gt;&lt;/pre&gt; 35 + &lt;p&gt;The &lt;code&gt;did:plc:stuff&lt;/code&gt; is my DID&lt;a href="#fn3" 36 + class="footnote-ref" id="fnref3" role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. 37 + Digging deeper:&lt;/p&gt; 38 + &lt;pre&gt;&lt;code&gt;λ 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 + .&lt;/code&gt;&lt;/pre&gt; 52 + &lt;p&gt;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 + &lt;code&gt;app.bsky.feed.post&lt;/code&gt; collection in my PDS. This will then be 55 + indexed by a Bluesky appview (such as &lt;a 56 + href="https://bsky.app"&gt;bsky.app&lt;/a&gt; or &lt;a 57 + href="https://zeppelin.social"&gt;zeppelin.social&lt;/a&gt;) and show up under my 58 + profile there.&lt;/p&gt; 59 + &lt;p&gt;pdsfs is kind enough to deserialize the in the PDS repository (stored 60 + as CBOR normally) to JSON on the filesystem:&lt;/p&gt; 61 + &lt;pre&gt;&lt;code&gt;λ cat sh.tangled.repo/3ljidbevrjh22 | jq 62 + { 63 + &amp;quot;$type&amp;quot;: &amp;quot;sh.tangled.repo&amp;quot;, 64 + &amp;quot;addedAt&amp;quot;: &amp;quot;2025-03-03T16:04:13Z&amp;quot;, 65 + &amp;quot;knot&amp;quot;: &amp;quot;knot1.tangled.sh&amp;quot;, 66 + &amp;quot;name&amp;quot;: &amp;quot;hello-world&amp;quot;, 67 + &amp;quot;owner&amp;quot;: &amp;quot;did:plc:3danwc67lo7obz2fmdg6jxcr&amp;quot; 68 + }&lt;/code&gt;&lt;/pre&gt; 69 + &lt;p&gt;Thanks pdsfs!&lt;/p&gt; 70 + &lt;p&gt;I publish my music listening habits to my PDS to the 71 + &lt;code&gt;app.rocksky.scrobble&lt;/code&gt; collection, because &lt;a 72 + href="https://rocksky.app"&gt;Rocksky&lt;/a&gt; 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:&lt;/p&gt; 76 + &lt;pre&gt;&lt;code&gt;λ jq -r &amp;#39;.artist&amp;#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&lt;/code&gt;&lt;/pre&gt; 87 + &lt;p&gt;It is true, I love Sam Cooke.&lt;/p&gt; 88 + &lt;p&gt;pdsfs allows mounting multiple repositories at a time. Allow me to 89 + introduce my friends:&lt;/p&gt; 90 + &lt;pre&gt;&lt;code&gt;λ 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 &amp;quot;mnt&amp;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 &amp;#39;&amp;quot;\(.displayName)\n\(.description)\n---&amp;quot;&amp;#39; \ 102 + | sed &amp;#39;/^$/d&amp;#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;amp; @icyphox.sh 126 + ---&lt;/code&gt;&lt;/pre&gt; 127 + &lt;p&gt;All my friends use &lt;a href="https://tangled.sh"&gt;tangled.sh&lt;/a&gt;, 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:&lt;/p&gt; 131 + &lt;pre&gt;&lt;code&gt;λ for dir in ./*/sh.tangled.publicKey; 132 + do cat $dir/$(ls -r $dir | head -n1) | jq -r &amp;#39;.key&amp;#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&lt;/code&gt;&lt;/pre&gt; 137 + &lt;p&gt;FUSE is quite liberating in that it allows you to represent anything 138 + as a filesystem. When applications like &lt;code&gt;ls&lt;/code&gt; and 139 + &lt;code&gt;cat&lt;/code&gt; are executed, the syscalls to &lt;code&gt;open&lt;/code&gt; and 140 + &lt;code&gt;read&lt;/code&gt; 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.&lt;/p&gt; 144 + &lt;section id="footnotes" class="footnotes footnotes-end-of-document" 145 + role="doc-endnotes"&gt; 146 + &lt;hr /&gt; 147 + &lt;ol&gt; 148 + &lt;li id="fn1"&gt;&lt;p&gt;https://atproto.com/guides/data-repos&lt;a href="#fnref1" 149 + class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 150 + &lt;li id="fn2"&gt;&lt;p&gt;https://atproto.com&lt;a href="#fnref2" 151 + class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 152 + &lt;li id="fn3"&gt;&lt;p&gt;https://en.wikipedia.org/wiki/Decentralized_identifier&lt;a 153 + href="#fnref3" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; 154 + &lt;/ol&gt; 155 + &lt;/section&gt;</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>&lt;p&gt;There are a lot of reasons to use &lt;a 17 163 href="https://github.com/jj-vcs/jj"&gt;jujutsu&lt;/a&gt;, but this post is not
+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
··· 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 + &nbsp 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 &quot;mnt&quot; 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 + &quot;$type&quot;: &quot;sh.tangled.repo&quot;, 93 + &quot;addedAt&quot;: &quot;2025-03-03T16:04:13Z&quot;, 94 + &quot;knot&quot;: &quot;knot1.tangled.sh&quot;, 95 + &quot;name&quot;: &quot;hello-world&quot;, 96 + &quot;owner&quot;: &quot;did:plc:3danwc67lo7obz2fmdg6jxcr&quot; 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 &#39;.artist&#39; 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 &quot;mnt&quot; 125 + hit enter to unmount and exit... 126 + 127 + # -- in a separate shell -- 128 + 129 + λ cat ./mnt/*/app.bsky.actor.profile/* \ 130 + | jq -r &#39;&quot;\(.displayName)\n\(.description)\n---&quot;&#39; \ 131 + | sed &#39;/^$/d&#39; 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 &amp; @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 &#39;.key&#39;; 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
··· 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