# Socially self-hosting source code with Tangled on Bluesky

*2025-03-08 — note*


I've been an avid user of [GitHub](https://github.com) since its launch, and it really has revolutionised how communities come together to work on open source. In recent years though, I find myself utterly overwhelmed by its notifications and want to experiment with [alternative workflows](https://www.offlineimap.org/github/2016/03/08/github-pr-suck.html). This experimentation also has a more serious undertone due to the increasing need for [data sovereignty](https://www.boell.de/en/2025/01/24/trump-and-big-tech-europes-sovereignty-stake) and so I'm starting to move my source code to self-hosted solutions that are less reliant on centralised services.

This has also come up persistently over the years in the [OCaml](https://ocaml.org) community, with questions over why participation in packaging [requires a GitHub account](https://discuss.ocaml.org/t/publishing-without-github/3232) ever since the [early days](https://anil.recoil.org/notes/opam-1-1-beta) of opam. I've never found a good answer... until now, with the launch of an exciting [new service](https://tangled.sh) that's built over the same protocol that [Bluesky](https://bsky.app) uses.
As I [noted](https://anil.recoil.org/notes/atproto-for-fun-and-blogging) a few weeks ago, the [ATProto](https://atproto.com/) can be used for more than just microblogging. It can also be an _identity_ layer, across which other applications can be built which reuse the social fabric from Bluesky accounts.

"[Tangled](https://tangled.sh)" is a new service launched (just yesterday!) by [opilli](https://tangled.sh/@oppili.bsky.social) and [icyphox](https://tangled.sh/@icyphox.sh) to manage Git repositories. I'm having a lot of fun trying it out, even in its early alpha stages!  The coolest thing about Tangled is that you can self-host your own [knots](https://blog.tangled.sh/intro), which control where the source code repositories are actually stored.


## Self hosting my own Tangled knot

I set up one of the first knots on the network on `git.recoil.org`, and can now directly share my source code online without depending on GitHub!  For example, this is the [knot-docker](https://tangled.sh/@anil.recoil.org/knot-docker) container config which you can use to deploy your own version of this.

<a href="https://tangled.sh/@anil.recoil.org/knot-docker"> <figure class="image-center"><img src="/images/tangled-ss-1.webp" alt="" title="" loading="lazy" srcset="/images/tangled-ss-1.768.webp 768w, /images/tangled-ss-1.640.webp 640w, /images/tangled-ss-1.480.webp 480w, /images/tangled-ss-1.320.webp 320w, /images/tangled-ss-1.1920.webp 1920w, /images/tangled-ss-1.1600.webp 1600w, /images/tangled-ss-1.1440.webp 1440w, /images/tangled-ss-1.1280.webp 1280w, /images/tangled-ss-1.1024.webp 1024w"><figcaption></figcaption></figure> </a>

It looks pretty similar to GitHub doesn't it? The first key difference is the login on the top-right, which is the same as my [anil.recoil.org](https://bsky.app/profile/anil.recoil.org) account.  Once you're logged in, the other difference shows up when creating a new Git repository.

<figure class="image-center"><img src="/images/tangled-ss-2.webp" alt="" title="" loading="lazy" srcset="/images/tangled-ss-2.768.webp 768w, /images/tangled-ss-2.640.webp 640w, /images/tangled-ss-2.480.webp 480w, /images/tangled-ss-2.320.webp 320w, /images/tangled-ss-2.1920.webp 1920w, /images/tangled-ss-2.1600.webp 1600w, /images/tangled-ss-2.1440.webp 1440w, /images/tangled-ss-2.1280.webp 1280w, /images/tangled-ss-2.1024.webp 1024w"><figcaption></figcaption></figure>

As you can see, you can not only select the name of the repository, but also _where_ it's going to be stored. I can either put it on the central Tangled knot, or stick it on my own Recoil one.  After this, the user experience of cloning is as simple as:

```
git clone https://tangled.sh/@anil.recoil.org/knot-docker
git clone git@git.recoil.org:anil.recoil.org/knot-docker
```

In the first case, the central tangled web server proxies the Git contents over HTTP, and for SSH I can just connect directly to my own server.  Inside my Knot container, we can see where the Git repositories are stored:

```
/home/git # ls -1
did:plc:nhyitepp3u4u6fcfboegzcjw
knotserver.db
knotserver.db-shm
knotserver.db-wal
log
```

The `did:` directory is actually my 'decentralised identifier' from the ATProto, which we can verify by looking up the [DNS atproto TXT](https://bsky.social/about/blog/4-28-2023-domain-handle-tutorial) record for my domain:

```
$ dig txt _atproto.anil.recoil.org
;; ANSWER SECTION:
_atproto.anil.recoil.org. 10799 IN      TXT     "did=did:plc:nhyitepp3u4u6fcfboegzcjw"
```

And then if we navigate into that directory, we can see there are just normal bare git repositories stored on my server.

```
/home/git/did:plc:nhyitepp3u4u6fcfboegzcjw/knot-docker # ls -la
total 24
drwxr-sr-x    4 git      git           4096 Mar  8 19:02 .
drwxr-sr-x    4 git      git           4096 Mar  8 18:23 ..
-rw-r--r--    1 git      git             21 Mar  8 18:01 HEAD
-rw-r--r--    1 git      git             36 Mar  8 18:01 config
drwxr-sr-x   17 git      git           4096 Mar  8 19:02 objects
drwxr-sr-x    4 git      git           4096 Mar  8 18:01 refs
```

This makes the core of Tangled very safe to use, even if the service disappears: I maintain the actual git repositories myself, so I can (e.g.) mirror them to GitHub via a simple cron script.

## Collaboration is as simple as Bluesky

Tangled has only been out for about a day, so I coopted fellow Recoiler [Nick Ludlam](https://nick.recoil.org) to create an account. I added his [handle](https://bsky.app/profile/nick.recoil.org) over to the Recoil knot, and that's all it took for him to be able to create repositories on our server.

<figure class="image-center"><img src="/images/tangled-ss-5.webp" alt="" title="" loading="lazy" srcset="/images/tangled-ss-5.768.webp 768w, /images/tangled-ss-5.640.webp 640w, /images/tangled-ss-5.480.webp 480w, /images/tangled-ss-5.320.webp 320w, /images/tangled-ss-5.1600.webp 1600w, /images/tangled-ss-5.1440.webp 1440w, /images/tangled-ss-5.1280.webp 1280w, /images/tangled-ss-5.1024.webp 1024w"><figcaption></figcaption></figure>

I can also just add people directly to a particular repository, as you can see from the one below on his profile.

<a href="https://tangled.sh/@nick.recoil.org"> <figure class="image-center"><img src="/images/tangled-ss-3.webp" alt="" title="" loading="lazy" srcset="/images/tangled-ss-3.768.webp 768w, /images/tangled-ss-3.640.webp 640w, /images/tangled-ss-3.480.webp 480w, /images/tangled-ss-3.320.webp 320w, /images/tangled-ss-3.1920.webp 1920w, /images/tangled-ss-3.1600.webp 1600w, /images/tangled-ss-3.1440.webp 1440w, /images/tangled-ss-3.1280.webp 1280w, /images/tangled-ss-3.1024.webp 1024w"><figcaption></figcaption></figure> </a>

## The issue metadata is also distributed

The real lockin to code repository management though, is the metadata around the repository; things like issues, comments and so on. Tangled makes it possible to decentralise where is this stored [without needing a central Forge](https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/git-no-forge/), by relaying it all via the ATProto.
Let's take a look at how this works.

I [created an issue](https://tangled.sh/@anil.recoil.org/knot-docker/issues/1) on knot-docker, and it looks very similar to a GitHub issue. Zicklag on `#tangled` pointed me to the [PDSLS](https://pdsls.dev/) public ATProto browser with which you can browse the actual ATProto records. I can start from my [DID record](https://pdsls.dev/at://did:plc:nhyitepp3u4u6fcfboegzcjw) and look for the [sh.tangled.repo.issue](https://pdsls.dev/at://did:plc:nhyitepp3u4u6fcfboegzcjw/sh.tangled.repo.issue) collection, and find the [issue URL from earlier](https://pdsls.dev/at://did:plc:nhyitepp3u4u6fcfboegzcjw/sh.tangled.repo.issue/3ljvbt4zni322).  I then prodded [Nick Ludlam](https://nick.recoil.org) to leave a comment on the issue, and you can see his [sh.tangled.repo.issue.comment](https://pdsls.dev/at://did:plc:dr3wsy7hlzgyanewhbw7fj5g/sh.tangled.repo.issue.comment/3ljvdsrlckj22) in the relay as well.

<a href="https://pdsls.dev/at://did:plc:nhyitepp3u4u6fcfboegzcjw/sh.tangled.repo.issue/3ljvbt4zni322"> <figure class="image-center"><img src="/images/tangled-ss-4.webp" alt="" title="" loading="lazy" srcset="/images/tangled-ss-4.768.webp 768w, /images/tangled-ss-4.640.webp 640w, /images/tangled-ss-4.480.webp 480w, /images/tangled-ss-4.320.webp 320w, /images/tangled-ss-4.1600.webp 1600w, /images/tangled-ss-4.1440.webp 1440w, /images/tangled-ss-4.1280.webp 1280w, /images/tangled-ss-4.1024.webp 1024w"><figcaption></figcaption></figure> </a>

Even the [repository stars](https://bsky.app/profile/tangled.sh/post/3ljv6wpioxc2q) are on the relay; see for example [this](https://pdsls.dev/at://did:plc:nhyitepp3u4u6fcfboegzcjw/sh.tangled.feed.star/3ljvbtbrhew22) entry for [knot-docker](https://pdsls.dev/at://did:plc:nhyitepp3u4u6fcfboegzcjw/sh.tangled.repo/3ljv45bhfql22) that I did. The Tangled developers just added support for stars [a few hours ago](https://tangled.sh/@tangled.sh/core/commit/662bd012caec9c2bd2a15e1dcfe184d5b2c49ff9#file-lexicons%2fstar.json), and that changeset is a nice way to see how to add a new lexicon entry.

[Samuel Wedgwood](https://bsky.app/profile/wedg.dev) then reminded me of his project a few years ago to run [git pull requests over Matrix chat](https://anil.recoil.org/ideas/version-control-matrix). It would indeed be very cool if the pull request model on Tangled evolved into something more message-oriented like [git-send-email](https://git-scm.com/docs/git-send-email), in order to let us try out more personalised workflows than GitHub PRs.

## Why this fits in so well with the rest of Bluesky

The ATProto developers also released their [roadmap for early 2025](https://docs.bsky.app/blog/2025-protocol-roadmap-spring) today, and it aligns really well with some of the productions features I would need to completely shift over to a service like Tangled.

The first, and most vital one, is [auth scopes](https://docs.bsky.app/blog/2025-protocol-roadmap-spring#auth-scopes) to control the permissions of an app password to only certain operations. Once this is in the protocol, then a client to manage Tangled repositories could use a differently privileged password from the main social client.

Secondly, [privately shared data](https://docs.bsky.app/blog/2025-protocol-roadmap-spring#privately-shared-data-and-e2ee-dms) and [encrypted DMs using MLS](https://www.ietf.org/blog/mls-secure-and-usable-end-to-end-encryption/) point to how private code repositories could work. [Srinivasan Keshav](https://svr-sk818-web.cl.cam.ac.uk/keshav/wiki/index.php/Main_Page) and I were discussing the difficulty of access-controlled replication over the Internet just yesterday, and I'm starting to believe that ATProto has the right balance of ergonomics and good design to make solving this problem much, much easier.

If you'd like to try this out, then the [Knot Docker](https://tangled.sh/@anil.recoil.org/knot-docker/) repository welcomes your issues\!


<small class="credits">

Many thanks to Zicklag and icyphox on [tangled IRC](https://web.libera.chat/#tangled) for helping me out with debugging the Knot setup and [fixing bugs in real-time](https://tangled.sh/@tangled.sh/core/commit/477da124ad0bdeeab5b621b81999683256ab7a4b). 12th Mar 2025: updated with [Samuel Wedgwood](https://bsky.app/profile/wedg.dev) comments.

</small>
Synopsis: Self-host source code with Tangled on Bluesky for decentralized Git repositories.
Words: 1104
DOI: 10.59350/r80vb-7b441

## Related

- [.plan-26-23: Earth Embeddings, Emails Everywhere, and ERRNOOOs](https://anil.recoil.org/notes/2026w23) (note, 2026-06-07)
- [Tangled, or federated enough git](https://digitalflapjack.com/weeknotes/tangled/) (feed, 2026-06-01)
- [Rewilding the Web: my workshop report from Edinburgh](https://anil.recoil.org/notes/rewilding-the-web-report) (note, 2026-05-30)
- [.plan-26-17: Unwedging kernels, dogfood deployments, and managing beef leakage](https://anil.recoil.org/notes/2026w17) (note, 2026-04-26)
- [.plan-26-15: Banyan trees, (anti)botnets and Bose-Einstein bases](https://anil.recoil.org/notes/2026w15) (note, 2026-04-12)
- [AoAH Day 23: Unpac unifies git branching with package management](https://anil.recoil.org/notes/aoah-2025-23) (note, 2025-12-23)
- [Dear ACM, you're doing AI wrong but you can still get it right](https://anil.recoil.org/notes/acm-ai-recs) (note, 2025-12-22)
- [AoAH Day 11: HTTP Cookies and vibing RFCs for breakfast](https://anil.recoil.org/notes/aoah-2025-11) (note, 2025-12-10)
- [Publish, Review, Curate to upend scholarly publishing](https://anil.recoil.org/notes/coar-prc) (note, 2025-12-08)
- [AoAH Day 5: Bytesrw Eio adapters and automating opam metadata](https://anil.recoil.org/notes/aoah-2025-5) (note, 2025-12-05)
- [AoAH Day 1: Building a Base32 Crockford library in OCaml](https://anil.recoil.org/notes/aoah-2025-1) (note, 2025-12-01)
- [Four Ps for Building Massive Collective Knowledge Systems](https://anil.recoil.org/notes/principles-for-collective-knowledge) (note, 2025-11-23)
- [mlgpx is the first Tangled-hosted package available on opam](https://anil.recoil.org/notes/tangled-and-ci) (note, 2025-08-17)
- [Using AT Proto for more than just Bluesky posts](https://anil.recoil.org/notes/atproto-for-fun-and-blogging) (note, 2025-02-11)
- [Decentralised Capability-based Code Collaboration using Matrix](https://anil.recoil.org/ideas/version-control-matrix) (idea, 2022-01-01)
- [OPAM 1.1 beta available, with pretty colours](https://anil.recoil.org/notes/opam-1-1-beta) (note, 2013-09-20)

---
Canonical: https://anil.recoil.org/notes/disentangling-git-with-bluesky
Type: note
License: CC BY 4.0 <https://creativecommons.org/licenses/by/4.0/>
Tags: selfhosting, identity, distributed, security, docker, bluesky, ocaml
