···33description: |
44 You thought Github was a social coding platform? Think again, get ready to tangle!
55 Built on atproto, tangled allows you to use your Bluesky identity on a (not quite yet) fully feldged git platform!
66-date: 2025-09-09
66+date: 2025-09-15
77authors:
88 - name: finxol
99tags:
···2020Embracing ATProto, part 1: Setting up a PDS
2121::
22222323-The PDS setup was an overall very smooth process.
2424-Bluesky and the AT Protocol are backed and built by a very competent team of well funded engineers for a few years already.
2323+The PDS setup and migration was an overall very smooth process.
2424+Bluesky and the AT Protocol are built by a very competent team of well funded engineers working on it for a few years already.
25252626## What's tangled?
27272828-Tangled, on the other hand, was started only about 8 months ago, at the start of 2025 by [two](https://tangled.sh/@oppi.li) [brothers](https://tangled.sh/@icyphox.sh).
2929-It's a "social-enabled git collaboration platform"
2828+[Tangled](https://tangled.sh), on the other hand, was started only about 8 months ago, at the start of 2025 by [two](https://tangled.sh/@oppi.li) [brothers](https://tangled.sh/@icyphox.sh).
2929+It's a "social-enabled git collaboration platform" built for decentralisation, ownership, and social coding.
30303131The platform has gained a lot of traction since, and the community is very much involved in the development, but for now tangled is still in alpha.
3232-That doesn't mean it's not usable yet.
3333-3232+That doesn't mean it's not usable yet, just that some things may break.
34333534### What's a Knot?
3635···3938In tangled, a knot is essentially a git server.
4039It's sort of like an atproto PDS in the sense that it's where your data—here your code—lives.
41404141+That's the main tangled-specific decentralised part, and what makes tangled special.
4242+You can keep ownership of your code, without cutting it off from a popular git platform by running it on a private Gitea or Gitlab server.
4343+4244## Setting up a Knot
43454444-## Setting up a Spindle
4646+Setting up my own knot took a little bit more work than for the PDS.
4747+The [official docs](https://tangled.sh/@tangled.sh/core/blob/master/docs/knot-hosting.md) give instructions for installation on a NixOS system.
4848+4949+## Spindles & CI
5050+5151+Another piece of lingo from the tangled world is "Spindle".
5252+5353+A Spindle is a very simple CI runner for tangled.
5454+It runs one Docker container per run, and gives access to any Nixpkg.
5555+The syntax is very similar to Github Actions workflow files, with some slight differences.
5656+5757+Since it's brand new, there isn't access to the thousands of pre-made reusable Github Actions,
5858+but access to the vast nixpkg catalog lets us do basically anything—with a couple extra steps from time to time.
5959+6060+### Self-hosting
6161+6262+As with everything else here, Spindles are self-hostable.
6363+There is a little gotcha for the moment though.
6464+6565+Since the Spindle runs a Docker container for each workflow run, it needs access to the Docker socket.
6666+They haven't got Docker-in-Docker working quite yet, so it means the Spindle needs to run natively outside a Docker container.
6767+6868+Although I don't like the idea, it's not really a problem for me.
6969+I prefer to have everything containerised on my servers to keep things tidy, but it's fine as a temporary solution until they get DinD working.
7070+7171+What's stopping me right now is rather that workflow runs would spin up a Docker container alongside all my other projects I'd rather not break.
7272+I'm aware it shouln't really be a problem, but it just bothers me.
7373+It is very much a me problem, so I'll figure out a way around it eventually.
7474+7575+## Migrating this blog
7676+7777+Migrating the repo over is the simplest things ever.
7878+7979+Just create a new repo on tangled—selecting your knot—set the remote on your local repo, and push to it!
8080+If you specified the knot correctly when creating your repo, it should now live directly on your Knot.
8181+8282+<img src="/posts/embracing-atproto-pt2/new-repo.png" alt="Select your new knot when creating a repo" width="80%" style="margin: auto;" />
8383+8484+You can now use git just as you normally do!
8585+8686+### CI
8787+8888+Migrating CI takes a tiny bit more work to migrate.
8989+I had a Github Action workflow to automatically deploy this blog to Deno Deploy on push.
9090+9191+<details class="minor-callout">
9292+9393+<summary>Here's the full file if you're curious.</summary>
9494+9595+```yaml
9696+name: deno-deploy
9797+on:
9898+ push:
9999+ branches:
100100+ - main
101101+jobs:
102102+ deploy:
103103+ runs-on: ubuntu-latest
104104+ permissions:
105105+ id-token: write # Needed for auth with Deno Deploy
106106+ contents: read # Needed to clone the repository
107107+ steps:
108108+ - uses: actions/checkout@v3
109109+110110+ - uses: pnpm/action-setup@v4
111111+ name: Install pnpm
112112+ with:
113113+ run_install: false
114114+115115+ - uses: actions/setup-node@v3
116116+ with:
117117+ node-version: 22
118118+ cache: pnpm
119119+120120+ - run: pnpm install
121121+122122+ - run: pnpm generate
123123+124124+ - name: Deploy to Deno Deploy
125125+ uses: denoland/deployctl@v1
126126+ with:
127127+ project: finxol-blog
128128+ entrypoint: https://deno.land/std@0.140.0/http/file_server.ts
129129+ root: .output/public
130130+```
131131+132132+</details>
133133+134134+Let's start off very easy by adapting the triggers.
135135+Just [follow the docs](https://tangled.sh/@tangled.sh/core/blob/master/docs/spindle/pipeline.md), and set the same trigger conditions.
136136+137137+```yaml
138138+when:
139139+ - event: ["push"]
140140+ branch: ["main"]
141141+```
142142+143143+I'll have a look at branch deploys later.
144144+It needs a bit more manual work since the official GH Action doesn't do it for us.
145145+146146+Since spindles work slightly differently to Github Actions runners, we need to give it a list of dependencies to install.
147147+It's similar to the setup steps in the GH workflow to install node and pnpm.
148148+149149+```yaml
150150+dependencies:
151151+ nixpkgs:
152152+ - deno
153153+ - nodejs
154154+ - pnpm
155155+ - python3
156156+ - gnused
157157+```
158158+159159+This bit took a bit of trial and error, as you might notice from the `python3` and `gnused` dependencies.
160160+161161+I'd initially set the dependencies to what I set up in the GH workflow, `nodejs` and `pnpm`, plus `deno` to be able to use the `deployctl` cli tool.
162162+But running that gave a few errors.
163163+This blog uses Nuxt Content to generate HTML from my Markdown files, and Nuxt Content itself uses `better-sqlite3`, which itself needs python and sed in its post-install script.
164164+Adding the corresponding nixpkgs in the dependencies array fixes this easily.
165165+166166+Now we can get to the actual steps of the workflow.
167167+168168+Since we don't have access to the existing Github Actions, there's a few sections that needed adapting or manual work.
169169+The install and generate steps are exactly the same, but the deploy step changes.
170170+171171+To replace the official Deno Deploy GH Action, we can directly use their `deployctl` cli tool, and give it the appropriate parametres.
172172+173173+I also used this as an excuse to using the `jsr:@std/http/file-server` entrypoint instead of the deno.land url style.
174174+175175+```yaml
176176+steps:
177177+ - name: Install dependencies
178178+ command: |
179179+ pnpm install
180180+181181+ - name: Generate static site
182182+ command: |
183183+ pnpm generate
184184+185185+ - name: Install deployctl
186186+ command: |
187187+ deno install -gArf jsr:@deno/deployctl
188188+189189+ - name: Deploy to Deno Deploy
190190+ command: |
191191+ cd .output/public
192192+ ~/.deno/bin/deployctl deploy --project finxol-blog --entrypoint jsr:@std/http/file-server --include=. --prod
193193+```
194194+195195+Lastly, don't forget to give the workflow permission to deploy by giving it a `DENO_DEPLOY_TOKEN` in the secrets!
196196+Since Deno Deploy integrates only with Github, the permission won't be given automatically here.
197197+198198+199199+200200+<details class="minor-callout">
201201+202202+<summary class="text-stone-500">Here is the full spindle workflow file.</summary>
203203+204204+```yaml
205205+when:
206206+ - event: ["push", "pull_request"]
207207+ branch: ["main"]
208208+209209+dependencies:
210210+ nixpkgs:
211211+ - deno
212212+ - nodejs
213213+ - pnpm
214214+ - python3
215215+ - gnused
216216+217217+engine: "nixery"
218218+219219+steps:
220220+ - name: Install dependencies
221221+ command: |
222222+ pnpm install
223223+224224+ - name: Generate static site
225225+ command: |
226226+ pnpm generate
227227+228228+ - name: Install deployctl
229229+ command: |
230230+ deno install -gArf jsr:@deno/deployctl
231231+232232+ - name: Deploy to Deno Deploy
233233+ command: |
234234+ cd .output/public
235235+ ~/.deno/bin/deployctl deploy --project finxol-blog --entrypoint jsr:@std/http/file-server --include=. --prod
236236+```
237237+238238+</details>
239239+240240+It took me a little bit more time to get things working right.
241241+I found a little bug in the tangled UI regarding spindle runs.
242242+243243+When pushing to the official knot, the workflow got picked up fine by the official spindle, and showed up in the UI.
244244+When I pushed to my knot however, the official spindle ran the workflow, but it didn't show in the UI.
245245+It took me a while to realise what was going on.
246246+247247+I thought the spindle wasn't picking up the workflow, but the bug was simply with showing the info in the UI.
248248+[Anirudh](https://tangled.sh/@icyphox.sh) was very quick to find the cause and implement a fix.
249249+250250+And just like that, this blog gets deployed automatically on push, using the tangled spindle!