{
  "$type": "site.standard.document",
  "canonicalUrl": "https:/finxol.eu/posts/embracing-atproto-pt-2-tangled-knot",
  "description": "You thought Github was a social coding platform? Think again, and get ready to tangle!\nBuilt on atproto, tangled allows you to use your Bluesky/atproto identity on a (not quite yet) fully feldged git platform!\n",
  "path": "/posts/embracing-atproto-pt-2-tangled-knot",
  "publishedAt": "2025-09-17T00:00:00.000Z",
  "site": "at://did:plc:hpmpe3pzpdtxbmvhlwrevhju/site.standard.publication/3mndozltfas27",
  "tags": [
    "atproto",
    "self-hosting"
  ],
  "textContent": "import Bookmark from \"../../components/Bookmark.astro\";\n\nI recently set up my own atproto PDS, for use with Bluesky and all other atproto apps.\nIf you already feel lost, check out last week's post where I quickly explain what atproto is,\nroughly how it works, and the steps I followed to get my PDS running.\n\n<Bookmark url=\"/posts/embracing-atproto-pt-1-hosting-pds\">\n  Embracing ATProto, part 1: Setting up a PDS\n</Bookmark>\n\nThe PDS setup and migration was an overall very smooth process.\nBluesky and the AT Protocol are built by a very competent team of well funded engineers who've been working on it for a few years already.\n\nWhat's tangled?\n\nTangled, on the other hand, was started only about 8 months ago, at the start of 2025 by two brothers.\nIt's a \"social-enabled git collaboration platform\" built for decentralisation, ownership, and social coding.\n\nThe 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.\nThat doesn't mean it's not usable yet, simply that some things may break.\n\nWhat's a Knot?\n\nJust like plain atproto, tangled has some lingo of its own.\n\nIn tangled, a knot is essentially an atproto-enabled git server.\nIt's sort of like a PDS in the sense that it's where your data—here your code—lives.\n\nThat's the main tangled-specific decentralised part, and what makes tangled special.\nYou can keep ownership of your code, without cutting it off from a popular git platform—which\nis a side effect of running a private Gitea or Gitlab server.\n\nSetting up a Knot\n\nSetting up my own knot took a little bit more work than for the PDS.\n\nThe official docs give instructions for installation on a NixOS system,\nbut I'm not running NixOS on my server.\nLuckily, they also provide a community-maintained Docker install process.\n\nAt the top of the README that serves as a documentation page, they talk about a pre-built image to use.\nPerfect!\nThat's exactly what I'm looking for.\nJust need to spin up the container and we're done!\n\nNot quite, unfortunately...\n\nI tried that route, added my knot on the tangled UI, but couldn't get it verified.\nI spent way too long trying to debug the parts I control, mainly the Caddy reverse proxy rules.\nIt turns out the pre-built image was just out of date, and rebuilding it myself fixed it immediately...\n\nUltimately, setting up a knot isn't all that hard.\nI just ran into a slightly stupid version mismatch problem a closer inspection could've revealed earlier.\n\nSpindles & CI\n\nAnother piece of lingo from the tangled world is \"Spindle\".\n\nA Spindle is a very simple CI runner for tangled.\nIt spins up one Docker container per run, and gives access to any Nixpkg.\nThe syntax is very similar to Github Actions workflow files, with some slight differences.\n\nSince it's brand new, there isn't access to the thousands of pre-made reusable Github Actions,\nbut access to the vast nixpkg catalog lets us do basically anything—with a couple extra steps from time to time.\n\nSelf-hosting\n\nAs with everything else here, Spindles are self-hostable.\nThere is a little gotcha for the moment though.\n\nSince the Spindle runs a Docker container for each workflow run, it needs access to the Docker socket.\nThey haven't got Docker-in-Docker working quite yet, so it means the Spindle needs to run natively outside a Docker container.\n\nAlthough I don't like the idea, it's not really a problem for me.\nI 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.\n\nWhat'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.\nI'm aware it shouln't really be a problem, but it just bothers me.\nIt is very much a me problem, so I'll figure out a way around it eventually.\n\nMigrating this blog\n\nMigrating the repo over is the simplest things ever.\n\nJust create a new repo on tangled—making sure to select your knot, set the remote on your local repo, and push to it!\nIf you specified the knot correctly when creating your repo, the repo should now live directly on your Knot.\n\n<img\n  src=\"/posts/embracing-atproto-pt2/new-repo.png\"\n  alt=\"Select your new knot when creating a repo\"\n  width=\"80%\"\n  style=\"margin: auto;\"\n/>\n\nYou can now use git just as you normally do!\n\nCI for auto-deploy\n\nMigrating CI takes a tiny bit more work to migrate.\nI had a Github Action workflow to automatically deploy this blog to Deno Deploy on push.\n\n<details class=\"minor-callout\">\n\n<summary>Here's the full file if you're curious.</summary>\n\n</details>\n\nLet's start off very easy by adapting the triggers.\nJust follow the docs, and set the same trigger conditions.\n\nI'll have a look at branch deploys later.\nIt needs a bit more manual work since the official GH Action doesn't handle it for us.\n\nSince spindles work slightly differently to Github Actions runners, we need to give it a list of dependencies to install.\nIt's similar to the setup steps in the GH workflow to install node and pnpm.\n\nThis bit took a bit of trial and error, as you might notice from the python3 and gnused dependencies.\n\nI'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.\nBut running that gave a few errors.\nThis 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.\nAdding the corresponding nixpkgs in the dependencies array fixes this easily.\n\nNow we can get to the actual steps of the workflow.\n\nSince we don't have access to the existing Github Actions, there's a couple sections that needed adapting or manual work.\nThe install and generate steps are exactly the same, but the deploy step changes.\n\nTo replace the official Deno Deploy GH Action, we can directly use their deployctl cli tool, and give it the appropriate parametres.\n\nI also used this as an excuse to switch to the jsr:@std/http/file-server entrypoint instead of the deno.land url style.\n\nLastly, don't forget to give the workflow permission to deploy by giving it a DENO_DEPLOY_TOKEN in the secrets!\nSince Deno Deploy integrates only with Github, the permission won't be given automatically here.\n\n<details class=\"minor-callout\">\n\n<summary class=\"text-stone-500\">Here is the full spindle workflow file.</summary>\n\n</details>\n\nIt took me a little bit more time to get things working right.\nI found a little bug in the tangled UI regarding spindle runs.\n\nWhen pushing to the _official_ knot, the workflow got picked up fine by the official spindle, and showed up in the UI.\nWhen I pushed to _my_ knot however, the official spindle ran the workflow, but it didn't show in the UI.\nIt took me a while to realise what was going on.\n\nI thought the spindle wasn't picking up the workflow, but the bug was simply with showing the info in the UI.\nAnirudh was very quick to find the cause and implement a fix.\n\nAnd just like that, this blog gets deployed automatically on push, using the tangled spindle!",
  "title": "Embracing ATProto, part 2: Tangled Knots and social coding"
}